mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-22 16:17:44 +00:00
Honor bound platform
- Route shared runtime hooks through the active Iris platform instead of classpath presence. - Keep Bukkit-specific mantle and Matter behavior behind explicit platform capabilities. - Cover hybrid classpaths and bound hook precedence with regression tests.
This commit is contained in:
1 parent
1ca943ab51
commit
ecec18509c
16 files changed
+179
-135
No files matched your search
@@ -47,7 +47,7 @@ public class IrisEnginePlatformHookIsolationTest {
|
||||
);
|
||||
|
||||
@Test
|
||||
public void sharedGeneratorHotPathsDoNotLinkBukkitImplementations() throws IOException {
|
||||
public void sharedGeneratorHotPathsDoNotLinkBukkitImplementations() throws IOException, ClassNotFoundException {
|
||||
assertNoClassLinks(IrisEngine.class, BUKKIT_ENGINE_CLASSES);
|
||||
assertNoClassLinks(EngineBackgroundTasks.class, BUKKIT_ENGINE_CLASSES);
|
||||
assertNoClassLinks(EngineDataStore.class, BUKKIT_ENGINE_CLASSES);
|
||||
@@ -56,6 +56,8 @@ public class IrisEnginePlatformHookIsolationTest {
|
||||
assertNoClassLinks(EngineRuntimeBuilder.class, BUKKIT_ENGINE_CLASSES);
|
||||
assertNoClassLinks(EngineShutdownSequence.class, BUKKIT_ENGINE_CLASSES);
|
||||
assertNoClassLinks(EngineTickRegistry.class, BUKKIT_ENGINE_CLASSES);
|
||||
assertNoClassLinks(IrisEngineMantle.class, BUKKIT_ENGINE_CLASSES);
|
||||
assertNoClassLinks(Class.forName(IrisEngineMantle.class.getName() + "$1"), BUKKIT_ENGINE_CLASSES);
|
||||
assertNoClassLinks(Engine.class, ENGINE_POLICY_CLASSES);
|
||||
assertNoClassLinks(EngineMode.class, PLATFORM_POLICY_CLASSES);
|
||||
assertNoClassLinks(EngineMantle.class, PLATFORM_POLICY_CLASSES);
|
||||
@@ -63,7 +65,8 @@ public class IrisEnginePlatformHookIsolationTest {
|
||||
}
|
||||
|
||||
private static void assertNoClassLinks(Class<?> type, List<String> forbiddenClasses) throws IOException {
|
||||
InputStream stream = type.getResourceAsStream(type.getSimpleName() + ".class");
|
||||
String resourceName = type.getName().substring(type.getName().lastIndexOf('.') + 1) + ".class";
|
||||
InputStream stream = type.getResourceAsStream(resourceName);
|
||||
assertNotNull(stream);
|
||||
String bytecode;
|
||||
try (InputStream input = stream) {
|
||||
|
||||
@@ -429,6 +429,28 @@ public class DecoratorCoreTest {
|
||||
assertEquals("minecraft:twisting_vines", DecoratorCore.stackedVineKey(vine, 3, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void boundDecoratorHooksWinWhenBukkitClassesArePresent() {
|
||||
PlatformBlockState vine = mock(PlatformBlockState.class);
|
||||
PlatformBlockState fixed = mock(PlatformBlockState.class);
|
||||
PlatformBlockState decorator = mock(PlatformBlockState.class);
|
||||
PlatformBlockState surface = mock(PlatformBlockState.class);
|
||||
Hunk<PlatformBlockState> output = Hunk.newArrayHunk(1, 1, 1);
|
||||
DecoratorPlatformHooks.FaceFixer faceFixer = mock(DecoratorPlatformHooks.FaceFixer.class);
|
||||
DecoratorPlatformHooks.SurfaceSturdiness sturdiness = mock(DecoratorPlatformHooks.SurfaceSturdiness.class);
|
||||
when(vine.isVineBlock()).thenReturn(true);
|
||||
when(faceFixer.fixFaces(vine, output, 0, 0, 0, 0, 0, null)).thenReturn(fixed);
|
||||
when(decorator.canPlaceOnto(surface)).thenReturn(true);
|
||||
when(sturdiness.canGoOn(surface)).thenReturn(true);
|
||||
DecoratorPlatformHooks.Bindings previous = DecoratorPlatformHooks.bind(faceFixer, sturdiness);
|
||||
try {
|
||||
assertSame(fixed, DecoratorCore.fixFacesForHunk(vine, output, 0, 0, 0, 0, 0, null));
|
||||
assertTrue(DecoratorCore.canGoOn(decorator, surface));
|
||||
} finally {
|
||||
DecoratorPlatformHooks.restore(previous);
|
||||
}
|
||||
}
|
||||
|
||||
private PlatformBlockState airState() {
|
||||
PlatformBlockState air = mock(PlatformBlockState.class);
|
||||
when(air.isAir()).thenReturn(true);
|
||||
|
||||
+54
-22
@@ -1,42 +1,74 @@
|
||||
package art.arcane.iris.engine.object;
|
||||
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class PlatformStateHookContractTest {
|
||||
@Test
|
||||
public void missingPlatformRotatorFailsLoudly() {
|
||||
IllegalStateException error = assertThrows(IllegalStateException.class,
|
||||
() -> IrisObjectRotation.requirePlatformRotator(null));
|
||||
|
||||
assertEquals("No platform block-state rotator is bound", error.getMessage());
|
||||
public void boundRotatorWinsWhenBukkitClassesArePresent() {
|
||||
PlatformBlockState source = mock(PlatformBlockState.class);
|
||||
PlatformBlockState rotated = mock(PlatformBlockState.class);
|
||||
IrisObjectRotation.StateRotator hook = mock(IrisObjectRotation.StateRotator.class);
|
||||
IrisObjectRotation rotation = new IrisObjectRotation();
|
||||
when(hook.rotate(rotation, source, 1, 2, 3)).thenReturn(rotated);
|
||||
IrisObjectRotation.StateRotator previous = IrisObjectRotation.bindPlatformRotator(hook);
|
||||
try {
|
||||
assertSame(rotated, rotation.rotate(source, 1, 2, 3));
|
||||
} finally {
|
||||
IrisObjectRotation.restorePlatformRotator(previous);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingPlatformMergerFailsLoudly() {
|
||||
IllegalStateException error = assertThrows(IllegalStateException.class,
|
||||
() -> BlockDataMergeSupport.requirePlatformMerger(null));
|
||||
|
||||
assertEquals("No platform block-state merger is bound", error.getMessage());
|
||||
public void boundMergerWinsWhenBukkitClassesArePresent() {
|
||||
PlatformBlockState base = mock(PlatformBlockState.class);
|
||||
PlatformBlockState update = mock(PlatformBlockState.class);
|
||||
PlatformBlockState merged = mock(PlatformBlockState.class);
|
||||
BlockDataMergeSupport.StateMerger hook = mock(BlockDataMergeSupport.StateMerger.class);
|
||||
when(hook.merge(base, update)).thenReturn(merged);
|
||||
BlockDataMergeSupport.StateMerger previous = BlockDataMergeSupport.bindPlatformMerger(hook);
|
||||
try {
|
||||
assertSame(merged, BlockDataMergeSupport.merge(base, update));
|
||||
} finally {
|
||||
BlockDataMergeSupport.restorePlatformMerger(previous);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingPlatformTileFactoryFailsLoudly() {
|
||||
IllegalStateException error = assertThrows(IllegalStateException.class,
|
||||
() -> TileData.requirePlatformFactory(null));
|
||||
|
||||
assertEquals("No platform tile-data factory is bound", error.getMessage());
|
||||
public void boundTileFactoryWinsWhenBukkitClassesArePresent() {
|
||||
PlatformBlockState state = mock(PlatformBlockState.class);
|
||||
KMap<String, Object> properties = new KMap<>();
|
||||
TileData expected = mock(TileData.class);
|
||||
TileData.TileFactory hook = mock(TileData.TileFactory.class);
|
||||
when(hook.create(state, properties)).thenReturn(expected);
|
||||
TileData.TileFactory previous = TileData.bindPlatformFactory(hook);
|
||||
try {
|
||||
assertSame(expected, TileData.of(state, properties));
|
||||
} finally {
|
||||
TileData.restorePlatformFactory(previous);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingPlatformTileReaderFailsLoudly() {
|
||||
IOException error = assertThrows(IOException.class,
|
||||
() -> TileData.requirePlatformReader(null));
|
||||
|
||||
assertEquals("No platform tile-data reader is bound", error.getMessage());
|
||||
public void boundTileReaderWinsWhenBukkitClassesArePresent() throws IOException {
|
||||
TileData expected = mock(TileData.class);
|
||||
TileData.TileReader hook = mock(TileData.TileReader.class);
|
||||
DataInputStream input = new DataInputStream(new ByteArrayInputStream(new byte[0]));
|
||||
when(hook.read(input)).thenReturn(expected);
|
||||
TileData.TileReader previous = TileData.bindPlatformReader(hook);
|
||||
try {
|
||||
assertSame(expected, TileData.read(input));
|
||||
} finally {
|
||||
TileData.restorePlatformReader(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,9 @@ import art.arcane.iris.spi.PlatformRegistries;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.junit.Assume;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
@@ -102,6 +104,16 @@ public class BukkitSpiConformanceTest {
|
||||
assertSame(BukkitBlockState.of(first), BukkitBlockState.of(second));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mantleValuesUseStableBukkitInterfaceSlices() {
|
||||
BukkitPlatform platform = new BukkitPlatform();
|
||||
assertTrue(platform.supportsMatterWorldIo());
|
||||
assertSame(World.class, platform.classifyMantleValue(mock(World.class)));
|
||||
assertSame(BlockData.class, platform.classifyMantleValue(blockData("minecraft:stone")));
|
||||
assertSame(Entity.class, platform.classifyMantleValue(mock(Entity.class)));
|
||||
assertSame(String.class, platform.classifyMantleValue("value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockStateKeyMatchesCanonicalString() {
|
||||
BlockData data = blockData("iristest:key_block[facing=north,lit=true]");
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package art.arcane.iris.util.project.matter.slices;
|
||||
|
||||
import art.arcane.iris.spi.IrisPlatform;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import org.bukkit.World;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class IrisMatterPlatformSelectionTest {
|
||||
@Test
|
||||
public void hybridClasspathDoesNotEnableBukkitMatterIoForModdedPlatform() {
|
||||
IrisPlatform platform = mock(IrisPlatform.class);
|
||||
withPlatform(platform, () -> {
|
||||
assertNull(new EntityMatter().readFrom(World.class));
|
||||
assertNull(new TileMatter().readFrom(World.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bukkitPlatformCapabilityEnablesBukkitMatterIo() {
|
||||
IrisPlatform platform = mock(IrisPlatform.class);
|
||||
when(platform.supportsMatterWorldIo()).thenReturn(true);
|
||||
withPlatform(platform, () -> {
|
||||
assertNotNull(new EntityMatter().readFrom(World.class));
|
||||
assertNotNull(new TileMatter().readFrom(World.class));
|
||||
});
|
||||
}
|
||||
|
||||
private void withPlatform(IrisPlatform platform, Runnable test) {
|
||||
IrisPlatform previous = IrisPlatforms.isBound() ? IrisPlatforms.get() : null;
|
||||
IrisPlatforms.unbind();
|
||||
IrisPlatforms.bind(platform);
|
||||
try {
|
||||
test.run();
|
||||
} finally {
|
||||
IrisPlatforms.unbind();
|
||||
if (previous != null) {
|
||||
IrisPlatforms.bind(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user