#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());