## T-1182 tests: step_canvas_cache.gd — the client-side in-memory LRU cache ## for decoded step-canvas payloads. Keyed on (body_id, rung, center, extent, ## min_wl_m), the exact tuple server/src/atlas/step_canvas.rs's own ## StepCanvasCache keys on. Mirrors test_atlas_window_cache.gd's own ## conventions (the surviving LRU shape this file is adapted from). class_name TestStepCanvasCache extends GdUnitTestSuite const StepCanvasCache := preload("res://ui/implant/apps/atlas/step_canvas/step_canvas_cache.gd") func test_make_key_distinguishes_body_rung_center_and_extent() -> void: var k1 := StepCanvasCache.make_key("GJ1c", "District", Vector2i(10, 20), Vector2i(64, 64)) var k2 := StepCanvasCache.make_key("GJ1d", "District", Vector2i(10, 20), Vector2i(64, 64)) var k3 := StepCanvasCache.make_key("GJ1c", "Chunk", Vector2i(10, 20), Vector2i(64, 64)) var k4 := StepCanvasCache.make_key("GJ1c", "District", Vector2i(11, 20), Vector2i(64, 64)) var k5 := StepCanvasCache.make_key("GJ1c", "District", Vector2i(10, 20), Vector2i(32, 32)) assert_str(k1).is_not_equal(k2) assert_str(k1).is_not_equal(k3) assert_str(k1).is_not_equal(k4) assert_str(k1).is_not_equal(k5) ## Global collapses center/extent to a fixed sentinel regardless of what's ## passed — every Global request for the same body_id must land on ONE slot. func test_make_key_global_ignores_center_and_extent() -> void: var k1 := StepCanvasCache.make_key("GJ1c", "Global", Vector2i(10, 20), Vector2i(64, 64)) var k2 := StepCanvasCache.make_key("GJ1c", "Global", Vector2i(999, -999), Vector2i(1, 1)) assert_str(k1).is_equal(k2) func test_miss_returns_null_and_has_reports_false() -> void: var cache := StepCanvasCache.new() assert_that(cache.get_canvas("GJ1c", "District", Vector2i.ZERO, Vector2i(64, 64))).is_null() assert_bool(cache.has("GJ1c", "District", Vector2i.ZERO, Vector2i(64, 64))).is_false() func test_put_then_get_round_trips_exact_canvas() -> void: var cache := StepCanvasCache.new() var canvas := {"width": 64, "height": 64} cache.put("GJ1c", "District", Vector2i(10, 20), Vector2i(64, 64), canvas) assert_bool(cache.has("GJ1c", "District", Vector2i(10, 20), Vector2i(64, 64))).is_true() assert_that(cache.get_canvas("GJ1c", "District", Vector2i(10, 20), Vector2i(64, 64))).is_equal( canvas ) ## D-227: a canvas fetched once is valid FOREVER for that exact key — no ## expiry, no invalidation path. func test_cached_canvas_never_expires() -> void: var cache := StepCanvasCache.new() var canvas := {"width": 1} cache.put("GJ1c", "Chunk", Vector2i.ZERO, Vector2i(1, 1), canvas) for _i in range(50): assert_that(cache.get_canvas("GJ1c", "Chunk", Vector2i.ZERO, Vector2i(1, 1))).is_equal(canvas) func test_different_rungs_at_identical_center_extent_do_not_collide() -> void: var cache := StepCanvasCache.new() var district_canvas := {"rung": "District"} var chunk_canvas := {"rung": "Chunk"} cache.put("GJ1c", "District", Vector2i(10, 20), Vector2i(64, 64), district_canvas) cache.put("GJ1c", "Chunk", Vector2i(10, 20), Vector2i(64, 64), chunk_canvas) assert_int(cache.size()).is_equal(2) assert_that(cache.get_canvas("GJ1c", "District", Vector2i(10, 20), Vector2i(64, 64))).is_equal( district_canvas ) assert_that(cache.get_canvas("GJ1c", "Chunk", Vector2i(10, 20), Vector2i(64, 64))).is_equal( chunk_canvas ) func test_put_overwrites_existing_key() -> void: var cache := StepCanvasCache.new() cache.put("GJ1c", "District", Vector2i.ZERO, Vector2i(64, 64), {"v": 1}) cache.put("GJ1c", "District", Vector2i.ZERO, Vector2i(64, 64), {"v": 2}) assert_int(cache.size()).is_equal(1) assert_that(cache.get_canvas("GJ1c", "District", Vector2i.ZERO, Vector2i(64, 64))).is_equal( {"v": 2} ) func test_eviction_drops_least_recently_used_on_overflow() -> void: var cache := StepCanvasCache.new(2) cache.put("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64), {"id": "a"}) cache.put("GJ1c", "District", Vector2i(1, 0), Vector2i(64, 64), {"id": "b"}) cache.put("GJ1c", "District", Vector2i(2, 0), Vector2i(64, 64), {"id": "c"}) assert_int(cache.size()).is_equal(2) assert_bool(cache.has("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64))).override_failure_message( "oldest entry should have been evicted" ).is_false() assert_bool(cache.has("GJ1c", "District", Vector2i(2, 0), Vector2i(64, 64))).is_true() func test_get_touches_entry_and_protects_it_from_eviction() -> void: var cache := StepCanvasCache.new(2) cache.put("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64), {"id": "a"}) cache.put("GJ1c", "District", Vector2i(1, 0), Vector2i(64, 64), {"id": "b"}) cache.get_canvas("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64)) cache.put("GJ1c", "District", Vector2i(2, 0), Vector2i(64, 64), {"id": "c"}) assert_bool(cache.has("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64))).override_failure_message( "touched entry should survive eviction" ).is_true() assert_bool(cache.has("GJ1c", "District", Vector2i(1, 0), Vector2i(64, 64))).override_failure_message( "untouched entry should be the one evicted" ).is_false() func test_max_entries_clamped_to_at_least_one() -> void: var cache := StepCanvasCache.new(0) cache.put("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64), {"id": "a"}) cache.put("GJ1c", "District", Vector2i(1, 0), Vector2i(64, 64), {"id": "b"}) assert_int(cache.size()).is_equal(1) func test_clear_empties_the_cache() -> void: var cache := StepCanvasCache.new() cache.put("GJ1c", "District", Vector2i.ZERO, Vector2i(64, 64), {"id": "a"}) cache.clear() assert_int(cache.size()).is_equal(0) assert_bool(cache.has("GJ1c", "District", Vector2i.ZERO, Vector2i(64, 64))).is_false()