84 lines
3.5 KiB
JavaScript
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"
|
|
);
|
|
}
|
|
}
|