From 5f13d209360024420397ba31c1eb425402df7ce2 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sat, 12 Sep 2026 23:00:22 +0200 Subject: [PATCH] test: cover manualObjective and statObjective --- tests/testScoreboard.cpp | 157 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 tests/testScoreboard.cpp diff --git a/tests/testScoreboard.cpp b/tests/testScoreboard.cpp new file mode 100644 index 0000000..c1e8bcb --- /dev/null +++ b/tests/testScoreboard.cpp @@ -0,0 +1,157 @@ +#include "testHarness.h" +#include "vf/Scoreboard.h" + +#include + +using namespace vf; + +namespace { + +ScoreObjective manualObjective(const std::string& name) { + ScoreObjective objective; + objective.name = name; + objective.displayName = name; + return objective; +} + +ScoreObjective statObjective(const std::string& name, StatKind kind, int subject = -1) { + ScoreObjective objective = manualObjective(name); + objective.criterion = ScoreObjective::Criterion::Statistic; + objective.statKind = kind; + objective.statSubject = subject; + return objective; +} + +ScoreTeam makeTeam(const std::string& name, ScoreTeam::Color color) { + ScoreTeam team; + team.name = name; + team.displayName = name; + team.color = color; + return team; +} + +} // namespace + +VF_TEST(statSheetsTallyEveryKindWithAndWithoutASubject) { + StatSheet sheet; + CHECK_EQ(sheet.revision(), 0); + CHECK_EQ(sheet.total(StatKind::Deaths), 0); + + sheet.add(StatKind::Deaths, 1); + sheet.add(StatKind::PlayTicks, 12000); + sheet.add(StatKind::DistanceWalked, 450); + sheet.add(StatKind::DistanceSprinted, 1200); + sheet.addBlockBroken(Block::Stone, 40); + sheet.addBlockBroken(Block::Dirt, 7); + sheet.addItemUsed(ItemId::IronPickaxe, 3); + sheet.addMobKilled(Species::Zombie, 2); + sheet.addMobKilled(Species::Creeper); + + CHECK_EQ(sheet.total(StatKind::Deaths), 1); + CHECK_EQ(sheet.total(StatKind::PlayTicks), 12000); + CHECK_EQ(sheet.blocksBroken(Block::Stone), 40); + CHECK_EQ(sheet.blocksBroken(Block::Sand), 0); + CHECK_EQ(sheet.total(StatKind::BlocksBroken), 47); + CHECK_EQ(sheet.itemsUsed(ItemId::IronPickaxe), 3); + CHECK_EQ(sheet.mobsKilled(Species::Zombie), 2); + CHECK_EQ(sheet.mobsKilled(Species::Creeper), 1); + CHECK_EQ(sheet.total(StatKind::MobsKilled), 3); + CHECK_EQ(sheet.distanceTravelled(), 1650); + CHECK_EQ(sheet.distinctSubjects(StatKind::BlocksBroken), 2); + CHECK_EQ(sheet.distinctSubjects(StatKind::Deaths), 1); + + long long before = sheet.revision(); + sheet.add(StatKind::Deaths, 0); + CHECK_EQ(sheet.revision(), before); + sheet.add(StatKind::Deaths, 1); + CHECK_EQ(sheet.revision(), before + 1); + CHECK_EQ(sheet.total(StatKind::Deaths), 2); + + std::vector counters = sheet.counters(); + CHECK_EQ(counters.size(), static_cast(9)); + for (std::size_t i = 1u; i < counters.size(); ++i) { + bool ordered = counters[i - 1u].kind < counters[i].kind || + (counters[i - 1u].kind == counters[i].kind && + counters[i - 1u].subject < counters[i].subject); + CHECK(ordered); + } + + sheet.clear(); + CHECK_EQ(sheet.counters().size(), static_cast(0)); + CHECK_EQ(sheet.total(StatKind::BlocksBroken), 0); + CHECK(sheet.revision() > before); + + for (int i = 0; i < static_cast(StatKind::Count); ++i) { + StatKind kind = static_cast(i); + StatKind reparsed = StatKind::Count; + CHECK(parseStatKindName(statKindName(kind), reparsed)); + CHECK(reparsed == kind); + } + StatKind unknown = StatKind::Count; + CHECK(!parseStatKindName("blocksPlaced", unknown)); + CHECK(statKindHasSubject(StatKind::BlocksBroken)); + CHECK(!statKindHasSubject(StatKind::Deaths)); + CHECK(statKindIsDistance(StatKind::DistanceFallen)); + CHECK(!statKindIsDistance(StatKind::PlayTicks)); +} + +VF_TEST(anAutomaticObjectiveFollowsTheStatSheetWithNoUpdateStep) { + Scoreboard board; + CHECK(board.addObjective(statObjective("mined", StatKind::BlocksBroken))); + CHECK(board.addObjective(statObjective("stone", StatKind::BlocksBroken, + static_cast(Block::Stone)))); + CHECK(board.addObjective(statObjective("deaths", StatKind::Deaths))); + + CHECK_EQ(board.score("mined", "foksiu"), 0); + CHECK(!board.tracked("mined", "foksiu")); + + board.stats("foksiu").addBlockBroken(Block::Stone, 12); + CHECK(board.tracked("mined", "foksiu")); + CHECK_EQ(board.score("mined", "foksiu"), 12); + CHECK_EQ(board.score("stone", "foksiu"), 12); + + board.stats("foksiu").addBlockBroken(Block::Dirt, 5); + CHECK_EQ(board.score("mined", "foksiu"), 17); + CHECK_EQ(board.score("stone", "foksiu"), 12); + + board.stats("foksiu").add(StatKind::Deaths, 1); + CHECK_EQ(board.score("deaths", "foksiu"), 1); + CHECK_EQ(board.score("mined", "foksiu"), 17); + + // An automatic objective refuses to be written by hand. + CHECK(!board.setScore("mined", "foksiu", 999)); + CHECK(!board.addScore("mined", "foksiu", 1)); + CHECK_EQ(board.score("mined", "foksiu"), 17); + + CHECK(!board.addObjective(statObjective("mined", StatKind::Deaths))); + CHECK_EQ(board.objectiveNames().size(), static_cast(3)); + CHECK(board.objective("mined")->automatic()); + CHECK(board.objective("nothing") == nullptr); + CHECK_EQ(board.score("nothing", "foksiu"), 0); +} + +VF_TEST(manualObjectivesOnlyMoveWhenSomethingSetsThem) { + Scoreboard board; + CHECK(board.addObjective(manualObjective("bounty"))); + CHECK(!board.addObjective(manualObjective(""))); + + CHECK(!board.tracked("bounty", "foksiu")); + CHECK(board.setScore("bounty", "foksiu", 10)); + CHECK(board.tracked("bounty", "foksiu")); + CHECK_EQ(board.score("bounty", "foksiu"), 10); + CHECK(board.addScore("bounty", "foksiu", -4)); + CHECK_EQ(board.score("bounty", "foksiu"), 6); + CHECK(board.addScore("bounty", "newcomer", 3)); + CHECK_EQ(board.score("bounty", "newcomer"), 3); + + CHECK(!board.setScore("absent", "foksiu", 1)); + CHECK(board.resetScore("bounty", "foksiu")); + CHECK(!board.resetScore("bounty", "foksiu")); + CHECK(!board.tracked("bounty", "foksiu")); + CHECK_EQ(board.score("bounty", "foksiu"), 0); + + board.stats("newcomer").add(StatKind::Deaths, 2); + board.resetPlayer("newcomer"); + CHECK(!board.tracked("bounty", "newcomer")); + CHECK(board.statsFor("newcomer") == nullptr); +