D-226 layer 4, rebuilt against the post-D-255 stepped Atlas after the Phase-1 reconciliation (the original intent list targeted the retired continuous-zoom viewer). Eleven intents, each backed by the exact production handler a click calls — select/open for systems and bodies (extracted shared by-id tails so click and intent paths are one code path), scroll_rung, reset_view, back, open/close_atlas, set_overlay — plus two new first-class capabilities: jump_to_center (the fixed-center revisit pattern proven by five eyeball drivers, via a new StepCanvasViewer.jump_to seam that reuses _scroll_rung's exact request tail — same extent cap, same cache keys) and get_current_canvas_summary (allocation-light reads off the raw wire dict, courses-by-class, draw-matched settlement dedup — no PNG decode). Contract shape: dumb AtlasAgentBridge autoload holding the app handle (untyped per the parse-order rule), all logic in the static AtlasAgentInterface class. observe() is side-effect-free: current state + a generic Control-walk affordance tree. In-process consumers only this ticket (documented); the committed reference driver (atlas_agent_driver.gd, InputSwallower + settle-until-ready from the T-1157 inventory) replaces the scratch eyeball drivers as the sanctioned headless-drive pattern. select_city/open_regional dropped with recorded rationale (no settlement hit-test affordance exists post-D-255) — diff on the ticket. 33 new tests across three suites. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
83 lines
3.5 KiB
GDScript
83 lines
3.5 KiB
GDScript
## T-971 smoke test for atlas_agent_driver.gd — the reference `-s` SceneTree
|
|
## driver for AtlasAgentInterface. A gdUnit suite cannot boot a SECOND full
|
|
## Godot process (the driver's real usage mode: `godot -s
|
|
## res://tests/atlas_agent_driver.gd -- --jobs ... --output ...`) without
|
|
## spawning a nested engine instance, which is slow/fragile and inconsistent
|
|
## with how this project already runs its OTHER `-s` drivers
|
|
## (visual_capture.gd/atlas_shots.json — manual `make` targets, never inside
|
|
## the gdUnit suite tests/run-godot invokes). The feasible headless smoke
|
|
## here is the driver's own PURE helper logic: job-file loading and
|
|
## result-array writing, both `static func`s with no SceneTree dependency —
|
|
## exercising the exact code path a real run's job-list parsing and
|
|
## output-writing go through, without booting a second engine.
|
|
class_name TestAtlasAgentDriver
|
|
extends GdUnitTestSuite
|
|
|
|
const DriverScript := preload("res://tests/atlas_agent_driver.gd")
|
|
|
|
var _tmp_dir: String = ""
|
|
|
|
|
|
func before_test() -> void:
|
|
_tmp_dir = "user://test_atlas_agent_driver/%d/" % Time.get_ticks_usec()
|
|
DirAccess.make_dir_recursive_absolute(_tmp_dir)
|
|
|
|
|
|
func after_test() -> void:
|
|
var d := DirAccess.open(_tmp_dir)
|
|
if d == null:
|
|
return
|
|
for f: String in d.get_files():
|
|
d.remove(f)
|
|
DirAccess.remove_absolute(_tmp_dir.rstrip("/"))
|
|
|
|
|
|
func test_load_jobs_reads_the_shipped_smoke_fixture() -> void:
|
|
var jobs: Array = DriverScript._load_jobs(
|
|
"res://tests/fixtures/atlas_agent_smoke_jobs.json"
|
|
)
|
|
assert_int(jobs.size()).is_equal(4)
|
|
assert_str((jobs[0] as Dictionary).get("intent", "")).is_equal("open_atlas")
|
|
assert_str((jobs[1] as Dictionary).get("intent", "")).is_equal("observe")
|
|
|
|
|
|
func test_load_jobs_returns_empty_array_for_a_missing_file() -> void:
|
|
var jobs: Array = DriverScript._load_jobs("res://tests/fixtures/does_not_exist.json")
|
|
assert_int(jobs.size()).is_equal(0)
|
|
|
|
|
|
func test_write_output_round_trips_through_json() -> void:
|
|
var out_path: String = _tmp_dir + "results.json"
|
|
var results: Array = [
|
|
{"intent": "observe", "params": {}, "result": {"screen": "reach"}},
|
|
{"intent": "select_system", "params": {"system_id": "GJ1"}, "result": {"ok": true}},
|
|
]
|
|
|
|
DriverScript._write_output(out_path, results)
|
|
|
|
var f := FileAccess.open(out_path, FileAccess.READ)
|
|
assert_object(f).is_not_null()
|
|
var parsed: Variant = JSON.parse_string(f.get_as_text())
|
|
f.close()
|
|
assert_that(parsed).is_equal(results)
|
|
|
|
|
|
## The InputSwallower inner class (T-1157 inventory item 1) — a plain Node
|
|
## subclass with no SceneTree/window dependency for its OWN logic
|
|
## (set_input_as_handled() requires a live viewport to call meaningfully, but
|
|
## the class must at least instantiate and expose the two input hooks by
|
|
## name — this is the structural smoke check; the swallowing BEHAVIOR itself
|
|
## is exercised implicitly every time atlas_agent_driver.gd actually runs,
|
|
## per its own header doc).
|
|
func test_input_swallower_inner_class_instantiates_and_has_both_input_hooks() -> void:
|
|
# A nested `class X: extends Y` inside a script is exposed as a
|
|
# script-level constant on the OUTER GDScript resource — reachable via
|
|
# plain dot access on the preloaded DriverScript, same as any other
|
|
# nested-class reference in this codebase's own suites (e.g.
|
|
# GdUnitObjectAssertImplTest.gd's MyNode/MyExtendedNode pattern), just
|
|
# via a loaded resource instead of a same-file bare identifier.
|
|
var instance: Node = DriverScript._InputSwallower.new()
|
|
assert_bool(instance.has_method("_input")).is_true()
|
|
assert_bool(instance.has_method("_unhandled_input")).is_true()
|
|
instance.free()
|