summaryrefslogtreecommitdiff
path: root/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd
diff options
context:
space:
mode:
authorradiohotline <radoihotline@disroot.rg>2026-08-25 16:33:56 +0300
committerradiohotline <radoihotline@disroot.rg>2026-08-25 16:33:56 +0300
commita89e744ed0e8c759caf041a580112365bbfe4303 (patch)
treedd61e320904176995727e86a857d00c90d4933ba /addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd
parent6d53d8cac78250dc888aa49d5f9d4175c6652feb (diff)
escoria updateHEADmain
Diffstat (limited to 'addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd')
-rw-r--r--addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd180
1 files changed, 180 insertions, 0 deletions
diff --git a/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd b/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd
new file mode 100644
index 0000000..6551e08
--- /dev/null
+++ b/addons/gdUnit4/src/core/runners/GdUnitTestSessionRunner.gd
@@ -0,0 +1,180 @@
+extends Node
+## The base test runner implementation.[br]
+## [br]
+## This class provides the core functionality to execute test suites with following features:[br]
+## - Loading and initialization of test suites[br]
+## - Executing test suites and managing test states[br]
+## - Event dispatching and test reporting[br]
+## - Support for headless mode[br]
+## - Plugin version verification[br]
+## [br]
+## Supported by specialized runners:[br]
+## - [b]GdUnitTestRunner[/b]: Used in the editor, connects via tcp to report test results[br]
+## - [b]GdUnitCLRunner[/b]: A command line interface runner, writes test reports to file[br]
+## The test runner runs checked default in fail-fast mode, it stops checked first test failure.
+
+## Overall test run status codes used by the runners
+const RETURN_SUCCESS = 0
+const RETURN_ERROR = 100
+const RETURN_ERROR_HEADLESS_NOT_SUPPORTED = 103
+const RETURN_ERROR_GODOT_VERSION_NOT_SUPPORTED = 104
+const RETURN_WARNING = 101
+
+## Specifies the Node name under which the runner is registered
+const GDUNIT_RUNNER = "GdUnitRunner"
+
+## The current runner configuration
+@warning_ignore("unused_private_class_variable")
+var _runner_config := GdUnitRunnerConfig.new()
+
+## The test suite executor instance
+var _executor: GdUnitTestSuiteExecutor
+var _hooks : GdUnitTestSessionHookService
+
+## Current runner state
+var _state := READY
+
+## Current tests to be processed
+var _test_cases: Array[GdUnitTestCase] = []
+
+
+## Configured report base path (can be set on CI test runner)
+var report_base_path: String = GdUnitFileAccess.current_dir() + "reports":
+ get:
+ return report_base_path
+
+
+## Current session report path
+var report_path: String:
+ get:
+ return "%s/%s%d" % [report_base_path, GdUnitConstants.REPORT_DIR_PREFIX, current_report_history_index]
+
+
+## Current report history index, if max_report_history > 1 we scan for the next index over the existing reports
+var current_report_history_index: int:
+ get:
+ if max_report_history > 1:
+ return GdUnitFileAccess.find_last_path_index(report_base_path, GdUnitConstants.REPORT_DIR_PREFIX) + 1
+ else:
+ return 1
+
+
+## Controls how many report historys will be hold
+var max_report_history: int = GdUnitConstants.DEFAULT_REPORT_HISTORY_COUNT:
+ get:
+ return max_report_history
+ set(value):
+ max_report_history = value
+
+
+# holds the current test session context
+var _test_session: GdUnitTestSession
+
+## Runner state machine
+enum {
+ READY,
+ INIT,
+ RUN,
+ STOP,
+ EXIT
+}
+
+func _init() -> void:
+ if OS.get_cmdline_args().size() == 1:
+ DisplayServer.window_set_title("GdUnit4 Runner (Debug Mode)")
+ else:
+ DisplayServer.window_set_title("GdUnit4 Runner (Release Mode)")
+ if not Engine.is_embedded_in_editor():
+ # minimize scene window checked debug mode
+ DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MINIMIZED)
+ # store current runner instance to engine meta data to can be access in as a singleton
+ Engine.set_meta(GDUNIT_RUNNER, self)
+
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ if Engine.get_version_info().hex < 0x40300:
+ printerr("The GdUnit4 plugin requires Godot version 4.3 or higher to run.")
+ quit(RETURN_ERROR_GODOT_VERSION_NOT_SUPPORTED)
+ return
+ _executor = GdUnitTestSuiteExecutor.new()
+
+ GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event)
+ _state = INIT
+
+
+func _notification(what: int) -> void:
+ if what == NOTIFICATION_PREDELETE:
+ Engine.remove_meta(GDUNIT_RUNNER)
+
+
+## Main test runner loop. Is called every frame to manage the test execution.
+func _process(_delta: float) -> void:
+ match _state:
+ INIT:
+ await init_runner()
+ RUN:
+ _hooks = GdUnitTestSessionHookService.instance()
+ _test_session = GdUnitTestSession.new(_test_cases, report_path)
+ GdUnitSignals.instance().gdunit_event.emit(GdUnitSessionStart.new())
+ # process next test suite
+ set_process(false)
+ var result := await _hooks.execute_startup(_test_session)
+ if result.is_error():
+ push_error(result.error_message())
+ await _executor.run_and_wait(_test_cases)
+ result = await _hooks.execute_shutdown(_test_session)
+ if result.is_error():
+ push_error(result.error_message())
+ _state = STOP
+ set_process(true)
+ GdUnitSignals.instance().gdunit_event.emit(GdUnitSessionClose.new())
+ cleanup_report_history()
+ STOP:
+ _state = EXIT
+ # give the engine small amount time to finish the rpc
+ await get_tree().create_timer(0.1).timeout
+ await quit(get_exit_code())
+
+
+## Used by the inheriting runners to initialize test execution
+func init_runner() -> void:
+ await get_tree().process_frame
+
+
+func cleanup_report_history() -> int:
+ return GdUnitFileAccess.delete_path_index_lower_equals_than(
+ report_path.get_base_dir(),
+ GdUnitConstants.REPORT_DIR_PREFIX,
+ current_report_history_index-1-max_report_history)
+
+
+## Returns the exit code when the test run is finished.[br]
+## Abstract method to be implemented by the inheriting runners.
+func get_exit_code() -> int:
+ return RETURN_SUCCESS
+
+
+## Quits the test runner with given exit code.
+func quit(code: int) -> void:
+ await get_tree().process_frame
+ await get_tree().physics_frame
+ get_tree().quit(code)
+
+
+func prints_warning(message: String) -> void:
+ prints(message)
+
+
+## Default event handler to process test events.[br]
+## Should be overridden by concrete runner implementation.
+@warning_ignore("unused_parameter")
+func _on_gdunit_event(event: GdUnitEvent) -> void:
+ pass
+
+
+## Event bridge from C# GdUnit4.ITestEventListener.cs[br]
+## Used to handle test events from C# tests.
+# gdlint: disable=function-name
+func PublishEvent(data: Dictionary) -> void:
+ _on_gdunit_event(GdUnitEvent.new().deserialize(data))