// The phase catalog is a published claim about the turn: it must stay complete, ordered and // self-consistent, because the completion metric is computed from it. #include #include #include #include #include "app/phase_catalog.h" static int failures = 0; #define CHECK(c) \ do { \ if (!(c)) { \ std::printf("FAIL %s:%d %s\n", __FILE__, __LINE__, #c); \ ++failures; \ } \ } while (0) using namespace sots::app; static void CheckTable(const PhaseDesc* p, size_t n, Driver d, int firstIndex, std::set& ids, std::set& names) { for (size_t i = 0; i < n; ++i) { CHECK(p[i].driver == d); // Indices are contiguous and in execution order -- a gap means a phase was dropped. CHECK(p[i].index == firstIndex + static_cast(i)); CHECK(p[i].id && std::strlen(p[i].id) == 3); CHECK(p[i].name && p[i].name[0] != '\0'); CHECK(ids.insert(p[i].id).second); CHECK(names.insert(p[i].name).second); // Anything not a stub must carry a note saying what it does or what is missing. if (p[i].status != PhaseStatus::Stub) CHECK(p[i].note && p[i].note[0] != '\0'); } } int main() { std::set ids, names; size_t nh = 0, ns = 0, np = 0, nt = 0; const PhaseDesc* h = HostPhases(nh); const PhaseDesc* s = StrategicPhases(ns); const PhaseDesc* p = PlayerPhases(np); const PhaseDesc* t = TailPhases(nt); // The three published phase counts. These are load-bearing: the milestone is stated as // "N of 44", and 44 is 32 + 12. CHECK(ns == 32); CHECK(np == 12); CHECK(nt == 37); CHECK(static_cast(ns + np) == kSpinePhaseCount); // The host steps are deliberately NOT part of the milestone's denominator. Their ids run // H00, H02, H01 because the table is in EXECUTION order and H02 was read later than the // step it runs before; the id is the stable name, the index is the ordinal. CHECK(nh == 3); CheckTable(h, nh, Driver::Host, 0, ids, names); CheckTable(s, ns, Driver::Strategic, 0, ids, names); CheckTable(p, np, Driver::Player, 1, ids, names); CheckTable(t, nt, Driver::Tail, 0, ids, names); const PhaseTally spine = TallySpine(); CHECK(spine.total == kSpinePhaseCount); CHECK(spine.verified + spine.implemented + spine.partial + spine.blocked + spine.stub == spine.total); CHECK(spine.modelled() <= spine.total); CHECK(spine.committed() <= spine.modelled()); const PhaseTally tail = TallyTail(); CHECK(tail.total == 37); CHECK(tail.verified + tail.implemented + tail.partial + tail.blocked + tail.stub == tail.total); // A phase that does nothing must not claim to be verified: `Verified` in this table means // "compared against the live game", and nothing here has been. CHECK(spine.verified == 0); CHECK(tail.verified == 0); std::printf("catalog: spine %d/%d modelled (%d committed), tail %d/%d modelled\n", spine.modelled(), spine.total, spine.committed(), tail.modelled(), tail.total); std::printf(failures ? "FAILED (%d)\n" : "ok (%d failures)\n", failures); return failures ? 1 : 0; }