Skip to content

Commit b923d4d

Browse files
Copilotrostam
andcommitted
Improve test coverage: add 5 existing test files to build and create UtilityAndCheckerTest
Co-authored-by: rostam <1497363+rostam@users.noreply.github.com> Agent-Logs-Url: https://github.com/rostam/GraphTea/sessions/ce73976f-09e9-4ea9-a5cf-23401e825b2a
1 parent 064e692 commit b923d4d

File tree

2 files changed

+370
-0
lines changed

2 files changed

+370
-0
lines changed

build.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@
7474
<include name="ShortestPathAndMSTTest.java"/>
7575
<include name="SubdividedGraphTest.java"/>
7676
<include name="CoronaAndUtilsTest.java"/>
77+
<include name="BiconnectedComponentsTest.java"/>
78+
<include name="G6FormatTest.java"/>
79+
<include name="GraphComplementTest.java"/>
80+
<include name="GraphJoinTest.java"/>
81+
<include name="RenderTableTest.java"/>
82+
<include name="UtilityAndCheckerTest.java"/>
7783
</javac>
7884
<junitlauncher haltOnFailure="false" printSummary="true">
7985
<classpath>
@@ -107,6 +113,12 @@
107113
<include name="ShortestPathAndMSTTest.class"/>
108114
<include name="SubdividedGraphTest.class"/>
109115
<include name="CoronaAndUtilsTest.class"/>
116+
<include name="BiconnectedComponentsTest.class"/>
117+
<include name="G6FormatTest.class"/>
118+
<include name="GraphComplementTest.class"/>
119+
<include name="GraphJoinTest.class"/>
120+
<include name="RenderTableTest.class"/>
121+
<include name="UtilityAndCheckerTest.class"/>
110122
</fileset>
111123
<listener type="legacy-xml" outputdir="${basedir}/build/test-classes" sendSysOut="true" sendSysErr="true"/>
112124
<listener type="legacy-plain" sendSysOut="true"/>

test/UtilityAndCheckerTest.java

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
import graphtea.extensions.algorithms.GOpUtils;
2+
import graphtea.extensions.generators.CircleGenerator;
3+
import graphtea.extensions.generators.CompleteGraphGenerator;
4+
import graphtea.extensions.generators.PathGenerator;
5+
import graphtea.graph.graph.Edge;
6+
import graphtea.graph.graph.GPoint;
7+
import graphtea.graph.graph.GraphModel;
8+
import graphtea.graph.graph.Vertex;
9+
import graphtea.library.algorithms.util.AcyclicChecker;
10+
import graphtea.library.algorithms.util.BipartiteChecker;
11+
import graphtea.library.algorithms.util.ConnectivityChecker;
12+
import graphtea.library.util.Pair;
13+
import org.junit.jupiter.api.Test;
14+
15+
import java.util.HashMap;
16+
17+
import static org.junit.jupiter.api.Assertions.*;
18+
19+
/**
20+
* Tests for utility classes and graph-property checkers that previously had no
21+
* dedicated test coverage:
22+
* - AcyclicChecker
23+
* - BipartiteChecker
24+
* - ConnectivityChecker
25+
* - GOpUtils
26+
* - Pair
27+
*/
28+
public class UtilityAndCheckerTest {
29+
30+
// =========================================================================
31+
// AcyclicChecker
32+
// =========================================================================
33+
34+
/** A single isolated vertex has no edges, so it is a tree (acyclic). */
35+
@Test
36+
public void testAcyclicCheckerSingleVertex() {
37+
GraphModel g = new GraphModel(false);
38+
g.insertVertex(new Vertex());
39+
assertTrue(AcyclicChecker.isGraphAcyclic(g));
40+
}
41+
42+
/** A path graph is acyclic (it is a tree). */
43+
@Test
44+
public void testAcyclicCheckerPathIsAcyclic() {
45+
GraphModel g = PathGenerator.generatePath(5);
46+
assertTrue(AcyclicChecker.isGraphAcyclic(g));
47+
}
48+
49+
/** A cycle graph C_n (n ≥ 3) contains a cycle, so it is not acyclic. */
50+
@Test
51+
public void testAcyclicCheckerCycleIsNotAcyclic() {
52+
GraphModel g = CircleGenerator.generateCircle(4);
53+
assertFalse(AcyclicChecker.isGraphAcyclic(g));
54+
}
55+
56+
/** A complete graph K_4 has many cycles and is not acyclic. */
57+
@Test
58+
public void testAcyclicCheckerCompleteK4IsNotAcyclic() {
59+
GraphModel g = CompleteGraphGenerator.generateCompleteGraph(4);
60+
assertFalse(AcyclicChecker.isGraphAcyclic(g));
61+
}
62+
63+
/** Two isolated vertices (no edges) form a forest — acyclic. */
64+
@Test
65+
public void testAcyclicCheckerTwoIsolatedVerticesIsAcyclic() {
66+
GraphModel g = new GraphModel(false);
67+
g.insertVertex(new Vertex());
68+
g.insertVertex(new Vertex());
69+
assertTrue(AcyclicChecker.isGraphAcyclic(g));
70+
}
71+
72+
/** A single edge (K_2) is a tree — acyclic. */
73+
@Test
74+
public void testAcyclicCheckerSingleEdgeIsAcyclic() {
75+
GraphModel g = PathGenerator.generatePath(2);
76+
assertTrue(AcyclicChecker.isGraphAcyclic(g));
77+
}
78+
79+
/** A triangle (C_3) is not acyclic. */
80+
@Test
81+
public void testAcyclicCheckerTriangleIsNotAcyclic() {
82+
GraphModel g = CircleGenerator.generateCircle(3);
83+
assertFalse(AcyclicChecker.isGraphAcyclic(g));
84+
}
85+
86+
// =========================================================================
87+
// BipartiteChecker
88+
// =========================================================================
89+
90+
/** A path graph is always bipartite (its two colour-classes alternate). */
91+
@Test
92+
public void testBipartiteCheckerPathIsBipartite() {
93+
GraphModel g = PathGenerator.generatePath(5);
94+
assertTrue(BipartiteChecker.isBipartite(g));
95+
}
96+
97+
/** An even cycle C_4 is bipartite. */
98+
@Test
99+
public void testBipartiteCheckerEvenCycleIsBipartite() {
100+
GraphModel g = CircleGenerator.generateCircle(4);
101+
assertTrue(BipartiteChecker.isBipartite(g));
102+
}
103+
104+
/** A larger even cycle C_6 is bipartite. */
105+
@Test
106+
public void testBipartiteCheckerC6IsBipartite() {
107+
GraphModel g = CircleGenerator.generateCircle(6);
108+
assertTrue(BipartiteChecker.isBipartite(g));
109+
}
110+
111+
/** An odd cycle C_3 (triangle) is NOT bipartite. */
112+
@Test
113+
public void testBipartiteCheckerOddCycleC3IsNotBipartite() {
114+
GraphModel g = CircleGenerator.generateCircle(3);
115+
assertFalse(BipartiteChecker.isBipartite(g));
116+
}
117+
118+
/** An odd cycle C_5 is NOT bipartite. */
119+
@Test
120+
public void testBipartiteCheckerOddCycleC5IsNotBipartite() {
121+
GraphModel g = CircleGenerator.generateCircle(5);
122+
assertFalse(BipartiteChecker.isBipartite(g));
123+
}
124+
125+
/** K_4 (complete on 4 vertices) contains odd cycles, so it is NOT bipartite. */
126+
@Test
127+
public void testBipartiteCheckerCompleteK4IsNotBipartite() {
128+
GraphModel g = CompleteGraphGenerator.generateCompleteGraph(4);
129+
assertFalse(BipartiteChecker.isBipartite(g));
130+
}
131+
132+
/** K_2 (single edge) is bipartite — the two endpoints form the two parts. */
133+
@Test
134+
public void testBipartiteCheckerK2IsBipartite() {
135+
GraphModel g = CompleteGraphGenerator.generateCompleteGraph(2);
136+
assertTrue(BipartiteChecker.isBipartite(g));
137+
}
138+
139+
/** A single vertex with no edges is trivially bipartite. */
140+
@Test
141+
public void testBipartiteCheckerSingleVertexIsBipartite() {
142+
GraphModel g = new GraphModel(false);
143+
g.insertVertex(new Vertex());
144+
assertTrue(BipartiteChecker.isBipartite(g));
145+
}
146+
147+
// =========================================================================
148+
// ConnectivityChecker
149+
// =========================================================================
150+
151+
/**
152+
* An empty graph (no vertices) is vacuously connected: the implementation
153+
* iterates over vertices and immediately returns true when there are none,
154+
* consistent with the convention that the empty graph satisfies all
155+
* universal (for-all) properties.
156+
*/
157+
@Test
158+
public void testConnectivityCheckerEmptyGraphIsConnected() throws Exception {
159+
GraphModel g = new GraphModel(false);
160+
assertTrue(ConnectivityChecker.isGraphConnected(g));
161+
}
162+
163+
/** A single vertex is connected. */
164+
@Test
165+
public void testConnectivityCheckerSingleVertexIsConnected() throws Exception {
166+
GraphModel g = new GraphModel(false);
167+
g.insertVertex(new Vertex());
168+
assertTrue(ConnectivityChecker.isGraphConnected(g));
169+
}
170+
171+
/** A path graph P_5 is connected. */
172+
@Test
173+
public void testConnectivityCheckerPathIsConnected() throws Exception {
174+
GraphModel g = PathGenerator.generatePath(5);
175+
assertTrue(ConnectivityChecker.isGraphConnected(g));
176+
}
177+
178+
/** A cycle C_4 is connected. */
179+
@Test
180+
public void testConnectivityCheckerCycleIsConnected() throws Exception {
181+
GraphModel g = CircleGenerator.generateCircle(4);
182+
assertTrue(ConnectivityChecker.isGraphConnected(g));
183+
}
184+
185+
/** K_4 is connected. */
186+
@Test
187+
public void testConnectivityCheckerCompleteK4IsConnected() throws Exception {
188+
GraphModel g = CompleteGraphGenerator.generateCompleteGraph(4);
189+
assertTrue(ConnectivityChecker.isGraphConnected(g));
190+
}
191+
192+
/** Two isolated vertices (no edges) form a disconnected graph. */
193+
@Test
194+
public void testConnectivityCheckerTwoIsolatedVerticesIsDisconnected() throws Exception {
195+
GraphModel g = new GraphModel(false);
196+
g.insertVertex(new Vertex());
197+
g.insertVertex(new Vertex());
198+
assertFalse(ConnectivityChecker.isGraphConnected(g));
199+
}
200+
201+
/** A graph with two components (two separate edges) is not connected. */
202+
@Test
203+
public void testConnectivityCheckerTwoSeparateEdgesIsDisconnected() throws Exception {
204+
GraphModel g = new GraphModel(false);
205+
Vertex v0 = new Vertex();
206+
Vertex v1 = new Vertex();
207+
Vertex v2 = new Vertex();
208+
Vertex v3 = new Vertex();
209+
g.insertVertex(v0);
210+
g.insertVertex(v1);
211+
g.insertVertex(v2);
212+
g.insertVertex(v3);
213+
g.insertEdge(new Edge(v0, v1));
214+
g.insertEdge(new Edge(v2, v3));
215+
assertFalse(ConnectivityChecker.isGraphConnected(g));
216+
}
217+
218+
// =========================================================================
219+
// GOpUtils
220+
// =========================================================================
221+
222+
/** center() of a single vertex at (3, 4) should be (3, 4). */
223+
@Test
224+
public void testGOpUtilsCenterSingleVertex() {
225+
GraphModel g = new GraphModel(false);
226+
Vertex v = new Vertex();
227+
v.setLocation(new GPoint(3.0, 4.0));
228+
g.insertVertex(v);
229+
230+
GPoint c = GOpUtils.center(g);
231+
assertEquals(3.0, c.x, 1e-9);
232+
assertEquals(4.0, c.y, 1e-9);
233+
}
234+
235+
/** center() of two vertices at (0,0) and (4,6) should be (2, 3). */
236+
@Test
237+
public void testGOpUtilsCenterTwoVertices() {
238+
GraphModel g = new GraphModel(false);
239+
Vertex v1 = new Vertex(); v1.setLocation(new GPoint(0.0, 0.0));
240+
Vertex v2 = new Vertex(); v2.setLocation(new GPoint(4.0, 6.0));
241+
g.insertVertex(v1); g.insertVertex(v2);
242+
243+
GPoint c = GOpUtils.center(g);
244+
assertEquals(2.0, c.x, 1e-9);
245+
assertEquals(3.0, c.y, 1e-9);
246+
}
247+
248+
/** center() of a symmetric arrangement should lie at the origin. */
249+
@Test
250+
public void testGOpUtilsCenterSymmetricArrangement() {
251+
GraphModel g = new GraphModel(false);
252+
Vertex v1 = new Vertex(); v1.setLocation(new GPoint(-1.0, 0.0));
253+
Vertex v2 = new Vertex(); v2.setLocation(new GPoint(1.0, 0.0));
254+
Vertex v3 = new Vertex(); v3.setLocation(new GPoint(0.0, 2.0));
255+
Vertex v4 = new Vertex(); v4.setLocation(new GPoint(0.0, -2.0));
256+
g.insertVertex(v1); g.insertVertex(v2);
257+
g.insertVertex(v3); g.insertVertex(v4);
258+
259+
GPoint c = GOpUtils.center(g);
260+
assertEquals(0.0, c.x, 1e-9);
261+
assertEquals(0.0, c.y, 1e-9);
262+
}
263+
264+
/** offsetPositionsToCenter() returns a map with one entry per vertex. */
265+
@Test
266+
public void testGOpUtilsOffsetPositionsToCenterEntryCount() {
267+
GraphModel g = new GraphModel(false);
268+
Vertex v1 = new Vertex(); v1.setLocation(new GPoint(1.0, 1.0));
269+
Vertex v2 = new Vertex(); v2.setLocation(new GPoint(3.0, 3.0));
270+
g.insertVertex(v1); g.insertVertex(v2);
271+
272+
HashMap<Integer, GPoint> offsets = GOpUtils.offsetPositionsToCenter(g);
273+
assertEquals(2, offsets.size());
274+
}
275+
276+
/** offsetPositionsToCenter() offsets sum to zero for a symmetric graph. */
277+
@Test
278+
public void testGOpUtilsOffsetPositionsToCenterSymmetric() {
279+
GraphModel g = new GraphModel(false);
280+
Vertex v1 = new Vertex(); v1.setLocation(new GPoint(-1.0, 0.0));
281+
Vertex v2 = new Vertex(); v2.setLocation(new GPoint(1.0, 0.0));
282+
g.insertVertex(v1); g.insertVertex(v2);
283+
284+
HashMap<Integer, GPoint> offsets = GOpUtils.offsetPositionsToCenter(g);
285+
double sumX = offsets.values().stream().mapToDouble(p -> p.x).sum();
286+
double sumY = offsets.values().stream().mapToDouble(p -> p.y).sum();
287+
assertEquals(0.0, sumX, 1e-9);
288+
assertEquals(0.0, sumY, 1e-9);
289+
}
290+
291+
/** midPoint() of an edge between (0,0) and (4,6) should be (2, 3). */
292+
@Test
293+
public void testGOpUtilsMidPoint() {
294+
GraphModel g = new GraphModel(false);
295+
Vertex v1 = new Vertex(); v1.setLocation(new GPoint(0.0, 0.0));
296+
Vertex v2 = new Vertex(); v2.setLocation(new GPoint(4.0, 6.0));
297+
g.insertVertex(v1); g.insertVertex(v2);
298+
Edge e = new Edge(v1, v2);
299+
g.insertEdge(e);
300+
301+
GPoint mid = GOpUtils.midPoint(e);
302+
assertEquals(2.0, mid.x, 1e-9);
303+
assertEquals(3.0, mid.y, 1e-9);
304+
}
305+
306+
/** midPoint() of an edge between two identical points should equal that point. */
307+
@Test
308+
public void testGOpUtilsMidPointSameLocation() {
309+
GraphModel g = new GraphModel(false);
310+
Vertex v1 = new Vertex(); v1.setLocation(new GPoint(5.0, 7.0));
311+
Vertex v2 = new Vertex(); v2.setLocation(new GPoint(5.0, 7.0));
312+
g.insertVertex(v1); g.insertVertex(v2);
313+
Edge e = new Edge(v1, v2);
314+
g.insertEdge(e);
315+
316+
GPoint mid = GOpUtils.midPoint(e);
317+
assertEquals(5.0, mid.x, 1e-9);
318+
assertEquals(7.0, mid.y, 1e-9);
319+
}
320+
321+
// =========================================================================
322+
// Pair
323+
// =========================================================================
324+
325+
/** Pair stores its two values and exposes them via the public fields. */
326+
@Test
327+
public void testPairHoldsValues() {
328+
Pair<String, Integer> p = new Pair<>("hello", 42);
329+
assertEquals("hello", p.first);
330+
assertEquals(42, p.second);
331+
}
332+
333+
/** Pair allows null values. */
334+
@Test
335+
public void testPairAllowsNull() {
336+
Pair<String, String> p = new Pair<>(null, null);
337+
assertNull(p.first);
338+
assertNull(p.second);
339+
}
340+
341+
/** Pair fields are mutable (public). */
342+
@Test
343+
public void testPairFieldsAreMutable() {
344+
Pair<Integer, Integer> p = new Pair<>(1, 2);
345+
p.first = 10;
346+
p.second = 20;
347+
assertEquals(10, p.first);
348+
assertEquals(20, p.second);
349+
}
350+
351+
/** Pair works with different generic type combinations. */
352+
@Test
353+
public void testPairGenericTypes() {
354+
Pair<Double, Boolean> p = new Pair<>(3.14, true);
355+
assertEquals(3.14, p.first, 1e-15);
356+
assertTrue(p.second);
357+
}
358+
}

0 commit comments

Comments
 (0)