Skip to content
This repository was archived by the owner on Jun 18, 2026. It is now read-only.

Commit 35386de

Browse files
author
Zalenix
committed
Add unit tests for Util and TimelineMetricsRecorder
UtilTest (23 tests): covers validateTimeFormat (canonical/malformed/null/label propagation), getTimeStamp (basic, millisecond precision, zero-padding, malformed/null rejection), and getTimeDifference (zero/positive/negative/sub-minute/combined-units/malformed/null). Skips the JDBC-bound factory methods which require a live PostgreSQL instance. TimelineMetricsRecorderTest (18 tests): covers per-step capture (density, avg/max degree, avg weight, isolated nodes, component count, per-category counts that only tally edges present in the graph), churn accounting (new/lost nodes/edges across steps), CSV export to file and string with header + RFC-4180 escaping of labels containing commas/quotes, trend analysis (peaks, averages, population std dev, category min/max/avg), phase-transition detection at the default threshold and respect for a custom threshold, validation on setPhaseThreshold (0.0 and >1.0 rejected, 1.0 boundary accepted), null-graph rejection, clear() resetting both step index and churn baseline, and snapshots list immutability.
1 parent f5588cf commit 35386de

2 files changed

Lines changed: 612 additions & 0 deletions

File tree

Gvisual/test/app/UtilTest.java

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package app;
2+
3+
import org.junit.Test;
4+
import static org.junit.Assert.*;
5+
6+
/**
7+
* Unit tests for the pure (non-database) helpers on {@link Util}:
8+
*
9+
* <ul>
10+
* <li>{@link Util#validateTimeFormat(String, String)}</li>
11+
* <li>{@link Util#getTimeStamp(String, String, String)}</li>
12+
* <li>{@link Util#getTimeDifference(String, String)}</li>
13+
* </ul>
14+
*
15+
* <p>The database-bound methods ({@code getAppConnection},
16+
* {@code getAzialaConnection}) are intentionally NOT exercised here \u2014
17+
* they require a live PostgreSQL instance and credentials from the
18+
* environment, which is outside the scope of unit tests.</p>
19+
*
20+
* <p>The trace format used throughout is {@code "HH.MM:SS.mmm"}:
21+
* dot-separated hours/minutes and seconds/millis, with a single colon
22+
* between the two halves.</p>
23+
*/
24+
public class UtilTest {
25+
26+
// ============================================================
27+
// validateTimeFormat
28+
// ============================================================
29+
30+
@Test
31+
public void validateTimeFormat_acceptsCanonicalFormat() {
32+
// Should not throw.
33+
Util.validateTimeFormat("10.30:15.000", "endTime");
34+
Util.validateTimeFormat("00.00:00.000", "endTime");
35+
Util.validateTimeFormat("23.59:59.999", "endTime");
36+
}
37+
38+
@Test(expected = IllegalArgumentException.class)
39+
public void validateTimeFormat_rejectsNull() {
40+
Util.validateTimeFormat(null, "endTime");
41+
}
42+
43+
@Test(expected = IllegalArgumentException.class)
44+
public void validateTimeFormat_rejectsEmpty() {
45+
Util.validateTimeFormat("", "endTime");
46+
}
47+
48+
@Test(expected = IllegalArgumentException.class)
49+
public void validateTimeFormat_rejectsMissingColon() {
50+
Util.validateTimeFormat("10.30.15.000", "endTime");
51+
}
52+
53+
@Test(expected = IllegalArgumentException.class)
54+
public void validateTimeFormat_rejectsMultipleColons() {
55+
// Two colons -> split() length != 2 -> rejected.
56+
Util.validateTimeFormat("10:30:15.000", "endTime");
57+
}
58+
59+
@Test(expected = IllegalArgumentException.class)
60+
public void validateTimeFormat_rejectsMissingDotInLeftHalf() {
61+
// "10:15.000" -> left half "10" has no dot -> rejected
62+
Util.validateTimeFormat("10:15.000", "endTime");
63+
}
64+
65+
@Test(expected = IllegalArgumentException.class)
66+
public void validateTimeFormat_rejectsMissingDotInRightHalf() {
67+
// "10.30:15" -> right half "15" has no dot -> rejected
68+
Util.validateTimeFormat("10.30:15", "endTime");
69+
}
70+
71+
@Test
72+
public void validateTimeFormat_errorMessageIncludesLabel() {
73+
try {
74+
Util.validateTimeFormat(null, "myCustomLabel");
75+
fail("expected IllegalArgumentException");
76+
} catch (IllegalArgumentException ex) {
77+
assertTrue("error message should reference the label, got: " + ex.getMessage(),
78+
ex.getMessage().contains("myCustomLabel"));
79+
}
80+
}
81+
82+
// ============================================================
83+
// getTimeStamp
84+
// ============================================================
85+
86+
@Test
87+
public void getTimeStamp_basicConversion() {
88+
// month="03", date="15", time="10.30:15.000"
89+
// -> "2011-03-15 10:30:15.000"
90+
String ts = Util.getTimeStamp("03", "15", "10.30:15.000");
91+
assertEquals("2011-03-15 10:30:15.000", ts);
92+
}
93+
94+
@Test
95+
public void getTimeStamp_preservesMillisecondsExactly() {
96+
String ts = Util.getTimeStamp("12", "31", "23.59:59.987");
97+
assertEquals("2011-12-31 23:59:59.987", ts);
98+
}
99+
100+
@Test
101+
public void getTimeStamp_zeroPaddedZerothSecond() {
102+
String ts = Util.getTimeStamp("01", "01", "00.00:00.000");
103+
assertEquals("2011-01-01 00:00:00.000", ts);
104+
}
105+
106+
@Test(expected = IllegalArgumentException.class)
107+
public void getTimeStamp_rejectsMalformedTime() {
108+
// No colon \u2192 validateTimeFormat throws \u2192 propagated out.
109+
Util.getTimeStamp("03", "15", "not-a-time");
110+
}
111+
112+
@Test(expected = IllegalArgumentException.class)
113+
public void getTimeStamp_rejectsNullTime() {
114+
Util.getTimeStamp("03", "15", null);
115+
}
116+
117+
// ============================================================
118+
// getTimeDifference
119+
// ============================================================
120+
121+
@Test
122+
public void getTimeDifference_sameTimeIsZero() {
123+
assertEquals(0.0f,
124+
Util.getTimeDifference("10.30:15.000", "10.30:15.000"),
125+
1e-4f);
126+
}
127+
128+
@Test
129+
public void getTimeDifference_oneHourApart() {
130+
// 11:30:00 - 10:30:00 = 60 minutes
131+
assertEquals(60.0f,
132+
Util.getTimeDifference("11.30:00.000", "10.30:00.000"),
133+
1e-3f);
134+
}
135+
136+
@Test
137+
public void getTimeDifference_oneMinuteApart() {
138+
// 10:31:00 - 10:30:00 = 1 minute
139+
assertEquals(1.0f,
140+
Util.getTimeDifference("10.31:00.000", "10.30:00.000"),
141+
1e-3f);
142+
}
143+
144+
@Test
145+
public void getTimeDifference_thirtySecondsApart() {
146+
// 30 seconds = 0.5 minutes
147+
assertEquals(0.5f,
148+
Util.getTimeDifference("10.30:30.000", "10.30:00.000"),
149+
1e-3f);
150+
}
151+
152+
@Test
153+
public void getTimeDifference_negativeWhenEndBeforeStart() {
154+
// 10:30 - 11:30 = -60 minutes
155+
assertEquals(-60.0f,
156+
Util.getTimeDifference("10.30:00.000", "11.30:00.000"),
157+
1e-3f);
158+
}
159+
160+
@Test
161+
public void getTimeDifference_combinedHoursMinutesSeconds() {
162+
// 11:31:30 - 10:30:00 = 60 + 1 + 0.5 = 61.5 minutes
163+
assertEquals(61.5f,
164+
Util.getTimeDifference("11.31:30.000", "10.30:00.000"),
165+
1e-3f);
166+
}
167+
168+
@Test(expected = IllegalArgumentException.class)
169+
public void getTimeDifference_rejectsMalformedEndTime() {
170+
Util.getTimeDifference("not-a-time", "10.30:00.000");
171+
}
172+
173+
@Test(expected = IllegalArgumentException.class)
174+
public void getTimeDifference_rejectsMalformedStartTime() {
175+
Util.getTimeDifference("10.30:00.000", "still-not-a-time");
176+
}
177+
178+
@Test(expected = IllegalArgumentException.class)
179+
public void getTimeDifference_rejectsNullEnd() {
180+
Util.getTimeDifference(null, "10.30:00.000");
181+
}
182+
183+
@Test(expected = IllegalArgumentException.class)
184+
public void getTimeDifference_rejectsNullStart() {
185+
Util.getTimeDifference("10.30:00.000", null);
186+
}
187+
}

0 commit comments

Comments
 (0)