From f00b6650df29fb038f7510fb2bb83f152c5e2007 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 11 Sep 2026 19:00:19 +0200 Subject: [PATCH] test: cover withEnchant and hitsUntilBroken --- tests/testItemStack.cpp | 160 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 tests/testItemStack.cpp diff --git a/tests/testItemStack.cpp b/tests/testItemStack.cpp new file mode 100644 index 0000000..5d8ec2c --- /dev/null +++ b/tests/testItemStack.cpp @@ -0,0 +1,160 @@ +#include "testHarness.h" +#include "vf/ItemStack.h" + +#include +#include + +using namespace vf; + +namespace { + +EnchantSet withEnchant(EnchantKind kind, int level) { + EnchantSet set; + addEnchant(set, kind, level); + return set; +} + +int hitsUntilBroken(MetaStack stack, uint32_t seed, int limit) { + uint32_t rng = seed; + for (int hits = 1; hits <= limit; ++hits) { + WearResult wear = damageStack(stack, 1, rng); + if (wear == WearResult::Broke) return hits; + } + return -1; +} + +} // namespace + +VF_TEST(stackLimitFollowsTheItemKindRatherThanAFixedNumber) { + CHECK_EQ(makeStack(ItemId::Stone, 1).maxCount(), 64); + CHECK_EQ(makeStack(ItemId::Bread, 1).maxCount(), 64); + CHECK_EQ(makeTool(ItemId::IronPickaxe).maxCount(), 1); + CHECK_EQ(stackLimitFor(ItemId::None), 0); + + MetaStack overfilled = makeStack(ItemId::Stone, 200); + CHECK_EQ(overfilled.count, 64); + CHECK(overfilled.full()); + CHECK_EQ(overfilled.room(), 0); +} + +VF_TEST(aFreshToolCarriesItsFullDurabilityAndNothingElse) { + MetaStack pickaxe = makeTool(ItemId::DiamondPickaxe); + CHECK_EQ(pickaxe.count, 1); + CHECK_EQ(pickaxe.meta.durability.max, toolMaxDurability(ItemId::DiamondPickaxe)); + CHECK_EQ(pickaxe.meta.durability.used, 0); + CHECK(pickaxe.meta.durability.damageable()); + CHECK(!pickaxe.meta.durability.broken()); + CHECK_NEAR(pickaxe.meta.durability.fraction(), 1.0f, 0.0001f); + CHECK(pickaxe.meta.pristine()); + + MetaStack notATool = makeTool(ItemId::Stone); + CHECK(notATool.empty()); +} + +VF_TEST(twoUsedToolsOnlyMergeWhenTheirWearIsIdentical) { + uint32_t rng = 7u; + MetaStack fresh = makeTool(ItemId::IronPickaxe); + MetaStack used = makeTool(ItemId::IronPickaxe); + damageStack(used, 5, rng); + + CHECK(!stacksMergeable(fresh, used)); + CHECK(stacksMergeable(fresh, makeTool(ItemId::IronPickaxe))); + + MetaStack sameWear = makeTool(ItemId::IronPickaxe); + sameWear.meta.durability.used = used.meta.durability.used; + CHECK(stacksMergeable(used, sameWear)); + + StackTransfer refused = transferAll(used, fresh); + CHECK(refused.incompatible); + CHECK_EQ(refused.moved, 0); + CHECK_EQ(fresh.count, 1); + CHECK_EQ(used.count, 1); +} + +VF_TEST(anEnchantedSwordNeverMergesWithAPlainOne) { + MetaStack plain = makeTool(ItemId::DiamondSword); + MetaStack enchanted = makeEnchantedTool(ItemId::DiamondSword, + withEnchant(EnchantKind::Sharpness, 3)); + + CHECK(!stacksMergeable(plain, enchanted)); + CHECK(!stacksIdentical(plain, enchanted)); + + MetaStack sameEnchant = makeEnchantedTool(ItemId::DiamondSword, + withEnchant(EnchantKind::Sharpness, 3)); + CHECK(stacksMergeable(enchanted, sameEnchant)); + + MetaStack otherLevel = makeEnchantedTool(ItemId::DiamondSword, + withEnchant(EnchantKind::Sharpness, 2)); + CHECK(!stacksMergeable(enchanted, otherLevel)); +} + +VF_TEST(enchantmentOrderDoesNotChangeStackIdentity) { + EnchantSet forward; + addEnchant(forward, EnchantKind::Unbreaking, 2); + addEnchant(forward, EnchantKind::Efficiency, 4); + + EnchantSet reversed; + addEnchant(reversed, EnchantKind::Efficiency, 4); + addEnchant(reversed, EnchantKind::Unbreaking, 2); + + CHECK(sameEnchants(forward, reversed)); + CHECK(stacksMergeable(makeEnchantedTool(ItemId::IronPickaxe, forward), + makeEnchantedTool(ItemId::IronPickaxe, reversed))); + + EnchantSet shorter = withEnchant(EnchantKind::Efficiency, 4); + CHECK(!sameEnchants(forward, shorter)); +} + +VF_TEST(aCustomNameKeepsAStackOnItsOwn) { + MetaStack named = makeNamedStack(ItemId::Stone, 10, "Cornerstone"); + MetaStack plain = makeStack(ItemId::Stone, 10); + + CHECK_EQ(named.count, 1); + CHECK_EQ(named.maxCount(), 1); + CHECK(!stacksMergeable(named, plain)); + CHECK(stacksMergeable(named, makeNamedStack(ItemId::Stone, 1, "Cornerstone"))); + CHECK(!stacksMergeable(named, makeNamedStack(ItemId::Stone, 1, "Keystone"))); +} + +VF_TEST(transferMovesOnlyWhatFitsAndLeavesTheRestBehind) { + MetaStack source = makeStack(ItemId::Cobblestone, 40); + MetaStack destination = makeStack(ItemId::Cobblestone, 40); + + StackTransfer moved = transferAll(source, destination); + CHECK_EQ(moved.moved, 24); + CHECK(moved.destinationFull); + CHECK(!moved.sourceEmptied); + CHECK_EQ(destination.count, 64); + CHECK_EQ(source.count, 16); + + MetaStack elsewhere; + StackTransfer rest = transferAll(source, elsewhere); + CHECK_EQ(rest.moved, 16); + CHECK(rest.sourceEmptied); + CHECK(source.empty()); + CHECK_EQ(elsewhere.count, 16); + CHECK(elsewhere.item == ItemId::Cobblestone); +} + +VF_TEST(transferRefusesAnIncompatibleDestinationWithoutMovingAnything) { + MetaStack planks = makeStack(ItemId::Planks, 12); + MetaStack stone = makeStack(ItemId::Stone, 5); + + StackTransfer blocked = transferAll(planks, stone); + CHECK(blocked.incompatible); + CHECK_EQ(blocked.moved, 0); + CHECK_EQ(planks.count, 12); + CHECK_EQ(stone.count, 5); +} + +VF_TEST(splittingAStackLeavesTheLargerHalfBehind) { + MetaStack odd = makeStack(ItemId::Sand, 7); + MetaStack taken = splitHalf(odd); + CHECK_EQ(taken.count, 4); + CHECK_EQ(odd.count, 3); + + MetaStack single = makeStack(ItemId::Sand, 1); + MetaStack lastOne = splitHalf(single); + CHECK_EQ(lastOne.count, 1); + CHECK(single.empty()); +