extends RefCounted # Base class for pure-function unit tests run by test_runner.gd. A test case # script extends this and defines any number of test_*() methods; the runner # discovers them by name, not by registration, so adding a test is just # adding a method. # # Test case scripts should `extends "res://tests/test_case.gd"` (path-based), # not `extends TestCase` (the bare class_name). On a fresh headless run the # global script class cache isn't guaranteed populated yet, so a bare-name # reference can fail to resolve; the path form and test_runner.gd's own # `preload()` both sidestep that. var failures: Array[String] = [] # Adversarial-review regression: GDScript has no exceptions, so a runtime # error partway through a test method (e.g. a null dereference) just logs a # SCRIPT ERROR and returns — `failures` stays empty exactly as if every # assertion had passed, and the runner counted it as a PASS. assertions_made # is incremented by every assert_* call; test_runner.gd now treats a test # that completes with zero assertions as a failure in its own right, so a # test that crashes before reaching its first assert_* can no longer read # as a silent pass. var assertions_made := 0 func assert_true(condition: bool, message: String) -> void: assertions_made += 1 if not condition: failures.append(message) func assert_eq(actual, expected, message: String) -> void: assertions_made += 1 if actual != expected: failures.append("%s: expected %s, got %s" % [message, expected, actual]) func assert_almost_eq(actual: float, expected: float, tolerance: float, message: String) -> void: assertions_made += 1 if absf(actual - expected) > tolerance: failures.append("%s: expected %s ± %s, got %s" % [message, expected, tolerance, actual])