extends SceneTree
## Headless gate for TerrainProbe's PURE metric functions.
##
## godot --headless --path . --script res://scenes/test/terrain_probe_selftest.gd
##
## It cannot measure terrain -- there is no GPU and no physics here, and on a
## heightfield map the CPU field is a different world anyway. What it CAN do is
## prove the maths behind the report: that a flat grid reads flat, a 30 degree
## hillside reads as slope and NOT as roughness, a 1 m spike is seen, a hole is
## counted, and a vertical triangle reads 90 degrees. Those are exactly the
## discriminations the live report's conclusions rest on.
##
## Exit code 0 = every case passed. Non-zero = the instrument is broken and any
## report it produced is not evidence (hyper-games #50 section 6).
func _initialize() -> void:
var st: Dictionary = TerrainProbe.selftest()
for c in st["cases"]:
print("%s %s (%s)" % ["PASS" if c[1] else "FAIL", c[0], c[2]])
print("SELFTEST: %s" % ("PASS" if st["pass"] else "FAIL"))
# THE GATE MUST ALSO CATCH A BROKEN GATE. A selftest that only ever runs
# correct data cannot tell a working check from one that returns "pass"
# unconditionally, so feed the metric a case whose answer it must get WRONG
# if it is not looking: a grid that is flat except for a step, asserted to
# read as flat. If this "fails", the metric is alive.
var n := 9
var g := PackedFloat32Array()
g.resize(n * n)
g.fill(10.0)
g[40] = 10.5
var m: Dictionary = TerrainProbe.height_metrics(g, n, 0.25)
var alive: bool = float(m["max_step"]) > 0.4
print("%s negative control: a 0.5 m step must NOT read as flat (max_step=%.4f)"
% ["PASS" if alive else "FAIL", m["max_step"]])
quit(0 if (bool(st["pass"]) and alive) else 1)