diff --git a/tests/testContainerMenu.cpp b/tests/testContainerMenu.cpp index fa6d7f5..e5edd2c 100644 --- a/tests/testContainerMenu.cpp +++ b/tests/testContainerMenu.cpp @@ -156,3 +156,162 @@ VF_TEST(aResultSlotCanBeEmptiedButNeverFilledByHand) { ContainerMenu menu(MenuKind::CraftingTable, &sharedRegistry()); int result = menu.layout().resultSlot; + CHECK(menu.slot(result).takeOnly); + CHECK(!menu.canPlace(result, makeStack(ItemId::Stone, 1))); + + MetaStack stone = makeStack(ItemId::Stone, 1); + CHECK_EQ(menu.insertAt(result, stone), 0); + CHECK_EQ(stone.count, 1); + CHECK(menu.stackAt(result).empty()); + + // The furnace, anvil and trade outputs answer the same way. + ContainerMenu furnace(MenuKind::Furnace, &sharedRegistry()); + int output = furnace.slotsWithRole(MenuSlot::Role::SmeltOutput)[0]; + CHECK(!furnace.canPlace(output, makeStack(ItemId::IronIngot, 1))); + + ContainerMenu villager(MenuKind::Villager, &sharedRegistry()); + int trade = villager.slotsWithRole(MenuSlot::Role::TradeResult)[0]; + CHECK(!villager.canPlace(trade, makeStack(ItemId::EmeraldGem, 1))); +} + +VF_TEST(theCraftingViewRecomputesTheResultAfterEveryGridChange) { + ContainerMenu menu(MenuKind::CraftingTable, &sharedRegistry()); + CraftingView grid = menu.crafting(); + CHECK_EQ(grid.cellCount(), 9); + CHECK(!grid.hasResult()); + + grid.inputAt(0) = makeStack(ItemId::Wood, 1); + grid.refresh(); + CHECK(grid.hasResult()); + CHECK(grid.result().item == ItemId::Planks); + CHECK_EQ(grid.result().count, 4); + + grid.inputAt(0).clear(); + grid.refresh(); + CHECK(!grid.hasResult()); + + grid.input(0, 0) = makeStack(ItemId::Planks, 3); + grid.input(0, 1) = makeStack(ItemId::Planks, 3); + grid.refresh(); + CHECK(grid.result().item == ItemId::Stick); + CHECK_EQ(grid.result().count, 4); +} + +VF_TEST(takingTheResultSpendsExactlyOneItemFromEachFilledInputSlot) { + ContainerMenu menu(MenuKind::CraftingTable, &sharedRegistry()); + CraftingView grid = menu.crafting(); + grid.input(0, 0) = makeStack(ItemId::Planks, 5); + grid.input(0, 1) = makeStack(ItemId::Planks, 3); + grid.refresh(); + CHECK_EQ(grid.maxCrafts(), 3); + + MetaStack sticks = grid.takeResult(); + CHECK(sticks.item == ItemId::Stick); + CHECK_EQ(sticks.count, 4); + CHECK_EQ(grid.input(0, 0).count, 4); + CHECK_EQ(grid.input(0, 1).count, 2); + CHECK(grid.hasResult()); + + grid.takeResult(); + grid.takeResult(); + CHECK_EQ(grid.input(0, 0).count, 2); + CHECK(grid.input(0, 1).empty()); + CHECK(!grid.hasResult()); + CHECK(grid.takeResult().empty()); +} + +VF_TEST(aDamageableIngredientStaysInTheGridOnePointWorse) { + CraftingRegistry registry = registryWithToolRecipe(); + ContainerMenu menu(MenuKind::CraftingTable, ®istry); + CraftingView grid = menu.crafting(); + + grid.input(0, 0) = makeTool(ItemId::IronShovel); + grid.input(0, 1) = makeStack(ItemId::Planks, 4); + grid.refresh(); + CHECK(grid.hasResult()); + CHECK(grid.result().item == ItemId::Stick); + + MetaStack sticks = grid.takeResult(); + CHECK_EQ(sticks.count, 4); + CHECK(!grid.input(0, 0).empty()); + CHECK(grid.input(0, 0).item == ItemId::IronShovel); + CHECK_EQ(grid.input(0, 0).meta.durability.used, 1); + CHECK_EQ(grid.input(0, 1).count, 3); + + // A shovel one point from death is spent by the craft instead of surviving. + grid.input(0, 0).meta.durability.used = grid.input(0, 0).meta.durability.max - 1; + grid.refresh(); + grid.takeResult(); + CHECK(grid.input(0, 0).empty()); +} + +VF_TEST(shiftCraftingRepeatsUntilTheGridRunsDry) { + ContainerMenu menu(MenuKind::CraftingTable, &sharedRegistry()); + CraftingView grid = menu.crafting(); + grid.input(0, 0) = makeStack(ItemId::Planks, 6); + grid.input(0, 1) = makeStack(ItemId::Planks, 6); + grid.refresh(); + + int rounds = grid.craftAll(grid.maxCrafts()); + CHECK_EQ(rounds, 6); + CHECK(grid.input(0, 0).empty()); + CHECK(grid.input(0, 1).empty()); + CHECK(!grid.hasResult()); + CHECK_EQ(menu.totalOf(ItemId::Stick), 24); + CHECK_EQ(menu.totalOf(ItemId::Planks), 0); +} + +VF_TEST(craftingStopsWhenThePlayerSectionsHaveNoRoomLeft) { + ContainerMenu menu(MenuKind::CraftingTable, &sharedRegistry()); + for (int index : menu.playerSectionSlots()) { + menu.slot(index).cell.stack = makeStack(ItemId::Obsidian, 64); + } + + CraftingView grid = menu.crafting(); + grid.input(0, 0) = makeStack(ItemId::Planks, 4); + grid.input(0, 1) = makeStack(ItemId::Planks, 4); + grid.refresh(); + + int rounds = grid.craftAll(grid.maxCrafts()); + CHECK_EQ(rounds, 1); + CHECK_EQ(menu.totalOf(ItemId::Stick), 4); + CHECK_EQ(menu.stackAt(menu.layout().resultSlot).count, 4); + CHECK_EQ(menu.totalOf(ItemId::Planks), 6); +} + +VF_TEST(distributingFillsPartialStacksBeforeReachingForAnEmptySlot) { + ContainerMenu menu(MenuKind::Chest, &sharedRegistry()); + std::vector storage = menu.containerSectionSlots(); + menu.slot(storage[0]).cell.stack = makeStack(ItemId::Sand, 60); + menu.slot(storage[3]).cell.stack = makeStack(ItemId::Sand, 50); + + MetaStack incoming = makeStack(ItemId::Sand, 20); + int moved = menu.distributeInto(storage, incoming); + CHECK_EQ(moved, 20); + CHECK(incoming.empty()); + CHECK_EQ(menu.stackAt(storage[0]).count, 64); + CHECK_EQ(menu.stackAt(storage[3]).count, 64); + CHECK_EQ(menu.stackAt(storage[1]).count, 2); + CHECK(menu.stackAt(storage[2]).empty()); +} + +VF_TEST(distributingReportsWhatItCouldNotPlace) { + ContainerMenu menu(MenuKind::Hopper, &sharedRegistry()); + std::vector storage = menu.containerSectionSlots(); + for (int index : storage) menu.slot(index).cell.stack = makeStack(ItemId::Obsidian, 64); + + MetaStack incoming = makeStack(ItemId::Sand, 30); + CHECK_EQ(menu.distributeInto(storage, incoming), 0); + CHECK_EQ(incoming.count, 30); +} + +VF_TEST(aBoundContainerLoadsIntoTheStorageSectionAndIsWrittenBackOnClose) { + Container chest(27); + chest.insert(ItemId::Cobblestone, 90); + chest.setSlot(5, ItemSlot{ItemId::IronPickaxe, 1, 100}); + + ContainerMenu menu(MenuKind::Chest, &sharedRegistry()); + menu.bindContainer(chest); + CHECK(menu.hasContainer()); + CHECK_EQ(menu.totalOf(ItemId::Cobblestone), 90); +