Compare commits
8 Commits
issue-25/m
...
bcbbcef321
| Author | SHA1 | Date | |
|---|---|---|---|
| bcbbcef321 | |||
| 692a03ee88 | |||
| e83a6ba7d1 | |||
| c264e7a7fc | |||
| f7646f99ba | |||
| 29d202c156 | |||
| 7ddef4d8ab | |||
| c51ae8cfbb |
14
pom.xml
14
pom.xml
@@ -15,6 +15,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>16</source>
|
<source>16</source>
|
||||||
<target>16</target>
|
<target>16</target>
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
<version>0.8.11</version>
|
<version>0.8.13</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@@ -70,13 +71,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>RELEASE</version>
|
<version>2.0.16</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>RELEASE</version>
|
<version>1.5.12</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -92,5 +93,12 @@
|
|||||||
<version>5.10.0</version>
|
<version>5.10.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-params</artifactId>
|
||||||
|
<version>5.10.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package ovh.gasser.newshapes.attributes;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class ColorAttributesTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorStoresFilledFlag() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(true, false, Color.RED, Color.BLACK);
|
||||||
|
assertTrue(attrs.filled, "filled flag should be true when constructed with true");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorStoresStrokedFlag() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(false, true, Color.RED, Color.BLACK);
|
||||||
|
assertTrue(attrs.stroked, "stroked flag should be true when constructed with true");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorStoresFilledColor() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(true, false, Color.BLUE, Color.BLACK);
|
||||||
|
assertEquals(Color.BLUE, attrs.filledColor, "filledColor should match the constructor argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorStoresStrokedColor() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(false, true, Color.RED, Color.GREEN);
|
||||||
|
assertEquals(Color.GREEN, attrs.strokedColor, "strokedColor should match the constructor argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFilledAndStrokedBothTrue() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(true, true, Color.RED, Color.BLUE);
|
||||||
|
assertTrue(attrs.filled);
|
||||||
|
assertTrue(attrs.stroked);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFilledAndStrokedBothFalse() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(false, false, Color.RED, Color.BLUE);
|
||||||
|
assertFalse(attrs.filled);
|
||||||
|
assertFalse(attrs.stroked);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNullFilledColor() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(true, false, null, Color.BLACK);
|
||||||
|
assertNull(attrs.filledColor, "filledColor should accept null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNullStrokedColor() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(false, true, Color.RED, null);
|
||||||
|
assertNull(attrs.strokedColor, "strokedColor should accept null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBothColorsNull() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(false, false, null, null);
|
||||||
|
assertNull(attrs.filledColor);
|
||||||
|
assertNull(attrs.strokedColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetIDReturnsCorrectValue() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(false, false, Color.RED, Color.BLACK);
|
||||||
|
assertEquals(ColorAttributes.ID, attrs.getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIDConstant() {
|
||||||
|
assertEquals("COLOR_ATTRS", ColorAttributes.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testImplementsAttributes() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(false, false, Color.RED, Color.BLACK);
|
||||||
|
assertInstanceOf(Attributes.class, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToStringContainsAllFields() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(true, false, Color.RED, Color.BLUE);
|
||||||
|
String str = attrs.toString();
|
||||||
|
assertTrue(str.contains("filled=true"), "toString should contain filled value");
|
||||||
|
assertTrue(str.contains("stroked=false"), "toString should contain stroked value");
|
||||||
|
assertTrue(str.contains("filledColor"), "toString should contain filledColor");
|
||||||
|
assertTrue(str.contains("strokedColor"), "toString should contain strokedColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToStringWithNullColors() {
|
||||||
|
ColorAttributes attrs = new ColorAttributes(false, false, null, null);
|
||||||
|
String str = attrs.toString();
|
||||||
|
assertNotNull(str, "toString should not throw with null colors");
|
||||||
|
assertTrue(str.contains("filledColor=null"), "toString should show null filledColor");
|
||||||
|
assertTrue(str.contains("strokedColor=null"), "toString should show null strokedColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testTwoInstancesAreIndependent() {
|
||||||
|
ColorAttributes attrs1 = new ColorAttributes(true, false, Color.RED, Color.BLACK);
|
||||||
|
ColorAttributes attrs2 = new ColorAttributes(false, true, Color.BLUE, Color.GREEN);
|
||||||
|
|
||||||
|
assertTrue(attrs1.filled);
|
||||||
|
assertFalse(attrs2.filled);
|
||||||
|
assertFalse(attrs1.stroked);
|
||||||
|
assertTrue(attrs2.stroked);
|
||||||
|
assertEquals(Color.RED, attrs1.filledColor);
|
||||||
|
assertEquals(Color.BLUE, attrs2.filledColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFieldsAreImmutable() {
|
||||||
|
Color fillColor = Color.RED;
|
||||||
|
Color strokeColor = Color.BLACK;
|
||||||
|
ColorAttributes attrs = new ColorAttributes(true, true, fillColor, strokeColor);
|
||||||
|
|
||||||
|
// Since fields are final, verify they retain their values
|
||||||
|
assertEquals(Color.RED, attrs.filledColor);
|
||||||
|
assertEquals(Color.BLACK, attrs.strokedColor);
|
||||||
|
assertTrue(attrs.filled);
|
||||||
|
assertTrue(attrs.stroked);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package ovh.gasser.newshapes.attributes;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class SelectionAttributesTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDefaultConstructorIsUnselected() {
|
||||||
|
SelectionAttributes attrs = new SelectionAttributes();
|
||||||
|
assertFalse(attrs.selected, "Default constructor should create unselected state");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorWithTrue() {
|
||||||
|
SelectionAttributes attrs = new SelectionAttributes(true);
|
||||||
|
assertTrue(attrs.selected, "Constructor with true should create selected state");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorWithFalse() {
|
||||||
|
SelectionAttributes attrs = new SelectionAttributes(false);
|
||||||
|
assertFalse(attrs.selected, "Constructor with false should create unselected state");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetIDReturnsCorrectValue() {
|
||||||
|
SelectionAttributes attrs = new SelectionAttributes();
|
||||||
|
assertEquals(SelectionAttributes.ID, attrs.getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIDConstant() {
|
||||||
|
assertEquals("SELECTION_ATTRS", SelectionAttributes.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testImplementsAttributes() {
|
||||||
|
SelectionAttributes attrs = new SelectionAttributes();
|
||||||
|
assertInstanceOf(Attributes.class, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSelectedFieldCanBeToggled() {
|
||||||
|
SelectionAttributes attrs = new SelectionAttributes(false);
|
||||||
|
assertFalse(attrs.selected);
|
||||||
|
|
||||||
|
attrs.selected = true;
|
||||||
|
assertTrue(attrs.selected);
|
||||||
|
|
||||||
|
attrs.selected = false;
|
||||||
|
assertFalse(attrs.selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testTwoInstancesAreIndependent() {
|
||||||
|
SelectionAttributes attrs1 = new SelectionAttributes(true);
|
||||||
|
SelectionAttributes attrs2 = new SelectionAttributes(false);
|
||||||
|
|
||||||
|
assertNotEquals(attrs1.selected, attrs2.selected);
|
||||||
|
|
||||||
|
attrs2.selected = true;
|
||||||
|
assertTrue(attrs1.selected);
|
||||||
|
assertTrue(attrs2.selected);
|
||||||
|
|
||||||
|
// Mutating one doesn't affect the other
|
||||||
|
attrs1.selected = false;
|
||||||
|
assertFalse(attrs1.selected);
|
||||||
|
assertTrue(attrs2.selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package ovh.gasser.newshapes.shapes;
|
||||||
|
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameterized contract tests verifying Shape interface invariants
|
||||||
|
* across all implementations (SRectangle, SCircle, STriangle, SText, SCollection).
|
||||||
|
*/
|
||||||
|
class ShapeContractTest {
|
||||||
|
|
||||||
|
@ParameterizedTest(name = "{0}")
|
||||||
|
@MethodSource("ovh.gasser.newshapes.shapes.ShapeFactory#allShapes")
|
||||||
|
void cloneReturnsIndependentCopy(Shape shape) {
|
||||||
|
Shape cloned = shape.clone();
|
||||||
|
|
||||||
|
// clone must not be the same instance
|
||||||
|
assertNotSame(shape, cloned, "clone() must return a new instance");
|
||||||
|
|
||||||
|
// clone must have equal bounds
|
||||||
|
assertEquals(shape.getBounds(), cloned.getBounds(),
|
||||||
|
"clone() must preserve bounds");
|
||||||
|
|
||||||
|
// mutating the clone must not affect the original
|
||||||
|
Rectangle originalBounds = shape.getBounds();
|
||||||
|
cloned.translate(999, 999);
|
||||||
|
assertEquals(originalBounds, shape.getBounds(),
|
||||||
|
"Translating the clone must not affect the original's bounds");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest(name = "{0}")
|
||||||
|
@MethodSource("ovh.gasser.newshapes.shapes.ShapeFactory#allShapes")
|
||||||
|
void getBoundsReturnsCopy(Shape shape) {
|
||||||
|
Rectangle bounds1 = shape.getBounds();
|
||||||
|
Rectangle bounds2 = shape.getBounds();
|
||||||
|
|
||||||
|
// successive calls must return equal bounds
|
||||||
|
assertEquals(bounds1, bounds2,
|
||||||
|
"getBounds() must return consistent values");
|
||||||
|
|
||||||
|
// but not the same object (defensive copy)
|
||||||
|
assertNotSame(bounds1, bounds2,
|
||||||
|
"getBounds() must return a copy, not internal state");
|
||||||
|
|
||||||
|
// mutating the returned Rectangle must not affect the shape
|
||||||
|
bounds1.translate(500, 500);
|
||||||
|
assertEquals(bounds2, shape.getBounds(),
|
||||||
|
"Mutating the returned Rectangle must not affect the shape");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest(name = "{0}")
|
||||||
|
@MethodSource("ovh.gasser.newshapes.shapes.ShapeFactory#allShapes")
|
||||||
|
void translateMutatesInPlace(Shape shape) {
|
||||||
|
Rectangle before = shape.getBounds();
|
||||||
|
int dx = 7, dy = -3;
|
||||||
|
|
||||||
|
shape.translate(dx, dy);
|
||||||
|
|
||||||
|
Rectangle after = shape.getBounds();
|
||||||
|
assertEquals(before.x + dx, after.x,
|
||||||
|
"translate() must shift x by dx");
|
||||||
|
assertEquals(before.y + dy, after.y,
|
||||||
|
"translate() must shift y by dy");
|
||||||
|
assertEquals(before.width, after.width,
|
||||||
|
"translate() must not change width");
|
||||||
|
assertEquals(before.height, after.height,
|
||||||
|
"translate() must not change height");
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/java/ovh/gasser/newshapes/shapes/ShapeFactory.java
Normal file
25
src/test/java/ovh/gasser/newshapes/shapes/ShapeFactory.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package ovh.gasser.newshapes.shapes;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides Shape instances for parameterized contract tests.
|
||||||
|
*/
|
||||||
|
public final class ShapeFactory {
|
||||||
|
|
||||||
|
private ShapeFactory() {}
|
||||||
|
|
||||||
|
static Stream<Shape> allShapes() {
|
||||||
|
return Stream.of(
|
||||||
|
SRectangle.create(10, 20, 100, 50),
|
||||||
|
SCircle.create(5, 5, 30),
|
||||||
|
STriangle.create(0, 0, 40, Color.RED, Color.BLACK),
|
||||||
|
SText.create(15, 25, "Hello"),
|
||||||
|
SCollection.of(
|
||||||
|
SRectangle.create(0, 0, 20, 20),
|
||||||
|
SCircle.create(10, 10, 5)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user