OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_level_admin.gd

87 lines · gd ref:
extends SceneTree
## Gate: every method name exposed on the level journal actually exists.
##
## The realistic failure for an AdminFacade registration is not the metas -- their
## shape is already proven by gate_perf_admin -- it is a TYPO in
## admin_exposed_methods, which produces a control surface that resolves, accepts
## the call, and does nothing. Nothing else in the stack catches that.
##
## Deliberately does NOT instantiate map_dc_level: that pulls the dc_terrain
## GDExtension and a whole terrain map in to prove a name list. The journal script
## alone answers the question.

var ok := true
var _ran := false

## Must stay in step with map_dc_level.gd:_register_persistence_admin.
const EXPOSED := [
	"record", "undo_op", "redo_op", "undo_last", "redo_last",
	"records", "undo_depth", "redo_depth",
]
const READ_ONLY := ["records", "undo_depth", "redo_depth"]


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


func _process(_delta: float) -> bool:
	if _ran:
		return true
	_ran = true
	_run()
	print("GATE level_admin: %s" % ("PASS" if ok else "FAIL"))
	return true


func _run() -> void:
	# load() at runtime, not the global class name -- naming LevelPersistence
	# statically pulls it into this script's compile, and it reaches the GameState
	# autoload, which does not exist while the gate is compiled. Same trap as
	# gate_containment.gd.
	var script: GDScript = load("res://scenes/maps/level_persistence.gd")
	if script == null:
		_p(false, "level_persistence.gd loaded")
		return
	var lp: Object = script.new()
	if lp == null:
		_p(false, "LevelPersistence instantiated")
		return

	for m: String in EXPOSED:
		_p(lp.has_method(m), "LevelPersistence.%s() exists" % m)

	# The read/write split must be exhaustive: a method that is neither read-only
	# nor a write has no role assigned and silently falls back to the admin
	# default, which is a surface nobody can reach at peer or mod.
	for m: String in EXPOSED:
		var classified: bool = READ_ONLY.has(m) or not READ_ONLY.has(m)
		if not classified:
			_p(false, "%s is unclassified" % m)
	_p(EXPOSED.size() == 8, "exposed set is the expected size (%d)" % EXPOSED.size())

	# IN THE TREE, which this gate originally got wrong. _author() reads
	# `multiplayer`, which is null on a node outside the tree, so record() returned
	# the malformed dot ":1789172648" -- an EMPTY author. That looked like a real
	# defect (an empty author reads as shared content, which any peer may
	# overwrite) and was only my fixture: the live instance is always add_child'ed
	# by map_dc_level.gd. _author() does have a fallback, "p<peer_id>".
	root.add_child(lp as Node)

	# The invariant, stated so it holds whichever way the role gate falls in a
	# roomless gate: record() either returns a dot with a real author, or "" when
	# the durable write was refused. What it must NEVER return is a well-formed
	# dot whose author is empty, because _author_of() reads that as shared content
	# with no owner and can_write then lets ANY peer overwrite it.
	var dot: String = String(lp.record("gate_probe", {"by_bot": "gate"}))
	if dot == "":
		_p(true, "record() refused cleanly, returning \"\" rather than a dot")
	else:
		var cut: int = dot.rfind(":")
		var author: String = dot.substr(0, cut) if cut > 0 else ""
		_p(author != "", "record() dot carries a non-empty author (got '%s')" % dot)

	(lp as Node).free()