from engine.inventory import Inventory from engine.item import ItemDef, ItemInstance STAFF = ItemDef(id="staff_oak", name="Oak Staff", width=1, height=5) SANDWICH = ItemDef(id="sandwich", name="Sandwich", width=2, height=2, stackable=True, max_stack=4) def test_place_non_overlapping_items_succeeds(): inv = Inventory(6, 5) staff = ItemInstance("item-1", "staff_oak") sandwich = ItemInstance("item-2", "sandwich") assert inv.place(staff, STAFF, 0, 0) is True assert inv.place(sandwich, SANDWICH, 1, 0) is True assert {p.item.item_id for p in inv.items()} == {"item-1", "item-2"} def test_overlapping_placement_rejected(): inv = Inventory(6, 5) staff = ItemInstance("item-1", "staff_oak") other = ItemInstance("item-2", "sandwich") assert inv.place(staff, STAFF, 0, 0) is True assert inv.can_place(SANDWICH, 0, 2) is False # overlaps rows 2-3 of the staff at x=0 assert inv.place(other, SANDWICH, 0, 2) is False def test_out_of_bounds_placement_rejected(): inv = Inventory(6, 4) assert inv.can_place(STAFF, 0, 0) is False # height 5 doesn't fit in a 4-tall grid at all def test_remove_frees_footprint_for_reuse(): inv = Inventory(6, 5) staff = ItemInstance("item-1", "staff_oak") inv.place(staff, STAFF, 0, 0) removed = inv.remove("item-1", STAFF) assert removed is staff assert inv.can_place(STAFF, 0, 0) is True assert inv.place(staff, STAFF, 0, 0) is True def test_find_first_fit_returns_leftmost_topmost_slot(): inv = Inventory(6, 5) inv.place(ItemInstance("item-1", "staff_oak"), STAFF, 0, 0) slot = inv.find_first_fit(SANDWICH) assert slot == (1, 0) def test_item_at_finds_item_from_its_top_left_corner(): inv = Inventory(6, 5) staff = ItemInstance("item-1", "staff_oak") inv.place(staff, STAFF, 0, 0) placed = inv.item_at(0, 0) assert placed is not None assert placed.item is staff def test_item_at_finds_item_from_anywhere_in_its_footprint(): inv = Inventory(6, 5) sandwich = ItemInstance("item-2", "sandwich") inv.place(sandwich, SANDWICH, 1, 0) # occupies (1,0),(2,0),(1,1),(2,1) for cx, cy in [(1, 0), (2, 0), (1, 1), (2, 1)]: placed = inv.item_at(cx, cy) assert placed is not None assert placed.item is sandwich def test_item_at_returns_none_for_an_empty_cell(): inv = Inventory(6, 5) inv.place(ItemInstance("item-1", "staff_oak"), STAFF, 0, 0) assert inv.item_at(5, 4) is None def test_item_at_returns_none_out_of_bounds(): inv = Inventory(6, 5) assert inv.item_at(-1, 0) is None assert inv.item_at(6, 0) is None assert inv.item_at(0, 5) is None