From 71e3af727f17d98601bc463b775d07ef522f945d Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Tue, 8 Sep 2026 05:01:44 -0400 Subject: [PATCH] Parameterize template-identical tests - Split PackValidatorCustomBiomeSpawnTest into parameterized accepted and rejected suites plus the resolver-failure case - Drive IrisCarveWallPaletteScopeTest from its four generation-scope modes - Parameterize the legacy bilerp parity samples in IrisComplexGridBoundsCacheTest behind Enclosed - Parameterize the resolved bounds in IrisStructureYBandTest - Parameterize the entity key normalization in IrisBiomeCustomSpawnTest - Parameterize the platform identity in IrisWorldIdentityTest - Parameterize the layer lock in IrisBiomeLayerSlopeSourceTest --- .../PackValidatorCustomBiomeSpawnTest.java | 308 +++++++++--------- .../engine/IrisCarveWallPaletteScopeTest.java | 39 ++- .../IrisComplexGridBoundsCacheTest.java | 183 ++++++----- .../object/IrisBiomeCustomSpawnTest.java | 39 ++- .../object/IrisBiomeLayerSlopeSourceTest.java | 28 +- .../engine/object/IrisStructureYBandTest.java | 85 +++-- .../engine/object/IrisWorldIdentityTest.java | 30 +- 7 files changed, 381 insertions(+), 331 deletions(-) diff --git a/core/src/test/java/art/arcane/iris/core/pack/PackValidatorCustomBiomeSpawnTest.java b/core/src/test/java/art/arcane/iris/core/pack/PackValidatorCustomBiomeSpawnTest.java index d7d8ff772..1d0198487 100644 --- a/core/src/test/java/art/arcane/iris/core/pack/PackValidatorCustomBiomeSpawnTest.java +++ b/core/src/test/java/art/arcane/iris/core/pack/PackValidatorCustomBiomeSpawnTest.java @@ -2,178 +2,172 @@ package art.arcane.iris.core.pack; import org.junit.Rule; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import java.io.File; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.util.Collection; import java.util.List; +import java.util.function.Function; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +@RunWith(Enclosed.class) public class PackValidatorCustomBiomeSpawnTest { - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + private static final Function MONSTER = + key -> PackSpawnValidator.SpawnCategoryResolution.known("monster"); + private static final Function MISC = + key -> PackSpawnValidator.SpawnCategoryResolution.known("misc"); + private static final Function AXOLOTLS = + key -> PackSpawnValidator.SpawnCategoryResolution.known("axolotls"); + private static final Function UNKNOWN = + key -> PackSpawnValidator.SpawnCategoryResolution.unknown(); - @Test - public void acceptsExplicitMatchingSpawnGroup() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\",\"group\":\"MONSTER\"}]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns( - biomes, key -> PackSpawnValidator.SpawnCategoryResolution.known("monster")); - - assertTrue(errors.isEmpty()); - } - - @Test - public void acceptsBiomeWithoutCustomSpawns() throws Exception { - File biomes = createBiomes("{\"name\":\"Plains\"}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns( - biomes, key -> PackSpawnValidator.SpawnCategoryResolution.known("monster")); - - assertTrue(errors.isEmpty()); - } - - @Test - public void rejectsMissingSpawnGroup() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\"}]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns( - biomes, key -> PackSpawnValidator.SpawnCategoryResolution.known("monster")); - - assertEquals(1, errors.size()); - assertTrue(errors.get(0).contains("must declare group 'MONSTER'")); - } - - @Test - public void acceptsImplicitMiscSpawnGroup() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"effects\",\"spawns\":[{\"type\":\"minecraft:armor_stand\"}]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns( - biomes, key -> PackSpawnValidator.SpawnCategoryResolution.known("misc")); - - assertTrue(errors.isEmpty()); - } - - @Test - public void rejectsSpawnGroupThatDisagreesWithRegistry() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\",\"group\":\"MISC\"}]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns( - biomes, key -> PackSpawnValidator.SpawnCategoryResolution.known("monster")); - - assertEquals(1, errors.size()); - assertTrue(errors.get(0).contains("live entity registry requires 'MONSTER'")); - } - - @Test - public void acceptsAxolotlSpawnCategory() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"cave\",\"spawns\":[{\"type\":\"minecraft:axolotl\",\"group\":\"AXOLOTLS\"}]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns( - biomes, key -> PackSpawnValidator.SpawnCategoryResolution.known("axolotls")); - - assertTrue(errors.isEmpty()); - } - - @Test - public void rejectsUnknownSpawnEntity() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"missing:entity\",\"group\":\"MISC\"}]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns( - biomes, key -> PackSpawnValidator.SpawnCategoryResolution.unknown()); - - assertEquals(1, errors.size()); - assertTrue(errors.get(0).contains("unknown entity type 'missing:entity'")); - } - - @Test - public void rejectsCaseNormalizedGroupThatRuntimeWouldNotParse() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\",\"group\":\"monster\"}]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns( - biomes, key -> PackSpawnValidator.SpawnCategoryResolution.known("monster")); - - assertEquals(1, errors.size()); - assertTrue(errors.get(0).contains("unknown group 'monster'")); - } - - @Test - public void rejectsWrongCustomDerivativeContainerType() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":{}}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, null); - - assertEquals(1, errors.size()); - assertTrue(errors.get(0).contains("customDerivitives must be an array")); - } - - @Test - public void rejectsWrongSpawnContainerType() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":{}}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, null); - - assertEquals(1, errors.size()); - assertTrue(errors.get(0).contains("spawns must be an array")); - } - - @Test - public void acceptsNullCustomDerivativeContainerAsAbsent() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":null}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, null); - - assertTrue(errors.isEmpty()); - } - - @Test - public void acceptsNullSpawnContainerAsAbsent() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":null}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, null); - - assertTrue(errors.isEmpty()); - } - - @Test - public void acceptsNamespacedCustomBiomeTags() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"tags\":[\"minecraft:allows_surface_slime_spawns\"]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, null); - - assertTrue(errors.isEmpty()); - } - - @Test - public void rejectsUnsafeCustomBiomeTags() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"tags\":[\"minecraft:../outside\"]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, null); - - assertEquals(1, errors.size()); - assertTrue(errors.get(0).contains("invalid tag")); - } - - @Test - public void convertsSpawnCategoryResolverFailureIntoBlockingError() throws Exception { - File biomes = createBiomes("{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\",\"group\":\"MONSTER\"}]}]}"); - - List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, key -> { - throw new IllegalStateException("registry unavailable"); - }); - - assertEquals(1, errors.size()); - assertTrue(errors.get(0).contains("spawn category lookup failed")); - assertTrue(errors.get(0).contains("registry unavailable")); - } - - private File createBiomes(String json) throws Exception { + private static File createBiomes(TemporaryFolder temporaryFolder, String json) throws Exception { File biomes = temporaryFolder.newFolder("biomes"); File biome = new File(biomes, "test.json"); Files.writeString(biome.toPath(), json, StandardCharsets.UTF_8); return biomes; } + + @RunWith(Parameterized.class) + public static class Accepted { + @Parameters(name = "{0}") + public static Collection biomes() { + return List.of( + new Object[]{"explicitMatchingSpawnGroup", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\",\"group\":\"MONSTER\"}]}]}", + MONSTER}, + new Object[]{"biomeWithoutCustomSpawns", + "{\"name\":\"Plains\"}", + MONSTER}, + new Object[]{"implicitMiscSpawnGroup", + "{\"customDerivitives\":[{\"id\":\"effects\",\"spawns\":[{\"type\":\"minecraft:armor_stand\"}]}]}", + MISC}, + new Object[]{"axolotlSpawnCategory", + "{\"customDerivitives\":[{\"id\":\"cave\",\"spawns\":[{\"type\":\"minecraft:axolotl\",\"group\":\"AXOLOTLS\"}]}]}", + AXOLOTLS}, + new Object[]{"nullCustomDerivativeContainerAsAbsent", + "{\"customDerivitives\":null}", + null}, + new Object[]{"nullSpawnContainerAsAbsent", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":null}]}", + null}, + new Object[]{"namespacedCustomBiomeTags", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"tags\":[\"minecraft:allows_surface_slime_spawns\"]}]}", + null} + ); + } + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private final String scenario; + private final String json; + private final Function categoryResolver; + + public Accepted( + String scenario, + String json, + Function categoryResolver + ) { + this.scenario = scenario; + this.json = json; + this.categoryResolver = categoryResolver; + } + + @Test + public void reportsNoSpawnErrors() throws Exception { + File biomes = createBiomes(temporaryFolder, json); + + List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, categoryResolver); + + assertTrue(scenario + " " + errors, errors.isEmpty()); + } + } + + @RunWith(Parameterized.class) + public static class Rejected { + @Parameters(name = "{0}") + public static Collection biomes() { + return List.of( + new Object[]{"missingSpawnGroup", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\"}]}]}", + MONSTER, "must declare group 'MONSTER'"}, + new Object[]{"spawnGroupThatDisagreesWithRegistry", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\",\"group\":\"MISC\"}]}]}", + MONSTER, "live entity registry requires 'MONSTER'"}, + new Object[]{"unknownSpawnEntity", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"missing:entity\",\"group\":\"MISC\"}]}]}", + UNKNOWN, "unknown entity type 'missing:entity'"}, + new Object[]{"caseNormalizedGroupThatRuntimeWouldNotParse", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\",\"group\":\"monster\"}]}]}", + MONSTER, "unknown group 'monster'"}, + new Object[]{"wrongCustomDerivativeContainerType", + "{\"customDerivitives\":{}}", + null, "customDerivitives must be an array"}, + new Object[]{"wrongSpawnContainerType", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":{}}]}", + null, "spawns must be an array"}, + new Object[]{"unsafeCustomBiomeTags", + "{\"customDerivitives\":[{\"id\":\"swamp\",\"tags\":[\"minecraft:../outside\"]}]}", + null, "invalid tag"} + ); + } + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private final String scenario; + private final String json; + private final Function categoryResolver; + private final String expectedError; + + public Rejected( + String scenario, + String json, + Function categoryResolver, + String expectedError + ) { + this.scenario = scenario; + this.json = json; + this.categoryResolver = categoryResolver; + this.expectedError = expectedError; + } + + @Test + public void reportsExactlyOneSpawnError() throws Exception { + File biomes = createBiomes(temporaryFolder, json); + + List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, categoryResolver); + + assertEquals(scenario + " " + errors, 1, errors.size()); + assertTrue(errors.get(0), errors.get(0).contains(expectedError)); + } + } + + public static class ResolverFailure { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void convertsSpawnCategoryResolverFailureIntoBlockingError() throws Exception { + File biomes = createBiomes(temporaryFolder, + "{\"customDerivitives\":[{\"id\":\"swamp\",\"spawns\":[{\"type\":\"minecraft:slime\",\"group\":\"MONSTER\"}]}]}"); + + List errors = PackSpawnValidator.validateCustomBiomeSpawns(biomes, key -> { + throw new IllegalStateException("registry unavailable"); + }); + + assertEquals(1, errors.size()); + assertTrue(errors.get(0).contains("spawn category lookup failed")); + assertTrue(errors.get(0).contains("registry unavailable")); + } + } } diff --git a/core/src/test/java/art/arcane/iris/engine/IrisCarveWallPaletteScopeTest.java b/core/src/test/java/art/arcane/iris/engine/IrisCarveWallPaletteScopeTest.java index 84423ea8f..51f79f2e6 100644 --- a/core/src/test/java/art/arcane/iris/engine/IrisCarveWallPaletteScopeTest.java +++ b/core/src/test/java/art/arcane/iris/engine/IrisCarveWallPaletteScopeTest.java @@ -24,11 +24,16 @@ import art.arcane.volmlib.util.math.RNG; import art.arcane.volmlib.util.matter.Matter; import art.arcane.volmlib.util.matter.MatterCavern; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import org.mockito.MockedStatic; import java.lang.reflect.Field; +import java.util.Collection; import java.util.Collections; import java.util.IdentityHashMap; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertEquals; @@ -47,25 +52,27 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.verify; +@RunWith(Parameterized.class) public class IrisCarveWallPaletteScopeTest { - @Test - public void naturalWallsUseOneSelectedDataLookup() throws Exception { - verifyWalls(Mode.NATURAL); + @Parameters(name = "{0}") + public static Collection scopes() { + return List.of( + new Object[]{Mode.NATURAL}, + new Object[]{Mode.CONTENT}, + new Object[]{Mode.DETACHED}, + new Object[]{Mode.ASSEMBLY} + ); + } + + private final Mode mode; + + public IrisCarveWallPaletteScopeTest(Mode mode) { + this.mode = mode; } @Test - public void contentWallsRestoreDataAfterNestedSampling() throws Exception { - verifyWalls(Mode.CONTENT); - } - - @Test - public void detachedWallsUseDetachedData() throws Exception { - verifyWalls(Mode.DETACHED); - } - - @Test - public void assemblyWallsUseUnpublishedData() throws Exception { - verifyWalls(Mode.ASSEMBLY); + public void wallsUseTheDataOfTheirGenerationScope() throws Exception { + verifyWalls(mode); } private static void verifyWalls(Mode mode) throws Exception { @@ -159,7 +166,7 @@ public class IrisCarveWallPaletteScopeTest { return runtime; } - private enum Mode { + enum Mode { NATURAL, CONTENT, DETACHED, diff --git a/core/src/test/java/art/arcane/iris/engine/IrisComplexGridBoundsCacheTest.java b/core/src/test/java/art/arcane/iris/engine/IrisComplexGridBoundsCacheTest.java index 00dfa3d9a..dcdf5d5af 100644 --- a/core/src/test/java/art/arcane/iris/engine/IrisComplexGridBoundsCacheTest.java +++ b/core/src/test/java/art/arcane/iris/engine/IrisComplexGridBoundsCacheTest.java @@ -6,11 +6,17 @@ import art.arcane.iris.engine.object.IrisInterpolator; import art.arcane.iris.util.project.interpolation.NoiseBounds; import art.arcane.iris.util.project.interpolation.NoiseBoundsProvider; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertEquals; @@ -19,109 +25,102 @@ import static org.junit.Assert.assertNotEquals; import static org.mockito.Answers.CALLS_REAL_METHODS; import static org.mockito.Mockito.mock; +@RunWith(Enclosed.class) public class IrisComplexGridBoundsCacheTest { + public static class CornerCache { @Test - public void gridBoundsCacheIsIsolatedPerComplex() throws Exception { - IrisComplex first = createComplex(); - IrisComplex second = createComplex(); - Method cornerBounds = cornerBoundsMethod(); + public void gridBoundsCacheIsIsolatedPerComplex() throws Exception { + IrisComplex first = createComplex(); + IrisComplex second = createComplex(); + Method cornerBounds = cornerBoundsMethod(); - long firstPacked = invokeCornerBounds(first, cornerBounds, new CountingInterpolator(1.25D, 2.5D), 64, -32); - long secondPacked = invokeCornerBounds(second, cornerBounds, new CountingInterpolator(10.25D, 20.5D), 64, -32); + long firstPacked = invokeCornerBounds(first, cornerBounds, new CountingInterpolator(1.25D, 2.5D), 64, -32); + long secondPacked = invokeCornerBounds(second, cornerBounds, new CountingInterpolator(10.25D, 20.5D), 64, -32); - assertNotEquals(firstPacked, secondPacked); - assertEquals(1.25F, unpackLow(firstPacked), 0D); - assertEquals(2.5F, unpackHigh(firstPacked), 0D); - assertEquals(10.25F, unpackLow(secondPacked), 0D); - assertEquals(20.5F, unpackHigh(secondPacked), 0D); - } + assertNotEquals(firstPacked, secondPacked); + assertEquals(1.25F, unpackLow(firstPacked), 0D); + assertEquals(2.5F, unpackHigh(firstPacked), 0D); + assertEquals(10.25F, unpackLow(secondPacked), 0D); + assertEquals(20.5F, unpackHigh(secondPacked), 0D); + } @Test - public void gridBoundsCacheReusesCornersWithinSameComplex() throws Exception { - IrisComplex complex = createComplex(); - Method cornerBounds = cornerBoundsMethod(); - CountingInterpolator interpolator = new CountingInterpolator(3.5D, 7.25D); + public void gridBoundsCacheReusesCornersWithinSameComplex() throws Exception { + IrisComplex complex = createComplex(); + Method cornerBounds = cornerBoundsMethod(); + CountingInterpolator interpolator = new CountingInterpolator(3.5D, 7.25D); - long firstPacked = invokeCornerBounds(complex, cornerBounds, interpolator, 128, 96); - long secondPacked = invokeCornerBounds(complex, cornerBounds, interpolator, 128, 96); + long firstPacked = invokeCornerBounds(complex, cornerBounds, interpolator, 128, 96); + long secondPacked = invokeCornerBounds(complex, cornerBounds, interpolator, 128, 96); - assertEquals(firstPacked, secondPacked); - assertEquals(1, interpolator.getInvocations()); - } + assertEquals(firstPacked, secondPacked); + assertEquals(1, interpolator.getInvocations()); + } @Test - public void nonFiniteCornerBoundsAreNeverCached() throws Exception { - IrisComplex complex = createComplex(); - Method cornerBounds = cornerBoundsMethod(); - CountingInterpolator interpolator = new CountingInterpolator(Double.NaN, 7.25D); + public void nonFiniteCornerBoundsAreNeverCached() throws Exception { + IrisComplex complex = createComplex(); + Method cornerBounds = cornerBoundsMethod(); + CountingInterpolator interpolator = new CountingInterpolator(Double.NaN, 7.25D); - long firstPacked = invokeCornerBounds(complex, cornerBounds, interpolator, 128, 96); - long secondPacked = invokeCornerBounds(complex, cornerBounds, interpolator, 128, 96); + long firstPacked = invokeCornerBounds(complex, cornerBounds, interpolator, 128, 96); + long secondPacked = invokeCornerBounds(complex, cornerBounds, interpolator, 128, 96); - assertTrue(Double.isNaN(unpackLow(firstPacked))); - assertTrue(Double.isNaN(unpackLow(secondPacked))); - assertEquals(2, interpolator.getInvocations()); - } + assertTrue(Double.isNaN(unpackLow(firstPacked))); + assertTrue(Double.isNaN(unpackLow(secondPacked))); + assertEquals(2, interpolator.getInvocations()); + } @Test - public void alignedGridSampleUsesOnlyTheContributingCorner() throws Exception { - IrisComplex complex = createComplex(); - Method gridSampleBounds = gridSampleBoundsMethod(); - CountingInterpolator interpolator = new CountingInterpolator(3.5D, 7.25D); + public void alignedGridSampleUsesOnlyTheContributingCorner() throws Exception { + IrisComplex complex = createComplex(); + Method gridSampleBounds = gridSampleBoundsMethod(); + CountingInterpolator interpolator = new CountingInterpolator(3.5D, 7.25D); - NoiseBounds bounds = invokeGridSampleBounds(complex, gridSampleBounds, interpolator, 64D, -32D); + NoiseBounds bounds = invokeGridSampleBounds(complex, gridSampleBounds, interpolator, 64D, -32D); - assertEquals(3.5F, bounds.min(), 0D); - assertEquals(7.25F, bounds.max(), 0D); - assertEquals(1, interpolator.getInvocations()); + assertEquals(3.5F, bounds.min(), 0D); + assertEquals(7.25F, bounds.max(), 0D); + assertEquals(1, interpolator.getInvocations()); + } } - @Test - public void horizontalGridAxisMatchesLegacyBilerpBitForBit() throws Exception { - IrisComplex complex = createComplex(); - Method gridSampleBounds = gridSampleBoundsMethod(); - CoordinateInterpolator interpolator = new CoordinateInterpolator(); - double x = 67D; - double z = -32D; + @RunWith(Parameterized.class) + public static class LegacyBilerpParity { + @Parameters(name = "x={0} z={1}") + public static Collection samples() { + return List.of( + new Object[]{67D, -32D, 2}, + new Object[]{-32D, -29D, 2}, + new Object[]{-29D, 67D, 4} + ); + } - NoiseBounds actual = invokeGridSampleBounds(complex, gridSampleBounds, interpolator, x, z); - NoiseBounds expected = legacyGridSampleBounds(x, z); + private final double x; + private final double z; + private final int expectedInvocations; - assertBoundsBitsEqual(expected, actual); - assertEquals(2, interpolator.getInvocations()); + public LegacyBilerpParity(double x, double z, int expectedInvocations) { + this.x = x; + this.z = z; + this.expectedInvocations = expectedInvocations; + } + + @Test + public void gridSampleMatchesLegacyBilerpBitForBit() throws Exception { + IrisComplex complex = createComplex(); + Method gridSampleBounds = gridSampleBoundsMethod(); + CoordinateInterpolator interpolator = new CoordinateInterpolator(); + + NoiseBounds actual = invokeGridSampleBounds(complex, gridSampleBounds, interpolator, x, z); + NoiseBounds expected = legacyGridSampleBounds(x, z); + + assertBoundsBitsEqual(expected, actual); + assertEquals(expectedInvocations, interpolator.getInvocations()); + } } - @Test - public void verticalGridAxisMatchesLegacyBilerpBitForBitAtNegativeCoordinates() throws Exception { - IrisComplex complex = createComplex(); - Method gridSampleBounds = gridSampleBoundsMethod(); - CoordinateInterpolator interpolator = new CoordinateInterpolator(); - double x = -32D; - double z = -29D; - - NoiseBounds actual = invokeGridSampleBounds(complex, gridSampleBounds, interpolator, x, z); - NoiseBounds expected = legacyGridSampleBounds(x, z); - - assertBoundsBitsEqual(expected, actual); - assertEquals(2, interpolator.getInvocations()); - } - - @Test - public void interiorGridSampleMatchesLegacyBilerpBitForBit() throws Exception { - IrisComplex complex = createComplex(); - Method gridSampleBounds = gridSampleBoundsMethod(); - CoordinateInterpolator interpolator = new CoordinateInterpolator(); - double x = -29D; - double z = 67D; - - NoiseBounds actual = invokeGridSampleBounds(complex, gridSampleBounds, interpolator, x, z); - NoiseBounds expected = legacyGridSampleBounds(x, z); - - assertBoundsBitsEqual(expected, actual); - assertEquals(4, interpolator.getInvocations()); - } - - private IrisComplex createComplex() throws Exception { + private static IrisComplex createComplex() throws Exception { IrisComplex complex = mock(IrisComplex.class, CALLS_REAL_METHODS); Field generatorBounds = IrisComplex.class.getDeclaredField("generatorBounds"); @@ -138,7 +137,7 @@ public class IrisComplexGridBoundsCacheTest { return complex; } - private Object newCache(Constructor constructor) { + private static Object newCache(Constructor constructor) { try { return constructor.newInstance(); } catch (ReflectiveOperationException e) { @@ -146,7 +145,7 @@ public class IrisComplexGridBoundsCacheTest { } } - private Method cornerBoundsMethod() throws Exception { + private static Method cornerBoundsMethod() throws Exception { Class cacheClass = Class.forName("art.arcane.iris.engine.IrisComplex$GridBoundsCache"); Method method = IrisComplex.class.getDeclaredMethod( "cornerBounds", @@ -162,7 +161,7 @@ public class IrisComplexGridBoundsCacheTest { return method; } - private Method gridSampleBoundsMethod() throws Exception { + private static Method gridSampleBoundsMethod() throws Exception { Method method = IrisComplex.class.getDeclaredMethod( "gridSampleBounds", Engine.class, @@ -176,14 +175,14 @@ public class IrisComplexGridBoundsCacheTest { return method; } - private long invokeCornerBounds(IrisComplex complex, Method method, IrisInterpolator interpolator, int x, int z) throws Exception { + private static long invokeCornerBounds(IrisComplex complex, Method method, IrisInterpolator interpolator, int x, int z) throws Exception { Field gridBoundsCache = IrisComplex.class.getDeclaredField("gridBoundsCache"); gridBoundsCache.setAccessible(true); ThreadLocal cache = (ThreadLocal) gridBoundsCache.get(complex); return (long) method.invoke(complex, cache.get(), null, interpolator, 0, new IrisGenerator[0], x, z); } - private NoiseBounds invokeGridSampleBounds( + private static NoiseBounds invokeGridSampleBounds( IrisComplex complex, Method method, IrisInterpolator interpolator, @@ -193,7 +192,7 @@ public class IrisComplexGridBoundsCacheTest { return (NoiseBounds) method.invoke(complex, null, interpolator, 0, new IrisGenerator[0], x, z); } - private NoiseBounds legacyGridSampleBounds(double x, double z) { + private static NoiseBounds legacyGridSampleBounds(double x, double z) { int grid = 4; int xi = (int) Math.floor(x); int zi = (int) Math.floor(z); @@ -212,14 +211,14 @@ public class IrisComplexGridBoundsCacheTest { ); } - private NoiseBounds packedCoordinateBounds(int x, int z) { + private static NoiseBounds packedCoordinateBounds(int x, int z) { return new NoiseBounds( (float) CoordinateInterpolator.low(x, z), (float) CoordinateInterpolator.high(x, z) ); } - private double legacyBiLerp( + private static double legacyBiLerp( double v00, double v10, double v01, @@ -232,16 +231,16 @@ public class IrisComplexGridBoundsCacheTest { return a + ((b - a) * fz); } - private void assertBoundsBitsEqual(NoiseBounds expected, NoiseBounds actual) { + private static void assertBoundsBitsEqual(NoiseBounds expected, NoiseBounds actual) { assertEquals(Double.doubleToRawLongBits(expected.min()), Double.doubleToRawLongBits(actual.min())); assertEquals(Double.doubleToRawLongBits(expected.max()), Double.doubleToRawLongBits(actual.max())); } - private float unpackLow(long packed) { + private static float unpackLow(long packed) { return Float.intBitsToFloat((int) (packed >>> 32)); } - private float unpackHigh(long packed) { + private static float unpackHigh(long packed) { return Float.intBitsToFloat((int) packed); } diff --git a/core/src/test/java/art/arcane/iris/engine/object/IrisBiomeCustomSpawnTest.java b/core/src/test/java/art/arcane/iris/engine/object/IrisBiomeCustomSpawnTest.java index 47548d9a8..b0bd91d2f 100644 --- a/core/src/test/java/art/arcane/iris/engine/object/IrisBiomeCustomSpawnTest.java +++ b/core/src/test/java/art/arcane/iris/engine/object/IrisBiomeCustomSpawnTest.java @@ -1,29 +1,38 @@ package art.arcane.iris.engine.object; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import java.util.Collection; +import java.util.List; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +@RunWith(Parameterized.class) public class IrisBiomeCustomSpawnTest { - @Test - public void normalizesNamespacedEntityKey() { - IrisBiomeCustomSpawn spawn = new IrisBiomeCustomSpawn().setType(" Minecraft:Slime "); + @Parameters(name = "{0} -> {1}") + public static Collection keys() { + return List.of( + new Object[]{" Minecraft:Slime ", "minecraft:slime"}, + new Object[]{"Slime", "minecraft:slime"}, + new Object[]{" ", null} + ); + } - assertEquals("minecraft:slime", spawn.getTypeKey()); + private final String authored; + private final String expectedKey; + + public IrisBiomeCustomSpawnTest(String authored, String expectedKey) { + this.authored = authored; + this.expectedKey = expectedKey; } @Test - public void prefixesBareEntityKey() { - IrisBiomeCustomSpawn spawn = new IrisBiomeCustomSpawn().setType("Slime"); + public void normalizesTheEntityKey() { + IrisBiomeCustomSpawn spawn = new IrisBiomeCustomSpawn().setType(authored); - assertEquals("minecraft:slime", spawn.getTypeKey()); - } - - @Test - public void returnsNullForBlankEntityKey() { - IrisBiomeCustomSpawn spawn = new IrisBiomeCustomSpawn().setType(" "); - - assertNull(spawn.getTypeKey()); + assertEquals(expectedKey, spawn.getTypeKey()); } } diff --git a/core/src/test/java/art/arcane/iris/engine/object/IrisBiomeLayerSlopeSourceTest.java b/core/src/test/java/art/arcane/iris/engine/object/IrisBiomeLayerSlopeSourceTest.java index ed445edb6..23f77061e 100644 --- a/core/src/test/java/art/arcane/iris/engine/object/IrisBiomeLayerSlopeSourceTest.java +++ b/core/src/test/java/art/arcane/iris/engine/object/IrisBiomeLayerSlopeSourceTest.java @@ -8,6 +8,12 @@ import art.arcane.iris.util.project.stream.ProceduralStream; import art.arcane.volmlib.util.collection.KList; import art.arcane.volmlib.util.math.RNG; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import java.util.Collection; +import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; @@ -17,19 +23,25 @@ import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@RunWith(Parameterized.class) public final class IrisBiomeLayerSlopeSourceTest { - @Test - public void explicitSlopeStreamControlsSurfacePaletteSelection() { - assertExplicitSlopeStreamControlsSurfacePaletteSelection(false); + @Parameters(name = "lockLayers={0}") + public static Collection layerLocks() { + return List.of( + new Object[]{false}, + new Object[]{true} + ); + } + + private final boolean lockLayers; + + public IrisBiomeLayerSlopeSourceTest(boolean lockLayers) { + this.lockLayers = lockLayers; } @Test - public void explicitSlopeStreamControlsLockedSurfacePaletteSelection() { - assertExplicitSlopeStreamControlsSurfacePaletteSelection(true); - } - @SuppressWarnings("unchecked") - private static void assertExplicitSlopeStreamControlsSurfacePaletteSelection(boolean lockLayers) { + public void explicitSlopeStreamControlsSurfacePaletteSelection() { IrisData data = mock(IrisData.class); IrisComplex hostComplex = mock(IrisComplex.class); ProceduralStream hostSlope = mock(ProceduralStream.class); diff --git a/core/src/test/java/art/arcane/iris/engine/object/IrisStructureYBandTest.java b/core/src/test/java/art/arcane/iris/engine/object/IrisStructureYBandTest.java index 51ea7bf81..5ed7ded0f 100644 --- a/core/src/test/java/art/arcane/iris/engine/object/IrisStructureYBandTest.java +++ b/core/src/test/java/art/arcane/iris/engine/object/IrisStructureYBandTest.java @@ -3,51 +3,68 @@ package art.arcane.iris.engine.object; import art.arcane.iris.engine.object.annotations.MaxNumber; import art.arcane.iris.engine.object.annotations.MinNumber; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import java.lang.reflect.Field; +import java.util.Collection; +import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +@RunWith(Enclosed.class) public class IrisStructureYBandTest { - @Test - public void authoredBoundsResolveInOrder() { - IrisStructureYBand band = new IrisStructureYBand().setMin(-120).setMax(-20); + @RunWith(Parameterized.class) + public static class Resolution { + @Parameters(name = "min={0} max={1}") + public static Collection bands() { + return List.of( + new Object[]{-120, -20, -120, -20}, + new Object[]{-20, -120, -120, -20}, + new Object[]{-64, -64, -64, -64} + ); + } - assertEquals(-120, band.resolvedMin()); - assertEquals(-20, band.resolvedMax()); + private final int min; + private final int max; + private final int expectedMin; + private final int expectedMax; + + public Resolution(int min, int max, int expectedMin, int expectedMax) { + this.min = min; + this.max = max; + this.expectedMin = expectedMin; + this.expectedMax = expectedMax; + } + + @Test + public void authoredBoundsResolveInOrder() { + IrisStructureYBand band = new IrisStructureYBand().setMin(min).setMax(max); + + assertEquals(expectedMin, band.resolvedMin()); + assertEquals(expectedMax, band.resolvedMax()); + } } - @Test - public void reversedBoundsNormalizeInsteadOfInverting() { - IrisStructureYBand band = new IrisStructureYBand().setMin(-20).setMax(-120); + public static class SchemaBounds { + @Test + public void numericSchemaBoundsCoverTheWholeBuildRange() throws NoSuchFieldException { + assertBounds("min"); + assertBounds("max"); + } - assertEquals(-120, band.resolvedMin()); - assertEquals(-20, band.resolvedMax()); - } + private void assertBounds(String fieldName) throws NoSuchFieldException { + Field field = IrisStructureYBand.class.getDeclaredField(fieldName); + MinNumber minimum = field.getAnnotation(MinNumber.class); + MaxNumber maximum = field.getAnnotation(MaxNumber.class); - @Test - public void collapsedBoundsResolveToASingleY() { - IrisStructureYBand band = new IrisStructureYBand().setMin(-64).setMax(-64); - - assertEquals(-64, band.resolvedMin()); - assertEquals(-64, band.resolvedMax()); - } - - @Test - public void numericSchemaBoundsCoverTheWholeBuildRange() throws NoSuchFieldException { - assertBounds("min"); - assertBounds("max"); - } - - private void assertBounds(String fieldName) throws NoSuchFieldException { - Field field = IrisStructureYBand.class.getDeclaredField(fieldName); - MinNumber minimum = field.getAnnotation(MinNumber.class); - MaxNumber maximum = field.getAnnotation(MaxNumber.class); - - assertNotNull(minimum); - assertNotNull(maximum); - assertEquals(-4064D, minimum.value(), 0D); - assertEquals(4064D, maximum.value(), 0D); + assertNotNull(minimum); + assertNotNull(maximum); + assertEquals(-4064D, minimum.value(), 0D); + assertEquals(4064D, maximum.value(), 0D); + } } } diff --git a/core/src/test/java/art/arcane/iris/engine/object/IrisWorldIdentityTest.java b/core/src/test/java/art/arcane/iris/engine/object/IrisWorldIdentityTest.java index f98b260c6..991582ceb 100644 --- a/core/src/test/java/art/arcane/iris/engine/object/IrisWorldIdentityTest.java +++ b/core/src/test/java/art/arcane/iris/engine/object/IrisWorldIdentityTest.java @@ -1,25 +1,37 @@ package art.arcane.iris.engine.object; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import java.util.Collection; +import java.util.List; import static org.junit.Assert.assertEquals; +@RunWith(Parameterized.class) public class IrisWorldIdentityTest { - @Test - public void usesPlatformIdentity() { - IrisWorld world = IrisWorld.builder() - .platformIdentity("iris:bukkit") - .build(); + @Parameters(name = "{0}") + public static Collection identities() { + return List.of( + new Object[]{"iris:bukkit"}, + new Object[]{"minecraft:the_nether"} + ); + } - assertEquals("iris:bukkit", world.identity()); + private final String platformIdentity; + + public IrisWorldIdentityTest(String platformIdentity) { + this.platformIdentity = platformIdentity; } @Test - public void preservesModdedIdentity() { + public void preservesThePlatformIdentity() { IrisWorld world = IrisWorld.builder() - .platformIdentity("minecraft:the_nether") + .platformIdentity(platformIdentity) .build(); - assertEquals("minecraft:the_nether", world.identity()); + assertEquals(platformIdentity, world.identity()); } }