diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/LuaBackendAuditTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/LuaBackendAuditTests.java index 786cb0361..ae565f849 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/LuaBackendAuditTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/LuaBackendAuditTests.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.Random; @@ -1544,7 +1545,10 @@ public void randomizedClassInterfaceModuleDispatchMatchesAllBackends() { public void randomizedGenericTupleDispatchMatchesJassAndLua() { Random random = new Random(0x71A9D15CL); for (int caseIndex = 0; caseIndex < 8; caseIndex++) { - List source = genericTupleDispatchCase(random, caseIndex); + EnumSet covered = EnumSet.noneOf(GenericDispatchShape.class); + List source = genericTupleDispatchCase(random, covered); + assertEquals("dispatch fuzz case must cover every semantic specialization shape", + EnumSet.allOf(GenericDispatchShape.class), covered); String[] lines = source.toArray(new String[0]); try { test().executeProg().lines(lines); @@ -1565,6 +1569,17 @@ public void randomizedGenericTupleDispatchMatchesJassAndLua() { } } + private enum GenericDispatchShape { + TUPLE_INT, + TUPLE_TEXT, + NESTED_TUPLE_INT, + NESTED_TUPLE_TEXT, + CLASS_PREDICATE, + OTHER_CLASS_PREDICATE, + OTHER_CLASS_PREDICATE_SECOND_TYPE, + CLASS_IMPLEMENTATION + } + /** A user method beginning with {@code destroy} is ordinary virtual dispatch, not lifecycle * destruction. The lifecycle slot is identified from the generated OnDestroy function. */ @Test @@ -1592,7 +1607,8 @@ public void ordinaryDestroyNamedMethodDoesNotUseLifecycleDispatchSlot() throws I assertFalse(dispatchBody.contains(".__wurst_destroy")); } - private List genericTupleDispatchCase(Random random, int caseIndex) { + private List genericTupleDispatchCase(Random random, + EnumSet covered) { List source = new ArrayList<>(); Collections.addAll(source, "package Test", @@ -1636,46 +1652,59 @@ private List genericTupleDispatchCase(Random random, int caseIndex) { " int successes = 0"); int expected = 0; + List shapes = new ArrayList<>( + EnumSet.allOf(GenericDispatchShape.class)); + Collections.shuffle(shapes, random); for (int i = 0; i < 16; i++) { int value = random.nextInt(100) + 1; - switch (random.nextInt(7)) { - case 0 -> { + GenericDispatchShape shape = i < shapes.size() + ? shapes.get(i) + : shapes.get(random.nextInt(shapes.size())); + covered.add(shape); + switch (shape) { + case TUPLE_INT -> { source.add(" let value" + i + " = new Box(PairInt(" + value + ", " + (value + 1) + "))"); source.add(" if value" + i + ".matches(x -> x.a == " + value + ")"); source.add(" successes++"); source.add(" destroy value" + i); } - case 1 -> { + case TUPLE_TEXT -> { source.add(" let value" + i + " = new Box(PairText(\"v" + value + "\", " + value + "))"); source.add(" if value" + i + ".matches(x -> x.a == \"v" + value + "\")"); source.add(" successes++"); source.add(" destroy value" + i); } - case 2 -> { + case NESTED_TUPLE_INT -> { source.add(" let value" + i + " = new Nested(PairInt(" + value + ", " + (value + 2) + "))"); source.add(" if value" + i + ".matches(x -> x.b == " + (value + 2) + ")"); source.add(" successes++"); source.add(" destroy value" + i); } - case 3 -> { + case NESTED_TUPLE_TEXT -> { + source.add(" let value" + i + " = new Nested(PairText(\"v" + value + "\", " + value + "))"); + source.add(" if value" + i + ".matches(x -> x.a == \"v" + value + "\")"); + source.add(" successes++"); + source.add(" destroy value" + i); + } + case CLASS_PREDICATE -> { source.add(" let value" + i + " = new Box(new Foo())"); source.add(" if value" + i + ".matches(x -> x != null)"); source.add(" successes++"); source.add(" destroy value" + i); } - case 4 -> { + case OTHER_CLASS_PREDICATE -> { source.add(" let value" + i + " = new OtherBox(new Foo())"); source.add(" if value" + i + ".matches(x -> x != null)"); source.add(" successes++"); source.add(" destroy value" + i); } - case 5 -> { + case OTHER_CLASS_PREDICATE_SECOND_TYPE -> { source.add(" let value" + i + " = new OtherBox(new Bar())"); source.add(" if value" + i + ".matches(x -> x != null)"); source.add(" successes++"); source.add(" destroy value" + i); } - default -> { + case CLASS_IMPLEMENTATION -> { source.add(" let value" + i + " = new Box(new Foo())"); source.add(" if value" + i + ".matches(new FooPredicate())"); source.add(" successes++");