From 2d7a1a726449a68d95d02f27be635f765356e1e5 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 11 Sep 2026 17:43:33 +0200 Subject: [PATCH] test: cover testEnchant --- tests/testEnchant.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/tests/testEnchant.cpp b/tests/testEnchant.cpp index 4aa1a88..9c9cdbb 100644 --- a/tests/testEnchant.cpp +++ b/tests/testEnchant.cpp @@ -164,3 +164,143 @@ VF_TEST(rolledEnchantmentsRespectTargetsCapsAndConflicts) { } } +VF_TEST(pickaxeRollsNeverProduceSwordOrBowEnchantments) { + bool sawDiggerEnchant = false; + for (uint32_t seed = 1; seed <= 200; ++seed) { + uint32_t rng = seed * 374761393u + 11u; + EnchantSet rolled = rollEnchantments(Enchantment::Target::Pickaxe, 10, 30, rng); + for (const Enchantment& entry : rolled.entries) { + CHECK(entry.kind != EnchantKind::Sharpness); + CHECK(entry.kind != EnchantKind::Looting); + CHECK(entry.kind != EnchantKind::Power); + CHECK(entry.kind != EnchantKind::Protection); + if (entry.kind == EnchantKind::Efficiency || entry.kind == EnchantKind::Fortune || + entry.kind == EnchantKind::SilkTouch) { + sawDiggerEnchant = true; + } + } + } + CHECK(sawDiggerEnchant); +} + +VF_TEST(conflictingFamiliesRejectEachOtherOnTheSameItem) { + CHECK(enchantsConflict(EnchantKind::Sharpness, EnchantKind::Smite)); + CHECK(enchantsConflict(EnchantKind::Smite, EnchantKind::BaneOfArthropods)); + CHECK(enchantsConflict(EnchantKind::SilkTouch, EnchantKind::Fortune)); + CHECK(enchantsConflict(EnchantKind::Protection, EnchantKind::BlastProtection)); + CHECK(enchantsConflict(EnchantKind::Infinity, EnchantKind::Mending)); + CHECK(!enchantsConflict(EnchantKind::Sharpness, EnchantKind::Knockback)); + CHECK(!enchantsConflict(EnchantKind::Sharpness, EnchantKind::Sharpness)); + + EnchantSet sword; + CHECK(addEnchant(sword, EnchantKind::Sharpness, 5)); + CHECK(!addEnchant(sword, EnchantKind::Smite, 3)); + CHECK(!addEnchant(sword, EnchantKind::Sharpness, 6)); + CHECK(!addEnchant(sword, EnchantKind::Sharpness, 4)); + CHECK(addEnchant(sword, EnchantKind::Knockback, 2)); + CHECK_EQ(sword.levelOf(EnchantKind::Sharpness), 5); + CHECK_EQ(sword.levelOf(EnchantKind::Smite), 0); + CHECK(sword.conflictsWith(EnchantKind::BaneOfArthropods)); + + CHECK(removeEnchant(sword, EnchantKind::Sharpness)); + CHECK(addEnchant(sword, EnchantKind::Smite, 3)); +} + +VF_TEST(anvilCombiningTwoEqualLevelsStepsUpAndBumpsPriorWork) { + EnchantSet target = setOf(EnchantKind::Sharpness, 3); + EnchantSet sacrifice = setOf(EnchantKind::Sharpness, 3); + + EnchantOffer merged = anvilCombine(target, 0, sacrifice, 0); + CHECK(merged.valid()); + CHECK_EQ(merged.enchants.levelOf(EnchantKind::Sharpness), 4); + CHECK_EQ(merged.requiredLevels, 4); + CHECK_EQ(merged.priorWork, 1); + + EnchantOffer capped = anvilCombine(setOf(EnchantKind::Sharpness, 5), 0, + setOf(EnchantKind::Sharpness, 5), 0); + CHECK_EQ(capped.enchants.levelOf(EnchantKind::Sharpness), 5); + + EnchantOffer upgraded = anvilCombine(setOf(EnchantKind::Sharpness, 1), 0, + setOf(EnchantKind::Sharpness, 4), 0); + CHECK_EQ(upgraded.enchants.levelOf(EnchantKind::Sharpness), 4); + + EnchantOffer downgraded = anvilCombine(setOf(EnchantKind::Sharpness, 4), 0, + setOf(EnchantKind::Sharpness, 1), 0); + CHECK_EQ(downgraded.enchants.levelOf(EnchantKind::Sharpness), 4); +} + +VF_TEST(anvilChargesAPenaltyForConflictingEnchantsAndDropsThem) { + EnchantSet sword = setOf(EnchantKind::Sharpness, 3); + EnchantSet book = setOf(EnchantKind::Smite, 2); + + EnchantOffer merged = anvilCombine(sword, 0, book, 0); + CHECK_EQ(merged.enchants.levelOf(EnchantKind::Smite), 0); + CHECK_EQ(merged.enchants.levelOf(EnchantKind::Sharpness), 3); + CHECK_EQ(merged.requiredLevels, 1); + + EnchantSet compatible = setOf(EnchantKind::Knockback, 2); + EnchantOffer stacked = anvilCombine(sword, 0, compatible, 0); + CHECK_EQ(stacked.enchants.levelOf(EnchantKind::Knockback), 2); + CHECK_EQ(stacked.requiredLevels, anvilCostMultiplier(EnchantKind::Knockback) * 2); +} + +VF_TEST(repeatedAnvilWorkEventuallyBecomesTooExpensive) { + CHECK_EQ(anvilRepairCost(0), 0); + CHECK_EQ(anvilRepairCost(1), 1); + CHECK_EQ(anvilRepairCost(3), 7); + CHECK_EQ(anvilRepairCost(6), 63); + + EnchantSet sword = setOf(EnchantKind::Unbreaking, 1); + int priorWork = 0; + int repairs = 0; + for (; repairs < 12; ++repairs) { + int held = sword.levelOf(EnchantKind::Unbreaking); + EnchantOffer merged = anvilCombine(sword, priorWork, setOf(EnchantKind::Unbreaking, held), 0); + if (merged.tooExpensive) break; + sword = merged.enchants; + priorWork = merged.priorWork; + } + CHECK(repairs > 2); + CHECK(repairs < 8); + CHECK(priorWork >= repairs); + CHECK(anvilCombine(sword, priorWork, setOf(EnchantKind::Unbreaking, 1), 0).tooExpensive); + CHECK_EQ(sword.levelOf(EnchantKind::Unbreaking), maxEnchantLevel(EnchantKind::Unbreaking)); +} + +VF_TEST(costBandsAndWeightsFollowTheRarityLadder) { + CHECK_EQ(enchantMinCost(EnchantKind::Sharpness, 1), 1); + CHECK_EQ(enchantMaxCost(EnchantKind::Sharpness, 1), 21); + CHECK_EQ(enchantMinCost(EnchantKind::Sharpness, 5), 45); + CHECK_EQ(enchantMinCost(EnchantKind::Mending, 1), 25); + + CHECK_EQ(enchantWeight(EnchantKind::Protection), 10); + CHECK_EQ(enchantWeight(EnchantKind::SilkTouch), 1); + CHECK_EQ(anvilCostMultiplier(EnchantKind::Sharpness), 1); + CHECK_EQ(anvilCostMultiplier(EnchantKind::SilkTouch), 8); + + for (int k = 0; k < static_cast(EnchantKind::Count); ++k) { + EnchantKind kind = static_cast(k); + for (int level = 1; level <= maxEnchantLevel(kind); ++level) { + CHECK(enchantMaxCost(kind, level) > enchantMinCost(kind, level)); + } + } +} + +VF_TEST(toolEnchantabilityFollowsTheMaterialAndMapsToTheRightTarget) { + CHECK_EQ(enchantabilityOf(ItemId::GoldSword), 22); + CHECK_EQ(enchantabilityOf(ItemId::DiamondPickaxe), 10); + CHECK_EQ(enchantabilityOf(ItemId::StoneAxe), 5); + CHECK_EQ(enchantabilityOf(ItemId::Bread), 0); + + CHECK(enchantTargetOf(ItemId::IronSword) == Enchantment::Target::Sword); + CHECK(enchantTargetOf(ItemId::IronPickaxe) == Enchantment::Target::Pickaxe); + CHECK(enchantTargetOf(ItemId::IronShovel) == Enchantment::Target::Shovel); + CHECK(enchantTargetOf(ItemId::Apple) == Enchantment::Target::Book); + + CHECK(enchantApplies(EnchantKind::FeatherFalling, Enchantment::Target::Boots)); + CHECK(!enchantApplies(EnchantKind::FeatherFalling, Enchantment::Target::Helmet)); + CHECK(enchantApplies(EnchantKind::Respiration, Enchantment::Target::Helmet)); + CHECK(enchantApplies(EnchantKind::Unbreaking, Enchantment::Target::Bow)); + CHECK(!enchantApplies(EnchantKind::Looting, Enchantment::Target::Axe)); + CHECK(enchantApplies(EnchantKind::Sharpness, Enchantment::Target::Axe)); +}