Full audit fixpass: 93 defect fixes, 14 perf wins, vestigial cleanup

This commit is contained in:
Brian Neumann-Fopiano committed 2026-08-13 01:01:01 -04:00
1 parent 13e02ecd2f
commit 14b6280668
215 files changed
+4604 -2407

No files matched your search

@@ -1,11 +1,32 @@
package art.arcane.iris.core;
import com.google.gson.Gson;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class IrisSettingsDefaultsTest {
@Test
public void concurrencyIsNotSerializedIntoSettingsJson() {
String json = new Gson().toJson(new IrisSettings());
assertFalse("settings.json must not advertise an unconfigurable concurrency block",
json.contains("\"concurrency\""));
}
@Test
public void legacyConcurrencyBlockStillLoadsAndKeepsDerivedValues() {
IrisSettings loaded = new Gson().fromJson(
"{\"concurrency\":{\"parallelism\":8,\"ioParallelism\":4}}", IrisSettings.class);
assertNotNull(loaded.getConcurrency());
assertEquals(Math.max(2, Runtime.getRuntime().availableProcessors()),
loaded.getConcurrency().getParallelism());
}
@Test
public void datapackIngestStaysAutomaticWhileEditableConversionIsOptIn() {
IrisSettings.IrisSettingsGeneral settings = new IrisSettings.IrisSettingsGeneral();
@@ -0,0 +1,57 @@
package art.arcane.iris.core.link;
import org.junit.After;
import org.junit.Test;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class WorldEditLinkDetectionTest {
@After
public void resetDetectionState() {
WorldEditLink.invalidate();
}
@Test
public void negativeDetectionIsNotMemoized() {
AtomicInteger calls = new AtomicInteger();
boolean[] answers = {false, true};
assertFalse(WorldEditLink.hasWorldEdit(() -> answers[calls.getAndIncrement()]));
assertTrue("WorldEdit enabling after a negative probe must be picked up without a restart",
WorldEditLink.hasWorldEdit(() -> answers[calls.getAndIncrement()]));
assertEquals(2, calls.get());
}
@Test
public void positiveDetectionIsMemoized() {
AtomicInteger calls = new AtomicInteger();
assertTrue(WorldEditLink.hasWorldEdit(() -> {
calls.incrementAndGet();
return true;
}));
assertTrue(WorldEditLink.hasWorldEdit(() -> {
throw new AssertionError("memoized positive must not re-probe");
}));
assertEquals(1, calls.get());
}
@Test
public void selectionFailureDoesNotLatchFalse() {
assertTrue(WorldEditLink.hasWorldEdit(() -> true));
WorldEditLink.invalidate();
assertTrue(WorldEditLink.hasWorldEdit(() -> true));
}
@Test
public void detectorFailureIsNotCachedAndDoesNotThrow() {
assertFalse(WorldEditLink.hasWorldEdit(() -> {
throw new IllegalStateException("server not ready");
}));
assertTrue(WorldEditLink.hasWorldEdit(() -> true));
}
}
@@ -0,0 +1,41 @@
package art.arcane.iris.core.localization;
import org.junit.Test;
import java.util.Locale;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class ResetMantleHelpTextTest {
@Test
public void resetMantleParamDescribesTheWholeWorldMantle() {
String english = DirectorCommandMessages
.COMMAND_DEVELOPER_PARAM_DELETE_MANTLE_DATA_SCAN_AREA_FIRST_FULL_REGENERATION_FROM_SCRATCH
.english().toLowerCase(Locale.ROOT);
assertTrue("help text must say the entire world mantle is deleted", english.contains("entire"));
assertFalse("help text must not claim the deletion is scoped to the scan area", english.contains("scan area"));
}
@Test
public void goldenhashDirectorDescribesTheWholeWorldMantle() {
String english = DirectorCommandMessages
.COMMAND_DEVELOPER_DIRECTOR_GENERATE_CHUNKS_INTO_BUFFERS_NO_WORLD_WRITES_HASH_BLOCKS_BIOMES_CAPTURES_GOLDEN
.english().toLowerCase(Locale.ROOT);
assertFalse("director text must not claim the mantle reset is scoped to the scan area",
english.contains("scanned area"));
assertTrue("director text must say the entire world mantle is deleted", english.contains("entire"));
}
@Test
public void keyIdsStayStableAcrossTheWordingFix() {
assertTrue(DirectorCommandMessages
.COMMAND_DEVELOPER_PARAM_DELETE_MANTLE_DATA_SCAN_AREA_FIRST_FULL_REGENERATION_FROM_SCRATCH
.id().endsWith("delete_mantle_data_scan_area_first_full_regeneration_from_scratch"));
assertTrue(DirectorCommandMessages
.COMMAND_DEVELOPER_DIRECTOR_GENERATE_CHUNKS_INTO_BUFFERS_NO_WORLD_WRITES_HASH_BLOCKS_BIOMES_CAPTURES_GOLDEN
.id().endsWith("generate_chunks_into_buffers_no_world_writes_hash_blocks_biomes_captures_golden"));
}
}
@@ -0,0 +1,83 @@
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.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class PackBiomeLayerValidatorTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void rejectsMoreCeilingLayersThanLayers() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "biomes/nested/cave.json",
"{\"layers\":[{}],\"caveCeilingLayers\":[{},{},{}]}");
assertEquals(List.of(
"Biome 'nested/cave' declares 3 caveCeilingLayers but only 1 layers. caveCeilingLayers reuses the layers height generators and must not have more entries."
), PackBiomeLayerValidator.validateCeilingLayerCounts(new File(pack, "biomes")));
}
@Test
public void respectsSingleEntryDefaultsWhenFieldsAreAbsent() throws Exception {
File pack = temporaryFolder.newFolder("pack");
// Both fields default to one entry, so omitting both is legal...
write(pack, "biomes/defaulted.json", "{\"name\":\"Defaulted\"}");
// ...and two ceiling entries against the implicit single default layer is not.
write(pack, "biomes/implicit.json", "{\"caveCeilingLayers\":[{},{}]}");
assertEquals(List.of(
"Biome 'implicit' declares 2 caveCeilingLayers but only 1 layers. caveCeilingLayers reuses the layers height generators and must not have more entries."
), PackBiomeLayerValidator.validateCeilingLayerCounts(new File(pack, "biomes")));
}
@Test
public void acceptsEqualOrFewerCeilingLayers() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "biomes/ok.json", "{\"layers\":[{},{},{}],\"caveCeilingLayers\":[{},{}]}");
assertTrue(PackBiomeLayerValidator.validateCeilingLayerCounts(new File(pack, "biomes")).isEmpty());
}
@Test
public void rejectsNonArrayLayerFields() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "biomes/bad.json", "{\"layers\":7,\"caveCeilingLayers\":\"nope\"}");
assertEquals(List.of(
"Biome 'bad' layers must be an array.",
"Biome 'bad' caveCeilingLayers must be an array."
), PackBiomeLayerValidator.validateCeilingLayerCounts(new File(pack, "biomes")));
}
@Test
public void ceilingLayerOverflowBlocksFullPackValidation() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "dimensions/main.json", "{\"regions\":[\"region\"]}");
write(pack, "regions/region.json", "{\"landBiomes\":[\"biome\"]}");
write(pack, "biomes/biome.json", "{\"name\":\"Biome\",\"layers\":[{}],\"caveCeilingLayers\":[{},{}]}");
PackValidationResult result = PackValidator.validate(pack);
assertFalse(result.isLoadable());
assertTrue(result.getBlockingErrors().contains(
"Biome 'biome' declares 2 caveCeilingLayers but only 1 layers. caveCeilingLayers reuses the layers height generators and must not have more entries."));
}
private void write(File root, String relative, String content) throws Exception {
Path target = new File(root, relative).toPath();
Files.createDirectories(target.getParent());
Files.writeString(target, content, StandardCharsets.UTF_8);
}
}
@@ -0,0 +1,25 @@
package art.arcane.iris.core.pack;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class PackDownloadBranchDefaultTest {
@Test
public void sharedDefaultBranchIsStable() {
assertEquals("stable", PackDownloader.DEFAULT_BRANCH);
}
@Test
public void packRepositoryDefaultsToTheSharedBranch() {
assertEquals(PackDownloader.DEFAULT_BRANCH, IrisPackRepository.builder().build().getBranch());
assertEquals(PackDownloader.DEFAULT_BRANCH, IrisPackRepository.from("overworld").getBranch());
}
@Test
public void managedPacksIgnoreTheBranchEntirely() {
assertTrue(PackDownloader.isManagedPack("overworld"));
assertTrue(PackDownloader.isManagedPack("underworld"));
}
}
@@ -420,7 +420,9 @@ public class PackDownloaderTest {
}
@Test
public void forceOverwriteRefusesLoadedPackData() throws Exception {
public void forceOverwriteReplacesEnginelessLoadedPackData() throws Exception {
// A registered loader with no engines is a stale catalog registration (startup
// validation registers one per visible pack); it must not block a forced update.
File packsFolder = temp.newFolder("loaded-packs");
File target = writePack(packsFolder.toPath().resolve("active_pack"), "active_pack", "old");
File extracted = writePack(temp.newFolder("loaded-update").toPath(), "active_pack", "new");
@@ -435,10 +437,41 @@ public class PackDownloaderTest {
}
);
assertNotNull(result);
assertEquals("new", Files.readString(target.toPath().resolve("state.txt"), StandardCharsets.UTF_8));
assertTransactionStateClean(packsFolder);
} finally {
loaded.close();
}
}
@Test
public void forceOverwriteRefusesPackWithLiveEngines() throws Exception {
File packsFolder = temp.newFolder("engine-packs");
File target = writePack(packsFolder.toPath().resolve("active_pack"), "active_pack", "old");
File extracted = writePack(temp.newFolder("engine-update").toPath(), "active_pack", "new");
// Engines attach to detached openRuntime loaders in production, never to the cached
// IrisData.get instance; the refusal gate must see this registration through the
// engine index.
IrisData loaded = IrisData.openRuntime(target);
art.arcane.iris.engine.framework.Engine engine =
org.mockito.Mockito.mock(art.arcane.iris.engine.framework.Engine.class);
loaded.registerEngine(engine);
try {
PackDownloader.PackInstallResult result = PackDownloader.installExtractedPack(
packsFolder,
extracted,
true,
"active_pack",
ignored -> {
}
);
assertNull(result);
assertEquals("old", Files.readString(target.toPath().resolve("state.txt"), StandardCharsets.UTF_8));
assertTransactionStateClean(packsFolder);
} finally {
loaded.unregisterEngine(engine);
loaded.close();
}
}
@@ -0,0 +1,73 @@
package art.arcane.iris.core.pack;
import art.arcane.iris.engine.object.IrisObjectMarker;
import art.arcane.iris.engine.object.IrisObjectPlacement;
import art.arcane.volmlib.util.collection.KList;
import org.junit.Test;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class PackExportClosureTest {
private static IrisObjectPlacement placement(String objectKey, String... markerKeys) {
IrisObjectPlacement placement = new IrisObjectPlacement();
placement.setPlace(new KList<>(objectKey));
KList<IrisObjectMarker> markers = new KList<>();
for (String markerKey : markerKeys) {
IrisObjectMarker marker = new IrisObjectMarker();
marker.setMarker(markerKey);
markers.add(marker);
}
placement.setMarkers(markers);
return placement;
}
@Test
public void collectsMarkerAndObjectKeysFromPlacements() {
List<IrisObjectPlacement> placements = List.of(
placement("houses/hut", "spawn-point", "loot-marker"),
placement("trees/oak"),
placement("houses/hut", "spawn-point"));
assertEquals(List.of("loot-marker", "spawn-point"),
PackExportClosure.collectMarkerKeys(placements).stream().sorted().toList());
assertEquals(List.of("houses/hut", "trees/oak"),
PackExportClosure.collectObjectKeys(placements).stream().sorted().toList());
}
@Test
public void toleratesNullPlacementsAndBlankKeys() {
KList<IrisObjectPlacement> placements = new KList<>();
placements.add(placement("", ""));
placements.add((IrisObjectPlacement) null);
assertTrue(PackExportClosure.collectMarkerKeys(placements).isEmpty());
assertTrue(PackExportClosure.collectObjectKeys(placements).isEmpty());
}
/**
* Source guard: both packagers must export the ambient-spawning graph. Spawner and marker
* folders were silently omitted from exports, leaving dangling entitySpawners references.
*/
@Test
public void bothPackagersExportSpawnersMarkersAndTheFullEntityGraph() throws Exception {
String bukkit = Files.readString(Path.of(
"src/main/java/art/arcane/iris/core/project/IrisPackageCompiler.java"));
assertTrue("Bukkit packager must write spawners/", bukkit.contains("\"spawners/\""));
assertTrue("Bukkit packager must write markers/", bukkit.contains("\"markers/\""));
assertTrue("Bukkit packager must export region objects alongside biome objects",
bukkit.contains("regions.forEach((r) -> allPlacements.addAll(r.getObjects()))"));
assertTrue("Bukkit packager must export entity loot tables", bukkit.contains("getLoot().getTables()"));
String modded = Files.readString(Path.of(
"../adapters/modded-common/src/main/java/art/arcane/iris/modded/command/ModdedStudioCommands.java"));
assertTrue("modded packager must write spawners/", modded.contains("\"spawners\""));
assertTrue("modded packager must write markers/", modded.contains("\"markers\""));
assertTrue("modded packager must include initial spawns", modded.contains("getInitialSpawns"));
assertTrue("modded packager must export region objects", modded.contains("region.getObjects()"));
}
}
@@ -0,0 +1,110 @@
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.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class PackGeneratorDuplicateValidatorTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void warnsWhenTwoReferencedGeneratorsAreContentIdentical() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "generators/a.json", "{\"seed\": 1,\n \"zoom\": 2}");
write(pack, "generators/b.json", "{\"zoom\":2,\"seed\":1}");
write(pack, "biomes/one.json", "{\"generators\":[{\"generator\":\"a\"}]}");
write(pack, "biomes/two.json", "{\"generators\":[{\"generator\":\"b\"}]}");
List<String> warnings = PackGeneratorDuplicateValidator.validateDuplicateGenerators(pack);
assertEquals(1, warnings.size());
assertTrue(warnings.get(0).startsWith("Generators a, b have identical content"));
}
@Test
public void doesNotWarnWhenOnlyOneDuplicateIsReferenced() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "generators/a.json", "{\"seed\":1}");
write(pack, "generators/b.json", "{\"seed\":1}");
write(pack, "biomes/one.json", "{\"generators\":[{\"generator\":\"a\"}]}");
assertTrue(PackGeneratorDuplicateValidator.validateDuplicateGenerators(pack).isEmpty());
}
@Test
public void doesNotWarnWhenGeneratorsDifferBySeed() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "generators/a.json", "{\"seed\":1}");
write(pack, "generators/b.json", "{\"seed\":2}");
write(pack, "biomes/one.json", "{\"generators\":[{\"generator\":\"a\"},{\"generator\":\"b\"}]}");
assertTrue(PackGeneratorDuplicateValidator.validateDuplicateGenerators(pack).isEmpty());
}
@Test
public void treatsNumericFormattingAsIdentical() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "generators/a.json", "{\"zoom\":1}");
write(pack, "generators/b.json", "{\"zoom\":1.0}");
write(pack, "biomes/one.json", "{\"generators\":[{\"generator\":\"a\"},{\"generator\":\"b\"}]}");
assertEquals(1, PackGeneratorDuplicateValidator.validateDuplicateGenerators(pack).size());
}
@Test
public void resolvesSnippetGeneratorLinks() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "generators/a.json", "{\"seed\":1}");
write(pack, "generators/b.json", "{\"seed\":1}");
write(pack, "biomes/one.json", "{\"generators\":[\"snippet/generator-layer/x\",{\"generator\":\"b\"}]}");
write(pack, "snippet/generator-layer/x.json", "{\"generator\":\"a\"}");
assertEquals(1, PackGeneratorDuplicateValidator.validateDuplicateGenerators(pack).size());
}
@Test
public void warningOrderIsStableAndSorted() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "generators/c.json", "{\"seed\":1}");
write(pack, "generators/a.json", "{\"seed\":1}");
write(pack, "generators/b.json", "{\"seed\":1}");
write(pack, "biomes/one.json",
"{\"generators\":[{\"generator\":\"c\"},{\"generator\":\"a\"},{\"generator\":\"b\"}]}");
List<String> warnings = PackGeneratorDuplicateValidator.validateDuplicateGenerators(pack);
assertEquals(1, warnings.size());
assertTrue(warnings.get(0).startsWith("Generators a, b, c have identical content"));
}
@Test
public void duplicatesSurfaceAsPackWarningsNotErrors() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "dimensions/main.json", "{\"regions\":[\"region\"]}");
write(pack, "regions/region.json", "{\"landBiomes\":[\"biome\"]}");
write(pack, "biomes/biome.json", "{\"name\":\"Biome\",\"generators\":[{\"generator\":\"a\"},{\"generator\":\"b\"}]}");
write(pack, "generators/a.json", "{\"seed\":1}");
write(pack, "generators/b.json", "{\"seed\":1}");
PackValidationResult result = PackValidator.validate(pack);
assertTrue(result.isLoadable());
assertTrue(result.getWarnings().stream().anyMatch(w -> w.startsWith("Generators a, b have identical content")));
}
private void write(File root, String relative, String content) throws Exception {
Path target = new File(root, relative).toPath();
Files.createDirectories(target.getParent());
Files.writeString(target, content, StandardCharsets.UTF_8);
}
}
@@ -0,0 +1,99 @@
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.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class PackStyledRangeDefaultValidatorTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void flagsEmptyDensityStyleAsSharedDefault() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "biomes/x.json", "{\"objects\":[{\"place\":[\"o\"],\"densityStyle\":{}}]}");
PackStyledRangeDefaultValidator.Validation validation = PackStyledRangeDefaultValidator.validate(pack);
assertEquals(1, validation.errors().size());
assertTrue(validation.errors().get(0).startsWith(
"Biome 'x' objects[0].densityStyle omits both min and max"));
assertTrue(validation.warnings().isEmpty());
}
@Test
public void acceptsExplicitDensityStyle() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "biomes/x.json",
"{\"objects\":[{\"place\":[\"o\"],\"densityStyle\":{\"min\":1,\"max\":3,\"style\":{\"style\":\"SIMPLEX\"}}}]}");
PackStyledRangeDefaultValidator.Validation validation = PackStyledRangeDefaultValidator.validate(pack);
assertTrue(validation.errors().isEmpty());
assertTrue(validation.warnings().isEmpty());
}
@Test
public void warnsOnPartialDensityStyle() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "biomes/x.json", "{\"objects\":[{\"place\":[\"o\"],\"densityStyle\":{\"min\":1}}]}");
PackStyledRangeDefaultValidator.Validation validation = PackStyledRangeDefaultValidator.validate(pack);
assertTrue(validation.errors().isEmpty());
assertEquals(1, validation.warnings().size());
assertTrue(validation.warnings().get(0).contains("omits max"));
assertTrue(validation.warnings().get(0).contains("32"));
}
@Test
public void resolvesSnippetReferences() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "biomes/x.json", "{\"objects\":[{\"place\":[\"o\"],\"densityStyle\":\"snippet/style-range/empty\"}]}");
write(pack, "snippet/style-range/empty.json", "{}");
PackStyledRangeDefaultValidator.Validation validation = PackStyledRangeDefaultValidator.validate(pack);
assertEquals(1, validation.errors().size());
assertTrue(validation.errors().get(0).contains("via snippet 'snippet/style-range/empty'"));
}
@Test
public void flagsEmptyCaveDensityThreshold() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "dimensions/main.json", "{\"caveProfile\":{\"densityThreshold\":{}}}");
PackStyledRangeDefaultValidator.Validation validation = PackStyledRangeDefaultValidator.validate(pack);
assertEquals(1, validation.errors().size());
assertTrue(validation.errors().get(0).startsWith(
"Dimension 'main' caveProfile.densityThreshold omits both min and max"));
}
@Test
public void emptyDensityStyleBlocksFullPackValidation() throws Exception {
File pack = temporaryFolder.newFolder("pack");
write(pack, "dimensions/main.json", "{\"regions\":[\"region\"]}");
write(pack, "regions/region.json", "{\"landBiomes\":[\"biome\"]}");
write(pack, "biomes/biome.json", "{\"name\":\"Biome\",\"objects\":[{\"place\":[\"o\"],\"densityStyle\":{}}]}");
PackValidationResult result = PackValidator.validate(pack);
assertFalse(result.isLoadable());
}
private void write(File root, String relative, String content) throws Exception {
Path target = new File(root, relative).toPath();
Files.createDirectories(target.getParent());
Files.writeString(target, content, StandardCharsets.UTF_8);
}
}
@@ -0,0 +1,148 @@
package art.arcane.iris.core.pack;
import art.arcane.iris.engine.object.IrisDimensionType;
import art.arcane.iris.engine.object.IrisDimensionTypeOptions;
import art.arcane.iris.core.nms.datapack.IDataFixer;
import org.junit.Rule;
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.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class PackValidatorDimensionHeightTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void rejectsNonMultipleOfSixteenSpan() throws Exception {
PackValidationResult result = validate("{\"regions\":[\"region\"],\"dimensionHeight\":{\"min\":-64,\"max\":300}}");
assertFalse(result.isLoadable());
assertTrue(result.getBlockingErrors().contains(
"Dimension 'main' dimensionHeight span (max - min) is 364; it must be a multiple of 16."));
}
@Test
public void rejectsMinYNotMultipleOfSixteen() throws Exception {
PackValidationResult result = validate("{\"regions\":[\"region\"],\"dimensionHeight\":{\"min\":-60,\"max\":324}}");
assertFalse(result.isLoadable());
assertTrue(result.getBlockingErrors().contains(
"Dimension 'main' dimensionHeight.min is -60; it must be a multiple of 16."));
}
@Test
public void rejectsSpanOutsideBounds() throws Exception {
assertTrue(validate("{\"regions\":[\"region\"],\"dimensionHeight\":{\"min\":0,\"max\":0}}")
.getBlockingErrors().contains(
"Dimension 'main' dimensionHeight span (max - min) is 0; it must be between 16 and 4064."));
assertTrue(validate("{\"regions\":[\"region\"],\"dimensionHeight\":{\"min\":-2032,\"max\":2048}}")
.getBlockingErrors().contains(
"Dimension 'main' dimensionHeight span (max - min) is 4080; it must be between 16 and 4064."));
}
@Test
public void rejectsMinYOutsideBounds() throws Exception {
assertTrue(validate("{\"regions\":[\"region\"],\"dimensionHeight\":{\"min\":-2048,\"max\":-1664}}")
.getBlockingErrors().contains(
"Dimension 'main' dimensionHeight.min is -2048; it must be between -2032 and 2031."));
}
@Test
public void rejectsLogicalHeightAboveTotalHeight() throws Exception {
PackValidationResult result = validate(
"{\"regions\":[\"region\"],\"logicalHeight\":512,\"dimensionHeight\":{\"min\":-64,\"max\":320}}");
assertFalse(result.isLoadable());
assertTrue(result.getBlockingErrors().contains(
"Dimension 'main' logicalHeight is 512; it cannot be greater than the dimension height of 384."));
}
@Test
public void acceptsShippingOverworldShape() throws Exception {
PackValidationResult result = validate(
"{\"regions\":[\"region\"],\"logicalHeight\":512,\"dimensionHeight\":{\"min\":-256,\"max\":512}}");
assertTrue(result.getBlockingErrors().toString(), result.isLoadable());
}
@Test
public void acceptsDimensionWithoutExplicitHeight() throws Exception {
PackValidationResult result = validate("{\"regions\":[\"region\"]}");
assertTrue(result.getBlockingErrors().toString(), result.isLoadable());
}
@Test
public void resolvesDimensionHeightSnippet() throws Exception {
File pack = pack("{\"regions\":[\"region\"],\"dimensionHeight\":\"snippet/range/tall\"}");
write(pack, "snippet/range/tall.json", "{\"min\":-60,\"max\":324}");
PackValidationResult result = PackValidator.validate(pack);
assertTrue(result.getBlockingErrors().contains(
"Dimension 'main' dimensionHeight.min is -60; it must be a multiple of 16."));
}
@Test
public void validatorAgreesWithIrisDimensionTypeExactly() {
int[][] triples = {
// {minY, maxY, logicalHeight}
{-64, 320, 256}, {-256, 512, 512}, {-64, 300, 256}, {-60, 324, 256},
{0, 0, 0}, {-2032, 2048, 256}, {-2048, -1664, 0}, {0, 16, 16},
{0, 16, 17}, {0, 16, -1}, {16, 32, 16}, {-64, 320, 384},
{-64, 320, 385}, {2016, 2032, 16}, {2032, 2048, 16}, {-2032, -2016, 16},
{8, 24, 16}, {0, 4064, 4064}, {0, 4080, 4064}, {-64, 4000, 4064},
};
for (int[] triple : triples) {
int minY = triple[0];
int maxY = triple[1];
int logicalHeight = triple[2];
boolean constructorRejects;
try {
new IrisDimensionType(IDataFixer.Dimension.OVERWORLD, new IrisDimensionTypeOptions(),
logicalHeight, maxY - minY, minY);
constructorRejects = false;
} catch (IllegalArgumentException e) {
constructorRejects = true;
}
List<String> errors = new ArrayList<>();
PackDimensionValidator.validateDimensionHeights(null, "main", new art.arcane.volmlib.util.json.JSONObject(
"{\"logicalHeight\":" + logicalHeight
+ ",\"dimensionHeight\":{\"min\":" + minY + ",\"max\":" + maxY + "}}"), errors);
assertEquals("triple (" + minY + "," + maxY + "," + logicalHeight + ") errors=" + errors,
constructorRejects, !errors.isEmpty());
}
}
private PackValidationResult validate(String dimensionJson) throws Exception {
return PackValidator.validate(pack(dimensionJson));
}
private File pack(String dimensionJson) throws Exception {
File pack = temporaryFolder.newFolder("pack-" + System.nanoTime());
write(pack, "dimensions/main.json", dimensionJson);
write(pack, "regions/region.json", "{\"landBiomes\":[\"biome\"]}");
write(pack, "biomes/biome.json", "{\"name\":\"Biome\"}");
return pack;
}
private void write(File root, String relative, String content) throws Exception {
Path target = new File(root, relative).toPath();
Files.createDirectories(target.getParent());
Files.writeString(target, content, StandardCharsets.UTF_8);
}
}
@@ -28,7 +28,7 @@ public class PackValidatorLootTest {
write(pack, "dimensions/main.json", "{\"loot\":{\"mode\":\"FALLBACK\",\"multiplier\":0.5,"
+ "\"tables\":[\"global/clutter\"]}}");
assertTrue(PackLootValidator.validateLootGraph(pack).isEmpty());
assertTrue(PackLootValidator.validateLootGraph(pack).errors().isEmpty());
}
@Test
@@ -37,7 +37,7 @@ public class PackValidatorLootTest {
write(pack, "dimensions/main.json", "{\"loot\":{\"tables\":[\"missing\"]}}");
assertEquals(List.of("Dimension 'main'.loot.tables[0] references missing loot table 'missing'."),
PackLootValidator.validateLootGraph(pack));
PackLootValidator.validateLootGraph(pack).errors());
}
@Test
@@ -47,7 +47,7 @@ public class PackValidatorLootTest {
+ "\"loot\":[{\"type\":\"\",\"rarity\":0,\"minAmount\":3,\"maxAmount\":1,"
+ "\"enchantments\":[{\"enchantment\":\"\",\"minLevel\":4,\"maxLevel\":2,\"chance\":2}]}]}");
List<String> errors = PackLootValidator.validateLootGraph(pack);
List<String> errors = PackLootValidator.validateLootGraph(pack).errors();
assertTrue(errors.stream().anyMatch(error -> error.contains(".rarity must be at least 1")));
assertTrue(errors.stream().anyMatch(error -> error.contains(".minPicked must not exceed")));
@@ -63,7 +63,7 @@ public class PackValidatorLootTest {
File pack = temporaryFolder.newFolder("pack");
write(pack, "dimensions/main.json", "{\"loot\":{\"mode\":\"MERGE\",\"multiplier\":-1,\"tables\":[]}}");
List<String> errors = PackLootValidator.validateLootGraph(pack);
List<String> errors = PackLootValidator.validateLootGraph(pack).errors();
assertEquals(2, errors.size());
assertTrue(errors.get(0).contains(".mode must be"));
@@ -74,12 +74,12 @@ public class PackValidatorLootTest {
public void enforcesPublishedLootMultiplierCap() throws Exception {
File acceptedPack = temporaryFolder.newFolder("accepted-pack");
write(acceptedPack, "dimensions/main.json", "{\"loot\":{\"multiplier\":16,\"tables\":[]}}");
assertTrue(PackLootValidator.validateLootGraph(acceptedPack).isEmpty());
assertTrue(PackLootValidator.validateLootGraph(acceptedPack).errors().isEmpty());
File rejectedPack = temporaryFolder.newFolder("rejected-pack");
write(rejectedPack, "dimensions/main.json", "{\"loot\":{\"multiplier\":16.01,\"tables\":[]}}");
assertEquals(List.of("Dimension 'main'.loot.multiplier must be a finite number from 0 to 16."),
PackLootValidator.validateLootGraph(rejectedPack));
PackLootValidator.validateLootGraph(rejectedPack).errors());
}
@Test
@@ -88,7 +88,7 @@ public class PackValidatorLootTest {
write(pack, "loot/boundary.json", "{\"minPicked\":64,\"maxPicked\":64,\"maxTries\":256,"
+ "\"loot\":[{\"type\":\"stone\",\"minAmount\":64,\"maxAmount\":64}]}");
assertTrue(PackLootValidator.validateLootGraph(pack).isEmpty());
assertTrue(PackLootValidator.validateLootGraph(pack).errors().isEmpty());
}
@Test
@@ -97,7 +97,7 @@ public class PackValidatorLootTest {
write(pack, "loot/excessive.json", "{\"minPicked\":65,\"maxPicked\":65,\"maxTries\":257,"
+ "\"loot\":[{\"type\":\"stone\",\"minAmount\":65,\"maxAmount\":65}]}");
List<String> errors = PackLootValidator.validateLootGraph(pack);
List<String> errors = PackLootValidator.validateLootGraph(pack).errors();
assertTrue(errors.contains("Loot table 'excessive'.minPicked must be at most 64."));
assertTrue(errors.contains("Loot table 'excessive'.maxPicked must be at most 64."));
@@ -121,6 +121,31 @@ public class PackValidatorLootTest {
assertEquals(expected, maximum.value(), 0D);
}
@Test
public void clearModeWithTablesWarnsWithoutBlocking() throws Exception {
File pack = temporaryFolder.newFolder("clear-warn");
write(pack, "loot/t.json", "{\"loot\":[{\"type\":\"minecraft:stone\"}]}");
write(pack, "biomes/x.json", "{\"loot\":{\"mode\":\"CLEAR\",\"tables\":[\"t\"]}}");
PackLootValidator.LootGraphIssues issues = PackLootValidator.validateLootGraph(pack);
assertTrue(issues.errors().isEmpty());
assertEquals(List.of("Biome 'x'.loot uses mode CLEAR and lists 1 table(s); CLEAR clears parent tables"
+ " and contributes no tables of its own, so these entries are dead. Use REPLACE to substitute them."),
issues.warnings());
}
@Test
public void clearModeWithMissingTableStillBlocksOnTheDanglingKey() throws Exception {
File pack = temporaryFolder.newFolder("clear-dangling");
write(pack, "biomes/x.json", "{\"loot\":{\"mode\":\"CLEAR\",\"tables\":[\"missing\"]}}");
PackLootValidator.LootGraphIssues issues = PackLootValidator.validateLootGraph(pack);
assertTrue(issues.errors().contains(
"Biome 'x'.loot.tables[0] references missing loot table 'missing'."));
}
private void write(File root, String relative, String content) throws Exception {
File file = new File(root, relative);
Files.createDirectories(file.toPath().getParent());
@@ -315,26 +315,6 @@ public class DecoratorCoreTest {
assertSame(occupied, output.get(0, 2, 0));
}
@Test
public void tallSinglePlantDoesNotPlaceWhenLowerTargetIsOccupied() {
IrisDecorator decorator = mock(IrisDecorator.class);
IrisData data = mock(IrisData.class);
PlatformBlockState occupied = mock(PlatformBlockState.class);
PlatformBlockState air = airState();
PlatformBlockState plant = tallPlantState();
when(decorator.pickBlockData(any(RNG.class), eq(data), anyDouble(), anyDouble())).thenReturn(plant);
Hunk<PlatformBlockState> output = Hunk.newArrayHunk(1, 4, 1);
output.set(0, 1, 0, occupied);
output.set(0, 2, 0, air);
DecoratorCore.placeSingleUp(
decorator, 0, 0, 0, 0, 0, output, new RNG(1L), data, false, null);
assertSame(occupied, output.get(0, 1, 0));
assertSame(air, output.get(0, 2, 0));
}
@Test
public void tallFloatingPlantDoesNotPlaceWhenUpperTargetIsOccupied() {
IrisDecorator decorator = mock(IrisDecorator.class);
@@ -0,0 +1,30 @@
package art.arcane.iris.engine.framework;
import art.arcane.iris.engine.object.IrisLootMode;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class LootResolverClearModeTest {
@Test
public void clearSuppressesItsOwnTablesAndReplaceDoesNot() {
List<String> cleared = new ArrayList<>(List.of("placement", "dimension"));
LootResolver.injectSources(cleared, List.of("biome"), IrisLootMode.CLEAR, false);
assertTrue("CLEAR must clear parents and contribute nothing", cleared.isEmpty());
List<String> replaced = new ArrayList<>(List.of("placement", "dimension"));
LootResolver.injectSources(replaced, List.of("biome"), IrisLootMode.REPLACE, false);
assertEquals(List.of("biome"), replaced);
}
@Test
public void clearIgnoresTheFallbackFlag() {
List<String> sources = new ArrayList<>(List.of("placement"));
LootResolver.injectSources(sources, List.of("biome"), IrisLootMode.CLEAR, true);
assertTrue(sources.isEmpty());
}
}
@@ -1,6 +1,7 @@
package art.arcane.iris.engine.mantle;
import art.arcane.iris.core.link.Identifier;
import art.arcane.iris.engine.framework.TreeBlockMaterial;
import art.arcane.iris.spi.IrisPlatform;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.spi.PlatformBlockState;
@@ -43,6 +44,57 @@ public class EngineMantleCleanupTest {
@After
public void unbindPlatform() {
IrisPlatforms.unbind();
MantleSliceRetention.clearForTesting();
}
@Test
public void retainedSlicesSurviveCoveredCleanup() {
MantleSliceRetention.retain(MatterCavern.class.getCanonicalName());
CleanupFixture fixture = cleanupFixture();
doReturn(true).when(fixture.engineMantle()).isCovered(7, -4);
fixture.engineMantle().cleanupChunk(7, -4);
verify(fixture.chunk(), never()).deleteSlices(MatterCavern.class);
verify(fixture.chunk()).deleteSlices(PlatformBlockState.class);
}
@Test
public void retainedSlicesSurvivePregenForceCleanup() {
MantleSliceRetention.retain(TreeBlockMaterial.class.getCanonicalName());
MantleSliceRetention.retain(String.class.getCanonicalName());
CleanupFixture fixture = cleanupFixture();
fixture.engineMantle().forceCleanupChunk(7, -4);
verify(fixture.chunk(), never()).deleteSlices(TreeBlockMaterial.class);
verify(fixture.chunk(), never()).deleteSlices(String.class);
verify(fixture.chunk()).deleteSlices(MatterCavern.class);
verify(fixture.chunk()).deleteSlices(PlatformBlockState.class);
}
@Test
public void bukkitBootRetentionsSurvivePregen() {
// Exactly the slice types the Bukkit plugin registers at boot: markers and tree materials
// must keep working in pregenerated chunks.
MantleSliceRetention.retain(String.class.getCanonicalName());
MantleSliceRetention.retain(TreeBlockMaterial.class.getCanonicalName());
CleanupFixture fixture = cleanupFixture();
fixture.engineMantle().forceCleanupChunk(7, -4);
verify(fixture.chunk(), never()).deleteSlices(String.class);
verify(fixture.chunk(), never()).deleteSlices(TreeBlockMaterial.class);
}
@Test
public void blockStateSliceIsNeverRetainable() {
MantleSliceRetention.retain(PlatformBlockState.class.getCanonicalName());
CleanupFixture fixture = cleanupFixture();
fixture.engineMantle().forceCleanupChunk(7, -4);
verify(fixture.chunk()).deleteSlices(PlatformBlockState.class);
}
@Test
@@ -0,0 +1,70 @@
package art.arcane.iris.engine.object;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class IrisAxisRotationClampPurityTest {
private static IrisAxisRotationClamp unlimited(double interval) {
IrisAxisRotationClamp clamp = new IrisAxisRotationClamp();
clamp.setEnabled(true);
clamp.setInterval(interval);
return clamp;
}
private static double reference(double interval, int rng) {
double resolved = interval < 1 ? 1 : interval;
return Math.toRadians((resolved * (Math.ceil(Math.abs((rng % 360D) / resolved)))) % 360D);
}
@Test
public void getRadiansDoesNotMutateIntervalWhenUnlimited() {
IrisAxisRotationClamp clamp = unlimited(0);
clamp.getRadians(37);
assertEquals(0D, clamp.getInterval(), 0D);
}
@Test
public void getRadiansValuesAreUnchangedByTheFix() {
double[] intervals = {0, 0.5, 1, 90};
int[] rngs = {0, 1, 37, 91, 359, 720, -13};
for (double interval : intervals) {
for (int rng : rngs) {
assertEquals("interval=" + interval + " rng=" + rng,
reference(interval, rng), unlimited(interval).getRadians(rng), 0D);
}
}
}
@Test
public void equalsAndHashCodeSurviveRepeatedGetRadians() {
IrisAxisRotationClamp a = unlimited(0);
IrisAxisRotationClamp b = unlimited(0);
a.getRadians(123);
assertEquals(a, b);
assertEquals(a.hashCode(), b.hashCode());
}
@Test
public void concurrentGetRadiansLeavesIntervalUntouched() throws InterruptedException {
IrisAxisRotationClamp shared = unlimited(0);
List<Thread> threads = new ArrayList<>();
for (int t = 0; t < 8; t++) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10_000; i++) {
shared.getRadians(i);
}
});
threads.add(thread);
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
assertTrue("interval must stay at the authored value", shared.getInterval() == 0D);
}
}
@@ -0,0 +1,50 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.math.RNG;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public class IrisBiomeCeilingLayerGuardTest {
private static IrisBiome biome(int layers, int ceilingLayers) {
IrisBiome biome = new IrisBiome();
KList<IrisBiomePaletteLayer> surface = new KList<>();
for (int i = 0; i < layers; i++) {
surface.add(new IrisBiomePaletteLayer().zero());
}
KList<IrisBiomePaletteLayer> ceiling = new KList<>();
for (int i = 0; i < ceilingLayers; i++) {
IrisBiomePaletteLayer layer = new IrisBiomePaletteLayer().zero();
layer.setMinHeight(0);
layer.setMaxHeight(0);
ceiling.add(layer);
}
biome.setLayers(surface);
biome.setCaveCeilingLayers(ceiling);
return biome;
}
@Test
public void moreCeilingLayersThanLayersMustNotThrow() {
IrisBiome biome = biome(1, 3);
KList<PlatformBlockState> result = biome.generateCeilingLayers(
new IrisDimension(), 0, 0, new RNG(1), 8, 64, mock(IrisData.class), null);
assertTrue("extra ceiling layers are skipped, not crashed on", result.isEmpty());
}
@Test
public void inRangeCeilingLayersKeepWorking() {
IrisBiome biome = biome(3, 2);
KList<PlatformBlockState> result = biome.generateCeilingLayers(
new IrisDimension(), 0, 0, new RNG(1), 8, 64, mock(IrisData.class), null);
assertTrue("zeroed palettes with zero heights produce no blocks", result.isEmpty());
}
}
@@ -0,0 +1,116 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.iris.util.common.math.IrisBlockVector;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class IrisObjectIoWriteLimitsTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
private static PlatformBlockState state(String key) {
return (PlatformBlockState) Proxy.newProxyInstance(
IrisObjectIoWriteLimitsTest.class.getClassLoader(),
new Class<?>[]{PlatformBlockState.class},
(proxy, method, args) -> switch (method.getName()) {
case "key" -> key;
case "toString" -> key;
case "hashCode" -> key.hashCode();
case "equals" -> proxy == args[0];
default -> switch (method.getReturnType().getName()) {
case "boolean" -> false;
case "int" -> 0;
case "double" -> 0D;
default -> null;
};
});
}
private static IrisObject objectWithDistinctStates(int paletteSize) {
IrisObject object = new IrisObject(64, 64, 64);
object.setLoadKey("limits-test");
int placed = 0;
outer:
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
for (int z = 0; z < 64; z++) {
if (placed >= paletteSize) {
break outer;
}
object.blocks.put(new IrisBlockVector(x, y, z), state("iris:test_" + placed));
placed++;
}
}
}
return object;
}
@Test
public void rejectsPaletteOverflowInsteadOfWrappingTheShort() {
IrisObject object = objectWithDistinctStates(32_768);
try {
IrisObjectIO.write(object, new ByteArrayOutputStream());
fail("expected the oversized palette to be rejected");
} catch (IOException e) {
assertTrue(e.getMessage(), e.getMessage().contains("limits-test"));
assertTrue(e.getMessage(), e.getMessage().contains("32768"));
}
}
@Test
public void acceptsPaletteAtExactlyTheCap() throws IOException {
IrisObject object = objectWithDistinctStates(32_767);
File file = folder.newFile("cap.iob");
IrisObjectIO.write(object, file);
assertEquals(32_767, IrisObjectIO.readPaletteKeys(file).size());
}
@Test
public void rejectsCoordinateBeyondShortRange() {
IrisObject object = new IrisObject(64, 64, 64);
object.setLoadKey("limits-test");
object.blocks.put(new IrisBlockVector(40_000, 0, 0), state("iris:test"));
try {
IrisObjectIO.write(object, new ByteArrayOutputStream());
fail("expected the out-of-range coordinate to be rejected");
} catch (IOException e) {
assertTrue(e.getMessage(), e.getMessage().contains("40000"));
assertTrue(e.getMessage(), e.getMessage().contains("x"));
}
}
@Test
public void failedWriteLeavesExistingFileIntact() throws IOException {
File file = folder.newFile("existing.iob");
IrisObject valid = objectWithDistinctStates(3);
IrisObjectIO.write(valid, file);
byte[] before = Files.readAllBytes(file.toPath());
IrisObject oversized = objectWithDistinctStates(32_768);
try {
IrisObjectIO.write(oversized, file);
fail("expected the oversized write to be rejected");
} catch (IOException expected) {
}
assertArrayEquals("a rejected write must not truncate the previous object", before,
Files.readAllBytes(file.toPath()));
}
}
@@ -67,7 +67,6 @@ public class IrisObjectPlacementToPlacementTest {
source.setBottom(true);
source.setBore(true);
source.setWarp(warp);
source.setTranslateCenter(true);
source.setMode(ObjectPlaceMode.FAST_MIN_STILT);
source.setEdit(edit);
source.setTranslate(translate);
@@ -112,7 +111,6 @@ public class IrisObjectPlacementToPlacementTest {
assertTrue(copy.isBottom());
assertTrue(copy.isBore());
assertSame(warp, copy.getWarp());
assertTrue(copy.isTranslateCenter());
assertEquals(ObjectPlaceMode.FAST_MIN_STILT, copy.getMode());
assertSame(edit, copy.getEdit());
assertSame(translate, copy.getTranslate());
@@ -0,0 +1,55 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.core.IrisSettings;
import com.google.gson.Gson;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
public class RemovedDeadFieldsTest {
@Test
public void removedFieldsStayRemoved() {
assertThrows(NoSuchFieldException.class, () -> IrisDimension.class.getDeclaredField("forceConvertTo320Height"));
assertThrows(NoSuchFieldException.class, () -> IrisDimension.class.getDeclaredField("rockZoom"));
assertThrows(NoSuchFieldException.class, () -> IrisDimension.class.getDeclaredField("disableExplorerMaps"));
assertThrows(NoSuchFieldException.class, () -> IrisRegion.class.getDeclaredField("riverStyle"));
assertThrows(NoSuchFieldException.class, () -> IrisRegion.class.getDeclaredField("lakeStyle"));
assertThrows(NoSuchFieldException.class, () -> IrisRegion.class.getDeclaredField("riverGen"));
assertThrows(NoSuchFieldException.class, () -> IrisRegion.class.getDeclaredField("lakeGen"));
assertThrows(NoSuchFieldException.class, () -> IrisRegion.class.getDeclaredField("riverChanceGen"));
assertThrows(NoSuchFieldException.class, () -> IrisRegion.class.getDeclaredField("realRiverBiomes"));
assertThrows(NoSuchFieldException.class, () -> IrisRegion.class.getDeclaredField("realLakeBiomes"));
assertThrows(NoSuchFieldException.class, () -> IrisObjectPlacement.class.getDeclaredField("translateCenter"));
assertThrows(NoSuchFieldException.class, () -> IrisTree.class.getDeclaredField("anyTree"));
assertThrows(NoSuchFieldException.class, () -> IrisTree.class.getDeclaredField("anySize"));
assertThrows(NoSuchMethodException.class, () -> IrisRegion.class.getDeclaredMethod("getBiomeZoom", InferredType.class));
}
@Test
public void legacyKeysAreIgnoredNotFatal() {
IrisDimension dimension = new Gson().fromJson(
"{\"name\":\"x\",\"rockZoom\":9,\"disableExplorerMaps\":true,\"forceConvertTo320Height\":true}",
IrisDimension.class);
assertNotNull(dimension);
assertEquals("x", dimension.getName());
IrisTree tree = new Gson().fromJson("{\"anyTree\":true,\"anySize\":true}", IrisTree.class);
assertNotNull(tree);
IrisRegion region = new Gson().fromJson(
"{\"name\":\"r\",\"riverStyle\":{\"zoom\":7.77},\"lakeStyle\":{}}", IrisRegion.class);
assertNotNull(region);
assertEquals("r", region.getName());
}
@Test
public void studioSettingsKeepTheirLiveToggles() throws Exception {
// disableTimeAndWeather is read by WorldRuntimeControlService, and autoStartDefaultStudio
// by Iris.autoStartStudio() at boot - both are live and must NOT be removed.
assertNotNull(IrisSettings.IrisSettingsStudio.class.getDeclaredField("disableTimeAndWeather"));
assertNotNull(IrisSettings.IrisSettingsStudio.class.getDeclaredField("autoStartDefaultStudio"));
}
}
@@ -0,0 +1,53 @@
package art.arcane.iris.spi;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.Answers.CALLS_REAL_METHODS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class PacksFolderContractTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void defaultPacksFolderIsDataFolderPacks() {
File data = temporaryFolder.getRoot();
IrisPlatform platform = mock(IrisPlatform.class, CALLS_REAL_METHODS);
when(platform.dataFolder()).thenReturn(data);
assertEquals(new File(data, "packs"), platform.packsFolder());
assertEquals(new File(data, "packs" + File.separator + "overworld"), platform.packsFolderNoCreate("overworld"));
}
/**
* Source guard: nothing outside the SPI defaults and platform overrides may spell the packs
* root by hand. New code goes through packsFolder()/packsFolderNoCreate().
*/
@Test
public void noCallSiteResolvesThePacksRootByHand() throws Exception {
List<Path> roots = List.of(
Path.of("src/main/java"),
Path.of("../adapters/bukkit/plugin/src/main/java"));
for (Path root : roots) {
try (var stream = Files.walk(root)) {
for (Path file : stream.filter(p -> p.toString().endsWith(".java")).toList()) {
String text = Files.readString(file);
assertFalse(file + " must use packsFolder() instead of dataFolder(\"packs\")",
text.contains("dataFolder(\"packs\")"));
assertFalse(file + " must use packsFolderNoCreate() instead of the WORKSPACE_NAME indirection",
text.contains("dataFolderNoCreate(StudioSVC.WORKSPACE_NAME"));
}
}
}
}
}
@@ -81,14 +81,16 @@ public class SimdKernelsTest {
}
@Test
public void vectorSumMatchesScalarWithinTolerance() {
public void vectorSumMatchesScalarExactly() {
// Zero tolerance on purpose: sum feeds generation-path ranking, so any kernel that
// reassociates FP addition must fail here instead of shipping a parity break.
SimdKernels vector = requireVectorKernels();
ScalarSimdKernels scalar = new ScalarSimdKernels();
for (int length : new int[]{256, 251, 1, 7}) {
double[] values = terrainLikeValues(length);
double expected = scalar.sum(values, length);
double actual = vector.sum(values, length);
assertEquals("length " + length, expected, actual, Math.max(1e-9D, Math.abs(expected) * 1e-12D));
assertEquals("length " + length, expected, actual, 0D);
}
}