diff --git a/src/functionalTest/java/codechicken/multipart/test/TMicroOcclusionFunctionalTest.java b/src/functionalTest/java/codechicken/multipart/test/TMicroOcclusionFunctionalTest.java new file mode 100644 index 0000000..7ff82b1 --- /dev/null +++ b/src/functionalTest/java/codechicken/multipart/test/TMicroOcclusionFunctionalTest.java @@ -0,0 +1,85 @@ +package codechicken.multipart.test; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import codechicken.microblock.CornerMicroClass$; +import codechicken.microblock.EdgeMicroClass$; +import codechicken.microblock.FaceMicroClass$; +import codechicken.microblock.MicroMaterialRegistry; +import codechicken.microblock.Microblock; +import codechicken.microblock.MicroblockGenerator; + +class TMicroOcclusionFunctionalTest { + + @Test + void generatedFacePairsRejectOnlyOpposingThicknessOverflowRegardlessOfMaterial() { + int stone = MicroMaterialRegistry.materialID("minecraft:stone"); + int glass = MicroMaterialRegistry.materialID("minecraft:glass"); + assertNotEquals(stone, glass); + Microblock first = MicroblockGenerator.create(FaceMicroClass$.MODULE$, stone, false); + for (int material : new int[] { stone, glass }) { + Microblock second = MicroblockGenerator.create(FaceMicroClass$.MODULE$, material, false); + for (int side = 0; side < 6; side++) { + for (int other = 0; other < 6; other++) { + for (int size = 1; size <= 7; size++) { + for (int otherSize = 1; otherSize <= 7; otherSize++) { + first.setShape(size, side); + second.setShape(otherSize, other); + boolean expected = other != (side ^ 1) || size + otherSize <= 8; + assertEquals( + expected, + first.occlusionTest(second), + "sides=" + side + "," + other + " sizes=" + size + "," + otherSize); + assertEquals(expected, second.occlusionTest(first)); + } + } + } + } + } + } + + @Test + void generatedCornerAndEdgePairsKeepMaterialBoundariesAndAxisRulesInBothDirections() { + int stone = MicroMaterialRegistry.materialID("minecraft:stone"); + int glass = MicroMaterialRegistry.materialID("minecraft:glass"); + assertNotEquals(stone, glass); + Microblock corner = MicroblockGenerator.create(CornerMicroClass$.MODULE$, stone, false); + Microblock edge = MicroblockGenerator.create(EdgeMicroClass$.MODULE$, stone, false); + int[] masks = { 6, 5, 3 }; + int[] edgePositions = { 0, 2, 4, 6, 0, 4, 1, 5, 0, 1, 2, 3 }; + for (int material : new int[] { stone, glass }) { + Microblock otherCorner = MicroblockGenerator.create(CornerMicroClass$.MODULE$, material, false); + Microblock otherEdge = MicroblockGenerator.create(EdgeMicroClass$.MODULE$, material, false); + for (int[] sizes : new int[][] { { 2, 6 }, { 3, 6 }, { 7, 7 } }) { + boolean restricted = material != stone && sizes[0] + sizes[1] > 8; + for (int c = 0; c < 8; c++) { + corner.setShape(sizes[0], 7 + c); + for (int other = 0; other < 8; other++) { + otherCorner.setShape(sizes[1], 7 + other); + int difference = Integer.bitCount(c ^ other); + assertBoth(!restricted || difference != 2, corner, otherCorner); + } + for (int e = 0; e < 12; e++) { + otherEdge.setShape(sizes[1], 15 + e); + assertBoth(!restricted || (c & masks[e / 4]) == edgePositions[e], corner, otherEdge); + } + } + for (int e = 0; e < 12; e++) { + edge.setShape(sizes[0], 15 + e); + for (int other = 0; other < 12; other++) { + otherEdge.setShape(sizes[1], 15 + other); + boolean oppositeParallel = e / 4 == other / 4 && (e % 4 + other % 4 == 3); + assertBoth(!restricted || !oppositeParallel, edge, otherEdge); + } + } + } + } + } + + private static void assertBoth(boolean expected, Microblock first, Microblock second) { + assertEquals(expected, first.occlusionTest(second)); + assertEquals(expected, second.occlusionTest(first)); + } +} diff --git a/src/test/fixtures/README.md b/src/test/fixtures/README.md index 09c48ab..d3ea775 100644 --- a/src/test/fixtures/README.md +++ b/src/test/fixtures/README.md @@ -283,3 +283,19 @@ Compiled with Scala 2.11.5 under Java 8, `-target:jvm-1.8`, against the untouche | --- | --- | | `ReferenceHollowClientBase` | `fe39f52cd776ded56adceb27ed011f3f72d405ee363dcb54877717e18de16450` | | `ReferenceScalaHollowMicroblockClient` | `5b11e01e3995bc314ffa10d129da7277e386edfe08520370e6b3ee40bdd18c67` | + +### `ReferenceScalaTMicroOcclusion` + +`scala/codechicken/multipart/compat/ReferenceScalaTMicroOcclusion.scala` freezes a trait implementor with a real +superclass predecessor. Tests pin super/type-guard ordering, repeated slot reads, signed size overflow, material +short-circuits, own-receiver edge/corner delegation, getter failures and the two independent edge reads. + +Compiled with Scala 2.11.5 under Java 8, `-target:jvm-1.8`, against the untouched dev jar at `a50ce52` +(SHA-256 `241e6315ddae2b09bb2baed7f28b545985f1cf329504288cc6de454b25c945fb`). Source SHA-256 is +`087afdc786c5ac59e70c5152f183bd0cc27e65de1672ece549870fb04f09b4ab`. Frozen class files under +`src/test/resources/compat/` have these SHA-256s; do not regenerate against the port: + +| Class | SHA-256 | +| --- | --- | +| `ReferenceMicroOcclusionBase` | `f3c7c10095fd19d6e18edcee345c4ea5e22557b07595e5274e46be36d0edcb1b` | +| `ReferenceScalaTMicroOcclusion` | `d92b9b9d938e8e85b364193807e878f7eb595c099205a4ded84fb1363e11639d` | diff --git a/src/test/fixtures/scala/codechicken/multipart/compat/ReferenceScalaTMicroOcclusion.scala b/src/test/fixtures/scala/codechicken/multipart/compat/ReferenceScalaTMicroOcclusion.scala new file mode 100644 index 0000000..514b289 --- /dev/null +++ b/src/test/fixtures/scala/codechicken/multipart/compat/ReferenceScalaTMicroOcclusion.scala @@ -0,0 +1,45 @@ +package codechicken.multipart.compat + +import codechicken.lib.vec.Cuboid6 +import codechicken.microblock.TMicroOcclusion +import codechicken.multipart.TMultiPart + +abstract class ReferenceMicroOcclusionBase extends TMultiPart { + var events: java.util.List[String] = new java.util.ArrayList[String]() + var label = "self" + var superResult = true + var superFailure = false + override def occlusionTest(other: TMultiPart): Boolean = { + events.add("super:" + label) + if (superFailure) throw new IllegalStateException("super") + superResult + } +} + +/** Frozen Scala trait forwarders with a real superclass and observable virtual calls. */ +class ReferenceScalaTMicroOcclusion extends ReferenceMicroOcclusionBase with TMicroOcclusion { + var slot = 0 + var slotAdvance = 0 + var size = 5 + var material = 0 + var failOn = "" + var useActualEdge = true + var edgeResult = true + var seenEdge: TMicroOcclusion = null + var seenCorner: TMicroOcclusion = null + def getType = "test:micro_occlusion" + def getBounds: Cuboid6 = throw new AssertionError("bounds must not be read") + private def record(name: String) { + events.add(name + ":" + label) + if (failOn == name) throw new IllegalStateException(name) + } + def getSlot = { record("slot"); val result = slot; slot += slotAdvance; result } + def getSize = { record("size"); size } + def getMaterial = { record("material"); material } + override def edgeCornerOcclusionTest(edge: TMicroOcclusion, corner: TMicroOcclusion): Boolean = { + record("edge") + seenEdge = edge + seenCorner = corner + if (useActualEdge) super.edgeCornerOcclusionTest(edge, corner) else edgeResult + } +} diff --git a/src/test/java/codechicken/microblock/TMicroOcclusionCharacterizationTest.java b/src/test/java/codechicken/microblock/TMicroOcclusionCharacterizationTest.java new file mode 100644 index 0000000..3a6f6ab --- /dev/null +++ b/src/test/java/codechicken/microblock/TMicroOcclusionCharacterizationTest.java @@ -0,0 +1,269 @@ +package codechicken.microblock; + +import static org.junit.jupiter.api.Assertions.*; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Scanner; + +import org.junit.jupiter.api.Test; + +import codechicken.multipart.TMultiPart; + +class TMicroOcclusionCharacterizationTest { + + @Test + void superclassRunsOnceBeforeNullAndNonMicroblockGuards() throws Exception { + Fixture f = new Fixture(); + TMultiPart plain = new TMultiPart() { + + @Override + public String getType() { + throw new AssertionError("type lookup"); + } + }; + for (TMultiPart candidate : new TMultiPart[] { null, plain, f.other }) { + f.set(f.part, "superResult", boolean.class, false); + f.events.clear(); + assertFalse(f.part.occlusionTest(candidate)); + assertEquals(Collections.singletonList("super:self"), f.events); + } + f.set(f.part, "superResult", boolean.class, true); + for (TMultiPart candidate : new TMultiPart[] { null, plain }) { + f.events.clear(); + assertTrue(f.part.occlusionTest(candidate)); + assertEquals(Collections.singletonList("super:self"), f.events); + } + f.set(f.part, "superFailure", boolean.class, true); + f.events.clear(); + assertEquals("super", assertThrows(IllegalStateException.class, () -> f.part.occlusionTest(null)).getMessage()); + assertEquals(Collections.singletonList("super:self"), f.events); + } + + @Test + void sizeThresholdUsesOtherThenSelfAndKeepsSignedOverflow() throws Exception { + Fixture f = new Fixture(); + f.configure(f.part, 0, 4, 0); + f.configure(f.other, 1, 4, 1); + int[][] sizes = { { 4, 4 }, { -1, 9 }, { Integer.MAX_VALUE, Integer.MAX_VALUE }, { Integer.MIN_VALUE, 0 } }; + for (int[] pair : sizes) { + f.set(f.part, "size", int.class, pair[0]); + f.set(f.other, "size", int.class, pair[1]); + f.events.clear(); + assertTrue(f.part.occlusionTest(f.other)); + assertEquals(Arrays.asList("super:self", "slot:self", "slot:other", "size:other", "size:self"), f.events); + } + f.set(f.part, "size", int.class, Integer.MIN_VALUE); + f.set(f.other, "size", int.class, -1); + assertFalse(f.part.occlusionTest(f.other)); + } + + @Test + void opposingFacesRereadOtherSlotBeforeOwnAndBypassMaterials() throws Exception { + Fixture f = new Fixture(); + f.configure(f.part, 0, 5, 0); + f.configure(f.other, 0, 5, 0); + f.set(f.part, "slotAdvance", int.class, 1); + f.set(f.part, "failOn", String.class, "material"); + f.set(f.other, "failOn", String.class, "material"); + assertFalse(f.part.occlusionTest(f.other)); + assertEquals( + Arrays.asList( + "super:self", + "slot:self", + "slot:other", + "size:other", + "size:self", + "slot:other", + "slot:self"), + f.events); + } + + @Test + void matchingMaterialsBypassCornerAndEdgeRulesAfterOtherFirstMaterialReads() throws Exception { + Fixture f = new Fixture(); + for (int[] slots : new int[][] { { 7, 10 }, { 15, 18 }, { 15, 8 } }) { + f.configure(f.part, slots[0], 5, 17); + f.configure(f.other, slots[1], 5, 17); + f.set(f.part, "failOn", String.class, "edge"); + f.events.clear(); + assertTrue(f.part.occlusionTest(f.other)); + assertEquals( + Arrays.asList( + "super:self", + "slot:self", + "slot:other", + "size:other", + "size:self", + "material:other", + "material:self"), + f.events); + } + } + + @Test + void diagonalCornersAndOppositeParallelEdgesUseFreshSlotsWithoutBounds() throws Exception { + Fixture f = new Fixture(); + for (int[] slots : new int[][] { { 7, 10 }, { 15, 18 } }) { + f.configure(f.part, slots[0], 5, 0); + f.configure(f.other, slots[1], 5, 1); + f.events.clear(); + assertFalse(f.part.occlusionTest(f.other)); + assertEquals( + Arrays.asList( + "super:self", + "slot:self", + "slot:other", + "size:other", + "size:self", + "material:other", + "material:self", + "slot:self", + "slot:other"), + f.events); + f.configure(f.part, slots[0], 5, 0); + f.configure(f.other, slots[1], 5, 1); + f.set(f.part, "slotAdvance", int.class, 1); + assertTrue(f.part.occlusionTest(f.other)); + f.set(f.part, "slotAdvance", int.class, 0); + } + // Slot 6 follows the reference's corner priority; it is not rejected as an invalid face slot. + f.configure(f.part, 6, 5, 0); + f.configure(f.other, 7, 5, 1); + assertTrue(f.part.occlusionTest(f.other)); + f.configure(f.part, -1, 5, 0); + f.configure(f.other, -2, 5, 1); + assertFalse(f.part.occlusionTest(f.other)); + } + + @Test + void edgeCornerDelegationUsesOwnOverrideAndPassesEdgeFirstInBothDirections() throws Exception { + Fixture f = new Fixture(); + f.set(f.part, "useActualEdge", boolean.class, false); + f.set(f.other, "failOn", String.class, "edge"); + for (boolean ownIsEdge : new boolean[] { false, true }) { + f.configure(f.part, ownIsEdge ? 15 : 7, 5, 0); + f.configure(f.other, ownIsEdge ? 7 : 15, 5, 1); + for (boolean result : new boolean[] { false, true }) { + f.set(f.part, "edgeResult", boolean.class, result); + f.events.clear(); + assertEquals(result, f.part.occlusionTest(f.other)); + assertEquals( + Arrays.asList( + "super:self", + "slot:self", + "slot:other", + "size:other", + "size:self", + "material:other", + "material:self", + "edge:self"), + f.events); + assertSame(ownIsEdge ? f.part : f.other, f.part.getClass().getMethod("seenEdge").invoke(f.part)); + assertSame(ownIsEdge ? f.other : f.part, f.part.getClass().getMethod("seenCorner").invoke(f.part)); + } + } + } + + @Test + void edgeCornerMappingKeepsCornerFirstAndTwoIndependentEdgeReads() throws Exception { + Fixture f = new Fixture(); + int[] masks = { 6, 5, 3 }; + int[] positions = { 0, 2, 4, 6, 0, 4, 1, 5, 0, 1, 2, 3 }; + for (int edge = 0; edge < 12; edge++) { + f.configure(f.part, 15 + edge, 5, 0); + for (int corner = 0; corner < 8; corner++) { + f.configure(f.other, 7 + corner, 5, 1); + f.events.clear(); + assertEquals( + (corner & masks[edge / 4]) == positions[edge], + f.micro.edgeCornerOcclusionTest(f.micro, f.otherMicro)); + assertEquals(Arrays.asList("edge:self", "slot:other", "slot:self", "slot:self"), f.events); + } + } + f.configure(f.part, 16, 5, 0); + f.configure(f.other, 11, 5, 1); + f.set(f.part, "slotAdvance", int.class, 4); + assertTrue(f.micro.edgeCornerOcclusionTest(f.micro, f.otherMicro)); + f.configure(f.part, 15, 5, 0); + f.set(f.part, "slotAdvance", int.class, 12); + f.events.clear(); + assertEquals( + "Switch Falloff", + assertThrows( + IllegalArgumentException.class, + () -> f.micro.edgeCornerOcclusionTest(f.micro, f.otherMicro)).getMessage()); + assertEquals(Arrays.asList("edge:self", "slot:other", "slot:self", "slot:self"), f.events); + f.configure(f.part, 27, 5, 0); + f.events.clear(); + assertThrows(IllegalArgumentException.class, () -> f.micro.edgeCornerOcclusionTest(f.micro, f.otherMicro)); + assertEquals(Arrays.asList("edge:self", "slot:other", "slot:self"), f.events); + f.events.clear(); + assertThrows(NullPointerException.class, () -> f.micro.edgeCornerOcclusionTest(null, null)); + assertEquals(Collections.singletonList("edge:self"), f.events); + } + + @Test + void getterFailuresStopBeforeLaterVirtualReads() throws Exception { + Fixture f = new Fixture(); + f.configure(f.part, 7, 5, 0); + f.configure(f.other, 10, 5, 1); + String[] expected = { "super:self", "slot:self", "slot:other", "size:other", "size:self", "material:other", + "material:self" }; + for (int i = 1; i < expected.length; i++) { + String[] pieces = expected[i].split(":"); + TMultiPart failing = pieces[1].equals("self") ? f.part : f.other; + f.set(failing, "failOn", String.class, pieces[0]); + f.events.clear(); + assertEquals( + pieces[0], + assertThrows(IllegalStateException.class, () -> f.part.occlusionTest(f.other)).getMessage()); + assertEquals(Arrays.asList(Arrays.copyOf(expected, i + 1)), f.events); + f.set(failing, "failOn", String.class, ""); + } + } + + private static final class Fixture extends ClassLoader { + + final List events = new ArrayList<>(); + final TMultiPart part; + final TMultiPart other; + final TMicroOcclusion micro; + final TMicroOcclusion otherMicro; + + Fixture() throws Exception { + super(TMultiPart.class.getClassLoader()); + for (String name : new String[] { "ReferenceMicroOcclusionBase", "ReferenceScalaTMicroOcclusion" }) { + byte[] bytes; + try (Scanner scanner = new Scanner( + getResourceAsStream("compat/" + name + ".class.b64"), + StandardCharsets.US_ASCII.name()).useDelimiter("\\A")) { + bytes = Base64.getMimeDecoder().decode(scanner.next()); + } + defineClass(null, bytes, 0, bytes.length); + } + Class type = loadClass("codechicken.multipart.compat.ReferenceScalaTMicroOcclusion"); + part = (TMultiPart) type.getConstructor().newInstance(); + other = (TMultiPart) type.getConstructor().newInstance(); + micro = (TMicroOcclusion) part; + otherMicro = (TMicroOcclusion) other; + set(part, "events", List.class, events); + set(other, "events", List.class, events); + set(other, "label", String.class, "other"); + } + + void set(TMultiPart target, String name, Class type, Object value) throws Exception { + target.getClass().getMethod(name + "_$eq", type).invoke(target, value); + } + + void configure(TMultiPart target, int slot, int size, int material) throws Exception { + set(target, "slot", int.class, slot); + set(target, "size", int.class, size); + set(target, "material", int.class, material); + } + } +} diff --git a/src/test/resources/compat/ReferenceMicroOcclusionBase.class.b64 b/src/test/resources/compat/ReferenceMicroOcclusionBase.class.b64 new file mode 100644 index 0000000..4bd27d4 --- /dev/null +++ b/src/test/resources/compat/ReferenceMicroOcclusionBase.class.b64 @@ -0,0 +1 @@ +yv66vgAAADQAXQEAOGNvZGVjaGlja2VuL211bHRpcGFydC9jb21wYXQvUmVmZXJlbmNlTWljcm9PY2NsdXNpb25CYXNlBwABAQAgY29kZWNoaWNrZW4vbXVsdGlwYXJ0L1RNdWx0aVBhcnQHAAMBACNSZWZlcmVuY2VTY2FsYVRNaWNyb09jY2x1c2lvbi5zY2FsYQEAHkxzY2FsYS9yZWZsZWN0L1NjYWxhU2lnbmF0dXJlOwEABWJ5dGVzAQLQBgFlM1EhAQICAiURMURVM2dLSixnblkzTlMOFHhuVDJkWVYcGG4cOENDTiwnQkECBQMZGXcuHDliaSoRUUFCAQpbVmRHLxs5YmVSVBFhQgEMRz4kV20ZNWpHLixnbgEBFAUBUQFDQQYNGwUhEUJBBwUFKSFWKh43dVNCCycPHgUGHwEhCQFFAQd5JXQXDh4gFQNFASJBBQEOAwlBcQEGAUECEwVRIwEEZm0WdEdvXQsCLUEZcQMIEA4DYVEhIQcOAglVJBgOHAYCNwUhIS4ZPGITCWkCRAEDTVNOJAhDQRAmHQkBMyVEASIVBRETIUI6ZEMyDBdCARMiAxkBJi8aM2ZNJhFhZQoCBydSFBhOXDQLBREKA2JCFQEBBCUJQUsBC0taLGcOXjpgSRUMSENBFi8hCQFDJgMCLkMJIVFLXDV1ER15AyYhQUECWQkxAR8TMhEZCQQBKVEFLQU5UU1eM29pTgQDYkIaAQEEJQkBTgEGWQYUVw1cCwJrQRFhJ08HAm8pEQFIRwEFWQZ0dy0DAidvITkxCAFhAQoDYRQhAzdiRRZkdwxKM3IpCVlTCEMEMHUFBQkZQRsJDX0CARUpAzYDGWEXTVkzbUEhOREJAWEBCgMRFWFDOnZhFhQoK1o6dllSLBJhEQkDQRFLISFSEQMPCXt3DlwzYl0iOXEJAWEBCgNBFWFEOnZhFhQoK1o6dllSfEYlWjkVBS1KBWJCGEcDAwUNYREFBxcCAQsVQiICGU0sCC8aOlNLTixIDh4RCQ81AwEZIUMBBQZhMS8eOWZlGgsXDlw7c0siOXEKAWEBCgMBFgFFOnZhFhRoKVk1bWtKLHcMSjNyKQlZEwtDBDAdBgUJGUEiCQ1NAwEVKQNEAzUZWA9dM3MNBkxHLh46ZkEhKVELAUMhLQZpcW5ZMm1rTkx3ThwrZmdSJCJhUSwJC2EjBhkBBgILPSQILho6AQAGZXZlbnRzAQAQTGphdmEvdXRpbC9MaXN0OwEAJExqYXZhL3V0aWwvTGlzdDxMamF2YS9sYW5nL1N0cmluZzs+OwEABWxhYmVsAQASTGphdmEvbGFuZy9TdHJpbmc7AQALc3VwZXJSZXN1bHQBAAFaAQAMc3VwZXJGYWlsdXJlAQASKClMamF2YS91dGlsL0xpc3Q7DAAJAAoJAAIAEgEABHRoaXMBADpMY29kZWNoaWNrZW4vbXVsdGlwYXJ0L2NvbXBhdC9SZWZlcmVuY2VNaWNyb09jY2x1c2lvbkJhc2U7AQAKZXZlbnRzXyRlcQEAEyhMamF2YS91dGlsL0xpc3Q7KVYBAAN4JDEBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwwADAANCQACABoBAAlsYWJlbF8kZXEBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAMoKVoMAA4ADwkAAgAfAQAPc3VwZXJSZXN1bHRfJGVxAQAEKFopVgwAEAAPCQACACMBABBzdXBlckZhaWx1cmVfJGVxAQANb2NjbHVzaW9uVGVzdAEAJShMY29kZWNoaWNrZW4vbXVsdGlwYXJ0L1RNdWx0aVBhcnQ7KVoMAAkAEQoAAgAoAQAmc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL1N0cmluZ0J1aWxkZXIHACoBAAY8aW5pdD4BAAMoKVYMACwALQoAKwAuAQAGc3VwZXI6CAAwAQAGYXBwZW5kAQA8KExqYXZhL2xhbmcvT2JqZWN0OylMc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL1N0cmluZ0J1aWxkZXI7DAAyADMKACsANAwADAAZCgACADYBAAh0b1N0cmluZwwAOAAZCgArADkBAA5qYXZhL3V0aWwvTGlzdAcAOwEAA2FkZAEAFShMamF2YS9sYW5nL09iamVjdDspWgwAPQA+CwA8AD8MABAAHgoAAgBBAQAfamF2YS9sYW5nL0lsbGVnYWxTdGF0ZUV4Y2VwdGlvbgcAQwEABXN1cGVyCABFDAAsAB0KAEQARwwADgAeCgACAEkBAAVvdGhlcgEAIkxjb2RlY2hpY2tlbi9tdWx0aXBhcnQvVE11bHRpUGFydDsKAAQALgEAE2phdmEvdXRpbC9BcnJheUxpc3QHAE4KAE8ALgEABHNlbGYIAFEBAAlTaWduYXR1cmUBAARDb2RlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAPTGluZU51bWJlclRhYmxlAQAmKClMamF2YS91dGlsL0xpc3Q8TGphdmEvbGFuZy9TdHJpbmc7PjsBACcoTGphdmEvdXRpbC9MaXN0PExqYXZhL2xhbmcvU3RyaW5nOz47KVYBAA1TdGFja01hcFRhYmxlAQAKU291cmNlRmlsZQEAGVJ1bnRpbWVWaXNpYmxlQW5ub3RhdGlvbnMBAAhTY2FsYVNpZwQhAAIABAAAAAQAAgAJAAoAAQBTAAAAAgALAAIADAANAAAAAgAOAA8AAAACABAADwAAAAoAAQAJABEAAgBUAAAALwABAAEAAAAFKrQAE7AAAAACAFUAAAAMAAEAAAAFABQAFQAAAFYAAAAGAAEAAAAIAFMAAAACAFcAAQAWABcAAgBUAAAAOgACAAIAAAAGKiu1ABOxAAAAAgBVAAAAFgACAAAABgAUABUAAAAAAAYAGAAKAAEAVgAAAAYAAQAAAAgAUwAAAAIAWAABAAwAGQABAFQAAAAvAAEAAQAAAAUqtAAbsAAAAAIAVQAAAAwAAQAAAAUAFAAVAAAAVgAAAAYAAQAAAAkAAQAcAB0AAQBUAAAAOgACAAIAAAAGKiu1ABuxAAAAAgBVAAAAFgACAAAABgAUABUAAAAAAAYAGAANAAEAVgAAAAYAAQAAAAkAAQAOAB4AAQBUAAAALwABAAEAAAAFKrQAIKwAAAACAFUAAAAMAAEAAAAFABQAFQAAAFYAAAAGAAEAAAAKAAEAIQAiAAEAVAAAADoAAgACAAAABiobtQAgsQAAAAIAVQAAABYAAgAAAAYAFAAVAAAAAAAGABgADwABAFYAAAAGAAEAAAAKAAEAEAAeAAEAVAAAAC8AAQABAAAABSq0ACSsAAAAAgBVAAAADAABAAAABQAUABUAAABWAAAABgABAAAACwABACUAIgABAFQAAAA6AAIAAgAAAAYqG7UAJLEAAAACAFUAAAAWAAIAAAAGABQAFQAAAAAABgAYAA8AAQBWAAAABgABAAAACwABACYAJwABAFQAAAB7AAMAAgAAADYqtgApuwArWbcALxIxtgA1KrYAN7YANbYAOrkAQAIAVyq2AEKZAA27AERZEka3AEi/KrYASqwAAAADAFUAAAAWAAIAAAA2ABQAFQAAAAAANgBLAEwAAQBWAAAADgADAAAADQAgAA4AMQAPAFkAAAADAAExAAEALAAtAAEAVAAAAFoAAwABAAAAICq3AE0quwBPWbcAULUAEyoSUrUAGyoEtQAgKgO1ACSxAAAAAgBVAAAADAABAAAAIAAUABUAAABWAAAAFgAFAAAABwAEAAgADwAJABUACgAaAAsAAwBaAAAAAgAFAFsAAAALAAEABgABAAdzAAgAXAAAAAMFAAA= diff --git a/src/test/resources/compat/ReferenceScalaTMicroOcclusion.class.b64 b/src/test/resources/compat/ReferenceScalaTMicroOcclusion.class.b64 new file mode 100644 index 0000000..1770b3b --- /dev/null +++ b/src/test/resources/compat/ReferenceScalaTMicroOcclusion.class.b64 @@ -0,0 +1 @@ +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BAAFaAQAKZWRnZVJlc3VsdAEACHNlZW5FZGdlAQAoTGNvZGVjaGlja2VuL21pY3JvYmxvY2svVE1pY3JvT2NjbHVzaW9uOwEACnNlZW5Db3JuZXIBADtjb2RlY2hpY2tlbiRtaWNyb2Jsb2NrJFRNaWNyb09jY2x1c2lvbiQkc3VwZXIkb2NjbHVzaW9uVGVzdAEAJShMY29kZWNoaWNrZW4vbXVsdGlwYXJ0L1RNdWx0aVBhcnQ7KVoBAA1vY2NsdXNpb25UZXN0DAAaABkKAAQAGwEABHRoaXMBADxMY29kZWNoaWNrZW4vbXVsdGlwYXJ0L2NvbXBhdC9SZWZlcmVuY2VTY2FsYVRNaWNyb09jY2x1c2lvbjsBAAVucGFydAEAIkxjb2RlY2hpY2tlbi9tdWx0aXBhcnQvVE11bHRpUGFydDsBACxjb2RlY2hpY2tlbi9taWNyb2Jsb2NrL1RNaWNyb09jY2x1c2lvbiRjbGFzcwcAIQEATShMY29kZWNoaWNrZW4vbWljcm9ibG9jay9UTWljcm9PY2NsdXNpb247TGNvZGVjaGlja2VuL211bHRpcGFydC9UTXVsdGlQYXJ0OylaDAAaACMKACIAJAEAAygpSQwACwAMCQACACcBAAhzbG90XyRlcQEABChJKVYBAAN4JDEMAA0ADAkAAgAsAQAPc2xvdEFkdmFuY2VfJGVxDAAOAAwJAAIALwEACHNpemVfJGVxDAAPAAwJAAIAMgEADG1hdGVyaWFsXyRlcQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7DAAQABEJAAIANgEACmZhaWxPbl8kZXEBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAMoKVoMABIAEwkAAgA7AQARdXNlQWN0dWFsRWRnZV8kZXEBAAQoWilWDAAUABMJAAIAPwEADmVkZ2VSZXN1bHRfJGVxAQAqKClMY29kZWNoaWNrZW4vbWljcm9ibG9jay9UTWljcm9PY2NsdXNpb247DAAVABYJAAIAQwEADHNlZW5FZGdlXyRlcQEAKyhMY29kZWNoaWNrZW4vbWljcm9ibG9jay9UTWljcm9PY2NsdXNpb247KVYMABcAFgkAAgBHAQAOc2VlbkNvcm5lcl8kZXEBAAdnZXRUeXBlAQAUdGVzdDptaWNyb19vY2NsdXNpb24IAEsBAAlnZXRCb3VuZHMBAB8oKUxjb2RlY2hpY2tlbi9saWIvdmVjL0N1Ym9pZDY7AQAYamF2YS9sYW5nL0Fzc2VydGlvbkVycm9yBwBPAQAXYm91bmRzIG11c3Qgbm90IGJlIHJlYWQIAFEBAAY8aW5pdD4BABUoTGphdmEvbGFuZy9PYmplY3Q7KVYMAFMAVAoAUABVAQAGcmVjb3JkAQAGZXZlbnRzAQASKClMamF2YS91dGlsL0xpc3Q7DABYAFkKAAIAWgEAJnNjYWxhL2NvbGxlY3Rpb24vbXV0YWJsZS9TdHJpbmdCdWlsZGVyBwBcAQADKClWDABTAF4KAF0AXwEABmFwcGVuZAEAPChMamF2YS9sYW5nL09iamVjdDspTHNjYWxhL2NvbGxlY3Rpb24vbXV0YWJsZS9TdHJpbmdCdWlsZGVyOwwAYQBiCgBdAGMBAAE6CABlAQAFbGFiZWwMAGcANQoAAgBoAQAIdG9TdHJpbmcMAGoANQoAXQBrAQAOamF2YS91dGlsL0xpc3QHAG0BAANhZGQBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoMAG8AcAsAbgBxDAAQADUKAAIAcwEAEGphdmEvbGFuZy9PYmplY3QHAHUBAAZlcXVhbHMMAHcAcAoAdgB4AQAfamF2YS9sYW5nL0lsbGVnYWxTdGF0ZUV4Y2VwdGlvbgcAegwAUwA5CgB7AHwBAARuYW1lAQAQamF2YS9sYW5nL1N0cmluZwcAfwEAB2dldFNsb3QIAAsMAFcAOQoAAgCDDAALACYKAAIAhQwADQAmCgACAIcMACkAKgoAAgCJAQAGcmVzdWx0AQAHZ2V0U2l6ZQgADgwADgAmCgACAI4BAAtnZXRNYXRlcmlhbAgADwwADwAmCgACAJIBABdlZGdlQ29ybmVyT2NjbHVzaW9uVGVzdAEAUyhMY29kZWNoaWNrZW4vbWljcm9ibG9jay9UTWljcm9PY2NsdXNpb247TGNvZGVjaGlja2VuL21pY3JvYmxvY2svVE1pY3JvT2NjbHVzaW9uOylaAQAEZWRnZQgAlgwARQBGCgACAJgMAEkARgoAAgCaDAASADoKAAIAnAEAeyhMY29kZWNoaWNrZW4vbWljcm9ibG9jay9UTWljcm9PY2NsdXNpb247TGNvZGVjaGlja2VuL21pY3JvYmx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