From 6d3379e8e7aa9f80e962d829b35359cad1d477d7 Mon Sep 17 00:00:00 2001 From: altrisi Date: Tue, 25 Jun 2024 23:09:26 +0200 Subject: [PATCH 1/5] WIP gametest --- build.gradle | 40 ++- gradle.properties | 2 + src/gametest/java/carpetextra/TestUtils.java | 10 + .../testbootstrap/TestBootstraper.java | 80 ++++++ .../TestsClassesCommandExtension.java | 110 ++++++++ .../carpetextra/tests/DispenserWithBlock.java | 259 ++++++++++++++++++ .../java/carpetextra/tests/WartFarming.java | 71 +++++ .../gametest/structure/dispenserbase.snbt | 23 ++ .../gametest/structure/wartbase.snbt | 34 +++ .../java/carpetextra/CarpetExtraServer.java | 16 ++ 10 files changed, 639 insertions(+), 6 deletions(-) create mode 100644 src/gametest/java/carpetextra/TestUtils.java create mode 100644 src/gametest/java/carpetextra/testbootstrap/TestBootstraper.java create mode 100644 src/gametest/java/carpetextra/testbootstrap/TestsClassesCommandExtension.java create mode 100644 src/gametest/java/carpetextra/tests/DispenserWithBlock.java create mode 100644 src/gametest/java/carpetextra/tests/WartFarming.java create mode 100644 src/gametest/resources/data/carpet-extra/gametest/structure/dispenserbase.snbt create mode 100644 src/gametest/resources/data/carpet-extra/gametest/structure/wartbase.snbt diff --git a/build.gradle b/build.gradle index 0d93edda..e581a0df 100644 --- a/build.gradle +++ b/build.gradle @@ -12,11 +12,10 @@ repositories { base { archivesName = project.archives_base_name } + version = project.minecraft_version+'-'+project.mod_version group = project.maven_group -loom { -} dependencies { //to change the versions see the gradle.properties file @@ -25,11 +24,40 @@ dependencies { modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "carpet:fabric-carpet:${project.minecraft_version}-${project.carpet_core_version}" - // Fabric API. This is technically optional, but you probably want it anyway. - // modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + // for gametests + modRuntimeOnly fabricApi.module("fabric-resource-loader-v0", project.fabric_api_version) + modRuntimeOnly fabricApi.module("fabric-api-base", project.fabric_api_version) + modRuntimeOnly fabricApi.module("fabric-gametest-api-v1", project.fabric_api_version) +} + +sourceSets { + gametest { + java { + compileClasspath += main.output + compileClasspath += main.compileClasspath + runtimeClasspath += main.output + runtimeClasspath += main.runtimeClasspath + } + } +} - // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. - // You may need to force-disable transitiveness on them. +loom { + runs { + gametest { + inherit server + name "Game Test" + vmArg "-Dfabric-api.gametest" + //vmArg "-Dmixin.debug.countInjections=true" + vmArg "-Dfabric-api.gametest.report-file=${project.buildDir}/junit.xml" + source sourceSets.gametest + runDir "build/gametest" + ideConfigGenerated = false + } + } + runConfigs.configureEach { + // to be able to create and run gametests on regular debug + source sourceSets.gametest + } } processResources { diff --git a/gradle.properties b/gradle.properties index 98a6d240..74a895ce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,6 +8,8 @@ org.gradle.jvmargs=-Xmx1G loader_version=0.15.11 # check available versions on maven (https://masa.dy.fi/maven/carpet/fabric-carpet/) for the given minecraft version you are using carpet_core_version=1.4.147+v240613 + # for gametests + fabric_api_version=0.100.3+1.21 # Mod Properties mod_version = 1.4.147 diff --git a/src/gametest/java/carpetextra/TestUtils.java b/src/gametest/java/carpetextra/TestUtils.java new file mode 100644 index 00000000..f4534fbe --- /dev/null +++ b/src/gametest/java/carpetextra/TestUtils.java @@ -0,0 +1,10 @@ +package carpetextra; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestUtils { + + public static final Logger LOGGER = LoggerFactory.getLogger("CarpetExtraTest"); + +} diff --git a/src/gametest/java/carpetextra/testbootstrap/TestBootstraper.java b/src/gametest/java/carpetextra/testbootstrap/TestBootstraper.java new file mode 100644 index 00000000..340758ff --- /dev/null +++ b/src/gametest/java/carpetextra/testbootstrap/TestBootstraper.java @@ -0,0 +1,80 @@ +package carpetextra.testbootstrap; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import com.google.common.reflect.ClassPath; +import com.google.common.reflect.ClassPath.ClassInfo; + +import carpet.CarpetServer; +import carpetextra.TestUtils; +import net.minecraft.test.TestFunctions; + +public class TestBootstraper { + static final String TEST_BASE_PACKAGE = "carpetextra.tests"; + static { + registerExtensionForCommands(); + registerAllClasses(); + } + + static Stream allTestClasses() { + try { + return ClassPath.from(TestBootstraper.class.getClassLoader()) + .getAllClasses() + .stream() + .filter(clazz -> clazz.getPackageName().startsWith(TEST_BASE_PACKAGE) && clazz.isTopLevel()); + } catch (IOException e) { + throw new UncheckedIOException("Exception while listing Carpet Extra gametests", e); + } + } + + private static void registerAllClasses() { + AtomicInteger count = new AtomicInteger(); + allTestClasses() + .map(cls -> { + try { + // cls.load() doesn't initialize it, making it not return annotations to the framework + return Class.forName(cls.getName()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Couldn't initialize test class we know is there", e); + } + }) + .peek(__ -> count.setPlain(count.getPlain() + 1)) // technically shouldn't be used for this, but good enough + .forEach(TestBootstraper::register); + TestUtils.LOGGER.info("Registered " + count + " gametest classes for Carpet Extra"); + } + + static void register(Class test) { + // HACK: add our modid to gametest api first, or it'll crash + @SuppressWarnings("unchecked") + class HackHolder { + static final HashMap, String> IDS; + static { + HashMap, String> ids; + try { + Field f = Class.forName("net.fabricmc.fabric.impl.gametest.FabricGameTestModInitializer").getDeclaredField("GAME_TEST_IDS"); + f.setAccessible(true); + ids = (HashMap, String>)f.get(null); + } catch (ReflectiveOperationException e) { + TestUtils.LOGGER.warn("Hack to register gametest into fabric gametest failed, expect a crash!"); + ids = null; + } + IDS = ids; + } + } + + if (HackHolder.IDS != null) { + HackHolder.IDS.put(test, "carpet-extra"); + } + + TestFunctions.register(test); + } + + static void registerExtensionForCommands() { + CarpetServer.manageExtension(new TestsClassesCommandExtension()); + } +} diff --git a/src/gametest/java/carpetextra/testbootstrap/TestsClassesCommandExtension.java b/src/gametest/java/carpetextra/testbootstrap/TestsClassesCommandExtension.java new file mode 100644 index 00000000..26662938 --- /dev/null +++ b/src/gametest/java/carpetextra/testbootstrap/TestsClassesCommandExtension.java @@ -0,0 +1,110 @@ +package carpetextra.testbootstrap; + +import static carpetextra.testbootstrap.TestBootstraper.TEST_BASE_PACKAGE; +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import static com.mojang.brigadier.arguments.StringArgumentType.word; +import static net.minecraft.command.CommandSource.suggestMatching; +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.stream.Stream; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; + +import carpet.CarpetExtension; +import carpet.utils.Messenger; +import carpetextra.TestUtils; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.data.DataWriter; +import net.minecraft.data.dev.NbtProvider; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.test.TestFunctions; +import net.minecraft.util.WorldSavePath; + +// to add a command to register test classes at runtime +public class TestsClassesCommandExtension implements CarpetExtension { + @Override + public void registerCommands(CommandDispatcher dispatcher, CommandRegistryAccess commandBuildContext) { + registerTestClassCommand(dispatcher); + } + + public static void registerTestClassCommand(CommandDispatcher dispatcher) { + LiteralArgumentBuilder command = literal("testhelper") + .then(literal("class") + .then(argument("class", word()) + .suggests((c, b) -> suggestMatching(TestBootstraper.allTestClasses() + .mapMulti((clazz, stream) -> { + if (!TestFunctions.testClassExists(clazz.getSimpleName())) + stream.accept(clazz.getName()); + }) + .map(name -> name.substring(TEST_BASE_PACKAGE.length() + 1)) + , b)) + .executes(c -> { + String className = getString(c, "class"); + try { + Class testClass = Class.forName(TEST_BASE_PACKAGE + '.' + className); + if (TestFunctions.testClassExists(testClass.getSimpleName())) { + c.getSource().sendError(Messenger.c("r Reloading classes is not supported")); + return 0; + } + TestBootstraper.register(testClass); + c.getSource().sendMessage(Messenger.c(" Added test class " + className)); + return 1; + } catch (ClassNotFoundException e) { + c.getSource().sendError(Messenger.c("r Failed to load class " + className)); + return 0; + } + })) + ) + .then(literal("convertnbt") + .then(argument("structure", word()) + .suggests((c, b) -> suggestMatching(listStructures(c), b)) + .executes(c -> { + String fileName = getString(c, "structure"); + Path from = structuresPath(c).resolve(fileName + ".nbt"); + Path to = Path.of("../src/gametest/resources/data/carpet-extra/gametest/structure"); + NbtProvider.convertNbtToSnbt(DataWriter.UNCACHED, from, fileName, to); + c.getSource().sendMessage(Messenger.c(" Converted and moved structure " + fileName)); + return 0; + }) + ) + ); + dispatcher.register(command); + } + + private static Path structuresPath(CommandContext ctx) { + return ctx.getSource().getServer().getSavePath(WorldSavePath.GENERATED).resolve("minecraft/structures"); + } + + private static Collection listStructures(CommandContext ctx) { + try (Stream paths = Files.list(structuresPath(ctx))) { + return paths + .map(p -> p.getFileName().toString()) + .filter(p -> p.endsWith(".nbt")) + .map(p -> p.substring(0, p.length() - 4)) + .toList(); + } catch (IOException e) { + TestUtils.LOGGER.info("Failed to list structures", e); + // do nothing? + return Stream.empty().toList(); + } + } + +// private static void reloadTestClass(Class cls) { +// String fabricBatchId = cls.getSimpleName().toLowerCase(); +// TestFunctions.getTestFunctions().removeIf(fn -> fn.templatePath().startsWith(fabricBatchId)); +// // we'd need to remove before and after batch handlers too +// TestFunctions.register(cls); +// } + + @Override + public String version() { + return "testcommand-adder"; + } +} diff --git a/src/gametest/java/carpetextra/tests/DispenserWithBlock.java b/src/gametest/java/carpetextra/tests/DispenserWithBlock.java new file mode 100644 index 00000000..74a9dbd1 --- /dev/null +++ b/src/gametest/java/carpetextra/tests/DispenserWithBlock.java @@ -0,0 +1,259 @@ +package carpetextra.tests; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import carpetextra.CarpetExtraSettings; +import carpetextra.mixins.AxeItem_StrippedBlocksAccessorMixin; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.LeveledCauldronBlock; +import net.minecraft.block.entity.DispenserBlockEntity; +import net.minecraft.component.type.PotionContentsComponent; +import net.minecraft.entity.EntityType; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.potion.Potions; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.test.AfterBatch; +import net.minecraft.test.BeforeBatch; +import net.minecraft.test.CustomTestProvider; +import net.minecraft.test.GameTest; +import net.minecraft.test.TestContext; +import net.minecraft.test.TestFunction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; + +public class DispenserWithBlock { + static final String STRUCTURE = "carpet-extra:dispenserbase"; + static final String BATCH = "dispenserwithblock"; + static final int DISPENSER_DELAY = 4; + BlockPos lapis = new BlockPos(2, 1, 0); + BlockPos button = new BlockPos(0, 2, 0); + BlockPos dispenser = new BlockPos(1, 2, 0); + + @BeforeBatch(batchId = BATCH) + public void before(ServerWorld world) { + CarpetExtraSettings.dispensersFillMinecarts = true; + CarpetExtraSettings.dispensersCarvePumpkins = true; + CarpetExtraSettings.dispensersStripBlocks = true; + CarpetExtraSettings.dispensersTillSoil = true; + CarpetExtraSettings.dispensersUseCauldrons = true; + } + + @AfterBatch(batchId = BATCH) + public void after(ServerWorld world) { + CarpetExtraSettings.dispensersFillMinecarts = false; + CarpetExtraSettings.dispensersCarvePumpkins = false; + CarpetExtraSettings.dispensersStripBlocks = false; + CarpetExtraSettings.dispensersTillSoil = false; + CarpetExtraSettings.dispensersUseCauldrons = false; + } + + @GameTest(templateName = STRUCTURE, batchId = BATCH) + public void shearPumpkin(TestContext ctx) { + itemConversionTest(ctx, Items.SHEARS, Blocks.PUMPKIN, Blocks.CARVED_PUMPKIN, 1, false, () -> ctx.expectItem(Items.PUMPKIN_SEEDS)); + } + + @GameTest(templateName = STRUCTURE, batchId = BATCH) + public void shearPumpkinBreaks(TestContext ctx) { + itemConversionTest(ctx, Items.SHEARS, Blocks.PUMPKIN, Blocks.CARVED_PUMPKIN, 1, true, () -> ctx.expectItem(Items.PUMPKIN_SEEDS)); + } + + @CustomTestProvider + public Collection stripTests() { + List fns = new ArrayList<>(); + Map conversions = AxeItem_StrippedBlocksAccessorMixin.getStrippedBlocks(); + + for (Map.Entry entry : conversions.entrySet()) { + fns.add(makeDispenserTest("strip_" + entry.getKey().asItem(), (ctx) -> { + stripTest(ctx, Items.IRON_AXE, entry.getKey(), entry.getValue()); + })); + } + for (Item tool : List.of(Items.WOODEN_AXE, Items.STONE_AXE, Items.GOLDEN_AXE, Items.IRON_AXE, Items.DIAMOND_AXE, Items.NETHERITE_AXE)) { + fns.add(makeDispenserTest("stripwith" + tool, (ctx) -> { + stripTest(ctx, tool, Blocks.OAK_LOG, Blocks.STRIPPED_OAK_LOG); + })); + } + // Copper. There's no way I'm adding all the coppers + fns.add(makeDispenserTest("stripDeoxidateCopper", (ctx) -> { + stripTest(ctx, Items.IRON_AXE, Blocks.WEATHERED_COPPER, Blocks.EXPOSED_COPPER); + })); + fns.add(makeDispenserTest("stripUnwaxCopper", (ctx) -> { + stripTest(ctx, Items.IRON_AXE, Blocks.WAXED_COPPER_BLOCK, Blocks.COPPER_BLOCK); + })); + + return fns; + } + + private void stripTest(TestContext ctx, Item tool, Block blockFrom, Block blockTo) { + itemConversionTest(ctx, tool, blockFrom, blockTo, 1, false); + } + + @CustomTestProvider + public Collection tillTests() { + List fns = new ArrayList<>(); + fns.add(makeDispenserTest("tillDirtAbove", (ctx) -> { + tillTest(ctx, Blocks.DIRT, Blocks.FARMLAND, 1); + })); + fns.add(makeDispenserTest("tillGrass", (ctx) -> { + tillTest(ctx, Blocks.GRASS_BLOCK, Blocks.FARMLAND, 0); + })); + fns.add(makeDispenserTest("tillCoarseDirt", (ctx) -> { + tillTest(ctx, Blocks.COARSE_DIRT, Blocks.DIRT, 0); + })); + fns.add(makeDispenserTest("tillRootedDirt", (ctx) -> { + tillTest(ctx, Blocks.ROOTED_DIRT, Blocks.DIRT, 0, () -> ctx.expectItem(Items.HANGING_ROOTS)); + })); + + for (Item hoe : List.of(Items.WOODEN_HOE, Items.STONE_HOE, Items.GOLDEN_HOE, Items.IRON_HOE, Items.DIAMOND_HOE, Items.NETHERITE_HOE)) { + fns.add(makeDispenserTest("tillDirtWith" + hoe, (ctx) -> { + itemConversionTest(ctx, hoe, Blocks.DIRT, Blocks.FARMLAND, 0, false); + })); + } + + return fns; + } + + @CustomTestProvider + public Collection cauldronTests() { + List fns = new ArrayList<>(); + for (int i = 0; i < 2; i++) { // 3 is handled separately + for (int off = -1; off <= 1; off += 2) { + int finalOff = off; + int adjustedI = off > 0 ? i : i + 1; + fns.add(makeDispenserTest("cauldronBottleLvl" + adjustedI + (off > 0 ? "Fill" : "Empty"), ctx -> { + putInDispenser(ctx, finalOff > 0 ? waterBottle() : Items.GLASS_BOTTLE.getDefaultStack()); + ctx.setBlockState(lapis.up(), waterCauldronFor(ctx, adjustedI)); + BlockPos referencePos = dispenser.down(); + ctx.setBlockState(referencePos, waterCauldronFor(ctx, adjustedI + finalOff)); + + ctx.pushButton(button); + + ctx.addFinalTaskWithDuration(DISPENSER_DELAY, () -> { + ctx.expectSameStates(lapis.up(), referencePos); + checkFirstSlotHas(ctx, finalOff > 0 ? Items.GLASS_BOTTLE : Items.POTION, false); + }); + })); + } + } + // TODO powdered snow + for (var entry : Map.of(Items.LAVA_BUCKET, Blocks.LAVA_CAULDRON + //Items.POWDER_SNOW_BUCKET, Blocks.POWDER_SNOW_CAULDRON + ).entrySet()) { + fns.add(makeDispenserTest("cauldronFillWith" + entry.getKey(), (ctx) -> { + itemConversionTest(ctx, entry.getKey(), Blocks.CAULDRON, entry.getValue(), 1, false, () -> { + checkFirstSlotHas(ctx, Items.BUCKET, false); + }); + })); + fns.add(makeDispenserTest("cauldronEmptyTo" + entry.getKey(), (ctx) -> { + itemConversionTest(ctx, Items.BUCKET, entry.getValue(), Blocks.CAULDRON, 1, false, () -> { + checkFirstSlotHas(ctx, entry.getKey(), false); + }); + })); + } + return fns; + } + + private static ItemStack waterBottle() { + return PotionContentsComponent.createStack(Items.POTION, Potions.WATER); + } + + private BlockState waterCauldronFor(TestContext ctx, int level) { + if (level == 0) { + return Blocks.CAULDRON.getDefaultState(); + } + return Blocks.WATER_CAULDRON.getDefaultState().with(LeveledCauldronBlock.LEVEL, level); + } + + private void tillTest(TestContext ctx, Block from, Block to, int offset, Runnable... extras) { + ctx.setBlockState(dispenser.down(), Blocks.WATER); + itemConversionTest(ctx, Items.IRON_HOE, from, to, offset, false, extras); + } + + private void itemConversionTest(TestContext ctx, Item tool, Block from, Block to, int offset, boolean putDamaged, Runnable... extras) { + if (putDamaged) { + putAtOneDurability(ctx, tool); + } else { + putInDispenser(ctx, tool.getDefaultStack()); + } + ctx.setBlockState(lapis.offset(Direction.UP, offset), from); + ctx.pushButton(button); + + ctx.addFinalTaskWithDuration(DISPENSER_DELAY, () -> { + ctx.expectBlock(to, lapis.offset(Direction.UP, offset)); + if (putDamaged) { + ctx.expectEmptyContainer(dispenser); + } else if (tool.getDefaultStack().isDamageable()) { // otherwise we expect extras to handle it + checkFirstSlotHas(ctx, tool, true); + } + runAll(extras); + }); + } + + @GameTest(templateName = STRUCTURE, batchId = BATCH) + public void fillMinecartChest(TestContext ctx) { + cartTest(ctx, Items.CHEST, EntityType.CHEST_MINECART); + } + + @GameTest(templateName = STRUCTURE, batchId = BATCH) + public void fillMinecartHopper(TestContext ctx) { + cartTest(ctx, Items.HOPPER, EntityType.HOPPER_MINECART); + } + + @GameTest(templateName = STRUCTURE, batchId = BATCH) + public void fillMinecartTnt(TestContext ctx) { + cartTest(ctx, Items.TNT, EntityType.TNT_MINECART, () -> ctx.dontExpectEntity(EntityType.TNT)); + } + + @GameTest(templateName = STRUCTURE, batchId = BATCH) + public void fillMinecartFurnace(TestContext ctx) { + cartTest(ctx, Items.FURNACE, EntityType.FURNACE_MINECART); + } + + private void cartTest(TestContext ctx, Item item, EntityType entity, Runnable... extras) { + putInDispenser(ctx, item.getDefaultStack()); + ctx.setBlockState(lapis.up(), Blocks.RAIL); + ctx.spawnEntity(EntityType.MINECART, lapis.up()); + + ctx.pushButton(button); + ctx.addFinalTaskWithDuration(4, () -> { + ctx.expectEntityAt(entity, lapis.up()); + ctx.dontExpectEntity(EntityType.MINECART); + ctx.dontExpectEntity(EntityType.ITEM); + runAll(extras); + }); + } + + // Util + private void putInDispenser(TestContext ctx, ItemStack item) { + ctx.getBlockEntity(dispenser).addToFirstFreeSlot(item); + } + + private void putAtOneDurability(TestContext ctx, Item item) { + ItemStack stack = item.getDefaultStack(); + stack.setDamage(stack.getMaxDamage() - 1); + putInDispenser(ctx, stack); + } + + private void checkFirstSlotHas(TestContext ctx, Item item, boolean damaged) { + ctx.checkBlockEntity(dispenser, + disp -> disp.getStack(0).getItem() == item && (!damaged || disp.getStack(0).isDamaged()), + () -> "Must have " + (damaged ? "damaged " : "") + item + " in dispenser"); + } + + private void runAll(Runnable... actions) { + for (Runnable r : actions) r.run(); + } + + // Setup util + private TestFunction makeDispenserTest(String name, Consumer runner) { + name = name.replace("minecraft\\:", ""); + return new TestFunction(BATCH, BATCH + '.' + name, STRUCTURE, 20, 0, true, runner); + } +} diff --git a/src/gametest/java/carpetextra/tests/WartFarming.java b/src/gametest/java/carpetextra/tests/WartFarming.java new file mode 100644 index 00000000..a060a320 --- /dev/null +++ b/src/gametest/java/carpetextra/tests/WartFarming.java @@ -0,0 +1,71 @@ +package carpetextra.tests; + +import static net.minecraft.block.NetherWartBlock.*; + +import java.util.Set; + +import carpetextra.CarpetExtraSettings; +import net.minecraft.block.Blocks; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.item.Items; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.test.AfterBatch; +import net.minecraft.test.BeforeBatch; +import net.minecraft.test.GameTest; +import net.minecraft.test.TestContext; +import net.minecraft.util.math.BlockPos; + +public class WartFarming { + private static final String STRUCTURE = "carpet-extra:wartbase"; + private static final String BATCH = "wartfarming"; + + BlockPos soulSand = new BlockPos(0, 1, 0); + BlockPos lapis = new BlockPos(3, 2, 0); + + @BeforeBatch(batchId = BATCH) + public void before(ServerWorld world) { + CarpetExtraSettings.clericsFarmWarts = true; + world.setTimeOfDay(2500); + } + @AfterBatch(batchId = BATCH) + public void after(ServerWorld world) { + CarpetExtraSettings.clericsFarmWarts = false; + } + + @GameTest(batchId = BATCH, templateName = STRUCTURE, tickLimit = 1500) + public void placesWarts(TestContext ctx) { + ctx.spawnItem(Items.NETHER_WART, lapis); + ctx.spawnEntity(EntityType.VILLAGER, lapis); + + ctx.addInstantFinalTask(() -> { + ctx.expectBlock(Blocks.NETHER_WART, soulSand.up()); + }); + } + + @GameTest(batchId = BATCH, templateName = STRUCTURE, tickLimit = 1500) + public void collectsWarts(TestContext ctx) { + ctx.setBlockState(soulSand.up(), Blocks.NETHER_WART.getDefaultState().with(AGE, MAX_AGE)); + VillagerEntity villager = ctx.spawnEntity(EntityType.VILLAGER, lapis); + + ctx.addInstantFinalTask(() -> { + ctx.checkBlockState(soulSand.up(), + state -> state.getBlock() != Blocks.NETHER_WART || state.get(AGE) != MAX_AGE, + () -> "Wart not collected"); + ctx.assertTrue(villager.getInventory().containsAny(Set.of(Items.NETHER_WART)), "Villager didn't get warts"); + }); + } + + /* Too slow + @GameTest(batchId = BATCH, templateName = STRUCTURE, tickLimit = 1500) + public void doesntCollectNonGrown(TestContext ctx) { + ctx.setBlockState(soulSand.up(), Blocks.NETHER_WART.getDefaultState().with(AGE, 0)); + ctx.spawnEntity(EntityType.VILLAGER, lapis); + + ctx.runAtEveryTick(() -> { + ctx.dontExpectBlock(Blocks.AIR, soulSand.up()); + }); + ctx.runAtTick(1500, () -> ctx.complete()); + } + */ +} diff --git a/src/gametest/resources/data/carpet-extra/gametest/structure/dispenserbase.snbt b/src/gametest/resources/data/carpet-extra/gametest/structure/dispenserbase.snbt new file mode 100644 index 00000000..15088ff7 --- /dev/null +++ b/src/gametest/resources/data/carpet-extra/gametest/structure/dispenserbase.snbt @@ -0,0 +1,23 @@ +{ + DataVersion: 3953, + size: [3, 3, 1], + data: [ + {pos: [0, 0, 0], state: "minecraft:white_concrete"}, + {pos: [1, 0, 0], state: "minecraft:white_concrete"}, + {pos: [2, 0, 0], state: "minecraft:lapis_block"}, + {pos: [0, 1, 0], state: "minecraft:stone_button{face:wall,facing:west,powered:false}"}, + {pos: [1, 1, 0], state: "minecraft:dispenser{facing:east,triggered:false}", nbt: {Items: [], id: "minecraft:dispenser"}}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:white_concrete"}, + {pos: [2, 2, 0], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:white_concrete", + "minecraft:lapis_block", + "minecraft:stone_button{face:wall,facing:west,powered:false}", + "minecraft:air", + "minecraft:dispenser{facing:east,triggered:false}" + ] +} diff --git a/src/gametest/resources/data/carpet-extra/gametest/structure/wartbase.snbt b/src/gametest/resources/data/carpet-extra/gametest/structure/wartbase.snbt new file mode 100644 index 00000000..7042495b --- /dev/null +++ b/src/gametest/resources/data/carpet-extra/gametest/structure/wartbase.snbt @@ -0,0 +1,34 @@ +{ + DataVersion: 3953, + size: [5, 4, 1], + data: [ + {pos: [0, 0, 0], state: "minecraft:soul_sand"}, + {pos: [1, 0, 0], state: "minecraft:stone"}, + {pos: [2, 0, 0], state: "minecraft:stone"}, + {pos: [3, 0, 0], state: "minecraft:lapis_block"}, + {pos: [4, 0, 0], state: "minecraft:stone"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:brewing_stand{has_bottle_0:false,has_bottle_1:false,has_bottle_2:false}", nbt: {BrewTime: 0s, Fuel: 0b, Items: [], id: "minecraft:brewing_stand"}}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:stone", + "minecraft:lapis_block", + "minecraft:soul_sand", + "minecraft:air", + "minecraft:brewing_stand{has_bottle_0:false,has_bottle_1:false,has_bottle_2:false}" + ] +} diff --git a/src/main/java/carpetextra/CarpetExtraServer.java b/src/main/java/carpetextra/CarpetExtraServer.java index 4c9cdae2..2b594798 100644 --- a/src/main/java/carpetextra/CarpetExtraServer.java +++ b/src/main/java/carpetextra/CarpetExtraServer.java @@ -8,6 +8,7 @@ import carpetextra.utils.CarpetExtraTranslations; import com.mojang.brigadier.CommandDispatcher; import net.fabricmc.api.ModInitializer; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.server.command.ServerCommandSource; @@ -30,6 +31,21 @@ public static void loadExtension() public void onInitialize() { CarpetExtraServer.loadExtension(); + if (FabricLoader.getInstance().isDevelopmentEnvironment()) { + try { + Class.forName("carpetextra.testbootstrap.TestBootstraper"); + } catch (ClassNotFoundException e) { + // Class may not be available if in a different mod's dev env + // However, we'd still like to crash if we can make sure we're in Carpet extra's, for debugging purposes + String version = FabricLoader.getInstance() + .getModContainer("carpet-extra").orElseThrow() + .getMetadata().getVersion() + .getFriendlyString(); + if (version.equals("${version}")) { + throw new IllegalStateException("Couldn't bootstrap CarpetExtra tests!"); + } + } + } } @Override From 6133db9eab76c3144fb69c5d61c62c81ab5c812b Mon Sep 17 00:00:00 2001 From: altrisi Date: Wed, 26 Jun 2024 19:36:41 +0200 Subject: [PATCH 2/5] Refactor into gametest mod, convert all the framework into one line Only loss is having to restart to add a new class, but it wasn't that useful anyway (couldn't reload). And many things got better --- build.gradle | 8 ++ .../java/carpetextra/ExportPathChanger.java | 11 ++ src/gametest/java/carpetextra/TestUtils.java | 10 -- .../{tests => test}/DispenserWithBlock.java | 54 ++++----- .../{tests => test}/WartFarming.java | 2 +- .../testbootstrap/TestBootstraper.java | 80 ------------- .../TestsClassesCommandExtension.java | 110 ------------------ src/gametest/resources/fabric.mod.json | 18 +++ .../java/carpetextra/CarpetExtraServer.java | 16 --- 9 files changed, 65 insertions(+), 244 deletions(-) create mode 100644 src/gametest/java/carpetextra/ExportPathChanger.java delete mode 100644 src/gametest/java/carpetextra/TestUtils.java rename src/gametest/java/carpetextra/{tests => test}/DispenserWithBlock.java (99%) rename src/gametest/java/carpetextra/{tests => test}/WartFarming.java (98%) delete mode 100644 src/gametest/java/carpetextra/testbootstrap/TestBootstraper.java delete mode 100644 src/gametest/java/carpetextra/testbootstrap/TestsClassesCommandExtension.java create mode 100644 src/gametest/resources/fabric.mod.json diff --git a/build.gradle b/build.gradle index e581a0df..c26bd8d5 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,14 @@ loom { // to be able to create and run gametests on regular debug source sourceSets.gametest } + mods { + "carpet-extra" { + sourceSet sourceSets.main + } + "carpet-extra-gametest" { + sourceSet sourceSets.gametest + } + } } processResources { diff --git a/src/gametest/java/carpetextra/ExportPathChanger.java b/src/gametest/java/carpetextra/ExportPathChanger.java new file mode 100644 index 00000000..6e406295 --- /dev/null +++ b/src/gametest/java/carpetextra/ExportPathChanger.java @@ -0,0 +1,11 @@ +package carpetextra; + +import net.fabricmc.api.ModInitializer; +import net.minecraft.test.StructureTestUtil; + +public class ExportPathChanger implements ModInitializer { + @Override + public void onInitialize() { + StructureTestUtil.testStructuresDirectoryName = "../src/gametest/resources/data/carpet-extra/gametest/structure"; + } +} diff --git a/src/gametest/java/carpetextra/TestUtils.java b/src/gametest/java/carpetextra/TestUtils.java deleted file mode 100644 index f4534fbe..00000000 --- a/src/gametest/java/carpetextra/TestUtils.java +++ /dev/null @@ -1,10 +0,0 @@ -package carpetextra; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TestUtils { - - public static final Logger LOGGER = LoggerFactory.getLogger("CarpetExtraTest"); - -} diff --git a/src/gametest/java/carpetextra/tests/DispenserWithBlock.java b/src/gametest/java/carpetextra/test/DispenserWithBlock.java similarity index 99% rename from src/gametest/java/carpetextra/tests/DispenserWithBlock.java rename to src/gametest/java/carpetextra/test/DispenserWithBlock.java index 74a9dbd1..2b1174ef 100644 --- a/src/gametest/java/carpetextra/tests/DispenserWithBlock.java +++ b/src/gametest/java/carpetextra/test/DispenserWithBlock.java @@ -1,4 +1,4 @@ -package carpetextra.tests; +package carpetextra.test; import java.util.ArrayList; import java.util.Collection; @@ -95,31 +95,6 @@ private void stripTest(TestContext ctx, Item tool, Block blockFrom, Block blockT itemConversionTest(ctx, tool, blockFrom, blockTo, 1, false); } - @CustomTestProvider - public Collection tillTests() { - List fns = new ArrayList<>(); - fns.add(makeDispenserTest("tillDirtAbove", (ctx) -> { - tillTest(ctx, Blocks.DIRT, Blocks.FARMLAND, 1); - })); - fns.add(makeDispenserTest("tillGrass", (ctx) -> { - tillTest(ctx, Blocks.GRASS_BLOCK, Blocks.FARMLAND, 0); - })); - fns.add(makeDispenserTest("tillCoarseDirt", (ctx) -> { - tillTest(ctx, Blocks.COARSE_DIRT, Blocks.DIRT, 0); - })); - fns.add(makeDispenserTest("tillRootedDirt", (ctx) -> { - tillTest(ctx, Blocks.ROOTED_DIRT, Blocks.DIRT, 0, () -> ctx.expectItem(Items.HANGING_ROOTS)); - })); - - for (Item hoe : List.of(Items.WOODEN_HOE, Items.STONE_HOE, Items.GOLDEN_HOE, Items.IRON_HOE, Items.DIAMOND_HOE, Items.NETHERITE_HOE)) { - fns.add(makeDispenserTest("tillDirtWith" + hoe, (ctx) -> { - itemConversionTest(ctx, hoe, Blocks.DIRT, Blocks.FARMLAND, 0, false); - })); - } - - return fns; - } - @CustomTestProvider public Collection cauldronTests() { List fns = new ArrayList<>(); @@ -170,7 +145,32 @@ private BlockState waterCauldronFor(TestContext ctx, int level) { } return Blocks.WATER_CAULDRON.getDefaultState().with(LeveledCauldronBlock.LEVEL, level); } - + + @CustomTestProvider + public Collection tillTests() { + List fns = new ArrayList<>(); + fns.add(makeDispenserTest("tillDirtAbove", (ctx) -> { + tillTest(ctx, Blocks.DIRT, Blocks.FARMLAND, 1); + })); + fns.add(makeDispenserTest("tillGrass", (ctx) -> { + tillTest(ctx, Blocks.GRASS_BLOCK, Blocks.FARMLAND, 0); + })); + fns.add(makeDispenserTest("tillCoarseDirt", (ctx) -> { + tillTest(ctx, Blocks.COARSE_DIRT, Blocks.DIRT, 0); + })); + fns.add(makeDispenserTest("tillRootedDirt", (ctx) -> { + tillTest(ctx, Blocks.ROOTED_DIRT, Blocks.DIRT, 0, () -> ctx.expectItem(Items.HANGING_ROOTS)); + })); + + for (Item hoe : List.of(Items.WOODEN_HOE, Items.STONE_HOE, Items.GOLDEN_HOE, Items.IRON_HOE, Items.DIAMOND_HOE, Items.NETHERITE_HOE)) { + fns.add(makeDispenserTest("tillDirtWith" + hoe, (ctx) -> { + itemConversionTest(ctx, hoe, Blocks.DIRT, Blocks.FARMLAND, 0, false); + })); + } + + return fns; + } + private void tillTest(TestContext ctx, Block from, Block to, int offset, Runnable... extras) { ctx.setBlockState(dispenser.down(), Blocks.WATER); itemConversionTest(ctx, Items.IRON_HOE, from, to, offset, false, extras); diff --git a/src/gametest/java/carpetextra/tests/WartFarming.java b/src/gametest/java/carpetextra/test/WartFarming.java similarity index 98% rename from src/gametest/java/carpetextra/tests/WartFarming.java rename to src/gametest/java/carpetextra/test/WartFarming.java index a060a320..49700e61 100644 --- a/src/gametest/java/carpetextra/tests/WartFarming.java +++ b/src/gametest/java/carpetextra/test/WartFarming.java @@ -1,4 +1,4 @@ -package carpetextra.tests; +package carpetextra.test; import static net.minecraft.block.NetherWartBlock.*; diff --git a/src/gametest/java/carpetextra/testbootstrap/TestBootstraper.java b/src/gametest/java/carpetextra/testbootstrap/TestBootstraper.java deleted file mode 100644 index 340758ff..00000000 --- a/src/gametest/java/carpetextra/testbootstrap/TestBootstraper.java +++ /dev/null @@ -1,80 +0,0 @@ -package carpetextra.testbootstrap; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Stream; - -import com.google.common.reflect.ClassPath; -import com.google.common.reflect.ClassPath.ClassInfo; - -import carpet.CarpetServer; -import carpetextra.TestUtils; -import net.minecraft.test.TestFunctions; - -public class TestBootstraper { - static final String TEST_BASE_PACKAGE = "carpetextra.tests"; - static { - registerExtensionForCommands(); - registerAllClasses(); - } - - static Stream allTestClasses() { - try { - return ClassPath.from(TestBootstraper.class.getClassLoader()) - .getAllClasses() - .stream() - .filter(clazz -> clazz.getPackageName().startsWith(TEST_BASE_PACKAGE) && clazz.isTopLevel()); - } catch (IOException e) { - throw new UncheckedIOException("Exception while listing Carpet Extra gametests", e); - } - } - - private static void registerAllClasses() { - AtomicInteger count = new AtomicInteger(); - allTestClasses() - .map(cls -> { - try { - // cls.load() doesn't initialize it, making it not return annotations to the framework - return Class.forName(cls.getName()); - } catch (ClassNotFoundException e) { - throw new IllegalStateException("Couldn't initialize test class we know is there", e); - } - }) - .peek(__ -> count.setPlain(count.getPlain() + 1)) // technically shouldn't be used for this, but good enough - .forEach(TestBootstraper::register); - TestUtils.LOGGER.info("Registered " + count + " gametest classes for Carpet Extra"); - } - - static void register(Class test) { - // HACK: add our modid to gametest api first, or it'll crash - @SuppressWarnings("unchecked") - class HackHolder { - static final HashMap, String> IDS; - static { - HashMap, String> ids; - try { - Field f = Class.forName("net.fabricmc.fabric.impl.gametest.FabricGameTestModInitializer").getDeclaredField("GAME_TEST_IDS"); - f.setAccessible(true); - ids = (HashMap, String>)f.get(null); - } catch (ReflectiveOperationException e) { - TestUtils.LOGGER.warn("Hack to register gametest into fabric gametest failed, expect a crash!"); - ids = null; - } - IDS = ids; - } - } - - if (HackHolder.IDS != null) { - HackHolder.IDS.put(test, "carpet-extra"); - } - - TestFunctions.register(test); - } - - static void registerExtensionForCommands() { - CarpetServer.manageExtension(new TestsClassesCommandExtension()); - } -} diff --git a/src/gametest/java/carpetextra/testbootstrap/TestsClassesCommandExtension.java b/src/gametest/java/carpetextra/testbootstrap/TestsClassesCommandExtension.java deleted file mode 100644 index 26662938..00000000 --- a/src/gametest/java/carpetextra/testbootstrap/TestsClassesCommandExtension.java +++ /dev/null @@ -1,110 +0,0 @@ -package carpetextra.testbootstrap; - -import static carpetextra.testbootstrap.TestBootstraper.TEST_BASE_PACKAGE; -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.word; -import static net.minecraft.command.CommandSource.suggestMatching; -import static net.minecraft.server.command.CommandManager.argument; -import static net.minecraft.server.command.CommandManager.literal; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collection; -import java.util.stream.Stream; - -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.context.CommandContext; - -import carpet.CarpetExtension; -import carpet.utils.Messenger; -import carpetextra.TestUtils; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.data.DataWriter; -import net.minecraft.data.dev.NbtProvider; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.test.TestFunctions; -import net.minecraft.util.WorldSavePath; - -// to add a command to register test classes at runtime -public class TestsClassesCommandExtension implements CarpetExtension { - @Override - public void registerCommands(CommandDispatcher dispatcher, CommandRegistryAccess commandBuildContext) { - registerTestClassCommand(dispatcher); - } - - public static void registerTestClassCommand(CommandDispatcher dispatcher) { - LiteralArgumentBuilder command = literal("testhelper") - .then(literal("class") - .then(argument("class", word()) - .suggests((c, b) -> suggestMatching(TestBootstraper.allTestClasses() - .mapMulti((clazz, stream) -> { - if (!TestFunctions.testClassExists(clazz.getSimpleName())) - stream.accept(clazz.getName()); - }) - .map(name -> name.substring(TEST_BASE_PACKAGE.length() + 1)) - , b)) - .executes(c -> { - String className = getString(c, "class"); - try { - Class testClass = Class.forName(TEST_BASE_PACKAGE + '.' + className); - if (TestFunctions.testClassExists(testClass.getSimpleName())) { - c.getSource().sendError(Messenger.c("r Reloading classes is not supported")); - return 0; - } - TestBootstraper.register(testClass); - c.getSource().sendMessage(Messenger.c(" Added test class " + className)); - return 1; - } catch (ClassNotFoundException e) { - c.getSource().sendError(Messenger.c("r Failed to load class " + className)); - return 0; - } - })) - ) - .then(literal("convertnbt") - .then(argument("structure", word()) - .suggests((c, b) -> suggestMatching(listStructures(c), b)) - .executes(c -> { - String fileName = getString(c, "structure"); - Path from = structuresPath(c).resolve(fileName + ".nbt"); - Path to = Path.of("../src/gametest/resources/data/carpet-extra/gametest/structure"); - NbtProvider.convertNbtToSnbt(DataWriter.UNCACHED, from, fileName, to); - c.getSource().sendMessage(Messenger.c(" Converted and moved structure " + fileName)); - return 0; - }) - ) - ); - dispatcher.register(command); - } - - private static Path structuresPath(CommandContext ctx) { - return ctx.getSource().getServer().getSavePath(WorldSavePath.GENERATED).resolve("minecraft/structures"); - } - - private static Collection listStructures(CommandContext ctx) { - try (Stream paths = Files.list(structuresPath(ctx))) { - return paths - .map(p -> p.getFileName().toString()) - .filter(p -> p.endsWith(".nbt")) - .map(p -> p.substring(0, p.length() - 4)) - .toList(); - } catch (IOException e) { - TestUtils.LOGGER.info("Failed to list structures", e); - // do nothing? - return Stream.empty().toList(); - } - } - -// private static void reloadTestClass(Class cls) { -// String fabricBatchId = cls.getSimpleName().toLowerCase(); -// TestFunctions.getTestFunctions().removeIf(fn -> fn.templatePath().startsWith(fabricBatchId)); -// // we'd need to remove before and after batch handlers too -// TestFunctions.register(cls); -// } - - @Override - public String version() { - return "testcommand-adder"; - } -} diff --git a/src/gametest/resources/fabric.mod.json b/src/gametest/resources/fabric.mod.json new file mode 100644 index 00000000..66b7a803 --- /dev/null +++ b/src/gametest/resources/fabric.mod.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "id": "carpet-extra-gametest", + "version": "0.0.0", + + "name": "Carpet Extra GameTests", + + "environment": "*", + "entrypoints": { + "main": [ + "carpetextra.ExportPathChanger" + ], + "fabric-gametest": [ + "carpetextra.test.DispenserWithBlock", + "carpetextra.test.WartFarming" + ] + } +} diff --git a/src/main/java/carpetextra/CarpetExtraServer.java b/src/main/java/carpetextra/CarpetExtraServer.java index 2b594798..4c9cdae2 100644 --- a/src/main/java/carpetextra/CarpetExtraServer.java +++ b/src/main/java/carpetextra/CarpetExtraServer.java @@ -8,7 +8,6 @@ import carpetextra.utils.CarpetExtraTranslations; import com.mojang.brigadier.CommandDispatcher; import net.fabricmc.api.ModInitializer; -import net.fabricmc.loader.api.FabricLoader; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.server.command.ServerCommandSource; @@ -31,21 +30,6 @@ public static void loadExtension() public void onInitialize() { CarpetExtraServer.loadExtension(); - if (FabricLoader.getInstance().isDevelopmentEnvironment()) { - try { - Class.forName("carpetextra.testbootstrap.TestBootstraper"); - } catch (ClassNotFoundException e) { - // Class may not be available if in a different mod's dev env - // However, we'd still like to crash if we can make sure we're in Carpet extra's, for debugging purposes - String version = FabricLoader.getInstance() - .getModContainer("carpet-extra").orElseThrow() - .getMetadata().getVersion() - .getFriendlyString(); - if (version.equals("${version}")) { - throw new IllegalStateException("Couldn't bootstrap CarpetExtra tests!"); - } - } - } } @Override From e32df529db41ddb3574951bc099a10e27094f011 Mon Sep 17 00:00:00 2001 From: altrisi Date: Wed, 26 Jun 2024 19:38:22 +0200 Subject: [PATCH 3/5] Add comment about why countInjections isn't on --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c26bd8d5..1b1a30c8 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ loom { inherit server name "Game Test" vmArg "-Dfabric-api.gametest" - //vmArg "-Dmixin.debug.countInjections=true" + //vmArg "-Dmixin.debug.countInjections=true" // gnembon/fabric-carpet#1938 vmArg "-Dfabric-api.gametest.report-file=${project.buildDir}/junit.xml" source sourceSets.gametest runDir "build/gametest" From 641c6c5efe6b89908f4820a69ccc002abbd8af66 Mon Sep 17 00:00:00 2001 From: altrisi Date: Wed, 26 Jun 2024 19:39:33 +0200 Subject: [PATCH 4/5] Remove var --- src/gametest/java/carpetextra/test/DispenserWithBlock.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gametest/java/carpetextra/test/DispenserWithBlock.java b/src/gametest/java/carpetextra/test/DispenserWithBlock.java index 2b1174ef..ffbb8083 100644 --- a/src/gametest/java/carpetextra/test/DispenserWithBlock.java +++ b/src/gametest/java/carpetextra/test/DispenserWithBlock.java @@ -118,7 +118,7 @@ public Collection cauldronTests() { } } // TODO powdered snow - for (var entry : Map.of(Items.LAVA_BUCKET, Blocks.LAVA_CAULDRON + for (Map.Entry entry : Map.of(Items.LAVA_BUCKET, Blocks.LAVA_CAULDRON //Items.POWDER_SNOW_BUCKET, Blocks.POWDER_SNOW_CAULDRON ).entrySet()) { fns.add(makeDispenserTest("cauldronFillWith" + entry.getKey(), (ctx) -> { From 9d3f8c0b3ae742ece6b8efadd8e15e3aebef598f Mon Sep 17 00:00:00 2001 From: altrisi Date: Wed, 26 Jun 2024 20:25:11 +0200 Subject: [PATCH 5/5] Some tweaks to dispenser test --- .../carpetextra/test/DispenserWithBlock.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/gametest/java/carpetextra/test/DispenserWithBlock.java b/src/gametest/java/carpetextra/test/DispenserWithBlock.java index ffbb8083..d243ed46 100644 --- a/src/gametest/java/carpetextra/test/DispenserWithBlock.java +++ b/src/gametest/java/carpetextra/test/DispenserWithBlock.java @@ -57,12 +57,12 @@ public void after(ServerWorld world) { @GameTest(templateName = STRUCTURE, batchId = BATCH) public void shearPumpkin(TestContext ctx) { - itemConversionTest(ctx, Items.SHEARS, Blocks.PUMPKIN, Blocks.CARVED_PUMPKIN, 1, false, () -> ctx.expectItem(Items.PUMPKIN_SEEDS)); + blockConversionTest(ctx, Items.SHEARS, Blocks.PUMPKIN, Blocks.CARVED_PUMPKIN, 1, false, () -> ctx.expectItem(Items.PUMPKIN_SEEDS)); } @GameTest(templateName = STRUCTURE, batchId = BATCH) public void shearPumpkinBreaks(TestContext ctx) { - itemConversionTest(ctx, Items.SHEARS, Blocks.PUMPKIN, Blocks.CARVED_PUMPKIN, 1, true, () -> ctx.expectItem(Items.PUMPKIN_SEEDS)); + blockConversionTest(ctx, Items.SHEARS, Blocks.PUMPKIN, Blocks.CARVED_PUMPKIN, 1, true, () -> ctx.expectItem(Items.PUMPKIN_SEEDS)); } @CustomTestProvider @@ -92,7 +92,7 @@ public Collection stripTests() { } private void stripTest(TestContext ctx, Item tool, Block blockFrom, Block blockTo) { - itemConversionTest(ctx, tool, blockFrom, blockTo, 1, false); + blockConversionTest(ctx, tool, blockFrom, blockTo, 1, false); } @CustomTestProvider @@ -122,12 +122,12 @@ public Collection cauldronTests() { //Items.POWDER_SNOW_BUCKET, Blocks.POWDER_SNOW_CAULDRON ).entrySet()) { fns.add(makeDispenserTest("cauldronFillWith" + entry.getKey(), (ctx) -> { - itemConversionTest(ctx, entry.getKey(), Blocks.CAULDRON, entry.getValue(), 1, false, () -> { + blockConversionTest(ctx, entry.getKey(), Blocks.CAULDRON, entry.getValue(), 1, false, () -> { checkFirstSlotHas(ctx, Items.BUCKET, false); }); })); fns.add(makeDispenserTest("cauldronEmptyTo" + entry.getKey(), (ctx) -> { - itemConversionTest(ctx, Items.BUCKET, entry.getValue(), Blocks.CAULDRON, 1, false, () -> { + blockConversionTest(ctx, Items.BUCKET, entry.getValue(), Blocks.CAULDRON, 1, false, () -> { checkFirstSlotHas(ctx, entry.getKey(), false); }); })); @@ -150,33 +150,31 @@ private BlockState waterCauldronFor(TestContext ctx, int level) { public Collection tillTests() { List fns = new ArrayList<>(); fns.add(makeDispenserTest("tillDirtAbove", (ctx) -> { - tillTest(ctx, Blocks.DIRT, Blocks.FARMLAND, 1); + blockConversionTest(ctx, Items.IRON_HOE, Blocks.DIRT, Blocks.FARMLAND, 1, false); })); fns.add(makeDispenserTest("tillGrass", (ctx) -> { - tillTest(ctx, Blocks.GRASS_BLOCK, Blocks.FARMLAND, 0); + blockConversionTest(ctx, Items.IRON_HOE, Blocks.GRASS_BLOCK, Blocks.FARMLAND, 0, false); + })); + fns.add(makeDispenserTest("tillCheckDurability", (ctx) -> { + blockConversionTest(ctx, Items.IRON_HOE, Blocks.DIRT, Blocks.FARMLAND, 0, true); })); fns.add(makeDispenserTest("tillCoarseDirt", (ctx) -> { - tillTest(ctx, Blocks.COARSE_DIRT, Blocks.DIRT, 0); + blockConversionTest(ctx, Items.IRON_HOE, Blocks.COARSE_DIRT, Blocks.DIRT, 0, false); })); fns.add(makeDispenserTest("tillRootedDirt", (ctx) -> { - tillTest(ctx, Blocks.ROOTED_DIRT, Blocks.DIRT, 0, () -> ctx.expectItem(Items.HANGING_ROOTS)); + blockConversionTest(ctx, Items.IRON_HOE, Blocks.ROOTED_DIRT, Blocks.DIRT, 0, false, () -> ctx.expectItem(Items.HANGING_ROOTS)); })); for (Item hoe : List.of(Items.WOODEN_HOE, Items.STONE_HOE, Items.GOLDEN_HOE, Items.IRON_HOE, Items.DIAMOND_HOE, Items.NETHERITE_HOE)) { fns.add(makeDispenserTest("tillDirtWith" + hoe, (ctx) -> { - itemConversionTest(ctx, hoe, Blocks.DIRT, Blocks.FARMLAND, 0, false); + blockConversionTest(ctx, hoe, Blocks.DIRT, Blocks.FARMLAND, 0, false); })); } return fns; } - private void tillTest(TestContext ctx, Block from, Block to, int offset, Runnable... extras) { - ctx.setBlockState(dispenser.down(), Blocks.WATER); - itemConversionTest(ctx, Items.IRON_HOE, from, to, offset, false, extras); - } - - private void itemConversionTest(TestContext ctx, Item tool, Block from, Block to, int offset, boolean putDamaged, Runnable... extras) { + private void blockConversionTest(TestContext ctx, Item tool, Block from, Block to, int offset, boolean putDamaged, Runnable... extras) { if (putDamaged) { putAtOneDurability(ctx, tool); } else {