mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-13 00:47:52 +00:00
test: characterize TCuboidPart
Freezes the observable behavior of TCuboidPart, JCuboidPart and the
TCuboidPart$class bridge before the Java port, per the test-first gate in
JAVA_MIGRATION.md. All cases pass against the untouched Scala.
Records two asymmetries worth preserving: getSubParts wraps the bounds in
an IndexedCuboid6, whose copy constructor makes it a copy carrying a boxed
Integer 0 as data, while getCollisionBoxes aliases the bounds instance
itself. Cuboid6 has no equals, so geometry is compared component-wise.
Also adds a frozen Scala consumer compiled with 2.11.5 against the
reference dev jar at 246daff. Its forwarders call all four $class statics,
so it detects the linkage break that a freshly recompiled test would miss.
ForgeRelocationFMP, OpenComputers, ProjRed and ProjectBlue all depend on
those descriptors.
One case exists specifically to guard the port: TMultiPart supplies empty
getSubParts and getCollisionBoxes, and on the JVM a superclass method beats
an interface default, so a Java interface cannot reproduce Scala trait
linearization on its own.
This commit is contained in:
1 parent
246dafffda
commit
8294240659
5 files changed
+265
-3
No files matched your search
@@ -0,0 +1,129 @@
|
||||
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.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import codechicken.lib.raytracer.IndexedCuboid6;
|
||||
import codechicken.lib.vec.Cuboid6;
|
||||
|
||||
class CuboidPartCharacterizationTest {
|
||||
|
||||
@Test
|
||||
void subPartsHoldOneIndexedCopyOfTheBounds() {
|
||||
TestPart part = new TestPart(box(0, 0, 0, 0.5, 0.5, 0.5));
|
||||
|
||||
List<IndexedCuboid6> subParts = drain(part.getSubParts());
|
||||
|
||||
assertEquals(1, subParts.size());
|
||||
IndexedCuboid6 only = assertInstanceOf(IndexedCuboid6.class, subParts.get(0));
|
||||
assertEquals(Integer.valueOf(0), only.data);
|
||||
assertGeometry(part.getBounds(), only);
|
||||
assertNotSame(part.getBounds(), only);
|
||||
}
|
||||
|
||||
@Test
|
||||
void collisionBoxesAliasTheBoundsInstance() {
|
||||
TestPart part = new TestPart(box(0, 0, 0, 1, 1, 1));
|
||||
|
||||
List<Cuboid6> boxes = drain(part.getCollisionBoxes());
|
||||
|
||||
assertEquals(1, boxes.size());
|
||||
assertSame(part.getBounds(), boxes.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resultsFollowTheCurrentBounds() {
|
||||
TestPart part = new TestPart(box(0, 0, 0, 1, 1, 1));
|
||||
part.bounds = box(0.25, 0.25, 0.25, 0.75, 0.75, 0.75);
|
||||
|
||||
assertGeometry(part.getBounds(), drain(part.getSubParts()).get(0));
|
||||
assertSame(part.getBounds(), drain(part.getCollisionBoxes()).get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void deprecatedBridgeMatchesTheInstanceMethods() {
|
||||
TestPart part = new TestPart(box(0.1, 0.2, 0.3, 0.4, 0.5, 0.6));
|
||||
|
||||
List<IndexedCuboid6> bridgeSubParts = drain(TCuboidPart$class.getSubParts(part));
|
||||
List<Cuboid6> bridgeBoxes = drain(TCuboidPart$class.getCollisionBoxes(part));
|
||||
|
||||
assertEquals(1, bridgeSubParts.size());
|
||||
assertEquals(Integer.valueOf(0), bridgeSubParts.get(0).data);
|
||||
assertGeometry(part.getBounds(), bridgeSubParts.get(0));
|
||||
assertEquals(1, bridgeBoxes.size());
|
||||
assertSame(part.getBounds(), bridgeBoxes.get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* TMultiPart supplies empty defaults. A cuboid part must not fall back to them: on the JVM a superclass method
|
||||
* beats an interface default, so this is the guard against the port silently losing the cuboid behavior.
|
||||
*/
|
||||
@Test
|
||||
void cuboidBehaviorWinsOverTheEmptyTMultiPartDefaults() {
|
||||
TMultiPart bare = new TMultiPart() {
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "test:bare";
|
||||
}
|
||||
};
|
||||
|
||||
assertFalse(bare.getSubParts().iterator().hasNext());
|
||||
assertFalse(bare.getCollisionBoxes().iterator().hasNext());
|
||||
|
||||
TestPart part = new TestPart(box(0, 0, 0, 1, 1, 1));
|
||||
assertTrue(part.getSubParts().iterator().hasNext());
|
||||
assertTrue(part.getCollisionBoxes().iterator().hasNext());
|
||||
}
|
||||
|
||||
private static void assertGeometry(Cuboid6 expected, Cuboid6 actual) {
|
||||
assertEquals(expected.min.x, actual.min.x);
|
||||
assertEquals(expected.min.y, actual.min.y);
|
||||
assertEquals(expected.min.z, actual.min.z);
|
||||
assertEquals(expected.max.x, actual.max.x);
|
||||
assertEquals(expected.max.y, actual.max.y);
|
||||
assertEquals(expected.max.z, actual.max.z);
|
||||
}
|
||||
|
||||
private static <T> List<T> drain(Iterable<T> values) {
|
||||
List<T> result = new ArrayList<>();
|
||||
for (Iterator<T> iterator = values.iterator(); iterator.hasNext();) {
|
||||
result.add(iterator.next());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Cuboid6 box(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
return new Cuboid6(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
private static final class TestPart extends JCuboidPart {
|
||||
|
||||
private Cuboid6 bounds;
|
||||
|
||||
private TestPart(Cuboid6 bounds) {
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cuboid6 getBounds() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "test:cuboid";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
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.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import codechicken.lib.raytracer.IndexedCuboid6;
|
||||
import codechicken.lib.vec.Cuboid6;
|
||||
|
||||
/**
|
||||
* Loads a Scala class compiled against the reference dev jar, whose forwarders call TCuboidPart$class directly.
|
||||
* Recompiling the fixture against the port would hide the linkage failure this exists to catch.
|
||||
*/
|
||||
class TCuboidPartBinaryCompatibilityTest {
|
||||
|
||||
@Test
|
||||
void referenceScalaImplementorStillLinksThroughTheBridge() throws Exception {
|
||||
byte[] bytecode = loadFixture();
|
||||
Class<?> fixtureClass = new FixtureClassLoader(TCuboidPart.class.getClassLoader()).define(bytecode);
|
||||
Object fixture = fixtureClass.getDeclaredConstructor().newInstance();
|
||||
|
||||
assertTrue(fixture instanceof TCuboidPart);
|
||||
assertTrue(fixture instanceof TMultiPart);
|
||||
TCuboidPart part = (TCuboidPart) fixture;
|
||||
|
||||
Cuboid6 bounds = part.getBounds();
|
||||
assertEquals(0.5, bounds.max.x);
|
||||
|
||||
Iterator<IndexedCuboid6> subParts = part.getSubParts().iterator();
|
||||
IndexedCuboid6 only = subParts.next();
|
||||
assertEquals(Integer.valueOf(0), only.data);
|
||||
assertEquals(0.5, only.max.x);
|
||||
assertFalse(subParts.hasNext());
|
||||
|
||||
Iterator<Cuboid6> boxes = part.getCollisionBoxes().iterator();
|
||||
assertEquals(0.5, boxes.next().max.x);
|
||||
assertFalse(boxes.hasNext());
|
||||
}
|
||||
|
||||
private static byte[] loadFixture() {
|
||||
InputStream input = Objects.requireNonNull(
|
||||
TCuboidPartBinaryCompatibilityTest.class
|
||||
.getResourceAsStream("/compat/ReferenceScalaCuboidPart.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user