This commit is contained in:
Brian Neumann-Fopiano committed 2026-08-04 11:13:16 -06:00
1 parent 10b2363226
commit aaccbacf32
66 files changed
+930 -557

No files matched your search

@@ -6,6 +6,9 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
@@ -49,6 +52,37 @@ public class IrisWorldStorageTest {
assertEquals("iris_world", IrisWorldStorage.logicalName(new NamespacedKey("iris", "iris_world"), "world"));
}
@Test
public void readsLevelNameFromServerPropertiesFile() throws Exception {
File serverProperties = temporaryFolder.newFile("server.properties");
Files.write(serverProperties.toPath(), "level-name=psycho_world\nmotd=A Minecraft Server\n".getBytes(StandardCharsets.UTF_8));
assertEquals("psycho_world", IrisWorldStorage.levelNameFromProperties(serverProperties));
}
@Test
public void defaultsLevelNameWhenServerPropertiesMissing() {
File missing = new File(temporaryFolder.getRoot(), "missing/server.properties");
assertEquals("world", IrisWorldStorage.levelNameFromProperties(missing));
}
@Test
public void defaultsLevelNameWhenPropertyAbsentOrBlank() {
assertEquals("world", IrisWorldStorage.levelNameFromProperties(new Properties()));
Properties blank = new Properties();
blank.setProperty("level-name", " ");
assertEquals("world", IrisWorldStorage.levelNameFromProperties(blank));
}
@Test
public void trimsLevelNameFromProperties() {
Properties padded = new Properties();
padded.setProperty("level-name", " main_level ");
assertEquals("main_level", IrisWorldStorage.levelNameFromProperties(padded));
}
@Test
public void rejectsKeysThatEscapeNamespaceStorage() throws Exception {
File levelRoot = temporaryFolder.newFolder("world");
@@ -0,0 +1,40 @@
package art.arcane.iris.core;
import org.bukkit.NamespacedKey;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class WorldCreatorCompatTest {
@Test
public void keyedPathPreservesWorldKey() {
NamespacedKey key = new NamespacedKey("iris", "compat_world");
assertEquals(key, WorldCreatorCompat.ofKey(key).key());
}
@Test
public void fallbackNameDerivesLogicalNameFromKey() {
assertEquals("compat_world", WorldCreatorCompat.fallbackName(new NamespacedKey("iris", "compat_world"), "world"));
assertEquals("world", WorldCreatorCompat.fallbackName(NamespacedKey.minecraft("overworld"), "world"));
assertEquals("world_nether", WorldCreatorCompat.fallbackName(NamespacedKey.minecraft("the_nether"), "world"));
assertEquals("world_the_end", WorldCreatorCompat.fallbackName(NamespacedKey.minecraft("the_end"), "world"));
}
@Test
public void fallbackKeyRoundTripsCreatorName() {
assertEquals(new NamespacedKey("iris", "compat_world"), WorldCreatorCompat.fallbackKey("compat_world", "world"));
assertEquals(NamespacedKey.minecraft("overworld"), WorldCreatorCompat.fallbackKey("world", "world"));
assertEquals(NamespacedKey.minecraft("the_nether"), WorldCreatorCompat.fallbackKey("world_nether", "world"));
}
@Test
public void fallbackMappingIsStableAcrossRoundTrips() {
NamespacedKey key = new NamespacedKey("iris", "iris_world");
String name = WorldCreatorCompat.fallbackName(key, "world");
assertEquals(key, WorldCreatorCompat.fallbackKey(name, "world"));
assertEquals(name, WorldCreatorCompat.fallbackName(key, "world"));
}
}
@@ -18,7 +18,15 @@
package art.arcane.iris.core.pack;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -26,6 +34,8 @@ import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class PackDownloaderTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Test
public void resolvesDefaultOverworldBetaRelease() {
assertEquals(
@@ -74,6 +84,55 @@ public class PackDownloaderTest {
);
}
@Test
public void isPackPresentRequiresNonEmptyFolder() throws IOException {
File packsFolder = temp.newFolder("packs");
assertFalse(PackDownloader.isPackPresent(packsFolder, "overworld"));
assertFalse(PackDownloader.isPackPresent(packsFolder, null));
assertFalse(PackDownloader.isPackPresent(packsFolder, ""));
assertFalse(PackDownloader.isPackPresent(null, "overworld"));
File pack = new File(packsFolder, "overworld");
assertTrue(pack.mkdirs());
assertFalse(PackDownloader.isPackPresent(packsFolder, "overworld"));
// A partial import (content but no dimension file) counts as absent so it can be replaced.
File biomes = new File(pack, "biomes");
assertTrue(biomes.mkdirs());
Files.writeString(new File(biomes, "plains.json").toPath(), "{}");
assertFalse(PackDownloader.isPackPresent(packsFolder, "overworld"));
File dimensions = new File(pack, "dimensions");
assertTrue(dimensions.mkdirs());
Files.writeString(new File(dimensions, "overworld.json").toPath(), "{}");
assertTrue(PackDownloader.isPackPresent(packsFolder, "overworld"));
}
@Test
public void downloadSkipsWhenExpectedPackAlreadyPresent() throws IOException {
File packsFolder = temp.newFolder("packs");
File dimensions = new File(packsFolder, "overworld/dimensions");
assertTrue(dimensions.mkdirs());
Files.writeString(new File(dimensions, "overworld.json").toPath(), "{}");
List<String> feedback = new ArrayList<>();
// The URL is unreachable on purpose: reaching the network would fail the download and
// return null, so a non-null key proves the presence check ran before any fetch.
String key = PackDownloader.download(
packsFolder,
"IrisDimensions/overworld",
"http://127.0.0.1:9/unreachable.zip",
false,
true,
"overworld",
feedback::add
);
assertEquals("overworld", key);
assertFalse(feedback.isEmpty());
}
@Test
public void rejectsUnsafeRepositoryAndReference() {
assertThrows(IllegalArgumentException.class, () -> PackDownloader.resolveGithubArchiveUrl("IrisDimensions/overworld?raw=1", "master"));
@@ -0,0 +1,68 @@
package art.arcane.iris.core.project;
import art.arcane.iris.engine.object.IrisImportedStructureControl;
import art.arcane.iris.engine.object.IrisVanillaStructureAdjustment;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListVanillaStructure;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.json.JSONArray;
import art.arcane.volmlib.util.json.JSONObject;
import org.junit.Test;
import java.util.regex.Pattern;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* importedStructures.disabled and adjustments[].match accept family/namespace PREFIXES
* ("minecraft:village", "nova_structures:") per IrisImportedStructureControl.matchesKey, so the
* generated editor schema must not reject them with a strict registered-key enum. Prefix-capable
* fields emit an anyOf of the registry enum plus a key/prefix pattern; exact-key fields (e.g.
* nativeStructures[].structure) keep the strict enum.
*/
public class VanillaStructurePrefixSchemaTest {
@Test
public void prefixCapableFieldsDeclareThePrefixAnnotation() throws NoSuchFieldException {
assertTrue(IrisImportedStructureControl.class.getDeclaredField("disabled")
.getAnnotation(RegistryListVanillaStructure.class).prefixes());
assertTrue(IrisVanillaStructureAdjustment.class.getDeclaredField("match")
.getAnnotation(RegistryListVanillaStructure.class).prefixes());
}
@Test
public void prefixListSchemaAcceptsFamilyAndNamespacePrefixes() {
JSONObject schema = new SchemaBuilder(PrefixModel.class, null).construct();
JSONObject items = schema.getJSONObject("properties").getJSONObject("disabled")
.getJSONObject("items");
String definitionKey = items.getString("$ref").substring("#/definitions/".length());
JSONArray anyOf = schema.getJSONObject("definitions").getJSONObject(definitionKey)
.getJSONArray("anyOf");
String pattern = null;
for (int i = 0; i < anyOf.length(); i++) {
JSONObject branch = anyOf.getJSONObject(i);
if (branch.has("pattern")) {
pattern = branch.getString("pattern");
}
}
assertTrue("anyOf must contain a pattern branch for prefixes", pattern != null);
Pattern compiled = Pattern.compile(pattern);
assertTrue(compiled.matcher("minecraft:village").matches());
assertTrue(compiled.matcher("minecraft:pillager_outpost").matches());
assertTrue(compiled.matcher("nova_structures:").matches());
assertTrue(compiled.matcher("towns_and_towers:exclusives/village_piglin").matches());
assertFalse(compiled.matcher("village").matches());
assertFalse(compiled.matcher("Nova Structures:tavern").matches());
}
@Desc("Schema model for prefix-capable vanilla structure lists.")
public static class PrefixModel {
@RegistryListVanillaStructure(prefixes = true)
@ArrayType(type = String.class, min = 1)
@Desc("Prefix-capable deny list.")
private KList<String> disabled = new KList<>();
}
}
@@ -14,4 +14,14 @@ public class IrisSplashComposerTest {
assertEquals(" Version: 4.0.0-26.2", info[2]);
assertFalse(String.join("\n", info).contains("RC.1.1.6"));
}
@Test
public void composeInfoShowsWebsiteAndKeepsSplashHeight() {
String[] info = IrisSplashComposer.composeInfo("4.0.0-26.2", "Paper 26.2", IrisSplashComposer.InfoStyle.PLAIN);
assertEquals(11, info.length);
assertEquals(" By: Volmit Software (Arcane Arts)", info[3]);
assertEquals(" Web: VolmitSoftware.com", info[4]);
assertEquals(" Server: Paper 26.2", info[5]);
}
}
@@ -0,0 +1,48 @@
package art.arcane.iris.core.structure;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* A bulk import walks every registered datapack structure, so one broken server-side assumption
* fails hundreds of times in a row from the same throw site. Printing a full stack trace per
* structure buried a Leaf 26.2 boot under ~4,700 identical lines. The first occurrence of a failure
* signature prints in full; repeats are counted by the per-structure "[fail] key: message" line
* instead of re-printing.
*/
public class VillageImporterFailureLogTest {
/** One throw site, mirroring a repeated in-loop failure (same class, message, and top frame). */
private static Throwable raise(boolean illegalArgument, String message) {
return illegalArgument ? new IllegalArgumentException(message) : new IllegalStateException(message);
}
@Test
public void repeatedIdenticalFailuresPrintOnce() {
VillageImporter.resetFailureLogState();
assertTrue(VillageImporter.shouldPrintFullTrace(
raise(true, "illegal data type conversion to int")));
for (int i = 0; i < 200; i++) {
assertFalse(VillageImporter.shouldPrintFullTrace(
raise(true, "illegal data type conversion to int")));
}
}
@Test
public void distinctFailuresEachPrintOnce() {
VillageImporter.resetFailureLogState();
assertTrue(VillageImporter.shouldPrintFullTrace(raise(true, "a")));
assertTrue(VillageImporter.shouldPrintFullTrace(raise(false, "a")));
assertTrue(VillageImporter.shouldPrintFullTrace(raise(true, "b")));
assertFalse(VillageImporter.shouldPrintFullTrace(raise(true, "b")));
}
@Test
public void nullFailureIsNotPrinted() {
VillageImporter.resetFailureLogState();
assertFalse(VillageImporter.shouldPrintFullTrace(null));
}
}
@@ -0,0 +1,44 @@
package art.arcane.iris.core.structure;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* JigsawStructure.maxDistanceFromCenter is a plain int on some server builds and a
* JigsawStructure$MaxDistance record ({int horizontal, int vertical}) on others (e.g. Leaf
* 26.2-33). The reflective member reader must handle both — the wrapper shape previously threw
* IllegalArgumentException from Field.getInt, failing the jigsaw import of every datapack
* structure ("Failed to read jigsaw structure graph").
*/
public class VillageImporterMaxDistanceReadTest {
private static final class IntShape {
private final int maxDistanceFromCenter = 80;
}
private record MaxDistance(int horizontal, int vertical) {
}
private static final class WrapperShape {
private final MaxDistance maxDistanceFromCenter = new MaxDistance(96, 48);
}
private static final class BoxedShape {
private final Integer maxDistanceFromCenter = 64;
}
@Test
public void readsPlainIntField() throws Exception {
assertEquals(80, VillageImporter.readIntMember(new IntShape(), "maxDistanceFromCenter"));
}
@Test
public void readsLargestIntComponentFromWrapperRecord() throws Exception {
assertEquals(96, VillageImporter.readIntMember(new WrapperShape(), "maxDistanceFromCenter"));
}
@Test
public void readsBoxedNumberField() throws Exception {
assertEquals(64, VillageImporter.readIntMember(new BoxedShape(), "maxDistanceFromCenter"));
}
}
@@ -1,9 +1,20 @@
package art.arcane.iris.engine.framework;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisImportedStructureControl;
import art.arcane.iris.engine.object.IrisNativeStructure;
import art.arcane.iris.engine.object.IrisNativeStructureDecision;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.IrisStructurePlacement;
import art.arcane.iris.engine.object.NativeStructureGenerationStatus;
import art.arcane.volmlib.util.collection.KList;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class NativeStructureGenerationPolicyTest {
@Test
@@ -17,4 +28,53 @@ public class NativeStructureGenerationPolicyTest {
NativeStructureGenerationPolicy.generationStatusMessage(
"minecraft:ancient_city", NativeStructureGenerationStatus.REPLACED_BY_IRIS));
}
/**
* The "blanket-disable a namespace, re-place chosen structures via nativeStructures placements"
* pattern: generation honors the placement (the planner never consults the disable list), so the
* policy must report those keys as REPLACED_BY_IRIS — making /iris find|goto and
* /iris structure verify locate the placement instead of claiming the key is disabled.
*/
@Test
public void disabledKeyWithActivePlacementResolvesAsReplacedByIris() {
Engine engine = engineWithDisabledNamespaceAndRegionPlacement("nova_structures:tavern_oak");
assertEquals(NativeStructureGenerationStatus.REPLACED_BY_IRIS,
NativeStructureGenerationPolicy.resolve(engine, "nova_structures:tavern_oak", false).status());
}
@Test
public void disabledKeyWithoutPlacementStaysDisabled() {
Engine engine = engineWithDisabledNamespaceAndRegionPlacement("nova_structures:tavern_oak");
IrisNativeStructureDecision decision =
NativeStructureGenerationPolicy.resolve(engine, "nova_structures:witch_villa", false);
assertEquals(NativeStructureGenerationStatus.DISABLED_BY_PACK, decision.status());
assertFalse(decision.generate());
}
private Engine engineWithDisabledNamespaceAndRegionPlacement(String placedKey) {
IrisData data = mock(IrisData.class);
Engine engine = mock(Engine.class);
IrisDimension dimension = mock(IrisDimension.class);
IrisImportedStructureControl control = new IrisImportedStructureControl();
control.getDisabled().add("nova_structures:");
IrisStructurePlacement placement = new IrisStructurePlacement();
placement.getNativeStructures().add(new IrisNativeStructure().setStructure(placedKey));
IrisRegion region = mock(IrisRegion.class);
KList<IrisStructurePlacement> regionPlacements = new KList<>();
regionPlacements.add(placement);
when(region.getStructures()).thenReturn(regionPlacements);
KList<IrisRegion> regions = new KList<>();
regions.add(region);
when(engine.getData()).thenReturn(data);
when(engine.getDimension()).thenReturn(dimension);
when(dimension.getImportedStructures()).thenReturn(control);
when(dimension.getStructures()).thenReturn(new KList<>());
when(dimension.getAllRegions(engine)).thenReturn(regions);
when(dimension.getReachableBiomes(engine)).thenReturn(new KList<>());
return engine;
}
}