Files
Battle-for-Tismo/tests/testing_mode_test.js
adrien d5305da449 Gave the world a simple economy: one pool per nation and a global market
The simple economy is now the default and the old simulation is frozen as the hard model, selectable per game. A nation keeps one resource pool available in every region, fed by public production works rather than private per-region stores, and construction and training begin at once, paced by the region's spare power instead of gathering materials over days.

Money is euro only: a per-inhabitant daily tax funds a treasury spent in a global market, where buy and sell lots trade against the world stock and move its price. The hard economy keeps its per-nation currencies, central banks and exchange rates.

Simple games skip the price-settling warmup and economic migration; the snapshot carries the economy model, the market and the pool figures the client draws. Added the matching test suites and the design briefs under docs/simple_economy.
2026-09-25 14:58:49 +02:00

160 lines
6.9 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { smallState, settleInlandCity, smallConfig } from "./framework/helpers.js";
import { GameServer } from "../server/game_server.js";
import { isLoopback, isLocalRequest } from "../server/server.js";
const BIG_BUDGET = 1.0e15;
function makeServer(testing) {
const network = { getPeerIds: () => [], send: () => {} };
const server = new GameServer(network);
server.configureGame({
seed: 12345,
player_civ: 0,
civilisations: ["france", "britain"],
testing,
mapConfig: smallConfig(),
// These fixtures compare the treasury before and after an order, so they
// pin the hard economy, where an order has a money cost to charge.
economyModel: "hard",
});
return server;
}
export class TestingModeTest extends TestCase {
test_loopback_addresses_are_recognised() {
this.assertTrue(isLoopback("127.0.0.1"), "v4 loopback");
this.assertTrue(isLoopback("127.0.1.5"), "any 127/8 address");
this.assertTrue(isLoopback("::1"), "v6 loopback");
this.assertTrue(isLoopback("::ffff:127.0.0.1"), "mapped v4 loopback");
this.assertFalse(isLoopback("10.0.0.1"), "a private address is remote");
this.assertFalse(isLoopback("::ffff:8.8.8.8"), "a mapped public address is remote");
this.assertFalse(isLoopback(""), "an empty address is remote");
this.assertFalse(isLoopback(undefined), "a missing address is remote");
}
test_a_local_page_is_distinguished_from_a_proxied_remote_client() {
this.assertTrue(isLocalRequest("127.0.0.1", "http://127.0.0.1:27015"), "a local page");
this.assertTrue(
isLocalRequest("::ffff:127.0.0.1", "http://localhost:27015"),
"a mapped local page"
);
this.assertFalse(
isLocalRequest("127.0.0.1", "https://tismo.example.com"),
"a proxied remote page is remote even though its socket is loopback"
);
this.assertFalse(
isLocalRequest("10.0.0.1", "http://127.0.0.1:27015"),
"a remote socket is remote"
);
this.assertFalse(isLocalRequest("127.0.0.1", ""), "a missing origin is remote");
}
test_free_training_spawns_instantly_and_costs_nothing() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const city = state.cities.find((c) => c.civ === 0);
const artillery = state.protoUnits.findIndex((u) => u.id === "artillery");
const before = state.units.filter((u) => u.civ === 0).length;
this.assertTrue(state.requestTrain(city.id, artillery, true), "the free order is accepted");
this.assertEqual(
state.units.filter((u) => u.civ === 0).length,
before + 1,
"the unit appears at once"
);
this.assertEqual(state.getBudget(0), BIG_BUDGET, "nothing is charged");
this.assertFalse(state.training.has(city.id), "nothing is queued");
}
test_free_build_raises_the_level_instantly_and_costs_nothing() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const city = state.cities.find((c) => c.civ === 0);
const barracks = state.protoBuildings.findIndex((b) => b.id === "barracks");
this.assertTrue(state.requestBuild(city.id, barracks, true), "the free build is accepted");
this.assertEqual(state.getCityBuildingLevel(city, barracks), 1, "the level rose at once");
this.assertEqual(state.getBudget(0), BIG_BUDGET, "nothing is charged");
this.assertFalse(state.training.has(city.id), "nothing is queued");
}
test_free_build_still_respects_placement_rules() {
const state = smallState();
const inland = settleInlandCity(state, 0);
this.assertNotNull(inland, "the fixture has an inland city");
const shipyard = state.protoBuildings.findIndex((b) => b.id === "shipyard");
this.assertFalse(state.requestBuild(inland.id, shipyard, true), "an inland shipyard is refused");
}
test_a_normal_order_still_charges_and_queues() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const city = state.cities.find((c) => c.civ === 0);
const barracks = state.protoBuildings.findIndex((b) => b.id === "barracks");
this.assertTrue(state.requestBuild(city.id, barracks), "the paid order is accepted");
this.assertEqual(state.getCityBuildingLevel(city, barracks), 0, "it does not rise at once");
this.assertLess(state.getBudget(0), BIG_BUDGET, "it was charged");
this.assertTrue(state.training.has(city.id), "it went into the queue");
}
test_server_honours_free_orders_in_a_testing_game() {
const server = makeServer(true);
server.peerCiv.set(1, 0);
const city = server.state.cities.find((c) => c.civ === 0);
const barracks = server.state.protoBuildings.findIndex((b) => b.id === "barracks");
const levelBefore = server.state.getCityBuildingLevel(city, barracks);
const budgetBefore = server.state.getBudget(0);
this.assertTrue(
server.handleOrder(1, { type: "build", city: city.id, building: barracks, free: true }),
"the order is accepted"
);
this.assertEqual(
server.state.getCityBuildingLevel(city, barracks),
levelBefore + 1,
"the building went up"
);
this.assertEqual(server.state.getBudget(0), budgetBefore, "it was free");
this.assertTrue(server.state.testing, "the snapshot flag is set");
}
test_server_ignores_the_free_flag_in_a_normal_game() {
const server = makeServer(false);
server.peerCiv.set(1, 0);
const city = server.state.cities.find((c) => c.civ === 0);
const barracks = server.state.protoBuildings.findIndex((b) => b.id === "barracks");
const levelBefore = server.state.getCityBuildingLevel(city, barracks);
const budgetBefore = server.state.getBudget(0);
this.assertTrue(
server.handleOrder(1, { type: "build", city: city.id, building: barracks, free: true }),
"the order is still processed"
);
this.assertEqual(
server.state.getCityBuildingLevel(city, barracks),
levelBefore,
"it only went into the queue"
);
this.assertLess(server.state.getBudget(0), budgetBefore, "the normal cost was charged");
this.assertFalse(server.state.testing, "the testing flag stays off");
}
test_a_local_peer_gets_free_orders_in_a_normal_game() {
const server = makeServer(false);
server.setPeerLocal(1, true);
server.peerCiv.set(1, 0);
const city = server.state.cities.find((c) => c.civ === 0);
const barracks = server.state.protoBuildings.findIndex((b) => b.id === "barracks");
const levelBefore = server.state.getCityBuildingLevel(city, barracks);
const budgetBefore = server.state.getBudget(0);
this.assertTrue(
server.handleOrder(1, { type: "build", city: city.id, building: barracks, free: true }),
"the order is accepted"
);
this.assertEqual(
server.state.getCityBuildingLevel(city, barracks),
levelBefore + 1,
"the building went up"
);
this.assertEqual(server.state.getBudget(0), budgetBefore, "it was free");
this.assertFalse(server.state.testing, "the game itself stays a normal game");
}
}