OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_settings_dump.gd

95 lines · gd ref:
extends SceneTree
## Gate: a settings dump reports exactly what was changed at runtime.
##
## The dump exists so a look tuned live (sliders, the Remote inspector, a panel)
## can be turned into a map's DEFAULTS in source. Its map section compares every
## stored property of the running map against a FRESH, uncached load of the map's
## own scene file. What that must get right:
##
##   - a changed NODE property is reported, with the live and the file value
##   - a changed property INSIDE a resource is reported -- a material, a clouds
##     resource -- which is where most of a map's look actually lives. A cached
##     load would hand back the very instance that was edited, and the dump would
##     say "nothing changed"; that is the reason for CACHE_MODE_IGNORE_DEEP
##   - an untouched property is NOT reported, or the output is noise
##
## Instances the REAL map_flat.tscn: the comparison is against the scene file, so
## a fixture would only prove the fixture.

var ok := true
var _ran := false
## Set on the LAST line of _run. A script error aborts _run without failing a
## check, and the first run of this gate printed PASS exactly that way.
var _completed := false


func _p(c: bool, m: String, detail: String = "") -> void:
	print(("ok   " if c else "FAIL: ") + m + ("" if c or detail == "" else "   [" + detail + "]"))
	if not c:
		ok = false


func _process(_delta: float) -> bool:
	if _ran:
		return true
	_ran = true
	_run()
	_p(_completed, "the gate ran to the end (no script error cut it short)")
	print("GATE settings_dump: %s" % ("PASS" if ok else "FAIL"))
	quit(0 if ok else 1)
	return true


func _find(changes: Array, node: String, prop: String) -> Dictionary:
	for c: Dictionary in changes:
		if String(c.get("node", "")) == node and String(c.get("prop", "")) == prop:
			return c
	return {}


func _run() -> void:
	var dump_script: Script = load("res://scenes/game/settings_dump.gd")
	_p(dump_script != null, "settings_dump.gd exists")
	if dump_script == null:
		return
	var map: Node = (load("res://scenes/maps/map_flat.tscn") as PackedScene).instantiate()
	root.add_child(map)

	var surface := map.get_node(^"Ground/Surface") as MeshInstance3D
	var mat := surface.get_surface_override_material(0) as StandardMaterial3D
	surface.transparency = 0.25          # a node property      (file: default 0.0)
	mat.roughness = 0.4                  # inside a resource    (file: 0.9)
	# albedo_color is left alone: it must NOT appear.

	var path: String = dump_script.call("write", map)
	_p(path != "" and FileAccess.file_exists(path), "the dump was written", path)
	var parsed: Variant = JSON.parse_string(FileAccess.get_file_as_string(path))
	_p(parsed is Dictionary, "and is JSON")
	if not (parsed is Dictionary):
		return
	var d: Dictionary = parsed
	_p(String(d.get("map_scene", "")) == "res://scenes/maps/map_flat.tscn", "it names the map scene",
			str(d.get("map_scene")))
	var changes: Array = d.get("map_changes", [])

	var t := _find(changes, "Ground/Surface", "transparency")
	_p(not t.is_empty(), "a changed node property is reported")
	_p(is_equal_approx(float(t.get("live", -1)), 0.25) and is_equal_approx(float(t.get("file", -1)), 0.0),
			"with its live and file values", str(t))

	var r := _find(changes, "Ground/Surface", "surface_material_override/0/roughness")
	_p(not r.is_empty(), "a changed property INSIDE a resource is reported")
	_p(is_equal_approx(float(r.get("live", -1)), 0.4) and is_equal_approx(float(r.get("file", -1)), 0.9),
			"with its live and file values", str(r))
	_p(String(r.get("edit_in", "")) == "res://scenes/maps/map_flat.tscn",
			"and says which file to edit (the material is embedded in the map)", str(r.get("edit_in")))

	_p(_find(changes, "Ground/Surface", "surface_material_override/0/albedo_color").is_empty(),
			"an untouched property is NOT reported")
	print("  (%d change(s) reported in total)" % changes.size())
	for c: Dictionary in changes:
		print("    %s . %s : file=%s live=%s" % [c.get("node"), c.get("prop"), str(c.get("file")), str(c.get("live"))])
	map.queue_free()
	_completed = true