400556134f
quit(1 if failed > 0 else 0) beendete einen Lauf mit "0 passed, 0 failed" mit Code 0, zum Beispiel nachdem der Testordner umbenannt wurde oder alle Tests falsch benannt waren. Die Prüfliste sah dann grün aus, ohne etwas geprüft zu haben. Der Läufer endet jetzt auch mit Code 1, wenn kein Test bestanden wurde. Der Doc-Kommentar sagt das. Einmal von Hand geprüft: Mit einem Dateifilter, den keine Testdatei erfüllt, meldete der alte Läufer 0 passed, 0 failed mit Code 0, der neue endet mit Code 1. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
83 lines
2.4 KiB
GDScript
83 lines
2.4 KiB
GDScript
extends SceneTree
|
|
## Runs every test script in res://tests whose file name starts with "test_".
|
|
## Every method whose name starts with "test_" is one test. A test fails if a
|
|
## check fails or if an error is reported while it runs, for example a call
|
|
## on a null value. Exits with code 1 if any test failed or if no test ran,
|
|
## so that a renamed test folder or misnamed tests cannot pass as a clean run.
|
|
##
|
|
## From the repository root:
|
|
## godot --headless --path game -s res://tests/run_tests.gd
|
|
|
|
const TEST_DIR := "res://tests"
|
|
|
|
|
|
## Counts the errors that are reported while tests run. Warnings do not count.
|
|
class ErrorCounter extends Logger:
|
|
var _mutex := Mutex.new()
|
|
var _errors := 0
|
|
|
|
func errors() -> int:
|
|
_mutex.lock()
|
|
var count := _errors
|
|
_mutex.unlock()
|
|
return count
|
|
|
|
func _log_error(
|
|
_function: String,
|
|
_file: String,
|
|
_line: int,
|
|
_code: String,
|
|
_rationale: String,
|
|
_editor_notify: bool,
|
|
error_type: int,
|
|
_script_backtraces: Array[ScriptBacktrace]
|
|
) -> void:
|
|
if error_type == ERROR_TYPE_WARNING:
|
|
return
|
|
_mutex.lock()
|
|
_errors += 1
|
|
_mutex.unlock()
|
|
|
|
|
|
func _initialize() -> void:
|
|
_run_all.call_deferred()
|
|
|
|
|
|
func _run_all() -> void:
|
|
var counter := ErrorCounter.new()
|
|
OS.add_logger(counter)
|
|
var passed := 0
|
|
var failed := 0
|
|
var files := DirAccess.get_files_at(TEST_DIR)
|
|
files.sort()
|
|
for file in files:
|
|
if not (file.begins_with("test_") and file.ends_with(".gd")):
|
|
continue
|
|
var script: GDScript = load(TEST_DIR.path_join(file))
|
|
if script == null or not script.can_instantiate():
|
|
failed += 1
|
|
print("FAIL %s the script does not load; see the error above" % file)
|
|
continue
|
|
for method in script.get_script_method_list():
|
|
var test_name: String = method["name"]
|
|
if not test_name.begins_with("test_"):
|
|
continue
|
|
var test: TestCase = script.new()
|
|
test.tree = self
|
|
var errors_before := counter.errors()
|
|
await test.call(test_name)
|
|
var errors := counter.errors() - errors_before
|
|
if errors > 0:
|
|
test.failures.append("%d error(s) reported while the test ran; see above" % errors)
|
|
if test.failures.is_empty():
|
|
passed += 1
|
|
print("ok %s %s" % [file, test_name])
|
|
else:
|
|
failed += 1
|
|
print("FAIL %s %s" % [file, test_name])
|
|
for failure in test.failures:
|
|
print(" " + failure)
|
|
OS.remove_logger(counter)
|
|
print("%d passed, %d failed" % [passed, failed])
|
|
quit(1 if failed > 0 or passed == 0 else 0)
|