mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-13 00:47:52 +00:00
test: characterize TIconHitEffects
Freezes what is reachable without a client: getBreakingIcon falls back to
getBrokenIcon for the same side and ignores its subPart argument, destroy
effects request sides 0 through 5 in order, and the scaleDensity overload
decides whether the part's own bounds are consulted at all. The particle
calls need a world and an EffectRenderer, so actual appearance stays on
the manual checklist.
Adds a frozen Scala 2.11.5 consumer compiled against the reference dev jar
at 57130a6. It exercises both bridges: getBreakingIcon proves
JIconHitEffects$class delegates to the fixture's getBrokenIcon, and
addDestroyEffects proves TIconHitEffects$class resolves by collecting all
six icons before failing on the null tile.
49 plain-JVM tests, all passing against the untouched Scala.
This commit is contained in:
1 parent
57130a6955
commit
07ffc01db1
5 files changed
+260
No files matched your search
@@ -0,0 +1,100 @@
|
||||
package codechicken.multipart;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import codechicken.lib.vec.Cuboid6;
|
||||
|
||||
/**
|
||||
* The particle calls themselves need a world and an EffectRenderer, so they cannot run headless. What is asserted here
|
||||
* is the part of the contract that is reachable: icon selection, the order and range of the icons requested, and
|
||||
* whether the part's own bounds are consulted. Actual particle appearance stays on the manual checklist.
|
||||
*/
|
||||
class IconHitEffectsCharacterizationTest {
|
||||
|
||||
@Test
|
||||
void breakingIconFallsBackToTheBrokenIconForThatSide() {
|
||||
SpyPart part = new SpyPart();
|
||||
|
||||
assertNull(part.getBreakingIcon("ignored-subpart", 3));
|
||||
assertEquals(1, part.brokenIconSides.size());
|
||||
assertEquals(3, part.brokenIconSides.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deprecatedBridgeMatchesTheBreakingIconFallback() {
|
||||
SpyPart part = new SpyPart();
|
||||
|
||||
assertNull(JIconHitEffects$class.getBreakingIcon(part, null, 5));
|
||||
assertEquals(1, part.brokenIconSides.size());
|
||||
assertEquals(5, part.brokenIconSides.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void destroyEffectsRequestAllSixSidesInOrderAndScaleToTheBounds() {
|
||||
SpyPart part = new SpyPart();
|
||||
|
||||
// The tile is null, so this reaches part.tile after collecting the icons and bounds.
|
||||
assertThrows(NullPointerException.class, () -> IconHitEffects.addDestroyEffects(part, null));
|
||||
|
||||
assertEquals(Arrays.asList(0, 1, 2, 3, 4, 5), part.brokenIconSides);
|
||||
assertEquals(1, part.boundsRequested);
|
||||
}
|
||||
|
||||
@Test
|
||||
void destroyEffectsWithoutDensityScalingIgnoreTheBounds() {
|
||||
SpyPart part = new SpyPart();
|
||||
|
||||
assertThrows(NullPointerException.class, () -> IconHitEffects.addDestroyEffects(part, null, false));
|
||||
|
||||
assertEquals(Arrays.asList(0, 1, 2, 3, 4, 5), part.brokenIconSides);
|
||||
assertEquals(0, part.boundsRequested);
|
||||
}
|
||||
|
||||
@Test
|
||||
void iconHitEffectsPartIsAMultiPart() {
|
||||
SpyPart part = new SpyPart();
|
||||
|
||||
assertTrue(part instanceof JIconHitEffects);
|
||||
assertTrue(part instanceof TMultiPart);
|
||||
}
|
||||
|
||||
/** Mirrors the forwarder Scala emits for a class that does not override getBreakingIcon. */
|
||||
private static final class SpyPart extends TMultiPart implements JIconHitEffects {
|
||||
|
||||
private final List<Integer> brokenIconSides = new ArrayList<>();
|
||||
private int boundsRequested;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "test:icon-hit";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cuboid6 getBounds() {
|
||||
boundsRequested++;
|
||||
return new Cuboid6(0, 0, 0, 1, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIcon getBrokenIcon(int side) {
|
||||
brokenIconSides.add(side);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIcon getBreakingIcon(Object subPart, int side) {
|
||||
return JIconHitEffects$class.getBreakingIcon(this, subPart, side);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package codechicken.multipart;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Loads a Scala class compiled against the reference dev jar. Its forwarders call all five statics across both
|
||||
* JIconHitEffects$class and TIconHitEffects$class.
|
||||
*/
|
||||
class TIconHitEffectsBinaryCompatibilityTest {
|
||||
|
||||
@Test
|
||||
void referenceScalaImplementorStillLinksThroughBothBridges() throws Exception {
|
||||
Class<?> fixtureClass = new FixtureClassLoader(TIconHitEffects.class.getClassLoader()).define(loadFixture());
|
||||
Object fixture = fixtureClass.getDeclaredConstructor().newInstance();
|
||||
|
||||
assertTrue(fixture instanceof TIconHitEffects);
|
||||
assertTrue(fixture instanceof JIconHitEffects);
|
||||
assertTrue(fixture instanceof TMultiPart);
|
||||
TIconHitEffects part = (TIconHitEffects) fixture;
|
||||
|
||||
// Runs JIconHitEffects$class.getBreakingIcon, which must delegate to the fixture's getBrokenIcon.
|
||||
assertNull(part.getBreakingIcon(null, 4));
|
||||
assertEquals(4, fixtureClass.getMethod("lastSide").invoke(fixture));
|
||||
|
||||
// Runs TIconHitEffects$class.addDestroyEffects. The fixture's tile is null, so it collects all six icons and
|
||||
// then fails on the tile; reaching that point proves the static resolved rather than failing to link.
|
||||
InvocationTargetException thrown = assertThrows(
|
||||
InvocationTargetException.class,
|
||||
() -> fixtureClass.getMethod("addDestroyEffects", EffectRenderer.class).invoke(fixture, (Object) null));
|
||||
assertInstanceOf(NullPointerException.class, thrown.getCause());
|
||||
assertEquals(5, fixtureClass.getMethod("lastSide").invoke(fixture));
|
||||
}
|
||||
|
||||
private static byte[] loadFixture() {
|
||||
InputStream input = Objects.requireNonNull(
|
||||
TIconHitEffectsBinaryCompatibilityTest.class
|
||||
.getResourceAsStream("/compat/ReferenceScalaIconHitEffects.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