O-o .o-o. o-O

This commit is contained in:
Brian Neumann-Fopiano committed 2026-07-12 20:53:51 -04:00
1 parent cd05fd1bca
commit 4dea984d77
30 files changed
+2363 -176

No files matched your search

@@ -0,0 +1,199 @@
package art.arcane.iris;
import io.papermc.paper.datapack.Datapack;
import io.papermc.paper.datapack.DatapackRegistrar;
import io.papermc.paper.datapack.DatapackSource;
import io.papermc.paper.datapack.DiscoveredDatapack;
import io.papermc.paper.plugin.configuration.PluginMeta;
import net.kyori.adventure.text.Component;
import org.bukkit.FeatureFlag;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class IrisBootstrapTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void discoverPackAutoEnablesAtFixedTop() throws Exception {
File datapackDirectory = temporaryFolder.newFolder("datapack");
RecordingRegistrar registrar = new RecordingRegistrar(DiscoveryBehavior.ACCEPT);
DiscoveredDatapack discovered = IrisBootstrap.discoverPack(registrar, datapackDirectory.toPath());
assertSame(registrar.discoveredDatapack, discovered);
assertEquals(datapackDirectory.toPath(), registrar.discoveredPath);
assertEquals(IrisBootstrap.PACK_ID, registrar.discoveredId);
assertTrue(registrar.configurer.autoEnableOnServerStart);
assertTrue(registrar.configurer.fixedPosition);
assertEquals(Datapack.Position.TOP, registrar.configurer.position);
}
@Test
public void rejectedDiscoveryReportsDatapackPath() throws Exception {
File datapackDirectory = temporaryFolder.newFolder("datapack");
RecordingRegistrar registrar = new RecordingRegistrar(DiscoveryBehavior.REJECT);
IllegalStateException failure = assertThrows(
IllegalStateException.class,
() -> IrisBootstrap.discoverPack(registrar, datapackDirectory.toPath())
);
assertTrue(failure.getMessage().contains(datapackDirectory.toPath().toString()));
}
@Test
public void discoveryIoFailurePropagates() throws Exception {
File datapackDirectory = temporaryFolder.newFolder("datapack");
RecordingRegistrar registrar = new RecordingRegistrar(DiscoveryBehavior.FAIL);
IOException failure = assertThrows(
IOException.class,
() -> IrisBootstrap.discoverPack(registrar, datapackDirectory.toPath())
);
assertEquals("discovery failed", failure.getMessage());
}
private enum DiscoveryBehavior {
ACCEPT,
REJECT,
FAIL
}
private static final class RecordingConfigurer implements DatapackRegistrar.Configurer {
private boolean autoEnableOnServerStart;
private boolean fixedPosition;
private Datapack.Position position;
@Override
public DatapackRegistrar.Configurer title(Component title) {
return this;
}
@Override
public DatapackRegistrar.Configurer autoEnableOnServerStart(boolean autoEnableOnServerStart) {
this.autoEnableOnServerStart = autoEnableOnServerStart;
return this;
}
@Override
public DatapackRegistrar.Configurer position(boolean fixed, Datapack.Position position) {
this.fixedPosition = fixed;
this.position = position;
return this;
}
}
private static final class RecordingRegistrar implements DatapackRegistrar {
private final DiscoveryBehavior behavior;
private final RecordingConfigurer configurer;
private final DiscoveredDatapack discoveredDatapack;
private Path discoveredPath;
private String discoveredId;
private RecordingRegistrar(DiscoveryBehavior behavior) {
this.behavior = behavior;
this.configurer = new RecordingConfigurer();
this.discoveredDatapack = new StubDiscoveredDatapack();
}
@Override
public boolean hasPackDiscovered(String name) {
return false;
}
@Override
public DiscoveredDatapack getDiscoveredPack(String name) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeDiscoveredPack(String name) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, DiscoveredDatapack> getDiscoveredPacks() {
return Collections.emptyMap();
}
@Override
public DiscoveredDatapack discoverPack(URI uri, String id, Consumer<Configurer> configurer) {
throw new UnsupportedOperationException();
}
@Override
public DiscoveredDatapack discoverPack(Path path, String id, Consumer<Configurer> configurer) throws IOException {
this.discoveredPath = path;
this.discoveredId = id;
if (behavior == DiscoveryBehavior.FAIL) {
throw new IOException("discovery failed");
}
configurer.accept(this.configurer);
return behavior == DiscoveryBehavior.ACCEPT ? discoveredDatapack : null;
}
@Override
public DiscoveredDatapack discoverPack(PluginMeta pluginMeta, URI uri, String id, Consumer<Configurer> configurer) {
throw new UnsupportedOperationException();
}
@Override
public DiscoveredDatapack discoverPack(PluginMeta pluginMeta, Path path, String id, Consumer<Configurer> configurer) {
throw new UnsupportedOperationException();
}
}
private static final class StubDiscoveredDatapack implements DiscoveredDatapack {
@Override
public String getName() {
return IrisBootstrap.PACK_ID;
}
@Override
public Component getTitle() {
return Component.text(IrisBootstrap.PACK_ID);
}
@Override
public Component getDescription() {
return Component.empty();
}
@Override
public boolean isRequired() {
return true;
}
@Override
public Datapack.Compatibility getCompatibility() {
return Datapack.Compatibility.COMPATIBLE;
}
@Override
public Set<FeatureFlag> getRequiredFeatures() {
return Collections.emptySet();
}
@Override
public DatapackSource getSource() {
throw new UnsupportedOperationException();
}
}
}
@@ -0,0 +1,59 @@
package art.arcane.iris;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoadOrder;
import org.junit.Test;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class PaperPluginMetadataTest {
@Test
public void paperMetadataDeclaresBootstrapAndFoliaSupport() throws Exception {
String metadata;
try (InputStream stream = PaperPluginMetadataTest.class.getResourceAsStream("/paper-plugin.yml")) {
assertNotNull(stream);
metadata = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
}
assertTrue(metadata.contains("bootstrapper: " + IrisBootstrap.class.getName()));
assertTrue(metadata.contains("folia-supported: true"));
assertTrue(metadata.contains("load: STARTUP"));
assertFalse(metadata.contains("commands:"));
}
@Test
public void bukkitMetadataRetainsStartupCommandAndAliases() throws Exception {
PluginDescriptionFile metadata;
try (InputStream stream = PaperPluginMetadataTest.class.getResourceAsStream("/plugin.yml")) {
assertNotNull(stream);
metadata = new PluginDescriptionFile(stream);
}
assertEquals(Iris.class.getName(), metadata.getMain());
assertEquals(PluginLoadOrder.STARTUP, metadata.getLoad());
Map<String, Map<String, Object>> commands = metadata.getCommands();
assertTrue(commands.containsKey("iris"));
assertEquals(List.of("ir", "irs"), commands.get("iris").get("aliases"));
}
@Test
public void processedResourcesContainBothMetadataFormats() throws Exception {
URL paperMetadata = PaperPluginMetadataTest.class.getResource("/paper-plugin.yml");
assertNotNull(paperMetadata);
assertEquals("file", paperMetadata.getProtocol());
Path bukkitMetadata = Path.of(paperMetadata.toURI()).resolveSibling("plugin.yml");
assertTrue(Files.isRegularFile(bukkitMetadata));
assertFalse(Files.readString(bukkitMetadata, StandardCharsets.UTF_8).contains("${"));
}
}
@@ -0,0 +1,115 @@
package art.arcane.iris.core.service;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.junit.Test;
import java.lang.reflect.Proxy;
import java.util.List;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class PaperCommandRegistrarTest {
@Test
public void paperCommandDelegatesExecutionAndSuggestions() {
RecordingCommandService service = new RecordingCommandService();
BasicCommand command = PaperCommandRegistrar.command(service);
CommandSender sender = sender();
CommandSourceStack source = new TestCommandSourceStack(sender);
String[] arguments = {"create", "world"};
command.execute(source, arguments);
assertSame(sender, service.sender);
assertEquals("iris", service.label);
assertArrayEquals(arguments, service.arguments);
assertEquals(List.of("first", "second"), command.suggest(source, new String[]{"cr"}));
assertTrue(command.canUse(sender));
}
private static CommandSender sender() {
return (CommandSender) Proxy.newProxyInstance(
CommandSender.class.getClassLoader(),
new Class<?>[]{CommandSender.class},
(proxy, method, arguments) -> primitiveDefault(method.getReturnType())
);
}
private static Object primitiveDefault(Class<?> type) {
if (type == boolean.class) {
return false;
}
if (type == byte.class) {
return (byte) 0;
}
if (type == short.class) {
return (short) 0;
}
if (type == int.class) {
return 0;
}
if (type == long.class) {
return 0L;
}
if (type == float.class) {
return 0F;
}
if (type == double.class) {
return 0D;
}
if (type == char.class) {
return '\0';
}
return null;
}
private static final class RecordingCommandService extends CommandSVC {
private CommandSender sender;
private String label;
private String[] arguments;
@Override
void executeRoot(CommandSender sender, String label, String[] args) {
this.sender = sender;
this.label = label;
this.arguments = args;
}
@Override
List<String> tabCompleteRoot(CommandSender sender, String alias, String[] args) {
return List.of("first", "second");
}
}
private record TestCommandSourceStack(CommandSender sender) implements CommandSourceStack {
@Override
public Location getLocation() {
return null;
}
@Override
public CommandSender getSender() {
return sender;
}
@Override
public Entity getExecutor() {
return null;
}
@Override
public CommandSourceStack withLocation(Location location) {
return this;
}
@Override
public CommandSourceStack withExecutor(Entity executor) {
return this;
}
}
}