Skip to content

Commit 3f6b5c1

Browse files
fix(java): implement literalEval and restore Java execution path
The Java implementation of concoredocker was fundamentally broken. literalEval() was implemented as a stub returning an empty HashMap, causing read(), write(), defaultMaxTime(), and initVal() to silently malfunction. Changes: - Implement proper Python-style literal parsing in literalEval() - Supports dicts: {'key': value} - Supports lists: [val1, val2] - Supports numbers, strings, booleans, None - Fix unchanged() to return boolean (was void) - Fix defaultMaxTime() to read actual integer value - Fix read() and write() to properly handle List types - Add simtime tracking to match Python semantics - Add TestLiteralEval.java with 15 test cases Fixes #228
1 parent 81b865c commit 3f6b5c1

2 files changed

Lines changed: 557 additions & 37 deletions

File tree

TestLiteralEval.java

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
import java.util.List;
2+
import java.util.Map;
3+
import java.lang.reflect.Method;
4+
5+
/**
6+
* Test cases for the literalEval implementation in concoredocker.
7+
* This verifies the fix for GitHub Issue #228.
8+
*/
9+
public class TestLiteralEval {
10+
private static int passed = 0;
11+
private static int failed = 0;
12+
13+
public static void main(String[] args) throws Exception {
14+
System.out.println("Testing literalEval implementation...\n");
15+
16+
// Get the private literalEval method via reflection
17+
Method literalEval = concoredocker.class.getDeclaredMethod("literalEval", String.class);
18+
literalEval.setAccessible(true);
19+
20+
// Test 1: Simple dictionary (port file format)
21+
testDict(literalEval, "{'PYM': 1}", "PYM", 1);
22+
23+
// Test 2: Dictionary with multiple keys
24+
testDict(literalEval, "{'CU': 1, 'PYM': 2}", "CU", 1);
25+
26+
// Test 3: Simple list (data format)
27+
testList(literalEval, "[0.0, 0.0]", 2);
28+
29+
// Test 4: List with mixed types
30+
testList(literalEval, "[0, 1.5, 2.3]", 3);
31+
32+
// Test 5: Simple integer (maxtime format)
33+
testNumber(literalEval, "100", 100);
34+
35+
// Test 6: Float number
36+
testNumber(literalEval, "3.14", 3.14);
37+
38+
// Test 7: Negative number
39+
testNumber(literalEval, "-42", -42);
40+
41+
// Test 8: String value
42+
testString(literalEval, "'hello'", "hello");
43+
44+
// Test 9: Double-quoted string
45+
testString(literalEval, "\"world\"", "world");
46+
47+
// Test 10: Empty dictionary
48+
testEmptyDict(literalEval, "{}");
49+
50+
// Test 11: Empty list
51+
testEmptyList(literalEval, "[]");
52+
53+
// Test 12: Boolean True
54+
testBoolean(literalEval, "True", true);
55+
56+
// Test 13: Boolean False
57+
testBoolean(literalEval, "False", false);
58+
59+
// Test 14: Nested structure (dict with list value)
60+
testNestedDictList(literalEval, "{'values': [1, 2, 3]}");
61+
62+
// Test 15: Scientific notation
63+
testNumber(literalEval, "1.5e-3", 0.0015);
64+
65+
System.out.println("\n========================================");
66+
System.out.println("Results: " + passed + " passed, " + failed + " failed");
67+
System.out.println("========================================");
68+
69+
if (failed > 0) {
70+
System.exit(1);
71+
}
72+
}
73+
74+
@SuppressWarnings("unchecked")
75+
private static void testDict(Method literalEval, String input, String key, Object expectedValue) {
76+
try {
77+
Object result = literalEval.invoke(null, input);
78+
if (result instanceof Map) {
79+
Map<String, Object> map = (Map<String, Object>) result;
80+
if (map.containsKey(key)) {
81+
Object actual = map.get(key);
82+
if (actual instanceof Number && expectedValue instanceof Number) {
83+
if (((Number) actual).doubleValue() == ((Number) expectedValue).doubleValue()) {
84+
pass("Dict parse: " + input);
85+
return;
86+
}
87+
} else if (actual.equals(expectedValue)) {
88+
pass("Dict parse: " + input);
89+
return;
90+
}
91+
}
92+
}
93+
fail("Dict parse: " + input, "Expected key '" + key + "' = " + expectedValue + ", got: " + result);
94+
} catch (Exception e) {
95+
fail("Dict parse: " + input, e.getMessage());
96+
}
97+
}
98+
99+
private static void testList(Method literalEval, String input, int expectedSize) {
100+
try {
101+
Object result = literalEval.invoke(null, input);
102+
if (result instanceof List) {
103+
List<?> list = (List<?>) result;
104+
if (list.size() == expectedSize) {
105+
pass("List parse: " + input + " (size=" + expectedSize + ")");
106+
return;
107+
}
108+
fail("List parse: " + input, "Expected size " + expectedSize + ", got " + list.size());
109+
} else {
110+
fail("List parse: " + input, "Expected List, got " + result.getClass().getSimpleName());
111+
}
112+
} catch (Exception e) {
113+
fail("List parse: " + input, e.getMessage());
114+
}
115+
}
116+
117+
private static void testNumber(Method literalEval, String input, double expectedValue) {
118+
try {
119+
Object result = literalEval.invoke(null, input);
120+
if (result instanceof Number) {
121+
double actual = ((Number) result).doubleValue();
122+
if (Math.abs(actual - expectedValue) < 0.0001) {
123+
pass("Number parse: " + input + " = " + actual);
124+
return;
125+
}
126+
fail("Number parse: " + input, "Expected " + expectedValue + ", got " + actual);
127+
} else {
128+
fail("Number parse: " + input, "Expected Number, got " + result.getClass().getSimpleName());
129+
}
130+
} catch (Exception e) {
131+
fail("Number parse: " + input, e.getMessage());
132+
}
133+
}
134+
135+
private static void testString(Method literalEval, String input, String expectedValue) {
136+
try {
137+
Object result = literalEval.invoke(null, input);
138+
if (result instanceof String) {
139+
if (result.equals(expectedValue)) {
140+
pass("String parse: " + input);
141+
return;
142+
}
143+
fail("String parse: " + input, "Expected '" + expectedValue + "', got '" + result + "'");
144+
} else {
145+
fail("String parse: " + input, "Expected String, got " + result.getClass().getSimpleName());
146+
}
147+
} catch (Exception e) {
148+
fail("String parse: " + input, e.getMessage());
149+
}
150+
}
151+
152+
private static void testEmptyDict(Method literalEval, String input) {
153+
try {
154+
Object result = literalEval.invoke(null, input);
155+
if (result instanceof Map && ((Map<?,?>) result).isEmpty()) {
156+
pass("Empty dict parse: " + input);
157+
} else {
158+
fail("Empty dict parse: " + input, "Expected empty Map, got " + result);
159+
}
160+
} catch (Exception e) {
161+
fail("Empty dict parse: " + input, e.getMessage());
162+
}
163+
}
164+
165+
private static void testEmptyList(Method literalEval, String input) {
166+
try {
167+
Object result = literalEval.invoke(null, input);
168+
if (result instanceof List && ((List<?>) result).isEmpty()) {
169+
pass("Empty list parse: " + input);
170+
} else {
171+
fail("Empty list parse: " + input, "Expected empty List, got " + result);
172+
}
173+
} catch (Exception e) {
174+
fail("Empty list parse: " + input, e.getMessage());
175+
}
176+
}
177+
178+
private static void testBoolean(Method literalEval, String input, boolean expectedValue) {
179+
try {
180+
Object result = literalEval.invoke(null, input);
181+
if (result instanceof Boolean && result.equals(expectedValue)) {
182+
pass("Boolean parse: " + input);
183+
} else {
184+
fail("Boolean parse: " + input, "Expected " + expectedValue + ", got " + result);
185+
}
186+
} catch (Exception e) {
187+
fail("Boolean parse: " + input, e.getMessage());
188+
}
189+
}
190+
191+
@SuppressWarnings("unchecked")
192+
private static void testNestedDictList(Method literalEval, String input) {
193+
try {
194+
Object result = literalEval.invoke(null, input);
195+
if (result instanceof Map) {
196+
Map<String, Object> map = (Map<String, Object>) result;
197+
Object values = map.get("values");
198+
if (values instanceof List && ((List<?>) values).size() == 3) {
199+
pass("Nested dict/list parse: " + input);
200+
return;
201+
}
202+
}
203+
fail("Nested dict/list parse: " + input, "Got: " + result);
204+
} catch (Exception e) {
205+
fail("Nested dict/list parse: " + input, e.getMessage());
206+
}
207+
}
208+
209+
private static void pass(String test) {
210+
System.out.println("[PASS] " + test);
211+
passed++;
212+
}
213+
214+
private static void fail(String test, String reason) {
215+
System.out.println("[FAIL] " + test + " - " + reason);
216+
failed++;
217+
}
218+
}

0 commit comments

Comments
 (0)