class_name GdUnitTestSessionHookService extends Object var enigne_hooks: Array[GdUnitTestSessionHook] = []: get: return enigne_hooks set(value): enigne_hooks.append(value) var _save_settings: bool = false static func instance() -> GdUnitTestSessionHookService: return GdUnitSingleton.instance("GdUnitTestSessionHookService", func()->GdUnitTestSessionHookService: GdUnitSignals.instance().gdunit_message.emit("Installing GdUnit4 session system hooks.") var service := GdUnitTestSessionHookService.new() # Register default system hooks here service._save_settings = false service.register(GdUnitHtmlReporterTestSessionHook.new()) service.register(GdUnitXMLReporterTestSessionHook.new()) service.load_hook_settings() service._save_settings = true return service ) static func contains_hook(current: GdUnitTestSessionHook, other: GdUnitTestSessionHook) -> bool: return current.get_script().resource_path == other.get_script().resource_path func find_custom(hook: GdUnitTestSessionHook) -> int: for index in enigne_hooks.size(): if contains_hook.call(enigne_hooks[index], hook): return index return -1 func load_hook(hook_resourc_path: String) -> GdUnitResult: if !FileAccess.file_exists(hook_resourc_path): return GdUnitResult.error("The hook '%s' not exists." % hook_resourc_path) var script: GDScript = load(hook_resourc_path) if script.get_base_script() != GdUnitTestSessionHook: return GdUnitResult.error("The hook '%s' must inhertit from 'GdUnitTestSessionHook'." % hook_resourc_path) return GdUnitResult.success(script.new()) func enable_hook(hook: GdUnitTestSessionHook, enabled: bool) -> void: _enable_hook(hook, enabled) GdUnitSignals.instance().gdunit_message.emit("Session hook '{name}' {enabled}.".format({ "name": hook.name, "enabled": "enabled" if enabled else "disabled"}) ) save_hock_setttings() func register(hook: GdUnitTestSessionHook, enabled: bool = true) -> GdUnitResult: if find_custom(hook) != -1: return GdUnitResult.error("A hook instance of '%s' is already registered." % hook.get_script().resource_path) _enable_hook(hook, enabled) enigne_hooks.append(hook) save_hock_setttings() GdUnitSignals.instance().gdunit_message.emit("Session hook '%s' installed." % hook.name) return GdUnitResult.success() func unregister(hook: GdUnitTestSessionHook) -> GdUnitResult: var hook_index := find_custom(hook) if hook_index == -1: return GdUnitResult.error("The hook instance of '%s' is NOT registered." % hook.get_script().resource_path) enigne_hooks.remove_at(hook_index) save_hock_setttings() return GdUnitResult.success() func move_before(hook: GdUnitTestSessionHook, before: GdUnitTestSessionHook) -> void: var before_index := find_custom(before) var hook_index := find_custom(hook) # Verify the hook to move is behind the hook to be moved if before_index >= hook_index: return enigne_hooks.remove_at(hook_index) enigne_hooks.insert(before_index, hook) save_hock_setttings() func move_after(hook: GdUnitTestSessionHook, after: GdUnitTestSessionHook) -> void: var after_index := find_custom(after) var hook_index := find_custom(hook) # Verify the hook to move is before the hook to be moved if after_index <= hook_index: return enigne_hooks.remove_at(hook_index) enigne_hooks.insert(after_index, hook) save_hock_setttings() func execute_startup(session: GdUnitTestSession) -> GdUnitResult: return await execute("startup", session) func execute_shutdown(session: GdUnitTestSession) -> GdUnitResult: return await execute("shutdown", session, true) func execute(hook_func: String, session: GdUnitTestSession, reverse := false) -> GdUnitResult: var failed_hook_calls: Array[GdUnitResult] = [] for hook_index in enigne_hooks.size(): var index := enigne_hooks.size()-hook_index-1 if reverse else hook_index var hook: = enigne_hooks[index] if not is_enabled(hook): continue if OS.is_stdout_verbose(): GdUnitSignals.instance().gdunit_message.emit("Session hook '%s' > %s()" % [hook.name, hook_func]) var result: GdUnitResult = await hook.call(hook_func, session) if result == null: failed_hook_calls.push_back(GdUnitResult.error("Result is null! Check '%s'" % hook.get_script().resource_path)) elif result.is_error(): failed_hook_calls.push_back(result) if failed_hook_calls.is_empty(): return GdUnitResult.success() var errors := failed_hook_calls.map(func(result: GdUnitResult) -> String: return "Hook call '%s' failed with error: '%s'" % [hook_func, result.error_message()] ) return GdUnitResult.error( "\n".join(errors)) func save_hock_setttings() -> void: if not _save_settings: return var hooks_to_save: Dictionary[String, bool] = {} for hook in enigne_hooks: var enabled: bool = hook.get_meta("enabled") hooks_to_save[hook.get_script().resource_path] = enabled GdUnitSettings.set_session_hooks(hooks_to_save) func load_hook_settings() -> void: var hooks_resource_paths := GdUnitSettings.get_session_hooks() if hooks_resource_paths.is_empty(): return for hock_path: String in hooks_resource_paths.keys(): var enabled := hooks_resource_paths[hock_path] # Do not reinstall already installed hooks var existing_hook: GdUnitTestSessionHook = enigne_hooks.filter(func(element: GdUnitTestSessionHook) -> bool: return element.get_script().resource_path == hock_path ).front() # Applay enabled settings if existing_hook != null: _enable_hook(existing_hook, enabled) continue # Load additional hooks var result := load_hook(hock_path) if result.is_error(): push_error(result.error_message()) continue GdUnitSignals.instance().gdunit_message.emit("Installing GdUnit4 session hooks.") var hook: GdUnitTestSessionHook = result.value() result = register(hook, enabled) if result.is_error(): push_error(result.error_message()) continue static func is_enabled(hook: GdUnitTestSessionHook) -> bool: if hook.has_meta("enabled"): return hook.get_meta("enabled") return true func _enable_hook(hook: GdUnitTestSessionHook, enabled: bool) -> void: hook.set_meta("enabled", enabled)