Files
Battle-for-Tismo/tests/game_server_test.gd
T

158 lines
4.9 KiB
GDScript

extends TestCase
## Covers GameServer's order handling and setup: only a peer's own units and
## cities may be commanded, and only the first configuration is applied.
const LAND := "Land"
const SEED := 12345
func _map_config() -> MapGenerationConfig:
var config := MapGenerationConfig.new()
config.map_size = Vector2i(24, 16)
config.terrain_seed = SEED
config.min_capital_landmass = 1
config.min_capital_distance = 2.0
config.cities_per_civ = 2
config.city_spacing = 2
return config
func _server() -> GameServer:
var server := GameServer.new()
server.map_config = _map_config()
server.configure_game({
"seed": SEED,
"player_civ": 0,
"civilisations": [
"res://data/civilisations/civ_france.tres",
"res://data/civilisations/civ_britain.tres",
],
})
return server
func _adjacent_land(state: GameState, unit: Dictionary) -> Vector2i:
for neighbour in state._neighbours(unit["coords"]):
if str((state.tiles.get(neighbour, {}) as Dictionary).get("terrain_class")) == LAND:
return neighbour
return Vector2i(9999, 9999)
func test_configure_game_builds_a_state() -> void:
var server := _server()
assert_true(server.is_configured())
assert_not_null(server.state)
assert_eq(server.host_civ, 0)
assert_eq(server.state.units.size(), 2)
assert_eq(server.state.civilisations.size(), 2)
server.free()
func test_configure_game_ignores_a_second_call() -> void:
var server := _server()
var first_seed := server.state.seed
server.configure_game({"seed": 999, "player_civ": 1, "civilisations": []})
assert_eq(server.state.seed, first_seed)
server.free()
func test_move_order_for_own_unit_is_accepted() -> void:
var server := _server()
server.peer_civ[1] = 0
var unit := server.state.units[0]
var goal := _adjacent_land(server.state, unit)
assert_true(server.handle_order(1, {"type": "move", "unit": unit["id"], "coords": [goal.x, goal.y]}))
server.free()
## The server must advance ordered units every frame, not only on the hour, or
## the client's prediction could never be confirmed.
func test_server_process_advances_movement() -> void:
var server := _server()
server.peer_civ[1] = 0
var unit := server.state.units[0]
var goal := _adjacent_land(server.state, unit)
assert_true(server.handle_order(1, {"type": "move", "unit": unit["id"], "coords": [goal.x, goal.y]}))
for _i in 30:
server._process(1.0 / 60.0)
assert_true(float(unit["progress_hours"]) > 0.0, "movement advanced between hourly ticks")
assert_eq(server.state.total_hours, 0, "_process does not tick the clock")
server.free()
## State changes only mark the server dirty; the broadcast is deferred to the
## next frame so a burst of orders cannot trigger several full snapshots.
func test_state_changes_coalesce_into_one_broadcast() -> void:
var server := _server()
server._on_state_changed()
server._on_state_changed()
assert_true(server._state_dirty)
server._process(1.0 / 60.0)
assert_false(server._state_dirty, "the pending change was flushed")
server.free()
func test_move_order_for_enemy_unit_is_rejected() -> void:
var server := _server()
server.peer_civ[1] = 0
var enemy: Dictionary = {}
for candidate in server.state.units:
if int(candidate["civ"]) != 0:
enemy = candidate
var goal := _adjacent_land(server.state, enemy)
assert_false(server.handle_order(1, {"type": "move", "unit": enemy["id"], "coords": [goal.x, goal.y]}))
server.free()
func test_train_order_for_own_city_is_accepted_once() -> void:
var server := _server()
server.peer_civ[1] = 0
var city: Dictionary = server.state.cities[0]
var order := {"type": "train", "city": city["id"], "proto": 0}
assert_true(server.handle_order(1, order))
assert_false(server.handle_order(1, order), "city is already training")
server.free()
func test_train_order_for_enemy_city_is_rejected() -> void:
var server := _server()
server.peer_civ[1] = 0
var enemy: Dictionary = {}
for city in server.state.cities:
if int(city["civ"]) != 0:
enemy = city
break
if enemy.is_empty():
server.free()
return
assert_false(server.handle_order(1, {"type": "train", "city": enemy["id"], "proto": 0}))
server.free()
func test_orders_from_unknown_peers_are_rejected() -> void:
var server := _server()
assert_false(server.handle_order(42, {"type": "move", "unit": 1, "coords": [0, 0]}))
server.free()
func test_unknown_order_types_are_ignored() -> void:
var server := _server()
server.peer_civ[1] = 0
assert_false(server.handle_order(1, {"type": "dance"}))
server.free()
func test_orders_before_configuration_are_ignored() -> void:
var server := GameServer.new()
assert_false(server.handle_order(1, {"type": "move", "unit": 1, "coords": [0, 0]}))
server.free()
func test_empty_civilisation_list_falls_back_to_the_project() -> void:
var server := GameServer.new()
server.map_config = _map_config()
server.configure_game({"seed": SEED, "player_civ": 0, "civilisations": []})
assert_eq(server.state.civilisations.size(), server._default_civ_paths().size())
server.free()