package inventory import ( "path/filepath" "testing" "mc/internal/item" ) // loadItemReg 加载物品注册表。 func loadItemReg(t *testing.T) *item.Registry { t.Helper() r, err := item.Load(filepath.Join("..", "..", "assets", "config", "items.json")) if err != nil { t.Fatalf("加载物品注册表失败: %v", err) } return r } // TestMerge 验证合并规则(物品与背包.md §3 规则表)。 func TestMerge(t *testing.T) { reg := loadItemReg(t) inv := New(reg) // 放入 30 个木板 → 合并到 34 个 rem := inv.Add(item.Stack{Name: "oak_planks", Count: 30}) if !rem.Empty() { t.Fatal("30 个木板应全部放入") } rem = inv.Add(item.Stack{Name: "oak_planks", Count: 34}) if !rem.Empty() { t.Fatal("34 个木板应合并入同一槽") } // 64 上限:再放 10 应进入新槽(槽 0 已满 64) rem = inv.Add(item.Stack{Name: "oak_planks", Count: 10}) if !rem.Empty() { t.Fatalf("剩余期望空,实际 %d", rem.Count) } if inv.Slots[1].Name != "oak_planks" || inv.Slots[1].Count != 10 { t.Fatalf("槽 1 期望 10 个木板,实际 %+v", inv.Slots[1]) } } // TestRemove 验证取出物品。 func TestRemove(t *testing.T) { reg := loadItemReg(t) inv := New(reg) inv.Add(item.Stack{Name: "stick", Count: 16}) if !inv.Remove("stick", 5) { t.Fatal("应能取出 5 个") } if inv.Remove("stick", 20) { t.Fatal("不足 20 个不应成功") } if !inv.Remove("stick", 11) { t.Fatal("应能取出剩余 11 个") } } // TestSelected 验证选中槽。 func TestSelected(t *testing.T) { reg := loadItemReg(t) inv := New(reg) inv.Slots[3] = item.Stack{Name: "torch", Count: 8} inv.Selected = 3 if s := inv.SelectedStack(); s.Name != "torch" || s.Count != 8 { t.Fatalf("选中槽异常: %+v", s) } } func TestCanPlaceArmor(t *testing.T) { reg := loadItemReg(t) planks := item.Stack{Name: "oak_planks", Count: 1} helm := item.Stack{Name: "iron_helmet", Count: 1} if CanPlace(reg, SlotHelmet, planks) { t.Fatal("盔甲槽应拒收木板") } if !CanPlace(reg, SlotHelmet, helm) { t.Fatal("头盔槽应接收铁头盔") } if CanPlace(reg, SlotChest, helm) { t.Fatal("胸甲槽应拒收头盔") } if !CanPlace(reg, SlotOffhand, item.Stack{Name: "shield", Count: 1}) { t.Fatal("副手应接收盾") } if CanPlace(reg, SlotOffhand, planks) { t.Fatal("副手应拒收木板") } } func TestClickRightHalf(t *testing.T) { slot := item.Stack{Name: "oak_planks", Count: 5} ns, nh := ClickRight(slot, item.Stack{}, 64, true) if nh.Count != 3 || ns.Count != 2 { t.Fatalf("空手右键应拿一半向上取整:槽=%d 手=%d", ns.Count, nh.Count) } ns, nh = ClickRight(item.Stack{}, nh, 64, true) if ns.Count != 1 || nh.Count != 2 { t.Fatalf("手持右键应放 1 个:槽=%d 手=%d", ns.Count, nh.Count) } } func TestShiftHotbarMain(t *testing.T) { reg := loadItemReg(t) inv := New(reg) inv.Slots[0] = item.Stack{Name: "stick", Count: 8} if !inv.ShiftFromInv(0) { t.Fatal("热键栏 Shift 应移到主区") } if !inv.Slots[0].Empty() || inv.Slots[9].Name != "stick" || inv.Slots[9].Count != 8 { t.Fatalf("应进入主区槽 9,实际 hot=%+v main=%+v", inv.Slots[0], inv.Slots[9]) } } func TestAddSkipsArmor(t *testing.T) { reg := loadItemReg(t) inv := New(reg) for i := 0; i < StorageSize; i++ { inv.Slots[i] = item.Stack{Name: "dirt", Count: 64} } rem := inv.Add(item.Stack{Name: "oak_planks", Count: 1}) if rem.Empty() { t.Fatal("存储满时不应写入盔甲槽") } if !inv.Slots[SlotHelmet].Empty() { t.Fatal("盔甲槽应保持空") } } func TestSpreadEven(t *testing.T) { reg := loadItemReg(t) slots := []item.Stack{{}, {}, {}, {}, {}} ptrs := []*item.Stack{&slots[0], &slots[1], &slots[2], &slots[3], &slots[4]} held := SpreadEven(reg, item.Stack{Name: "oak_planks", Count: 5}, ptrs) if !held.Empty() { t.Fatalf("5 个应均分完,剩余 %+v", held) } for i, st := range slots { if st.Count != 1 { t.Fatalf("槽 %d 应各 1,实际 %+v", i, st) } } } func TestGather(t *testing.T) { reg := loadItemReg(t) inv := New(reg) inv.Slots[0] = item.Stack{Name: "stick", Count: 10} inv.Slots[9] = item.Stack{Name: "stick", Count: 20} held := inv.GatherStorage(item.Stack{}, "stick") if held.Count != 30 { t.Fatalf("应聚 30 棍,实际 %d", held.Count) } }