Files
Battle-for-Tismo/tests/game_state_buildings_test.js
T

154 lines
6.5 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { smallState, cityOf, gdpBuilding } from "./framework/helpers.js";
import { ECONOMY, EFFECT_BUDGET_INCOME, EFFECT_RESEARCH } from "../shared/data.js";
const BIG_BUDGET = 1.0e15;
export class GameStateBuildingsTest extends TestCase {
addBuilding(state, proto) {
state.protoBuildings.push(proto);
return state.protoBuildings.length - 1;
}
test_request_build_charges_budget_and_raises_the_level() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const index = this.addBuilding(state, gdpBuilding());
const city = cityOf(state, 0);
const beforeBudget = state.getBudget(0);
const beforeGdp = state.getPlayerGdp(0);
this.assertTrue(state.requestBuild(city.id, index));
this.assertEqual(state.getCityBuildingLevel(city, index), 1);
this.assertLess(state.getBudget(0), beforeBudget, "cost was paid");
this.assertGreater(state.getPlayerGdp(0), beforeGdp, "GDP bonus applied");
}
test_request_build_rejects_when_unaffordable() {
const state = smallState();
state.budgets.set(0, 0);
const index = this.addBuilding(state, gdpBuilding());
this.assertFalse(state.requestBuild(cityOf(state, 0).id, index));
}
test_request_build_respects_max_level() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const index = this.addBuilding(state, gdpBuilding({ maxLevel: 1 }));
const cityId = cityOf(state, 0).id;
this.assertTrue(state.requestBuild(cityId, index));
this.assertFalse(state.requestBuild(cityId, index), "already at max level");
}
test_request_build_rejects_unknown_targets() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
this.assertFalse(state.requestBuild(99999, 0));
this.assertFalse(state.requestBuild(cityOf(state, 0).id, 9999));
}
test_request_demolish_refunds_and_removes_the_building() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const index = this.addBuilding(state, gdpBuilding());
const city = cityOf(state, 0);
this.assertTrue(state.requestBuild(city.id, index));
this.assertTrue(state.requestBuild(city.id, index));
const before = state.getBudget(0);
this.assertTrue(state.requestDemolish(city.id, index));
this.assertEqual(state.getCityBuildingLevel(city, index), 1);
this.assertGreater(state.getBudget(0), before, "refunded");
this.assertTrue(state.requestDemolish(city.id, index));
this.assertEqual(state.getCityBuildingLevel(city, index), 0);
this.assertFalse(state.requestDemolish(city.id, index), "nothing left to demolish");
}
test_building_upkeep_is_added_to_player_upkeep() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const index = this.addBuilding(
state,
gdpBuilding({ baseCost: 0, costGdpFraction: 0, baseUpkeep: 100, upkeepAlpha: 1.0 })
);
const before = state.getPlayerUpkeep(0);
this.assertTrue(state.requestBuild(cityOf(state, 0).id, index));
this.assertApprox(state.getPlayerUpkeep(0), before + 100);
}
test_research_buildings_accumulate_points_each_hour() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const building = gdpBuilding({ baseCost: 0, costGdpFraction: 0, effects: [] });
building.effects.push({ stat: EFFECT_RESEARCH, baseValue: 2.0, exponent: 1.0 });
const index = this.addBuilding(state, building);
this.assertTrue(state.requestBuild(cityOf(state, 0).id, index));
this.assertEqual(state.getResearch(0), 0);
state.advanceHour();
const first = state.getResearch(0);
const governmentRate = state.getCivGovernmentModifiers(0)[EFFECT_RESEARCH] || 0;
this.assertApprox(first - governmentRate, 2.0);
state.advanceHour();
this.assertApprox(state.getResearch(0) - first - governmentRate, 2.0);
}
test_viewer_stats_split_income_and_upkeep() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const index = this.addBuilding(
state,
gdpBuilding({ baseCost: 0, costGdpFraction: 0, baseUpkeep: 100, upkeepAlpha: 1.0, effects: [] })
);
this.assertTrue(state.requestBuild(cityOf(state, 0).id, index));
const breakdown = state.viewerStats(0).breakdown;
this.assertHas(breakdown, "income");
this.assertHas(breakdown, "buildingUpkeep");
this.assertHas(breakdown, "unitUpkeep");
this.assertApprox(breakdown.buildingUpkeep.total, 100);
this.assertApprox(
breakdown.unitUpkeep.total,
state.getPlayerUpkeep(0) - breakdown.buildingUpkeep.total
);
const expected = state.getPlayerGdp(0) * ECONOMY.budgetGdpRate * (1 + breakdown.income.modifier);
this.assertApprox(breakdown.income.total, expected);
}
test_budget_breakdown_names_income_sources() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const effect = { stat: EFFECT_BUDGET_INCOME, baseValue: 0.05, exponent: 1.0 };
const index = this.addBuilding(
state,
gdpBuilding({ baseCost: 0, costGdpFraction: 0, baseUpkeep: 0, effects: [effect] })
);
this.assertTrue(state.requestBuild(cityOf(state, 0).id, index));
const breakdown = state.viewerStats(0).breakdown;
const source = breakdown.income.sources.find((s) => s.label === "Test market");
this.assertTrue(source, "the building appears as an income source");
this.assertEqual(source.kind, "building");
this.assertApprox(source.effect, 0.05);
this.assertApprox(breakdown.income.modifier, state.getCivModifiers(0)[EFFECT_BUDGET_INCOME] || 0);
this.assertApprox(source.amount, breakdown.income.base * 0.05);
this.assertApprox(breakdown.income.total, breakdown.income.base * (1 + breakdown.income.modifier));
}
test_snapshot_exposes_buildings_and_resources() {
const state = smallState();
const snapshot = state.snapshot(0);
this.assertSize(snapshot.buildings, state.protoBuildings.length);
this.assertHas(snapshot, "research");
this.assertHas(snapshot, "culture");
for (const city of snapshot.cities) this.assertHas(city, "buildings");
this.assertHas(snapshot.viewerStats, "research");
this.assertHas(snapshot.viewerStats, "culture");
}
test_snapshot_serialises_city_building_levels() {
const state = smallState();
state.budgets.set(0, BIG_BUDGET);
const index = this.addBuilding(state, gdpBuilding());
const cityId = cityOf(state, 0).id;
this.assertTrue(state.requestBuild(cityId, index));
const city = state.snapshot(0).cities.find((c) => c.id === cityId);
this.assertEqual(city.buildings[index], 1);
}
}