WIP Building for latest.

Still Quantizing, WOrking on that next
also removed prebake
This commit is contained in:
Brian Neumann-Fopiano
2026-04-15 09:05:41 -04:00
parent 568fb07f66
commit aa706d027b
97 changed files with 8003 additions and 3087 deletions
@@ -0,0 +1,74 @@
package art.arcane.iris;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class IrisDiagnosticsTest {
@Test
public void reportErrorWithContextPrintsFullStacktrace() {
ByteArrayOutputStream output = new ByteArrayOutputStream();
PrintStream originalErr = System.err;
System.setErr(new PrintStream(output, true, StandardCharsets.UTF_8));
try {
Iris.reportError("Runtime world creation failed.", new IllegalStateException("outer", new IllegalArgumentException("inner")));
} finally {
System.setErr(originalErr);
}
String text = output.toString(StandardCharsets.UTF_8);
assertTrue(text.contains("Runtime world creation failed."));
assertTrue(text.contains("IllegalStateException"));
assertTrue(text.contains("IllegalArgumentException"));
assertTrue(text.contains("inner"));
}
@Test
public void collectSplashPacksSkipsInternalAndInvalidFolders() throws Exception {
Path root = Files.createTempDirectory("iris-splash");
try {
Path validPack = root.resolve("overworld");
Files.createDirectories(validPack.resolve("dimensions"));
Files.writeString(validPack.resolve("dimensions").resolve("overworld.json"), "{\"version\":\"4000\"}");
Files.createDirectories(root.resolve("datapack-imports"));
Path brokenPack = root.resolve("broken");
Files.createDirectories(brokenPack.resolve("dimensions"));
Files.writeString(brokenPack.resolve("dimensions").resolve("broken.json"), "{");
ByteArrayOutputStream output = new ByteArrayOutputStream();
PrintStream originalErr = System.err;
System.setErr(new PrintStream(output, true, StandardCharsets.UTF_8));
List<Iris.SplashPackMetadata> packs;
try {
packs = Iris.collectSplashPacks(root.toFile());
} finally {
System.setErr(originalErr);
}
assertEquals(1, packs.size());
assertEquals("overworld", packs.get(0).name());
assertEquals("4000", packs.get(0).version());
String text = output.toString(StandardCharsets.UTF_8);
assertTrue(text.contains("Failed to read splash metadata for dimension pack \"broken\"."));
assertTrue(text.contains("Json"));
} finally {
Files.walk(root)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
}
}
@@ -37,6 +37,16 @@ public class IrisRuntimeSchedulerModeRoutingTest {
assertEquals(IrisRuntimeSchedulerMode.FOLIA, resolved);
}
@Test
public void autoResolvesToPaperLikeOnCanvasBranding() {
installServer("Canvas", "git-Canvas-101 (MC: 1.21.11)");
IrisSettings.IrisSettingsPregen pregen = new IrisSettings.IrisSettingsPregen();
pregen.runtimeSchedulerMode = IrisRuntimeSchedulerMode.AUTO;
IrisRuntimeSchedulerMode resolved = IrisRuntimeSchedulerMode.resolve(pregen);
assertEquals(IrisRuntimeSchedulerMode.PAPER_LIKE, resolved);
}
@Test
public void explicitModeBypassesAutoDetection() {
installServer("Purpur", "git-Purpur-2562 (MC: 1.21.11)");
@@ -0,0 +1,44 @@
package art.arcane.iris.core;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KMap;
import org.junit.Test;
import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class ServerConfiguratorDatapackFolderTest {
@Test
public void resolvesDimensionWorldFolderBackToRootDatapacks() {
File folder = new File("/tmp/server/world/dimensions/minecraft/overworld");
File datapacks = ServerConfigurator.resolveDatapacksFolder(folder);
assertEquals(new File("/tmp/server/world/datapacks").getAbsolutePath(), datapacks.getAbsolutePath());
}
@Test
public void keepsStandaloneWorldFolderDatapacksUnchanged() {
File folder = new File("/tmp/server/custom_world");
File datapacks = ServerConfigurator.resolveDatapacksFolder(folder);
assertEquals(new File("/tmp/server/custom_world/datapacks").getAbsolutePath(), datapacks.getAbsolutePath());
}
@Test
public void installFoldersIncludeExtraStudioWorldDatapackTargets() {
File baseFolder = new File("/tmp/server/world/datapacks");
File extraFolder = new File("/tmp/server/iris-studio/datapacks");
KList<File> baseFolders = new KList<>();
baseFolders.add(baseFolder);
KList<File> extraFolders = new KList<>();
extraFolders.add(extraFolder);
KMap<String, KList<File>> extrasByPack = new KMap<>();
extrasByPack.put("overworld", extraFolders);
KList<File> folders = ServerConfigurator.collectInstallDatapackFolders(baseFolders, extrasByPack);
assertEquals(2, folders.size());
assertTrue(folders.contains(baseFolder));
assertTrue(folders.contains(extraFolder));
}
}
@@ -0,0 +1,47 @@
package art.arcane.iris.core;
import art.arcane.iris.core.commands.CommandStudio;
import art.arcane.iris.core.tools.IrisCreator;
import org.junit.Test;
import java.util.Arrays;
import static org.junit.Assert.assertFalse;
public class StudioRuntimeCleanupTest {
@Test
public void pregenSettingsNoLongerExposeStartupNoisemapPrebake() {
boolean found = Arrays.stream(IrisSettings.IrisSettingsPregen.class.getDeclaredFields())
.anyMatch(field -> field.getName().equals("startupNoisemapPrebake"));
assertFalse(found);
}
@Test
public void studioCommandNoLongerExposesProfilecache() {
boolean found = Arrays.stream(CommandStudio.class.getDeclaredMethods())
.anyMatch(method -> method.getName().equals("profilecache"));
assertFalse(found);
}
@Test
public void studioCreatorNoLongerContainsPrewarmOrPrebakeHelpers() {
boolean found = Arrays.stream(IrisCreator.class.getDeclaredMethods())
.map(method -> method.getName().toLowerCase())
.anyMatch(name -> name.contains("prewarm") || name.contains("prebake"));
assertFalse(found);
}
@Test
public void noisemapPrebakePipelineClassIsRemoved() {
try {
Class.forName("art.arcane.iris.engine.IrisNoisemapPrebakePipeline");
} catch (ClassNotFoundException ignored) {
return;
}
throw new AssertionError("IrisNoisemapPrebakePipeline should not exist.");
}
}
@@ -0,0 +1,164 @@
package art.arcane.iris.core.lifecycle;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import static org.junit.Assert.assertEquals;
public class CapabilityResolutionTest {
@Test
public void resolvesExactCreateLevelMethod() throws Exception {
Method method = CapabilityResolution.resolveCreateLevelMethod(CurrentCreateLevelOwner.class);
assertEquals("createLevel", method.getName());
assertEquals(3, method.getParameterCount());
}
@Test
public void resolvesDeclaredLegacyCreateLevelMethod() throws Exception {
Method method = CapabilityResolution.resolveCreateLevelMethod(DeclaredLegacyCreateLevelOwner.class);
assertEquals("createLevel", method.getName());
assertEquals(4, method.getParameterCount());
}
@Test
public void resolvesTwoArgLevelStorageAccessMethod() throws Exception {
Method method = CapabilityResolution.resolveLevelStorageAccessMethod(TwoArgLevelStorageSource.class);
assertEquals("validateAndCreateAccess", method.getName());
assertEquals(2, method.getParameterCount());
}
@Test
public void resolvesOneArgLevelStorageAccessMethod() throws Exception {
Method method = CapabilityResolution.resolveLevelStorageAccessMethod(OneArgLevelStorageSource.class);
assertEquals("validateAndCreateAccess", method.getName());
assertEquals(1, method.getParameterCount());
}
@Test
public void resolvesPublicWorldDataHelper() throws Exception {
Method method = CapabilityResolution.resolvePaperWorldDataMethod(PublicWorldLoader.class);
assertEquals("loadWorldData", method.getName());
assertEquals(3, method.getParameterCount());
}
@Test
public void resolvesDeclaredWorldDataHelper() throws Exception {
Method method = CapabilityResolution.resolvePaperWorldDataMethod(DeclaredWorldLoader.class);
assertEquals("loadWorldData", method.getName());
assertEquals(3, method.getParameterCount());
}
@Test
public void resolvesDeclaredServerRegistryAccessMethod() throws Exception {
Method method = CapabilityResolution.resolveServerRegistryAccessMethod(DeclaredRegistryAccessOwner.class);
assertEquals("registryAccess", method.getName());
assertEquals(0, method.getParameterCount());
}
@Test
public void resolvesCurrentWorldLoadingInfoConstructor() throws Exception {
Constructor<?> constructor = CapabilityResolution.resolveWorldLoadingInfoConstructor(CurrentWorldLoadingInfo.class);
assertEquals(4, constructor.getParameterCount());
}
@Test
public void resolvesLegacyWorldLoadingInfoConstructor() throws Exception {
Constructor<?> constructor = CapabilityResolution.resolveWorldLoadingInfoConstructor(LegacyWorldLoadingInfo.class);
assertEquals(5, constructor.getParameterCount());
}
public static final class LevelStem {
}
public static final class WorldLoadingInfo {
}
public static final class WorldLoadingInfoAndData {
}
public static final class WorldDataAndGenSettings {
}
public static final class PrimaryLevelData {
}
public static final class LevelStorageAccess {
}
public static final class ResourceKey {
}
public static final class LoadedWorldData {
}
public static final class MinecraftServer {
}
public static final class RegistryAccess {
}
public enum Environment {
NORMAL
}
public static final class CurrentCreateLevelOwner {
public void createLevel(LevelStem levelStem, WorldLoadingInfoAndData worldLoadingInfoAndData, WorldDataAndGenSettings worldDataAndGenSettings) {
}
}
public static final class DeclaredLegacyCreateLevelOwner {
private void createLevel(LevelStem levelStem, WorldLoadingInfo worldLoadingInfo, LevelStorageAccess levelStorageAccess, PrimaryLevelData primaryLevelData) {
}
}
public static final class TwoArgLevelStorageSource {
public LevelStorageAccess validateAndCreateAccess(String worldName, ResourceKey resourceKey) {
return null;
}
}
public static final class OneArgLevelStorageSource {
public LevelStorageAccess validateAndCreateAccess(String worldName) {
return null;
}
}
public static final class PublicWorldLoader {
public static LoadedWorldData loadWorldData(MinecraftServer minecraftServer, ResourceKey dimensionKey, String worldName) {
return null;
}
}
public static final class DeclaredWorldLoader {
private static LoadedWorldData loadWorldData(MinecraftServer minecraftServer, ResourceKey dimensionKey, String worldName) {
return null;
}
}
public static final class DeclaredRegistryAccessOwner {
private RegistryAccess registryAccess() {
return null;
}
}
public static final class CurrentWorldLoadingInfo {
public CurrentWorldLoadingInfo(Environment environment, ResourceKey stemKey, ResourceKey dimensionKey, boolean enabled) {
}
}
public static final class LegacyWorldLoadingInfo {
private LegacyWorldLoadingInfo(int index, String worldName, String environment, ResourceKey stemKey, boolean enabled) {
}
}
}
@@ -0,0 +1,38 @@
package art.arcane.iris.core.lifecycle;
import org.bukkit.World;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletionException;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class WorldLifecycleDiagnosticsTest {
@Test
public void studioCreateSelectionFailurePrintsFullStacktrace() {
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, false));
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
ByteArrayOutputStream output = new ByteArrayOutputStream();
PrintStream originalErr = System.err;
System.setErr(new PrintStream(output, true, StandardCharsets.UTF_8));
try {
try {
service.create(request).join();
fail("Expected lifecycle create to fail when paper_like_runtime is unavailable.");
} catch (CompletionException | IllegalStateException ignored) {
}
} finally {
System.setErr(originalErr);
}
String text = output.toString(StandardCharsets.UTF_8);
assertTrue(text.contains("WorldLifecycle create backend selection failed"));
assertTrue(text.contains("paper_like_runtime"));
assertTrue(text.contains("IllegalStateException"));
}
}
@@ -0,0 +1,142 @@
package art.arcane.iris.core.lifecycle;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.nms.INMSBinding;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.EngineTarget;
import art.arcane.iris.engine.platform.ChunkReplacementListener;
import art.arcane.iris.engine.platform.ChunkReplacementOptions;
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
public class WorldLifecycleRuntimeLevelStemTest {
@Test
public void runtimeStemUsesFullServerRegistryAccessForPlatformGenerators() throws Exception {
Object datapackDimensions = new MissingDimensionTypeRegistry();
Object serverRegistryAccess = new Object();
CapabilitySnapshot capabilities = CapabilitySnapshot.forTestingRuntimeRegistries(ServerFamily.PURPUR, false, datapackDimensions, serverRegistryAccess);
WorldLifecycleRequest request = new WorldLifecycleRequest(
"studio",
World.Environment.NORMAL,
new TestingPlatformChunkGenerator(),
null,
null,
true,
false,
1337L,
true,
false,
WorldLifecycleCaller.STUDIO
);
AtomicReference<Object> seenRegistryAccess = new AtomicReference<>();
INMSBinding binding = createBinding((registryAccess, generator) -> {
seenRegistryAccess.set(registryAccess);
return "runtime-stem";
});
Object levelStem = WorldLifecycleSupport.resolveRuntimeLevelStem(capabilities, request, binding);
assertEquals("runtime-stem", levelStem);
assertSame(serverRegistryAccess, seenRegistryAccess.get());
assertNotSame(datapackDimensions, seenRegistryAccess.get());
}
private static INMSBinding createBinding(RuntimeStemFactory factory) {
InvocationHandler handler = (proxy, method, args) -> {
if ("createRuntimeLevelStem".equals(method.getName())) {
return factory.create(args[0], (ChunkGenerator) args[1]);
}
Class<?> returnType = method.getReturnType();
if (boolean.class.equals(returnType)) {
return false;
}
if (int.class.equals(returnType)) {
return 0;
}
if (long.class.equals(returnType)) {
return 0L;
}
if (float.class.equals(returnType)) {
return 0F;
}
if (double.class.equals(returnType)) {
return 0D;
}
return null;
};
return (INMSBinding) Proxy.newProxyInstance(
INMSBinding.class.getClassLoader(),
new Class[]{INMSBinding.class},
handler
);
}
@FunctionalInterface
private interface RuntimeStemFactory {
Object create(Object registryAccess, ChunkGenerator generator);
}
private static final class MissingDimensionTypeRegistry {
}
private static final class TestingPlatformChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator {
@Override
public Engine getEngine() {
return null;
}
@Override
public IrisData getData() {
return null;
}
@Override
public EngineTarget getTarget() {
return null;
}
@Override
public void injectChunkReplacement(World world, int x, int z, Executor syncExecutor, ChunkReplacementOptions options, ChunkReplacementListener listener) {
}
@Override
public void close() {
}
@Override
public boolean isStudio() {
return true;
}
@Override
public void touch(World world) {
}
@Override
public CompletableFuture<Integer> getSpawnChunks() {
return CompletableFuture.completedFuture(0);
}
@Override
public Location getInitialSpawnLocation(World world) {
return null;
}
@Override
public void hotload() {
}
}
}
@@ -0,0 +1,64 @@
package art.arcane.iris.core.lifecycle;
import org.bukkit.World;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class WorldLifecycleSelectionTest {
@Test
public void studioSelectsPaperLikeBackendOnPaper() {
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, true));
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
}
@Test
public void studioSelectsPaperLikeBackendOnPurpur() {
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
}
@Test
public void studioSelectsPaperLikeBackendOnCanvas() {
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.CANVAS, true, false, true));
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
}
@Test
public void studioSelectsPaperLikeBackendOnFolia() {
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, true));
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
}
@Test
public void studioSelectsBukkitBackendOnSpigot() {
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.SPIGOT, false, false, false));
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
}
@Test
public void persistentCreatePrefersBukkitBackendOnPaperLikeServers() {
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
}
@Test
public void unloadUsesRememberedBackendFamily() {
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
service.rememberBackend("studio", "paper_like_runtime");
assertEquals("paper_like_runtime", service.selectUnloadBackend("studio").backendName());
}
}
@@ -0,0 +1,46 @@
package art.arcane.iris.core.lifecycle;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
import org.junit.Test;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
public class WorldLifecycleStagingTest {
@Test
public void stagedGeneratorIsConsumedExactlyOnce() {
ChunkGenerator generator = mock(ChunkGenerator.class);
WorldLifecycleStaging.stageGenerator("world", generator, null);
assertSame(generator, WorldLifecycleStaging.consumeGenerator("world"));
assertNull(WorldLifecycleStaging.consumeGenerator("world"));
}
@Test
public void stagedStemGeneratorIsIndependentFromGeneratorConsumption() {
ChunkGenerator generator = mock(ChunkGenerator.class);
WorldLifecycleStaging.stageGenerator("world", generator, null);
WorldLifecycleStaging.stageStemGenerator("world", generator);
assertSame(generator, WorldLifecycleStaging.consumeGenerator("world"));
assertSame(generator, WorldLifecycleStaging.consumeStemGenerator("world"));
}
@Test
public void clearAllRemovesGeneratorBiomeAndStemState() {
ChunkGenerator generator = mock(ChunkGenerator.class);
BiomeProvider biomeProvider = mock(BiomeProvider.class);
WorldLifecycleStaging.stageGenerator("world", generator, biomeProvider);
WorldLifecycleStaging.stageStemGenerator("world", generator);
WorldLifecycleStaging.clearAll("world");
assertNull(WorldLifecycleStaging.consumeGenerator("world"));
assertNull(WorldLifecycleStaging.consumeBiomeProvider("world"));
assertNull(WorldLifecycleStaging.consumeStemGenerator("world"));
}
}
@@ -0,0 +1,31 @@
package art.arcane.iris.core.nms;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class INMSBindingProbeCodesTest {
@Test
public void skipsSyntheticBukkitBindingWhenNmsIsEnabled() {
List<String> probeCodes = NmsBindingProbeSupport.getBindingProbeCodes("BUKKIT", false, List.of("v1_21_R7"));
assertEquals(List.of("v1_21_R7"), probeCodes);
}
@Test
public void leavesBukkitFallbackEmptyWhenNmsIsDisabled() {
List<String> probeCodes = NmsBindingProbeSupport.getBindingProbeCodes("BUKKIT", true, List.of("v1_21_R7"));
assertTrue(probeCodes.isEmpty());
}
@Test
public void keepsConcreteBindingCodesAsPrimaryProbe() {
List<String> probeCodes = NmsBindingProbeSupport.getBindingProbeCodes("v1_21_R7", false, List.of("v1_21_R7"));
assertEquals(List.of("v1_21_R7"), probeCodes);
}
}
@@ -0,0 +1,63 @@
package art.arcane.iris.core.nms;
import org.bukkit.Server;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
public class MinecraftVersionTest {
private interface PaperLikeServer extends Server {
String getMinecraftVersion();
}
@Test
public void detectsMinecraftVersionFromPurpurDecoratedVersion() {
Server server = mock(Server.class);
doReturn("git-Purpur-2570 (MC: 1.21.11)").when(server).getVersion();
doReturn("26.1.2.build.2570-experimental").when(server).getBukkitVersion();
MinecraftVersion version = MinecraftVersion.detect(server);
assertEquals("1.21.11", version.value());
assertEquals(21, version.major());
assertEquals(11, version.minor());
}
@Test
public void prefersRuntimeMinecraftVersionMethodWhenPresent() {
PaperLikeServer server = mock(PaperLikeServer.class);
doReturn("1.21.11").when(server).getMinecraftVersion();
doReturn("26.1.2-2570-e64b1b2 (MC: 26.1.2)").when(server).getVersion();
doReturn("26.1.2.build.2570-experimental").when(server).getBukkitVersion();
MinecraftVersion version = MinecraftVersion.detect(server);
assertEquals("1.21.11", version.value());
assertEquals(21, version.major());
assertEquals(11, version.minor());
}
@Test
public void rejectsPurpurApiBuildNumbersAsMinecraftVersion() {
MinecraftVersion version = MinecraftVersion.fromBukkitVersion("26.1.2.build.2570-experimental");
assertNull(version);
}
@Test
public void parsesStandardBukkitSnapshotVersion() {
MinecraftVersion version = MinecraftVersion.fromBukkitVersion("1.21.11-R0.1-SNAPSHOT");
assertEquals("1.21.11", version.value());
assertEquals(21, version.major());
assertEquals(11, version.minor());
}
@Test
public void comparesMajorBeforeMinor() {
MinecraftVersion version = MinecraftVersion.fromBukkitVersion("1.20.12-R0.1-SNAPSHOT");
assertFalse(version.isAtLeast(21, 11));
assertTrue(version.isNewerThan(20, 11));
}
}
@@ -0,0 +1,28 @@
package art.arcane.iris.core.nms.datapack.v1217;
import art.arcane.iris.core.nms.datapack.IDataFixer.Dimension;
import art.arcane.volmlib.util.json.JSONObject;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class DataFixerV1217DimensionTypeTest {
private final DataFixerV1217 fixer = new DataFixerV1217();
@Test
public void createsOverworldDimensionWithDragonFightDisabled() {
JSONObject json = fixer.createDimension(Dimension.OVERWORLD, -256, 768, 512, null);
assertTrue(json.has("has_ender_dragon_fight"));
assertEquals(false, json.getBoolean("has_ender_dragon_fight"));
}
@Test
public void createsEndDimensionWithDragonFightEnabled() {
JSONObject json = fixer.createDimension(Dimension.END, 0, 256, 256, null);
assertTrue(json.has("has_ender_dragon_fight"));
assertEquals(true, json.getBoolean("has_ender_dragon_fight"));
}
}
@@ -0,0 +1,45 @@
package art.arcane.iris.core.runtime;
import org.junit.Test;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class DatapackReadinessResultTest {
@Test
public void verificationUsesDimensionTypeKeyPath() throws Exception {
Path root = Files.createTempDirectory("iris-datapack-readiness");
Path datapackRoot = root.resolve("iris");
Files.createDirectories(datapackRoot.resolve("data/iris/dimension_type"));
Files.writeString(datapackRoot.resolve("pack.mcmeta"), "{}");
Files.writeString(datapackRoot.resolve("data/iris/dimension_type/runtime-key.json"), "{}");
ArrayList<String> verifiedPaths = new ArrayList<>();
ArrayList<String> missingPaths = new ArrayList<>();
DatapackReadinessResult.collectVerificationPaths(root.toFile(), "runtime-key", verifiedPaths, missingPaths);
assertTrue(missingPaths.isEmpty());
assertEquals(2, verifiedPaths.size());
}
@Test
public void verificationMarksMissingDimensionTypePath() throws Exception {
Path root = Files.createTempDirectory("iris-datapack-readiness-missing");
Path datapackRoot = root.resolve("iris");
Files.createDirectories(datapackRoot);
Files.writeString(datapackRoot.resolve("pack.mcmeta"), "{}");
ArrayList<String> verifiedPaths = new ArrayList<>();
ArrayList<String> missingPaths = new ArrayList<>();
DatapackReadinessResult.collectVerificationPaths(root.toFile(), "runtime-key", verifiedPaths, missingPaths);
assertEquals(1, verifiedPaths.size());
assertEquals(1, missingPaths.size());
assertTrue(missingPaths.get(0).endsWith(File.separator + "iris" + File.separator + "data" + File.separator + "iris" + File.separator + "dimension_type" + File.separator + "runtime-key.json"));
}
}
@@ -0,0 +1,28 @@
package art.arcane.iris.core.runtime;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class SmokeDiagnosticsServiceCloseStateTest {
@Test
public void closeStateIsPersistedIntoRunSnapshot() {
SmokeDiagnosticsService service = SmokeDiagnosticsService.get();
SmokeDiagnosticsService.SmokeRunHandle handle = service.beginRun(
SmokeDiagnosticsService.SmokeRunMode.STUDIO_CLOSE,
"iris-test-world",
true,
true,
null,
false
);
handle.setCloseState(true, false, true);
SmokeDiagnosticsService.SmokeRunReport report = handle.snapshot();
assertTrue(report.isCloseUnloadCompletedLive());
assertFalse(report.isCloseFolderDeletionCompletedLive());
assertTrue(report.isCloseStartupCleanupQueued());
}
}
@@ -0,0 +1,63 @@
package art.arcane.iris.core.runtime;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.LinkedHashSet;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class TransientWorldCleanupSupportTest {
@Test
public void identifiesTransientStudioBaseNamesAndSidecars() {
String baseName = "iris-123e4567-e89b-12d3-a456-426614174000";
assertTrue(TransientWorldCleanupSupport.isTransientStudioWorldName(baseName));
assertEquals(baseName, TransientWorldCleanupSupport.transientStudioBaseWorldName(baseName));
assertEquals(baseName, TransientWorldCleanupSupport.transientStudioBaseWorldName(baseName + "_nether"));
assertEquals(baseName, TransientWorldCleanupSupport.transientStudioBaseWorldName(baseName + "_the_end"));
assertFalse(TransientWorldCleanupSupport.isTransientStudioWorldName("iris-smoke-studio-deadbeef"));
assertNull(TransientWorldCleanupSupport.transientStudioBaseWorldName("overworld"));
}
@Test
public void expandsWorldFamilyNamesForDeletion() {
String baseName = "iris-123e4567-e89b-12d3-a456-426614174000";
List<String> names = TransientWorldCleanupSupport.worldFamilyNames(baseName);
assertEquals(List.of(baseName, baseName + "_nether", baseName + "_the_end"), names);
}
@Test
public void collectsOnlyTransientStudioWorldFamiliesFromContainer() throws IOException {
File container = Files.createTempDirectory("transient-world-cleanup-test").toFile();
String baseName = "iris-123e4567-e89b-12d3-a456-426614174000";
File baseFolder = new File(container, baseName);
File netherFolder = new File(container, baseName + "_nether");
File smokeFolder = new File(container, "iris-smoke-studio-deadbeef");
File regularFolder = new File(container, "overworld");
baseFolder.mkdirs();
netherFolder.mkdirs();
smokeFolder.mkdirs();
regularFolder.mkdirs();
try {
LinkedHashSet<String> names = TransientWorldCleanupSupport.collectTransientStudioWorldNames(container);
assertEquals(new LinkedHashSet<>(List.of(baseName)), names);
} finally {
Files.deleteIfExists(baseFolder.toPath());
Files.deleteIfExists(netherFolder.toPath());
Files.deleteIfExists(smokeFolder.toPath());
Files.deleteIfExists(regularFolder.toPath());
Files.deleteIfExists(container.toPath());
}
}
}
@@ -0,0 +1,59 @@
package art.arcane.iris.core.runtime;
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
import org.bukkit.Location;
import org.bukkit.World;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
public class WorldRuntimeControlServiceSafeEntryTest {
@Test
public void resolvesStudioEntryAnchorFromGeneratorInsteadOfMutableWorldSpawn() {
World world = mock(World.class);
PlatformChunkGenerator provider = mock(PlatformChunkGenerator.class);
Location initialSpawn = new Location(world, 0.5D, 96D, 0.5D);
Location mutableWorldSpawn = new Location(world, 128.5D, 80D, -64.5D);
doReturn(true).when(provider).isStudio();
doReturn(initialSpawn).when(provider).getInitialSpawnLocation(world);
doReturn(mutableWorldSpawn).when(world).getSpawnLocation();
Location resolved = WorldRuntimeControlService.resolveEntryAnchor(world, provider);
assertEquals(initialSpawn, resolved);
}
@Test
public void fallsBackToWorldSpawnWhenGeneratorIsNotStudio() {
World world = mock(World.class);
PlatformChunkGenerator provider = mock(PlatformChunkGenerator.class);
Location mutableWorldSpawn = new Location(world, 128.5D, 80D, -64.5D);
doReturn(false).when(provider).isStudio();
doReturn(mutableWorldSpawn).when(world).getSpawnLocation();
Location resolved = WorldRuntimeControlService.resolveEntryAnchor(world, provider);
assertEquals(mutableWorldSpawn, resolved);
}
@Test
public void scansFromRuntimeSurfaceBeforeFallingThroughRemainingWorldHeight() {
World world = mock(World.class);
doReturn(0).when(world).getMinHeight();
doReturn(256).when(world).getMaxHeight();
doReturn(179).when(world).getHighestBlockYAt(0, 0);
int[] scanOrder = WorldRuntimeControlService.buildSafeLocationScanOrder(world, new Location(world, 0.5D, 96D, 0.5D));
assertEquals(180, scanOrder[0]);
assertEquals(179, scanOrder[1]);
assertEquals(1, scanOrder[179]);
assertEquals(181, scanOrder[180]);
assertEquals(254, scanOrder[scanOrder.length - 1]);
}
}
@@ -0,0 +1,239 @@
package art.arcane.iris.core.runtime;
import art.arcane.iris.core.lifecycle.CapabilitySnapshot;
import art.arcane.iris.core.lifecycle.ServerFamily;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.plugin.PluginManager;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.OptionalLong;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
public class WorldRuntimeControlServiceTimeLockTest {
@Before
public void ensureBukkitServer() {
if (Bukkit.getServer() != null) {
return;
}
Server server = mock(Server.class);
PluginManager pluginManager = mock(PluginManager.class);
doReturn(pluginManager).when(server).getPluginManager();
doReturn(Logger.getLogger("WorldRuntimeControlServiceTimeLockTest")).when(server).getLogger();
Bukkit.setServer(server);
}
@Test
public void skipsTimeLockWhenWorldDoesNotExposeMutableClock() throws Exception {
AtomicBoolean setTimeCalled = new AtomicBoolean(false);
AtomicLong dayTime = new AtomicLong(0L);
World world = createWorldProxy("fixed", true, setTimeCalled, dayTime, false);
boolean applied = createService().applyNoonTimeLock(world);
assertFalse(applied);
assertFalse(setTimeCalled.get());
}
@Test
public void skipsTimeLockWhenRuntimeSetterRejectsClockMutation() throws Exception {
AtomicBoolean setTimeCalled = new AtomicBoolean(false);
AtomicLong dayTime = new AtomicLong(0L);
World world = createWorldProxy("no-clock", false, setTimeCalled, dayTime, true);
boolean applied = createService().applyNoonTimeLock(world);
assertFalse(applied);
assertTrue(setTimeCalled.get());
}
@Test
public void appliesTimeLockWhenWorldHasMutableClock() throws Exception {
AtomicBoolean setTimeCalled = new AtomicBoolean(false);
AtomicLong dayTime = new AtomicLong(0L);
World world = createWorldProxy("mutable", false, setTimeCalled, dayTime, false);
boolean applied = createService().applyNoonTimeLock(world);
assertTrue(applied);
assertTrue(setTimeCalled.get());
assertTrue(dayTime.get() == 6000L);
}
private WorldRuntimeControlService createService() throws Exception {
Constructor<CapabilitySnapshot> snapshotConstructor = CapabilitySnapshot.class.getDeclaredConstructor(
ServerFamily.class,
boolean.class,
Object.class,
Class.class,
Class.class,
String.class,
Object.class,
Object.class,
java.lang.reflect.Method.class,
CapabilitySnapshot.PaperLikeFlavor.class,
Class.class,
java.lang.reflect.Method.class,
java.lang.reflect.Constructor.class,
java.lang.reflect.Constructor.class,
java.lang.reflect.Method.class,
java.lang.reflect.Method.class,
java.lang.reflect.Field.class,
java.lang.reflect.Method.class,
java.lang.reflect.Field.class,
java.lang.reflect.Field.class,
java.lang.reflect.Method.class,
java.lang.reflect.Method.class,
java.lang.reflect.Method.class,
java.lang.reflect.Method.class,
String.class
);
snapshotConstructor.setAccessible(true);
CapabilitySnapshot snapshot = snapshotConstructor.newInstance(
ServerFamily.PAPER,
false,
null,
null,
null,
"test",
Bukkit.getServer(),
null,
null,
CapabilitySnapshot.PaperLikeFlavor.UNSUPPORTED,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
"test"
);
Constructor<WorldRuntimeControlService> serviceConstructor = WorldRuntimeControlService.class.getDeclaredConstructor(CapabilitySnapshot.class);
serviceConstructor.setAccessible(true);
return serviceConstructor.newInstance(snapshot);
}
private World createWorldProxy(String name, boolean fixedTime, AtomicBoolean setTimeCalled, AtomicLong dayTime, boolean throwOnSetTime) {
Object dimensionType = Proxy.newProxyInstance(
World.class.getClassLoader(),
new Class[]{DimensionTypeProbe.class},
(proxy, method, args) -> {
if ("hasFixedTime".equals(method.getName())) {
return fixedTime;
}
if ("fixedTime".equals(method.getName())) {
return fixedTime ? OptionalLong.of(6000L) : OptionalLong.empty();
}
return null;
}
);
Object holder = Proxy.newProxyInstance(
World.class.getClassLoader(),
new Class[]{HolderProbe.class},
(proxy, method, args) -> {
if ("value".equals(method.getName())) {
return dimensionType;
}
return null;
}
);
Object handle = Proxy.newProxyInstance(
World.class.getClassLoader(),
new Class[]{HandleProbe.class},
(proxy, method, args) -> {
if ("dimensionTypeRegistration".equals(method.getName())) {
return holder;
}
if ("getDayTime".equals(method.getName())) {
return dayTime.get();
}
if ("setDayTime".equals(method.getName())) {
setTimeCalled.set(true);
if (throwOnSetTime) {
throw new IllegalArgumentException("Cannot set time in world without world clock");
}
dayTime.set(((Long) args[0]).longValue());
return null;
}
return null;
}
);
return (World) Proxy.newProxyInstance(
World.class.getClassLoader(),
new Class[]{World.class, WorldHandleProbe.class},
(proxy, method, args) -> {
if ("getName".equals(method.getName())) {
return name;
}
if ("getHandle".equals(method.getName())) {
return handle;
}
if ("getFullTime".equals(method.getName())) {
return dayTime.get();
}
Class<?> returnType = method.getReturnType();
if (boolean.class.equals(returnType)) {
return false;
}
if (int.class.equals(returnType)) {
return 0;
}
if (long.class.equals(returnType)) {
return 0L;
}
if (float.class.equals(returnType)) {
return 0F;
}
if (double.class.equals(returnType)) {
return 0D;
}
return null;
}
);
}
private interface WorldHandleProbe {
Object getHandle();
}
private interface HandleProbe {
Object dimensionTypeRegistration();
long getDayTime();
void setDayTime(long time);
}
private interface HolderProbe {
Object value();
}
private interface DimensionTypeProbe {
boolean hasFixedTime();
OptionalLong fixedTime();
}
}
@@ -0,0 +1,47 @@
package art.arcane.iris.engine.framework;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertTrue;
public class GenerationSessionManagerTest {
@Test
public void teardownSealMarksRejectedWorkAsExpected() throws Exception {
GenerationSessionManager manager = new GenerationSessionManager();
manager.sealAndAwait("close", 1000L, true);
try {
manager.acquire("chunk_generate");
} catch (GenerationSessionException e) {
assertTrue(e.isExpectedTeardown());
assertTrue(e.getMessage().contains("during close"));
return;
}
throw new AssertionError("Expected teardown rejection.");
}
@Test
public void sealAndAwaitCompletesWhenOutstandingLeaseReleases() throws Exception {
GenerationSessionManager manager = new GenerationSessionManager();
GenerationSessionLease lease = manager.acquire("chunk_generate");
CountDownLatch latch = new CountDownLatch(1);
Thread releaser = new Thread(() -> {
try {
latch.await(200L, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
lease.close();
});
releaser.start();
latch.countDown();
manager.sealAndAwait("close", 1000L, true);
}
}
@@ -0,0 +1,23 @@
package art.arcane.iris.engine.object;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class IrisDimensionTypeKeyTest {
@Test
public void dimensionTypeKeyUsesSanitizedSemanticPackKey() {
IrisDimension dimension = new IrisDimension();
dimension.setLoadKey("Overworld");
assertEquals("overworld", dimension.getDimensionTypeKey());
}
@Test
public void dimensionTypeKeySanitizesUnsafePackCharacters() {
IrisDimension dimension = new IrisDimension();
dimension.setLoadKey("Worlds/My Pack");
assertEquals("worlds_my_pack", dimension.getDimensionTypeKey());
}
}
@@ -0,0 +1,81 @@
package art.arcane.iris.engine.object;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
public class IrisObjectBlockDataMergeTest {
@Test
public void reparsesBlockDataBeforeRetryingMerge() {
BlockData base = mock(BlockData.class);
BlockData update = mock(BlockData.class);
BlockData parsedBase = mock(BlockData.class);
BlockData parsedUpdate = mock(BlockData.class);
BlockData merged = mock(BlockData.class);
Function<String, BlockData> resolver = createResolver(
"minecraft:oak_log[axis=x]", parsedBase,
"minecraft:oak_log[axis=y]", parsedUpdate
);
doThrow(new IllegalArgumentException("Block data not created via string parsing")).when(base).merge(update);
doReturn("minecraft:oak_log[axis=x]").when(base).getAsString(false);
doReturn("minecraft:oak_log[axis=y]").when(update).getAsString(false);
doReturn(merged).when(parsedBase).merge(parsedUpdate);
BlockData result = BlockDataMergeSupport.merge(base, update, resolver);
assertSame(merged, result);
}
@Test
public void fallsBackToNormalizedUpdateWhenRetryMergeStillFails() {
BlockData base = mock(BlockData.class);
BlockData update = mock(BlockData.class);
BlockData parsedBase = mock(BlockData.class);
BlockData parsedUpdate = mock(BlockData.class);
Function<String, BlockData> resolver = createResolver(
"minecraft:stone", parsedBase,
"minecraft:stone[waterlogged=true]", parsedUpdate
);
doThrow(new IllegalArgumentException("Block data not created via string parsing")).when(base).merge(update);
doReturn("minecraft:stone").when(base).getAsString(false);
doReturn("minecraft:stone[waterlogged=true]").when(update).getAsString(false);
doThrow(new IllegalArgumentException("normalized merge failed")).when(parsedBase).merge(parsedUpdate);
BlockData result = BlockDataMergeSupport.merge(base, update, resolver);
assertSame(parsedUpdate, result);
}
@Test
public void keepsDirectMergeWhenBukkitAcceptsIt() {
BlockData base = mock(BlockData.class);
BlockData update = mock(BlockData.class);
BlockData merged = mock(BlockData.class);
doReturn(Material.STONE).when(base).getMaterial();
doReturn(Material.STONE).when(update).getMaterial();
doReturn(merged).when(base).merge(update);
BlockData result = BlockDataMergeSupport.merge(base, update, key -> null);
assertSame(merged, result);
}
private Function<String, BlockData> createResolver(String firstKey, BlockData firstValue, String secondKey, BlockData secondValue) {
Map<String, BlockData> resolved = new HashMap<>();
resolved.put(firstKey, firstValue);
resolved.put(secondKey, secondValue);
return resolved::get;
}
}
@@ -0,0 +1,36 @@
package art.arcane.iris.util.common.parallel;
import art.arcane.volmlib.util.parallel.BurstExecutorSupport;
import org.junit.Test;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.Assert.assertTrue;
public class BurstExecutorSupportReentrantTest {
@Test
public void runsNestedBurstInlineOnSameForkJoinPoolWorker() throws Exception {
ForkJoinPool pool = new ForkJoinPool(1);
AtomicBoolean nestedExecuted = new AtomicBoolean(false);
try {
Future<?> future = pool.submit(() -> {
BurstExecutorSupport burst = new BurstExecutorSupport(pool, 1);
burst.queue(() -> {
BurstExecutorSupport nested = new BurstExecutorSupport(pool, 1);
nested.queue(() -> nestedExecuted.set(true));
nested.complete();
});
burst.complete();
});
future.get(5, TimeUnit.SECONDS);
assertTrue(nestedExecuted.get());
} finally {
pool.shutdownNow();
}
}
}
@@ -0,0 +1,24 @@
package art.arcane.iris.util.common.plugin;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class VolmitSenderMiniMessageEscapeTest {
@Test
public void escapesApostrophesForQuotedHoverText() {
String escaped = VolmitSender.escapeMiniMessageQuotedText("This world's dimension config");
assertEquals("This world\\'s dimension config", escaped);
MiniMessage.miniMessage().deserialize("<hover:show_text:'" + escaped + "'>ok</hover>");
}
@Test
public void escapesBackslashesBeforeQuotedHoverText() {
String escaped = VolmitSender.escapeMiniMessageQuotedText("Path \\\\ data");
assertEquals("Path \\\\\\\\ data", escaped);
MiniMessage.miniMessage().deserialize("<hover:show_text:'" + escaped + "'>ok</hover>");
}
}
@@ -1,5 +1,6 @@
package art.arcane.iris.util.project.context;
import art.arcane.iris.Iris;
import art.arcane.iris.engine.IrisComplex;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisRegion;
@@ -7,9 +8,16 @@ import art.arcane.iris.util.project.stream.ProceduralStream;
import org.bukkit.block.data.BlockData;
import org.junit.Test;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -76,6 +84,16 @@ public class ChunkContextPrefillPlanTest {
assertEquals(256, caveCalls.get());
}
@Test
public void paperCommonWorkerThreadsDisableAsyncPrefillWhenPluginLoaded() throws Exception {
assertPrefillAsyncDecision("Paper Common Worker #0", false);
}
@Test
public void irisWorkerThreadsKeepAsyncPrefillWhenPluginLoaded() throws Exception {
assertPrefillAsyncDecision("Iris 42", true);
}
private ChunkContext createContext(
ChunkContext.PrefillPlan prefillPlan,
AtomicInteger caveCalls,
@@ -145,4 +163,26 @@ public class ChunkContextPrefillPlanTest {
return new ChunkContext(32, 48, complex, true, prefillPlan, null);
}
private void assertPrefillAsyncDecision(String threadName, boolean expected) throws InterruptedException, ExecutionException, java.util.concurrent.TimeoutException {
Iris previous = Iris.instance;
ExecutorService executor = Executors.newSingleThreadExecutor(runnable -> {
Thread thread = new Thread(runnable);
thread.setName(threadName);
return thread;
});
try {
Iris.instance = mock(Iris.class);
Future<Boolean> future = executor.submit(() -> ChunkContext.shouldPrefillAsync(2));
boolean actual = future.get(10, TimeUnit.SECONDS);
if (expected) {
assertTrue(actual);
} else {
assertFalse(actual);
}
} finally {
Iris.instance = previous;
executor.shutdownNow();
}
}
}
@@ -0,0 +1,29 @@
Paper 1.21.11
/iris create matrix-paper overworld
/iris std o overworld
close Studio world
benchmark create/unload
Purpur 1.21.11
/iris create matrix-purpur overworld
/iris std o overworld
close Studio world
benchmark create/unload
Canvas 1.21.11
/iris create matrix-canvas overworld
/iris std o overworld
close Studio world
benchmark create/unload
Folia 1.21.11
/iris create matrix-folia overworld
/iris std o overworld
close Studio world
benchmark create/unload
Spigot 1.21.11
/iris create matrix-spigot overworld
/iris std o overworld
close Studio world
unload/remove