|
|
|
@@ -0,0 +1,142 @@
|
|
|
|
|
package com.octoturge.mcmapper.common.json;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hand-rolled test runner (no JUnit) for {@link MiniJson}, following the same
|
|
|
|
|
* "common/ must compile and run standalone under plain javac" constraint as the class under
|
|
|
|
|
* test — see common/README.md for why, and common/run-tests.sh to actually run this.
|
|
|
|
|
*/
|
|
|
|
|
public class MiniJsonTest {
|
|
|
|
|
private static int passed = 0;
|
|
|
|
|
private static int failed = 0;
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
test("writeObject encodes strings, numbers, booleans, and null", MiniJsonTest::writesScalars);
|
|
|
|
|
test("writeObject escapes special characters in strings", MiniJsonTest::escapesStrings);
|
|
|
|
|
test("writeObject encodes nested objects and arrays", MiniJsonTest::writesNestedStructures);
|
|
|
|
|
test("parse reads a hello_ack-shaped object", MiniJsonTest::parsesHelloAck);
|
|
|
|
|
test("parse reads nested arrays of objects (a columns message)", MiniJsonTest::parsesColumnsMessage);
|
|
|
|
|
test("parse unescapes strings", MiniJsonTest::parseUnescapesStrings);
|
|
|
|
|
test("parse reads numbers as Double, including negatives", MiniJsonTest::parsesNumbers);
|
|
|
|
|
test("write-then-parse round-trips a columns-shaped message", MiniJsonTest::roundTripsColumnsMessage);
|
|
|
|
|
|
|
|
|
|
System.out.println();
|
|
|
|
|
System.out.println(passed + " passed, " + failed + " failed");
|
|
|
|
|
if (failed > 0) {
|
|
|
|
|
System.exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void writesScalars() {
|
|
|
|
|
Map<String, Object> obj = new LinkedHashMap<>();
|
|
|
|
|
obj.put("type", "hello");
|
|
|
|
|
obj.put("ok", true);
|
|
|
|
|
obj.put("count", 3.0);
|
|
|
|
|
obj.put("missing", null);
|
|
|
|
|
assertEquals("{\"type\":\"hello\",\"ok\":true,\"count\":3.0,\"missing\":null}", MiniJson.writeObject(obj));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void escapesStrings() {
|
|
|
|
|
Map<String, Object> obj = new LinkedHashMap<>();
|
|
|
|
|
obj.put("text", "line1\nline2\t\"quoted\"\\backslash");
|
|
|
|
|
String json = MiniJson.writeObject(obj);
|
|
|
|
|
assertEquals("{\"text\":\"line1\\nline2\\t\\\"quoted\\\"\\\\backslash\"}", json);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void writesNestedStructures() {
|
|
|
|
|
Map<String, Object> column = new LinkedHashMap<>();
|
|
|
|
|
column.put("x", 1.0);
|
|
|
|
|
column.put("z", 2.0);
|
|
|
|
|
List<Object> columns = new ArrayList<>();
|
|
|
|
|
columns.add(column);
|
|
|
|
|
Map<String, Object> msg = new LinkedHashMap<>();
|
|
|
|
|
msg.put("type", "columns");
|
|
|
|
|
msg.put("columns", columns);
|
|
|
|
|
assertEquals("{\"type\":\"columns\",\"columns\":[{\"x\":1.0,\"z\":2.0}]}", MiniJson.writeObject(msg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
private static void parsesHelloAck() {
|
|
|
|
|
Object parsed = MiniJson.parse("{\"type\":\"hello_ack\",\"ok\":true,\"serverId\":\"abc-123\"}");
|
|
|
|
|
Map<String, Object> obj = (Map<String, Object>) parsed;
|
|
|
|
|
assertEquals("hello_ack", obj.get("type"));
|
|
|
|
|
assertEquals(Boolean.TRUE, obj.get("ok"));
|
|
|
|
|
assertEquals("abc-123", obj.get("serverId"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
private static void parsesColumnsMessage() {
|
|
|
|
|
String json = "{\"type\":\"columns\",\"dimension\":0,\"columns\":["
|
|
|
|
|
+ "{\"x\":1,\"z\":2,\"height\":64,\"blockId\":2,\"blockMeta\":0},"
|
|
|
|
|
+ "{\"x\":3,\"z\":4,\"height\":65,\"blockId\":3,\"blockMeta\":0}]}";
|
|
|
|
|
Map<String, Object> obj = (Map<String, Object>) MiniJson.parse(json);
|
|
|
|
|
List<Object> columns = (List<Object>) obj.get("columns");
|
|
|
|
|
assertEquals(2, columns.size());
|
|
|
|
|
Map<String, Object> first = (Map<String, Object>) columns.get(0);
|
|
|
|
|
assertEquals(1.0, first.get("x"));
|
|
|
|
|
assertEquals(64.0, first.get("height"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
private static void parseUnescapesStrings() {
|
|
|
|
|
Map<String, Object> obj = (Map<String, Object>) MiniJson.parse("{\"error\":\"bad \\\"token\\\"\\nvalue\"}");
|
|
|
|
|
assertEquals("bad \"token\"\nvalue", obj.get("error"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
private static void parsesNumbers() {
|
|
|
|
|
Map<String, Object> obj = (Map<String, Object>) MiniJson.parse("{\"a\":-5,\"b\":3.5,\"c\":0}");
|
|
|
|
|
assertEquals(-5.0, obj.get("a"));
|
|
|
|
|
assertEquals(3.5, obj.get("b"));
|
|
|
|
|
assertEquals(0.0, obj.get("c"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
private static void roundTripsColumnsMessage() {
|
|
|
|
|
// Mirrors exactly what DefaultBackendConnection.sendDeltas() builds — the real
|
|
|
|
|
// regression risk isn't MiniJson in isolation, it's this shape drifting silently.
|
|
|
|
|
Map<String, Object> col = new LinkedHashMap<>();
|
|
|
|
|
col.put("x", 7.0);
|
|
|
|
|
col.put("z", -3.0);
|
|
|
|
|
col.put("height", 70.0);
|
|
|
|
|
col.put("blockId", 2.0);
|
|
|
|
|
col.put("blockMeta", 0.0);
|
|
|
|
|
List<Object> columns = new ArrayList<>();
|
|
|
|
|
columns.add(col);
|
|
|
|
|
Map<String, Object> msg = new LinkedHashMap<>();
|
|
|
|
|
msg.put("type", "columns");
|
|
|
|
|
msg.put("dimension", 0.0);
|
|
|
|
|
msg.put("columns", columns);
|
|
|
|
|
|
|
|
|
|
String json = MiniJson.writeObject(msg);
|
|
|
|
|
Map<String, Object> reparsed = (Map<String, Object>) MiniJson.parse(json);
|
|
|
|
|
assertEquals("columns", reparsed.get("type"));
|
|
|
|
|
assertEquals(0.0, reparsed.get("dimension"));
|
|
|
|
|
List<Object> reparsedColumns = (List<Object>) reparsed.get("columns");
|
|
|
|
|
Map<String, Object> reparsedCol = (Map<String, Object>) reparsedColumns.get(0);
|
|
|
|
|
assertEquals(7.0, reparsedCol.get("x"));
|
|
|
|
|
assertEquals(-3.0, reparsedCol.get("z"));
|
|
|
|
|
assertEquals(2.0, reparsedCol.get("blockId"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void test(String name, Runnable body) {
|
|
|
|
|
try {
|
|
|
|
|
body.run();
|
|
|
|
|
passed++;
|
|
|
|
|
System.out.println("PASS " + name);
|
|
|
|
|
} catch (AssertionError e) {
|
|
|
|
|
failed++;
|
|
|
|
|
System.out.println("FAIL " + name + " — " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void assertEquals(Object expected, Object actual) {
|
|
|
|
|
if (expected == null ? actual != null : !expected.equals(actual)) {
|
|
|
|
|
throw new AssertionError("expected <" + expected + "> but got <" + actual + ">");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|