Cover untested contract surfaces

- Add a test source set to spi with bind, service registry and platform value contracts
- Prove the DataType probe contract, the ExternalDataProvider defaults and the string-only provider namespace claims
- Prove Identifier parsing and rendering
- Cover the data version, primitive and vector director handlers
- Cover the vanilla export identifier, block state, orientation, request and settings values
- Cover the structure adoption limits, diagnostics and result invariants
- Cover the pregen mantle backpressure, heap reclaim urgency, empty cache, listener defaults and diagnostic descriptions
This commit is contained in:
Brian Neumann-Fopiano
2026-09-08 05:27:49 -04:00
parent 71e3af727f
commit 290412b62a
21 changed files with 2030 additions and 0 deletions
+4
View File
@@ -11,6 +11,10 @@ java {
}
}
dependencies {
testImplementation('junit:junit:4.13.2')
}
tasks.named('jar', Jar).configure {
archiveBaseName.set('iris-spi')
}
@@ -0,0 +1,172 @@
package art.arcane.iris.spi;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class IrisPlatformsBindContractTest {
@Before
public void requireUnbound() {
IrisPlatforms.unbind();
}
@After
public void releaseBinding() {
IrisPlatforms.unbind();
}
@Test
public void unboundLookupsReportAbsenceInsteadOfImprovising() {
assertFalse(IrisPlatforms.isBound());
assertNull(IrisPlatforms.getOrNull());
IllegalStateException failure = assertThrows(IllegalStateException.class, IrisPlatforms::get);
assertTrue(failure.getMessage(), failure.getMessage().contains("No Iris platform is bound"));
}
@Test
public void bindingIsVisibleThroughEveryAccessor() {
IrisPlatform platform = new StubPlatform();
IrisPlatforms.bind(platform);
assertTrue(IrisPlatforms.isBound());
assertSame(platform, IrisPlatforms.get());
assertSame(platform, IrisPlatforms.getOrNull());
}
@Test
public void rebindingTheSameInstanceIsAccepted() {
IrisPlatform platform = new StubPlatform();
IrisPlatforms.bind(platform);
IrisPlatforms.bind(platform);
assertSame(platform, IrisPlatforms.get());
}
@Test
public void aSecondPlatformCannotDisplaceTheBoundOne() {
IrisPlatform first = new StubPlatform();
IrisPlatforms.bind(first);
IllegalStateException failure = assertThrows(
IllegalStateException.class, () -> IrisPlatforms.bind(new StubPlatform()));
assertTrue(failure.getMessage(), failure.getMessage().contains("already bound"));
assertSame(first, IrisPlatforms.get());
}
@Test
public void unbindIsIdempotentAndClearsTheBinding() {
IrisPlatforms.bind(new StubPlatform());
IrisPlatforms.unbind();
IrisPlatforms.unbind();
assertFalse(IrisPlatforms.isBound());
assertNull(IrisPlatforms.getOrNull());
}
@Test
public void unbindingClearsTheOnceKeysSoLaterRunsWarnAgain() {
IrisPlatforms.bind(new StubPlatform());
assertTrue(IrisLogging.warnOnce("spi-contract-once", "first"));
assertFalse(IrisLogging.warnOnce("spi-contract-once", "second"));
IrisPlatforms.unbind();
assertTrue(IrisLogging.warnOnce("spi-contract-once", "third"));
}
private static final class StubPlatform implements IrisPlatform {
@Override
public String platformName() {
return "stub";
}
@Override
public String minecraftVersion() {
return "26.2";
}
@Override
public PlatformRegistries registries() {
throw new UnsupportedOperationException();
}
@Override
public PlatformScheduler scheduler() {
throw new UnsupportedOperationException();
}
@Override
public PlatformStructureHooks structureHooks() {
throw new UnsupportedOperationException();
}
@Override
public PlatformBiomeWriter biomeWriter() {
throw new UnsupportedOperationException();
}
@Override
public File dataFolder() {
throw new UnsupportedOperationException();
}
@Override
public File dataFile(String... path) {
throw new UnsupportedOperationException();
}
@Override
public File pluginJar() {
throw new UnsupportedOperationException();
}
@Override
public int irisVersionNumber() {
return 0;
}
@Override
public int minecraftVersionNumber() {
return 0;
}
@Override
public void callEvent(Object event) {
}
@Override
public void dispatchConsoleCommand(String command) {
}
@Override
public boolean spawnEntity(PlatformWorld world, String entityKey, double x, double y, double z) {
return false;
}
@Override
public void log(LogLevel level, String message) {
}
@Override
public void msg(String message) {
}
@Override
public void reportError(Throwable error) {
}
}
}
@@ -0,0 +1,93 @@
package art.arcane.iris.spi;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class IrisServicesRegistryContractTest {
@Before
public void requireEmptyRegistry() {
IrisServices.clear();
}
@After
public void releaseRegistry() {
IrisServices.clear();
}
@Test
public void registeredServicesResolveThroughBothAccessors() {
Greeter greeter = new Greeter();
IrisServices.register(Greeter.class, greeter);
assertSame(greeter, IrisServices.get(Greeter.class));
assertSame(greeter, IrisServices.getOrNull(Greeter.class));
}
@Test
public void anAbsentServiceNamesItselfInTheFailure() {
assertNull(IrisServices.getOrNull(Greeter.class));
IllegalStateException failure = assertThrows(IllegalStateException.class, () -> IrisServices.get(Greeter.class));
assertTrue(failure.getMessage(), failure.getMessage().contains(Greeter.class.getName()));
}
@Test
public void reregisteringATypeReplacesThePreviousImplementation() {
Greeter first = new Greeter();
Greeter second = new Greeter();
IrisServices.register(Greeter.class, first);
IrisServices.register(Greeter.class, second);
assertSame(second, IrisServices.get(Greeter.class));
}
@Test
public void removingAServiceLeavesTheRegistryUsable() {
IrisServices.register(Greeter.class, new Greeter());
IrisServices.remove(Greeter.class);
IrisServices.remove(Greeter.class);
assertNull(IrisServices.getOrNull(Greeter.class));
}
@Test
public void clearDropsEveryRegistration() {
IrisServices.register(Greeter.class, new Greeter());
IrisServices.register(Counter.class, new Counter());
IrisServices.clear();
assertNull(IrisServices.getOrNull(Greeter.class));
assertNull(IrisServices.getOrNull(Counter.class));
}
@Test
public void aMismatchedImplementationIsRejectedBeforeItEntersTheRegistry() {
assertThrows(ClassCastException.class, () -> IrisServices.register(Greeter.class, new Counter()));
assertNull(IrisServices.getOrNull(Greeter.class));
}
@Test
public void aNullImplementationIsRejectedBeforeItEntersTheRegistry() {
assertThrows(NullPointerException.class, () -> IrisServices.register(Greeter.class, null));
assertNull(IrisServices.getOrNull(Greeter.class));
}
private static final class Greeter {
}
private static final class Counter {
}
}
@@ -0,0 +1,177 @@
package art.arcane.iris.spi;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class PlatformValueContractTest {
private static final String FINGERPRINT = "a".repeat(64);
@Test
public void jigsawMetadataAcceptsTheWholeDocumentedRange() {
PlatformStructureHooks.JigsawSourceMetadata smallest =
new PlatformStructureHooks.JigsawSourceMetadata(1, 0, 0);
PlatformStructureHooks.JigsawSourceMetadata largest =
new PlatformStructureHooks.JigsawSourceMetadata(128, 7, 96);
assertEquals(1, smallest.maxDistanceHorizontal());
assertEquals(128, largest.maxDistanceHorizontal());
assertEquals(7, largest.referenceExpansion());
assertEquals(96, largest.maxStartElementHorizontalSpan());
}
@Test
public void jigsawMetadataDefaultsTheStartElementSpanToZero() {
PlatformStructureHooks.JigsawSourceMetadata metadata =
new PlatformStructureHooks.JigsawSourceMetadata(64, 3);
assertEquals(0, metadata.maxStartElementHorizontalSpan());
}
@Test
public void jigsawMetadataRejectsOutOfRangeGeometry() {
assertThrows(IllegalArgumentException.class,
() -> new PlatformStructureHooks.JigsawSourceMetadata(0, 0, 0));
assertThrows(IllegalArgumentException.class,
() -> new PlatformStructureHooks.JigsawSourceMetadata(129, 0, 0));
assertThrows(IllegalArgumentException.class,
() -> new PlatformStructureHooks.JigsawSourceMetadata(64, -1, 0));
assertThrows(IllegalArgumentException.class,
() -> new PlatformStructureHooks.JigsawSourceMetadata(64, 0, -1));
}
@Test
public void unimplementedStructureHookDefaultsRefuseInsteadOfReturningNothing() {
PlatformStructureHooks hooks = new MinimalStructureHooks();
assertEquals(List.of(), hooks.jigsawStructureKeys());
assertEquals(List.of(), hooks.templatePoolKeys());
assertThrows(UnsupportedOperationException.class, () -> hooks.jigsawSourceMetadata("iris:village"));
assertThrows(UnsupportedOperationException.class, () -> hooks.templatePoolHorizontalSpan("iris:pool"));
assertThrows(UnsupportedOperationException.class,
() -> hooks.jigsawStartPoolHorizontalSpan("iris:village", "iris:pool"));
}
@Test
public void definitionFactoriesCarryTheirEncoding() {
PlatformGenerationRegistry.Definition json = PlatformGenerationRegistry.Definition.exactJson("{}");
PlatformGenerationRegistry.Definition identity =
PlatformGenerationRegistry.Definition.conservativeIdentity("abc");
assertEquals(PlatformGenerationRegistry.Encoding.JSON, json.encoding());
assertEquals("{}", json.value());
assertEquals(PlatformGenerationRegistry.Encoding.CONSERVATIVE_IDENTITY, identity.encoding());
assertEquals("abc", identity.value());
}
@Test
public void resourceIdentityTrimsItsPartsIntoAStableKey() {
PlatformGenerationRegistry.Definition definition =
PlatformGenerationRegistry.Definition.resourceIdentity(" worldgen/biome ", " iris:plains ");
assertEquals(PlatformGenerationRegistry.Encoding.CONSERVATIVE_IDENTITY, definition.encoding());
assertEquals("registry-resource-key-v1|worldgen/biome|iris:plains", definition.value());
}
@Test
public void definitionsRejectMissingAndBlankValues() {
assertThrows(NullPointerException.class,
() -> new PlatformGenerationRegistry.Definition(null, "value"));
assertThrows(NullPointerException.class,
() -> new PlatformGenerationRegistry.Definition(PlatformGenerationRegistry.Encoding.JSON, null));
assertThrows(IllegalArgumentException.class,
() -> new PlatformGenerationRegistry.Definition(PlatformGenerationRegistry.Encoding.JSON, " "));
assertThrows(IllegalArgumentException.class,
() -> PlatformGenerationRegistry.Definition.resourceIdentity(" ", "iris:plains"));
assertThrows(IllegalArgumentException.class,
() -> PlatformGenerationRegistry.Definition.resourceIdentity("worldgen/biome", " "));
}
@Test
public void customBiomeResourceKeysAreContentAddressed() {
assertEquals("iris:biomes/" + FINGERPRINT,
PlatformGenerationRegistry.contentAddressedCustomBiomeResourceKey(FINGERPRINT));
}
@Test
public void customBiomeResourceKeysRejectAnythingButALowercaseSha256() {
assertThrows(NullPointerException.class,
() -> PlatformGenerationRegistry.contentAddressedCustomBiomeResourceKey(null));
assertThrows(IllegalArgumentException.class,
() -> PlatformGenerationRegistry.contentAddressedCustomBiomeResourceKey(FINGERPRINT.toUpperCase()));
assertThrows(IllegalArgumentException.class,
() -> PlatformGenerationRegistry.contentAddressedCustomBiomeResourceKey("a".repeat(63)));
assertThrows(IllegalArgumentException.class,
() -> PlatformGenerationRegistry.contentAddressedCustomBiomeResourceKey("z".repeat(64)));
}
@Test
public void blockPropertiesReportWhetherTheyCarryANumericRange() {
PlatformNumericRange range = new PlatformNumericRange(0D, 15D, false, true);
PlatformBlockProperty numeric =
new PlatformBlockProperty("level", "integer", 0, List.of(0, 15), range);
PlatformBlockProperty enumerated =
new PlatformBlockProperty("axis", "string", "y", List.of("x", "y", "z"), null);
assertTrue(numeric.hasNumericRange());
assertEquals(range, numeric.numericRange());
assertEquals(0D, range.minimum(), 0D);
assertEquals(15D, range.maximum(), 0D);
assertFalse(range.exclusiveMinimum());
assertTrue(range.exclusiveMaximum());
assertFalse(enumerated.hasNumericRange());
assertEquals(List.of("x", "y", "z"), enumerated.allowedValues());
}
private static final class MinimalStructureHooks implements PlatformStructureHooks {
@Override
public List<String> structureKeys() {
return List.of();
}
@Override
public List<String> structureSetKeys() {
return List.of();
}
@Override
public List<String> structureBiomeKeys(String structureKey) {
return List.of();
}
@Override
public List<String> objectFeatureKeys() {
return List.of();
}
@Override
public List<String> reachableStructureKeys(PlatformWorld world) {
return List.of();
}
@Override
public List<String> possibleBiomeKeys(PlatformWorld world) {
return List.of();
}
@Override
public boolean placeFeature(PlatformWorld world, int x, int y, int z, String featureKey, long seed) {
return false;
}
@Override
public int[] placeStructure(PlatformWorld world, int chunkX, int chunkZ, String structureKey, long seed, int maxSpan) {
return new int[0];
}
@Override
public boolean supportsStructurePlacement() {
return false;
}
}
}