mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-22 16:17:44 +00:00
dwa
This commit is contained in:
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));
|
||||
}
|
||||
}
|
||||
+44
@@ -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"));
|
||||
}
|
||||
}
|
||||
+60
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user