The atlas 'regional' screen now opens the LADDER at the canonical orbital frame (Region granularity, whole body fitted and centered) and wheel zoom descends continuously — cursor-anchored, unclamped across rungs, with progressive refinement (held composite keeps drawing, finer rung swaps in place on arrival; no blank frame, no mode flip). Full-zoom-out resets to the canonical planetary frame per Jeroen's HARD condition (is_fully_zoomed_out = extent >= body circumference, not a zoom-value heuristic). The district_screen nav hop is deleted — D-013 restored: descent is a zoom gesture, not a nav push. AtlasViewer's heightmap-texture path is unreachable from nav (code intact; overlay surface deferred, see report/tickets). Rung selection: design doc §5's literal formula has NO legal District band at any real viewport (visual-tolerance band and n=64 coverage ceiling never overlap — pinned by executable boundary tests at 1600x900); select_rung() splits it into a coverage ceiling (decides Region) then the 2x visual tolerance (District vs Quarter), documented at the function. In practice the ladder steps Region -> Quarter directly. Wire: window_granularity_v2 encoded (omitted at District for byte-compat), granularity_v2 echoed value keyed + staleness-guarded end to end; Region clamp mirror replicates the server's bounded halving loop (no closed form). MIN/MAX_ZOOM widened to [0.0005, 64] — the old 0.5 floor would have clamped a real body's canonical fit zoom, violating the reset condition. Real pre-existing bug fixed in atlas_window_overlay.gd: the draw path used echoed n as both cell-grid dimension and district extent — only coincidentally correct at District granularity; Quarter/Region would have read wrong array offsets. cell_grid_side_for_window() now mirrors the server's WindowGranularity::cell_grid_side. Tests: +26 pure-function geometry tests, new 30-test zoom-ladder suite, extensions across the window cache/request/overlay/delivery suites. Full suite 3518 green; cold-parse clean.
446 lines
19 KiB
GDScript
446 lines
19 KiB
GDScript
## T-949 tests: Atlas data delivery migration — StarMapRequest/StarMapResponse
|
|
## and CityNamesRequest/CityNamesResponse (protocol.gd encode/decode,
|
|
## decode_inbound's frame classification, and SimBridge signal routing).
|
|
##
|
|
## Wire shapes pinned to dudley-atlas-server's contract (2026-07-14):
|
|
## AtlasLayerResponse gains road_graph/settlements (Option, "None until ready"
|
|
## like district_grid); StarMapResponse is {status, data} (data = a verbatim
|
|
## MessagePack re-encoding of star_map_data.json, unwrapped by
|
|
## star_map_response_from_raw so callers see {"nodes": [...]} directly);
|
|
## CityNamesResponse is {body_id, status, cities: [{city_id, name, is_capital}]}
|
|
## with a SolExcluded status as the server-side Sol backstop (D-236).
|
|
class_name TestAtlasDataDelivery
|
|
extends GdUnitTestSuite
|
|
|
|
# T-1138: REGION_TEMP_NONE_DC sentinel reused verbatim for district_window's
|
|
# temp_dc field (D-226 T-1124 amendment §2 — one colorizer/sentinel scheme
|
|
# across both zoom levels). No class_name on atlas_overlay_colors.gd (review
|
|
# #8 precedent elsewhere in this suite) — preloaded by path.
|
|
const AtlasOverlayColors := preload("res://ui/implant/apps/atlas/atlas_overlay_colors.gd")
|
|
|
|
|
|
# =============================================================================
|
|
# Encode/decode round-trips
|
|
# =============================================================================
|
|
|
|
|
|
func test_encode_star_map_request_carries_discriminator() -> void:
|
|
var bytes := Protocol.encode_star_map_request()
|
|
assert_int(bytes.size()).is_greater(0)
|
|
var decoded = Messagepack.decode(bytes)
|
|
assert_that(decoded.status == null).is_true()
|
|
assert_that(decoded.value.get("star_map")).is_equal(true)
|
|
|
|
|
|
func test_star_map_response_from_raw_unwraps_data_to_nodes() -> void:
|
|
var nodes := [
|
|
{"system_id": "GJ 71", "proper_name": "Tau Ceti"},
|
|
{"system_id": "GJ 0", "proper_name": "Sol"},
|
|
]
|
|
var raw := {"status": "Ready", "data": {"_meta": {"system_count": 2}, "nodes": nodes}}
|
|
var response: Variant = Protocol.star_map_response_from_raw(raw)
|
|
assert_that(response).is_not_null()
|
|
assert_str((response as Dictionary).get("status")).is_equal("Ready")
|
|
assert_that((response as Dictionary).get("nodes")).is_equal(nodes)
|
|
|
|
|
|
func test_star_map_response_from_raw_error_status_yields_no_nodes() -> void:
|
|
var raw := {"status": {"Error": "db unavailable"}, "data": null}
|
|
var response: Variant = Protocol.star_map_response_from_raw(raw)
|
|
assert_that(response).is_not_null()
|
|
assert_str((response as Dictionary).get("status")).is_equal("Error")
|
|
assert_str((response as Dictionary).get("error")).is_equal("db unavailable")
|
|
assert_that((response as Dictionary).get("nodes")).is_equal([])
|
|
|
|
|
|
func test_star_map_response_from_raw_rejects_shape_without_status() -> void:
|
|
assert_that(Protocol.star_map_response_from_raw({"data": {}})).is_null()
|
|
assert_that(Protocol.star_map_response_from_raw("not a dict")).is_null()
|
|
|
|
|
|
func test_decode_star_map_response_bytes_round_trip() -> void:
|
|
var raw := {"status": "Ready", "data": {"nodes": [{"system_id": "GJ 71"}]}}
|
|
var encoded = Messagepack.encode(raw)
|
|
var response: Variant = Protocol.decode_star_map_response(encoded.value)
|
|
assert_that(response).is_not_null()
|
|
assert_that((response as Dictionary).get("nodes")).is_equal(raw["data"]["nodes"])
|
|
|
|
|
|
func test_encode_city_names_request_carries_discriminator_and_body_id() -> void:
|
|
var bytes := Protocol.encode_city_names_request("GJ903b")
|
|
var decoded = Messagepack.decode(bytes)
|
|
assert_that(decoded.status == null).is_true()
|
|
assert_that(decoded.value.get("city_names")).is_equal(true)
|
|
assert_that(decoded.value.get("body_id")).is_equal("GJ903b")
|
|
|
|
|
|
func test_city_names_response_from_raw_round_trips_ready() -> void:
|
|
var cities := [{"city_id": 1, "name": "Ridgeback", "is_capital": false}]
|
|
var raw := {"body_id": "GJ903b", "status": "Ready", "cities": cities}
|
|
var response: Variant = Protocol.city_names_response_from_raw(raw)
|
|
assert_that(response).is_not_null()
|
|
assert_str((response as Dictionary).get("body_id")).is_equal("GJ903b")
|
|
assert_str((response as Dictionary).get("status")).is_equal("Ready")
|
|
assert_that((response as Dictionary).get("cities")).is_equal(cities)
|
|
|
|
|
|
func test_city_names_response_from_raw_sol_excluded() -> void:
|
|
var raw := {"body_id": "GJ0d", "status": "SolExcluded", "cities": []}
|
|
var response: Variant = Protocol.city_names_response_from_raw(raw)
|
|
assert_that(response).is_not_null()
|
|
assert_str((response as Dictionary).get("status")).is_equal("SolExcluded")
|
|
|
|
|
|
func test_city_names_response_from_raw_requires_body_id_and_status() -> void:
|
|
assert_that(Protocol.city_names_response_from_raw({"body_id": "GJ903b"})).is_null()
|
|
assert_that(Protocol.city_names_response_from_raw({"status": "Ready"})).is_null()
|
|
|
|
|
|
# =============================================================================
|
|
# decode_inbound classification — snapshot / atlas / starmap / citynames
|
|
# =============================================================================
|
|
|
|
|
|
func test_decode_inbound_classifies_snapshot() -> void:
|
|
var raw := {"tick": 1, "entities": []}
|
|
var encoded = Messagepack.encode(raw)
|
|
var inbound: Dictionary = Protocol.decode_inbound(encoded.value)
|
|
assert_str(inbound.kind).is_equal("snapshot")
|
|
|
|
|
|
func test_decode_inbound_classifies_atlas() -> void:
|
|
var raw := {"body_id": "GJ1c", "status": "Ready", "layer1": null, "district_grid": null}
|
|
var encoded = Messagepack.encode(raw)
|
|
var inbound: Dictionary = Protocol.decode_inbound(encoded.value)
|
|
assert_str(inbound.kind).is_equal("atlas")
|
|
|
|
|
|
func test_decode_inbound_classifies_starmap() -> void:
|
|
# StarMapResponse is the only kind with "data" and no "body_id".
|
|
var raw := {"status": "Ready", "data": {"nodes": [{"system_id": "GJ 71"}]}}
|
|
var encoded = Messagepack.encode(raw)
|
|
var inbound: Dictionary = Protocol.decode_inbound(encoded.value)
|
|
assert_str(inbound.kind).is_equal("starmap")
|
|
assert_that((inbound.value as Dictionary).get("nodes")).is_equal(raw["data"]["nodes"])
|
|
|
|
|
|
func test_decode_inbound_classifies_citynames() -> void:
|
|
# CityNamesResponse is the only kind with "cities" — must classify as
|
|
# citynames, NOT atlas, even though both carry status + body_id.
|
|
var raw := {"body_id": "GJ903b", "status": "Ready", "cities": [{"city_id": 1, "name": "Ridgeback"}]}
|
|
var encoded = Messagepack.encode(raw)
|
|
var inbound: Dictionary = Protocol.decode_inbound(encoded.value)
|
|
assert_str(inbound.kind).is_equal("citynames")
|
|
assert_that((inbound.value as Dictionary).get("body_id")).is_equal("GJ903b")
|
|
|
|
|
|
func test_atlas_response_road_graph_and_settlements_passthrough() -> void:
|
|
var road_graph := {
|
|
"nodes": [{"position": [1, 2], "kind": "Settlement", "city_id": 5}],
|
|
"edges":
|
|
[
|
|
{
|
|
"from": 0,
|
|
"to": 1,
|
|
"path": [[1, 2], [3, 4]],
|
|
"maintenance": "Trade",
|
|
"is_rail": false,
|
|
"named_route_id": null,
|
|
}
|
|
],
|
|
}
|
|
var settlements := {
|
|
"settlements":
|
|
[
|
|
{
|
|
"city_id": 5,
|
|
"name": "Ridgeback",
|
|
"position": [1, 2],
|
|
"size_class": "Minor",
|
|
"is_capital": false,
|
|
"is_port": false,
|
|
}
|
|
]
|
|
}
|
|
var raw := {
|
|
"body_id": "GJ1c",
|
|
"status": "Ready",
|
|
"road_graph": road_graph,
|
|
"settlements": settlements,
|
|
}
|
|
var decoded: Variant = Protocol.atlas_response_from_raw(raw)
|
|
assert_that(decoded).is_not_null()
|
|
assert_that((decoded as Dictionary).get("road_graph")).is_equal(road_graph)
|
|
assert_that((decoded as Dictionary).get("settlements")).is_equal(settlements)
|
|
|
|
|
|
func test_atlas_response_road_graph_and_settlements_default_null() -> void:
|
|
# A Ready response before road_graph/settlements land on a given server
|
|
# build must decode cleanly with both fields absent, not error.
|
|
var decoded: Variant = Protocol.atlas_response_from_raw({"body_id": "GJ1c", "status": "Ready"})
|
|
assert_that(decoded).is_not_null()
|
|
assert_that((decoded as Dictionary).get("road_graph")).is_null()
|
|
assert_that((decoded as Dictionary).get("settlements")).is_null()
|
|
|
|
|
|
# =============================================================================
|
|
# T-1138 (D-226 T-1124 amendment): windowed district-resolution regional map
|
|
# =============================================================================
|
|
|
|
|
|
## §1: window_center/window_n are OMITTED (not sent as null) when no window is
|
|
## requested — this is what makes an old-shaped call (every whole-body-layer
|
|
## call site) byte-identical to pre-T-1138 wire traffic.
|
|
func test_encode_atlas_layer_request_omits_window_fields_by_default() -> void:
|
|
var bytes := Protocol.encode_atlas_layer_request("GJ1c", "Topography")
|
|
var decoded = Messagepack.decode(bytes)
|
|
assert_that(decoded.status == null).is_true()
|
|
assert_bool(decoded.value.has("window_center")).is_false()
|
|
assert_bool(decoded.value.has("window_n")).is_false()
|
|
|
|
|
|
## §1: a windowed request carries window_center as a [row, col] pair (the same
|
|
## int-pair convention every other position field on this channel already
|
|
## uses — road_graph nodes, settlements, Layer-1 river cells) and window_n
|
|
## verbatim, unclamped (the server owns the [1, DISTRICT_WINDOW_MAX_N] clamp).
|
|
func test_encode_atlas_layer_request_carries_window_params() -> void:
|
|
var bytes := Protocol.encode_atlas_layer_request(
|
|
"GJ1c", "Topography", Vector2i(140, 260), 32
|
|
)
|
|
var decoded = Messagepack.decode(bytes)
|
|
assert_that(decoded.status == null).is_true()
|
|
assert_that(decoded.value.get("body_id")).is_equal("GJ1c")
|
|
assert_that(decoded.value.get("window_center")).is_equal([140, 260])
|
|
assert_that(decoded.value.get("window_n")).is_equal(32)
|
|
|
|
|
|
## T-1150: window_granularity/window_min_wl_m are OMITTED (not sent as 0)
|
|
## when at their default — a windowed request that doesn't pass them (every
|
|
## pre-T-1150 window caller) is byte-identical to pre-T-1150 wire traffic,
|
|
## same contract as window_center/window_n's own default-omission above.
|
|
func test_encode_atlas_layer_request_omits_granularity_and_min_wl_by_default() -> void:
|
|
var bytes := Protocol.encode_atlas_layer_request(
|
|
"GJ1c", "Topography", Vector2i(140, 260), 32
|
|
)
|
|
var decoded = Messagepack.decode(bytes)
|
|
assert_bool(decoded.value.has("window_granularity")).is_false()
|
|
assert_bool(decoded.value.has("window_min_wl_m")).is_false()
|
|
|
|
|
|
## T-1150: a quarter-granularity request with an octave cutoff carries both
|
|
## new fields verbatim, unclamped (the server owns
|
|
## resolve_window_granularity()/clamp_window_n() — never trusted from the
|
|
## wire, same posture as window_n).
|
|
func test_encode_atlas_layer_request_carries_granularity_and_min_wl() -> void:
|
|
var bytes := Protocol.encode_atlas_layer_request(
|
|
"GJ1c", "Topography", Vector2i(140, 260), 32, 4, 512
|
|
)
|
|
var decoded = Messagepack.decode(bytes)
|
|
assert_that(decoded.value.get("window_granularity")).is_equal(4)
|
|
assert_that(decoded.value.get("window_min_wl_m")).is_equal(512)
|
|
|
|
|
|
## T-1152/T-1153: window_granularity_v2 is OMITTED (not sent as "") when at
|
|
## its empty-string default — same byte-compatibility contract as
|
|
## window_granularity/window_min_wl_m's own default-omission.
|
|
func test_encode_atlas_layer_request_omits_granularity_v2_by_default() -> void:
|
|
var bytes := Protocol.encode_atlas_layer_request(
|
|
"GJ1c", "Topography", Vector2i(140, 260), 32
|
|
)
|
|
var decoded = Messagepack.decode(bytes)
|
|
assert_bool(decoded.value.has("window_granularity_v2")).is_false()
|
|
|
|
|
|
## T-1152/T-1153: a Region-rung request carries window_granularity_v2 as the
|
|
## bare string "Region" — the ONLY way to express the coarser-than-district
|
|
## rung (WindowGranularity's Rust doc: "the ONLY way to actually request
|
|
## Region is window_granularity_v2 = Some(WindowGranularity::Region)"), a
|
|
## plain rmp_serde variant-name encoding matching RoadNodeKind's existing
|
|
## wire precedent, NOT an integer discriminant.
|
|
func test_encode_atlas_layer_request_carries_granularity_v2_region() -> void:
|
|
var bytes := Protocol.encode_atlas_layer_request(
|
|
"GJ1c", "Topography", Vector2i(0, 0), 6400, 0, 0, "Region"
|
|
)
|
|
var decoded = Messagepack.decode(bytes)
|
|
assert_that(decoded.value.get("window_granularity_v2")).is_equal("Region")
|
|
# The legacy window_granularity field is independently omittable — a
|
|
# Region request sends ONLY the v2 tag, never a legacy value pretending
|
|
# to mean something for Region (WINDOW_GRANULARITY_REGION_KEY is a
|
|
# key-space tag the SERVER echoes, never a legal wire INPUT).
|
|
assert_bool(decoded.value.has("window_granularity")).is_false()
|
|
|
|
|
|
## §2: district_window is a distinct payload (echoes center/n for the
|
|
## client's staleness guard) but the codec passthrough is the same shape as
|
|
## every sibling layer — raw.get(), no reshaping. Field types follow the
|
|
## established district_grid/region_grid convention: u8 arrays decode as
|
|
## PackedByteArray, i16 (temp_dc, REGION_TEMP_NONE_DC sentinel scheme) as a
|
|
## plain Array (test_region_grid_round_trips' mean_temp_dc precedent).
|
|
func test_atlas_response_district_window_passthrough() -> void:
|
|
var window := {
|
|
"center": [140, 260],
|
|
"n": 32,
|
|
"granularity": 4, # T-1150: quarter granularity, passed through same as every other field
|
|
"min_wl_m": 512,
|
|
"morphology": PackedByteArray([8, 14, 0, 5]),
|
|
"elev_q": PackedByteArray([40, 62, 5, 88]),
|
|
"temp_dc": [120, 95, AtlasOverlayColors.REGION_TEMP_NONE_DC, 60],
|
|
"moisture_q": PackedByteArray([50, 30, 90, 20]),
|
|
"vegetation": PackedByteArray([2, 1, 6, 3]),
|
|
"glaciation": PackedByteArray([0, 0, 1, 2]),
|
|
}
|
|
var raw := {"body_id": "GJ1c", "status": "Ready", "district_window": window}
|
|
var decoded: Variant = Protocol.atlas_response_from_raw(raw)
|
|
assert_that(decoded).is_not_null()
|
|
assert_that((decoded as Dictionary).get("district_window")).is_equal(window)
|
|
|
|
|
|
## T-1152/T-1153, design doc §6 encoding-continuity acceptance: a Region-rung
|
|
## response passes through the EXACT SAME codec path as District/Quarter —
|
|
## granularity_v2 is just another field in the same dict, no special-cased
|
|
## decode branch for the coarser rung. This is the direct regression test for
|
|
## "one colorizer family, no per-rung palettes": the wire contract itself
|
|
## draws no distinction, so nothing downstream (the overlay's
|
|
## cell_grid_side_for_window()/_cell_color()) needs a rung-specific decode
|
|
## path either.
|
|
func test_atlas_response_district_window_passthrough_region_rung() -> void:
|
|
var window := {
|
|
"center": [0, 0],
|
|
"n": 6400,
|
|
"granularity": 4294967295, # WINDOW_GRANULARITY_REGION_KEY (u32::MAX) — key-space tag, not a real multiplier
|
|
"granularity_v2": "Region",
|
|
"min_wl_m": 0,
|
|
"morphology": PackedByteArray([8, 14, 0, 5]),
|
|
"elev_q": PackedByteArray([40, 62, 5, 88]),
|
|
"temp_dc": [120, 95, AtlasOverlayColors.REGION_TEMP_NONE_DC, 60],
|
|
"moisture_q": PackedByteArray([50, 30, 90, 20]),
|
|
"vegetation": PackedByteArray([2, 1, 6, 3]),
|
|
"glaciation": PackedByteArray([0, 0, 1, 2]),
|
|
}
|
|
var raw := {"body_id": "GJ1c", "status": "Ready", "district_window": window}
|
|
var decoded: Variant = Protocol.atlas_response_from_raw(raw)
|
|
assert_that(decoded).is_not_null()
|
|
var district_window: Dictionary = (decoded as Dictionary).get("district_window")
|
|
assert_that(district_window).is_equal(window)
|
|
assert_str(str(district_window.get("granularity_v2"))).is_equal("Region")
|
|
|
|
|
|
## A body with no window requested (or not yet derived — §1's background-queue
|
|
## serving model: the completion may not have landed yet) must decode with
|
|
## district_window absent -> null, same "layer hasn't produced yet" contract
|
|
## every other Option layer already has.
|
|
func test_atlas_response_district_window_default_null() -> void:
|
|
var decoded: Variant = Protocol.atlas_response_from_raw({"body_id": "GJ1c", "status": "Ready"})
|
|
assert_that(decoded).is_not_null()
|
|
assert_that((decoded as Dictionary).get("district_window")).is_null()
|
|
|
|
|
|
# =============================================================================
|
|
# SimBridge routing — receive_bytes emits the right signal with the right value
|
|
# =============================================================================
|
|
|
|
|
|
func test_sim_bridge_routes_star_map_response_to_signal() -> void:
|
|
var received: Array = []
|
|
var handler := func(response: Dictionary) -> void: received.append(response)
|
|
SimBridge.star_map_received.connect(handler)
|
|
|
|
var raw := {"status": "Ready", "data": {"nodes": [{"system_id": "GJ 71", "proper_name": "Tau Ceti"}]}}
|
|
var encoded = Messagepack.encode(raw)
|
|
SimBridge.receive_bytes(encoded.value)
|
|
|
|
SimBridge.star_map_received.disconnect(handler)
|
|
|
|
assert_int(received.size()).is_equal(1)
|
|
assert_that(received[0].get("nodes")).is_equal(raw["data"]["nodes"])
|
|
|
|
|
|
func test_sim_bridge_routes_city_names_response_to_signal() -> void:
|
|
var received: Array = []
|
|
var handler := func(response: Dictionary) -> void: received.append(response)
|
|
SimBridge.city_names_received.connect(handler)
|
|
|
|
var raw := {
|
|
"body_id": "GJ903b",
|
|
"status": "Ready",
|
|
"cities": [{"city_id": 1, "name": "Ridgeback", "is_capital": false}],
|
|
}
|
|
var encoded = Messagepack.encode(raw)
|
|
SimBridge.receive_bytes(encoded.value)
|
|
|
|
SimBridge.city_names_received.disconnect(handler)
|
|
|
|
assert_int(received.size()).is_equal(1)
|
|
assert_that(received[0].get("body_id")).is_equal("GJ903b")
|
|
|
|
|
|
func test_sim_bridge_still_routes_snapshots_after_starmap_additions() -> void:
|
|
# Regression guard: adding the starmap/citynames branches must not steal
|
|
# ordinary snapshot frames (the 20 Hz hot path).
|
|
var raw := {"tick": 5, "entities": []}
|
|
var encoded = Messagepack.encode(raw)
|
|
SimBridge.receive_bytes(encoded.value)
|
|
assert_that(SimBridge._last_snapshot).is_not_null()
|
|
assert_int(SimBridge._last_snapshot.get("tick")).is_equal(5)
|
|
|
|
|
|
func test_request_star_map_is_noop_in_test_mode() -> void:
|
|
# SimBridge defaults to test_mode = true (SR_LIVE unset) — request_star_map
|
|
# must not error even with no live bridge/server, but it MUST still record
|
|
# the wish so replay-on-connect can fire later (review H3: this flag's
|
|
# unreset leak was the cross-suite crash fixed in this same PR).
|
|
SimBridge.reset_test_state()
|
|
SimBridge.request_star_map()
|
|
assert_bool(SimBridge._star_map_wanted).override_failure_message(
|
|
"test-mode request_star_map must still set the replay flag"
|
|
).is_true()
|
|
SimBridge.reset_test_state()
|
|
|
|
|
|
func test_request_city_names_is_noop_in_test_mode() -> void:
|
|
# Must not error — and must NOT touch the star-map replay flag (guards a
|
|
# future copy-paste wiring city-names into the wrong flag).
|
|
SimBridge.reset_test_state()
|
|
SimBridge.request_city_names("GJ903b")
|
|
assert_bool(SimBridge._star_map_wanted).is_false()
|
|
|
|
|
|
class _CaptureBridge:
|
|
var sent: Array = []
|
|
|
|
func send_message(bytes: PackedByteArray) -> int:
|
|
sent.append(bytes)
|
|
return OK
|
|
|
|
|
|
func test_replay_on_connect_sends_star_map_request_live() -> void:
|
|
# Review H7: the replay-on-CONNECTED path (_set_state →
|
|
# _send_star_map_request) is the exact mechanism behind the cross-suite
|
|
# crash fixed in this PR, and every other test runs test_mode=true where
|
|
# the guard short-circuits before touching _bridge — proving only
|
|
# "doesn't crash", never "actually replays". Exercise the positive case
|
|
# per the test_local_bridge.gd test-mode-flip precedent.
|
|
var original_test_mode: bool = SimBridge.test_mode
|
|
var original_state: SimBridge.ConnectionState = SimBridge.state
|
|
var original_bridge = SimBridge._bridge
|
|
SimBridge.reset_test_state()
|
|
|
|
var stub := _CaptureBridge.new()
|
|
SimBridge.test_mode = false
|
|
SimBridge._bridge = stub
|
|
SimBridge.state = SimBridge.ConnectionState.CONNECTING
|
|
SimBridge._star_map_wanted = true
|
|
SimBridge._set_state(SimBridge.ConnectionState.CONNECTED)
|
|
|
|
assert_int(stub.sent.size()).override_failure_message(
|
|
"reaching CONNECTED with _star_map_wanted set must replay the request"
|
|
).is_equal(1)
|
|
var decoded = Messagepack.decode(stub.sent[0])
|
|
assert_that(decoded.value).is_equal({"star_map": true})
|
|
|
|
# Restore autoload state for later suites.
|
|
SimBridge.test_mode = original_test_mode
|
|
SimBridge._bridge = original_bridge
|
|
SimBridge.state = original_state
|
|
SimBridge.reset_test_state()
|