Files
ForgeMultipart/src/test/java/codechicken/multipart/TItemMultiPartBinaryCompatibilityTest.java
T
Algent 6813144d84 test: characterize TItemMultiPart
Freezes the placement logic before the port. getHitDepth projects the hit
vector onto the axis for that side and adds 1 on even sides, giving the
six frozen values, and it copies the vector rather than mutating the
caller's. onItemUse tries the clicked block first only when the depth is
below 1, then always tries the neighbour on that side, reusing and
mutating a single BlockCoord across both attempts.

Placement short-circuits as soon as newPart returns null, before any
world, player or stack access, so all of that is reachable headless with
null arguments. Real placement needs a world and stays on the functional
and manual layers.

Adds a frozen Scala 2.11.5 consumer compiled against the reference dev jar
at 7843f13, whose forwarders call all three statics. ProjRed is the only
consumer of this bridge.

57 plain-JVM tests, all passing against the untouched Scala.
2026-08-14 21:23:45 +02:00

78 lines
2.8 KiB
Java

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.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Objects;
import java.util.Scanner;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import org.junit.jupiter.api.Test;
import codechicken.lib.vec.Vector3;
/**
* Loads a Scala class compiled against the reference dev jar, whose forwarders call all three TItemMultiPart$class
* statics. Its newPart returns null, so placement short-circuits before touching the world.
*/
class TItemMultiPartBinaryCompatibilityTest {
@Test
void referenceScalaImplementorStillLinksThroughTheBridge() throws Exception {
Class<?> fixtureClass = new FixtureClassLoader(TItemMultiPart.class.getClassLoader()).define(loadFixture());
Object fixture = fixtureClass.getDeclaredConstructor().newInstance();
assertTrue(fixture instanceof TItemMultiPart);
assertTrue(fixture instanceof Item);
TItemMultiPart item = (TItemMultiPart) fixture;
assertEquals(0.75, item.getHitDepth(new Vector3(0.25, 0.5, 0.75), 3));
Method onItemUse = fixtureClass.getMethod(
"onItemUse",
ItemStack.class,
EntityPlayer.class,
World.class,
int.class,
int.class,
int.class,
int.class,
float.class,
float.class,
float.class);
assertFalse((Boolean) onItemUse.invoke(fixture, null, null, null, 4, 5, 6, 1, 0f, 0.3f, 0f));
// A shallow hit tries the clicked block first, then its neighbour on that side.
assertEquals("4,5,6;4,6,6;", fixtureClass.getMethod("attempts").invoke(fixture));
}
private static byte[] loadFixture() {
InputStream input = Objects.requireNonNull(
TItemMultiPartBinaryCompatibilityTest.class
.getResourceAsStream("/compat/ReferenceScalaItemMultiPart.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);
}
}
}