// Hull size, the defence-platform class flag, and the six-counter census. #include "game/design/hull.h" #include "game/design/stats.h" #include "mini_catalog.h" #include "test_main.h" using namespace game::data; using namespace game::design; namespace { Design platform() { Design d; d.name = "Light Defense Platform"; d.race = Species::Human; d.mission() = use("DEDefencePlatform", {"bal_gauss", "bal_gauss", "bal_gauss", "bal_gauss", "mis"}); return d; } Design cruiser() { Design d; d.name = "Cruiser"; d.race = Species::Human; d.command() = use("CRCommand", {}); d.mission() = use("CRArmor", {}); d.engine() = use("CRFission", {}); return d; } } // namespace TEST(hull_size_from_section_class) { CHECK_EQ(hull_size(SectionClass::Destroyer), 0); CHECK_EQ(hull_size(SectionClass::Cruiser), 1); CHECK_EQ(hull_size(SectionClass::Dreadnought), 2); // An absent or unrecognised class is a destroyer, not an error: the // original's name lookup fails and leaves the field at zero. CHECK_EQ(hull_size(SectionClass::None), 0); CHECK_EQ(hull_size(SectionClass::Other), 0); } TEST(hull_class_of_a_stock_destroyer) { HullClass h = classify_design(mini_catalog(), armor()); CHECK(h.ok()); CHECK_EQ(h.hull_size, 0); CHECK(!h.defence_platform); CHECK_EQ(h.resolved_sections, 3); CHECK_EQ(h.unresolved_sections, 0); } TEST(hull_class_of_a_cruiser) { HullClass h = classify_design(mini_catalog(), cruiser()); CHECK(h.ok()); CHECK_EQ(h.hull_size, 1); CHECK(!h.defence_platform); } TEST(defence_platform_flag_is_read_from_the_section) { const ShipSectionDef* s = mini_catalog().section("Human", "DEDefencePlatform"); CHECK(s != nullptr); if (s) CHECK(s->defence_platform.value_or(false)); const ShipSectionDef* armorsec = mini_catalog().section("Human", "DEArmor"); CHECK(armorsec != nullptr); if (armorsec) CHECK(!armorsec->defence_platform.value_or(false)); HullClass h = classify_design(mini_catalog(), platform()); CHECK(h.ok()); CHECK(h.defence_platform); CHECK_EQ(h.hull_size, 0); CHECK_EQ(h.resolved_sections, 1); } TEST(one_flagged_section_makes_the_whole_design_a_platform) { // The flag word is OR-ed across sections, so a design that mixes a // flagged section with unflagged ones is still a platform. No shipped // design does this -- the platforms are all standalone mission sections -- // so this is the rule, tested where the data cannot show it. Design d = armor(); d.mission() = use("DEDefencePlatform", {"bal_gauss", "bal_gauss", "bal_gauss", "bal_gauss", "mis"}); HullClass h = classify_design(mini_catalog(), d); CHECK(h.defence_platform); CHECK_EQ(h.resolved_sections, 3); } TEST(hull_size_takes_the_last_resolved_section) { // Assignment in slot order, not first-wins and not max. Class-mixing is a // rule A6 error, so this can only be shown on a design the validator // rejects -- which is exactly why it is worth pinning. Design d; d.race = Species::Human; d.command() = use("DECommand", {"bal_gauss"}); d.mission() = use("CRArmor", {}); HullClass h = classify_design(mini_catalog(), d); CHECK_EQ(h.resolved_sections, 2); CHECK_EQ(h.hull_size, 1); // the cruiser mission section, visited last Design r; r.race = Species::Human; r.command() = use("CRCommand", {}); r.mission() = use("DEArmor", {"bal_gauss", "bal_gauss", "mis"}); CHECK_EQ(classify_design(mini_catalog(), r).hull_size, 0); } TEST(an_unresolvable_design_is_reported_not_counted_as_a_destroyer) { Design d; d.race = Species::Human; d.mission() = use("NoSuchSection", {}); HullClass h = classify_design(mini_catalog(), d); CHECK(!h.ok()); CHECK_EQ(h.resolved_sections, 0); CHECK_EQ(h.unresolved_sections, 1); } TEST(derive_stats_carries_the_two_census_words) { DesignStats st = derive_stats(mini_rules(), armor()); CHECK_EQ(st.hull_size, 0); CHECK(!st.defence_platform); DesignStats p = derive_stats(mini_rules(), platform()); CHECK_EQ(p.hull_size, 0); CHECK(p.defence_platform); DesignStats c = derive_stats(mini_rules(), cruiser()); CHECK_EQ(c.hull_size, 1); CHECK_EQ(c.hull_class, "cruiser"); } TEST(census_counts_ships_and_platforms_separately) { ShipCensus c; HullClass de; // destroyer ship HullClass cr; cr.hull_size = 1; cr.resolved_sections = 1; HullClass dn; dn.hull_size = 2; dn.resolved_sections = 1; HullClass pl; pl.defence_platform = true; pl.resolved_sections = 1; de.resolved_sections = 1; c.add(de); c.add(de); c.add(cr); c.add(dn); c.add(pl); c.add(pl); c.add(pl); CHECK_EQ(c.ships[0], 2); CHECK_EQ(c.ships[1], 1); CHECK_EQ(c.ships[2], 1); CHECK_EQ(c.platforms[0], 3); CHECK_EQ(c.platforms[1], 0); CHECK_EQ(c.platforms[2], 0); CHECK_EQ(c.ship_total(), 4); CHECK_EQ(c.platform_total(), 3); }