test: extend coverage of testBrewing

This commit is contained in:
dualfroz committed 2026-09-10 23:30:44 +02:00
1 parent 3a7affff0c
commit 73e65e5dd0
1 file changed
+223
+223
View File
@@ -313,3 +313,226 @@ VF_TEST(bottlesTheIngredientCannotChangeAreLeftAsTheyWere) {
CHECK(canBrew(stand)); CHECK(canBrew(stand));
for (int tick = 0; tick < brewDurationTicks; ++tick) tickBrewing(stand); for (int tick = 0; tick < brewDurationTicks; ++tick) tickBrewing(stand);
CHECK_EQ(stand.bottles[0].potion.kind, PotionKind::Swiftness);
CHECK_EQ(stand.bottles[1].potion.kind, PotionKind::Water);
CHECK(!stand.bottles[2].occupied);
}
VF_TEST(theStandRefusesAMixedIngredientStackButTakesMoreOfTheSame) {
BrewingStandState stand = fueledStand(PotionItem{}, 1);
CHECK(setIngredient(stand, Ingredient::Sugar, 2));
CHECK_EQ(stand.ingredientCount, 2);
CHECK(!setIngredient(stand, Ingredient::Redstone, 1));
CHECK_EQ(stand.ingredient, Ingredient::Sugar);
CHECK_EQ(stand.ingredientCount, 2);
CHECK(setIngredient(stand, Ingredient::Sugar, 3));
CHECK_EQ(stand.ingredientCount, 5);
CHECK(!setIngredient(stand, Ingredient::None, 1));
CHECK(!setIngredient(stand, Ingredient::Sugar, 0));
CHECK(!setIngredient(stand, Ingredient::Sugar, -4));
}
VF_TEST(everyCompletedBrewSpendsExactlyOneIngredientAndOneFuelCharge) {
BrewingStandState stand;
setBottle(stand, 0, PotionItem{});
addFuel(stand, 1);
setIngredient(stand, Ingredient::NetherWart, 3);
for (int tick = 0; tick < brewDurationTicks; ++tick) tickBrewing(stand);
CHECK_EQ(stand.ingredientCount, 2);
CHECK_EQ(stand.ingredient, Ingredient::NetherWart);
CHECK_EQ(stand.fuel, brewsPerBlazePowder - 1);
// The bottle is awkward now and nether wart does nothing to it, so the
// remaining stack sits unused instead of burning fuel.
CHECK(!canBrew(stand));
for (int tick = 0; tick < brewDurationTicks; ++tick) CHECK(!tickBrewing(stand));
CHECK_EQ(stand.ingredientCount, 2);
CHECK_EQ(stand.fuel, brewsPerBlazePowder - 1);
}
VF_TEST(fuelIsCountedInBrewsAndOneBlazePowderBuysTwenty) {
BrewingStandState stand;
CHECK(!addFuel(stand, 0));
CHECK(!addFuel(stand, -3));
CHECK_EQ(stand.fuel, 0);
CHECK(addFuel(stand, 1));
CHECK_EQ(stand.fuel, brewsPerBlazePowder);
CHECK(addFuel(stand, 2));
CHECK_EQ(stand.fuel, 3 * brewsPerBlazePowder);
}
VF_TEST(anEmptyFuelBarStopsTheStandEvenWithAValidRecipeLoaded) {
BrewingStandState stand;
setBottle(stand, 0, PotionItem{});
setIngredient(stand, Ingredient::NetherWart, 1);
CHECK(!canBrew(stand));
CHECK(!tickBrewing(stand));
CHECK_EQ(stand.progressTicks, 0);
stand.fuel = 1;
CHECK(canBrew(stand));
for (int tick = 0; tick < brewDurationTicks; ++tick) tickBrewing(stand);
CHECK_EQ(stand.fuel, 0);
CHECK_EQ(stand.bottles[0].potion.kind, PotionKind::Awkward);
setIngredient(stand, Ingredient::Sugar, 1);
CHECK(!canBrew(stand));
CHECK(!tickBrewing(stand));
}
VF_TEST(pullingABottleMidBrewThrowsAwayTheProgressBar) {
BrewingStandState stand = fueledStand(PotionItem{}, 1);
setIngredient(stand, Ingredient::NetherWart, 1);
for (int tick = 0; tick < 200; ++tick) tickBrewing(stand);
CHECK_EQ(stand.progressTicks, 200);
bool taken = false;
PotionItem pulled = takeBottle(stand, 0, taken);
CHECK(taken);
CHECK_EQ(pulled.kind, PotionKind::Water);
CHECK_EQ(stand.progressTicks, 0);
CHECK(!stand.bottles[0].occupied);
CHECK(!tickBrewing(stand));
CHECK(setBottle(stand, 0, PotionItem{}));
for (int tick = 1; tick < brewDurationTicks; ++tick) {
CHECK_EQ(tickBrewing(stand), false);
}
CHECK(tickBrewing(stand));
}
VF_TEST(bottleSlotsRejectOutOfRangeIndicesAndDoubleFilling) {
BrewingStandState stand;
CHECK(!setBottle(stand, -1, PotionItem{}));
CHECK(!setBottle(stand, brewingBottleSlots, PotionItem{}));
CHECK(setBottle(stand, 0, PotionItem{}));
CHECK(!setBottle(stand, 0, potionOf(PotionKind::Awkward)));
CHECK_EQ(stand.bottles[0].potion.kind, PotionKind::Water);
bool taken = true;
takeBottle(stand, 1, taken);
CHECK(!taken);
taken = true;
takeBottle(stand, brewingBottleSlots, taken);
CHECK(!taken);
}
VF_TEST(theFourBasePotionsCarryNoEffectAndCannotBeDrunkForOne) {
const PotionKind effectless[] = {PotionKind::Water, PotionKind::Mundane, PotionKind::Thick,
PotionKind::Awkward};
for (PotionKind kind : effectless) {
PotionItem potion = potionOf(kind);
CHECK(!potionHasEffect(potion));
CHECK_EQ(potionEffect(potion).kind, EffectKind::Count);
EffectSet target;
CHECK(!drinkPotion(target, potion));
CHECK(target.active.empty());
}
}
VF_TEST(drinkingWorksOnlyInDrinkableFormAndLandsTheCatalogDuration) {
EffectSet target;
PotionItem regeneration = potionOf(PotionKind::Regeneration);
CHECK(drinkPotion(target, regeneration));
CHECK_EQ(effectLevel(target, EffectKind::Regeneration), 1);
CHECK_EQ(effectDuration(target, EffectKind::Regeneration), 900);
PotionItem splash = regeneration;
splash.form = PotionItem::Form::Splash;
EffectSet other;
CHECK(!drinkPotion(other, splash));
CHECK(other.active.empty());
PotionItem strong = regeneration;
strong.upgraded = true;
CHECK(drinkPotion(target, strong));
CHECK_EQ(effectLevel(target, EffectKind::Regeneration), 2);
CHECK_EQ(effectDuration(target, EffectKind::Regeneration), 440);
}
VF_TEST(splashPotencyFallsOffLinearlyAndClampsAtBothEnds) {
CHECK_NEAR(splashPotency(0.0f, 4.0f), 1.0f, 0.0001f);
CHECK_NEAR(splashPotency(1.0f, 4.0f), 0.75f, 0.0001f);
CHECK_NEAR(splashPotency(4.0f, 4.0f), 0.0f, 0.0001f);
CHECK_NEAR(splashPotency(9.0f, 4.0f), 0.0f, 0.0001f);
CHECK_NEAR(splashPotency(-2.0f, 4.0f), 1.0f, 0.0001f);
CHECK_NEAR(splashPotency(1.0f, 0.0f), 0.0f, 0.0001f);
}
VF_TEST(aSplashTimedPotionKeepsItsLevelAndLosesDurationWithDistance) {
PotionItem splash = potionOf(PotionKind::Swiftness);
splash.form = PotionItem::Form::Splash;
EffectSet atImpact;
CHECK(splashPotion(atImpact, splash, 0.0f, 4.0f));
CHECK_EQ(effectLevel(atImpact, EffectKind::Speed), 1);
CHECK_EQ(effectDuration(atImpact, EffectKind::Speed), 2700);
EffectSet halfway;
CHECK(splashPotion(halfway, splash, 2.0f, 4.0f));
CHECK_EQ(effectDuration(halfway, EffectKind::Speed), 1350);
EffectSet outOfRange;
CHECK(!splashPotion(outOfRange, splash, 4.0f, 4.0f));
CHECK(outOfRange.active.empty());
EffectSet wrongForm;
CHECK(!splashPotion(wrongForm, potionOf(PotionKind::Swiftness), 0.0f, 4.0f));
}
VF_TEST(aSplashInstantPotionScalesItsPotencyInsteadOfItsDuration) {
PotionItem harming = potionOf(PotionKind::Harming);
harming.form = PotionItem::Form::Splash;
EffectSet target;
CHECK(splashPotion(target, harming, 3.0f, 4.0f));
CHECK_EQ(target.active.size(), std::size_t{1});
CHECK_EQ(target.active[0].kind, EffectKind::InstantDamage);
CHECK_EQ(target.active[0].durationTicks, 1);
CHECK_NEAR(target.active[0].potency, 0.25f, 0.0001f);
PotionItem strong = harming;
strong.upgraded = true;
EffectSet direct;
CHECK(splashPotion(direct, strong, 0.0f, 4.0f));
CHECK_EQ(direct.active[0].level(), 2);
CHECK_NEAR(direct.active[0].potency, 1.0f, 0.0001f);
}
VF_TEST(everyPotionKindKeepsTheLevelAndDurationInvariantsOfItsModifiers) {
for (int index = 0; index < static_cast<int>(PotionKind::Count); ++index) {
PotionKind kind = static_cast<PotionKind>(index);
PotionItem plain = potionOf(kind);
EffectInstance base = potionEffect(plain);
CHECK_EQ(potionHasEffect(plain), base.kind != EffectKind::Count);
if (!potionHasEffect(plain)) {
CHECK_EQ(base.durationTicks, 0);
continue;
}
CHECK(base.durationTicks > 0);
CHECK_EQ(base.level(), 1);
int upgradedDuration = durationOf(kind, true, false);
int extendedDuration = durationOf(kind, false, true);
CHECK(extendedDuration >= base.durationTicks);
CHECK(levelOf(kind, false, true) == 1);
int upgradedLevel = levelOf(kind, true, false);
CHECK(upgradedLevel >= 1);
if (upgradedLevel > 1 && !isInstantEffect(base.kind)) {
CHECK(upgradedDuration < base.durationTicks);
}
if (isInstantEffect(base.kind)) {
CHECK_EQ(base.durationTicks, 1);
CHECK_EQ(upgradedDuration, 1);
}
}
}