// The global resource pool and public production introduced by // 02-resource-pool-and-production.md: one pool per player, every producer // feeding it, and no per-tile store or private-agent accounting in the simple // model. The hard economy must keep its per-region stores. // // Note on the hard fixtures: `smallState` now pins `economyModel: "hard"` so // the historical suites keep exercising the model they were written against; // these tests use `simpleState` for the simple model. import { TestCase } from "./framework/test_case.js"; import { simpleState, smallState, cityOf } from "./framework/helpers.js"; import { SIMPLE_ECONOMY, STORABLE_RESOURCE_IDS } from "../shared/data.js"; export class SimplePoolTest extends TestCase { test_a_simple_game_has_one_seeded_pool_per_civ() { const state = simpleState(); this.assertEqual(state.resourcePools.size, state.civilisations.length, "one pool per nation"); for (let civ = 0; civ < state.civilisations.length; civ++) { const pool = state.getResourcePool(civ); for (const id of STORABLE_RESOURCE_IDS) { this.assertEqual( pool[id], SIMPLE_ECONOMY.startingPool[id], `${id} in civ ${civ}'s pool` ); } } } test_a_simple_game_keeps_no_per_tile_stock() { const state = simpleState(); state.applyStartingScenario(); for (let hour = 0; hour < 24; hour++) state.advanceHour(); this.assertEqual(state.resourceStock.size, 0, "nothing is written to the per-tile store"); } test_a_city_stock_is_a_view_of_its_owners_pool() { const state = simpleState(); const pool = state.getResourcePool(0); const city = cityOf(state, 0); this.assertTrue(state.getCityResourceStock(city) === pool, "the city reads the pool"); state.getCityResourceStock(city).steel = 1234; this.assertEqual(pool.steel, 1234, "an edit through the city view lands in the pool"); } test_the_hard_game_keeps_per_tile_stock() { const state = smallState(); this.assertEqual(typeof state.getResourcePool, "undefined", "no pool API on the hard model"); this.assertTrue(state.resourceStock.size > 0, "hard cities and works hold their own stock"); } test_the_public_producers_fill_the_pool() { const state = simpleState(); // Isolate production from the day's consumption and grid, so whatever the // pool gains is exactly the public works' and the land's output. state._consumeCityResources = () => {}; state._settleUpkeep = () => 1; state._applyWorksMaintenance = () => {}; state._buildEnergyLedger = () => new Map(); const pool = state.getResourcePool(0); for (const id of STORABLE_RESOURCE_IDS) pool[id] = 0; state._tickResources(); const produced = STORABLE_RESOURCE_IDS.filter((id) => pool[id] > 0); this.assertNotEmpty(produced, `a public producer fed the pool (got ${JSON.stringify(pool)})`); } test_procurement_is_a_pool_draw_without_a_supplier_search() { const state = simpleState(); const pool = state.getResourcePool(0); pool.steel = 1000; let searched = false; state._nearbySuppliers = () => { searched = true; return []; }; state._resourceNodes = () => { searched = true; return []; }; const city = cityOf(state, 0); const drawn = state._drawFromNearest(0, city.coords, { steel: 400, hightech: 0 }); this.assertEqual(drawn.steel, 400, "the pool supplied the draw"); this.assertEqual(pool.steel, 600, "and was debited exactly"); this.assertFalse(searched, "no supplier search ran"); const rest = state._drawFromNearest(0, city.coords, { steel: 1000, hightech: 0 }); this.assertEqual(rest.steel, 600, "a shortfall takes only what is there"); this.assertEqual(pool.steel, 0, "the pool is empty, not negative"); } test_a_pool_shortfall_leaves_the_need_unmet() { const state = simpleState(); const pool = state.getResourcePool(0); pool.steel = 100; const missing = state._drawFromCities(0, "steel", 500); this.assertEqual(missing, 400, "the unmet amount is reported"); this.assertEqual(pool.steel, 0); const city = cityOf(state, 0); this.assertEqual( state._procureFromNeighbours(city, "steel", 400, {}, state._resourceNodes(), {}), 0, "no bid is placed for the shortfall" ); } test_the_summary_reports_the_pool_and_its_public_production() { const state = simpleState(); const summary = state.getCivResourceSummary(0); const pool = state.getResourcePool(0); for (const id of STORABLE_RESOURCE_IDS) { this.assertEqual(summary.stock[id], pool[id], `${id} stock is the pool`); } this.assertTrue(summary.production.food > 0, "the land's harvest is public production"); } test_a_simple_day_moves_the_pool_without_throwing() { const state = simpleState(); state.applyStartingScenario(); const before = { ...state.getResourcePool(0) }; for (let hour = 0; hour < 24; hour++) state.advanceHour(); const after = state.getResourcePool(0); const changed = STORABLE_RESOURCE_IDS.some((id) => before[id] !== after[id]); this.assertTrue(changed, "the day's production and consumption moved the pool"); this.assertEqual(state.getPrivateBuildingCash(0), 0, "no private building cash is kept"); this.assertEmpty(state.getProductionAgents(0), "no private production agents exist"); } }