## T-1153, live round 3 (Jeroen's ruling, design doc §4): tests for ## AtlasWindowTileSet — the orbital rest-state multi-window mosaic ## orchestration. Same hand-built-response-dict conventions as ## test_atlas_window_request.gd/test_atlas_zoom_ladder.gd; this file is ## about the ORCHESTRATION (N tiles, progressive per-tile arrival, ## teardown), not the tile-grid MATH (already covered directly against ## AtlasWindowGeometry.compute_tile_grid() in test_atlas_window_geometry.gd). class_name TestAtlasWindowTileSet extends GdUnitTestSuite const AtlasWindowTileSet := preload("res://ui/implant/apps/atlas/atlas_window_tile_set.gd") const AtlasWindowRequest := preload("res://ui/implant/apps/atlas/atlas_window_request.gd") static func _mock_window(center: Vector2i, n: int) -> Dictionary: return { "center": [center.x, center.y], "n": n, "granularity_v2": "Region", "morphology": PackedByteArray([1, 2, 3, 4]), "elev_q": PackedByteArray([10, 20, 30, 40]), "temp_dc": [0, 0, 0, 0], "moisture_q": PackedByteArray([0, 0, 0, 0]), "vegetation": PackedByteArray([0, 0, 0, 0]), "glaciation": PackedByteArray([0, 0, 0, 0]), } static func _mock_response(body_id: String, window: Variant) -> Dictionary: return {"body_id": body_id, "status": "Ready", "district_window": window} func _make_tile_set() -> Variant: var owner_stub := RefCounted.new() var ts = auto_free(AtlasWindowTileSet.new(owner_stub)) add_child(ts) return ts # ============================================================================= # enter() — tile grid computation + one request per tile # ============================================================================= ## enter() on a real, tiling-sized body must produce the SAME tile count ## compute_tile_grid() would — 6 for GJ380c/Lendel, the coordinator's own ## live-round number. func test_enter_produces_the_expected_tile_count_for_lendel() -> void: var ts = _make_tile_set() ts.enter("GJ380c", 6238.4) assert_int(ts.get_tile_count()).is_equal(6) assert_bool(ts.is_multi_tile()).is_true() ## A tiny (non-tiling) body produces exactly ONE tile — the degenerate case ## compute_tile_grid() itself already covers; this confirms the ORCHESTRATION ## (not just the grid math) handles it without crashing or requesting zero ## tiles. func test_enter_tiny_body_produces_one_tile() -> void: var ts = _make_tile_set() ts.enter("TinyBody", 50.0) assert_int(ts.get_tile_count()).is_equal(1) assert_bool(ts.is_multi_tile()).is_false() ## Every tile must start with a null window (nothing has arrived yet) and ## the tile set must not report "fully arrived" before any response lands. func test_enter_all_tiles_start_unarrived() -> void: var ts = _make_tile_set() ts.enter("GJ380c", 6238.4) for tile: Dictionary in ts.get_tiles(): assert_that(tile["window"]).is_null() assert_bool(ts.is_fully_arrived()).is_false() ## An empty tile set (never entered) must not report "fully arrived" either ## — an empty AND-over-nothing must not vacuously read true. func test_empty_tile_set_is_not_fully_arrived() -> void: var ts = _make_tile_set() assert_bool(ts.is_fully_arrived()).is_false() # ============================================================================= # Progressive per-tile arrival (design doc §4: "with visible refinement as # tiles complete") — each tile's response is independent of every other's. # ============================================================================= ## Delivering ONE tile's response must populate ONLY that tile's window, ## leaving every other tile still null — the direct "progressive, not ## block-on-all" regression. func test_one_tile_arriving_does_not_affect_the_others() -> void: var ts = _make_tile_set() ts.enter("GJ380c", 6238.4) var tiles: Array = ts.get_tiles() var first_center: Vector2i = tiles[0]["center"] var window: Dictionary = _mock_window(first_center, AtlasWindowRequest.SERVER_DISTRICT_WINDOW_MAX_N_REGION) SimBridge.atlas_layers_received.emit(_mock_response("GJ380c", window)) var updated_tiles: Array = ts.get_tiles() assert_that(updated_tiles[0]["window"]).override_failure_message( "the tile whose response arrived must have its window populated" ).is_equal(window) for i in range(1, updated_tiles.size()): assert_that(updated_tiles[i]["window"]).override_failure_message( "tile %d must still be unarrived — only tile 0's response was delivered" % i ).is_null() ## tile_ready must fire with the INDEX of the tile that actually arrived — ## the viewer/overlay needs this to know WHICH tile to redraw, not just ## "something changed". func test_tile_ready_signal_fires_with_the_correct_index() -> void: var ts = _make_tile_set() ts.enter("GJ380c", 6238.4) var received_indices: Array = [] ts.tile_ready.connect(func(index: int) -> void: received_indices.append(index)) var tiles: Array = ts.get_tiles() var second_center: Vector2i = tiles[1]["center"] var window: Dictionary = _mock_window(second_center, AtlasWindowRequest.SERVER_DISTRICT_WINDOW_MAX_N_REGION) SimBridge.atlas_layers_received.emit(_mock_response("GJ380c", window)) assert_int(received_indices.size()).is_equal(1) assert_int(received_indices[0]).is_equal(1) ## Delivering EVERY tile's response must flip is_fully_arrived() to true — ## the mosaic-complete signal the viewer/legend chrome can use. func test_all_tiles_arriving_flips_fully_arrived() -> void: var ts = _make_tile_set() ts.enter("GJ380c", 6238.4) var tiles: Array = ts.get_tiles() for tile: Dictionary in tiles: var window: Dictionary = _mock_window( tile["center"], AtlasWindowRequest.SERVER_DISTRICT_WINDOW_MAX_N_REGION ) SimBridge.atlas_layers_received.emit(_mock_response("GJ380c", window)) assert_bool(ts.is_fully_arrived()).override_failure_message( "once every tile's response has arrived, the tile set must report fully arrived" ).is_true() ## A response for a body the tile set is NOT currently showing (a stale ## response from a body the player has since navigated away from) must not ## be adopted by any tile — the SAME body_id staleness guard every other ## AtlasWindowRequest-based path already relies on (this is inherited for ## free since each tile IS an AtlasWindowRequest, but pinned here as an ## orchestration-level regression too). func test_response_for_a_different_body_is_ignored() -> void: var ts = _make_tile_set() ts.enter("GJ380c", 6238.4) var tiles: Array = ts.get_tiles() var window: Dictionary = _mock_window( tiles[0]["center"], AtlasWindowRequest.SERVER_DISTRICT_WINDOW_MAX_N_REGION ) SimBridge.atlas_layers_received.emit(_mock_response("GJ_wrong_body", window)) assert_that(ts.get_tiles()[0]["window"]).is_null() # ============================================================================= # Teardown — re-entering (a fresh body, or the same body again) must not # leave stale tile request nodes wired up. # ============================================================================= ## Calling enter() a SECOND time (e.g. re-entering the orbital frame, or ## switching to a different body) must replace the tile set entirely — the ## OLD tiles' indices/centers must not linger. func test_second_enter_replaces_the_tile_set() -> void: var ts = _make_tile_set() ts.enter("GJ380c", 6238.4) var first_count: int = ts.get_tile_count() assert_int(first_count).is_equal(6) ts.enter("TinyBody", 50.0) assert_int(ts.get_tile_count()).override_failure_message( "a second enter() must fully replace the tile set, not append to it" ).is_equal(1) ## A response matching an OLD tile set's (body, center) — arriving AFTER a ## second enter() has already torn it down — must not be adopted (or crash): ## the old tile's AtlasWindowRequest node is queue_free()'d, and _tiles no ## longer references it, so a stale signal (if it could somehow still fire) ## has no live entry left to update. func test_stale_response_after_second_enter_does_not_crash_or_leak() -> void: var ts = _make_tile_set() ts.enter("GJ380c", 6238.4) var old_tiles: Array = ts.get_tiles() var old_center: Vector2i = old_tiles[0]["center"] ts.enter("GJ380c", 50.0) # same body_id, different (tiny) radius -> different tile grid # A response shaped like it's answering the OLD tile set's first tile — # must not crash, and must not corrupt the NEW tile set's single tile. var stale_window: Dictionary = _mock_window( old_center, AtlasWindowRequest.SERVER_DISTRICT_WINDOW_MAX_N_REGION ) SimBridge.atlas_layers_received.emit(_mock_response("GJ380c", stale_window)) assert_int(ts.get_tile_count()).is_equal(1)