diff --git a/tests/testSlotAction.cpp b/tests/testSlotAction.cpp index f17e8fa..96f12fd 100644 --- a/tests/testSlotAction.cpp +++ b/tests/testSlotAction.cpp @@ -468,3 +468,134 @@ VF_TEST(anAbandonedDragGivesEverythingBackToTheCursor) { session.menu.slot(0).cell.stack = makeStack(ItemId::Stone, 12); session.click(ClickKind::Left, 0); + session.click(ClickKind::DragLeftStart, -1); + CHECK(session.drag.active); + SlotActionResult released = session.click(ClickKind::DragLeftEnd, -1); + CHECK(released.applied); + CHECK_EQ(released.moved, 0); + CHECK_EQ(session.cursor.held.count, 12); + CHECK(!session.drag.active); + + // A drag end for the other button is not this drag's business. + session.click(ClickKind::DragLeftStart, 1); + CHECK(!session.click(ClickKind::DragRightEnd, -1).applied); + CHECK(session.drag.active); +} + +VF_TEST(aDragNeverStartsWithAnEmptyCursor) { + Session session(MenuKind::Chest); + session.menu.slot(0).cell.stack = makeStack(ItemId::Stone, 12); + CHECK(!session.click(ClickKind::DragLeftStart, 0).applied); + CHECK(!session.drag.active); + CHECK(!session.click(ClickKind::DragLeftAdd, 1).applied); + CHECK_EQ(session.menu.stackAt(0).count, 12); +} + +VF_TEST(throwingFromTheCursorReportsExactlyWhatLeftTheMenu) { + Session session(MenuKind::Chest); + session.menu.slot(0).cell.stack = makeStack(ItemId::Gravel, 6); + session.click(ClickKind::Left, 0); + + SlotActionResult one = session.click(ClickKind::DropOne, -1); + CHECK(one.applied); + CHECK_EQ(one.dropped, 1); + CHECK_EQ(one.droppedStacks.size(), 1u); + CHECK_EQ(one.droppedStacks[0].count, 1); + CHECK_EQ(session.cursor.held.count, 5); + + SlotActionResult all = session.click(ClickKind::DropStack, -1); + CHECK_EQ(all.dropped, 5); + CHECK(session.cursor.empty()); + CHECK(!session.click(ClickKind::DropStack, -1).applied); +} + +VF_TEST(throwingFromASlotOnlyWorksWithAnEmptyHand) { + Session session(MenuKind::Chest); + session.menu.slot(0).cell.stack = makeStack(ItemId::Gravel, 6); + + SlotActionResult one = session.click(ClickKind::DropOne, 0); + CHECK(one.applied); + CHECK_EQ(one.dropped, 1); + CHECK_EQ(session.menu.stackAt(0).count, 5); + + SlotActionResult rest = session.click(ClickKind::DropStack, 0); + CHECK_EQ(rest.dropped, 5); + CHECK(session.menu.stackAt(0).empty()); + CHECK(!session.click(ClickKind::DropOne, 0).applied); + + session.menu.slot(1).cell.stack = makeStack(ItemId::Stone, 4); + session.click(ClickKind::Left, 1); + session.menu.slot(2).cell.stack = makeStack(ItemId::Sand, 4); + CHECK(!session.click(ClickKind::DropOne, 2).applied); + CHECK_EQ(session.menu.stackAt(2).count, 4); +} + +VF_TEST(theResultSlotCannotBeUsedAsStorageByAnyClick) { + Session session(MenuKind::CraftingTable); + int result = session.menu.layout().resultSlot; + session.menu.slot(0).cell.stack = makeStack(ItemId::Stone, 10); + session.click(ClickKind::Left, 0); + + CHECK(!session.click(ClickKind::Left, result).applied); + CHECK(!session.click(ClickKind::Right, result).applied); + CHECK(!session.click(ClickKind::DragLeftStart, result).applied || + session.drag.paintedSlots.empty()); + session.drag.reset(); + CHECK(session.menu.stackAt(result).empty()); + CHECK_EQ(session.cursor.held.count, 10); +} + +VF_TEST(takingAResultOntoAMatchingCursorKeepsCrafting) { + Session session(MenuKind::CraftingTable); + CraftingView grid = session.menu.crafting(); + grid.input(0, 0) = makeStack(ItemId::Wood, 4); + grid.refresh(); + + session.click(ClickKind::Left, session.menu.layout().resultSlot); + CHECK_EQ(session.cursor.held.count, 4); + CHECK(session.cursor.held.item == ItemId::Planks); + + SlotActionResult second = session.click(ClickKind::Left, session.menu.layout().resultSlot); + CHECK(second.applied); + CHECK(second.craftedResult); + CHECK_EQ(session.cursor.held.count, 8); + CHECK_EQ(grid.input(0, 0).count, 2); + + // A cursor holding something else cannot take the result. + session.cursor.held = makeStack(ItemId::Stone, 1); + CHECK(!session.click(ClickKind::Left, session.menu.layout().resultSlot).applied); + CHECK_EQ(grid.input(0, 0).count, 2); +} + +VF_TEST(noSequenceOfChestClicksEverCreatesOrDestroysAnItem) { + WalkCoverage walk = runConservationWalk(MenuKind::Chest, 20260904u, 500); + // A walk that never actually did anything would pass the invariant for the + // wrong reason, so the coverage itself is asserted: most click kinds have + // to have landed, and items have to have really left through the drop path. + CHECK(walk.applied > 100); + CHECK(walk.dropped > 0); + CHECK(walk.distinctKindsApplied >= 12); +} + +VF_TEST(theSameInvariantHoldsOnAFilteredFurnaceScreen) { + WalkCoverage walk = runConservationWalk(MenuKind::Furnace, 77u, 500); + CHECK(walk.applied > 100); + CHECK(walk.dropped > 0); + CHECK(walk.distinctKindsApplied >= 12); +} + +VF_TEST(theSameInvariantHoldsOnAHopperAndOnALargeChest) { + WalkCoverage hopper = runConservationWalk(MenuKind::Hopper, 4242u, 500); + WalkCoverage large = runConservationWalk(MenuKind::LargeChest, 991u, 500); + CHECK(hopper.applied > 100); + CHECK(large.applied > 100); + CHECK(hopper.dropped > 0); + CHECK(large.dropped > 0); +} + +VF_TEST(theConservationWalkIsReproducibleFromItsSeed) { + CHECK_EQ(runConservationWalk(MenuKind::Chest, 555u, 500).applied, + runConservationWalk(MenuKind::Chest, 555u, 500).applied); + CHECK(runConservationWalk(MenuKind::Chest, 555u, 500).applied != + runConservationWalk(MenuKind::Chest, 556u, 500).applied); +}