This commit is contained in:
Brian Neumann-Fopiano
2026-08-19 19:36:03 -04:00
parent 4adef4576f
commit 41b2b53ac8
25 changed files with 966 additions and 43 deletions
@@ -0,0 +1,101 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2026 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package art.arcane.iris.core;
import org.bukkit.HeightMap;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.WorldInfo;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
import java.util.Random;
/**
* Answer to a generator-plugin discovery probe.
* <p>
* Multiverse-Core calls {@code getDefaultWorldGenerator} with an empty dimension id and the name of
* an already loaded world purely to find out whether a plugin is a generator plugin, then throws the
* returned instance away. A non-null answer keeps Iris in {@code /mv generators} and in Multiverse's
* generator tab-completion without Multiverse logging a warning block on every boot.
* <p>
* Nothing here can build terrain: every generation entry point refuses, so an instance that escapes
* the probe fails loudly instead of silently producing vanilla chunks.
*/
final class IrisProbeChunkGenerator extends ChunkGenerator {
private final String worldName;
IrisProbeChunkGenerator(String worldName) {
this.worldName = Objects.requireNonNull(worldName, "worldName");
}
@Override
public void generateNoise(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
throw refusal();
}
@Override
public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
throw refusal();
}
@Override
public void generateBedrock(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
throw refusal();
}
@Override
public void generateCaves(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
throw refusal();
}
@Override
public ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome) {
throw refusal();
}
@Override
public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {
throw refusal();
}
@Override
public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) {
throw refusal();
}
@Override
public List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
throw refusal();
}
@Override
public Location getFixedSpawnLocation(@NotNull World world, @NotNull Random random) {
throw refusal();
}
private IllegalStateException refusal() {
return new IllegalStateException("Iris generator-discovery probe for '" + worldName
+ "' was asked to generate terrain. Iris worlds are created with /iris create.");
}
}
@@ -33,15 +33,19 @@ import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisWorld; import art.arcane.iris.engine.object.IrisWorld;
import art.arcane.iris.engine.platform.BukkitChunkGenerator; import art.arcane.iris.engine.platform.BukkitChunkGenerator;
import art.arcane.iris.util.common.plugin.VolmitPlugin; import art.arcane.iris.util.common.plugin.VolmitPlugin;
import art.arcane.volmlib.util.bukkit.WorldIdentity;
import lombok.NonNull; import lombok.NonNull;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -56,6 +60,7 @@ import java.util.function.Supplier;
public final class IrisWorldGeneratorResolver { public final class IrisWorldGeneratorResolver {
private static final int VALIDATION_STABILITY_ATTEMPTS = 2; private static final int VALIDATION_STABILITY_ATTEMPTS = 2;
private static final Object SNAPSHOT_VALIDATION_LOCK = new Object(); private static final Object SNAPSHOT_VALIDATION_LOCK = new Object();
private static final String IRIS_DIMENSION_NAMESPACE = "iris";
private final VolmitPlugin plugin; private final VolmitPlugin plugin;
@@ -278,6 +283,10 @@ public final class IrisWorldGeneratorResolver {
} }
public ChunkGenerator resolveDefaultWorldGenerator(String worldName, String id) { public ChunkGenerator resolveDefaultWorldGenerator(String worldName, String id) {
if (isGeneratorDiscoveryProbe(worldName, id)) {
Iris.debug("Generator discovery probe for loaded world " + worldName);
return new IrisProbeChunkGenerator(worldName);
}
IrisStartupValidation.requireWorldCreationReady(); IrisStartupValidation.requireWorldCreationReady();
ChunkGenerator stagedGenerator = WorldLifecycleStaging.consumeGenerator(worldName); ChunkGenerator stagedGenerator = WorldLifecycleStaging.consumeGenerator(worldName);
if (stagedGenerator != null) { if (stagedGenerator != null) {
@@ -288,6 +297,11 @@ public final class IrisWorldGeneratorResolver {
if (id == null || id.isEmpty()) id = IrisSettings.get().getGenerator().getDefaultWorldType(); if (id == null || id.isEmpty()) id = IrisSettings.get().getGenerator().getDefaultWorldType();
Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); Iris.debug("Generator ID: " + id + " requested by bukkit/plugin");
File levelRoot = IrisWorldStorage.levelRoot();
NamespacedKey worldKey = configuredWorldKey(worldName, levelRoot.getName());
requireWorldKeyAvailable(worldName, worldKey);
requireOwnedWorld(worldName, levelRoot, worldKey);
try { try {
return resolveFrozenWorldGenerator(worldName, id); return resolveFrozenWorldGenerator(worldName, id);
} catch (RuntimeException failure) { } catch (RuntimeException failure) {
@@ -298,6 +312,66 @@ public final class IrisWorldGeneratorResolver {
} }
} }
/**
* Multiverse-Core probes every enabled plugin by asking for a generator with an empty dimension
* id and the name of a world that is already loaded. Bukkit never creates a world that is
* already loaded, so that pair only ever means discovery, never generation.
*/
private static boolean isGeneratorDiscoveryProbe(String worldName, String id) {
return id != null && id.isEmpty() && Bukkit.getWorld(worldName) != null;
}
/**
* Refuses a second generator for a world key that is already live. Multiverse imports accept a
* world name that maps onto a loaded Iris key, which would otherwise start a second engine on
* the same storage with a different seed.
*/
private static void requireWorldKeyAvailable(String worldName, NamespacedKey worldKey) {
World loaded = WorldIdentity.resolve(worldKey).orElse(null);
if (loaded == null) {
return;
}
throw new IllegalStateException("Refusing to generate '" + worldName + "': " + worldKey
+ " is already loaded as '" + loaded.getName() + "'.");
}
/**
* Refuses worlds Iris does not own before the fail-fast path can see them. A world without Iris
* storage is somebody else's create or import, and returning null there would silently hand the
* caller a vanilla world.
* <p>
* The {@code iris} dimension namespace is Iris-exclusive, so a directory in it is ownership on
* its own. Every server already has {@code dimensions/minecraft/*}, so a vanilla slot counts as
* Iris' only once it carries a frozen pack snapshot.
*/
private static void requireOwnedWorld(String worldName, File levelRoot, NamespacedKey worldKey) {
File dimensionRoot;
try {
dimensionRoot = IrisWorldStorage.frozenDimensionRoot(
Bukkit.getWorldContainer(),
levelRoot,
worldName,
worldKey
).orElse(null);
} catch (RuntimeException unusableStorage) {
// Storage exists but cannot be resolved: an owned world, left to the fail-fast path.
return;
}
if (dimensionRoot != null
&& (IRIS_DIMENSION_NAMESPACE.equals(worldKey.getNamespace()) || hasFrozenPack(dimensionRoot))) {
return;
}
throw new IllegalStateException("'" + worldName + "' (" + worldKey
+ ") has no Iris world storage, so Iris cannot generate it."
+ " Create Iris worlds with /iris create " + worldName + " type=<pack>;"
+ " Iris registers them with Multiverse itself.");
}
private static boolean hasFrozenPack(File dimensionRoot) {
Path packRoot = dimensionRoot.toPath().toAbsolutePath().normalize().resolve("iris").resolve("pack");
return Files.isDirectory(packRoot, LinkOption.NOFOLLOW_LINKS);
}
private ChunkGenerator resolveFrozenWorldGenerator(String worldName, String id) { private ChunkGenerator resolveFrozenWorldGenerator(String worldName, String id) {
File levelRoot = IrisWorldStorage.levelRoot(); File levelRoot = IrisWorldStorage.levelRoot();
NamespacedKey worldKey = configuredWorldKey(worldName, levelRoot.getName()); NamespacedKey worldKey = configuredWorldKey(worldName, levelRoot.getName());
@@ -234,7 +234,7 @@ public class CommandSVC implements IrisService, CommandExecutor, TabCompleter, D
} }
private boolean sendHelpIfRequested(CommandSender sender, String[] args) { private boolean sendHelpIfRequested(CommandSender sender, String[] args) {
Optional<DirectorHelpPage> request = DirectorMiniMenu.resolveHelp(getDirector(), Arrays.asList(args), 17); Optional<DirectorHelpPage> request = DirectorMiniMenu.resolveHelp(getDirector(), Arrays.asList(args));
if (request.isEmpty()) { if (request.isEmpty()) {
return false; return false;
} }
@@ -1,5 +1,6 @@
package art.arcane.iris.core; package art.arcane.iris.core;
import art.arcane.iris.Iris;
import art.arcane.iris.core.pack.BrokenPackException; import art.arcane.iris.core.pack.BrokenPackException;
import art.arcane.iris.core.pack.PackValidationRegistry; import art.arcane.iris.core.pack.PackValidationRegistry;
import art.arcane.iris.core.pack.PackValidationResult; import art.arcane.iris.core.pack.PackValidationResult;
@@ -7,19 +8,30 @@ import org.junit.After;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.WorldInfo;
import org.mockito.MockedStatic;
import java.io.File; import java.io.File;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Random;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
public class IrisWorldGeneratorResolverTest { public class IrisWorldGeneratorResolverTest {
@Rule @Rule
@@ -130,22 +142,158 @@ public class IrisWorldGeneratorResolverTest {
} }
@Test @Test
public void configuredWorldSnapshotFailureStopsStartupAndRethrows() throws Exception { public void ownedWorldSnapshotFailureStopsStartupAndRethrows() throws Exception {
String source = Files.readString(Path.of( String source = Files.readString(Path.of(
"src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java")); "src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java"));
int resolverStart = source.indexOf("public ChunkGenerator resolveDefaultWorldGenerator("); int resolverStart = source.indexOf("public ChunkGenerator resolveDefaultWorldGenerator(");
int resolverEnd = source.indexOf("private ChunkGenerator resolveFrozenWorldGenerator(", resolverStart); int resolverEnd = source.indexOf("private ChunkGenerator resolveFrozenWorldGenerator(", resolverStart);
String resolver = source.substring(resolverStart, resolverEnd); String resolver = source.substring(resolverStart, resolverEnd);
int failureCapture = resolver.indexOf("catch (RuntimeException failure)"); int probe = resolver.indexOf("isGeneratorDiscoveryProbe(worldName, id)");
int readiness = resolver.indexOf("IrisStartupValidation.requireWorldCreationReady()");
int duplicateGuard = resolver.indexOf("requireWorldKeyAvailable(worldName, worldKey)");
int ownership = resolver.indexOf("requireOwnedWorld(worldName, levelRoot, worldKey)");
int frozen = resolver.indexOf("return resolveFrozenWorldGenerator(", ownership);
int failureCapture = resolver.indexOf("catch (RuntimeException failure)", frozen);
int report = resolver.indexOf("Iris.reportError(", failureCapture); int report = resolver.indexOf("Iris.reportError(", failureCapture);
int shutdown = resolver.indexOf("Bukkit.shutdown()", report); int shutdown = resolver.indexOf("Bukkit.shutdown()", report);
int rethrow = resolver.indexOf("throw failure", shutdown); int rethrow = resolver.indexOf("throw failure", shutdown);
assertTrue(failureCapture >= 0); assertTrue(probe >= 0);
assertTrue(readiness > probe);
assertTrue(duplicateGuard > readiness);
assertTrue(ownership > duplicateGuard);
assertTrue(frozen > ownership);
assertTrue(failureCapture > frozen);
assertTrue(report > failureCapture); assertTrue(report > failureCapture);
assertTrue(shutdown > report); assertTrue(shutdown > report);
assertTrue(rethrow > shutdown); assertTrue(rethrow > shutdown);
String shutdownScope = "the fail-fast shutdown must stay scoped to the frozen snapshot of an owned world";
assertEquals(shutdownScope, resolverStart + shutdown, source.indexOf("Bukkit.shutdown()"));
assertEquals(shutdownScope, resolverStart + shutdown, source.lastIndexOf("Bukkit.shutdown()"));
}
@Test
public void discoveryProbeOfLoadedWorldReturnsInertGeneratorQuietly() {
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
MockedStatic<Iris> iris = mockStatic(Iris.class)) {
bukkit.when(() -> Bukkit.getWorld("world")).thenReturn(mock(World.class));
ChunkGenerator probe = new IrisWorldGeneratorResolver(null)
.resolveDefaultWorldGenerator("world", "");
assertNotNull("Multiverse drops Iris from /mv generators when the probe returns null", probe);
bukkit.verify(Bukkit::shutdown, never());
IllegalStateException refusal = assertThrows(
IllegalStateException.class,
() -> probe.generateNoise(mock(WorldInfo.class), new Random(), 0, 0, null));
assertTrue(refusal.getMessage(), refusal.getMessage().contains("'world'"));
}
}
@Test
public void externalCreateWithoutIrisStorageThrowsWithoutShutdown() throws Exception {
File worldContainer = temporaryFolder.newFolder("external-create");
File levelRoot = new File(worldContainer, "world");
assertTrue(levelRoot.mkdirs());
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
MockedStatic<Iris> iris = mockStatic(Iris.class)) {
Server server = mock(Server.class);
when(server.getLevelDirectory()).thenReturn(levelRoot.toPath());
bukkit.when(Bukkit::getServer).thenReturn(server);
bukkit.when(Bukkit::getWorldContainer).thenReturn(worldContainer);
bukkit.when(Bukkit::getWorlds).thenReturn(List.of());
IllegalStateException failure = assertThrows(
IllegalStateException.class,
() -> new IrisWorldGeneratorResolver(null)
.resolveDefaultWorldGenerator("mvtest", "overworld"));
assertTrue(failure.getMessage(), failure.getMessage().contains("mvtest"));
assertTrue(failure.getMessage(), failure.getMessage().contains("/iris create"));
bukkit.verify(Bukkit::shutdown, never());
}
}
@Test
public void ownedIrisWorldWithUnusableSnapshotStillStopsTheServer() throws Exception {
File worldContainer = temporaryFolder.newFolder("owned-broken");
File levelRoot = new File(worldContainer, "world");
assertTrue(levelRoot.mkdirs());
assertTrue(new File(worldContainer, "world_iris_moon/dimensions/iris/moon").mkdirs());
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
MockedStatic<Iris> iris = mockStatic(Iris.class)) {
Server server = mock(Server.class);
when(server.getLevelDirectory()).thenReturn(levelRoot.toPath());
bukkit.when(Bukkit::getServer).thenReturn(server);
bukkit.when(Bukkit::getWorldContainer).thenReturn(worldContainer);
bukkit.when(Bukkit::getWorlds).thenReturn(List.of());
assertThrows(
IllegalStateException.class,
() -> new IrisWorldGeneratorResolver(null)
.resolveDefaultWorldGenerator("world_iris_moon", "overworld"));
bukkit.verify(Bukkit::shutdown);
}
}
@Test
public void vanillaDimensionSlotWithoutFrozenPackIsNotOwned() throws Exception {
File worldContainer = temporaryFolder.newFolder("vanilla-slot");
File levelRoot = new File(worldContainer, "world");
assertTrue(new File(levelRoot, "dimensions/minecraft/the_nether").mkdirs());
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
MockedStatic<Iris> iris = mockStatic(Iris.class)) {
Server server = mock(Server.class);
when(server.getLevelDirectory()).thenReturn(levelRoot.toPath());
bukkit.when(Bukkit::getServer).thenReturn(server);
bukkit.when(Bukkit::getWorldContainer).thenReturn(worldContainer);
bukkit.when(Bukkit::getWorlds).thenReturn(List.of());
IllegalStateException failure = assertThrows(
IllegalStateException.class,
() -> new IrisWorldGeneratorResolver(null)
.resolveDefaultWorldGenerator("world_nether", "overworld"));
assertTrue(failure.getMessage(), failure.getMessage().contains("minecraft:the_nether"));
assertTrue(failure.getMessage(), failure.getMessage().contains("/iris create"));
bukkit.verify(Bukkit::shutdown, never());
}
}
@Test
public void alreadyLoadedIrisKeyIsRefusedBeforeAnyEngineCanStart() throws Exception {
File worldContainer = temporaryFolder.newFolder("duplicate-key");
File levelRoot = new File(worldContainer, "world");
assertTrue(levelRoot.mkdirs());
writeValidPack(new File(levelRoot, "dimensions/iris/irisworld/iris/pack").toPath());
World loaded = mock(World.class);
when(loaded.getKey()).thenReturn(new NamespacedKey("iris", "irisworld"));
when(loaded.getName()).thenReturn("world_iris_irisworld");
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
MockedStatic<Iris> iris = mockStatic(Iris.class)) {
Server server = mock(Server.class);
when(server.getLevelDirectory()).thenReturn(levelRoot.toPath());
bukkit.when(Bukkit::getServer).thenReturn(server);
bukkit.when(Bukkit::getWorldContainer).thenReturn(worldContainer);
bukkit.when(Bukkit::getWorlds).thenReturn(List.of(loaded));
IllegalStateException failure = assertThrows(
IllegalStateException.class,
() -> new IrisWorldGeneratorResolver(null)
.resolveDefaultWorldGenerator("irisworld", "overworld"));
assertTrue(failure.getMessage(), failure.getMessage().contains("iris:irisworld"));
assertTrue(failure.getMessage(), failure.getMessage().contains("world_iris_irisworld"));
bukkit.verify(Bukkit::shutdown, never());
}
} }
private static void writeValidPack(Path packRoot) throws Exception { private static void writeValidPack(Path packRoot) throws Exception {
+488 -3
View File
@@ -1,3 +1,488 @@
[15:24:46] [Test worker/INFO]: Iris object undo service ready (bounded to 32 paste(s) per player) [19:35:02] [Test worker/WARN]: Iris cannot resolve the biome id for 'minecraft:plains' before the Minecraft server is available; using biome id 0
[15:24:46] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered [19:35:02] [Test worker/WARN]: Iris cannot enumerate the biome registry before the Minecraft server is available; returning no biomes
[15:24:46] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered [19:35:02] [Test worker/INFO]: [STDERR]: [Iris/WARN] Can't find block data for minecraft:definitely_not_a_real_block
[19:35:02] [Test worker/INFO]: [STDERR]: [Iris/WARN] Can't find block data for minecraft:minecraft:definitely_not_a_real_block
[19:35:02] [Test worker/INFO]: [STDERR]: [Iris/WARN] Block 'minecraft:oak_log' rejected state 'not_a_property=x'; using its default state
[19:35:02] [Test worker/INFO]: Iris registered custom content provider 'iris_deferred_test'
[19:35:02] [Test worker/WARN]: Iris persistent dimension registry entry 1 in /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-partial7029509183426900057/iris-dimensions.json is invalid (entry 1 in /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-partial7029509183426900057/iris-dimensions.json has no dimension); kept verbatim: {"id":"iris:broken","pack":"overworld"}
[19:35:02] [Test worker/ERROR]: Iris persistent dimension registry at /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-corrupt-boot10459791259189814912/iris-dimensions.json is corrupt; quarantining it and continuing boot
java.lang.IllegalStateException: Iris persistent dimension registry at /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-corrupt-boot10459791259189814912/iris-dimensions.json could not be read; refusing to discard persistent worlds
at art.arcane.iris.modded.ModdedDimensionRegistryStore.contents(ModdedDimensionRegistryStore.java:150)
at art.arcane.iris.modded.ModdedDimensionRegistryStore.load(ModdedDimensionRegistryStore.java:56)
at art.arcane.iris.modded.ModdedDimensionRegistryStore.loadForStartup(ModdedDimensionRegistryStore.java:69)
at art.arcane.iris.modded.ModdedDimensionRegistryStoreTest.startupLoadQuarantinesACorruptRegistryInsteadOfFailingBoot(ModdedDimensionRegistryStoreTest.java:99)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: art.arcane.volmlib.util.json.JSONException: A JSONObject text must end with '}' at 34 [character 35 line 1]
at art.arcane.volmlib.util.json.JSONTokener.syntaxError(JSONTokener.java:414)
at art.arcane.volmlib.util.json.JSONObject.<init>(JSONObject.java:145)
at art.arcane.volmlib.util.json.JSONTokener.nextValue(JSONTokener.java:345)
at art.arcane.volmlib.util.json.JSONArray.<init>(JSONArray.java:111)
at art.arcane.volmlib.util.json.JSONTokener.nextValue(JSONTokener.java:348)
at art.arcane.volmlib.util.json.JSONObject.<init>(JSONObject.java:159)
at art.arcane.volmlib.util.json.JSONObject.<init>(JSONObject.java:260)
at art.arcane.iris.modded.ModdedDimensionRegistryStore.contents(ModdedDimensionRegistryStore.java:117)
... 45 more
[19:35:02] [Test worker/ERROR]: Iris lost 1 persistent dimension(s) from the corrupt registry: iris:lost
[19:35:02] [Test worker/ERROR]: Iris moved the corrupt persistent dimension registry to /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-corrupt-boot10459791259189814912/iris-dimensions.json.broken-1787182502612
[19:35:02] [Test worker/ERROR]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
java.lang.RuntimeException: second disable failed
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndNeverRethrows(ModdedServiceManagerTest.java:55)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
[19:35:02] [Test worker/ERROR]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$FirstService
java.lang.RuntimeException: first disable failed
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndNeverRethrows(ModdedServiceManagerTest.java:54)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
[19:35:02] [Test worker/ERROR]: Iris disabled all services with 2 failure(s)
java.lang.RuntimeException: second disable failed
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndNeverRethrows(ModdedServiceManagerTest.java:55)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Suppressed: java.lang.RuntimeException: first disable failed
at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndNeverRethrows(ModdedServiceManagerTest.java:54)
... 42 more
[19:35:02] [Test worker/ERROR]: Iris service rollback failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
java.lang.RuntimeException: cleanup failed
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
[19:35:02] [Test worker/ERROR]: Iris service onEnable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
java.lang.RuntimeException: enable failed
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:31)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Suppressed: java.lang.RuntimeException: cleanup failed
at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32)
... 42 more
[19:35:02] [Test worker/ERROR]: [worldcheck] server stop request failed
java.lang.IllegalStateException: stop request failed
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$stopRequestFailureForcesNonzeroResult$1(ModdedWorldCheckTest.java:238)
at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:144)
at art.arcane.iris.modded.ModdedWorldCheckTest.stopRequestFailureForcesNonzeroResult(ModdedWorldCheckTest.java:235)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
[19:35:02] [Test worker/ERROR]: [worldcheck] waiting for server shutdown failed
java.lang.IllegalStateException: shutdown wait failed
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$shutdownWaitFailureForcesNonzeroExit$0(ModdedWorldCheckTest.java:264)
at art.arcane.iris.modded.ModdedWorldCheck.awaitStopAndExit(ModdedWorldCheck.java:159)
at art.arcane.iris.modded.ModdedWorldCheckTest.shutdownWaitFailureForcesNonzeroExit(ModdedWorldCheckTest.java:262)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
[19:35:02] [Test worker/ERROR]: [worldcheck] check failed
java.lang.IllegalStateException: check failed
at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$thrownCheckStillRequestsStop$0(ModdedWorldCheckTest.java:224)
at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:139)
at art.arcane.iris.modded.ModdedWorldCheckTest.thrownCheckStillRequestsStop(ModdedWorldCheckTest.java:222)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
[19:35:02] [Test worker/INFO]: Iris registered custom content provider 'iris_discovery_success'
[19:35:02] [Test worker/WARN]: Iris custom content provider discovery failed at provider 'iris_discovery_failure' (art.arcane.iris.modded.api.ModdedCustomContentRegistryTest$TestProvider)
java.lang.RuntimeException: provider init failed
at art.arcane.iris.modded.api.ModdedCustomContentRegistryTest.failedDiscoveryPublishesNothingAndPreservesTheCause(ModdedCustomContentRegistryTest.java:39)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
[19:35:02] [Test worker/INFO]: Iris object undo service ready (bounded to 32 paste(s) per player)
[19:35:02] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered
[19:35:02] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered
@@ -278,46 +278,75 @@ public class ModdedLifecycleFailureContractTest {
private static String method(String source, String signature) { private static String method(String source, String signature) {
int start = requiredIndex(source, signature); int start = requiredIndex(source, signature);
int openBrace = requiredIndex(source, "{", start); int openBrace = openingBrace(source, start);
return source.substring(start, matchingBrace(source, openBrace) + 1); return source.substring(start, matchingBrace(source, openBrace) + 1);
} }
/**
* Returns the block of the shallowest catch in the method, i.e. the one attached to the
* method's outermost try. Textual first-match would return a nested catch instead, and a
* nested catch handles a different failure than the one these contracts pin.
*/
private static String catchBlock(String source) { private static String catchBlock(String source) {
int catchIndex = requiredIndex(source, "catch ("); int bodyStart = openingBrace(source, 0);
int openBrace = requiredIndex(source, "{", catchIndex); int depth = 0;
return blockAt(source, openBrace); int bestDepth = Integer.MAX_VALUE;
int catchIndex = -1;
int i = bodyStart;
while (i < source.length()) {
int skipped = skipNonCode(source, i);
if (skipped > i) {
i = skipped;
continue;
}
char current = source.charAt(i);
if (current == '{') {
depth++;
} else if (current == '}') {
depth--;
if (depth == 0) {
break;
}
} else if (current == 'c' && depth < bestDepth && source.startsWith("catch (", i)) {
bestDepth = depth;
catchIndex = i;
}
i++;
}
assertTrue("Missing source contract token: catch (", catchIndex >= 0);
return blockAt(source, openingBrace(source, catchIndex));
} }
private static String blockAt(String source, int openBrace) { private static String blockAt(String source, int openBrace) {
return source.substring(openBrace, matchingBrace(source, openBrace) + 1); return source.substring(openBrace, matchingBrace(source, openBrace) + 1);
} }
private static int openingBrace(String source, int start) {
int i = start;
while (i < source.length()) {
int skipped = skipNonCode(source, i);
if (skipped > i) {
i = skipped;
continue;
}
if (source.charAt(i) == '{') {
return i;
}
i++;
}
throw new IllegalArgumentException("No source block after offset " + start);
}
private static int matchingBrace(String source, int openBrace) { private static int matchingBrace(String source, int openBrace) {
int depth = 0; int depth = 0;
boolean quoted = false; int i = openBrace;
boolean character = false; while (i < source.length()) {
boolean escaped = false; int skipped = skipNonCode(source, i);
for (int i = openBrace; i < source.length(); i++) { if (skipped > i) {
i = skipped;
continue;
}
char current = source.charAt(i); char current = source.charAt(i);
if (escaped) {
escaped = false;
continue;
}
if ((quoted || character) && current == '\\') {
escaped = true;
continue;
}
if (!character && current == '"') {
quoted = !quoted;
continue;
}
if (!quoted && current == '\'') {
character = !character;
continue;
}
if (quoted || character) {
continue;
}
if (current == '{') { if (current == '{') {
depth++; depth++;
} else if (current == '}') { } else if (current == '}') {
@@ -326,10 +355,54 @@ public class ModdedLifecycleFailureContractTest {
return i; return i;
} }
} }
i++;
} }
throw new IllegalArgumentException("Unclosed source block"); throw new IllegalArgumentException("Unclosed source block");
} }
/**
* Advances past a comment, string, char or text block starting at the index, otherwise returns
* the index unchanged. Comments must be skipped: an apostrophe in prose ("generator's") would
* otherwise open a char literal and swallow the rest of the file.
*/
private static int skipNonCode(String source, int index) {
char current = source.charAt(index);
if (current == '/' && index + 1 < source.length()) {
char next = source.charAt(index + 1);
if (next == '/') {
int end = source.indexOf('\n', index);
return end < 0 ? source.length() : end + 1;
}
if (next == '*') {
int end = source.indexOf("*/", index + 2);
return end < 0 ? source.length() : end + 2;
}
return index;
}
if (current == '"' && source.startsWith("\"\"\"", index)) {
int end = source.indexOf("\"\"\"", index + 3);
return end < 0 ? source.length() : end + 3;
}
if (current == '"' || current == '\'') {
return endOfLiteral(source, index, current);
}
return index;
}
private static int endOfLiteral(String source, int index, char terminator) {
for (int i = index + 1; i < source.length(); i++) {
char current = source.charAt(i);
if (current == '\\') {
i++;
continue;
}
if (current == terminator) {
return i + 1;
}
}
return source.length();
}
private static int occurrences(String source, String needle) { private static int occurrences(String source, String needle) {
int count = 0; int count = 0;
int offset = 0; int offset = 0;
@@ -35,6 +35,8 @@ import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
public class IrisWorlds { public class IrisWorlds {
private static final String IRIS_GENERATOR_NAME = "iris";
private static final String IRIS_GENERATOR_PREFIX = "iris:";
private static final AtomicCache<IrisWorlds> cache = new AtomicCache<>(); private static final AtomicCache<IrisWorlds> cache = new AtomicCache<>();
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Type TYPE = TypeToken.getParameterized(KMap.class, String.class, String.class).getType(); private static final Type TYPE = TypeToken.getParameterized(KMap.class, String.class, String.class).getType();
@@ -262,16 +264,10 @@ public class IrisWorlds {
if (worlds == null) return new KMap<>(); if (worlds == null) return new KMap<>();
KMap<String, String> result = new KMap<>(); KMap<String, String> result = new KMap<>();
String defaultWorldType = IrisSettings.get().getGenerator().getDefaultWorldType();
for (String world : worlds.getKeys(false)) { for (String world : worlds.getKeys(false)) {
String gen = worlds.getString(world + ".generator"); String loadKey = generatorLoadKey(worlds.getString(world + ".generator"), defaultWorldType);
if (gen == null) continue; if (loadKey == null) continue;
String loadKey;
if (gen.equalsIgnoreCase("iris")) {
loadKey = IrisSettings.get().getGenerator().getDefaultWorldType();
} else if (gen.startsWith("Iris:")) {
loadKey = gen.substring(5);
} else continue;
result.put(world, loadKey); result.put(world, loadKey);
} }
@@ -279,6 +275,22 @@ public class IrisWorlds {
return filterBukkitWorldsByStorage(levelRoot, result); return filterBukkitWorldsByStorage(levelRoot, result);
} }
/**
* Maps a bukkit.yml generator string onto the Iris pack it selects, or null when the string is
* not Iris. Bukkit matches generator plugin names case-insensitively, so the prefix does too.
*/
static String generatorLoadKey(String generator, String defaultWorldType) {
if (generator == null) return null;
if (generator.equalsIgnoreCase(IRIS_GENERATOR_NAME)) return defaultWorldType;
int prefixLength = IRIS_GENERATOR_PREFIX.length();
if (generator.length() > prefixLength
&& generator.regionMatches(true, 0, IRIS_GENERATOR_PREFIX, 0, prefixLength)) {
return generator.substring(prefixLength);
}
return null;
}
private Optional<File> packRoot(String worldIdentity) { private Optional<File> packRoot(String worldIdentity) {
NamespacedKey worldKey = WorldIdentity.parse(worldIdentity); NamespacedKey worldKey = WorldIdentity.parse(worldIdentity);
Path worldContainer = levelRoot.getParent(); Path worldContainer = levelRoot.getParent();
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Dieser Befehl kann von diesem Ursprung aus nicht ausgeführt werden.", "director.runtime.error.invalid_origin": "Dieser Befehl kann von diesem Ursprung aus nicht ausgeführt werden.",
"director.runtime.error.unknown_parameter": "Unbekannter Parameterschlüssel: {key}", "director.runtime.error.unknown_parameter": "Unbekannter Parameterschlüssel: {key}",
"director.runtime.error.unexpected_argument": "Unerwartetes Argument \"{argument}\". Optionale Parameter müssen als Schlüssel angegeben werden, z. B. seed=123", "director.runtime.error.unexpected_argument": "Unerwartetes Argument \"{argument}\". Optionale Parameter müssen als Schlüssel angegeben werden, z. B. seed=123",
"director.runtime.error.unclosed_group": "Fehlende schließende \"]\" für Parameter {key}",
"director.runtime.error.conversion_failed": "\"{value}\" kann für {parameter} nicht in {type} konvertiert werden", "director.runtime.error.conversion_failed": "\"{value}\" kann für {parameter} nicht in {type} konvertiert werden",
"director.runtime.error.default_parse_failed": "Der Standardwert für Parameter {parameter} kann nicht gelesen werden", "director.runtime.error.default_parse_failed": "Der Standardwert für Parameter {parameter} kann nicht gelesen werden",
"director.runtime.error.missing_argument": "Fehlendes Argument \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Fehlendes Argument \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Este comando no se puede ejecutar desde este origen.", "director.runtime.error.invalid_origin": "Este comando no se puede ejecutar desde este origen.",
"director.runtime.error.unknown_parameter": "Clave de parámetro desconocida: {key}", "director.runtime.error.unknown_parameter": "Clave de parámetro desconocida: {key}",
"director.runtime.error.unexpected_argument": "Argumento inesperado \"{argument}\". Los parámetros opcionales deben especificarse con clave, p. ej. seed=123", "director.runtime.error.unexpected_argument": "Argumento inesperado \"{argument}\". Los parámetros opcionales deben especificarse con clave, p. ej. seed=123",
"director.runtime.error.unclosed_group": "Falta el corchete de cierre \"]\" para el parámetro {key}",
"director.runtime.error.conversion_failed": "No se puede convertir \"{value}\" a {type} para {parameter}", "director.runtime.error.conversion_failed": "No se puede convertir \"{value}\" a {type} para {parameter}",
"director.runtime.error.default_parse_failed": "No se puede analizar el valor predeterminado del parámetro {parameter}", "director.runtime.error.default_parse_failed": "No se puede analizar el valor predeterminado del parámetro {parameter}",
"director.runtime.error.missing_argument": "Falta el argumento \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Falta el argumento \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Tätä komentoa ei voi suorittaa tästä lähteestä.", "director.runtime.error.invalid_origin": "Tätä komentoa ei voi suorittaa tästä lähteestä.",
"director.runtime.error.unknown_parameter": "Tuntematon parametriavain: {key}", "director.runtime.error.unknown_parameter": "Tuntematon parametriavain: {key}",
"director.runtime.error.unexpected_argument": "Odottamaton argumentti \"{argument}\". Valinnaiset parametrit on annettava avaimella, esim. seed=123", "director.runtime.error.unexpected_argument": "Odottamaton argumentti \"{argument}\". Valinnaiset parametrit on annettava avaimella, esim. seed=123",
"director.runtime.error.unclosed_group": "Parametrilta {key} puuttuu sulkeva \"]\"",
"director.runtime.error.conversion_failed": "Arvoa \"{value}\" ei voi muuntaa tyypiksi {type} parametrille {parameter}", "director.runtime.error.conversion_failed": "Arvoa \"{value}\" ei voi muuntaa tyypiksi {type} parametrille {parameter}",
"director.runtime.error.default_parse_failed": "Parametrin {parameter} oletusarvoa ei voi jäsentää", "director.runtime.error.default_parse_failed": "Parametrin {parameter} oletusarvoa ei voi jäsentää",
"director.runtime.error.missing_argument": "Puuttuva argumentti \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Puuttuva argumentti \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Cette commande ne peut pas être exécutée depuis cette origine.", "director.runtime.error.invalid_origin": "Cette commande ne peut pas être exécutée depuis cette origine.",
"director.runtime.error.unknown_parameter": "Clé de paramètre inconnue : {key}", "director.runtime.error.unknown_parameter": "Clé de paramètre inconnue : {key}",
"director.runtime.error.unexpected_argument": "Argument inattendu \"{argument}\". Les paramètres facultatifs doivent être nommés, par ex. seed=123", "director.runtime.error.unexpected_argument": "Argument inattendu \"{argument}\". Les paramètres facultatifs doivent être nommés, par ex. seed=123",
"director.runtime.error.unclosed_group": "Crochet fermant \"]\" manquant pour le paramètre {key}",
"director.runtime.error.conversion_failed": "Impossible de convertir \"{value}\" en {type} pour {parameter}", "director.runtime.error.conversion_failed": "Impossible de convertir \"{value}\" en {type} pour {parameter}",
"director.runtime.error.default_parse_failed": "Impossible d'analyser la valeur par défaut du paramètre {parameter}", "director.runtime.error.default_parse_failed": "Impossible d'analyser la valeur par défaut du paramètre {parameter}",
"director.runtime.error.missing_argument": "Argument manquant \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Argument manquant \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "לא ניתן להריץ פקודה זו ממקור זה.", "director.runtime.error.invalid_origin": "לא ניתן להריץ פקודה זו ממקור זה.",
"director.runtime.error.unknown_parameter": "מפתח פרמטר לא ידוע: {key}", "director.runtime.error.unknown_parameter": "מפתח פרמטר לא ידוע: {key}",
"director.runtime.error.unexpected_argument": "ארגומנט לא צפוי \"{argument}\". פרמטרים אופציונליים חייבים להינתן עם מפתח, לדוגמה seed=123", "director.runtime.error.unexpected_argument": "ארגומנט לא צפוי \"{argument}\". פרמטרים אופציונליים חייבים להינתן עם מפתח, לדוגמה seed=123",
"director.runtime.error.unclosed_group": "חסר סוגר מרובע סוגר \"]\" עבור הפרמטר {key}",
"director.runtime.error.conversion_failed": "לא ניתן להמיר את \"{value}\" ל-{type} עבור {parameter}", "director.runtime.error.conversion_failed": "לא ניתן להמיר את \"{value}\" ל-{type} עבור {parameter}",
"director.runtime.error.default_parse_failed": "לא ניתן לנתח את ערך ברירת המחדל של הפרמטר {parameter}", "director.runtime.error.default_parse_failed": "לא ניתן לנתח את ערך ברירת המחדל של הפרמטר {parameter}",
"director.runtime.error.missing_argument": "חסר ארגומנט \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "חסר ארגומנט \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Questo comando non può essere eseguito da questa origine.", "director.runtime.error.invalid_origin": "Questo comando non può essere eseguito da questa origine.",
"director.runtime.error.unknown_parameter": "Chiave di parametro sconosciuta: {key}", "director.runtime.error.unknown_parameter": "Chiave di parametro sconosciuta: {key}",
"director.runtime.error.unexpected_argument": "Argomento imprevisto \"{argument}\". I parametri opzionali devono essere specificati con una chiave, ad es. seed=123", "director.runtime.error.unexpected_argument": "Argomento imprevisto \"{argument}\". I parametri opzionali devono essere specificati con una chiave, ad es. seed=123",
"director.runtime.error.unclosed_group": "Manca la parentesi quadra di chiusura \"]\" per il parametro {key}",
"director.runtime.error.conversion_failed": "Impossibile convertire \"{value}\" in {type} per {parameter}", "director.runtime.error.conversion_failed": "Impossibile convertire \"{value}\" in {type} per {parameter}",
"director.runtime.error.default_parse_failed": "Impossibile analizzare il valore predefinito del parametro {parameter}", "director.runtime.error.default_parse_failed": "Impossibile analizzare il valore predefinito del parametro {parameter}",
"director.runtime.error.missing_argument": "Argomento mancante \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Argomento mancante \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "この実行元からはコマンドを実行できません。", "director.runtime.error.invalid_origin": "この実行元からはコマンドを実行できません。",
"director.runtime.error.unknown_parameter": "不明なパラメーターキー: {key}", "director.runtime.error.unknown_parameter": "不明なパラメーターキー: {key}",
"director.runtime.error.unexpected_argument": "予期しない引数 \"{argument}\"。オプションのパラメーターはキー付きで指定してください。例: seed=123", "director.runtime.error.unexpected_argument": "予期しない引数 \"{argument}\"。オプションのパラメーターはキー付きで指定してください。例: seed=123",
"director.runtime.error.unclosed_group": "パラメーター {key} の閉じ角括弧 \"]\" がありません",
"director.runtime.error.conversion_failed": "\"{value}\" を {parameter} 用の {type} に変換できません", "director.runtime.error.conversion_failed": "\"{value}\" を {parameter} 用の {type} に変換できません",
"director.runtime.error.default_parse_failed": "パラメーター {parameter} のデフォルト値を解析できません", "director.runtime.error.default_parse_failed": "パラメーター {parameter} のデフォルト値を解析できません",
"director.runtime.error.missing_argument": "引数 \"{parameter}\" ({type}) が必要です", "director.runtime.error.missing_argument": "引数 \"{parameter}\" ({type}) が必要です",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "이 실행 위치에서는 이 명령어를 실행할 수 없습니다.", "director.runtime.error.invalid_origin": "이 실행 위치에서는 이 명령어를 실행할 수 없습니다.",
"director.runtime.error.unknown_parameter": "알 수 없는 매개변수 키: {key}", "director.runtime.error.unknown_parameter": "알 수 없는 매개변수 키: {key}",
"director.runtime.error.unexpected_argument": "예상하지 못한 인수 \"{argument}\". 선택적 매개변수는 키와 함께 지정해야 합니다. 예: seed=123", "director.runtime.error.unexpected_argument": "예상하지 못한 인수 \"{argument}\". 선택적 매개변수는 키와 함께 지정해야 합니다. 예: seed=123",
"director.runtime.error.unclosed_group": "매개변수 {key}에 닫는 대괄호 \"]\"가 없습니다",
"director.runtime.error.conversion_failed": "\"{value}\" 값을 {parameter}용 {type} 형식으로 변환할 수 없습니다", "director.runtime.error.conversion_failed": "\"{value}\" 값을 {parameter}용 {type} 형식으로 변환할 수 없습니다",
"director.runtime.error.default_parse_failed": "매개변수 {parameter}의 기본값을 분석할 수 없습니다", "director.runtime.error.default_parse_failed": "매개변수 {parameter}의 기본값을 분석할 수 없습니다",
"director.runtime.error.missing_argument": "인수 \"{parameter}\" ({type})가 필요합니다", "director.runtime.error.missing_argument": "인수 \"{parameter}\" ({type})가 필요합니다",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Šios komandos negalima vykdyti iš šio šaltinio.", "director.runtime.error.invalid_origin": "Šios komandos negalima vykdyti iš šio šaltinio.",
"director.runtime.error.unknown_parameter": "Nežinomas parametro raktas: {key}", "director.runtime.error.unknown_parameter": "Nežinomas parametro raktas: {key}",
"director.runtime.error.unexpected_argument": "Netikėtas argumentas \"{argument}\". Pasirenkami parametrai turi būti nurodyti su raktu, pvz. seed=123", "director.runtime.error.unexpected_argument": "Netikėtas argumentas \"{argument}\". Pasirenkami parametrai turi būti nurodyti su raktu, pvz. seed=123",
"director.runtime.error.unclosed_group": "Parametrui {key} trūksta uždaromojo skliausto \"]\"",
"director.runtime.error.conversion_failed": "Reikšmės \"{value}\" nepavyko konvertuoti į {type} parametrui {parameter}", "director.runtime.error.conversion_failed": "Reikšmės \"{value}\" nepavyko konvertuoti į {type} parametrui {parameter}",
"director.runtime.error.default_parse_failed": "Nepavyko nuskaityti parametro {parameter} numatytosios reikšmės", "director.runtime.error.default_parse_failed": "Nepavyko nuskaityti parametro {parameter} numatytosios reikšmės",
"director.runtime.error.missing_argument": "Trūksta argumento \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Trūksta argumento \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Deze opdracht kan niet vanuit deze bron worden uitgevoerd.", "director.runtime.error.invalid_origin": "Deze opdracht kan niet vanuit deze bron worden uitgevoerd.",
"director.runtime.error.unknown_parameter": "Onbekende parametersleutel: {key}", "director.runtime.error.unknown_parameter": "Onbekende parametersleutel: {key}",
"director.runtime.error.unexpected_argument": "Onverwacht argument \"{argument}\". Optionele parameters moeten met een sleutel worden opgegeven, bijv. seed=123", "director.runtime.error.unexpected_argument": "Onverwacht argument \"{argument}\". Optionele parameters moeten met een sleutel worden opgegeven, bijv. seed=123",
"director.runtime.error.unclosed_group": "Ontbrekend afsluitend haakje \"]\" voor parameter {key}",
"director.runtime.error.conversion_failed": "Kan \"{value}\" voor {parameter} niet naar {type} converteren", "director.runtime.error.conversion_failed": "Kan \"{value}\" voor {parameter} niet naar {type} converteren",
"director.runtime.error.default_parse_failed": "Kan de standaardwaarde voor parameter {parameter} niet verwerken", "director.runtime.error.default_parse_failed": "Kan de standaardwaarde voor parameter {parameter} niet verwerken",
"director.runtime.error.missing_argument": "Ontbrekend argument \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Ontbrekend argument \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Tego polecenia nie można wykonać z tego źródła.", "director.runtime.error.invalid_origin": "Tego polecenia nie można wykonać z tego źródła.",
"director.runtime.error.unknown_parameter": "Nieznany klucz parametru: {key}", "director.runtime.error.unknown_parameter": "Nieznany klucz parametru: {key}",
"director.runtime.error.unexpected_argument": "Nieoczekiwany argument \"{argument}\". Parametry opcjonalne muszą mieć klucz, np. seed=123", "director.runtime.error.unexpected_argument": "Nieoczekiwany argument \"{argument}\". Parametry opcjonalne muszą mieć klucz, np. seed=123",
"director.runtime.error.unclosed_group": "Brak zamykającego nawiasu \"]\" dla parametru {key}",
"director.runtime.error.conversion_failed": "Nie można przekonwertować \"{value}\" na {type} dla {parameter}", "director.runtime.error.conversion_failed": "Nie można przekonwertować \"{value}\" na {type} dla {parameter}",
"director.runtime.error.default_parse_failed": "Nie można odczytać wartości domyślnej parametru {parameter}", "director.runtime.error.default_parse_failed": "Nie można odczytać wartości domyślnej parametru {parameter}",
"director.runtime.error.missing_argument": "Brak argumentu \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Brak argumentu \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Este comando não pode ser executado a partir desta origem.", "director.runtime.error.invalid_origin": "Este comando não pode ser executado a partir desta origem.",
"director.runtime.error.unknown_parameter": "Chave de parâmetro desconhecida: {key}", "director.runtime.error.unknown_parameter": "Chave de parâmetro desconhecida: {key}",
"director.runtime.error.unexpected_argument": "Argumento inesperado \"{argument}\". Os parâmetros opcionais devem ser indicados por chave, por ex. seed=123", "director.runtime.error.unexpected_argument": "Argumento inesperado \"{argument}\". Os parâmetros opcionais devem ser indicados por chave, por ex. seed=123",
"director.runtime.error.unclosed_group": "Falta o parêntese reto de fecho \"]\" para o parâmetro {key}",
"director.runtime.error.conversion_failed": "Não foi possível converter \"{value}\" em {type} para {parameter}", "director.runtime.error.conversion_failed": "Não foi possível converter \"{value}\" em {type} para {parameter}",
"director.runtime.error.default_parse_failed": "Não foi possível interpretar o valor predefinido do parâmetro {parameter}", "director.runtime.error.default_parse_failed": "Não foi possível interpretar o valor predefinido do parâmetro {parameter}",
"director.runtime.error.missing_argument": "Falta o argumento \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Falta o argumento \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Эту команду нельзя выполнить из данного источника.", "director.runtime.error.invalid_origin": "Эту команду нельзя выполнить из данного источника.",
"director.runtime.error.unknown_parameter": "Неизвестный ключ параметра: {key}", "director.runtime.error.unknown_parameter": "Неизвестный ключ параметра: {key}",
"director.runtime.error.unexpected_argument": "Неожиданный аргумент \"{argument}\". Необязательные параметры должны задаваться с ключом, например seed=123", "director.runtime.error.unexpected_argument": "Неожиданный аргумент \"{argument}\". Необязательные параметры должны задаваться с ключом, например seed=123",
"director.runtime.error.unclosed_group": "Отсутствует закрывающая скобка \"]\" для параметра {key}",
"director.runtime.error.conversion_failed": "Невозможно преобразовать \"{value}\" в {type} для {parameter}", "director.runtime.error.conversion_failed": "Невозможно преобразовать \"{value}\" в {type} для {parameter}",
"director.runtime.error.default_parse_failed": "Невозможно разобрать значение по умолчанию параметра {parameter}", "director.runtime.error.default_parse_failed": "Невозможно разобрать значение по умолчанию параметра {parameter}",
"director.runtime.error.missing_argument": "Отсутствует аргумент \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Отсутствует аргумент \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Bu komut bu kaynaktan çalıştırılamaz.", "director.runtime.error.invalid_origin": "Bu komut bu kaynaktan çalıştırılamaz.",
"director.runtime.error.unknown_parameter": "Bilinmeyen parametre anahtarı: {key}", "director.runtime.error.unknown_parameter": "Bilinmeyen parametre anahtarı: {key}",
"director.runtime.error.unexpected_argument": "Beklenmeyen bağımsız değişken \"{argument}\". İsteğe bağlı parametreler anahtarla belirtilmelidir, ör. seed=123", "director.runtime.error.unexpected_argument": "Beklenmeyen bağımsız değişken \"{argument}\". İsteğe bağlı parametreler anahtarla belirtilmelidir, ör. seed=123",
"director.runtime.error.unclosed_group": "{key} parametresi için kapanış köşeli parantezi \"]\" eksik",
"director.runtime.error.conversion_failed": "\"{value}\", {parameter} için {type} türüne dönüştürülemiyor", "director.runtime.error.conversion_failed": "\"{value}\", {parameter} için {type} türüne dönüştürülemiyor",
"director.runtime.error.default_parse_failed": "{parameter} parametresinin varsayılan değeri ayrıştırılamıyor", "director.runtime.error.default_parse_failed": "{parameter} parametresinin varsayılan değeri ayrıştırılamıyor",
"director.runtime.error.missing_argument": "Eksik bağımsız değişken \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Eksik bağımsız değişken \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Không thể chạy lệnh này từ nguồn này.", "director.runtime.error.invalid_origin": "Không thể chạy lệnh này từ nguồn này.",
"director.runtime.error.unknown_parameter": "Khóa tham số không xác định: {key}", "director.runtime.error.unknown_parameter": "Khóa tham số không xác định: {key}",
"director.runtime.error.unexpected_argument": "Đối số không mong đợi \"{argument}\". Các tham số tùy chọn phải được chỉ định bằng khóa, ví dụ seed=123", "director.runtime.error.unexpected_argument": "Đối số không mong đợi \"{argument}\". Các tham số tùy chọn phải được chỉ định bằng khóa, ví dụ seed=123",
"director.runtime.error.unclosed_group": "Thiếu dấu ngoặc vuông đóng \"]\" cho tham số {key}",
"director.runtime.error.conversion_failed": "Không thể chuyển \"{value}\" thành {type} cho {parameter}", "director.runtime.error.conversion_failed": "Không thể chuyển \"{value}\" thành {type} cho {parameter}",
"director.runtime.error.default_parse_failed": "Không thể phân tích giá trị mặc định của tham số {parameter}", "director.runtime.error.default_parse_failed": "Không thể phân tích giá trị mặc định của tham số {parameter}",
"director.runtime.error.missing_argument": "Thiếu đối số \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "Thiếu đối số \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "无法从此来源运行该命令。", "director.runtime.error.invalid_origin": "无法从此来源运行该命令。",
"director.runtime.error.unknown_parameter": "未知参数键: {key}", "director.runtime.error.unknown_parameter": "未知参数键: {key}",
"director.runtime.error.unexpected_argument": "意外参数 \"{argument}\"。可选参数必须使用键指定,例如 seed=123", "director.runtime.error.unexpected_argument": "意外参数 \"{argument}\"。可选参数必须使用键指定,例如 seed=123",
"director.runtime.error.unclosed_group": "参数 {key} 缺少右方括号 \"]\"",
"director.runtime.error.conversion_failed": "无法将 \"{value}\" 转换为 {parameter} 所需的 {type}", "director.runtime.error.conversion_failed": "无法将 \"{value}\" 转换为 {parameter} 所需的 {type}",
"director.runtime.error.default_parse_failed": "无法解析参数 {parameter} 的默认值", "director.runtime.error.default_parse_failed": "无法解析参数 {parameter} 的默认值",
"director.runtime.error.missing_argument": "缺少参数 \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "缺少参数 \"{parameter}\" ({type})",
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "無法從此來源執行該指令。", "director.runtime.error.invalid_origin": "無法從此來源執行該指令。",
"director.runtime.error.unknown_parameter": "未知參數鍵: {key}", "director.runtime.error.unknown_parameter": "未知參數鍵: {key}",
"director.runtime.error.unexpected_argument": "意外參數 \"{argument}\"。選用參數必須使用鍵指定,例如 seed=123", "director.runtime.error.unexpected_argument": "意外參數 \"{argument}\"。選用參數必須使用鍵指定,例如 seed=123",
"director.runtime.error.unclosed_group": "參數 {key} 缺少右方括號 \"]\"",
"director.runtime.error.conversion_failed": "無法將 \"{value}\" 轉換為 {parameter} 所需的 {type}", "director.runtime.error.conversion_failed": "無法將 \"{value}\" 轉換為 {parameter} 所需的 {type}",
"director.runtime.error.default_parse_failed": "無法解析參數 {parameter} 的預設值", "director.runtime.error.default_parse_failed": "無法解析參數 {parameter} 的預設值",
"director.runtime.error.missing_argument": "缺少參數 \"{parameter}\" ({type})", "director.runtime.error.missing_argument": "缺少參數 \"{parameter}\" ({type})",
@@ -11,6 +11,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class IrisWorldsTest { public class IrisWorldsTest {
@Rule @Rule
@@ -53,6 +54,18 @@ public class IrisWorldsTest {
assertEquals(Set.of("archive_iris_foreign"), other.keySet()); assertEquals(Set.of("archive_iris_foreign"), other.keySet());
} }
@Test
public void bukkitGeneratorStringsAreMatchedCaseInsensitively() {
assertEquals("pack", IrisWorlds.generatorLoadKey("Iris:pack", "overworld"));
assertEquals("pack", IrisWorlds.generatorLoadKey("iris:pack", "overworld"));
assertEquals("pack", IrisWorlds.generatorLoadKey("IRIS:pack", "overworld"));
assertEquals("overworld", IrisWorlds.generatorLoadKey("Iris", "overworld"));
assertEquals("overworld", IrisWorlds.generatorLoadKey("iris", "overworld"));
assertNull(IrisWorlds.generatorLoadKey("VoidGen", "overworld"));
assertNull(IrisWorlds.generatorLoadKey("Irissy:pack", "overworld"));
assertNull(IrisWorlds.generatorLoadKey(null, "overworld"));
}
@Test @Test
public void bukkitWorldFilteringRecognizesCurrentCraftBukkitConfiguredStorage() throws Exception { public void bukkitWorldFilteringRecognizesCurrentCraftBukkitConfiguredStorage() throws Exception {
Path worldContainer = temporaryFolder.newFolder("configured-server").toPath(); Path worldContainer = temporaryFolder.newFolder("configured-server").toPath();