From 76ca8e86f9b7bd7641a8481eb5c5b7e249b955f9 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 13 Sep 2026 21:30:05 +0200 Subject: [PATCH] test: extend coverage of testTrade --- tests/testTrade.cpp | 100 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/testTrade.cpp b/tests/testTrade.cpp index a6a690b..52b4b0b 100644 --- a/tests/testTrade.cpp +++ b/tests/testTrade.cpp @@ -313,3 +313,103 @@ VF_TEST(aCompletedTradeMovesBothSidesAndFeedsTheVillagerExperience) { Container wallet = makeWallet(40); TradeSession session(villager, offers, wallet); + int lapisOffer = 1; + CHECK(offers.at(lapisOffer).output == ItemId::LapisLazuli); + int price = session.priceOf(lapisOffer); + TradeResult outcome = session.trade(lapisOffer); + + CHECK(outcome.success); + CHECK(outcome.reason == TradeResult::Reason::Ok); + CHECK_EQ(outcome.pricePaid, price); + CHECK_EQ(outcome.secondaryPaid, 0); + CHECK_EQ(stockOf(wallet, ItemId::EmeraldGem), 40 - price); + CHECK_EQ(stockOf(wallet, ItemId::LapisLazuli), outcome.receivedCount); + CHECK_EQ(villager.experience, outcome.experienceGained); + CHECK_EQ(villager.gossip.valueOf(GossipKind::Trading), gossipTradingGain); + CHECK_EQ(session.tradesCompleted(), 1); + CHECK_EQ(session.emeraldsSpent(), price); + + bool sawLevelUp = false; + for (int i = 0; i < 12 && session.available(lapisOffer); ++i) + if (session.trade(lapisOffer).leveledUp) sawLevelUp = true; + CHECK(sawLevelUp); + CHECK_EQ(villager.level, 2); + CHECK(villager.gossip.valueOf(GossipKind::Trading) > gossipTradingGain); +} + +VF_TEST(secondaryInputIsRequiredAndConsumedByTheTrade) { + Villager villager = makeVillager(2, {0.5f, static_cast(walkY), 0.5f}, 5u); + villager.profession = VillagerProfession::Cartographer; + villager.level = 2; + TradeOfferList offers = buildTradeOffers(VillagerProfession::Cartographer, 3u); + Container wallet = makeWallet(60); + TradeSession session(villager, offers, wallet); + + int chestOffer = 3; + CHECK(offers.at(chestOffer).output == ItemId::Chest); + CHECK(offers.at(chestOffer).hasSecondaryInput()); + CHECK(offers.at(chestOffer).inputB == ItemId::GoldIngot); + + CHECK(!session.canAfford(chestOffer)); + CHECK(session.trade(chestOffer).reason == TradeResult::Reason::MissingInputB); + + wallet.insert(ItemId::GoldIngot, 3); + CHECK(session.canAfford(chestOffer)); + int price = session.priceOf(chestOffer); + TradeResult outcome = session.trade(chestOffer); + CHECK(outcome.success); + CHECK_EQ(outcome.secondaryPaid, offers.at(chestOffer).inputBCount); + CHECK_EQ(stockOf(wallet, ItemId::GoldIngot), 3 - offers.at(chestOffer).inputBCount); + CHECK_EQ(stockOf(wallet, ItemId::EmeraldGem), 60 - price); + CHECK_EQ(stockOf(wallet, ItemId::Chest), outcome.receivedCount); +} + +VF_TEST(sellingToTheVillagerTakesGoodsAndPaysOutEmeralds) { + Villager villager = makeLibrarian(1); + TradeOfferList offers = buildTradeOffers(VillagerProfession::Librarian, 1u); + Container wallet(27); + int planksOffer = 0; + CHECK(offers.at(planksOffer).inputA == ItemId::Planks); + CHECK(offers.at(planksOffer).output == ItemId::EmeraldGem); + + TradeSession session(villager, offers, wallet); + CHECK(session.trade(planksOffer).reason == TradeResult::Reason::MissingInputA); + + int price = session.priceOf(planksOffer); + wallet.insert(ItemId::Planks, price * 2); + TradeResult outcome = session.trade(planksOffer); + CHECK(outcome.success); + CHECK_EQ(stockOf(wallet, ItemId::Planks), price); + CHECK_EQ(stockOf(wallet, ItemId::EmeraldGem), outcome.receivedCount); + CHECK_EQ(session.emeraldsSpent(), 0); +} + +VF_TEST(tradingLeavesGossipAndAStrongReputationCutsThePrice) { + Villager villager = makeLibrarian(villagerMaxLevel); + TradeOfferList offers = buildTradeOffers(VillagerProfession::Librarian, 1u); + Container wallet = makeWallet(400); + TradeSession session(villager, offers, wallet); + + int diamondOffer = 7; + CHECK(offers.at(diamondOffer).tier == TradeTier::Master); + CHECK(offers.at(diamondOffer).output == ItemId::DiamondGem); + + for (int i = 0; i < 2; ++i) CHECK(session.trade(diamondOffer).success); + CHECK_EQ(villager.gossip.valueOf(GossipKind::Trading), gossipTradingGain * 2); + + restockOffers(offers); + CHECK_EQ(offers.at(diamondOffer).demand, 0); + session.refreshPrices(buildReputation(villager.gossip, {}), 0); + int politePrice = session.priceOf(diamondOffer); + CHECK_EQ(politePrice, offers.at(diamondOffer).basePrice()); + + villager.gossip.add(GossipKind::MajorPositive, gossipMajorPositiveGain); + ReputationView heroic = buildReputation(villager.gossip, {}); + CHECK_EQ(heroic.discountPercent(), 10); + session.refreshPrices(heroic, 0); + CHECK(session.priceOf(diamondOffer) < politePrice); + + session.refreshPrices(heroic, 3); + CHECK_EQ(session.priceModifier().totalPercent(), 90); + CHECK_EQ(session.priceOf(diamondOffer), 1); +}