import { TestCase } from "./framework/test_case.js"; import { RESOURCE_BUILDINGS, RESOURCE_RULES, TILE_IMPROVEMENTS, STATUSES, POLICY_OPINION, opinionToPoints, SPY_OPERATIONS, AIR_DEFENSE, SATELLITE, SABOTAGE, PARALLEL_LINES_PER_LEVEL, buildingById, policyById, } from "../shared/data.js"; import { formatEnergy, formatResourceAmount } from "../shared/resources.js"; import { formatNumber, formatPercent } from "../shared/text_format.js"; // Every figure a description quotes must be derived from the same field the // simulation applies, never typed in. These tests recompute the figure and // assert the description shows it, so a rule change that leaves the prose stale // fails here. export class DescriptionsTest extends TestCase { test_resource_building_descriptions_quote_their_output() { for (const proto of RESOURCE_BUILDINGS) { const output = formatResourceAmount(proto.resource, proto.outputPerDay); this.assertTrue( proto.description.includes(output), `${proto.id} should quote ${output}: ${proto.description}` ); } } test_material_producer_descriptions_quote_their_energy_ratio() { const ratios = { steel_mill: RESOURCE_RULES.energyPerSteelTonne, gold_mine: RESOURCE_RULES.energyPerLuxuryCarat.gold_mine, diamond_mine: RESOURCE_RULES.energyPerLuxuryCarat.diamond_mine, chip_foundry: RESOURCE_RULES.energyPerHighTechUnit, }; for (const [id, ratio] of Object.entries(ratios)) { const proto = RESOURCE_BUILDINGS.find((b) => b.id === id); const energy = formatEnergy(ratio); this.assertTrue( proto.description.includes(energy), `${id} should quote ${energy} per unit: ${proto.description}` ); } } test_building_descriptions_quote_their_rules() { const shelters = buildingById("shelters"); const protection = formatPercent(shelters.civilianProtectionPerLevel); this.assertTrue(shelters.description.includes(protection), `shelters quote ${protection}`); const air = buildingById("aa_building"); this.assertTrue(air.description.includes(`${AIR_DEFENSE.rangeTiles} tiles`), "air defense range"); const port = buildingById("port"); const production = formatNumber(port.productionPerSeaTilePerLevel); this.assertTrue(port.description.includes(production), `port quote ${production}`); const space = buildingById("space_launch_center"); this.assertTrue(space.description.includes(`${SATELLITE.revealEveryDays} days`), "satellite cadence"); this.assertTrue( space.description.includes(String(SATELLITE.perLaunchCentreLevel)), "satellites per centre level" ); for (const id of ["barracks", "shipyard"]) { const proto = buildingById(id); this.assertTrue( proto.description.includes(String(PARALLEL_LINES_PER_LEVEL)), `${id} quotes ${PARALLEL_LINES_PER_LEVEL} line(s)` ); } } test_improvement_descriptions_quote_their_range() { for (const [id, field] of [["radar_tower", "vision"], ["coastal_cannon", "range"]]) { const proto = TILE_IMPROVEMENTS.find((i) => i.id === id); this.assertTrue( proto.description.includes(String(proto[field])), `${id} quotes its ${field} (${proto[field]})` ); } } test_status_descriptions_quote_their_effect() { const encircled = STATUSES.find((s) => s.id === "encircled"); this.assertTrue(encircled.description.includes(formatPercent(encircled.hpLossPerDay))); this.assertTrue(encircled.description.includes(formatPercent(encircled.cityHpLossPerDay))); const battle = STATUSES.find((s) => s.id === "battle"); this.assertTrue(battle.description.includes(String(battle.upkeepMultiplier))); } test_policy_effects_quote_their_opinion_shift() { const expected = [ ["champion", "championTarget", "targetEffect"], ["champion", "championMajority", "politicalCost"], ["protect", "protectTarget", "targetEffect"], ["protect", "protectMajority", "politicalCost"], ["expel", "expelTarget", "politicalCost"], ["immigration", "immigrationOthers", "politicalCost"], ]; for (const [id, field, slot] of expected) { const points = opinionToPoints(POLICY_OPINION[field]); this.assertTrue( policyById(id)[slot].includes(String(Math.abs(points))), `${id}.${slot} should quote ${Math.abs(points)} points` ); } } test_spy_operation_descriptions_quote_their_block() { const sabotage = SPY_OPERATIONS.find((op) => op.id === "sabotage"); this.assertTrue(sabotage.description.includes(`${SABOTAGE.blockDays} days`)); } }