Files

84 lines
3.5 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { smallState } from "./framework/helpers.js";
import {
PROTO_UNITS,
TRAINABLE_UNIT_IDS,
SPY_OPERATIONS,
SPY_SABOTAGE,
SPY_CITY,
SPY_COMMS,
technologyById,
} from "../shared/data.js";
import { key, parseKey } from "../shared/hex.js";
export class SpyTest extends TestCase {
test_the_spy_is_a_gated_trainable_unit() {
const proto = PROTO_UNITS.find((u) => u.id === "spy");
this.assertNotNull(proto, "the spy exists");
this.assertTrue(proto.spy, "it is marked a spy");
this.assertFalse(proto.military, "it does not fight");
this.assertEqual(proto.vision, 1, "it watches a single tile out");
this.assertEqual(proto.requiresTechnology, "intelligence_agencies", "it needs the agency");
this.assertTrue(TRAINABLE_UNIT_IDS.includes("spy"), "it can be trained");
this.assertTrue(proto.icon.endsWith(".svg"), "it carries an icon");
this.assertNotNull(technologyById("intelligence_agencies"), "the agency technology exists");
this.assertNotNull(technologyById("counter_intelligence"), "the counter-intelligence technology exists");
}
test_the_covert_operations_are_well_formed() {
this.assertNotEmpty(SPY_OPERATIONS);
const ids = new Set();
for (const operation of SPY_OPERATIONS) {
this.assertTrue(operation.id.length > 0, "every operation has an id");
this.assertFalse(ids.has(operation.id), `the id ${operation.id} is unique`);
ids.add(operation.id);
this.assertTrue(operation.name.length > 0, `name of ${operation.id}`);
this.assertTrue(operation.description.length > 0, `description of ${operation.id}`);
}
this.assertTrue(ids.has(SPY_SABOTAGE), "sabotage");
this.assertTrue(ids.has(SPY_CITY), "city spying");
this.assertTrue(ids.has(SPY_COMMS), "comms spying");
}
test_an_enemy_spy_is_hidden_from_every_other_nation() {
const state = smallState();
const home = state.cities.find((city) => city.civ === 1);
const spy = state._spawnUnit(home.coords, 1, state.protoUnits.find((u) => u.id === "spy"));
const seenByEnemy = (state.snapshot(0).units || []).map((unit) => unit.id);
this.assertFalse(seenByEnemy.includes(spy.id), "the enemy never sees the spy");
const seenByOwner = (state.snapshot(1).units || []).map((unit) => unit.id);
this.assertTrue(seenByOwner.includes(spy.id), "its own nation always sees it");
}
test_a_spy_slips_through_foreign_territory() {
const state = smallState();
const home = state.cities.find((city) => city.civ === 0);
const spy = state._spawnUnit(home.coords, 0, state.protoUnits.find((u) => u.id === "spy"));
const infantry = state._spawnUnit(home.coords, 0, state.protoUnits.find((u) => u.id === "modern_infantry"));
// A quiet, unowned British land tile, explored by the spy's nation.
let foreign = null;
for (const [k, civ] of state.territory) {
if (civ !== 1) continue;
const coords = parseKey(k);
if (state._cityByCoords.has(k)) continue;
if (state.unitsAt(coords).length > 0) continue;
const tile = state.tiles[k];
if (!tile || tile.terrainClass !== "Land") continue;
foreign = coords;
break;
}
this.assertNotNull(foreign, "the fixture has a British land tile");
state.explored.get(0).add(key(foreign.x, foreign.y));
this.assertTrue(
state._canUnitEnter(spy, foreign, false),
"a spy may cross foreign land on the way through"
);
this.assertFalse(
state._canUnitEnter(infantry, foreign, false),
"a soldier still treats foreign land as a wall"
);
}
}