Skip to content

Commit 9c900b0

Browse files
committed
test: add TestConcoredockerApi covering read/write/unchanged/initVal
closes #464
1 parent 01e0ec0 commit 9c900b0

2 files changed

Lines changed: 205 additions & 0 deletions

File tree

TestConcoredockerApi.java

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import java.io.IOException;
2+
import java.nio.file.Files;
3+
import java.nio.file.Path;
4+
import java.util.*;
5+
6+
/**
7+
* Tests for concoredocker read(), write(), unchanged(), initVal()
8+
* using temp directories for file-based IPC.
9+
*/
10+
public class TestConcoredockerApi {
11+
static int passed = 0;
12+
static int failed = 0;
13+
14+
public static void main(String[] args) {
15+
// zero delay so tests don't sleep for 1s per read()
16+
concoredocker.setDelay(0);
17+
18+
testWriteProducesCorrectFormat();
19+
testReadParsesFileAndStripsSimtime();
20+
testReadWriteRoundtrip();
21+
testSimtimeAdvancesWithDelta();
22+
testUnchangedReturnsFalseAfterRead();
23+
testUnchangedReturnsTrueOnSameData();
24+
testInitValExtractsSimtime();
25+
testInitValReturnsRemainingValues();
26+
testOutputFileMatchesPythonWireFormat();
27+
28+
System.out.println("\n=== Results: " + passed + " passed, " + failed + " failed out of " + (passed + failed) + " tests ===");
29+
if (failed > 0) {
30+
System.exit(1);
31+
}
32+
}
33+
34+
static void check(String testName, Object expected, Object actual) {
35+
if (Objects.equals(expected, actual)) {
36+
System.out.println("PASS: " + testName);
37+
passed++;
38+
} else {
39+
System.out.println("FAIL: " + testName + " | expected: " + expected + " | actual: " + actual);
40+
failed++;
41+
}
42+
}
43+
44+
static Path makeTempDir() {
45+
try {
46+
return Files.createTempDirectory("concore_test_");
47+
} catch (IOException e) {
48+
throw new RuntimeException("Failed to create temp dir", e);
49+
}
50+
}
51+
52+
/** Creates temp dir with port subdirectory ready for write(). */
53+
static Path makeTempDir(int port) {
54+
Path tmp = makeTempDir();
55+
try {
56+
Files.createDirectories(tmp.resolve(String.valueOf(port)));
57+
} catch (IOException e) {
58+
throw new RuntimeException(e);
59+
}
60+
return tmp;
61+
}
62+
63+
static void writeFile(Path base, int port, String name, String content) {
64+
try {
65+
Path dir = base.resolve(String.valueOf(port));
66+
Files.createDirectories(dir);
67+
Files.write(dir.resolve(name), content.getBytes());
68+
} catch (IOException e) {
69+
throw new RuntimeException("Failed to write test file", e);
70+
}
71+
}
72+
73+
static String readFile(Path base, int port, String name) {
74+
try {
75+
return new String(Files.readAllBytes(base.resolve(String.valueOf(port)).resolve(name)));
76+
} catch (IOException e) {
77+
throw new RuntimeException("Failed to read test file", e);
78+
}
79+
}
80+
81+
static void testWriteProducesCorrectFormat() {
82+
Path tmp = makeTempDir(1);
83+
concoredocker.resetState();
84+
concoredocker.setOutPath(tmp.toString());
85+
86+
List<Object> vals = new ArrayList<>();
87+
vals.add(10.0);
88+
vals.add(20.0);
89+
concoredocker.write(1, "signal", vals, 1);
90+
91+
String content = readFile(tmp, 1, "signal");
92+
@SuppressWarnings("unchecked")
93+
List<Object> parsed = (List<Object>) concoredocker.literalEval(content);
94+
check("write: simtime+delta as first element", 1.0, parsed.get(0));
95+
check("write: val1 correct", 10.0, parsed.get(1));
96+
check("write: val2 correct", 20.0, parsed.get(2));
97+
}
98+
99+
static void testReadParsesFileAndStripsSimtime() {
100+
Path tmp = makeTempDir();
101+
concoredocker.resetState();
102+
concoredocker.setInPath(tmp.toString());
103+
writeFile(tmp, 1, "sensor", "[0.0, 42.0, 99.0]");
104+
105+
List<Object> result = concoredocker.read(1, "sensor", "[0.0, 0.0, 0.0]");
106+
check("read: strips simtime, size=2", 2, result.size());
107+
check("read: val1 correct", 42.0, result.get(0));
108+
check("read: val2 correct", 99.0, result.get(1));
109+
}
110+
111+
static void testReadWriteRoundtrip() {
112+
Path tmp = makeTempDir(1);
113+
concoredocker.resetState();
114+
concoredocker.setInPath(tmp.toString());
115+
concoredocker.setOutPath(tmp.toString());
116+
117+
List<Object> outVals = new ArrayList<>();
118+
outVals.add(7.0);
119+
outVals.add(8.0);
120+
concoredocker.write(1, "data", outVals, 1);
121+
122+
List<Object> inVals = concoredocker.read(1, "data", "[0.0, 0.0, 0.0]");
123+
check("roundtrip: size", 2, inVals.size());
124+
check("roundtrip: val1", 7.0, inVals.get(0));
125+
check("roundtrip: val2", 8.0, inVals.get(1));
126+
}
127+
128+
static void testSimtimeAdvancesWithDelta() {
129+
Path tmp = makeTempDir(1);
130+
concoredocker.resetState();
131+
concoredocker.setInPath(tmp.toString());
132+
concoredocker.setOutPath(tmp.toString());
133+
134+
List<Object> v = Collections.singletonList((Object) 1.0);
135+
136+
// iteration 1: simtime=0, delta=1 -> file has [1.0, 1.0], read -> simtime becomes 1.0
137+
concoredocker.write(1, "tick", v, 1);
138+
concoredocker.read(1, "tick", "[0.0, 0.0]");
139+
check("simtime after iter 1", 1.0, concoredocker.getSimtime());
140+
141+
// iteration 2: write again with delta=1 -> file has [2.0, 1.0], read -> simtime becomes 2.0
142+
concoredocker.write(1, "tick", v, 1);
143+
concoredocker.read(1, "tick", "[0.0, 0.0]");
144+
check("simtime after iter 2", 2.0, concoredocker.getSimtime());
145+
}
146+
147+
static void testUnchangedReturnsFalseAfterRead() {
148+
Path tmp = makeTempDir();
149+
concoredocker.resetState();
150+
concoredocker.setInPath(tmp.toString());
151+
writeFile(tmp, 1, "sig", "[0.0, 5.0]");
152+
153+
concoredocker.read(1, "sig", "[0.0, 0.0]");
154+
check("unchanged: false right after read", false, concoredocker.unchanged());
155+
}
156+
157+
static void testUnchangedReturnsTrueOnSameData() {
158+
Path tmp = makeTempDir();
159+
concoredocker.resetState();
160+
concoredocker.setInPath(tmp.toString());
161+
writeFile(tmp, 1, "sig", "[0.0, 5.0]");
162+
163+
concoredocker.read(1, "sig", "[0.0, 0.0]");
164+
concoredocker.unchanged(); // first call: false, locks olds = s
165+
check("unchanged: true on second call with same data", true, concoredocker.unchanged());
166+
}
167+
168+
static void testInitValExtractsSimtime() {
169+
concoredocker.resetState();
170+
concoredocker.initVal("[2.0, 10, 20]");
171+
check("initVal: simtime extracted", 2.0, concoredocker.getSimtime());
172+
}
173+
174+
static void testInitValReturnsRemainingValues() {
175+
concoredocker.resetState();
176+
List<Object> result = concoredocker.initVal("[3.5, 100, 200]");
177+
check("initVal: size of returned list", 2, result.size());
178+
check("initVal: first remaining val", 100, result.get(0));
179+
check("initVal: second remaining val", 200, result.get(1));
180+
}
181+
182+
static void testOutputFileMatchesPythonWireFormat() {
183+
Path tmp = makeTempDir(1);
184+
concoredocker.resetState();
185+
concoredocker.setOutPath(tmp.toString());
186+
187+
List<Object> vals = new ArrayList<>();
188+
vals.add(1.0);
189+
vals.add(2.0);
190+
concoredocker.write(1, "out", vals, 0);
191+
192+
String raw = readFile(tmp, 1, "out");
193+
check("wire format: starts with '['", true, raw.startsWith("["));
194+
check("wire format: ends with ']'", true, raw.endsWith("]"));
195+
Object reparsed = concoredocker.literalEval(raw);
196+
check("wire format: re-parseable as list", true, reparsed instanceof List);
197+
}
198+
}

concoredocker.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ public static void defaultMaxTime(double defaultValue) {
130130
}
131131
}
132132

133+
// package-level helpers for testing with temp directories
134+
static void setInPath(String path) { inpath = path; }
135+
static void setOutPath(String path) { outpath = path; }
136+
static void setDelay(int ms) { delay = ms; }
137+
static double getSimtime() { return simtime; }
138+
static void resetState() { s = ""; olds = ""; simtime = 0; }
139+
133140
public static boolean unchanged() {
134141
if (olds.equals(s)) {
135142
s = "";

0 commit comments

Comments
 (0)