mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 13:30:08 +00:00
Retire source-text tests
- Delete 22 test classes whose assertions only read production .java text and check call ordering or literal presence - Remove 77 source-text assertion methods from 34 test classes that keep real behavioural coverage - Replace the core process-stream source grep with an ASM gate over compiled core classes in CoreProcessStreamPurityGateTest - Replace the packs-root source grep in PacksFolderContractTest with an ASM call-site gate over compiled core classes - Replace the IrisData registered-root regex in PackTypeBukkitPurityGateTest with an ASM scan of the registerLoader class constants - Trim six mixed tests down to their behavioural assertions and drop their source-text tails - Drop the eight iris.*Source and three iris.moddedCommonSources test system properties now that nothing reads them
This commit is contained in:
1 parent
7841efed54
commit
c75cfd387e
65 files changed
+245
-4273
No files matched your search
@@ -59,12 +59,4 @@ tasks.named('jar', Jar).configure {
|
||||
}
|
||||
|
||||
tasks.named('test').configure {
|
||||
systemProperty('iris.pregeneratorJobSource', rootProject.file('core/src/main/java/art/arcane/iris/core/gui/PregeneratorJob.java').absolutePath)
|
||||
systemProperty('iris.bukkitEnginePlatformHooksSource', file('src/main/java/art/arcane/iris/core/runtime/BukkitEnginePlatformHooks.java').absolutePath)
|
||||
systemProperty('iris.engineSvcSource', file('src/main/java/art/arcane/iris/core/service/IrisEngineSVC.java').absolutePath)
|
||||
systemProperty('iris.terrainSvcSource', file('src/main/java/art/arcane/iris/core/service/IrisTerrainSVC.java').absolutePath)
|
||||
systemProperty('iris.apiEventSvcSource', file('src/main/java/art/arcane/iris/core/service/IrisApiEventSVC.java').absolutePath)
|
||||
systemProperty('iris.worldInfoFactorySource', file('src/main/java/art/arcane/iris/core/service/terrain/IrisWorldInfoFactory.java').absolutePath)
|
||||
systemProperty('iris.startupSource', file('src/main/java/art/arcane/iris/Iris.java').absolutePath)
|
||||
systemProperty('iris.readmeSource', rootProject.file('README.md').absolutePath)
|
||||
}
|
||||
@@ -3,14 +3,10 @@ package art.arcane.iris;
|
||||
import art.arcane.iris.spi.LogLevel;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Core states a severity on every message it logs and the modded adapters honour it. Bukkit must preserve
|
||||
@@ -33,58 +29,4 @@ public class IrisDiagnosticLogLevelTest {
|
||||
public void lifecycleNoticesReachThePluginLoggerAtInfo() {
|
||||
assertEquals(Level.INFO, Iris.diagnosticLevel(LogLevel.NOTICE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adapterSideWarningsCarryTheSameSeverityAsCoreWarnings() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/art/arcane/iris/Iris.java")).replace("\r\n", "\n");
|
||||
|
||||
String warn = method(source, "public static void warn(String format, Object... objs)");
|
||||
assertTrue(warn, warn.contains("diagnostic(Level.WARNING"));
|
||||
assertFalse(warn, warn.contains("msg("));
|
||||
|
||||
String error = method(source, "public static void error(String format, Object... objs)");
|
||||
assertTrue(error, error.contains("diagnostic(Level.SEVERE"));
|
||||
assertFalse(error, error.contains("msg("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theCoreLogBridgeRoutesDiagnosticsToThePluginLogger() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/art/arcane/iris/Iris.java")).replace("\r\n", "\n");
|
||||
String bridge = method(source, "private static void bridgeLog(LogLevel level, String message)");
|
||||
|
||||
assertTrue(bridge, bridge.contains("diagnosticLevel(target)"));
|
||||
assertTrue(bridge, bridge.contains("diagnostic(diagnostic, message)"));
|
||||
String diagnostic = method(source, "private static void diagnostic(Level level, String message)");
|
||||
assertTrue(diagnostic, diagnostic.contains("ComponentLog.log("));
|
||||
assertTrue(diagnostic, diagnostic.contains("ComponentText.literal(line)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void informationalMessagesUseTheSharedComponentLogger() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/art/arcane/iris/Iris.java")).replace("\r\n", "\n");
|
||||
String message = method(source, "public static void msg(String string)");
|
||||
|
||||
assertTrue(message, message.contains("ComponentLog.logMarkup("));
|
||||
assertTrue(message, message.contains("logPrefix(plugin)"));
|
||||
assertFalse(message, message.contains("getSender().sendMessage"));
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
assertTrue("method not found: " + signature, start >= 0);
|
||||
int open = source.indexOf('{', start);
|
||||
int depth = 0;
|
||||
for (int i = open; i < source.length(); i++) {
|
||||
char c = source.charAt(i);
|
||||
if (c == '{') {
|
||||
depth++;
|
||||
} else if (c == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return source.substring(start, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new AssertionError("unterminated method: " + signature);
|
||||
}
|
||||
}
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
package art.arcane.iris.core;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IrisStartupOrderingTest {
|
||||
@Test
|
||||
public void admissionGateIsRegisteredBeforeStartupValidationBegins() throws Exception {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.startupSource")));
|
||||
String onEnable = section(source, "public void onEnable()", "public void onDisable()");
|
||||
|
||||
assertOrdered(onEnable,
|
||||
"IrisStartupValidation.begin();",
|
||||
"registerEvents(new IrisStartupAdmissionListener(), this);",
|
||||
"enable();");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalDatapacksValidateBeforeDimensionPacks() throws Exception {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.startupSource")));
|
||||
String enable = section(source, "private boolean enable()", "public void addShutdownHook()");
|
||||
|
||||
assertOrdered(enable,
|
||||
"DatapackIngestService.validateOnStartup();",
|
||||
"generatorResolver.validateAllPacks();");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalProvidersEnableBeforePackValidation() throws Exception {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.startupSource")));
|
||||
String enable = section(source, "private boolean enable()", "public void addShutdownHook()");
|
||||
|
||||
assertOrdered(enable,
|
||||
"service.onEnable();",
|
||||
"setContentChangeListener(generatorResolver::requestExternalContentRefresh)",
|
||||
"generatorResolver.validateAllPacks();");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restartRequiredStartupTerminatesAfterPluginInitialization() throws Exception {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.startupSource")));
|
||||
String onEnable = section(source, "public void onEnable()", "public void onDisable()");
|
||||
|
||||
assertOrdered(onEnable,
|
||||
"BukkitGuiHost.install();",
|
||||
"super.onEnable();",
|
||||
"IrisStartupValidation.isRestartRequired()",
|
||||
"ServerConfigurator.restartAtStartupBoundary(restartReason);");
|
||||
}
|
||||
|
||||
private static String section(String source, String startMarker, String endMarker) {
|
||||
int start = source.indexOf(startMarker);
|
||||
int end = source.indexOf(endMarker, start);
|
||||
assertTrue("Missing source section starting with " + startMarker, start >= 0);
|
||||
assertTrue("Missing source section ending with " + endMarker, end > start);
|
||||
return source.substring(start, end);
|
||||
}
|
||||
|
||||
private static void assertOrdered(String source, String... markers) {
|
||||
int previous = -1;
|
||||
for (String marker : markers) {
|
||||
int current = source.indexOf(marker);
|
||||
assertTrue("Missing source marker " + marker, current >= 0);
|
||||
assertTrue("Source marker is out of order: " + marker, current > previous);
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
-98
@@ -140,23 +140,6 @@ public class IrisWorldGeneratorResolverTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startupValidationPublishesFingerprintBoundExactRootResults() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java")).replace("\r\n", "\n");
|
||||
int validateAll = source.indexOf("public void validateAllPacks()");
|
||||
int snapshot = source.indexOf("ServerConfigurator.computePackContentSnapshot(packsRoot)", validateAll);
|
||||
int perPackFingerprint = source.indexOf("contentSnapshot.packContents()", snapshot);
|
||||
int exactRootPublish = source.indexOf(
|
||||
"PackValidationRegistry.publish(packDirectory.toPath(), result, packFingerprint)",
|
||||
perPackFingerprint);
|
||||
|
||||
assertTrue(validateAll >= 0);
|
||||
assertTrue(snapshot > validateAll);
|
||||
assertTrue(perPackFingerprint > snapshot);
|
||||
assertTrue(exactRootPublish > perPackFingerprint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paperStartupAliasResolvesToCanonicalRuntimeKey() throws Exception {
|
||||
File levelRoot = ownedLevelRoot("startup-alias", "moon");
|
||||
@@ -251,87 +234,6 @@ public class IrisWorldGeneratorResolverTest {
|
||||
return levelRoot;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuredWorldResolutionUsesOnlyActiveImmutableGenerationPack() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java")).replace("\r\n", "\n");
|
||||
int resolverStart = source.indexOf("private ChunkGenerator resolveFrozenWorldGenerator(");
|
||||
int resolverEnd = source.indexOf("private record FreshValidation", resolverStart);
|
||||
String resolver = source.substring(resolverStart, resolverEnd);
|
||||
|
||||
int dimensionRoot = resolver.indexOf("IrisWorldStorage.requireFrozenDimensionRoot(");
|
||||
int currentPlatformRoot = resolver.indexOf("WorldCreatorCompat.persistentDimensionRoot(worldKey)");
|
||||
int layoutRefusal = resolver.indexOf(
|
||||
"Frozen Iris world storage does not match the current platform layout",
|
||||
currentPlatformRoot
|
||||
);
|
||||
int history = resolver.indexOf("requireGenerationHistory(dimensionRoot, id, worldSeed)");
|
||||
int snapshotRoot = resolver.indexOf("requireActivePack(history)", history);
|
||||
int validation = resolver.indexOf("requireSnapshotLoadable(snapshotRoot)");
|
||||
int exactLoad = resolver.indexOf("requireHistoricalDimension(history, snapshotRoot, id)");
|
||||
int canonicalIdentity = resolver.indexOf(".platformIdentity(worldKey.toString())");
|
||||
int historicalSeed = resolver.indexOf(".seed(history.activeEpoch().worldSeed())");
|
||||
int resolvedStorage = resolver.indexOf(".worldFolder(dimensionRoot)");
|
||||
|
||||
assertTrue(dimensionRoot >= 0);
|
||||
assertTrue(currentPlatformRoot > dimensionRoot);
|
||||
assertTrue(layoutRefusal > currentPlatformRoot);
|
||||
assertTrue(history > layoutRefusal);
|
||||
assertTrue(snapshotRoot > history);
|
||||
assertTrue(validation > snapshotRoot);
|
||||
assertTrue(exactLoad > validation);
|
||||
assertTrue(canonicalIdentity > exactLoad);
|
||||
assertTrue(historicalSeed > canonicalIdentity);
|
||||
assertTrue(resolvedStorage > historicalSeed);
|
||||
assertFalse(resolver.contains("loadDimension("));
|
||||
assertFalse(resolver.contains("loadAnyDimension("));
|
||||
assertFalse(resolver.contains("replaceIntoWorld("));
|
||||
assertFalse(resolver.contains("installIntoWorld("));
|
||||
assertFalse(resolver.contains(".seed(1337)"));
|
||||
assertTrue(resolver.contains("GenerationHistory.openIfPresent(root, worldSeed)"));
|
||||
assertTrue(resolver.contains("GenerationHistory.adoptLegacyPack("));
|
||||
assertTrue(resolver.contains("GenerationRegistryContractFactory.captureRequiredDefinitions("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ownedWorldSnapshotFailureStopsStartupAndRethrows() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java")).replace("\r\n", "\n");
|
||||
int resolverStart = source.indexOf("public ChunkGenerator resolveDefaultWorldGenerator(");
|
||||
int resolverEnd = source.indexOf("private ChunkGenerator resolveFrozenWorldGenerator(", resolverStart);
|
||||
String resolver = source.substring(resolverStart, resolverEnd);
|
||||
|
||||
int plotSquaredProbe = resolver.indexOf("isPlotSquaredGeneratorDiscoveryProbe(worldName, id)");
|
||||
int probe = resolver.indexOf("isGeneratorDiscoveryProbe(worldName, id)", plotSquaredProbe);
|
||||
int denial = resolver.indexOf("IrisStartupValidation.denialReason()", probe);
|
||||
int failClosed = resolver.indexOf("IrisFailClosedChunkGenerator.startupLock(", denial);
|
||||
int staged = resolver.indexOf("WorldLifecycleStaging.consumeGenerator(worldName)", failClosed);
|
||||
int duplicateGuard = resolver.indexOf("requireWorldKeyAvailable(worldName, worldKey)");
|
||||
int ownership = resolver.indexOf("requireOwnedWorld(worldName, levelRoot, worldKey)");
|
||||
int frozen = resolver.indexOf("return resolveFrozenWorldGenerator(", ownership);
|
||||
int failureCapture = resolver.indexOf("catch (RuntimeException failure)", frozen);
|
||||
int report = resolver.indexOf("Iris.reportError(", failureCapture);
|
||||
int shutdown = resolver.indexOf("Bukkit.shutdown()", report);
|
||||
int rethrow = resolver.indexOf("throw failure", shutdown);
|
||||
|
||||
assertTrue(plotSquaredProbe >= 0);
|
||||
assertTrue(probe > plotSquaredProbe);
|
||||
assertTrue(denial > probe);
|
||||
assertTrue(failClosed > denial);
|
||||
assertTrue(staged > failClosed);
|
||||
assertTrue(duplicateGuard > staged);
|
||||
assertTrue(ownership > duplicateGuard);
|
||||
assertTrue(frozen > ownership);
|
||||
assertTrue(failureCapture > frozen);
|
||||
assertTrue(report > failureCapture);
|
||||
assertTrue(shutdown > report);
|
||||
assertTrue(rethrow > shutdown);
|
||||
|
||||
String shutdownScope = "the fail-fast shutdown must stay scoped to the frozen snapshot of an owned world";
|
||||
assertEquals(shutdownScope, resolverStart + shutdown, source.indexOf("Bukkit.shutdown()"));
|
||||
assertEquals(shutdownScope, resolverStart + shutdown, source.lastIndexOf("Bukkit.shutdown()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void plotSquaredDiscoveryProbeIsIgnoredQuietly() {
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package art.arcane.iris.core.commands;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public final class CommandDeveloperGenerationHistoryTest {
|
||||
@Test
|
||||
public void updateWorldStagesThePackWithTheLiveWorldSeed() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandDeveloper.java"
|
||||
)).replace("\r\n", "\n");
|
||||
int updateStart = source.indexOf("public void updateWorld(");
|
||||
int updateEnd = source.indexOf("@Director(description = \"Test\"", updateStart);
|
||||
String update = source.substring(updateStart, updateEnd);
|
||||
|
||||
assertTrue(update.contains(
|
||||
"replaceIntoWorld(sender(), pack, folder, world.getSeed())"
|
||||
));
|
||||
assertFalse(update.contains("iris/pack"));
|
||||
}
|
||||
}
|
||||
-24
@@ -7,8 +7,6 @@ import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -73,26 +71,4 @@ public class CommandIrisCreateOverwriteContractTest {
|
||||
assertEquals(Long.valueOf(Long.MAX_VALUE), handler.parse(Long.toString(Long.MAX_VALUE), false));
|
||||
assertThrows(DirectorParsingException.class, () -> handler.parse("9223372036854775808", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAndReplaceUseLocalizedStyledMissingDimensionFeedback() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandIris.java"
|
||||
)).replace("\r\n", "\n");
|
||||
|
||||
assertEquals(2, occurrences(source, "COMMAND_IRIS_DIMENSION_NOT_FOUND"));
|
||||
assertEquals(2, occurrences(source, "COMMAND_IRIS_INSTALL_PACK_AND_RESTART"));
|
||||
assertFalse(source.contains("sendMessage(\"Could not find dimension"));
|
||||
assertFalse(source.contains("sendMessage(\"Install its pack with"));
|
||||
}
|
||||
|
||||
private static int occurrences(String value, String match) {
|
||||
int count = 0;
|
||||
int offset = 0;
|
||||
while ((offset = value.indexOf(match, offset)) >= 0) {
|
||||
count++;
|
||||
offset += match.length();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
-17
@@ -5,13 +5,10 @@ import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -47,20 +44,6 @@ public class CommandIrisDownloadContractTest {
|
||||
assertThrows(Exception.class, () -> handler.parse("custom", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void commandDelegatesAcceptedDownloadsWithoutRawPreamble() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandIris.java"
|
||||
)).replace("\r\n", "\n");
|
||||
String download = method(source, "public void download(");
|
||||
|
||||
assertTrue(download.contains("downloadBuiltIn(sender(), builtInPack)"));
|
||||
assertTrue(download.contains("downloadUrl(sender(), directLink)"));
|
||||
assertFalse(download.contains("Downloading built-in Iris pack"));
|
||||
assertFalse(download.contains("Downloading Iris pack from"));
|
||||
assertFalse(download.contains("sendMessage(directLink"));
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
assertTrue(start >= 0);
|
||||
|
||||
-48
@@ -115,21 +115,6 @@ public class CommandJigsawContractTest {
|
||||
new IllegalStateException("Unexpected Studio failure")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void committedActivationStartsInitialEvaluationBeforePlayerBinding() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandJigsaw.java")).replace("\r\n", "\n");
|
||||
int commit = source.indexOf("JigsawStudioActivation.commit(staged)");
|
||||
int evaluation = source.indexOf(
|
||||
"studioService.activationCommitted(world, request.requestId())",
|
||||
commit);
|
||||
int binding = source.indexOf("PLAYER_PACKS.put", evaluation);
|
||||
|
||||
assertTrue(commit >= 0);
|
||||
assertTrue(evaluation > commit);
|
||||
assertTrue(binding > evaluation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertIsAddOnlyWorkflowWithAliasesAndDefaults() throws Exception {
|
||||
Method convert = CommandJigsaw.class.getDeclaredMethod(
|
||||
@@ -358,20 +343,6 @@ public class CommandJigsawContractTest {
|
||||
.getAnnotation(Director.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pieceCreateUsesResolvedWorkcellCapacityInsteadOfLayoutDefault() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandJigsaw.java")).replace("\r\n", "\n");
|
||||
int pieceCommands = source.indexOf("public static class CommandJigsawPiece");
|
||||
int create = source.indexOf("public void create(", pieceCommands);
|
||||
int add = source.indexOf("public void add(", create);
|
||||
String createSource = source.substring(create, add);
|
||||
|
||||
assertTrue(createSource.contains("targetWorkcell = contextual;"));
|
||||
assertTrue(createSource.contains("JigsawStudioCellDimensions dimensions = targetWorkcell.capacity();"));
|
||||
assertFalse(createSource.contains("layout().cellDimensions()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pieceAddUsesCanonicalAxesForRotatedRectangularPlanarWorkcells() {
|
||||
JigsawStudioLayout layout = nonuniformPlanarLayout();
|
||||
@@ -510,25 +481,6 @@ public class CommandJigsawContractTest {
|
||||
assertEquals(1, releases.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exportSourceAcquiresStudioLeaseBeforeStaticLeaseAndReleasesBothPaths() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandJigsaw.java")).replace("\r\n", "\n");
|
||||
int serviceLease = source.indexOf("studioService.tryBeginExport(requestId, playerId)");
|
||||
int staticLease = source.indexOf("beginExport(playerId, destination)", serviceLease);
|
||||
int dispatch = source.indexOf("J.a(() -> runExport(operation))", staticLease);
|
||||
int schedulingRelease = source.indexOf("operation.lease().release()", dispatch);
|
||||
int exporter = source.indexOf("new VanillaJigsawDatapackExporter().export(operation.request())", dispatch);
|
||||
int completionRelease = source.indexOf("operation.lease().release()", exporter);
|
||||
|
||||
assertTrue(serviceLease >= 0);
|
||||
assertTrue(staticLease > serviceLease);
|
||||
assertTrue(dispatch > staticLease);
|
||||
assertTrue(schedulingRelease > dispatch);
|
||||
assertTrue(exporter > schedulingRelease);
|
||||
assertTrue(completionRelease > exporter);
|
||||
}
|
||||
|
||||
private static void assertCommand(String name, Class<?>... parameterTypes) throws Exception {
|
||||
Method method = CommandJigsaw.class.getDeclaredMethod(name, parameterTypes);
|
||||
assertNotNull(method.getAnnotation(Director.class));
|
||||
|
||||
-16
@@ -7,8 +7,6 @@ import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
@@ -212,20 +210,6 @@ public class IrisPapiExpansionTest {
|
||||
assertTrue(expansion.persist());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theReadmeDocumentsEveryPublishedKeyAndEveryRetiredOne() throws Exception {
|
||||
String readme = Files.readString(Path.of(System.getProperty("iris.readmeSource")));
|
||||
|
||||
for (String key : PUBLISHED_KEYS) {
|
||||
assertTrue("README must document %iris_" + key + "%", readme.contains("%iris_" + key + "%"));
|
||||
}
|
||||
|
||||
for (String retired : RETIRED_KEYS) {
|
||||
assertTrue("README must carry the migration row for %iris_" + retired + "%",
|
||||
readme.contains("%iris_" + retired + "%"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theTerrainServiceIsTheOnlyDoorIntoIris() {
|
||||
IrisTerrainService service = new FakeIrisTerrainService();
|
||||
|
||||
-137
@@ -1,137 +0,0 @@
|
||||
package art.arcane.iris.core.link;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IrisPapiLifecycleTest {
|
||||
private static final Path PLUGIN_SOURCE = Path.of("src/main/java/art/arcane/iris/Iris.java");
|
||||
private static final String SETUP = "private void setupPapi() {";
|
||||
private static final String TEARDOWN = "private void teardownPapi() {";
|
||||
|
||||
private static String source() throws Exception {
|
||||
// The assertions below match against literals written with \n, so a CRLF checkout has to
|
||||
// be folded first or every multi-line expectation misses.
|
||||
return Files.readString(PLUGIN_SOURCE).replace("\r\n", "\n");
|
||||
}
|
||||
|
||||
private static String body(String declaration) throws Exception {
|
||||
String source = source();
|
||||
int start = source.indexOf(declaration);
|
||||
|
||||
assertTrue("Iris.java must declare " + declaration, start >= 0);
|
||||
|
||||
int open = source.indexOf('{', start);
|
||||
int depth = 0;
|
||||
|
||||
for (int index = open; index < source.length(); index++) {
|
||||
char character = source.charAt(index);
|
||||
|
||||
if (character == '{') {
|
||||
depth++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (character != '}') {
|
||||
continue;
|
||||
}
|
||||
|
||||
depth--;
|
||||
|
||||
if (depth == 0) {
|
||||
return source.substring(open + 1, index);
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError(declaration + " is not brace balanced");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registrationIsGatedOnPlaceholderApiBeingEnabled() throws Exception {
|
||||
assertTrue("setupPapi must bail out when PlaceholderAPI is absent",
|
||||
body(SETUP).contains("if (!PlaceholderRegistration.isPlaceholderApiEnabled()) {"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theRegistrationTheListenerAndTheStateAreAllRetained() throws Exception {
|
||||
String source = source();
|
||||
|
||||
assertTrue(source.contains("private volatile PlaceholderRegistration papiRegistration;"));
|
||||
assertTrue(source.contains("private volatile IrisPapiListener papiListener;"));
|
||||
assertTrue(source.contains("private volatile IrisPapiState papiState;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void teardownUnregistersTheExpansionTheListenerAndClearsTheState() throws Exception {
|
||||
String teardown = body(TEARDOWN);
|
||||
|
||||
assertTrue("the retained registration must be unregistered inside teardownPapi",
|
||||
teardown.contains("registration.unregister();"));
|
||||
assertTrue("the retained listener must be detached inside teardownPapi",
|
||||
teardown.contains("HandlerList.unregisterAll(listener);"));
|
||||
assertTrue("the retained state must drop every held world reference inside teardownPapi",
|
||||
teardown.contains("state.clear();"));
|
||||
assertTrue("teardownPapi must drop the retained listener", teardown.contains("papiListener = null;"));
|
||||
assertTrue("teardownPapi must drop the retained registration", teardown.contains("papiRegistration = null;"));
|
||||
assertTrue("teardownPapi must drop the retained state", teardown.contains("papiState = null;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bothDisablePathsTearThePlaceholderSurfaceDown() throws Exception {
|
||||
String disable = body("public void onDisable() {");
|
||||
String preUnload = body("public void onPreUnload(ReloadAware.PreUnloadReason reason) {");
|
||||
int disableTeardown = disable.indexOf("teardownPapi();");
|
||||
int preUnloadTeardown = preUnload.indexOf("teardownPapi();");
|
||||
|
||||
assertTrue("onDisable must tear the expansion down before branching into runtime shutdown",
|
||||
disableTeardown >= 0 && disableTeardown < disable.indexOf("IrisToolbelt.isServerStopping()"));
|
||||
assertTrue("the BileTools pre-unload hook must tear the expansion down before any shutdown branch",
|
||||
preUnloadTeardown >= 0 && preUnloadTeardown < preUnload.indexOf("IrisToolbelt.isServerStopping()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aFailedListenerAttachDoesNotLeaveTheExpansionRegistered() throws Exception {
|
||||
String setup = body(SETUP);
|
||||
int attach = setup.indexOf("registerEvents(listener, this)");
|
||||
|
||||
assertTrue("the listener must be attached inside setupPapi", attach >= 0);
|
||||
|
||||
int rescue = setup.indexOf("} catch (Throwable failure) {", attach);
|
||||
|
||||
assertTrue("the attach must be guarded inside setupPapi", rescue > attach);
|
||||
|
||||
int rollback = setup.indexOf("registration.unregister();", rescue);
|
||||
|
||||
assertTrue("a failed attach must roll the registration back inside setupPapi", rollback > rescue);
|
||||
|
||||
int bail = setup.indexOf("return;", rollback);
|
||||
|
||||
assertTrue("a failed attach must leave setupPapi", bail > rollback);
|
||||
|
||||
int retained = setup.indexOf("papiRegistration = registration;");
|
||||
|
||||
assertTrue("setupPapi must retain the registration", retained > 0);
|
||||
assertTrue("the registration may only be retained after a successful attach", retained > bail);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theExpansionIsNeverConstructedFromAPluginStatic() throws Exception {
|
||||
String setup = body(SETUP);
|
||||
|
||||
assertFalse("the plugin class must not construct the expansion: that forces PlaceholderExpansion to load during enable and crashes a server without PlaceholderAPI",
|
||||
setup.contains("new IrisPapiExpansion("));
|
||||
assertTrue("the expansion takes its state as a constructor argument, built inside the installer",
|
||||
installerSource().contains("new IrisPapiExpansion(state, logger)"));
|
||||
assertFalse("the hand rolled PlaceholderAPI presence check must be gone",
|
||||
source().contains("isPluginEnabled(\"PlaceholderAPI\")"));
|
||||
}
|
||||
|
||||
private static String installerSource() throws Exception {
|
||||
return java.nio.file.Files.readString(java.nio.file.Path.of(
|
||||
"src/main/java/art/arcane/iris/core/link/IrisPapiInstaller.java")).replace("\r\n", "\n");
|
||||
}
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
package art.arcane.iris.core.runtime;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class StudioPlayerModeContractTest {
|
||||
@Test
|
||||
public void autoStartedStudioUsesSpectatorMode() throws IOException {
|
||||
String plugin = Files.readString(Path.of("src/main/java/art/arcane/iris/Iris.java")).replace("\r\n", "\n");
|
||||
String commands = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandStudio.java")).replace("\r\n", "\n");
|
||||
|
||||
assertFalse(plugin.contains("GameMode.CREATIVE"));
|
||||
assertFalse(commands.contains("GameMode.CREATIVE"));
|
||||
assertTrue(plugin.contains("GameMode.SPECTATOR"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tpStudioUsesThePreparedCoordinatorEntry() throws IOException {
|
||||
String commands = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandStudio.java")).replace("\r\n", "\n");
|
||||
int methodStart = commands.indexOf("public void tpstudio()");
|
||||
int methodEnd = commands.indexOf("\n @Director", methodStart);
|
||||
String method = commands.substring(methodStart, methodEnd);
|
||||
|
||||
assertTrue(method.contains("StudioSVC studioService = Iris.service(StudioSVC.class)"));
|
||||
assertTrue(method.contains("studioService.teleportToActiveProject(player)"));
|
||||
assertFalse(method.contains("setGameMode("));
|
||||
assertFalse(method.contains("getActiveProject()"));
|
||||
assertFalse(method.contains("BukkitPlatform.teleportAsync"));
|
||||
assertFalse(method.contains("BukkitWorldBinding.spawnLocation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void editingStudiosRemainCreative() throws IOException {
|
||||
String objectCommands = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandObject.java")).replace("\r\n", "\n");
|
||||
String jigsawCommands = Files.readString(Path.of(
|
||||
"src/main/java/art/arcane/iris/core/commands/CommandJigsaw.java")).replace("\r\n", "\n");
|
||||
|
||||
assertTrue(objectCommands.contains("GameMode.CREATIVE"));
|
||||
assertTrue(objectCommands.contains("StudioOpenCoordinator.StudioOpenKind.OBJECT"));
|
||||
assertTrue(jigsawCommands.contains("GameMode.CREATIVE"));
|
||||
assertFalse(objectCommands.contains("GameMode.SPECTATOR"));
|
||||
assertFalse(jigsawCommands.contains("GameMode.SPECTATOR"));
|
||||
}
|
||||
}
|
||||
-195
@@ -1,195 +0,0 @@
|
||||
package art.arcane.iris.core.service;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class IrisApiWiringContractTest {
|
||||
@Test
|
||||
public void theTerrainServiceRegistersOnBothRegistriesAndReleasesBoth() throws IOException {
|
||||
String source = source("iris.terrainSvcSource");
|
||||
String onEnable = method(source, "public void onEnable()");
|
||||
String onDisable = method(source, "public void onDisable()");
|
||||
|
||||
assertTrue(onEnable.contains("Bukkit.getServicesManager().register("));
|
||||
assertTrue(onEnable.contains("IrisTerrainService.class"));
|
||||
assertTrue(onEnable.contains("IrisServices.register(IrisTerrainService.class, this)"));
|
||||
assertTrue(onDisable.contains("Bukkit.getServicesManager().unregister(IrisTerrainService.class, this)"));
|
||||
assertTrue(onDisable.contains("IrisServices.remove(IrisTerrainService.class)"));
|
||||
assertBefore(onDisable, "serviceEnabled.set(false)", "Bukkit.getServicesManager().unregister(");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theTerrainServiceNeverForcesEngineInitialisationOrLoadsTheMantle() throws IOException {
|
||||
String source = source("iris.terrainSvcSource");
|
||||
|
||||
assertFalse("isIrisWorld must not touch the generator", source.contains("IrisToolbelt"));
|
||||
assertFalse("isIrisWorld must not touch the generator", source.contains(".touch("));
|
||||
assertFalse("terrain queries must not load mantle chunks", source.contains("getMantle()"));
|
||||
assertFalse("terrain queries must not load mantle chunks", source.contains("getObjectsAt("));
|
||||
assertFalse("terrain queries must not load mantle chunks", source.contains("getPOIsAt("));
|
||||
assertFalse("terrain queries must not load mantle chunks", source.contains("getCaveOrMantleBiome("));
|
||||
assertFalse("terrain queries must never block", source.contains(".join()"));
|
||||
assertFalse("terrain queries must never block", source.contains("synchronized"));
|
||||
assertFalse("terrain queries must never block", source.contains("J.sfut("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sampleColumnsBoundsTheQueryBeforeItWalksAndTreatsAThrowingSinkAsARefusal() throws IOException {
|
||||
String sampleColumns = method(source("iris.terrainSvcSource"),
|
||||
"public boolean sampleColumns(World world, IrisColumnQuery query, IrisColumnSink sink)");
|
||||
|
||||
assertBefore(sampleColumns, "IrisSampleLimits.withinLimits(", "IrisColumnWalk.walk(");
|
||||
assertBefore(sampleColumns, "IrisColumnWalk.walk(", "catch (Throwable error)");
|
||||
assertTrue(sampleColumns.contains("reportSinkFault(world, error)"));
|
||||
assertTrue(sampleColumns.contains("return false;"));
|
||||
assertTrue("the walk must abort when the engine closes underneath it",
|
||||
sampleColumns.contains("engine.isClosed()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thePregeneratorDispatchesPhasesFromItsExistingTickAndNeverBlocksOnTheSink() throws IOException {
|
||||
String source = source("iris.pregeneratorJobSource");
|
||||
String dispatch = method(source, "private void dispatchApiPhases(List<PregenApiPhase> phases)");
|
||||
|
||||
assertTrue(dispatch.contains("IrisServices.getOrNull(PregenApiSink.class)"));
|
||||
assertTrue(dispatch.contains("catch (Throwable error)"));
|
||||
assertBefore(dispatch, "sink.pregen(phase, progress)", "catch (Throwable error)");
|
||||
assertFalse(dispatch.contains(".join()"));
|
||||
|
||||
assertTrue(method(source, "public void onTick(").contains("dispatchApiPhases(apiPhases.onTick(paused()))"));
|
||||
assertTrue(method(source, "public void onSaving()").contains("dispatchApiPhases(apiPhases.onSaving())"));
|
||||
assertTrue(method(source, "public void onClose()").contains("dispatchApiPhases(apiPhases.onClose(reachedTotal()))"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worldPhasesAreFiredOutsideTheRegistrationLock() throws IOException {
|
||||
String source = source("iris.engineSvcSource");
|
||||
|
||||
String add = method(source, "private void add(World world)");
|
||||
assertBefore(add, "catch (RejectedExecutionException exception)", "phases.ready(world)");
|
||||
assertBefore(add, "registered = true;", "phases.ready(world)");
|
||||
|
||||
String remove = method(source,
|
||||
"private boolean remove(World world, CompletionStage<Boolean> unloadBoundary)");
|
||||
assertBefore(remove, "registered = worlds.remove(world)", "phases.closing(world)");
|
||||
assertBefore(remove, "phases.closing(world)",
|
||||
"deferCloseUntilWorldUnload(world, registered, closing, unloadBoundary)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everyRegisteredWorldIsAnnouncedClosingWhenTheServiceShutsDown() throws IOException {
|
||||
String onDisable = method(source("iris.engineSvcSource"), "public void onDisable()");
|
||||
|
||||
assertTrue("service shutdown must announce ENGINE_CLOSING for every registered world",
|
||||
onDisable.contains("phases.closing(teardown.world())"));
|
||||
assertBefore(onDisable, "worlds.clear()", "phases.closing(teardown.world())");
|
||||
assertBefore(onDisable, "phases.closing(teardown.world())", "shutdownAndDrain(activeService)");
|
||||
assertBefore(onDisable, "phases.closing(teardown.world())",
|
||||
"startClose(teardown.registered(), teardown.closing())");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aReplacedEngineIsAnnouncedClosingBeforeTheRetryReRegistersTheWorld() throws IOException {
|
||||
String add = method(source("iris.engineSvcSource"), "private void add(World world)");
|
||||
|
||||
assertBefore(add, "catch (RejectedExecutionException exception)", "phases.closing(world)");
|
||||
assertBefore(add, "phases.closing(world)", "retryRegistrationAfterClose(world, retryAfter)");
|
||||
assertBefore(add, "phases.closing(world)", "startClose(replaced, replacementClose)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aWorldPhaseIsNeverConditionalOnAnotherServicesRegistration() throws IOException {
|
||||
String source = source("iris.apiEventSvcSource");
|
||||
String fire = method(source, "public static void fireWorldPhase(World world, IrisWorldPhase phase)");
|
||||
|
||||
assertFalse("world lifecycle must not resolve a swappable service to build its payload",
|
||||
fire.contains("IrisServices"));
|
||||
assertFalse("world lifecycle must not resolve a swappable service to build its payload",
|
||||
fire.contains("IrisTerrainService"));
|
||||
assertTrue(fire.contains("deliver(new IrisWorldEngineEvent(world, phase, describe(world, phase)))"));
|
||||
|
||||
String describe = method(source, "private static IrisWorldInfo describe(World world, IrisWorldPhase phase)");
|
||||
assertTrue(describe.contains("IrisWorldInfoFactory.forWorld(world)"));
|
||||
assertTrue("an undescribable world must be reported, not swallowed",
|
||||
describe.contains("IrisLogging.reportError("));
|
||||
assertTrue("an undescribable world must still deliver the phase", describe.contains("return null;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aWorldPhaseRaisedFromAServerThreadIsDeliveredBeforeThatThreadMovesOn() throws IOException {
|
||||
String deliver = method(source("iris.apiEventSvcSource"), "private static void deliver(Event event)");
|
||||
|
||||
assertBefore(deliver, "Bukkit.isPrimaryThread()", "Bukkit.getPluginManager().callEvent(event)");
|
||||
assertBefore(deliver, "Bukkit.getPluginManager().callEvent(event)", "Iris.callEvent(event)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theWorldInfoFactoryNeverForcesEngineInitialisationOrLoadsTheMantle() throws IOException {
|
||||
String source = source("iris.worldInfoFactorySource");
|
||||
|
||||
assertFalse("the factory must not touch the generator", source.contains("IrisToolbelt"));
|
||||
assertFalse("the factory must not touch the generator", source.contains(".touch("));
|
||||
assertFalse("the factory must not load mantle chunks", source.contains("getMantle()"));
|
||||
assertFalse("the factory must never block", source.contains(".join()"));
|
||||
assertFalse("the factory must never block", source.contains("synchronized"));
|
||||
assertTrue("the factory must refuse a closed engine", source.contains("engine.isClosed()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theHotloadHookStillFiresTheLegacyEventAlongsideTheApiEvent() throws IOException {
|
||||
String hook = method(source("iris.bukkitEnginePlatformHooksSource"), "public void fireHotloadEvent(Engine engine)");
|
||||
|
||||
assertBefore(hook, "new IrisEngineHotloadEvent(engine)",
|
||||
"IrisApiEventSVC.fireWorldPhase(BukkitWorldBinding.world(engine.getWorld()), IrisWorldPhase.ENGINE_HOTLOADED)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theEventServiceNeverLetsAThirdPartyFailureEscapeALifecyclePath() throws IOException {
|
||||
String fire = method(source("iris.apiEventSvcSource"),
|
||||
"public static void fireWorldPhase(World world, IrisWorldPhase phase)");
|
||||
|
||||
assertTrue(fire.contains("catch (Throwable error)"));
|
||||
assertTrue(fire.contains("IrisLogging.reportError("));
|
||||
assertFalse(fire.contains("printStackTrace"));
|
||||
}
|
||||
|
||||
private static String source(String property) throws IOException {
|
||||
String path = System.getProperty(property);
|
||||
assertTrue("missing source property " + property, path != null && !path.isBlank());
|
||||
return Files.readString(Path.of(path));
|
||||
}
|
||||
|
||||
private static void assertBefore(String source, String first, String second) {
|
||||
int firstIndex = source.indexOf(first);
|
||||
int secondIndex = source.indexOf(second);
|
||||
assertTrue("Missing source contract token: " + first, firstIndex >= 0);
|
||||
assertTrue("Missing source contract token: " + second, secondIndex >= 0);
|
||||
assertTrue(first + " must occur before " + second, firstIndex < secondIndex);
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
assertTrue("Missing source contract signature: " + signature, start >= 0);
|
||||
int openBrace = source.indexOf('{', start);
|
||||
assertTrue("Missing source contract method body: " + signature, openBrace >= 0);
|
||||
int depth = 0;
|
||||
for (int index = openBrace; index < source.length(); index++) {
|
||||
char current = source.charAt(index);
|
||||
if (current == '{') {
|
||||
depth++;
|
||||
} else if (current == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return source.substring(start, index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unclosed source contract method: " + signature);
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,6 @@ tasks.named('compileJava', JavaCompile).configure {
|
||||
}
|
||||
|
||||
tasks.named('test').configure {
|
||||
systemProperty('iris.moddedCommonSources', file('../modded-common/src/main/java').absolutePath)
|
||||
}
|
||||
|
||||
loom {
|
||||
|
||||
@@ -240,7 +240,6 @@ tasks.named('compileJava', JavaCompile).configure {
|
||||
}
|
||||
|
||||
tasks.named('test').configure {
|
||||
systemProperty('iris.moddedCommonSources', file('../modded-common/src/main/java').absolutePath)
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
||||
+3
-9
@@ -73,15 +73,9 @@ public class IrisModLanguageAssetsTest {
|
||||
|
||||
private Set<String> resourceFiles() throws Exception {
|
||||
URL resource = IrisModLanguageAssetsTest.class.getClassLoader().getResource(ROOT);
|
||||
Path directory;
|
||||
if (resource != null && "file".equals(resource.getProtocol())) {
|
||||
directory = Path.of(resource.toURI());
|
||||
} else {
|
||||
String sources = System.getProperty("iris.moddedCommonSources");
|
||||
assertNotNull("Missing mod language resource directory and source root", sources);
|
||||
directory = Path.of(sources).getParent()
|
||||
.resolve("resources").resolve(ROOT);
|
||||
}
|
||||
assertNotNull("Missing mod language resource directory: " + ROOT, resource);
|
||||
assertEquals("Mod language resources must resolve to a directory on disk", "file", resource.getProtocol());
|
||||
Path directory = Path.of(resource.toURI());
|
||||
try (Stream<Path> paths = Files.list(directory)) {
|
||||
return paths
|
||||
.filter(Files::isRegularFile)
|
||||
|
||||
-21
@@ -9,13 +9,9 @@ import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.IOException;
|
||||
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 IrisModdedChunkGeneratorSpawnTest {
|
||||
@BeforeClass
|
||||
@@ -48,21 +44,4 @@ public class IrisModdedChunkGeneratorSpawnTest {
|
||||
assertEquals(explicitCow, entries.get(2).value());
|
||||
assertEquals(3, entries.get(2).weight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vanillaChunkGenerationMobsUseTheVisibleBiomesVanillaDerivative() throws IOException {
|
||||
Path sourcePath = Path.of(System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/IrisModdedChunkGenerator.java");
|
||||
String source = Files.readString(sourcePath);
|
||||
int spawnStart = source.indexOf("public void spawnOriginalMobs");
|
||||
int spawnEnd = source.indexOf("@Override", spawnStart + 1);
|
||||
String spawn = source.substring(spawnStart, spawnEnd);
|
||||
|
||||
assertTrue(spawn.contains("spawnTables.initializeVanillaSpawnBiomes(registry)"));
|
||||
assertTrue(spawn.contains("structureBiomeSource.getVisibleSurfaceBiome("));
|
||||
assertTrue(spawn.contains("spawnTables.vanillaSpawnBiome(visibleBiome.value())"));
|
||||
assertTrue(spawn.contains("NaturalSpawner.spawnMobsForChunkGeneration("));
|
||||
assertTrue(spawn.contains("new LegacyRandomSource(RandomSupport.generateUniqueSeed())"));
|
||||
assertTrue(spawn.contains("random.setDecorationSeed(region.getSeed()"));
|
||||
}
|
||||
}
|
||||
+2
-153
@@ -14,9 +14,6 @@ import net.minecraft.server.Bootstrap;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
@@ -64,16 +61,10 @@ public class IrisModdedStructureParityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void strongholdRingSearchSamplesOneQuartColumnPerChunk() throws IOException {
|
||||
public void strongholdRingSearchSamplesOneQuartColumnPerChunk() {
|
||||
assertEquals(4, IrisModdedBiomeSource.horizontalBiomeSearchQuartStep(0, 112));
|
||||
assertEquals(1, IrisModdedBiomeSource.horizontalBiomeSearchQuartStep(1, 112));
|
||||
assertEquals(1, IrisModdedBiomeSource.horizontalBiomeSearchQuartStep(0, 111));
|
||||
String source = Files.readString(Path.of(
|
||||
System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/IrisModdedBiomeSource.java"));
|
||||
assertTrue(source.contains("x, y, z, searchRadius, quartStep, allowed, random, false, sampler"));
|
||||
assertTrue(source.contains(
|
||||
"return super.findBiomeHorizontal(x, y, z, searchRadius, allowed, random, sampler)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -130,126 +121,12 @@ public class IrisModdedStructureParityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void visibleBiomeResolutionSelectsStackOwnershipBeforeHostCaves() throws IOException {
|
||||
String source = Files.readString(Path.of(
|
||||
System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/IrisModdedBiomeSource.java"));
|
||||
int resolutionStart = source.indexOf("private BiomeResolution resolveBiomeResolution(");
|
||||
int resolutionEnd = source.indexOf("private Holder<Biome> resolveRequiredStructureBiome(", resolutionStart);
|
||||
|
||||
assertTrue(resolutionStart >= 0);
|
||||
assertTrue(resolutionEnd > resolutionStart);
|
||||
String resolution = source.substring(resolutionStart, resolutionEnd);
|
||||
|
||||
assertTrue(resolution.contains("resolveDimensionStackLayer("));
|
||||
assertTrue(resolution.contains("!stackLayer.terrainContext().isSelfReferencing()"));
|
||||
assertTrue(resolution.indexOf("resolveDimensionStackLayer(")
|
||||
< resolution.indexOf("boolean underground"));
|
||||
assertTrue(resolution.contains("includeDimensionStack"));
|
||||
assertTrue(resolution.contains(
|
||||
"return resolveBiomeResolution(engine, quartX, quartY, quartZ, false)"));
|
||||
assertTrue(source.contains("resolution.packName(), resolution.dimension(), customBiome.getId()"));
|
||||
int helperStart = source.indexOf("private static IrisBiome resolveSurfaceStructureBiome(");
|
||||
int helperEnd = source.indexOf("private static Set<String> registeredBiomeKeys(", helperStart);
|
||||
String helper = source.substring(helperStart, helperEnd);
|
||||
assertTrue(helper.contains("engine.getComplex().getTrueBiomeStream().get(blockX, blockZ)"));
|
||||
assertFalse(helper.contains("getDimensionStackContext()"));
|
||||
assertFalse(helper.contains("getSurfaceBiome("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stackBiomesAreVisibleButExcludedFromStructureReachability() throws IOException {
|
||||
String source = Files.readString(Path.of(
|
||||
System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/IrisModdedBiomeSource.java"));
|
||||
|
||||
assertTrue(source.contains("return biomeKeySets().structureRequired()"));
|
||||
assertTrue(source.contains("generatedBiomeKeys.addAll(keys.visibleRequired())"));
|
||||
assertTrue(source.contains("collectStructureBiomeKeys("));
|
||||
assertTrue(source.contains("dimension.getReachableBiomes(() -> data)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void biomeLocatorSearchesTheVisibleStack() throws IOException {
|
||||
String source = Files.readString(Path.of(
|
||||
System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/IrisModdedBiomeSource.java"));
|
||||
int start = source.indexOf("public Pair<BlockPos, Holder<Biome>> findClosestBiome3d(");
|
||||
int end = source.indexOf("private Holder<Biome> getNoiseBiome(", start);
|
||||
String method = source.substring(start, end);
|
||||
|
||||
assertTrue(method.contains("modded_locate_visible_biome"));
|
||||
assertTrue(method.contains("return super.findClosestBiome3d("));
|
||||
assertTrue(method.contains("collectVisibleBiomeHolders()"));
|
||||
assertTrue(method.contains("QuartPos.toBlock(quartX), QuartPos.toBlock(quartZ)"));
|
||||
assertTrue(method.contains("resolveVisibleBiome("));
|
||||
assertFalse(method.contains("Holder<Biome> structureBiome = getNoiseBiome("));
|
||||
assertTrue(method.indexOf("tryAcquireGenerationLease(engine, \"modded_locate_visible_biome\")")
|
||||
< method.indexOf("engine.getDimensionStackContext()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void surfaceSpawnBiomeUsesTheVisibleQuartCell() throws IOException {
|
||||
String source = Files.readString(Path.of(
|
||||
System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/IrisModdedBiomeSource.java"));
|
||||
int start = source.indexOf("Holder<Biome> getVisibleSurfaceBiome(");
|
||||
int end = source.indexOf("boolean isStructureReachable(", start);
|
||||
String method = source.substring(start, end);
|
||||
|
||||
assertTrue(method.contains("QuartPos.fromBlock(blockX)"));
|
||||
assertTrue(method.contains("QuartPos.toBlock(quartX)"));
|
||||
assertTrue(method.contains("QuartPos.fromBlock(internalY + engine.getMinHeight())"));
|
||||
assertTrue(method.contains("stackContext.getLayout(sampleX, sampleZ).surfaceLayer()"));
|
||||
assertTrue(method.contains("visibleBiomeCache"));
|
||||
assertTrue(method.contains("isBiomeCacheable(engine, sampleX, sampleZ)"));
|
||||
assertTrue(method.indexOf("boolean cacheable = isBiomeCacheable(engine, sampleX, sampleZ)")
|
||||
< method.indexOf("Engine.hostHeight(engine, sampleX, sampleZ, true)"));
|
||||
assertCacheGuarded(method, "visibleBiomeCache");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void temporaryNaturalBiomeAnswersAreNotMemoized() throws IOException {
|
||||
public void temporaryNaturalBiomeAnswersAreNotMemoized() {
|
||||
Engine engine = mock(Engine.class);
|
||||
when(engine.answersFromNaturalTerrain(12, -8)).thenReturn(true);
|
||||
assertFalse(IrisModdedBiomeSource.isBiomeCacheable(engine, 12, -8));
|
||||
when(engine.answersFromNaturalTerrain(12, -8)).thenReturn(false);
|
||||
assertTrue(IrisModdedBiomeSource.isBiomeCacheable(engine, 12, -8));
|
||||
|
||||
String source = Files.readString(Path.of(
|
||||
System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/IrisModdedBiomeSource.java"));
|
||||
int structureStart = source.indexOf("private Holder<Biome> getNoiseBiome(Engine engine");
|
||||
int structureEnd = source.indexOf("Holder<Biome> getVisibleNoiseBiome(", structureStart);
|
||||
String structure = source.substring(structureStart, structureEnd);
|
||||
assertTrue(structure.contains("QuartPos.toBlock(quartX)"));
|
||||
assertTrue(structure.contains("QuartPos.toBlock(quartZ)"));
|
||||
assertCacheGuarded(structure, "structureBiomeCache");
|
||||
|
||||
int visibleStart = source.indexOf(
|
||||
"private Holder<Biome> getVisibleNoiseBiomeWithActiveGenerationLease(");
|
||||
int visibleEnd = source.indexOf("Holder<Biome> getVisibleSurfaceBiome(", visibleStart);
|
||||
String visible = source.substring(visibleStart, visibleEnd);
|
||||
assertTrue(visible.contains("QuartPos.toBlock(quartX)"));
|
||||
assertTrue(visible.contains("QuartPos.toBlock(quartZ)"));
|
||||
assertCacheGuarded(visible, "visibleBiomeCache");
|
||||
|
||||
int predicateStart = source.indexOf("static boolean isBiomeCacheable(");
|
||||
int predicateEnd = source.indexOf("static boolean isMonumentSurfaceBiomeQuery(", predicateStart);
|
||||
String predicate = source.substring(predicateStart, predicateEnd);
|
||||
assertTrue(predicate.contains("return !engine.answersFromNaturalTerrain(blockX, blockZ)"));
|
||||
assertFalse(predicate.contains("getDimensionStackContext()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importedFeaturesCollectOnlyHostOwnedStackCells() throws IOException {
|
||||
String source = Files.readString(Path.of(
|
||||
System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/ModdedImportedFeatureStage.java"));
|
||||
|
||||
assertTrue(source.contains("stackContext.getLayerAt("));
|
||||
assertTrue(source.contains("layer.terrainContext().isSelfReferencing()"));
|
||||
assertTrue(source.contains("section.getBiomes().get(quartX, quartY, quartZ)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -281,17 +158,6 @@ public class IrisModdedStructureParityTest {
|
||||
assertTrue(recursiveKeys.contains("layers:sky/aurora"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void biomeWriterDerivativeFallbackMatchesCanonicalRecursiveKeys() throws IOException {
|
||||
String source = Files.readString(Path.of(
|
||||
System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/ModdedBiomeWriter.java"));
|
||||
|
||||
assertTrue(source.contains(
|
||||
"key.equalsIgnoreCase(dimension.getCustomBiomeKey(custom.getId()))"));
|
||||
assertFalse(source.contains("String dimensionLoadKey = key.substring(0, colon)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureStateRejectsBiomesOutsideThePackContract() {
|
||||
Set<String> generated = Set.of("minecraft:deep_ocean", "minecraft:dark_forest");
|
||||
@@ -410,21 +276,4 @@ public class IrisModdedStructureParityTest {
|
||||
public void initialEntitySpawnsUseThePaperCompletionMarker() {
|
||||
assertSame(MantleFlag.INITIAL_SPAWNED_MARKER, ModdedWorldManager.INITIAL_SPAWN_COMPLETION_FLAG);
|
||||
}
|
||||
|
||||
private static void assertCacheGuarded(String method, String cacheName) {
|
||||
int predicate = method.indexOf("boolean cacheable = isBiomeCacheable(");
|
||||
int cache = method.indexOf("BiomeHolderTable cache = " + cacheName, predicate);
|
||||
int read = method.indexOf("cache.get(", predicate);
|
||||
int readGuard = method.lastIndexOf("if (cacheable)", read);
|
||||
int write = method.indexOf("cache.put(", read);
|
||||
int writeGuard = method.lastIndexOf("if (cacheable)", write);
|
||||
|
||||
assertTrue(predicate >= 0);
|
||||
assertTrue(cache >= 0);
|
||||
assertTrue(read > predicate);
|
||||
assertTrue(readGuard >= predicate);
|
||||
assertTrue(write > read);
|
||||
assertTrue(writeGuard > read);
|
||||
}
|
||||
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedDynamicLevelLifecycleContractTest {
|
||||
private static final String SOURCE_ROOT_PROPERTY = "iris.moddedCommonSources";
|
||||
|
||||
@Test
|
||||
public void sharedManagerPublishesDynamicLoadAndUnloadAroundRegistration() throws IOException {
|
||||
String manager = commonSource("ModdedDimensionManager.java");
|
||||
String loader = commonSource("ModdedLoader.java");
|
||||
String injection = method(manager, "private static Handle inject(");
|
||||
String removal = method(manager, "public static boolean remove(");
|
||||
String injectionRollback = method(manager, "private static void rollbackInjection(");
|
||||
String removalRollback = method(manager, "private static void rollbackRemoval(");
|
||||
|
||||
assertTrue(loader.contains("void fireDynamicLevelLoad(MinecraftServer server, ServerLevel level);"));
|
||||
assertTrue(loader.contains("void fireDynamicLevelUnload(MinecraftServer server, ServerLevel level);"));
|
||||
assertBefore(injection, "serverAccess.putLevelIfAbsent(server, key, level);",
|
||||
"fireDynamicLevelLoad(server, level);");
|
||||
assertBefore(removal, "fireDynamicLevelUnload(server, level);",
|
||||
"serverAccess.removeLevel(server, key);");
|
||||
assertTrue(injectionRollback.contains("fireDynamicLevelUnload(server, level);"));
|
||||
assertTrue(removalRollback.contains("fireDynamicLevelLoad(server, level);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everyLoaderUsesItsNativeLifecycleBus() throws IOException {
|
||||
String fabric = loaderSource("fabric", "art/arcane/iris/fabric/FabricModdedLoader.java");
|
||||
String forge = loaderSource("forge", "art/arcane/iris/forge/ForgeModdedLoader.java");
|
||||
String neoForge = loaderSource("neoforge", "art/arcane/iris/neoforge/NeoForgeModdedLoader.java");
|
||||
|
||||
assertTrue(fabric.contains("ServerLevelEvents.LOAD.invoker().onLevelLoad(server, level);"));
|
||||
assertTrue(fabric.contains("ServerLevelEvents.UNLOAD.invoker().onLevelUnload(server, level);"));
|
||||
assertTrue(forge.contains("LevelEvent.Load.BUS.post(new LevelEvent.Load(level));"));
|
||||
assertTrue(forge.contains("LevelEvent.Unload.BUS.post(new LevelEvent.Unload(level));"));
|
||||
assertTrue(neoForge.contains("NeoForge.EVENT_BUS.post(new LevelEvent.Load(level));"));
|
||||
assertTrue(neoForge.contains("NeoForge.EVENT_BUS.post(new LevelEvent.Unload(level));"));
|
||||
}
|
||||
|
||||
private static String commonSource(String file) throws IOException {
|
||||
return Files.readString(commonRoot().resolve("art/arcane/iris/modded").resolve(file))
|
||||
.replace("\r\n", "\n");
|
||||
}
|
||||
|
||||
private static String loaderSource(String loader, String relative) throws IOException {
|
||||
Path adaptersRoot = commonRoot().getParent().getParent().getParent().getParent();
|
||||
return Files.readString(adaptersRoot.resolve(loader).resolve("src/main/java").resolve(relative))
|
||||
.replace("\r\n", "\n");
|
||||
}
|
||||
|
||||
private static Path commonRoot() {
|
||||
String root = System.getProperty(SOURCE_ROOT_PROPERTY);
|
||||
if (root == null || root.isBlank()) {
|
||||
throw new IllegalStateException("Missing test property " + SOURCE_ROOT_PROPERTY);
|
||||
}
|
||||
return Path.of(root);
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
if (start < 0) {
|
||||
throw new IllegalArgumentException("Missing source method " + signature);
|
||||
}
|
||||
int open = source.indexOf('{', start);
|
||||
int depth = 0;
|
||||
for (int index = open; index < source.length(); index++) {
|
||||
char current = source.charAt(index);
|
||||
if (current == '{') {
|
||||
depth++;
|
||||
} else if (current == '}' && --depth == 0) {
|
||||
return source.substring(start, index + 1);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unclosed source method " + signature);
|
||||
}
|
||||
|
||||
private static void assertBefore(String source, String first, String second) {
|
||||
int firstIndex = source.indexOf(first);
|
||||
int secondIndex = source.indexOf(second);
|
||||
assertTrue("Missing source token " + first, firstIndex >= 0);
|
||||
assertTrue("Missing source token " + second, secondIndex >= 0);
|
||||
assertTrue(first + " must precede " + second, firstIndex < secondIndex);
|
||||
}
|
||||
}
|
||||
-64
@@ -7,12 +7,8 @@ import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
@@ -24,8 +20,6 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ModdedGenerationBootstrapBindingTest {
|
||||
private static final String SOURCE_ROOT_PROPERTY = "iris.moddedCommonSources";
|
||||
|
||||
@Test
|
||||
public void publishedLevelRequiresCurrentGeneratorIdentity() {
|
||||
IrisModdedChunkGenerator generator = mock(IrisModdedChunkGenerator.class, CALLS_REAL_METHODS);
|
||||
@@ -89,62 +83,4 @@ public class ModdedGenerationBootstrapBindingTest {
|
||||
assertSame(dynamicLevel, generator.resolveBoundLevel(server, List.of(dynamicLevel)));
|
||||
verify(server, never()).getLevel(Level.OVERWORLD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void firstGenerationStagesProvideAuthoritativeLevelContext() throws IOException {
|
||||
String source = source("IrisModdedChunkGenerator.java");
|
||||
String structures = method(source, "public void createStructures(");
|
||||
String references = method(source, "public void createReferences(");
|
||||
assertTrue(structures.contains("Engine current = engine(levelKey);"));
|
||||
assertTrue(references.contains("Engine current = engine(level.getLevel());"));
|
||||
|
||||
String publishedBinding = method(source, "private Engine engine(ResourceKey<Level> levelKey)");
|
||||
assertTrue(publishedBinding.contains("requirePublishedLevel(ModdedEngineBootstrap.currentServer(), levelKey)"));
|
||||
assertTrue(publishedBinding.contains("return bindGenerationLevel(level);"));
|
||||
assertFalse(publishedBinding.contains("ModdedServerLevels.level("));
|
||||
|
||||
String fullBinding = method(source, "private Engine bindGenerationLevel(ServerLevel level)");
|
||||
assertTrue(fullBinding.contains("bindLevel(level);"));
|
||||
assertTrue(fullBinding.contains("Engine bound = readyEngine();"));
|
||||
|
||||
String genericBinding = method(source, "Engine engine()");
|
||||
assertTrue(genericBinding.contains("return bindGenerationLevel(level);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorMixinIsNotPartOfGenerationBootstrap() throws IOException {
|
||||
String sourceRoot = System.getProperty(SOURCE_ROOT_PROPERTY);
|
||||
assertTrue(sourceRoot != null && !sourceRoot.isBlank());
|
||||
Path root = Path.of(sourceRoot);
|
||||
assertFalse(Files.exists(root.resolve(Path.of("art", "arcane", "iris", "modded", "mixin",
|
||||
"ServerLevelBindingMixin.java"))));
|
||||
String mixinConfig = Files.readString(root.getParent().resolve("resources/irisworldgen.entity.mixins.json"));
|
||||
assertFalse(mixinConfig.contains("ServerLevelBindingMixin"));
|
||||
}
|
||||
|
||||
private String source(String fileName) throws IOException {
|
||||
String sourceRoot = System.getProperty(SOURCE_ROOT_PROPERTY);
|
||||
assertTrue(sourceRoot != null && !sourceRoot.isBlank());
|
||||
return Files.readString(Path.of(sourceRoot, "art", "arcane", "iris", "modded", fileName));
|
||||
}
|
||||
|
||||
private String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
assertTrue(start >= 0);
|
||||
int body = source.indexOf('{', start);
|
||||
assertTrue(body >= 0);
|
||||
int depth = 0;
|
||||
for (int index = body; index < source.length(); index++) {
|
||||
char token = source.charAt(index);
|
||||
if (token == '{') {
|
||||
depth++;
|
||||
} else if (token == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return source.substring(start, index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unclosed source contract method: " + signature);
|
||||
}
|
||||
}
|
||||
-203
@@ -1,203 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedGenerationHistoryRoutingContractTest {
|
||||
private static final String SOURCE_ROOT_PROPERTY = "iris.moddedCommonSources";
|
||||
|
||||
@Test
|
||||
public void startupPublishesOnlyAnImmutableHistoryBoundRuntime() throws IOException {
|
||||
String source = source("ModdedWorldEngines.java");
|
||||
String create = method(source, "private static Engine create(");
|
||||
String createHistoryEngine = method(source, "private static Engine createHistoryEngine(");
|
||||
String buildEngine = method(source, "private static IrisEngine buildEngine(");
|
||||
|
||||
assertTrue(create.contains("ModdedGenerationHistoryStorage.openOrAdopt("));
|
||||
assertFalse(create.contains("resolvePack("));
|
||||
assertTrue(createHistoryEngine.contains("candidate.attachGenerationHistory("));
|
||||
assertTrue(createHistoryEngine.contains("IrisBoundarySignatureSampler.INSTANCE"));
|
||||
assertTrue(createHistoryEngine.contains("getGenerationTransitionWidthBlocks()"));
|
||||
assertTrue(createHistoryEngine.contains("router.preloadActiveRuntimes();"));
|
||||
assertBefore(createHistoryEngine, "history.prepareCurrentGenerator(",
|
||||
"opened = ModdedGenerationHistoryStorage.resolveActive(history)");
|
||||
assertBefore(createHistoryEngine, "opened = ModdedGenerationHistoryStorage.resolveActive(history)",
|
||||
"IrisEngine candidate = buildEngine(level, seed, opened)");
|
||||
String promoted = method(createHistoryEngine,
|
||||
"if (history.activeActivation().activationId() != openedActivationId)");
|
||||
assertBefore(promoted, "close(candidate);", "ModdedGenerationHistoryStorage.resolveActive(history)");
|
||||
assertBefore(promoted, "ModdedGenerationHistoryStorage.resolveActive(history)",
|
||||
"candidate = buildEngine(level, seed, promoted)");
|
||||
assertTrue(createHistoryEngine.contains("GenerationHistoryRuntimeRouter.attach("));
|
||||
assertTrue(buildEngine.contains("active.packRoot().toFile()"));
|
||||
assertTrue(buildEngine.contains("history.paths().activationMantleRoot(activation.activationId())"));
|
||||
assertTrue(buildEngine.contains("epoch.kernelVersion()"));
|
||||
assertTrue(buildEngine.contains("transitionPlan"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onlyExplicitTransientStudioEnginesBypassHistory() throws IOException {
|
||||
String manager = source("ModdedDimensionManager.java");
|
||||
String transientCreate = method(manager, "public static Handle createTransientStudio(");
|
||||
String persistentCreate = method(manager, "public static Handle createPersistent(");
|
||||
String engines = source("ModdedWorldEngines.java");
|
||||
String studio = method(engines, "private static IrisEngine createTransientStudioEngine(");
|
||||
String generator = source("IrisModdedChunkGenerator.java");
|
||||
String bypass = method(generator, "boolean allowsGenerationHistoryBypass(");
|
||||
String route = method(generator, "private GenerationHistoryRuntimeRouter.RuntimeRoute openHistoryRoute(");
|
||||
|
||||
assertTrue(transientCreate.contains("ModdedGenerationMode.TRANSIENT_STUDIO"));
|
||||
assertTrue(persistentCreate.contains("ModdedGenerationMode.PERSISTENT_CREATE"));
|
||||
assertTrue(studio.contains("IrisData.openRuntime(packDir)"));
|
||||
assertTrue(studio.contains("IrisEngine.InitializationMode.STUDIO"));
|
||||
assertFalse(studio.contains("ModdedGenerationHistoryStorage"));
|
||||
assertFalse(studio.contains("attachGenerationHistory("));
|
||||
assertTrue(bypass.contains("generationMode != ModdedGenerationMode.TRANSIENT_STUDIO"));
|
||||
assertTrue(bypass.contains("irisEngine.isStudio()"));
|
||||
assertTrue(bypass.contains("Only an explicitly transient Iris Studio engine"));
|
||||
assertBefore(route, "allowsGenerationHistoryBypass(current)", "requireHistoryRouter(current, operation)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everyCoordinateBearingChunkStageOpensItsRoutedRuntime() throws IOException {
|
||||
String source = source("IrisModdedChunkGenerator.java");
|
||||
|
||||
assertRuntimeRoute(source, "public Pair<BlockPos, Holder<Structure>> findNearestMapStructure(");
|
||||
assertCoordinateRoute(source, "public WeightedList<MobSpawnSettings.SpawnerData> getMobsAt(");
|
||||
assertRuntimeRoute(source, "public CompletableFuture<ChunkAccess> createBiomes(");
|
||||
assertRuntimeRoute(source, "public void applyCarvers(");
|
||||
assertRuntimeRoute(source, "public void buildSurface(");
|
||||
assertRuntimeRoute(source, "public void applyBiomeDecoration(");
|
||||
assertRuntimeRoute(source, "public void createStructures(");
|
||||
assertRuntimeRoute(source, "public void createReferences(");
|
||||
assertRuntimeRoute(source, "public void spawnOriginalMobs(");
|
||||
assertCoordinateRoute(source, "public int getBaseHeight(");
|
||||
assertCoordinateRoute(source, "public NoiseColumn getBaseColumn(");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncTerrainKeepsTheRouteUntilDurableSemanticClaim() throws IOException {
|
||||
String source = source("IrisModdedChunkGenerator.java");
|
||||
String fill = method(source, "public CompletableFuture<ChunkAccess> fillFromNoise(");
|
||||
String terrain = method(source, "private ChunkAccess generateTerrain(");
|
||||
String completion = method(source, "private static CompletableFuture<ChunkAccess> closeRouteOnCompletion(");
|
||||
|
||||
assertBefore(fill, "openHistoryRoute(", "CompletableFuture.supplyAsync(");
|
||||
assertTrue(fill.contains("generateTerrain(chunk, generationEngine, pos, air, route)"));
|
||||
assertTrue(fill.contains("return closeRouteOnCompletion(pipeline, route);"));
|
||||
assertTrue(terrain.contains("openHistoryRuntimeScope(route)"));
|
||||
assertBefore(terrain, "generationEngine.generate(", "writeBlocks(chunk, blocks, dimMinY, height)");
|
||||
assertBefore(terrain, "writeBlocks(chunk, blocks, dimMinY, height)", "route.claimGeneratedSemantics(");
|
||||
assertTrue(terrain.contains("chunk.getBlockState(position.set(x, dimMinY + y, z))"));
|
||||
assertTrue(terrain.contains("state.isAir() || state.liquid()"));
|
||||
assertBefore(terrain, "route.claimGeneratedSemantics(", "ModdedNativeTerrainReceipts.persist(chunk, route)");
|
||||
assertBefore(terrain, "ModdedNativeTerrainReceipts.persist(chunk, route)", "return chunk;");
|
||||
assertTrue(completion.contains("pipeline.whenComplete("));
|
||||
assertTrue(completion.contains("route.close();"));
|
||||
assertBefore(completion, "pipeline.whenComplete(", "route.detachThread()");
|
||||
assertBefore(completion, "route.detachThread()", "return completion;");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void biomeQueriesRouteEachCoordinateAndKeepRuntimeSpecificCaches() throws IOException {
|
||||
String source = source("IrisModdedBiomeSource.java");
|
||||
String structure = method(source, "public Holder<Biome> getNoiseBiome(");
|
||||
String visible = method(source, "Holder<Biome> getVisibleNoiseBiome(");
|
||||
String batch = method(source, "public Set<Holder<Biome>> getBiomesWithin(");
|
||||
String resolution = method(source, "private Holder<Biome> resolveVisibleBiome(");
|
||||
|
||||
assertTrue(structure.contains("openHistoryCoordinateScope("));
|
||||
assertTrue(visible.contains("openHistoryCoordinateScope("));
|
||||
assertTrue(batch.contains("quartX << 2, quartZ << 2"));
|
||||
assertTrue(source.contains("int runtimeIdentity = engine.getCacheID();"));
|
||||
assertTrue(source.contains("cache.get(runtimeIdentity, key)"));
|
||||
assertTrue(source.contains("cache.put(runtimeIdentity, key, resolved)"));
|
||||
assertBefore(resolution, "historicalPhysicalBiomeKeyAt(", "ModdedWorldgenIds.biomeRef(engine");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pendingNativeStagesPreserveSavedStartsAndGuardNewFeatureFootprints() throws IOException {
|
||||
String generator = source("IrisModdedChunkGenerator.java");
|
||||
String discrete = method(generator, "private boolean allowsRoutedDiscreteGeneration(");
|
||||
String decoration = method(generator, "public void applyBiomeDecoration(");
|
||||
String structures = method(generator, "public void createStructures(");
|
||||
String mobs = method(generator, "public void spawnOriginalMobs(");
|
||||
String nativeStage = source("ModdedNativeStructureStage.java");
|
||||
String adjust = method(nativeStage, "void adjustGeneratedStructures(");
|
||||
String place = method(nativeStage, "void placeVanillaStructures(");
|
||||
String savedStart = method(nativeStage, "private boolean isHistoricalStructureStart(");
|
||||
|
||||
assertTrue(discrete.contains("chunk.getPersistedStatus().isOrAfter(stage)"));
|
||||
assertFalse(discrete.contains("router.history().activeActivation().activationId()"));
|
||||
assertFalse(discrete.contains("return true;"));
|
||||
assertTrue(discrete.contains("allowsNewGenerationChunk("));
|
||||
assertTrue(discrete.contains("NativeGenerationWriteGuard.allowsPendingStage(current, chunk, stage)"));
|
||||
assertTrue(decoration.contains("ChunkStatus.FEATURES"));
|
||||
assertTrue(structures.contains("ChunkStatus.STRUCTURE_STARTS"));
|
||||
assertTrue(mobs.contains("ChunkStatus.SPAWN"));
|
||||
assertBefore(decoration, "chunk.getPersistedStatus().isOrAfter(ChunkStatus.FEATURES)",
|
||||
"nativeStructures.placeVanillaStructures(");
|
||||
assertBefore(decoration, "nativeStructures.placeVanillaStructures(", "allowsRoutedDiscreteGeneration(");
|
||||
assertBefore(decoration, "allowsRoutedDiscreteGeneration(", "importedFeatures.run(");
|
||||
assertBefore(decoration, "NativeGenerationWriteGuard.allowsDecoration(", "importedFeatures.run(");
|
||||
assertBefore(structures, "allowsRoutedDiscreteGeneration(", "super.createStructures(");
|
||||
assertBefore(mobs, "allowsRoutedDiscreteGeneration(", "NaturalSpawner.spawnMobsForChunkGeneration(");
|
||||
assertBefore(adjust, "allowsNewGenerationFootprint(", "recordWorldCheckStructureShift(");
|
||||
assertBefore(place, "!isHistoricalStructureStart(current, world, start)", "allowsNewGenerationFootprint(");
|
||||
assertTrue(savedStart.contains("world.getChunk(origin.x(), origin.z(), ChunkStatus.EMPTY, false)"));
|
||||
assertTrue(savedStart.contains("ModdedNativeTerrainReceipts.structureActivation(source)"));
|
||||
assertBefore(structures, "super.createStructures(", "ModdedNativeTerrainReceipts.persistStructureActivation(");
|
||||
}
|
||||
|
||||
private static void assertRuntimeRoute(String source, String signature) {
|
||||
String body = method(source, signature);
|
||||
assertTrue(signature + " must open a generation-history route", body.contains("openHistoryRoute("));
|
||||
assertTrue(signature + " must open its routed runtime", body.contains("openHistoryRuntimeScope(route)"));
|
||||
}
|
||||
|
||||
private static void assertCoordinateRoute(String source, String signature) {
|
||||
String body = method(source, signature);
|
||||
assertTrue(signature + " must route its coordinate", body.contains("openHistoryCoordinateScope("));
|
||||
}
|
||||
|
||||
private static void assertBefore(String source, String first, String second) {
|
||||
int firstIndex = source.indexOf(first);
|
||||
int secondIndex = source.indexOf(second);
|
||||
assertTrue("Missing source contract token: " + first, firstIndex >= 0);
|
||||
assertTrue("Missing source contract token: " + second, secondIndex >= 0);
|
||||
assertTrue(first + " must occur before " + second, firstIndex < secondIndex);
|
||||
}
|
||||
|
||||
private static String source(String fileName) throws IOException {
|
||||
String sourceRoot = System.getProperty(SOURCE_ROOT_PROPERTY);
|
||||
assertTrue("Missing system property " + SOURCE_ROOT_PROPERTY,
|
||||
sourceRoot != null && !sourceRoot.isBlank());
|
||||
return Files.readString(Path.of(sourceRoot, "art", "arcane", "iris", "modded", fileName));
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
assertTrue("Missing source contract signature: " + signature, start >= 0);
|
||||
int openBrace = source.indexOf('{', start);
|
||||
assertTrue("Missing source contract method body: " + signature, openBrace >= 0);
|
||||
int depth = 0;
|
||||
for (int index = openBrace; index < source.length(); index++) {
|
||||
char current = source.charAt(index);
|
||||
if (current == '{') {
|
||||
depth++;
|
||||
} else if (current == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return source.substring(start, index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unclosed source contract method: " + signature);
|
||||
}
|
||||
}
|
||||
-244
@@ -1,244 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedGenerationLeaseContractTest {
|
||||
private static final String SOURCE_ROOT_PROPERTY = "iris.moddedCommonSources";
|
||||
|
||||
@Test
|
||||
public void biomeRuntimeReadsAreGenerationLeased() throws IOException {
|
||||
String source = source("art/arcane/iris/modded/IrisModdedBiomeSource.java");
|
||||
|
||||
assertTrue(source.contains("tryAcquireGenerationLease(engine, \"modded_structure_biome\")"));
|
||||
assertTrue(source.contains("tryAcquireGenerationLease(engine, \"modded_visible_biome\")"));
|
||||
assertTrue(source.contains("tryAcquireGenerationLease(engine, \"modded_biomes_within\")"));
|
||||
assertTrue(source.contains("tryAcquireGenerationLease(engine, \"modded_structure_reachability\")"));
|
||||
assertTrue(source.contains("tryAcquireGenerationLease(engine, \"modded_structure_state_biome\")"));
|
||||
assertTrue(source.contains("tryAcquireGenerationLease(engine, \"modded_structure_biome_keys\")"));
|
||||
assertTrue(source.contains("engine == null || engine.isClosed()"));
|
||||
assertTrue(source.contains("catch (GenerationSessionException e)"));
|
||||
assertTrue(source.contains("e.isExpectedTeardown()"));
|
||||
assertTrue(source.contains("Iris structure biome key lookup was rejected during an engine transition"));
|
||||
assertTrue(source.contains("int runtimeIdentity = engine.getCacheID();"));
|
||||
assertTrue(source.contains("cache.get(runtimeIdentity, key)"));
|
||||
assertTrue(source.contains("cache.put(runtimeIdentity, key, resolved)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void terrainAndHeightQueriesShareGenerationSessions() throws IOException {
|
||||
String source = source("art/arcane/iris/modded/IrisModdedChunkGenerator.java");
|
||||
|
||||
assertTrue(source.contains("generationEngine.acquireGenerationLease(\"modded_chunk_pipeline\")"));
|
||||
assertTrue(source.contains("current.acquireGenerationLease(\"modded_base_height\")"));
|
||||
assertTrue(source.contains("current.acquireGenerationLease(\"modded_base_column\")"));
|
||||
assertTrue(source.contains("current.acquireGenerationLease(\"modded_configured_biome_keys\")"));
|
||||
assertTrue(source.contains("generationEngine.isClosing() || e.isExpectedTeardown()"));
|
||||
String terrain = method(source, "private ChunkAccess generateTerrain(");
|
||||
int sessionFailure = terrain.indexOf("catch (GenerationSessionException e)");
|
||||
int generalFailure = terrain.indexOf("catch (Throwable e)", sessionFailure);
|
||||
String sessionHandler = terrain.substring(sessionFailure, generalFailure);
|
||||
assertTrue(sessionHandler.contains("throw new IllegalStateException"));
|
||||
assertFalse(sessionHandler.contains("return chunk;"));
|
||||
|
||||
String references = method(source, "public void createReferences(");
|
||||
assertTrue(references.contains("requireGenerationLease(current, \"modded_create_references\")"));
|
||||
assertTrue(references.contains("IrisContext.open(current, lease.sessionId(), null)"));
|
||||
assertTrue(references.contains("NativeStructureReferenceRepair.createReferences("));
|
||||
assertFalse(references.contains("super.createReferences(level, structureManager, chunk);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preservationDereferencesSharedPackData() throws IOException {
|
||||
String source = source("art/arcane/iris/modded/service/ModdedPreservationService.java");
|
||||
int dereference = source.indexOf("public void dereference()");
|
||||
int irisData = source.indexOf("IrisData.dereference();", dereference);
|
||||
int trackedResources = source.indexOf("threads.removeIf", dereference);
|
||||
|
||||
assertTrue(dereference >= 0);
|
||||
assertTrue(irisData > dereference);
|
||||
assertTrue(trackedResources > irisData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hotloadShutdownOnlyTargetsItsOwnWorld() throws IOException {
|
||||
String source = source("art/arcane/iris/modded/service/ModdedStudioHotloadService.java");
|
||||
int shutdown = source.indexOf("public void shutdownPregenerator(Engine engine)");
|
||||
int nextMethod = source.indexOf("private boolean throttled", shutdown);
|
||||
String method = source.substring(shutdown, nextMethod);
|
||||
|
||||
assertTrue(method.contains("ModdedPregenJob.shutdownForWorld(world.identity());"));
|
||||
assertFalse(method.contains("PregeneratorJob.shutdownInstance();"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maintenanceOwnsOneGenerationSessionUntilWorkCompletes() throws IOException {
|
||||
String source = source("art/arcane/iris/modded/service/ModdedEngineMaintenanceService.java");
|
||||
String maintain = method(source, "private void maintain(Engine engine, long scheduledAt)");
|
||||
|
||||
assertTrue(maintain.contains("engine.acquireGenerationLease(\"modded_engine_maintenance\")"));
|
||||
assertTrue(maintain.contains("IrisContext.open(engine, lease.sessionId(), null)"));
|
||||
assertTrue(maintain.contains("exception.isExpectedTeardown()"));
|
||||
assertTrue(source.contains("active.awaitTermination(INTERRUPT_DRAIN_TIMEOUT_SECONDS, TimeUnit.SECONDS)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packDownloadAdmissionPrecedesAsyncDispatch() throws IOException {
|
||||
String source = source("art/arcane/iris/modded/command/IrisModdedCommands.java");
|
||||
String download = method(source, "static int download(CommandSourceStack source, String rawRequest)");
|
||||
int admission = download.indexOf("LifecycleOperationCoordinator.get().acquire(");
|
||||
int executionTracking = download.indexOf("new PackDownloadExecution(");
|
||||
int dispatch = download.indexOf("scheduler.asyncIfRunning(execution, execution::cancel)");
|
||||
|
||||
assertTrue(admission >= 0);
|
||||
assertTrue(executionTracking > admission);
|
||||
assertTrue(dispatch > admission);
|
||||
assertTrue(download.contains("execution.cancel();"));
|
||||
|
||||
String execution = method(source, "private static void executeDownload(");
|
||||
assertTrue(execution.contains("PackDownloader.DownloadCancellation cancellation"));
|
||||
assertTrue(execution.contains("catch (PackDownloader.PackDownloadCancelledException error)"));
|
||||
assertTrue(execution.contains("dispatchDownloadFeedback(source,"));
|
||||
assertFalse(execution.contains("scheduler.global("));
|
||||
assertFalse(execution.contains("lease.close();"));
|
||||
|
||||
String feedback = method(source, "private static void dispatchDownloadFeedback(");
|
||||
assertTrue(feedback.contains("source.getServer().execute(feedback);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packDownloadsDrainBeforeModdedSchedulerShutdown() throws IOException {
|
||||
String commands = source("art/arcane/iris/modded/command/IrisModdedCommands.java");
|
||||
String shutdownDownloads = method(commands, "public static void shutdownDownloads()");
|
||||
assertTrue(shutdownDownloads.contains("downloadAdmissionOpen = false;"));
|
||||
assertTrue(shutdownDownloads.contains("execution.cancel();"));
|
||||
assertTrue(shutdownDownloads.contains("execution.await("));
|
||||
|
||||
String bootstrap = source("art/arcane/iris/modded/ModdedEngineBootstrap.java");
|
||||
String stop = method(bootstrap, "public static void stop()");
|
||||
int downloads = stop.indexOf("IrisModdedCommands::shutdownDownloads");
|
||||
int scheduler = stop.indexOf("scheduler::shutdown");
|
||||
assertTrue(downloads >= 0);
|
||||
assertTrue(scheduler > downloads);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void moddedSchedulerRejectsAndCancelsAbandonedDownloadSubmissions() throws IOException {
|
||||
String scheduler = source("art/arcane/iris/modded/ModdedScheduler.java");
|
||||
String dispatch = method(scheduler, "public boolean asyncIfRunning(Runnable task, Runnable rejection)");
|
||||
assertTrue(dispatch.contains("RejectionAwareTask"));
|
||||
assertTrue(dispatch.contains("Objects.requireNonNull(rejection"));
|
||||
|
||||
String shutdown = method(scheduler, "public void shutdown()");
|
||||
assertTrue(shutdown.contains("asyncExecutor.shutdownNow()"));
|
||||
assertTrue(shutdown.contains("rejectAbandonedTasks(abandonedTasks);"));
|
||||
|
||||
String reset = method(scheduler, "public void reset()");
|
||||
assertTrue(reset.contains("asyncExecutor.getQueue().drainTo(abandonedTasks);"));
|
||||
assertTrue(reset.contains("rejectAbandonedTasks(abandonedTasks);"));
|
||||
|
||||
String rejection = method(scheduler, "private static void rejectAbandonedTasks(");
|
||||
assertTrue(rejection.contains("rejectionAwareTask.reject();"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockingPregenShutdownDefersItsFinalSaveToTheServerThread() throws IOException {
|
||||
String jobSource = source("art/arcane/iris/modded/command/ModdedPregenJob.java");
|
||||
String shutdown = method(jobSource, "private static boolean shutdownAndSave(");
|
||||
assertTrue(shutdown.contains("deferFinalSaveToServerThread()"));
|
||||
assertTrue(shutdown.contains("completeDeferredFinalSave()"));
|
||||
assertTrue(shutdown.contains("cancelDeferredFinalSave()"));
|
||||
|
||||
String methodSource = source("art/arcane/iris/modded/command/ModdedPregenMethod.java");
|
||||
String close = method(methodSource, "public void close()");
|
||||
assertTrue(close.contains("deferFinalSaveIfRequested()"));
|
||||
|
||||
String await = method(methodSource, "private void awaitFinalSave(");
|
||||
assertTrue(await.contains("FINAL_SAVE_POLL_MILLIS"));
|
||||
assertTrue(await.contains("deferFinalSaveIfRequested()"));
|
||||
|
||||
String complete = method(methodSource, "void completeDeferredFinalSave()");
|
||||
int cancel = complete.indexOf("cancelQueuedFinalSave();");
|
||||
int directSave = complete.indexOf("saveLevelOnServerThread();");
|
||||
assertTrue(cancel >= 0);
|
||||
assertTrue(directSave > cancel);
|
||||
|
||||
String queuedSave = method(methodSource, "private void executeFinalSave(");
|
||||
assertTrue(queuedSave.contains("if (!request.claim())"));
|
||||
String cancelRequest = method(methodSource, "private void cancelQueuedFinalSave()");
|
||||
assertTrue(cancelRequest.contains("request.cancel();"));
|
||||
String pending = method(methodSource, "boolean hasPendingFinalSave()");
|
||||
assertTrue(pending.contains("queuedFinalSave.get() != null"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void firstPregenChunkFailureRetainsItsFullCause() throws IOException {
|
||||
String methodSource = source("art/arcane/iris/modded/command/ModdedPregenMethod.java");
|
||||
String logFailure = method(methodSource, "private void logChunkFailure(");
|
||||
|
||||
assertTrue(methodSource.contains("AtomicBoolean failureDetailLogged"));
|
||||
assertTrue(logFailure.contains("unwrap(failure)"));
|
||||
assertTrue(logFailure.contains("failureDetailLogged.compareAndSet(false, true)"));
|
||||
assertTrue(logFailure.contains("x, z, cause);"));
|
||||
assertTrue(logFailure.contains("cause.toString()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pregenReportsOnlyCleanupCallbacksFromCoveredTargets() throws IOException {
|
||||
String source = source("art/arcane/iris/modded/command/ModdedPregenMethod.java");
|
||||
String cleanup = method(source, "private void cleanupMantleChunksCoveredBy(");
|
||||
|
||||
assertTrue(source.contains("cleanupMantleChunksCoveredBy(x, z, listener);"));
|
||||
assertFalse(source.contains("cleanupMantleChunk(x, z);"));
|
||||
assertTrue(cleanup.contains("cleanupChunksCoveredBy(x, z, true, listener::onChunkCleaned)"));
|
||||
assertFalse(cleanup.contains("forceCleanupChunk"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidPregenBoundsFailBeforeRuntimeMutation() throws IOException {
|
||||
String jobSource = source("art/arcane/iris/modded/command/ModdedPregenJob.java");
|
||||
String start = method(jobSource, "public static boolean start(");
|
||||
int taskConstruction = start.indexOf("PregenTask task = PregenTask.builder()");
|
||||
int profileMutation = start.indexOf("PregenPerformanceProfile.apply(engine)");
|
||||
|
||||
assertTrue(taskConstruction >= 0);
|
||||
assertTrue(profileMutation > taskConstruction);
|
||||
|
||||
String commandSource = source("art/arcane/iris/modded/command/ModdedPregenCommands.java");
|
||||
String command = method(commandSource, "static int pregenStart(");
|
||||
assertTrue(command.contains("catch (IllegalArgumentException failure)"));
|
||||
assertTrue(command.contains("IrisModdedCommands.fail(source, failure.getMessage())"));
|
||||
}
|
||||
|
||||
private static String source(String relativePath) throws IOException {
|
||||
String root = System.getProperty(SOURCE_ROOT_PROPERTY);
|
||||
assertTrue("Missing system property " + SOURCE_ROOT_PROPERTY, root != null && !root.isBlank());
|
||||
return Files.readString(Path.of(root, relativePath));
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
assertTrue("Missing source contract signature: " + signature, start >= 0);
|
||||
int openBrace = source.indexOf('{', start);
|
||||
assertTrue("Missing source contract method body: " + signature, openBrace >= 0);
|
||||
int depth = 0;
|
||||
for (int index = openBrace; index < source.length(); index++) {
|
||||
char current = source.charAt(index);
|
||||
if (current == '{') {
|
||||
depth++;
|
||||
} else if (current == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return source.substring(start, index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unclosed source contract method: " + signature);
|
||||
}
|
||||
}
|
||||
-58
@@ -2,32 +2,9 @@ package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* The level router is a switch statement, which the compiler does not check for exhaustiveness. A level added
|
||||
* to {@link art.arcane.iris.spi.LogLevel} with no arm here would compile and then drop every message at that
|
||||
* level without a trace, so the fallback arm is what keeps a new level visible on the modded loaders.
|
||||
*/
|
||||
public class ModdedIrisLogLevelCoverageTest {
|
||||
@Test
|
||||
public void everyLogLevelReachesTheLoggerIncludingOnesAddedLater() throws IOException {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/ModdedIrisLog.java"));
|
||||
int router = source.indexOf("public static void log(LogLevel level, String message)");
|
||||
assertTrue("log(LogLevel, String) not found", router >= 0);
|
||||
|
||||
String body = source.substring(router, source.indexOf("public static void debug(", router));
|
||||
assertTrue(body, body.contains("default -> info(message);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void slf4jStyleArgumentsAndTrailingThrowableArePreserved() {
|
||||
RuntimeException failure = new RuntimeException("broken");
|
||||
@@ -37,39 +14,4 @@ public class ModdedIrisLogLevelCoverageTest {
|
||||
assertEquals("chunk 4,9 failed", rendered.message());
|
||||
assertEquals(failure, rendered.error());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formattedDebugThrowableUsesTheVisibleDebugRouteWhenEnabled() throws IOException {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/ModdedIrisLog.java"));
|
||||
int start = source.indexOf("public static void debug(String format, Object... arguments)");
|
||||
int end = source.indexOf("public static void info(String message)", start);
|
||||
assertTrue("formatted debug overload not found", start >= 0);
|
||||
assertTrue("formatted debug overload boundary not found", end > start);
|
||||
String body = source.substring(start, end);
|
||||
|
||||
assertTrue(body, body.contains("if (!debugEnabled())"));
|
||||
assertTrue(body, body.contains("LOGGER.info(\"[Iris/DEBUG] \" + clean(rendered.message()), rendered.error())"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void moddedProductionUsesTheIrisLogFrontDoor() throws IOException {
|
||||
Path root = Path.of(System.getProperty("iris.moddedCommonSources"));
|
||||
try (Stream<Path> files = Files.walk(root)) {
|
||||
List<Path> bypasses = files
|
||||
.filter(path -> path.toString().endsWith(".java"))
|
||||
.filter(path -> !path.getFileName().toString().equals("ModdedIrisLog.java"))
|
||||
.filter(path -> {
|
||||
try {
|
||||
String source = Files.readString(path);
|
||||
return source.contains("LoggerFactory.getLogger")
|
||||
|| source.contains("private static final Logger LOGGER");
|
||||
} catch (IOException unreadable) {
|
||||
throw new IllegalStateException(unreadable);
|
||||
}
|
||||
})
|
||||
.toList();
|
||||
assertTrue(bypasses.toString(), bypasses.isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
-23
@@ -2,10 +2,6 @@ package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
@@ -48,25 +44,6 @@ public class ModdedLevelDataAttachmentTest {
|
||||
assertNull(failure.getCause());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initializesLevelDataBeforeBindingAndPublication() throws IOException {
|
||||
String source = Files.readString(sourcePath("ModdedDimensionManager.java"));
|
||||
int construction = source.indexOf("ServerLevel level = new ServerLevel(");
|
||||
int initialization = source.indexOf("serverAccess.initializeLevelData(server, level);", construction);
|
||||
int binding = source.indexOf("generator.bindLevel(level);", initialization);
|
||||
int publication = source.indexOf("serverAccess.putLevelIfAbsent(server, key, level);", binding);
|
||||
|
||||
assertTrue(construction >= 0);
|
||||
assertTrue(initialization > construction);
|
||||
assertTrue(binding > initialization);
|
||||
assertTrue(publication > binding);
|
||||
}
|
||||
|
||||
private static Path sourcePath(String fileName) {
|
||||
return Path.of(System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded", fileName);
|
||||
}
|
||||
|
||||
public static final class AttachedLevelData {
|
||||
private RootData rootData;
|
||||
private DimensionKey dimensionKey;
|
||||
|
||||
-436
@@ -1,436 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
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 ModdedLifecycleFailureContractTest {
|
||||
private static final String SOURCE_ROOT_PROPERTY = "iris.moddedCommonSources";
|
||||
|
||||
@Test
|
||||
public void existingDimensionStagesWithoutReplacingTheLiveEngine() throws IOException {
|
||||
String managerSource = source("ModdedDimensionManager.java");
|
||||
String create = method(managerSource, "private static Handle create(");
|
||||
int existingStart = requiredIndex(create, "if (existing != null");
|
||||
int presentStart = requiredIndex(create, "if (serverAccess.hasLevel(server, key))", existingStart + 1);
|
||||
int injectionStart = requiredIndex(create, "try {", presentStart);
|
||||
|
||||
assertFalse(create.substring(existingStart, presentStart).contains("repointAndBind("));
|
||||
assertFalse(create.substring(presentStart, injectionStart).contains("repointAndBind("));
|
||||
assertBefore(create, "ModdedGenerationHistoryStorage.createOrStage(", "if (existing != null");
|
||||
|
||||
String generatorSource = source("IrisModdedChunkGenerator.java");
|
||||
String repointAndBind = method(generatorSource, "void repointAndBind(");
|
||||
assertBefore(repointAndBind, "ModdedWorldEngines.prepareReplacement(",
|
||||
"ModdedWorldEngines.installReplacement(");
|
||||
assertBefore(repointAndBind, "ModdedWorldEngines.installReplacement(", "this.activePack = pack;");
|
||||
String failure = catchBlock(repointAndBind);
|
||||
assertTrue(failure.contains("ModdedWorldEngines.closeUnregistered(replacement);"));
|
||||
assertTrue(failure.contains("addSuppressed("));
|
||||
|
||||
String worldEnginesSource = source("ModdedWorldEngines.java");
|
||||
String installReplacement = method(worldEnginesSource, "static void installReplacement(");
|
||||
assertTrue(installReplacement.contains("ENGINES.compute("));
|
||||
assertBefore(installReplacement, "close(current);", "return activeReplacement;");
|
||||
assertFalse(installReplacement.contains("catch ("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void persistentPackUpdatesUseAnExplicitRestartBoundPath() throws IOException {
|
||||
String managerSource = source("ModdedDimensionManager.java");
|
||||
String createPersistent = method(managerSource, "public static Handle createPersistent(");
|
||||
String update = method(managerSource, "public static UpdateResult stagePersistentUpdate(");
|
||||
|
||||
assertBefore(createPersistent, "if (previous != null)", "ModdedDimensionRegistryStore.put(");
|
||||
assertTrue(createPersistent.contains("Use the Iris world update command"));
|
||||
assertTrue(update.contains("ModdedGenerationHistoryStorage.createOrStage("));
|
||||
assertTrue(update.contains("active.history().pendingActivation()"));
|
||||
assertTrue(update.contains("restartRequired()"));
|
||||
assertFalse(update.contains("inject("));
|
||||
assertFalse(update.contains("repointAndBind("));
|
||||
assertBefore(update, "ModdedDimensionRegistryStore.put(server, updated);",
|
||||
"ModdedGenerationHistoryStorage.createOrStage(");
|
||||
assertTrue(update.contains("ModdedDimensionRegistryStore.put(server, previous);"));
|
||||
|
||||
String commandsSource = source("command/ModdedWorldCommands.java");
|
||||
assertTrue(commandsSource.contains("root.then(updateTree());"));
|
||||
String command = method(commandsSource, "private static int update(");
|
||||
assertTrue(command.contains("ModdedDimensionManager.stagePersistentUpdate("));
|
||||
assertTrue(command.contains("Restart the server to activate it"));
|
||||
assertTrue(command.contains("running world remains on its current pack"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void injectionBindsBeforeRegistrationAndRollsBackEveryFailure() throws IOException {
|
||||
String source = source("ModdedDimensionManager.java");
|
||||
String injection = method(source, "private static Handle inject(");
|
||||
|
||||
assertBefore(injection, "generator.bindLevel(level);", "serverAccess.putLevelIfAbsent(server, key, level);");
|
||||
assertBefore(injection, "serverAccess.putLevelIfAbsent(server, key, level);",
|
||||
"server.getPlayerList().addWorldborderListener(level);");
|
||||
assertFalse(injection.contains("serverAccess.putLevel(server, key, previous);"));
|
||||
String failure = catchBlock(injection);
|
||||
assertBefore(failure, "rollbackInjection(", "throw ");
|
||||
|
||||
String rollback = method(source, "void rollbackInjection(");
|
||||
assertBefore(rollback, "serverAccess.hasLevel(server, key)", "serverAccess.removeLevel(server, key);");
|
||||
assertTrue(rollback.contains("generator.unbindEngine("));
|
||||
assertTrue(rollback.contains("level.close();"));
|
||||
assertTrue(rollback.contains("addSuppressed("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void persistentReinjectionQuarantinesBrokenEntriesAndContinues() throws IOException {
|
||||
String source = source("ModdedStartup.java");
|
||||
String reinjection = method(source, "private static void reinjectPersistentDimensions(");
|
||||
String failure = catchBlock(reinjection);
|
||||
|
||||
assertTrue(failure.contains("ModdedIrisLog.error("));
|
||||
assertFalse(failure.contains("e.toString()"));
|
||||
assertFalse(failure.contains("throw new IllegalStateException("));
|
||||
assertTrue(reinjection.contains("injected++;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void persistentReinjectionWaitsForPlayerServicesAndServerStarted() throws IOException {
|
||||
String bootstrapSource = source("ModdedEngineBootstrap.java");
|
||||
String start = method(bootstrapSource, "public static void start(");
|
||||
String serverAboutToStart = method(bootstrapSource, "public static void serverAboutToStart(");
|
||||
String serverStarted = method(bootstrapSource, "public static void serverStarted(");
|
||||
|
||||
assertFalse(start.contains("ModdedStartup.runOnce(server);"));
|
||||
assertFalse(serverAboutToStart.contains("ModdedStartup.runOnce(server);"));
|
||||
assertEquals(1, occurrences(serverStarted, "ModdedStartup.runOnce(server);"));
|
||||
assertBefore(serverStarted, "bindWorldGenerators(server);", "ModdedStartup.runOnce(server);");
|
||||
assertBefore(serverStarted, "ModdedStartup.runOnce(server);", "reconcileSpawn(server);");
|
||||
|
||||
String startupSource = source("ModdedStartup.java");
|
||||
String runOnce = method(startupSource, "public static void runOnce(");
|
||||
assertBefore(runOnce, "server.getPlayerList() == null", "STARTED.compareAndSet(false, true)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dynamicLevelMutationsInvalidateLoaderTickCaches() throws IOException {
|
||||
String levelsSource = source("ModdedServerLevels.java");
|
||||
String put = method(levelsSource, "public ServerLevel putLevel(");
|
||||
String putIfAbsent = method(levelsSource, "public ServerLevel putLevelIfAbsent(");
|
||||
String remove = method(levelsSource, "public ServerLevel removeLevel(");
|
||||
|
||||
assertBefore(put, "server.levels.put(key, level);", "levelCacheInvalidator.accept(server);");
|
||||
assertTrue(put.contains("if (previous != level)"));
|
||||
assertBefore(putIfAbsent, "server.levels.putIfAbsent(key, level);", "levelCacheInvalidator.accept(server);");
|
||||
assertTrue(putIfAbsent.contains("if (previous == null)"));
|
||||
assertBefore(remove, "server.levels.remove(key);", "levelCacheInvalidator.accept(server);");
|
||||
assertTrue(remove.contains("if (removed != null)"));
|
||||
|
||||
String loaderSource = source("ModdedLoader.java");
|
||||
assertTrue(loaderSource.contains("void invalidateLevelCache(MinecraftServer server);"));
|
||||
String bootstrapSource = source("ModdedEngineBootstrap.java");
|
||||
assertTrue(bootstrapSource.contains("new ModdedServerLevels(boundLoader::invalidateLevelCache)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void persistentRestoreOpensHistoryBeforeConsultingTheGlobalPack() throws IOException {
|
||||
String source = source("ModdedGenerationHistoryStorage.java");
|
||||
String restore = method(source, "static GenerationHistory restoreOrAdopt(");
|
||||
|
||||
assertBefore(restore, "GenerationHistory.openIfPresent(", "sourceSupplier\").get();");
|
||||
assertTrue(restore.contains("if (existing.isPresent())"));
|
||||
assertBefore(restore, "requireRegistryDefinitions(existing.get()", "return existing.get();");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void productionPackResolutionNeverUsesTheParityProbeAsData() throws IOException {
|
||||
String source = source("ModdedWorldEngines.java");
|
||||
String resolvePack = method(source, "static File resolvePack(");
|
||||
|
||||
assertFalse(source.contains("System.getProperty(\"iris.parity\")"));
|
||||
assertFalse(source.contains("parityPack"));
|
||||
assertFalse(source.contains("falling back to parity pack"));
|
||||
assertTrue(resolvePack.contains("throw new IllegalStateException("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineBootstrapResetsStartupExactlyOnceDuringStop() throws IOException {
|
||||
String source = source("ModdedEngineBootstrap.java");
|
||||
String stop = method(source, "public static void stop(");
|
||||
|
||||
assertEquals(1, occurrences(stop, "ModdedStartup::reset"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineBootstrapAttemptsEveryShutdownStageAndAggregatesFailures() throws IOException {
|
||||
String source = source("ModdedEngineBootstrap.java");
|
||||
String stop = method(source, "public static void stop(");
|
||||
|
||||
assertBefore(stop, "\"services\"", "\"world engines\"");
|
||||
assertBefore(stop, "\"world engines\"", "\"dimension manager\"");
|
||||
assertBefore(stop, "\"server state\"", "if (failure != null)");
|
||||
assertFalse(stop.contains("throw"));
|
||||
assertTrue(stop.contains("ModdedIrisLog.error(\"Iris modded shutdown completed with failures\", failure);"));
|
||||
|
||||
String runStage = method(source, "private static Throwable runStopStage(");
|
||||
assertTrue(runStage.contains("catch (Throwable stageFailure)"));
|
||||
assertTrue(runStage.contains("failure.addSuppressed(stageFailure);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worldShutdownRemovesOnlySuccessfullyClosedMappings() throws IOException {
|
||||
String source = source("ModdedWorldEngines.java");
|
||||
String shutdown = method(source, "public static void shutdown()");
|
||||
|
||||
assertTrue(shutdown.contains("new ArrayList<>(ENGINES.entrySet())"));
|
||||
assertFalse(shutdown.contains("ENGINES.clear()"));
|
||||
// Bound generators must go through unbindEngine (latch unloading, then strict evict) so a
|
||||
// late chunk-system drain cannot rebuild an engine nothing closes again.
|
||||
assertTrue(shutdown.contains("generator.unbindEngine(level);"));
|
||||
assertBefore(shutdown, "close(engine);", "ENGINES.remove(level, engine)");
|
||||
assertTrue(shutdown.contains("ENGINES.containsKey(level)"));
|
||||
assertTrue(shutdown.contains("failure.addSuppressed(e);"));
|
||||
assertTrue(shutdown.contains("failed mappings were retained"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineEvictionRetainsTheMappingUntilCloseSucceeds() throws IOException {
|
||||
String source = source("ModdedWorldEngines.java");
|
||||
String eviction = method(source, "static void evictOrThrow(");
|
||||
|
||||
assertTrue(eviction.contains("ENGINES.computeIfPresent("));
|
||||
assertFalse(eviction.contains("ENGINES.remove("));
|
||||
assertBefore(eviction, "close(current);", "return null;");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generatorUnbindRetainsOwnershipWhenEvictionFails() throws IOException {
|
||||
String source = source("IrisModdedChunkGenerator.java");
|
||||
String unbind = method(source, "synchronized void unbindEngine(ServerLevel level)");
|
||||
|
||||
assertFalse(unbind.contains("finally"));
|
||||
assertBefore(unbind, "unloading = true;", "ModdedWorldEngines.evictOrThrow(level);");
|
||||
assertBefore(unbind, "ModdedWorldEngines.evictOrThrow(level);", "clearEngineBinding();");
|
||||
String binding = method(source, "private Engine bindEngine(ServerLevel level)");
|
||||
assertTrue(binding.contains("requireBindingAllowed();"));
|
||||
assertTrue(binding.contains("requireCompletedShutdown(cached);"));
|
||||
String bindLevel = method(source, "synchronized void bindLevel(ServerLevel level)");
|
||||
assertBefore(bindLevel, "requireCompletedShutdown(engine);", "unloading = false;");
|
||||
String boundEngine = method(source, "public Engine engineIfBound()");
|
||||
assertTrue(boundEngine.contains("unloading || current == null || current.isClosing() || current.isClosed()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loaderUnloadSurfacesCloseFailureAndDynamicRemovalUsesStrictEviction() throws IOException {
|
||||
String bootstrapSource = source("ModdedEngineBootstrap.java");
|
||||
String unload = method(bootstrapSource, "public static void levelUnloaded(ServerLevel level)");
|
||||
String failure = catchBlock(unload);
|
||||
assertTrue(failure.contains("ModdedIrisLog.error("));
|
||||
assertTrue(failure.contains("throw "));
|
||||
|
||||
String managerSource = source("ModdedDimensionManager.java");
|
||||
String remove = method(managerSource, "public static boolean remove(MinecraftServer server, String dimensionId, boolean wipeStorage)");
|
||||
assertTrue(remove.contains("ModdedWorldEngines.evictOrThrow(level);"));
|
||||
assertFalse(remove.contains("ModdedWorldEngines.evict(level);"));
|
||||
assertTrue(remove.contains("unloadEventStarted = true;"));
|
||||
assertTrue(remove.contains("rollbackRemoval(server, serverAccess, key, level, generator, unloadEventStarted, e);"));
|
||||
|
||||
String rollback = method(managerSource, "private static void rollbackRemoval(");
|
||||
assertTrue(rollback.contains("serverAccess.hasLevel(server, key)"));
|
||||
assertTrue(rollback.contains("generator.bindLevel(level);"));
|
||||
assertTrue(rollback.contains("failure.addSuppressed(rollbackFailure);"));
|
||||
assertTrue(rollback.contains("ModdedIrisLog.error("));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineBootstrapRollsBackEveryPublishedBindingBeforeRethrowing() throws IOException {
|
||||
String source = source("ModdedEngineBootstrap.java");
|
||||
String bind = method(source, "public static ModdedPlatform bind(");
|
||||
String failure = catchBlock(bind);
|
||||
|
||||
assertBefore(bind, "createdServices.enableAll();", "runtime = new BoundRuntime(");
|
||||
assertTrue(bind.contains("rollback.add(() -> GuiHost.suppressDesktop("));
|
||||
assertTrue(bind.contains("rollback.add(() -> restorePlatform("));
|
||||
assertTrue(bind.contains("rollback.add(() -> ModdedDimensionManager.restoreAccess("));
|
||||
assertTrue(bind.contains("rollback.add(() -> IrisObjectRotation.restorePlatformRotator("));
|
||||
assertTrue(bind.contains("rollback.add(() -> BlockDataMergeSupport.restorePlatformMerger("));
|
||||
assertTrue(bind.contains("rollback.add(() -> TileData.restorePlatformReader("));
|
||||
assertTrue(bind.contains("rollback.add(() -> TileData.restorePlatformFactory("));
|
||||
assertTrue(bind.contains("rollback.add(() -> GuiHost.set("));
|
||||
assertTrue(bind.contains("rollback.add(() -> DecoratorPlatformHooks.restore("));
|
||||
assertTrue(bind.contains("bindService(PreservationRegistry.class"));
|
||||
assertTrue(bind.contains("bindService(EngineEffectsProvider.class"));
|
||||
assertTrue(bind.contains("bindService(EnginePlatformHooks.class"));
|
||||
assertTrue(bind.contains("bindService(EngineWorldManagerProvider.class"));
|
||||
assertTrue(bind.contains("rollback.add(customContentDiscovery::rollback);"));
|
||||
assertBefore(failure, "createdServices.rollback(failure);", "rollback.restore(failure);");
|
||||
assertBefore(failure, "rollback.restore(failure);", "throw ");
|
||||
}
|
||||
|
||||
private static void assertBefore(String source, String first, String second) {
|
||||
int firstIndex = requiredIndex(source, first);
|
||||
int secondIndex = requiredIndex(source, second);
|
||||
assertTrue(first + " must occur before " + second, firstIndex < secondIndex);
|
||||
}
|
||||
|
||||
private static int requiredIndex(String source, String needle) {
|
||||
return requiredIndex(source, needle, 0);
|
||||
}
|
||||
|
||||
private static int requiredIndex(String source, String needle, int start) {
|
||||
int index = source.indexOf(needle, start);
|
||||
assertTrue("Missing source contract token: " + needle, index >= 0);
|
||||
return index;
|
||||
}
|
||||
|
||||
private static String source(String fileName) throws IOException {
|
||||
String sourceRoot = System.getProperty(SOURCE_ROOT_PROPERTY);
|
||||
assertTrue("Missing system property " + SOURCE_ROOT_PROPERTY,
|
||||
sourceRoot != null && !sourceRoot.isBlank());
|
||||
Path sourcePath = Path.of(sourceRoot, "art", "arcane", "iris", "modded", fileName);
|
||||
return Files.readString(sourcePath);
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = requiredIndex(source, signature);
|
||||
int openBrace = openingBrace(source, start);
|
||||
return source.substring(start, matchingBrace(source, openBrace) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block of the shallowest catch in the method, i.e. the one attached to the
|
||||
* method's outermost try. Textual first-match would return a nested catch instead, and a
|
||||
* nested catch handles a different failure than the one these contracts pin.
|
||||
*/
|
||||
private static String catchBlock(String source) {
|
||||
int bodyStart = openingBrace(source, 0);
|
||||
int depth = 0;
|
||||
int bestDepth = Integer.MAX_VALUE;
|
||||
int catchIndex = -1;
|
||||
int i = bodyStart;
|
||||
while (i < source.length()) {
|
||||
int skipped = skipNonCode(source, i);
|
||||
if (skipped > i) {
|
||||
i = skipped;
|
||||
continue;
|
||||
}
|
||||
char current = source.charAt(i);
|
||||
if (current == '{') {
|
||||
depth++;
|
||||
} else if (current == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
break;
|
||||
}
|
||||
} else if (current == 'c' && depth < bestDepth && source.startsWith("catch (", i)) {
|
||||
bestDepth = depth;
|
||||
catchIndex = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assertTrue("Missing source contract token: catch (", catchIndex >= 0);
|
||||
return blockAt(source, openingBrace(source, catchIndex));
|
||||
}
|
||||
|
||||
private static String blockAt(String source, int openBrace) {
|
||||
return source.substring(openBrace, matchingBrace(source, openBrace) + 1);
|
||||
}
|
||||
|
||||
private static int openingBrace(String source, int start) {
|
||||
int i = start;
|
||||
while (i < source.length()) {
|
||||
int skipped = skipNonCode(source, i);
|
||||
if (skipped > i) {
|
||||
i = skipped;
|
||||
continue;
|
||||
}
|
||||
if (source.charAt(i) == '{') {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
throw new IllegalArgumentException("No source block after offset " + start);
|
||||
}
|
||||
|
||||
private static int matchingBrace(String source, int openBrace) {
|
||||
int depth = 0;
|
||||
int i = openBrace;
|
||||
while (i < source.length()) {
|
||||
int skipped = skipNonCode(source, i);
|
||||
if (skipped > i) {
|
||||
i = skipped;
|
||||
continue;
|
||||
}
|
||||
char current = source.charAt(i);
|
||||
if (current == '{') {
|
||||
depth++;
|
||||
} else if (current == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
throw new IllegalArgumentException("Unclosed source block");
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances past a comment, string, char or text block starting at the index, otherwise returns
|
||||
* the index unchanged. Comments must be skipped: an apostrophe in prose ("generator's") would
|
||||
* otherwise open a char literal and swallow the rest of the file.
|
||||
*/
|
||||
private static int skipNonCode(String source, int index) {
|
||||
char current = source.charAt(index);
|
||||
if (current == '/' && index + 1 < source.length()) {
|
||||
char next = source.charAt(index + 1);
|
||||
if (next == '/') {
|
||||
int end = source.indexOf('\n', index);
|
||||
return end < 0 ? source.length() : end + 1;
|
||||
}
|
||||
if (next == '*') {
|
||||
int end = source.indexOf("*/", index + 2);
|
||||
return end < 0 ? source.length() : end + 2;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
if (current == '"' && source.startsWith("\"\"\"", index)) {
|
||||
int end = source.indexOf("\"\"\"", index + 3);
|
||||
return end < 0 ? source.length() : end + 3;
|
||||
}
|
||||
if (current == '"' || current == '\'') {
|
||||
return endOfLiteral(source, index, current);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private static int endOfLiteral(String source, int index, char terminator) {
|
||||
for (int i = index + 1; i < source.length(); i++) {
|
||||
char current = source.charAt(i);
|
||||
if (current == '\\') {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (current == terminator) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return source.length();
|
||||
}
|
||||
|
||||
private static int occurrences(String source, String needle) {
|
||||
int count = 0;
|
||||
int offset = 0;
|
||||
while (true) {
|
||||
int index = source.indexOf(needle, offset);
|
||||
if (index < 0) {
|
||||
return count;
|
||||
}
|
||||
count++;
|
||||
offset = index + needle.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
-37
@@ -5,13 +5,9 @@ import art.arcane.iris.engine.object.IrisEntitySpawn;
|
||||
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.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedSpawnerRarityParityTest {
|
||||
private static IrisEntitySpawn spawn(int rarity) {
|
||||
@@ -39,37 +35,4 @@ public class ModdedSpawnerRarityParityTest {
|
||||
assertEquals(1, IRare.get(spawn(-5)));
|
||||
assertEquals(3, IRare.get(spawn(3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void perPositionSpawnLoopsDoNotRerollEntryRarity() throws Exception {
|
||||
String source = Files.readString(Path.of(System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/ModdedWorldManager.java"));
|
||||
|
||||
for (String method : List.of("private int spawnEntry(", "private int spawnEntryAt(")) {
|
||||
String body = methodBody(source, method);
|
||||
assertFalse(method + " must not re-roll rarity per position; rarityPick already weighted the pool",
|
||||
body.contains("getRarity()"));
|
||||
assertTrue(method + " must keep the min/max spawn-count roll",
|
||||
body.contains("LootResolver.inclusive("));
|
||||
}
|
||||
}
|
||||
|
||||
private static String methodBody(String source, String declaration) {
|
||||
int start = source.indexOf(declaration);
|
||||
assertTrue("ModdedWorldManager must declare " + declaration, start >= 0);
|
||||
int open = source.indexOf('{', start);
|
||||
int depth = 0;
|
||||
for (int index = open; index < source.length(); index++) {
|
||||
char character = source.charAt(index);
|
||||
if (character == '{') {
|
||||
depth++;
|
||||
} else if (character == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
return source.substring(open + 1, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new AssertionError(declaration + " is not brace balanced");
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedStructurePlacementFailureContractTest {
|
||||
@Test
|
||||
public void structurePlacementPropagatesRuntimeFailuresWithContext() throws IOException {
|
||||
Path sourcePath = Path.of(System.getProperty("iris.moddedCommonSources"),
|
||||
"art/arcane/iris/modded/ModdedStructureHooks.java");
|
||||
String source = Files.readString(sourcePath);
|
||||
int methodStart = source.indexOf("public int[] placeStructure(");
|
||||
int methodEnd = source.indexOf("\n @Override", methodStart + 1);
|
||||
String method = source.substring(methodStart, methodEnd);
|
||||
int catchStart = method.indexOf("catch (RuntimeException error)");
|
||||
|
||||
assertTrue(catchStart >= 0);
|
||||
String failurePath = method.substring(catchStart);
|
||||
assertTrue(failurePath.contains("throw NativeStructureGenerationException.failure("));
|
||||
assertTrue(failurePath.contains("\"capture placement\", structureKey, chunkX, chunkZ, error"));
|
||||
assertFalse(failurePath.contains("return null;"));
|
||||
assertFalse(failurePath.contains("catch (Throwable"));
|
||||
}
|
||||
}
|
||||
+4
-11
@@ -4,8 +4,6 @@ import org.junit.Test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -64,14 +62,9 @@ public class ModdedStructureTemplateCacheTest {
|
||||
config = new String(input.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
assertTrue(config.contains("\"StructureTemplatePaletteConcurrencyMixin\""));
|
||||
|
||||
Path source = Path.of(System.getProperty("iris.moddedCommonSources"))
|
||||
.resolve("art/arcane/iris/modded/mixin/StructureTemplatePaletteConcurrencyMixin.java");
|
||||
String mixin = Files.readString(source);
|
||||
assertTrue(mixin.contains("@Mixin(StructureTemplate.Palette.class)"));
|
||||
assertTrue(mixin.contains("@Shadow\n @Final\n @Mutable"));
|
||||
assertTrue(mixin.contains("private Map<Block, List<StructureTemplate.StructureBlockInfo>> cache;"));
|
||||
assertTrue(mixin.contains("@Inject(method = \"<init>(Ljava/util/List;)V\", at = @At(\"RETURN\"))"));
|
||||
assertTrue(mixin.contains("cache = new ConcurrentHashMap<>();"));
|
||||
assertNotNull(Class.forName(
|
||||
"art.arcane.iris.modded.mixin.StructureTemplatePaletteConcurrencyMixin",
|
||||
false,
|
||||
ModdedStructureTemplateCacheTest.class.getClassLoader()));
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,6 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -26,32 +23,6 @@ public class ModdedWorldCheckTest {
|
||||
assertTrue(thread.isDaemon());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void poiAuditRunsInASecondServerTaskAfterVillageGeneration() throws IOException {
|
||||
Path sourceRoot = Path.of(System.getProperty("iris.moddedCommonSources"));
|
||||
String source = Files.readString(sourceRoot.resolve("art/arcane/iris/modded/ModdedWorldCheck.java"));
|
||||
String auditSource = Files.readString(
|
||||
sourceRoot.resolve("art/arcane/iris/modded/WorldCheckStructureAudit.java"));
|
||||
int preparationSubmit = source.indexOf(
|
||||
"WorldCheckPreparation preparation = serverRef.submit(() -> run(serverRef))");
|
||||
int completionSubmit = source.indexOf(
|
||||
"exitCode = serverRef.submit(() -> runAndRequestStop(", preparationSubmit);
|
||||
int completionMethod = source.indexOf("private static boolean completeWorldCheck");
|
||||
int deferredAudit = source.indexOf(
|
||||
"PoiAudit poi = WorldCheckStructureAudit.auditStructurePois", completionMethod);
|
||||
int structureMethod = auditSource.indexOf("private static StructureCheckResult checkNativeStructure");
|
||||
int structureMethodEnd = auditSource.indexOf("private static StructureStart resolveStructureStart",
|
||||
structureMethod);
|
||||
String structureSource = auditSource.substring(structureMethod, structureMethodEnd);
|
||||
|
||||
assertTrue(preparationSubmit >= 0);
|
||||
assertTrue(completionSubmit > preparationSubmit);
|
||||
assertTrue(deferredAudit > completionMethod);
|
||||
assertFalse(structureSource.contains("auditStructurePois"));
|
||||
assertFalse(source.contains("prepareDeferredAudits"));
|
||||
assertFalse(auditSource.contains("prepareDeferredAudits"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validStructureStartIsGenerationEvidence() {
|
||||
assertTrue(WorldCheckPredicates.hasNativeStructureEvidence(true, 0));
|
||||
|
||||
-90
@@ -6,11 +6,6 @@ import net.minecraft.server.Bootstrap;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -22,25 +17,6 @@ public class NativeStructureFailureContractTest {
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureLocateDoesNotCatchAndFallThroughToAnotherImplementation() throws IOException {
|
||||
String source = moddedSource("IrisModdedChunkGenerator.java");
|
||||
int locateStart = source.indexOf("public Pair<BlockPos, Holder<Structure>> findNearestMapStructure");
|
||||
int locateEnd = source.indexOf("public boolean isNativeStructureReachable", locateStart);
|
||||
String locate = source.substring(locateStart, locateEnd);
|
||||
String stage = moddedSource("ModdedNativeStructureStage.java");
|
||||
int filterStart = stage.indexOf("HolderSet<Structure> filterReachableNativeStructures");
|
||||
int filterEnd = stage.indexOf("void adjustGeneratedStructures", filterStart);
|
||||
String filter = stage.substring(filterStart, filterEnd);
|
||||
|
||||
assertTrue(locate.contains("Engine current = engine();"));
|
||||
assertFalse(locate.contains("catch (Throwable"));
|
||||
assertFalse(locate.contains("return null;\n } catch"));
|
||||
assertTrue(filter.contains("unregistered structure holder"));
|
||||
assertFalse(filter.contains("catch (Throwable"));
|
||||
assertFalse(filter.contains("failed closed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void globalStructureDisableRefusesGeneratorBinding() {
|
||||
IrisModdedChunkGenerator.requireGlobalStructureGeneration(true, "overworld:overworld");
|
||||
@@ -56,66 +32,6 @@ public class NativeStructureFailureContractTest {
|
||||
assertTrue(error.getMessage().contains("importedStructures.disabledExact"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureVegetationCleanupPrecedesTerrainPreparationAndPlacement() throws IOException {
|
||||
String source = moddedSource("ModdedNativeStructureStage.java");
|
||||
int placementStart = source.indexOf("void placeVanillaStructures");
|
||||
int placementEnd = source.indexOf("private static String nativeStructureBatchContext", placementStart);
|
||||
String placement = source.substring(placementStart, placementEnd);
|
||||
|
||||
assertTrue(placement.contains("\"terrain integration\""));
|
||||
assertTrue(placement.contains("\"terrain preparation\""));
|
||||
assertTrue(placement.contains("\"foundation repair\""));
|
||||
assertFalse(placement.contains("\"terrain carving\""));
|
||||
assertTrue(placement.contains("visitExistingPois(chunk"));
|
||||
assertTrue(placement.contains("level.updatePOIOnBlockStateChange("));
|
||||
assertTrue(placement.contains("Blocks.AIR.defaultBlockState(), state"));
|
||||
assertTrue(placement.indexOf("visitExistingPois(chunk")
|
||||
< placement.indexOf("WorldgenTerrainHeightmaps.primeStructurePlacement("));
|
||||
assertTrue(placement.contains("prepareSurfaceStructures"));
|
||||
assertTrue(placement.contains("clearIntersectingVegetation"));
|
||||
assertTrue(placement.indexOf("clearIntersectingVegetation")
|
||||
< placement.indexOf("prepareSurfaceStructures"));
|
||||
assertTrue(placement.indexOf("prepareSurfaceStructures")
|
||||
< placement.indexOf("for (NativePlacementGroup group"));
|
||||
assertTrue(placement.indexOf("repairVacuumFoundations")
|
||||
> placement.indexOf("for (NativePlacementGroup group"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structurePlacementPrimesNeighbourWorldgenHeightmapsBeforeTerrainPreparation() throws IOException {
|
||||
String source = moddedSource("ModdedNativeStructureStage.java");
|
||||
int placementStart = source.indexOf("void placeVanillaStructures");
|
||||
int placementEnd = source.indexOf("private static String nativeStructureBatchContext", placementStart);
|
||||
String placement = source.substring(placementStart, placementEnd);
|
||||
|
||||
assertTrue(source.contains("import art.arcane.iris.nativegen.WorldgenTerrainHeightmaps;"));
|
||||
assertTrue(placement.contains("WorldgenTerrainHeightmaps.primeStructurePlacement("));
|
||||
assertTrue(placement.contains("\"heightmap priming\""));
|
||||
assertTrue(placement.contains("heightmapStarts.add(start);"));
|
||||
assertTrue(placement.indexOf("WorldgenTerrainHeightmaps.primeStructurePlacement(")
|
||||
< placement.indexOf("prepareSurfaceStructures"));
|
||||
assertTrue(source.contains("Engine.hostHeight(generationEngine, x, z, false) + runtimeMinY + 1"));
|
||||
assertTrue(source.contains("Engine.hostHeight(generationEngine, x, z, true) + runtimeMinY + 1"));
|
||||
assertTrue(placement.contains("current.getDimensionStackContext() != null"));
|
||||
assertTrue(source.contains("int minY = chunk.getMinY() + 1;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nativeStructurePostProcessingUsesBoundedWorldgenAccess() throws IOException {
|
||||
String source = moddedSource("ModdedNativeStructureStage.java");
|
||||
int placementStart = source.indexOf("void placeVanillaStructures");
|
||||
int placementEnd = source.indexOf("private List<List<Structure>> structuresByStep", placementStart);
|
||||
String placement = source.substring(placementStart, placementEnd);
|
||||
|
||||
assertTrue(placement.contains("ModdedNativeStructureWorldgenAccess.create("));
|
||||
assertTrue(placement.contains("nativeStructureProtection(current, staticObjects)"));
|
||||
assertTrue(placement.contains("Engine.hostHeight(current, x, z, true)"));
|
||||
assertTrue(placement.contains("placeVanillaStructure(boundedWorld, structureManager"));
|
||||
assertFalse(placement.contains("NativeStructurePostProcessor.place(world,"));
|
||||
assertTrue(placement.contains("world.setCurrentlyGenerating(null);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureFailurePreservesPhaseIdentityChunkAndCause() {
|
||||
IllegalArgumentException cause = new IllegalArgumentException("broken placement");
|
||||
@@ -128,10 +44,4 @@ public class NativeStructureFailureContractTest {
|
||||
assertTrue(error.getMessage().contains("12,-8"));
|
||||
assertTrue(error.getMessage().contains("aborted"));
|
||||
}
|
||||
|
||||
private static String moddedSource(String fileName) throws IOException {
|
||||
Path sourcePath = Path.of(System.getProperty("iris.moddedCommonSources"),
|
||||
"art", "arcane", "iris", "modded", fileName);
|
||||
return Files.readString(sourcePath);
|
||||
}
|
||||
}
|
||||
-183
@@ -7,9 +7,6 @@ import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -48,30 +45,6 @@ public class IrisModdedStructureCommandTest {
|
||||
assertEquals(1, nativeReferences.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gotoStructureSupportsIrisAndNativeRegistryTargets() throws IOException {
|
||||
String source = source("ModdedLocateCommands.java");
|
||||
String suggestions = source("ModdedCommandSuggestions.java");
|
||||
|
||||
assertTrue(source.contains("IrisStructureLocator.hasLocatableEditablePlacement(engine, key)"));
|
||||
assertTrue(source.contains("registry.get(identifier)"));
|
||||
assertTrue(source.contains("getPlacementsForStructure(holder)"));
|
||||
assertTrue(source.contains("generator.findNearestMapStructure("));
|
||||
assertTrue(source.contains("NATIVE_STRUCTURE_LOCATE_RADIUS = 100"));
|
||||
assertTrue(source.contains("HolderSet.direct(target.holder())"));
|
||||
assertFalse(source.contains("NativeStructureLocateCapability"));
|
||||
assertTrue(source.contains("boolean teleported = player.teleportTo("));
|
||||
assertTrue(suggestions.contains("combineStructureKeys(unregisteredIrisKeys, nativeKeys)"));
|
||||
assertTrue(source.contains("irisGenerator.isNativeStructureReachable(holder)"));
|
||||
assertTrue(source.contains("LocateStatus.SEARCH_LIMIT_REACHED"));
|
||||
assertTrue(source.contains("IRIS_MODDED_COMMANDS_UNABLE_LOCATE_IRIS_PLACED_STRUCTURE_DENSITY_SEARCH_SAFETY_LIMIT_WAS"));
|
||||
assertTrue(source.contains("int targetX = result.originX()"));
|
||||
assertTrue(source.contains("int targetY = result.baseY() + 2"));
|
||||
assertTrue(source.contains("int targetZ = result.originZ()"));
|
||||
assertFalse(source.contains("at[0] + 8"));
|
||||
assertFalse(source.contains("at[2] + 8"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registeredStructureEligibilityMatchesGotoAndSuggestions() {
|
||||
IrisNativeStructureDecision nativeDecision = decision(NativeStructureGenerationStatus.GENERATE_NATIVE);
|
||||
@@ -175,162 +148,6 @@ public class IrisModdedStructureCommandTest {
|
||||
.contains("non-positive density or a Y band outside"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unregisteredCommandUsesGotoEligibilityAndPrintsToConsole() throws IOException {
|
||||
String command = source("ModdedUnregisteredStructures.java");
|
||||
String tree = source("ModdedCommandTree.java");
|
||||
|
||||
assertTrue(tree.contains("Commands.literal(\"unregistered\")"));
|
||||
assertTrue(tree.contains("ModdedUnregisteredStructures.print(context.getSource())"));
|
||||
assertTrue(command.contains("ModdedCommandSuggestions.isEligibleRegisteredStructure("));
|
||||
assertTrue(command.contains("ModdedLocateCommands.registeredStructureUnavailableMessage("));
|
||||
assertTrue(command.contains("engine.getData().getStructureLoader().getPossibleKeys()"));
|
||||
assertTrue(command.contains("IrisStructureLocator.hasLocatableEditablePlacement(engine, key)"));
|
||||
assertTrue(command.contains("ModdedIrisLog.info(\"[Iris goto unregistered] [{}] {} - {}\""));
|
||||
assertTrue(command.contains("UNREGISTERED(\"unregistered\")"));
|
||||
assertFalse(command.contains("DatapackIngestService"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureSuggestionsUseActiveLevelAvailability() throws IOException {
|
||||
String suggestions = source("ModdedCommandSuggestions.java");
|
||||
int methodStart = suggestions.indexOf("static CompletableFuture<Suggestions> suggestStructureKeys(");
|
||||
int methodEnd = suggestions.indexOf("static boolean isEligibleRegisteredStructure(", methodStart);
|
||||
String method = suggestions.substring(methodStart, methodEnd);
|
||||
|
||||
assertTrue(method.contains("ServerLevel level = source.getLevel()"));
|
||||
assertTrue(method.contains("Engine engine = IrisModdedCommands.engineFor(level)"));
|
||||
assertFalse(method.contains("IrisStructureLocator.locatableKeys(engine)"));
|
||||
assertTrue(method.contains("IrisStructureLocator.locatableEditableKeys(engine)"));
|
||||
assertTrue(method.contains("StructureReachability.reachableKeys(engine)"));
|
||||
assertTrue(method.contains("NativeStructureGenerationPolicy.resolve(engine, key, false)"));
|
||||
assertTrue(method.contains("IrisStructureLocator.hasLocatableNativePlacement(engine, key)"));
|
||||
assertTrue(method.contains("IrisStructureLocator.hasLocatableEditablePlacement(engine, key)"));
|
||||
assertTrue(method.contains("reachableNativeKeys.contains(normalizeKey(key))"));
|
||||
assertTrue(method.contains("nativeGenerationEnabled"));
|
||||
assertTrue(method.contains("eligibleUnregisteredEditableKeys("));
|
||||
assertTrue(method.contains("IrisStructureLocator.hasNativePlacement(engine, candidate)"));
|
||||
assertFalse(method.contains("NativeStructureGenerationKeys.active(level)"));
|
||||
assertFalse(method.contains("getPlacementsForStructure"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generatorLocateUsesEveryIrisPlacedNativeStructure() throws IOException {
|
||||
String source = moddedSource("ModdedNativeStructureStage.java");
|
||||
int methodStart = source.indexOf("Pair<BlockPos, Holder<Structure>> findNearestIrisStructure(");
|
||||
int methodEnd = source.indexOf("HolderSet<Structure> filterReachableNativeStructures(", methodStart);
|
||||
String method = source.substring(methodStart, methodEnd);
|
||||
int registryLookup = method.indexOf("level.registryAccess().lookupOrThrow(Registries.STRUCTURE)");
|
||||
int placedCheck = method.indexOf(
|
||||
"if (!IrisStructureLocator.hasNativePlacement(current, structureId))");
|
||||
int irisLocate = method.indexOf("NativeStructureLocatePersistence.search(", placedCheck);
|
||||
int nearestSelection = method.indexOf(
|
||||
"NativeStructureLocateResults.nearest(pos, predicted, nativeLocated)", irisLocate);
|
||||
int selectedVerification = method.indexOf("bestSearch.search().verify(bestResult)", nearestSelection);
|
||||
int selectedReference = method.indexOf(
|
||||
"selectedSearch.search().reference(selectedStart)", selectedVerification);
|
||||
|
||||
assertTrue(registryLookup >= 0);
|
||||
assertTrue(placedCheck > registryLookup);
|
||||
assertTrue(irisLocate > placedCheck);
|
||||
assertTrue(nearestSelection > irisLocate);
|
||||
assertTrue(selectedVerification > nearestSelection);
|
||||
assertTrue(selectedReference > selectedVerification);
|
||||
assertTrue(method.contains("NativeStructureLocatePersistence.probe("));
|
||||
assertTrue(method.contains("findUnexplored"));
|
||||
assertTrue(method.contains("LocateStatus.SEARCH_LIMIT_REACHED"));
|
||||
assertTrue(method.contains("verified.ownership().locatorY()"));
|
||||
assertTrue(method.contains("selectedSearch.search().reference(selectedStart)"));
|
||||
assertTrue(method.contains("NativeStructureLocateResults.selectAndReference("));
|
||||
assertFalse(method.contains("NativeStructureLocateCapability"));
|
||||
assertTrue(source.contains("structureBiomeSource.isStructureReachable(holder)"));
|
||||
assertFalse(source.contains("isPaperUnavailable"));
|
||||
String generator = moddedSource("IrisModdedChunkGenerator.java");
|
||||
assertTrue(generator.contains("NativeStructureVanillaLocator.predict("));
|
||||
assertFalse(generator.contains("super.findNearestMapStructure(level, reachable"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void commandResolvesNativePolicyBeforeAnyVanillaAliasLookup() throws IOException {
|
||||
String source = source("ModdedLocateCommands.java");
|
||||
int methodStart = source.indexOf("static int gotoStructure(");
|
||||
int methodEnd = source.indexOf("private static void locateIrisStructure(", methodStart);
|
||||
String method = source.substring(methodStart, methodEnd);
|
||||
int nativeResolution = method.indexOf("resolveNativeStructure(source, level, engine, key)");
|
||||
int editableIrisLookup = method.indexOf(
|
||||
"IrisStructureLocator.hasLocatableEditablePlacement(engine, key)", nativeResolution);
|
||||
int policyResolution = method.indexOf(
|
||||
"NativeStructureGenerationPolicy.resolve(engine, target.key(), false)", editableIrisLookup);
|
||||
int eligibilityCheck = method.indexOf(
|
||||
"ModdedCommandSuggestions.isEligibleRegisteredStructure(", policyResolution);
|
||||
int replacementLocate = method.indexOf(
|
||||
"locateIrisStructure(source, level, engine, player, target.key())", eligibilityCheck);
|
||||
int nativeLocate = method.indexOf("runNativeStructureLocate(source, level, player, target)",
|
||||
replacementLocate);
|
||||
|
||||
assertTrue(nativeResolution >= 0);
|
||||
assertTrue(editableIrisLookup > nativeResolution);
|
||||
assertTrue(policyResolution > editableIrisLookup);
|
||||
assertTrue(eligibilityCheck > policyResolution);
|
||||
assertTrue(replacementLocate > eligibilityCheck);
|
||||
assertTrue(nativeLocate > replacementLocate);
|
||||
assertTrue(method.contains("IrisStructureLocator.hasLocatableNativePlacement(engine, target.key())"));
|
||||
assertTrue(method.contains("IrisStructureLocator.hasLocatableEditablePlacement(engine, target.key())"));
|
||||
assertTrue(method.contains("!IrisStructureLocator.hasNativePlacement(engine, key)"));
|
||||
assertTrue(method.contains("StructureReachability.isReachable(engine, target.key())"));
|
||||
assertTrue(method.contains("getWorldGenSettings().options().generateStructures()"));
|
||||
assertFalse(method.contains("IrisStructureLocator.isPlaced(engine, key)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyResolvesRegisteredNativeBeforeGenericIrisAliases() throws IOException {
|
||||
String source = source("ModdedLocateCommands.java");
|
||||
int methodStart = source.indexOf("private static int verifyStructure(");
|
||||
int methodEnd = source.indexOf("private static Optional<NativeStructureTarget> resolveNativeStructure(",
|
||||
methodStart);
|
||||
String method = source.substring(methodStart, methodEnd);
|
||||
int nativeResolution = method.indexOf("resolveNativeStructure(source, level, engine, key)");
|
||||
int genericIrisLookup = method.indexOf("IrisStructureLocator.isPlaced(engine, key)", nativeResolution);
|
||||
|
||||
assertTrue(nativeResolution >= 0);
|
||||
assertTrue(genericIrisLookup > nativeResolution);
|
||||
assertTrue(method.contains("NativeStructureAvailability.IRIS_SUPPRESSED"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureVerificationNoLongerClaimsNativeGenerationIsMissing() throws IOException {
|
||||
String source = source("ModdedStructureCommands.java");
|
||||
|
||||
assertTrue(source.contains("verifyTree(\"verify\")"));
|
||||
assertTrue(source.contains("verifyTree(\"locateall\")"));
|
||||
assertTrue(source.contains("IrisModdedCommands.verifyStructures("));
|
||||
assertFalse(source.contains("Vanilla structure locate is meaningless here"));
|
||||
}
|
||||
|
||||
private String source(String fileName) throws IOException {
|
||||
Path source = commonSourceRoot().resolve("art/arcane/iris/modded/command/")
|
||||
.resolve(fileName)
|
||||
.normalize();
|
||||
return Files.readString(source);
|
||||
}
|
||||
|
||||
private String moddedSource(String fileName) throws IOException {
|
||||
Path source = commonSourceRoot().resolve("art/arcane/iris/modded/")
|
||||
.resolve(fileName)
|
||||
.normalize();
|
||||
return Files.readString(source);
|
||||
}
|
||||
|
||||
private Path commonSourceRoot() {
|
||||
String configuredRoot = System.getProperty("iris.moddedCommonSources");
|
||||
if (configuredRoot != null && !configuredRoot.isBlank()) {
|
||||
return Path.of(configuredRoot);
|
||||
}
|
||||
return Path.of(System.getProperty("user.dir"))
|
||||
.resolve("../modded-common/src/main/java")
|
||||
.normalize();
|
||||
}
|
||||
|
||||
private IrisNativeStructureDecision decision(NativeStructureGenerationStatus status) {
|
||||
return new IrisNativeStructureDecision(status, 0, null, false, null, null);
|
||||
}
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public final class ModdedRiverLocateContractTest {
|
||||
@Test
|
||||
public void riverLookupMergesRecordedAndEligibleActiveFeatures() throws IOException {
|
||||
Path sourcePath = Path.of(System.getProperty("iris.moddedCommonSources"))
|
||||
.resolve("art/arcane/iris/modded/command/ModdedLocateCommands.java");
|
||||
String source = Files.readString(sourcePath);
|
||||
int methodStart = source.indexOf("static int gotoRiver(");
|
||||
int methodEnd = source.indexOf("static int gotoStructure(", methodStart);
|
||||
String method = source.substring(methodStart, methodEnd);
|
||||
|
||||
assertTrue(method.contains("GenerationSemanticQueries.nearestRiver("));
|
||||
assertTrue(method.contains("runtime == null"));
|
||||
assertTrue(method.contains("feature.y() + 2"));
|
||||
assertFalse(method.contains("runtime.nearestFeature("));
|
||||
assertFalse(method.contains("feature.y() + engine.getDimension().getMinHeight()"));
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public final class ModdedStructureHistoryContractTest {
|
||||
@Test
|
||||
public void retainedStructureNamesReachTheSemanticSearchOnBothAdmissionBranches() throws IOException {
|
||||
Path root = Path.of(System.getProperty("iris.moddedCommonSources"));
|
||||
String source = Files.readString(root.resolve("art/arcane/iris/modded/command/ModdedLocateCommands.java"));
|
||||
int start = source.indexOf("static int gotoStructure(");
|
||||
int end = source.indexOf("static String registeredStructureUnavailableMessage(", start);
|
||||
String admission = source.substring(start, end);
|
||||
String retainedCheck = "GenerationFindCatalog.hasRetainedStructurePlacement(engine, key)";
|
||||
int firstCheck = admission.indexOf(retainedCheck);
|
||||
assertTrue(firstCheck >= 0);
|
||||
assertTrue(admission.indexOf(retainedCheck, firstCheck + retainedCheck.length()) >= 0);
|
||||
|
||||
int locateStart = source.indexOf("private static void locateIrisStructure(");
|
||||
int locateEnd = source.indexOf("private static void runNativeStructureLocate(", locateStart);
|
||||
String locate = source.substring(locateStart, locateEnd);
|
||||
assertTrue(locate.contains("GenerationSemanticQueries.nearestStructure("));
|
||||
assertFalse(locate.contains("IrisStructureLocator.locate("));
|
||||
|
||||
String suggestions = Files.readString(root.resolve("art/arcane/iris/modded/command/ModdedCommandSuggestions.java"));
|
||||
assertTrue(suggestions.contains("GenerationFindCatalog.retainedStructureKeys(engine)"));
|
||||
}
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ModdedStudioTeleportContractTest {
|
||||
private static final String SOURCE_ROOT_PROPERTY = "iris.moddedCommonSources";
|
||||
|
||||
@Test
|
||||
public void studioOpenSerializesReplacementAndWaitsForTheNativePath() throws IOException {
|
||||
String source = source("command/ModdedStudioCommands.java");
|
||||
String open = method(source, "private static int open(");
|
||||
String execute = method(source, "private static void executeStudioOpen(");
|
||||
|
||||
assertTrue(open.contains("TRANSITIONS.submit("));
|
||||
assertFalse(open.contains("orTimeout("));
|
||||
assertFalse(open.contains("deadlineNanos"));
|
||||
assertBefore(execute, "replaceExistingStudio(", "ModdedDimensionManager.createTransientStudio(");
|
||||
assertBefore(execute, "ModdedDimensionManager.createTransientStudio(", "ModdedDimensionManager.teleportAsync(");
|
||||
assertFalse(execute.contains("deadlineNanos"));
|
||||
assertFalse(source.contains("player.teleportTo(studio"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void studioTeleportAndVisionShareWarmFutureSemantics() throws IOException {
|
||||
String studio = source("command/ModdedStudioCommands.java");
|
||||
String vision = source("command/ModdedVisionOverlay.java");
|
||||
String dimensions = source("ModdedDimensionManager.java");
|
||||
|
||||
assertTrue(studio.contains("private static CompletableFuture<Void> teleportToStudio("));
|
||||
assertTrue(studio.contains("ModdedDimensionManager.teleportAsync("));
|
||||
assertTrue(dimensions.contains("TELEPORT_WARM_RADIUS = 0"));
|
||||
assertTrue(dimensions.contains("addTicketAndLoadWithRadius(\n"
|
||||
+ " TELEPORT_WARM_TICKET,\n"
|
||||
+ " chunkPos,\n"
|
||||
+ " TELEPORT_WARM_RADIUS)"));
|
||||
assertTrue(dimensions.contains("removeTicketWithRadius(\n"
|
||||
+ " TELEPORT_WARM_TICKET,\n"
|
||||
+ " chunkPos,\n"
|
||||
+ " TELEPORT_WARM_RADIUS)"));
|
||||
assertTrue(vision.contains("Math.floor(worldX)"));
|
||||
assertTrue(vision.contains("Math.floor(worldZ)"));
|
||||
assertTrue(vision.contains("if (opener != null)"));
|
||||
assertTrue(vision.contains("ModdedDimensionManager.teleportAsync("));
|
||||
assertFalse(vision.contains("level.getHeight("));
|
||||
assertFalse(vision.contains("player.teleportTo("));
|
||||
}
|
||||
|
||||
private static String source(String relative) throws IOException {
|
||||
String root = System.getProperty(SOURCE_ROOT_PROPERTY);
|
||||
if (root == null || root.isBlank()) {
|
||||
throw new IllegalStateException("Missing test property " + SOURCE_ROOT_PROPERTY);
|
||||
}
|
||||
return Files.readString(Path.of(root).resolve("art/arcane/iris/modded").resolve(relative))
|
||||
.replace("\r\n", "\n");
|
||||
}
|
||||
|
||||
private static String method(String source, String signature) {
|
||||
int start = source.indexOf(signature);
|
||||
if (start < 0) {
|
||||
throw new IllegalArgumentException("Missing source method " + signature);
|
||||
}
|
||||
int open = source.indexOf('{', start);
|
||||
int depth = 0;
|
||||
for (int index = open; index < source.length(); index++) {
|
||||
char current = source.charAt(index);
|
||||
if (current == '{') {
|
||||
depth++;
|
||||
} else if (current == '}' && --depth == 0) {
|
||||
return source.substring(start, index + 1);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unclosed source method " + signature);
|
||||
}
|
||||
|
||||
private static void assertBefore(String source, String first, String second) {
|
||||
int firstIndex = source.indexOf(first);
|
||||
int secondIndex = source.indexOf(second);
|
||||
assertTrue("Missing source token " + first, firstIndex >= 0);
|
||||
assertTrue("Missing source token " + second, secondIndex >= 0);
|
||||
assertTrue(first + " must precede " + second, firstIndex < secondIndex);
|
||||
}
|
||||
}
|
||||
@@ -222,7 +222,6 @@ tasks.named('compileJava', JavaCompile).configure {
|
||||
|
||||
tasks.named('test').configure {
|
||||
useJUnitPlatform()
|
||||
systemProperty('iris.moddedCommonSources', file('../modded-common/src/main/java').absolutePath)
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
||||
Reference in new issue
Block a user