Two _CountingNatureOverlay draw-spy tests (the PR #196 pattern): window arrival and rung-swap arrival both advance the nature overlay's draw count past baseline. Two isolation bugs caught before reporting: (1) _on_window_ready has a second pre-existing redraw path via _fit_and_center -> _apply_transform that fires on first arrivals and masks a sabotaged line 507 — isolated by setting _user_adjusted (the real pan/zoom guard, a reachable state); (2) simulating the swap via _enter_at_rung resets _awaiting_first_window and takes the same masked branch — the real production trigger is _maybe_reselect_rung's request path, so the test drives request_now directly. Revert- verified: dropping the queue_redraw line fails exactly both tests by name; 82/82 restored. Viewer file itself zero net diff. Tickets: T-1170 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -233,6 +233,146 @@ func test_set_overlay_visible_gen_basins_flips_gate_and_redraws_nature_overlay()
|
||||
).is_greater(baseline)
|
||||
|
||||
|
||||
## T-1170 B3 (PR #197 review, Hoshe #3): _on_window_ready() now also calls
|
||||
## _nature_overlay.queue_redraw() (atlas_window_viewer.gd:507) — courses ride
|
||||
## `DistrictWindowLayer.courses`, the SAME `_window` this handler adopts, so
|
||||
## a window arrival that never redraws the nature overlay would leave freshly
|
||||
## arrived courses invisible until an UNRELATED pan/zoom gesture happened to
|
||||
## redraw it. Same spy-and-baseline shape as
|
||||
## test_set_overlay_visible_gen_basins_flips_gate_and_redraws_nature_overlay()
|
||||
## above — this is the exact pattern PR #196 established for "prove a
|
||||
## specific queue_redraw() call site actually fires", applied to the
|
||||
## window-arrival call site instead of the toggle call site.
|
||||
##
|
||||
## **Isolation note (live finding while writing this test):** `_on_window_ready()`
|
||||
## ALSO calls `_fit_and_center()` on the first-ever arrival
|
||||
## (`_awaiting_first_window and not _user_adjusted`), and `_fit_and_center()`
|
||||
## itself already ends in `_apply_transform()`, which redraws the nature
|
||||
## overlay through a SEPARATE, pre-existing call site. That path would mask
|
||||
## a broken/removed line 507 (both call sites fire on a fresh entry's first
|
||||
## arrival, so removing just one wouldn't drop draw_count below baseline).
|
||||
## Setting `_user_adjusted = true` before the response arrives — the SAME
|
||||
## guard a real pan/zoom gesture sets (`_maybe_refloat_window()`/`_zoom_at()`)
|
||||
## — skips the fit-and-center branch, so ONLY line 507 can be the source of
|
||||
## any redraw the assertion below observes. This is a real, reachable state
|
||||
## (any window arrival after the player's first manual pan/zoom), not a
|
||||
## test-only fiction.
|
||||
func test_window_arrival_redraws_nature_overlay() -> void:
|
||||
var v: AtlasWindowViewer = auto_free(AtlasWindowViewer.new())
|
||||
add_child(v)
|
||||
v.enter({"body_id": "GJ380c"}, {}, Vector2i(10, 20), 2)
|
||||
v._user_adjusted = true # isolate line 507 from the first-arrival fit-and-center redraw
|
||||
|
||||
# Swap in the counting spy AFTER enter() (matching the gen_basins test's
|
||||
# own "swap after construction, then let it settle" shape) so enter()'s
|
||||
# own queue_redraw() calls don't pollute the baseline.
|
||||
var spy := _CountingNatureOverlay.new(v)
|
||||
v._nature_overlay.queue_free()
|
||||
v._nature_overlay = spy
|
||||
v._canvas.add_child(spy)
|
||||
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
var baseline: int = spy.draw_count
|
||||
assert_int(baseline).override_failure_message(
|
||||
"sanity: the spy must have drawn at least once before the window"
|
||||
+ " arrives, or this test can't distinguish 'redrawn BY the arrival'"
|
||||
+ " from 'never drawn at all'"
|
||||
).is_greater(0)
|
||||
|
||||
var window: Dictionary = _mock_window(Vector2i(10, 20), 2)
|
||||
SimBridge.atlas_layers_received.emit(_mock_response("GJ380c", window))
|
||||
await get_tree().process_frame
|
||||
|
||||
assert_that(v.get_district_window()).override_failure_message(
|
||||
"sanity: the response must actually have been adopted (matching echo)"
|
||||
+ " or this test proves nothing about the arrival path specifically"
|
||||
).is_equal(window)
|
||||
assert_int(spy.draw_count).override_failure_message(
|
||||
"_on_window_ready() must queue_redraw() the NATURE overlay — courses"
|
||||
+ " ride the SAME _window this handler adopts, so a window arrival"
|
||||
+ " that doesn't redraw the nature overlay leaves freshly arrived"
|
||||
+ " courses invisible until an unrelated pan/zoom happens to redraw"
|
||||
+ " it — draw_count must have advanced past the baseline (%d)" % baseline
|
||||
).is_greater(baseline)
|
||||
|
||||
|
||||
## The RUNG-SWAP arrival case (a later _on_window_ready() call for a
|
||||
## DIFFERENT granularity_v2 than the one the viewer entered at — e.g. a
|
||||
## wheel-zoom crossing from District into Quarter) — cheap to cover in the
|
||||
## SAME test file per the review's own "if cheap" allowance. Confirms the
|
||||
## redraw fires on EVERY window adoption, not just the first-ever one
|
||||
## (T-1153's progressive-refinement doc is explicit that _window only ever
|
||||
## gets REPLACED, never renulled, on a rung swap).
|
||||
##
|
||||
## **Uses `_window_request.request_now()` directly, NOT `_enter_at_rung()`**
|
||||
## — a live finding while writing this test: `_enter_at_rung()` sets
|
||||
## `_awaiting_first_window = true` again (it's the SAME reset path a fresh
|
||||
## descent uses), which would route the swap response back through
|
||||
## `_fit_and_center()`'s OWN redraw call site, masking line 507 exactly like
|
||||
## the note on the test above. The REAL production rung-swap path,
|
||||
## `_maybe_reselect_rung()`, never touches `_awaiting_first_window` at all —
|
||||
## it only calls `_window_request.request_debounced(...)`. `request_now()`
|
||||
## (the non-debounced sibling, same effect minus the timer) is called
|
||||
## directly here to update `_window_request`'s own `_granularity_v2` — the
|
||||
## exact field `_on_window_ready()`'s echo-matching guard reads — mirroring
|
||||
## the real path's state change without needing a live debounce timer in a
|
||||
## unit test.
|
||||
func test_rung_swap_window_arrival_redraws_nature_overlay() -> void:
|
||||
var v: AtlasWindowViewer = auto_free(AtlasWindowViewer.new())
|
||||
add_child(v)
|
||||
v.enter({"body_id": "GJ380c"}, {}, Vector2i(10, 20), 2)
|
||||
|
||||
# First arrival (District, matches enter()'s own default rung) — settles
|
||||
# the viewer into a held window, exactly as a real progressive-refinement
|
||||
# sequence would before a rung swap. Uses the REAL (non-spy) nature
|
||||
# overlay for this leg — only the swap leg itself needs the spy.
|
||||
var district_window: Dictionary = _mock_window(Vector2i(10, 20), 2)
|
||||
SimBridge.atlas_layers_received.emit(_mock_response("GJ380c", district_window))
|
||||
await get_tree().process_frame
|
||||
assert_that(v.get_district_window()).override_failure_message(
|
||||
"sanity: the first (District) arrival must have been adopted before"
|
||||
+ " simulating the swap"
|
||||
).is_equal(district_window)
|
||||
|
||||
# Now swap in the spy and simulate the RUNG SWAP itself — update the
|
||||
# request's echoed granularity_v2 to "Quarter" (what
|
||||
# _maybe_reselect_rung() -> request_debounced() would do on a real
|
||||
# wheel-zoom crossing) WITHOUT touching _awaiting_first_window, so the
|
||||
# response below takes the "not first window" branch — the genuinely
|
||||
# different code path from the test above.
|
||||
var spy := _CountingNatureOverlay.new(v)
|
||||
v._nature_overlay.queue_free()
|
||||
v._nature_overlay = spy
|
||||
v._canvas.add_child(spy)
|
||||
v._window_request.request_now(
|
||||
"GJ380c", Vector2i(10, 20), 2, AtlasWindowRequest.GRANULARITY_V2_QUARTER
|
||||
)
|
||||
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
var baseline: int = spy.draw_count
|
||||
assert_int(baseline).override_failure_message(
|
||||
"sanity: the spy must have drawn at least once before the rung-swap"
|
||||
+ " response arrives"
|
||||
).is_greater(0)
|
||||
|
||||
var quarter_window: Dictionary = _mock_window(Vector2i(10, 20), 2)
|
||||
quarter_window["granularity_v2"] = "Quarter"
|
||||
SimBridge.atlas_layers_received.emit(_mock_response("GJ380c", quarter_window))
|
||||
await get_tree().process_frame
|
||||
|
||||
assert_that(v.get_district_window()).override_failure_message(
|
||||
"sanity: the rung-swap response must actually have been adopted"
|
||||
).is_equal(quarter_window)
|
||||
assert_int(spy.draw_count).override_failure_message(
|
||||
"a RUNG-SWAP window arrival (a later _on_window_ready() call at a"
|
||||
+ " DIFFERENT granularity_v2 than entry) must ALSO redraw the nature"
|
||||
+ " overlay — draw_count must have advanced past the post-first-"
|
||||
+ " arrival baseline (%d)" % baseline
|
||||
).is_greater(baseline)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# T-1120 capture-API parity (the ticket's explicit note: must survive here too)
|
||||
# =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user