diff --git a/src/test/fixtures/README.md b/src/test/fixtures/README.md index 5abba95..d0b1d6c 100644 --- a/src/test/fixtures/README.md +++ b/src/test/fixtures/README.md @@ -87,3 +87,14 @@ Compiled with Scala 2.11.5 under Java 8, `-target:jvm-1.8`, against the referenc (SHA-256 `c003d02407d901271f42e182b5036ed3c295c2acbf416603513d2bec5b8210d0`). Class-file SHA-256 is `0b9d9dba78a25b0c0867fe545bc6c6400be272c418d755ef72f46dde6294c75e`, stored as `src/test/resources/compat/ReferenceScalaItemMultiPart.class.b64`. + +### `ReferenceScalaEdgePart` + +`scala/codechicken/multipart/compat/ReferenceScalaEdgePart.scala` mixes in `TEdgePart` without overriding what it +supplies, so its compiled forwarder calls `TEdgePart$class.conductsRedstone` and its constructor calls +`TEdgePart$class.$init$`. OpenComputers links against `$init$`. + +Compiled with Scala 2.11.5 under Java 8, `-target:jvm-1.8`, against the reference dev jar built at `f2f1870` +(SHA-256 `cec40ee4c94f89fadf29e3f4860c68ca7d55caf12634d950a3eb5ecfb272a01b`). Class-file SHA-256 is +`76e4d3875ae9246ed2277f0470b22f596885282386ed179a42e5f571711ae5e0`, stored as +`src/test/resources/compat/ReferenceScalaEdgePart.class.b64`. diff --git a/src/test/fixtures/scala/codechicken/multipart/compat/ReferenceScalaEdgePart.scala b/src/test/fixtures/scala/codechicken/multipart/compat/ReferenceScalaEdgePart.scala new file mode 100644 index 0000000..888d4ca --- /dev/null +++ b/src/test/fixtures/scala/codechicken/multipart/compat/ReferenceScalaEdgePart.scala @@ -0,0 +1,12 @@ +package codechicken.multipart.compat + +import codechicken.multipart.{TEdgePart, TMultiPart} + +/** Mixes in TEdgePart without overriding what it supplies, so the compiled forwarder calls + * TEdgePart$class.conductsRedstone and the constructor calls TEdgePart$class.$init$. + */ +class ReferenceScalaEdgePart extends TMultiPart with TEdgePart { + def getType = "test:reference-edge" + + def getSlotMask = 1 << 15 +} diff --git a/src/test/java/codechicken/multipart/EdgePartCharacterizationTest.java b/src/test/java/codechicken/multipart/EdgePartCharacterizationTest.java new file mode 100644 index 0000000..6d1b864 --- /dev/null +++ b/src/test/java/codechicken/multipart/EdgePartCharacterizationTest.java @@ -0,0 +1,58 @@ +package codechicken.multipart; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class EdgePartCharacterizationTest { + + @Test + void edgePartsDoNotConductRedstoneByDefault() { + assertFalse(new ForwardingPart().conductsRedstone()); + } + + /** The bridge holds the trait default rather than dispatching, so an override does not change what it returns. */ + @Test + void deprecatedBridgeReturnsTheTraitDefaultEvenWhenOverridden() { + assertFalse(TEdgePart$class.conductsRedstone(new ForwardingPart())); + assertTrue(new ConductingPart().conductsRedstone()); + assertFalse(TEdgePart$class.conductsRedstone(new ConductingPart())); + } + + @Test + void edgePartIsASlottedPart() { + ForwardingPart part = new ForwardingPart(); + + assertTrue(part instanceof TSlottedPart); + assertEquals(1 << 15, part.getSlotMask()); + } + + /** Mirrors the forwarder Scala emits for a class mixing in the trait without overriding it. */ + private static class ForwardingPart extends TMultiPart implements TEdgePart { + + @Override + public String getType() { + return "test:edge"; + } + + @Override + public int getSlotMask() { + return 1 << 15; + } + + @Override + public boolean conductsRedstone() { + return TEdgePart$class.conductsRedstone(this); + } + } + + private static final class ConductingPart extends ForwardingPart { + + @Override + public boolean conductsRedstone() { + return true; + } + } +} diff --git a/src/test/java/codechicken/multipart/TEdgePartBinaryCompatibilityTest.java b/src/test/java/codechicken/multipart/TEdgePartBinaryCompatibilityTest.java new file mode 100644 index 0000000..87b4c7a --- /dev/null +++ b/src/test/java/codechicken/multipart/TEdgePartBinaryCompatibilityTest.java @@ -0,0 +1,53 @@ +package codechicken.multipart; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Objects; +import java.util.Scanner; + +import org.junit.jupiter.api.Test; + +/** + * Loads a Scala class compiled against the reference dev jar, whose forwarder calls TEdgePart$class.conductsRedstone + * and whose constructor calls TEdgePart$class.$init$. OpenComputers links against the latter. + */ +class TEdgePartBinaryCompatibilityTest { + + @Test + void referenceScalaImplementorStillLinksThroughTheBridge() throws Exception { + Class fixtureClass = new FixtureClassLoader(TEdgePart.class.getClassLoader()).define(loadFixture()); + Object fixture = fixtureClass.getDeclaredConstructor().newInstance(); + + assertTrue(fixture instanceof TEdgePart); + assertTrue(fixture instanceof TSlottedPart); + assertTrue(fixture instanceof TMultiPart); + TEdgePart part = (TEdgePart) fixture; + + assertFalse(part.conductsRedstone()); + assertEquals(1 << 15, part.getSlotMask()); + } + + private static byte[] loadFixture() { + InputStream input = Objects.requireNonNull( + TEdgePartBinaryCompatibilityTest.class.getResourceAsStream("/compat/ReferenceScalaEdgePart.class.b64")); + try (Scanner scanner = new Scanner(input, StandardCharsets.US_ASCII.name()).useDelimiter("\\A")) { + return Base64.getMimeDecoder().decode(scanner.next()); + } + } + + private static final class FixtureClassLoader extends ClassLoader { + + private FixtureClassLoader(ClassLoader parent) { + super(parent); + } + + private Class define(byte[] bytecode) { + return defineClass(null, bytecode, 0, bytecode.length); + } + } +} diff --git a/src/test/resources/compat/ReferenceScalaEdgePart.class.b64 b/src/test/resources/compat/ReferenceScalaEdgePart.class.b64 new file mode 100644 index 0000000..a43b0ca --- /dev/null +++ b/src/test/resources/compat/ReferenceScalaEdgePart.class.b64 @@ -0,0 +1,22 @@ +yv66vgAAADQAKQEAM2NvZGVjaGlja2VuL211bHRpcGFydC9jb21wYXQvUmVmZXJlbmNlU2NhbGFF +ZGdlUGFydAcAAQEAIGNvZGVjaGlja2VuL211bHRpcGFydC9UTXVsdGlQYXJ0BwADAQAfY29kZWNo +aWNrZW4vbXVsdGlwYXJ0L1RFZGdlUGFydAcABQEAHFJlZmVyZW5jZVNjYWxhRWRnZVBhcnQuc2Nh +bGEBAB5Mc2NhbGEvcmVmbGVjdC9TY2FsYVNpZ25hdHVyZTsBAAVieXRlcwEBJQYBKTJBIQECARMJ +MSIrGjRmZRZ0Ny1aKmRDMgxXCVo0ZiEGFEhPAwIECQUxMW1cN3FDUlQhIQIEAhM1LEgOXjVxQ0ok +KCJBBAIXDXxHLVoyaVMOXFdNXAIBJw0BIUIECQMXMWkRAUIFAxsRESECVid2WVJMBysZOnUhCVlx +IgMCEQkJSUErEjNoS0ILJw8eBQYlASEJYUUBB3kldBcOHiAVA1EBIiEGAQ4DCUFRYQYBBQJhCXFh +WjN1KWYEWC1GARohCVFyJEQBHBUJYVIkAQNtQzo8JyIBEAIJKQxnL1kFA0FtEWFhFTtzUzo8ByIC +EgEJAxkTYUM0ZmlOY3cOXidiZy4sEgEKCQNLIWoRQQoGAk8FKTFvWTFtQyYREUYKAgQTOiQIAQAQ +Y29uZHVjdHNSZWRzdG9uZQEAAygpWgEAJWNvZGVjaGlja2VuL211bHRpcGFydC9URWRnZVBhcnQk +Y2xhc3MHAA0BACQoTGNvZGVjaGlja2VuL211bHRpcGFydC9URWRnZVBhcnQ7KVoMAAsADwoADgAQ +AQAEdGhpcwEANUxjb2RlY2hpY2tlbi9tdWx0aXBhcnQvY29tcGF0L1JlZmVyZW5jZVNjYWxhRWRn +ZVBhcnQ7AQAHZ2V0VHlwZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQATdGVzdDpyZWZlcmVuY2Ut +ZWRnZQgAFgEAC2dldFNsb3RNYXNrAQADKClJAwAAgAABAAY8aW5pdD4BAAMoKVYMABsAHAoABAAd +AQAGJGluaXQkAQAkKExjb2RlY2hpY2tlbi9tdWx0aXBhcnQvVEVkZ2VQYXJ0OylWDAAfACAKAA4A +IQEABENvZGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAA9MaW5lTnVtYmVyVGFibGUBAApTb3VyY2VG +aWxlAQAZUnVudGltZVZpc2libGVBbm5vdGF0aW9ucwEACFNjYWxhU2lnACEAAgAEAAEABgAAAAQA +AQALAAwAAQAjAAAALwABAAEAAAAFKrgAEawAAAACACQAAAAMAAEAAAAFABIAEwAAACUAAAAGAAEA +AAAIAAEAFAAVAAEAIwAAAC0AAQABAAAAAxIXsAAAAAIAJAAAAAwAAQAAAAMAEgATAAAAJQAAAAYA +AQAAAAkAAQAYABkAAQAjAAAALQABAAEAAAADEhqsAAAAAgAkAAAADAABAAAAAwASABMAAAAlAAAA +BgABAAAACwABABsAHAABACMAAAAzAAEAAQAAAAkqtwAeKrgAIrEAAAACACQAAAAMAAEAAAAJABIA +EwAAACUAAAAGAAEAAAAIAAMAJgAAAAIABwAnAAAACwABAAgAAQAJcwAKACgAAAADBQAA