From cf8fa13be9d02c9f22a1afd051589943d629b01d Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 11 Sep 2026 14:32:20 +0200 Subject: [PATCH] test: cover registryWithToolRecipe and countSlotsWithRole --- tests/testContainerMenu.cpp | 158 ++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 tests/testContainerMenu.cpp diff --git a/tests/testContainerMenu.cpp b/tests/testContainerMenu.cpp new file mode 100644 index 0000000..fa6d7f5 --- /dev/null +++ b/tests/testContainerMenu.cpp @@ -0,0 +1,158 @@ +#include "testHarness.h" +#include "vf/ContainerMenu.h" + +#include +#include + +using namespace vf; + +namespace { + +const CraftingRegistry& sharedRegistry() { + static CraftingRegistry registry; + return registry; +} + +// A recipe nothing in the default set uses: a tool sits in the grid as a proper +// ingredient, which is the only way to exercise the remainder rule. +CraftingRegistry registryWithToolRecipe() { + CraftingRegistry registry; + ShapedRecipe carving; + carving.width = 1; + carving.height = 2; + carving.pattern = {ItemId::IronShovel, ItemId::Planks}; + carving.result = {ItemId::Stick, 4}; + carving.allowMirror = false; + registry.addShaped(carving); + return registry; +} + +int countSlotsWithRole(const ContainerMenu& menu, MenuSlot::Role role) { + return static_cast(menu.slotsWithRole(role).size()); +} + +} // namespace + +VF_TEST(everyMenuKindLaysOutTheSectionsItsScreenNeeds) { + for (int i = 0; i < static_cast(MenuKind::Count); ++i) { + MenuKind kind = static_cast(i); + ContainerMenu menu(kind, &sharedRegistry()); + CHECK(menu.slotCount() > 0); + CHECK_EQ(menu.slotCount(), menu.layout().totalSlots); + CHECK_EQ(menu.layout().inventoryCount, playerInventorySlots); + CHECK_EQ(menu.layout().hotbarCount, playerHotbarSlots); + CHECK(std::string(menuKindName(kind)) != std::string("unknown")); + } + + CHECK_EQ(ContainerMenu(MenuKind::Chest).slotCount(), 27 + 27 + 9); + CHECK_EQ(ContainerMenu(MenuKind::LargeChest).slotCount(), 54 + 27 + 9); + CHECK_EQ(ContainerMenu(MenuKind::Hopper).slotCount(), 5 + 27 + 9); + CHECK_EQ(countSlotsWithRole(ContainerMenu(MenuKind::Hopper), MenuSlot::Role::Storage), 5); +} + +VF_TEST(thePlayerInventoryKeepsItsTwoByTwoGridAndAnOffHandSlot) { + ContainerMenu menu(MenuKind::PlayerInventory, &sharedRegistry()); + const MenuLayout& layout = menu.layout(); + + CHECK_EQ(layout.craftWidth, 2); + CHECK_EQ(layout.craftHeight, 2); + CHECK_EQ(layout.craftCells(), 4); + CHECK(layout.hasCrafting()); + CHECK(layout.resultSlot >= 0); + CHECK(layout.offHandSlot >= 0); + CHECK_EQ(countSlotsWithRole(menu, MenuSlot::Role::CraftInput), 4); + CHECK_EQ(countSlotsWithRole(menu, MenuSlot::Role::OffHand), 1); + CHECK(menu.isPlayerSection(layout.offHandSlot)); + CHECK(!menu.isPlayerSection(layout.resultSlot)); +} + +VF_TEST(theCraftingTableGivesTheFullThreeByThreeGrid) { + ContainerMenu menu(MenuKind::CraftingTable, &sharedRegistry()); + CHECK_EQ(menu.layout().craftWidth, 3); + CHECK_EQ(menu.layout().craftHeight, 3); + CHECK_EQ(countSlotsWithRole(menu, MenuSlot::Role::CraftInput), 9); + CHECK(menu.hasCrafting()); + CHECK_EQ(menu.layout().offHandSlot, -1); +} + +VF_TEST(theFurnaceFuelSlotRefusesAnythingThatWillNotBurn) { + ContainerMenu menu(MenuKind::Furnace, &sharedRegistry()); + std::vector fuelSlots = menu.slotsWithRole(MenuSlot::Role::FuelInput); + CHECK_EQ(fuelSlots.size(), 1u); + int fuel = fuelSlots[0]; + + CHECK(menu.canPlace(fuel, makeStack(ItemId::CoalLump, 8))); + CHECK(menu.canPlace(fuel, makeStack(ItemId::Planks, 8))); + CHECK(!menu.canPlace(fuel, makeStack(ItemId::Stone, 8))); + CHECK(!menu.canPlace(fuel, makeStack(ItemId::IronIngot, 1))); + + MetaStack stone = makeStack(ItemId::Stone, 8); + CHECK_EQ(menu.insertAt(fuel, stone), 0); + CHECK_EQ(stone.count, 8); + + MetaStack coal = makeStack(ItemId::CoalLump, 8); + CHECK_EQ(menu.insertAt(fuel, coal), 8); + CHECK(coal.empty()); + CHECK_EQ(menu.stackAt(fuel).count, 8); +} + +VF_TEST(theFurnaceInputSlotOnlyTakesItemsWithASmeltingRecipe) { + ContainerMenu menu(MenuKind::Furnace, &sharedRegistry()); + int input = menu.slotsWithRole(MenuSlot::Role::SmeltInput)[0]; + + CHECK(menu.canPlace(input, makeStack(ItemId::IronOre, 4))); + CHECK(menu.canPlace(input, makeStack(ItemId::RawBeef, 4))); + CHECK(!menu.canPlace(input, makeStack(ItemId::Stick, 4))); + CHECK(!menu.canPlace(input, makeStack(ItemId::Glowstone, 4))); + + // Without a registry there is nothing to consult, so nothing is smeltable. + ContainerMenu blind(MenuKind::Furnace, nullptr); + CHECK(!blind.canPlace(input, makeStack(ItemId::IronOre, 4))); +} + +VF_TEST(theEnchantingTableTakesOnlyLapisForPaymentAndOnlyGearForTheItem) { + ContainerMenu menu(MenuKind::EnchantingTable, &sharedRegistry()); + int item = menu.slotsWithRole(MenuSlot::Role::EnchantItem)[0]; + int lapis = menu.slotsWithRole(MenuSlot::Role::EnchantLapis)[0]; + + CHECK(menu.canPlace(lapis, makeStack(ItemId::LapisLazuli, 3))); + CHECK(!menu.canPlace(lapis, makeStack(ItemId::DiamondGem, 3))); + CHECK(!menu.canPlace(lapis, makeStack(ItemId::LapisOre, 3))); + + CHECK(menu.canPlace(item, makeTool(ItemId::DiamondSword))); + CHECK(!menu.canPlace(item, makeStack(ItemId::Stone, 1))); + CHECK(!menu.canPlace(item, makeStack(ItemId::LapisLazuli, 1))); +} + +VF_TEST(theAnvilOnlyAcceptsItemsThatCarryDurability) { + ContainerMenu menu(MenuKind::Anvil, &sharedRegistry()); + std::vector inputs = menu.slotsWithRole(MenuSlot::Role::AnvilInput); + CHECK_EQ(inputs.size(), 2u); + + CHECK(menu.canPlace(inputs[0], makeTool(ItemId::GoldHoe))); + CHECK(menu.canPlace(inputs[1], makeTool(ItemId::DiamondAxe))); + CHECK(!menu.canPlace(inputs[0], makeStack(ItemId::IronIngot, 4))); +} + +VF_TEST(theBrewingStandFiltersIngredientsAndHoldsOneItemPerBottleSlot) { + ContainerMenu menu(MenuKind::BrewingStand, &sharedRegistry()); + int ingredient = menu.slotsWithRole(MenuSlot::Role::BrewIngredient)[0]; + std::vector bottles = menu.slotsWithRole(MenuSlot::Role::BrewBottle); + CHECK_EQ(bottles.size(), 3u); + + CHECK(menu.canPlace(ingredient, makeStack(ItemId::Gunpowder, 2))); + CHECK(menu.canPlace(ingredient, makeStack(ItemId::RedstoneDust, 2))); + CHECK(!menu.canPlace(ingredient, makeStack(ItemId::Stick, 2))); + + MetaStack pile = makeStack(ItemId::Glowstone, 20); + int moved = menu.insertAt(bottles[0], pile); + CHECK_EQ(moved, 1); + CHECK_EQ(menu.stackAt(bottles[0]).count, 1); + CHECK_EQ(pile.count, 19); + CHECK_EQ(menu.insertAt(bottles[0], pile), 0); +} + +VF_TEST(aResultSlotCanBeEmptiedButNeverFilledByHand) { + ContainerMenu menu(MenuKind::CraftingTable, &sharedRegistry()); + int result = menu.layout().resultSlot; +