From 97a3f7e7c35a883b9efacdf9183469e591fa3879 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Fri, 16 Oct 2026 11:21:01 -0400 Subject: [PATCH] Ran tests under NeoForge 1.21.1 - Classpath scans accept the union filesystem the NeoForge 21.1 test harness mounts and skip test classes merged into it - The 1.21.1 NeoForge server access test checks the cached world array the tick loop reads --- .../modded/IrisModLanguageAssetsTest.java | 3 +- .../ModdedClientPackageIsolationTest.java | 7 +- .../NativeNeoForgeServerAccessTest.java | 89 +++++++++++++++++++ 3 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 adapters/neoforge/src/versions/1.21.1/test/java/art/arcane/volmlib/nativelib/minecraft26_2/neoforge/NativeNeoForgeServerAccessTest.java diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/IrisModLanguageAssetsTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/IrisModLanguageAssetsTest.java index 68c402121..c72598b30 100644 --- a/adapters/modded-common/src/test/java/art/arcane/iris/modded/IrisModLanguageAssetsTest.java +++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/IrisModLanguageAssetsTest.java @@ -74,7 +74,8 @@ public class IrisModLanguageAssetsTest { private Set resourceFiles() throws Exception { URL resource = IrisModLanguageAssetsTest.class.getClassLoader().getResource(ROOT + "en_us.json"); assertNotNull("Missing English mod language resource", resource); - assertEquals("Mod language resources must resolve to a directory on disk", "file", resource.getProtocol()); + assertTrue("Mod language resources must resolve to a directory, got " + resource, + resource.getProtocol().equals("file") || resource.getProtocol().equals("union")); Path directory = Path.of(resource.toURI()).getParent(); try (Stream paths = Files.list(directory)) { return paths diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedClientPackageIsolationTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedClientPackageIsolationTest.java index f719be3e9..c91f4fa08 100644 --- a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedClientPackageIsolationTest.java +++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedClientPackageIsolationTest.java @@ -116,7 +116,9 @@ public class ModdedClientPackageIsolationTest { } private static boolean isClassFile(Path path) { - return Files.isRegularFile(path) && path.getFileName().toString().endsWith(".class"); + String name = path.getFileName().toString(); + return Files.isRegularFile(path) && name.endsWith(".class") + && !name.endsWith("Test.class") && !name.contains("Test$"); } private static String readAsLatin1(Path path) throws IOException { @@ -127,7 +129,8 @@ public class ModdedClientPackageIsolationTest { String anchor = "/art/arcane/iris/modded/ModdedMixinAudit.class"; URL located = ModdedClientPackageIsolationTest.class.getResource(anchor); assertNotNull("compiled main classes are not on the test classpath as files", located); - assertEquals("expected a directory classpath entry, got " + located, "file", located.getProtocol()); + assertTrue("expected a directory classpath entry, got " + located, + located.getProtocol().equals("file") || located.getProtocol().equals("union")); Path root = Path.of(located.toURI()); for (int depth = 0; depth < 5; depth++) { root = root.getParent(); diff --git a/adapters/neoforge/src/versions/1.21.1/test/java/art/arcane/volmlib/nativelib/minecraft26_2/neoforge/NativeNeoForgeServerAccessTest.java b/adapters/neoforge/src/versions/1.21.1/test/java/art/arcane/volmlib/nativelib/minecraft26_2/neoforge/NativeNeoForgeServerAccessTest.java new file mode 100644 index 000000000..b6c2bd70f --- /dev/null +++ b/adapters/neoforge/src/versions/1.21.1/test/java/art/arcane/volmlib/nativelib/minecraft26_2/neoforge/NativeNeoForgeServerAccessTest.java @@ -0,0 +1,89 @@ +package art.arcane.volmlib.nativelib.minecraft26_2.neoforge; + +import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedServerAccess; +import art.arcane.volmlib.nativelib.minecraft26_2.modded.ModdedServerLevels; +import art.arcane.volmlib.nativelib.modded.NativeLoaderOptions; +import net.minecraft.SharedConstants; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.Bootstrap; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.LinkedHashMap; +import java.util.function.BooleanSupplier; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class NativeNeoForgeServerAccessTest { + private static final ResourceKey RUNTIME_DIMENSION = + ResourceKey.create(Registries.DIMENSION, ResourceLocation.fromNamespaceAndPath("irisworldgen", "runtime")); + + @BeforeClass + public static void bootstrap() { + SharedConstants.tryDetectVersion(); + Bootstrap.bootStrap(); + } + + @After + public void forgetLevelSnapshot() { + ModdedServerLevels.forget(); + } + + @Test + public void runtimeLevelsJoinAndLeaveTheServerTickView() throws ReflectiveOperationException { + ModdedServerAccess access = new NativeNeoForgeLoader( + new NativeLoaderOptions("irisworldgen", "treefeller", BooleanSupplier::getAsBoolean)).serverAccess(); + MinecraftServer server = serverWithLiveLevelMap(); + ServerLevel level = mock(ServerLevel.class); + when(level.dimension()).thenReturn(RUNTIME_DIMENSION); + + assertNull(access.putLevelIfAbsent(server, RUNTIME_DIMENSION, level)); + assertTrue(access.hasLevel(server, RUNTIME_DIMENSION)); + assertTrue(ticks(server, level)); + assertSame(level, ModdedServerLevels.level(server, RUNTIME_DIMENSION)); + + assertSame(level, access.removeLevel(server, RUNTIME_DIMENSION)); + assertFalse(access.hasLevel(server, RUNTIME_DIMENSION)); + assertFalse(ticks(server, level)); + assertNull(ModdedServerLevels.level(server, RUNTIME_DIMENSION)); + + assertNull(access.putLevel(server, RUNTIME_DIMENSION, level)); + assertTrue(ticks(server, level)); + assertSame(level, ModdedServerLevels.level(server, RUNTIME_DIMENSION)); + } + + private static MinecraftServer serverWithLiveLevelMap() throws ReflectiveOperationException { + MinecraftServer server = mock(MinecraftServer.class); + Field levels = MinecraftServer.class.getDeclaredField("levels"); + levels.setAccessible(true); + levels.set(server, new LinkedHashMap, ServerLevel>()); + doCallRealMethod().when(server).getAllLevels(); + doCallRealMethod().when(server).markWorldsDirty(); + return server; + } + + private static boolean ticks(MinecraftServer server, ServerLevel expected) throws ReflectiveOperationException { + Method worldArray = MinecraftServer.class.getDeclaredMethod("getWorldArray"); + worldArray.setAccessible(true); + for (ServerLevel level : (ServerLevel[]) worldArray.invoke(server)) { + if (level == expected) { + return true; + } + } + return false; + } +}