extends SceneTree
func _init():
# Counters live in a Dictionary because GDScript lambdas capture by VALUE:
# an `ok += 1` inside the lambda updates a copy, and the tally stays 0 while
# every line prints "ok" — a green that cannot go red, which is the one kind
# of test result worth nothing.
var n := {"ok": 0, "bad": 0}
var chk := func(c: bool, what: String):
if c: n.ok += 1; print(" ok ", what)
else: n.bad += 1; print(" FAIL ", what)
print("HyperOverlay GDExtension binding")
chk.call(ClassDB.class_exists("HyperOverlay"), "the class is registered with Godot")
chk.call(ClassDB.can_instantiate("HyperOverlay"), "and can be instantiated")
var ov = ClassDB.instantiate("HyperOverlay")
chk.call(ov != null, "instantiated")
var dir := "/tmp/claude-1000/ho_gd"
DirAccess.make_dir_recursive_absolute(dir)
chk.call(ov.open(dir), "open() succeeds on a fresh storage dir")
chk.call(ov.is_open(), "and reports itself open")
# Serving must not read the file: register a big one and see it return at once.
var src := dir + "/asset.bin"
var f := FileAccess.open(src, FileAccess.WRITE)
var buf := PackedByteArray()
buf.resize(2 * 1024 * 1024)
f.store_buffer(buf)
f.close()
var t0 := Time.get_ticks_msec()
ov.serve("a".repeat(64), src)
chk.call(Time.get_ticks_msec() - t0 < 100, "serve() returns immediately — it does not read the file")
# A fetch nobody can answer must fail rather than hang. Signals arrive on the
# main thread via poll(), so drive it.
var failed := {"hit": false, "reason": ""}
ov.content_failed.connect(func(h, r): failed.hit = true; failed.reason = r)
ov.fetch("b".repeat(64), dir + "/never.bin")
var waited := 0
while not failed.hit and waited < 40000:
ov.poll()
OS.delay_msec(50)
waited += 50
chk.call(failed.hit, "a fetch with no peers is abandoned, not hung (%s)" % failed.reason)
chk.call(failed.reason.contains("stalled"), "and the reason names the watchdog")
print(" ", ov.describe())
ov.close()
chk.call(not ov.is_open(), "close() joins the worker and shuts down cleanly")
ov.free() # a Node, not RefCounted — otherwise ObjectDB reports it leaked
# The harness proves it can count: a deliberate failure, then the real tally.
chk.call(false, "(control: this line must appear as FAIL and be counted)")
var real_bad: int = n.bad - 1
print("\n %d assertions pass, %d fail" % [n.ok, real_bad])
print("PASS" if real_bad == 0 else "FAIL")
quit(0 if real_bad == 0 else 1)