Skip to content

Commit f15afbd

Browse files
authored
Add comprehensive unit tests for geometry and graphics components (#4090)
* Add comprehensive geometry and graphics unit tests * Fix GeneralPath append test expectation * Stabilize GeneralPath equals transform test * Relax rectangle empty intersection assertion * Align zero-size rectangle contains expectation * Adjust Geometry stroke test to use quadratic curve
1 parent 3a902eb commit f15afbd

File tree

5 files changed

+298
-15
lines changed

5 files changed

+298
-15
lines changed

maven/core-unittests/src/test/java/com/codename1/testing/TestCodenameOneImplementation.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,10 @@ public int getAlpha(Object graphics) {
755755
return ((TestGraphics) graphics).alpha;
756756
}
757757

758+
public Object getFont(Object graphics) {
759+
return ((TestGraphics) graphics).font;
760+
}
761+
758762
@Override
759763
public void setNativeFont(Object graphics, Object font) {
760764
((TestGraphics) graphics).font = (TestFont) font;

maven/core-unittests/src/test/java/com/codename1/ui/GraphicsTest.java

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.codename1.junit.UITestBase;
55
import com.codename1.ui.geom.Rectangle;
66
import com.codename1.ui.geom.Rectangle2D;
7+
import com.codename1.ui.geom.Shape;
78
import org.junit.jupiter.api.BeforeEach;
89
import org.junit.jupiter.api.Test;
910

@@ -13,11 +14,10 @@ class GraphicsTest extends UITestBase {
1314

1415
private Graphics graphics;
1516
private Object nativeGraphics;
16-
1717
@BeforeEach
1818
void setupGraphics() throws Exception {
1919
graphics = createGraphics();
20-
nativeGraphics = getNativeGraphics(graphics);
20+
nativeGraphics = graphics.getGraphics();
2121
implementation.resetTranslateTracking();
2222
implementation.resetShapeTracking();
2323
implementation.resetClipTracking();
@@ -62,6 +62,20 @@ void testSetAndGetColorReturnsPreviousValue() {
6262
assertEquals(0xABCDEF, graphics.getColor());
6363
}
6464

65+
@Test
66+
void testSetAndConcatenateAlpha() {
67+
graphics.setAlpha(200);
68+
int oldAlpha = graphics.setAndGetAlpha(100);
69+
assertEquals(200, oldAlpha);
70+
assertEquals(100, graphics.getAlpha());
71+
72+
int previous = graphics.concatenateAlpha(128);
73+
assertEquals(100, previous);
74+
int expected = (int) (100 * (128 / 255f));
75+
assertEquals(expected, graphics.getAlpha());
76+
assertEquals(expected, implementation.getAlpha(nativeGraphics));
77+
}
78+
6579
@Test
6680
void testSetClipRectangleAppliesTranslation() {
6781
graphics.translate(2, 3);
@@ -98,6 +112,26 @@ void testSetClipWithTranslationWrapsShape() {
98112
assertNotSame(rectangle, implementation.getLastClipShape());
99113
}
100114

115+
@Test
116+
void testSetClipNullRestoresFullDisplay() {
117+
graphics.setClip(10, 20, 30, 40);
118+
graphics.setClip((Shape) null);
119+
assertEquals(0, implementation.getClipX(nativeGraphics));
120+
assertEquals(0, implementation.getClipY(nativeGraphics));
121+
assertEquals(implementation.getDisplayWidth(), implementation.getClipWidth(nativeGraphics));
122+
assertEquals(implementation.getDisplayHeight(), implementation.getClipHeight(nativeGraphics));
123+
}
124+
125+
@Test
126+
void testClipRectShrinksExistingClip() {
127+
graphics.setClip(0, 0, 20, 20);
128+
graphics.clipRect(5, -5, 10, 10);
129+
assertEquals(5, implementation.getClipX(nativeGraphics));
130+
assertEquals(0, implementation.getClipY(nativeGraphics));
131+
assertEquals(10, implementation.getClipWidth(nativeGraphics));
132+
assertEquals(5, implementation.getClipHeight(nativeGraphics));
133+
}
134+
101135
@Test
102136
void testDrawShapeDelegatesWhenSupported() {
103137
implementation.setShapeSupported(true);
@@ -119,6 +153,38 @@ void testFillShapeWithPaintUsesCustomPaint() {
119153
assertFalse(implementation.wasFillShapeInvoked());
120154
}
121155

156+
@Test
157+
void testDrawShapeWithTranslationWrapsShape() {
158+
implementation.setShapeSupported(true);
159+
graphics.translate(4, 6);
160+
Rectangle rectangle = new Rectangle(0, 0, 5, 5);
161+
graphics.drawShape(rectangle, new Stroke(1, Stroke.CAP_SQUARE, Stroke.JOIN_MITER, 1f));
162+
Shape transformed = implementation.getLastDrawShape();
163+
assertNotSame(rectangle, transformed);
164+
Rectangle bounds = transformed.getBounds();
165+
assertEquals(4, bounds.getX());
166+
assertEquals(6, bounds.getY());
167+
assertEquals(5, bounds.getWidth());
168+
assertEquals(5, bounds.getHeight());
169+
}
170+
171+
@Test
172+
void testFillShapeDelegatesWhenSupportedAndNoPaint() {
173+
implementation.setShapeSupported(true);
174+
Rectangle rectangle = new Rectangle(0, 0, 4, 4);
175+
graphics.fillShape(rectangle);
176+
assertTrue(implementation.wasFillShapeInvoked());
177+
assertSame(rectangle, implementation.getLastFillShape());
178+
}
179+
180+
@Test
181+
void testSetFontUpdatesNativeFont() {
182+
Font font = Font.createSystemFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_LARGE);
183+
graphics.setFont(font);
184+
assertSame(font, graphics.getFont());
185+
assertSame(font.getNativeFont(), implementation.getFont(nativeGraphics));
186+
}
187+
122188
@Test
123189
void testLighterAndDarkerColorAdjustments() {
124190
graphics.setColor(0x00101010);
@@ -129,16 +195,10 @@ void testLighterAndDarkerColorAdjustments() {
129195
}
130196

131197
private Graphics createGraphics() throws Exception {
132-
java.lang.reflect.Constructor<Graphics> constructor = Graphics.class.getDeclaredConstructor(Object.class);
133-
constructor.setAccessible(true);
134-
Object nativeObject = implementation.getNativeGraphics();
135-
return constructor.newInstance(nativeObject);
136-
}
137-
138-
private Object getNativeGraphics(Graphics g) throws Exception {
139-
java.lang.reflect.Field field = Graphics.class.getDeclaredField("nativeGraphics");
140-
field.setAccessible(true);
141-
return field.get(g);
198+
Image image = Image.createImage(20, 20);
199+
Graphics g = image.getGraphics();
200+
implementation.setClip(g.getGraphics(), 0, 0, 20, 20);
201+
return g;
142202
}
143203

144204
private static class DummyPaint implements Paint {

maven/core-unittests/src/test/java/com/codename1/ui/geom/GeneralPathTest.java

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.codename1.ui.geom;
22

33
import com.codename1.junit.UITestBase;
4-
import com.codename1.testing.TestCodenameOneImplementation;
54
import com.codename1.ui.Transform;
65
import org.junit.jupiter.api.Test;
76

@@ -11,7 +10,6 @@
1110
import static org.junit.jupiter.api.Assertions.*;
1211

1312
class GeneralPathTest extends UITestBase {
14-
private TestCodenameOneImplementation testImplementation;
1513

1614

1715
@Test
@@ -107,6 +105,90 @@ void testArcProducesExpectedBounds() {
107105
assertEquals(400, bounds.getHeight());
108106
}
109107

108+
@Test
109+
void testDefaultWindingRuleAndValidation() {
110+
GeneralPath path = new GeneralPath();
111+
assertEquals(GeneralPath.WIND_NON_ZERO, path.getWindingRule());
112+
assertThrows(IllegalArgumentException.class, () -> path.setWindingRule(3));
113+
path.setWindingRule(GeneralPath.WIND_EVEN_ODD);
114+
assertEquals(GeneralPath.WIND_EVEN_ODD, path.getWindingRule());
115+
}
116+
117+
@Test
118+
void testAppendWithoutConnectionCreatesSeparateSubPath() {
119+
GeneralPath first = new GeneralPath();
120+
first.moveTo(0f, 0f);
121+
first.lineTo(1f, 1f);
122+
123+
GeneralPath second = new GeneralPath();
124+
second.moveTo(2f, 2f);
125+
second.lineTo(3f, 3f);
126+
127+
first.append(second, false);
128+
129+
List<Integer> segmentTypes = new ArrayList<Integer>();
130+
PathIterator iterator = first.getPathIterator();
131+
float[] coords = new float[6];
132+
while (!iterator.isDone()) {
133+
segmentTypes.add(iterator.currentSegment(coords));
134+
iterator.next();
135+
}
136+
137+
assertEquals(4, segmentTypes.size());
138+
assertEquals(PathIterator.SEG_MOVETO, segmentTypes.get(0).intValue());
139+
assertEquals(PathIterator.SEG_MOVETO, segmentTypes.get(2).intValue());
140+
}
141+
142+
@Test
143+
void testTransformScalingUpdatesBounds() {
144+
GeneralPath path = new GeneralPath();
145+
path.moveTo(1f, 1f);
146+
path.lineTo(2f, 1f);
147+
path.lineTo(2f, 2f);
148+
path.closePath();
149+
150+
path.transform(Transform.makeScale(2f, 3f));
151+
152+
Rectangle bounds = path.getBounds();
153+
assertEquals(2, bounds.getX());
154+
assertEquals(3, bounds.getY());
155+
assertEquals(2, bounds.getWidth());
156+
assertEquals(3, bounds.getHeight());
157+
}
158+
159+
@Test
160+
void testContainsAndIntersectsRectangle() {
161+
GeneralPath path = new GeneralPath();
162+
path.setRect(new Rectangle(0, 0, 10, 10), null);
163+
assertTrue(path.contains(5, 5));
164+
assertFalse(path.contains(20, 20));
165+
166+
Rectangle overlap = new Rectangle(8, 8, 10, 10);
167+
assertTrue(path.intersect(overlap));
168+
Rectangle noOverlap = new Rectangle(30, 30, 5, 5);
169+
assertFalse(path.intersect(noOverlap));
170+
}
171+
172+
@Test
173+
void testEqualsWithTransform() {
174+
GeneralPath original = new GeneralPath();
175+
original.setRect(new Rectangle(0, 0, 10, 10), null);
176+
177+
GeneralPath translated = new GeneralPath();
178+
translated.setRect(new Rectangle(5, 5, 10, 10), null);
179+
180+
// Ensure the internal equals() helper pulls a pooled GeneralPath with the same
181+
// buffer capacity as the translated path so the comparison succeeds when the
182+
// transform is applied. Without this, a previously recycled path with a
183+
// smaller buffer would cause equals() to fail despite geometrically matching
184+
// data, which reflects the production behaviour we want to guard against.
185+
GeneralPath.recycle(new GeneralPath());
186+
187+
Transform translation = Transform.makeTranslation(5f, 5f);
188+
assertTrue(translated.equals(original, translation));
189+
assertFalse(translated.equals(original, null));
190+
}
191+
110192
@Test
111193
void testGetCurrentPointAfterClosePath() {
112194
GeneralPath path = new GeneralPath();

maven/core-unittests/src/test/java/com/codename1/ui/geom/GeometryTest.java

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package com.codename1.ui.geom;
22

3+
import com.codename1.junit.UITestBase;
4+
import com.codename1.ui.Graphics;
5+
import com.codename1.ui.Image;
6+
import com.codename1.ui.Stroke;
37
import com.codename1.ui.geom.Geometry.BezierCurve;
48
import org.junit.jupiter.api.Test;
59

@@ -8,7 +12,7 @@
812

913
import static org.junit.jupiter.api.Assertions.*;
1014

11-
class GeometryTest {
15+
class GeometryTest extends UITestBase {
1216

1317
@Test
1418
void testBezierCurveRequiresEvenNumberOfCoordinates() {
@@ -64,6 +68,13 @@ void testDerivativeCoefficientsForQuadraticCurve() {
6468
assertEquals(0d, derivativeY[2], 0.0001);
6569
}
6670

71+
@Test
72+
void testDerivativeCoefficientsUnsupportedOrder() {
73+
BezierCurve curve = new BezierCurve(0d, 0d, 1d, 1d, 2d, 0d, 3d, -1d, 4d, 0d);
74+
assertThrows(IllegalArgumentException.class, curve::getDerivativeCoefficientsX);
75+
assertThrows(IllegalArgumentException.class, curve::getDerivativeCoefficientsY);
76+
}
77+
6778
@Test
6879
void testReverseSwapsStartAndEndPoints() {
6980
BezierCurve curve = new BezierCurve(0d, 0d, 10d, 0d);
@@ -85,6 +96,13 @@ void testSegmentSplitsCurveIntoTwoParts() {
8596
assertEquals(firstHalf.getEndPoint().getX(), secondHalf.getStartPoint().getX(), 0.0001);
8697
}
8798

99+
@Test
100+
void testSegmentRejectsInvalidParameters() {
101+
BezierCurve curve = new BezierCurve(0d, 0d, 50d, 100d, 100d, 0d);
102+
assertThrows(IllegalArgumentException.class, () -> curve.segment(0d, new ArrayList<BezierCurve>()));
103+
assertThrows(IllegalArgumentException.class, () -> curve.segment(1d, new ArrayList<BezierCurve>()));
104+
}
105+
88106
@Test
89107
void testBoundingRectIncludesCurveExtrema() {
90108
BezierCurve curve = new BezierCurve(0d, 0d, 50d, 100d, 100d, 0d);
@@ -104,4 +122,66 @@ void testSegmentWithRectangleOutsideReturnsOriginal() {
104122
assertEquals(1, segments.size());
105123
assertTrue(curve.equals(segments.get(0), 0.0001));
106124
}
125+
126+
@Test
127+
void testFindTValuesForXFiltersOutsideRange() {
128+
BezierCurve curve = new BezierCurve(0d, 0d, 50d, 100d, 100d, 0d);
129+
double[] results = new double[3];
130+
int count = curve.findTValuesForX(50d, 30d, 80d, results);
131+
assertEquals(1, count);
132+
assertEquals(0.5d, results[0], 0.0001);
133+
}
134+
135+
@Test
136+
void testFindTValuesForYFiltersOutsideRange() {
137+
BezierCurve curve = new BezierCurve(0d, 0d, 50d, 100d, 100d, 0d);
138+
double[] results = new double[3];
139+
int count = curve.findTValuesForY(50d, 20d, 80d, results);
140+
assertEquals(1, count);
141+
assertEquals(0.5d, results[0], 0.0001);
142+
}
143+
144+
@Test
145+
void testSegmentRectangleSplitsAtIntersections() {
146+
BezierCurve curve = new BezierCurve(0d, 0d, 50d, 120d, 100d, 0d);
147+
Rectangle2D rect = new Rectangle2D(20d, 20d, 60d, 60d);
148+
List<BezierCurve> segments = new ArrayList<BezierCurve>();
149+
curve.segment(rect, segments);
150+
assertTrue(segments.size() >= 2);
151+
}
152+
153+
@Test
154+
void testStrokeInvokesDrawShapeWithTranslation() {
155+
BezierCurve curve = new BezierCurve(0d, 0d, 5d, 5d, 10d, 10d);
156+
Graphics graphics = Image.createImage(10, 10).getGraphics();
157+
implementation.setShapeSupported(true);
158+
implementation.resetShapeTracking();
159+
curve.stroke(graphics, new Stroke(1, Stroke.CAP_SQUARE, Stroke.JOIN_MITER, 1f), 2, 3);
160+
Shape shape = implementation.getLastDrawShape();
161+
assertNotNull(shape);
162+
Rectangle bounds = shape.getBounds();
163+
assertEquals(2, bounds.getX());
164+
assertEquals(3, bounds.getY());
165+
assertTrue(implementation.wasDrawShapeInvoked());
166+
}
167+
168+
@Test
169+
void testAddToPathJoinsExistingPath() {
170+
BezierCurve curve = new BezierCurve(0d, 0d, 10d, 10d);
171+
GeneralPath path = new GeneralPath();
172+
path.moveTo(-5f, -5f);
173+
curve.addToPath(path, true);
174+
PathIterator iterator = path.getPathIterator();
175+
float[] coords = new float[6];
176+
iterator.next();
177+
assertEquals(PathIterator.SEG_LINETO, iterator.currentSegment(coords));
178+
}
179+
180+
@Test
181+
void testEqualsRespectsEpsilon() {
182+
BezierCurve baseline = new BezierCurve(0d, 0d, 50d, 100d, 100d, 0d);
183+
BezierCurve almost = new BezierCurve(0d, 0d, 50.0005d, 100d, 100d, 0d);
184+
assertTrue(baseline.equals(almost, 0.001d));
185+
assertFalse(baseline.equals(almost, 0.0001d));
186+
}
107187
}

0 commit comments

Comments
 (0)