diff --git a/addons/besseretests/src/runtimescene.gd b/addons/besseretests/src/runtimescene.gd index 560bb87..e2b8480 100644 --- a/addons/besseretests/src/runtimescene.gd +++ b/addons/besseretests/src/runtimescene.gd @@ -3,11 +3,12 @@ extends Control # Configuration for the configuration var config: Node = Node.new() const config_path: String = "res://addons/besseretests_config.gd" -const config_keys: Dictionary = { "test_directory": TYPE_STRING, "loglevel": TYPE_INT, "print_orphan_nodes": TYPE_BOOL } +const config_keys: Dictionary = { "test_directory": TYPE_STRING, "log_level": TYPE_INT, "log_format": TYPE_STRING, "print_orphan_nodes": TYPE_BOOL } # Configuration var config_test_directory: String = "res://tests" -var config_loglevel: int = 2 +var config_log_level: int = 2 +var config_log_format: String = "%color_start%%level% %origin%: %message%%color_end%" var config_print_orphan_nodes: bool = false # Statistics <3 & results @@ -23,10 +24,30 @@ var stats_unknown: int = 0 # To stop any still running test var crashed: bool = false +# +++ initialization +++ +# Startup function func _ready() -> void: await get_tree().process_frame - # Load configuration + await load_config() + update_window_properties() + await perform_checks() + + # Run test suites + for suite in DirAccess.get_files_at(config_test_directory): + if crashed: return + await run_suite(suite.replace(".gd", "")) + if crashed: return # Check if crashed + + await print_results() + + # Shutdown + if stats_all == stats_ok + stats_skip: terminate(0) + elif stats_all == stats_ok + stats_warn + stats_skip: terminate(1) + else: terminate(2) + +# Load configuration +func load_config() -> void: if FileAccess.file_exists(config_path): config.set_script(load(config_path)) for config_key in config_keys: @@ -34,8 +55,9 @@ func _ready() -> void: if typeof(config.get(config_key)) != config_keys[config_key]: await lerror("Configuration error: Key \"" + config_key + "\" is not of type '" + type_string(config_keys[config_key]) + "' (is '" + type_string(typeof(config.get(config_key))) + "')") ldiag("Configuration update: Key \"" + config_key + "\" has been updated") set("config_" + config_key, config.get(config_key)) - - # Update window properties + +# Update window properties +func update_window_properties() -> void: DisplayServer.window_set_size(Vector2i(960, 540)) DisplayServer.window_set_title("Running tests") DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED) @@ -47,18 +69,14 @@ func _ready() -> void: DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_RESIZE_DISABLED, true) DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_TRANSPARENT, false) DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) - + +# Perform startup checks +func perform_checks() -> void: # Check for testing directory if !DirAccess.dir_exists_absolute(config_test_directory): await lcrash("Testing directory \"" + config_test_directory + "\" does not exist") - - # Run test suites - for suite in DirAccess.get_files_at(config_test_directory): - if crashed: return - await run_suite(suite.replace(".gd", "")) - - if crashed: return - - # Print test results + +# Print test results +func print_results() -> void: lresu("") lresu("Test results:") for test in results: @@ -104,12 +122,70 @@ func _ready() -> void: if stats_unknown == 1: lerror(" -> " + str(stats_unknown) + " test has an unknown status (fix that!)") else: lerror(" -> " + str(stats_unknown) + " tests have an unknown status (fix that!)") lresu("") - - # Shutdown - if stats_all == stats_ok + stats_skip: terminate(0) - elif stats_all == stats_ok + stats_warn + stats_skip: terminate(1) - else: terminate(2) +# +++ logging +++ +# Main logging function +func _log(message: String, origin: String, level: int, sanitize: bool = true, level_name: String = "", level_color_start: String = "", level_color_end: String = "") -> void: + if level >= config_log_level: + var format: String = config_log_format + + # Replace common placeholders + format = format.replace("%time_us", str(Time.get_ticks_usec())) + format = format.replace("%time_ms%", str(Time.get_ticks_msec())) + format = format.replace("%time%", Time.get_time_string_from_system(true)) + format = format.replace("%origin%", origin) + format = format.replace("%message%", message) + format = format.replace("%color%", "no!") # no! + if level != NAN: # except when level is not a number + format = format.replace("%color_start%", "[color=%color%]") + format = format.replace("%color_end%", "[/color]") + + # Replace level-specific placeholders + match(level): + 0: + format = format.replace("%level%", "DIAG") + format = format.replace("%color%", "gray") + 1: + format = format.replace("%level%", "VERB") + format = format.replace("%color%", "gray") + 2: + format = format.replace("%level%", "INFO") + format = format.replace("%color%", "white") + 3: + format = format.replace("%level%", "WARN") + format = format.replace("%color%", "yellow") + 4: + format = format.replace("%level%", "ERR!") + format = format.replace("%color%", "red") + NAN: + format = format.replace("%level%", level_name) + format = format.replace("%color_start%", level_color_start) + format = format.replace("%color_end%", level_color_end) + _: + assert(true, "Invalid level '" + str(level) + "' (message='" + message + "')") + return + + # Print message + print_rich(format) + +# Crash +func lcrash(message: String, origin: String = "Bessere Tests") -> void: + crashed = true + _log(message, origin, NAN, true, "CRSH", "[color=red][b]", "[/b][/color]") + await terminate(69) + +# Self explanitory +func lresu(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, NAN, false, "RESU", "[color=white]", "[/color]") +func ldiag(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 0) +func lverb(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 1) +func linfo(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 2) +func lwarn(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 3) +func lerror(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 4) + +# Message sanitization +func lsanitize(message: String) -> String: return message.replace("[", "[lb]").replace("]", "[rb]").replace("[lb[rb]", "[lb]").replace("\n", "\\n") + +# +++ /etc/ +++ # Runs a test suite func run_suite(suite: String) -> void: linfo("Running suite \"" + suite + "\"") @@ -162,43 +238,6 @@ func run_suite(suite: String) -> void: # Remove suite node get_tree().root.remove_child(suite_node) suite_node.queue_free() - -# Logging -func _log(message: String, origin: String, level: int) -> void: - if level >= config_loglevel: - var level_name: String - var level_color: String - match(level): - 0: - level_name = "DIAG" - level_color = "gray" - 1: - level_name = "VERB" - level_color = "gray" - 2: - level_name = "INFO" - level_color = "white" - 3: - level_name = "WARN" - level_color = "yellow" - 4: - level_name = "ERR!" - level_color = "red" - print_rich("[color=" + level_color + "]" + level_name + " " + origin + ": " + message.replace("\n", "\\n") + "[/color]") -func lresu(message: String, origin: String = "Bessere Tests") -> void: print_rich("[color=white]RESU " + origin + ": " + message + "[/color]") -func ldiag(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 0) -func lverb(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 1) -func linfo(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 2) -func lwarn(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 3) -func lerror(message: String, origin: String = "Bessere Tests") -> void: _log(message, origin, 4) -func lcrash(message: String, origin: String = "Bessere Tests") -> void: - crashed = true - print_rich("[color=red][b]CRSH " + origin + ": " + message + "[/b][/color]") - await terminate(69) - -# Log message sanitization -func lsanitize(message: String) -> String: return message.replace("[", "[lb]").replace("]", "[rb]").replace("[lb[rb]", "[lb]").replace("\n", "\\n") - # Terminates the engine func terminate(exit_code: int = 0) -> void: config.queue_free() diff --git a/addons/besseretests_config.gd b/addons/besseretests_config.gd index b6191d8..5d8d143 100644 --- a/addons/besseretests_config.gd +++ b/addons/besseretests_config.gd @@ -1,4 +1,6 @@ extends Node var test_directory: String = "res://addons/besseretests/examples/" +var log_level: int = 0 +var log_format = null var print_orphan_nodes: bool = true