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