Skip to content

Commit

Permalink
address plugin load issues (#244)
Browse files Browse the repository at this point in the history
* address plugin load issues

* increase range

* fix test runner
  • Loading branch information
bitbrain authored Nov 13, 2023
1 parent 8b7d4ba commit fbf4b65
Show file tree
Hide file tree
Showing 117 changed files with 2,430 additions and 1,674 deletions.
6 changes: 2 additions & 4 deletions addons/beehave/plugin.gd
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ var frames: RefCounted

func _init():
name = "BeehavePlugin"
add_autoload_singleton("BeehaveGlobalMetrics", "./metrics/beehave_global_metrics.gd")
add_autoload_singleton("BeehaveGlobalDebugger", "./debug/global_debugger.gd")
add_autoload_singleton("BeehaveGlobalMetrics", "metrics/beehave_global_metrics.gd")
add_autoload_singleton("BeehaveGlobalDebugger", "debug/global_debugger.gd")
print("Beehave initialized!")


Expand All @@ -20,5 +20,3 @@ func _enter_tree() -> void:

func _exit_tree() -> void:
remove_debugger_plugin(editor_debugger)
editor_debugger.free()
frames.free()
30 changes: 15 additions & 15 deletions addons/gdUnit4/bin/GdUnitCmdTool.gd
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env -S godot -s
extends SceneTree

const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd")

#warning-ignore-all:return_value_discarded
class CLIRunner extends Node:

Expand All @@ -21,12 +23,12 @@ class CLIRunner extends Node:
var _state = READY
var _test_suites_to_process :Array
var _executor
var _cs_executor
var _report :GdUnitHtmlReport
var _report_dir: String
var _report_max: int = DEFAULT_REPORT_COUNT
var _runner_config := GdUnitRunnerConfig.new()
var _console := CmdConsole.new()
var _cs_executor
var _cmd_options: = CmdOptions.new([
CmdOption.new("-a, --add", "-a <directory|path of testsuite>", "Adds the given test suite or directory to the execution pipeline.", TYPE_STRING),
CmdOption.new("-i, --ignore", "-i <testsuite_name|testsuite_name:test-name>", "Adds the given test suite or test case to the ignore list.", TYPE_STRING),
Expand All @@ -48,19 +50,18 @@ class CLIRunner extends Node:
func _ready():
_state = INIT
_report_dir = GdUnitTools.current_dir() + "reports"
_executor = load("res://addons/gdUnit4/src/core/GdUnitExecutor.gd").new()
_executor = load("res://addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd").new()
# stop checked first test failure to fail fast
_executor.fail_fast(true)

if GdUnitTools.is_mono_supported():
_cs_executor = GdUnit3MonoAPI.create_executor(self)

if GdUnit4MonoApiLoader.is_mono_supported():
prints("GdUnit4Mono Version %s loaded." % GdUnit4MonoApiLoader.version())
_cs_executor = GdUnit4MonoApiLoader.create_executor(self)
var err = GdUnitSignals.instance().gdunit_event.connect(Callable(self, "_on_gdunit_event"))
if err != OK:
prints("gdUnitSignals failed")
push_error("Error checked startup, can't connect executor for 'send_event'")
quit(RETURN_ERROR)
add_child(_executor)


func _process(_delta):
Expand All @@ -76,10 +77,11 @@ class CLIRunner extends Node:
set_process(false)
# process next test suite
var test_suite := _test_suites_to_process.pop_front() as Node
add_child(test_suite)
var executor = _cs_executor if GdObjects.is_cs_test_suite(test_suite) else _executor
executor.Execute(test_suite)
await executor.ExecutionCompleted
if _cs_executor != null and _cs_executor.IsExecutable(test_suite):
_cs_executor.Execute(test_suite)
await _cs_executor.ExecutionCompleted
else:
await _executor.execute(test_suite)
set_process(true)
STOP:
_state = EXIT
Expand All @@ -88,9 +90,8 @@ class CLIRunner extends Node:


func quit(code :int) -> void:
if is_instance_valid(_executor):
_executor.free()
GdUnitTools.dispose_all()
await GdUnitMemoryObserver.gc_on_guarded_instances()
await get_tree().physics_frame
get_tree().quit(code)

Expand Down Expand Up @@ -397,9 +398,8 @@ func _initialize():

func _finalize():
prints("Finallize ..")
_cli_runner.free()
if is_instance_valid(_cli_runner):
_cli_runner.free()
prints("-Orphan nodes report-----------------------")
Window.print_orphan_nodes()
prints("-SceneTree report-----------------------")
root.print_tree_pretty()
prints("Finallize .. done")
2 changes: 2 additions & 0 deletions addons/gdUnit4/bin/GdUnitCopyLog.gd
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env -S godot -s
extends MainLoop

const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd")

const NO_LOG_TEMPLATE = """
<!DOCTYPE html>
<html>
Expand Down
56 changes: 34 additions & 22 deletions addons/gdUnit4/bin/ProjectScanner.gd
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@ extends SceneTree

const CmdConsole = preload("res://addons/gdUnit4/src/cmd/CmdConsole.gd")

var scanner := ProjectScanner.new()
var scanner := SourceScanner.new()

func _initialize():
set_auto_accept_quit(false)
root.add_child(scanner)


func _process(_delta):
if not is_instance_valid(scanner):
quit(0)


func _finalize():
if Engine.get_version_info().hex < 0x40100 or Engine.get_version_info().hex > 0x40101:
print("Finalize scanner ..")
scanner.free()
if Engine.get_version_info().hex < 0x40100 or Engine.get_version_info().hex > 0x40101:
prints("done")
prints("__finalize")


class ProjectScanner extends Node:

class SourceScanner extends Node:

enum {
INIT,
SCAN,
QUIT
QUIT,
DONE
}


var _counter = 0
var WAIT_TIME_IN_MS = 5.000
var _state = INIT
Expand All @@ -46,36 +51,43 @@ class ProjectScanner extends Node:
_console.prints_color("Running project scan:", Color.CORNFLOWER_BLUE)
await scan_project()
set_process(true)
_state = QUIT
if _state == QUIT or _counter >= WAIT_TIME_IN_MS:
_state = DONE
_console.prints_color("Scan project done.", Color.CORNFLOWER_BLUE)
_console.prints_color("======================================", Color.CORNFLOWER_BLUE)
_console.new_line()
await get_tree().process_frame
get_tree().quit(0)
queue_free()


func scan_project() -> void:
var plugin := EditorPlugin.new()
var fs := plugin.get_editor_interface().get_resource_filesystem()

_console.prints_color("Scan :", Color.SANDY_BROWN)
_console.progressBar(0)
fs.scan()
await get_tree().process_frame
while fs.is_scanning():
await get_tree().process_frame
_console.progressBar(fs.get_scanning_progress() * 100 as int)
_console.progressBar(100)
_console.new_line()

if fs.has_method("reimport_files--"):
_console.prints_color("Reimport images :", Color.SANDY_BROWN)
for source in ["res://addons/gdUnit4/src/ui/assets/orphan", "res://addons/gdUnit4/src/ui/assets/spinner", "res://addons/gdUnit4/src/ui/assets/"]:
var image_files := Array(DirAccess.get_files_at(source))
#_console.prints_color("%s" % image_files, Color.SANDY_BROWN)
var files := image_files.map(func full_path(file_name):
return "%s/%s" % [source, file_name] )\
.filter(func filter_import_files(path :String):
return path.get_extension() != "import")
prints(files)
fs.reimport_files(files)

_console.prints_color("Scan sources: ", Color.SANDY_BROWN)
_console.progressBar(0)
fs.scan_sources()
await get_tree().create_timer(5).timeout
await get_tree().process_frame

_console.prints_color("Scan: ", Color.SANDY_BROWN)
fs.scan()
await get_tree().process_frame
while fs.is_scanning():
await get_tree().process_frame
_console.progressBar(fs.get_scanning_progress() * 100 as int)
_console.progressBar(100)
_console.new_line()
plugin.free()
_state = QUIT
plugin.queue_free()
2 changes: 1 addition & 1 deletion addons/gdUnit4/plugin.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
name="gdUnit4"
description="Unit Testing Framework for Godot Scripts"
author="Mike Schulze"
version="4.1.4"
version="4.2.0"
script="plugin.gd"
18 changes: 4 additions & 14 deletions addons/gdUnit4/plugin.gd
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
@tool
extends EditorPlugin

const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd")

var _gd_inspector :Node
var _server_node
var _gd_console :Node


# removes GdUnit classes inherits from Godot.Node from the node inspecor, ohterwise it takes very long to popup the dialog
func _fixup_node_inspector() -> void:
var classes := PackedStringArray([
"GdUnitTestSuite",
"_TestCase",
"GdUnitInspecor",
"GdUnitExecutor",
"GdUnitTcpClient",
"GdUnitTcpServer"])
for clazz in classes:
remove_custom_type(clazz)


func _enter_tree():
Engine.set_meta("GdUnitEditorPlugin", self)
GdUnitSettings.setup()
Expand All @@ -30,11 +19,12 @@ func _enter_tree():
add_control_to_bottom_panel(_gd_console, "gdUnitConsole")
_server_node = load("res://addons/gdUnit4/src/network/GdUnitServer.tscn").instantiate()
add_child(_server_node)
_fixup_node_inspector()
prints("Loading GdUnit4 Plugin success")
if GdUnitSettings.is_update_notification_enabled():
var update_tool = load("res://addons/gdUnit4/src/update/GdUnitUpdateNotify.tscn").instantiate()
Engine.get_main_loop().root.call_deferred("add_child", update_tool)
if GdUnit4MonoApiLoader.is_mono_supported():
prints("GdUnit4Mono Version %s loaded." % GdUnit4MonoApiLoader.version())


func _exit_tree():
Expand Down
2 changes: 1 addition & 1 deletion addons/gdUnit4/runtest.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ IF "%GODOT_TYPE%" == "mono" (

%GODOT_BIN% -s -d .\addons\gdUnit4\bin\GdUnitCmdTool.gd %*
SET exit_code=%errorlevel%
%GODOT_BIN% --no-window --quiet -s -d .\addons\gdUnit4\bin\GdUnitCopyLog.gd %*
%GODOT_BIN% --headless --quiet -s -d .\addons\gdUnit4\bin\GdUnitCopyLog.gd %*

ECHO %exit_code%

Expand Down
26 changes: 26 additions & 0 deletions addons/gdUnit4/src/GdUnitAssert.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,32 @@ class_name GdUnitAssert
extends RefCounted


# Scans the current stack trace for the root cause to extract the line number
static func _get_line_number() -> int:
var stack_trace := get_stack()
if stack_trace == null or stack_trace.is_empty():
return -1
for stack_info in stack_trace:
var function :String = stack_info.get("function")
# we catch helper asserts to skip over to return the correct line number
if function.begins_with("assert_"):
continue
if function.begins_with("test_"):
return stack_info.get("line")
var source :String = stack_info.get("source")
if source.is_empty() \
or source.begins_with("user://") \
or source.ends_with("GdUnitAssert.gd") \
or source.ends_with("AssertImpl.gd") \
or source.ends_with("GdUnitTestSuite.gd") \
or source.ends_with("GdUnitSceneRunnerImpl.gd") \
or source.ends_with("GdUnitObjectInteractions.gd") \
or source.ends_with("GdUnitAwaiter.gd"):
continue
return stack_info.get("line")
return -1


## Verifies that the current value is null.
func is_null():
return self
Expand Down
21 changes: 14 additions & 7 deletions addons/gdUnit4/src/GdUnitAwaiter.gd
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
class_name GdUnitAwaiter
extends RefCounted

const GdUnitAssertImpl = preload("res://addons/gdUnit4/src/asserts/GdUnitAssertImpl.gd")


# Waits for a specified signal in an interval of 50ms sent from the <source>, and terminates with an error after the specified timeout has elapsed.
# source: the object from which the signal is emitted
# signal_name: signal name
# args: the expected signal arguments as an array
# timeout: the timeout in ms, default is set to 2000ms
static func await_signal_on(source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> Variant:
var line_number := GdUnitAssertImpl._get_line_number()
func await_signal_on(source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> Variant:
# fail fast if the given source instance invalid
var line_number := GdUnitAssert._get_line_number()
if not is_instance_valid(source):
GdUnitAssertImpl.new(signal_name)\
.report_error(GdAssertMessages.error_await_signal_on_invalid_instance(source, signal_name, args), line_number)
return await Engine.get_main_loop().process_frame
# fail fast if the given source instance invalid
if not is_instance_valid(source):
GdUnitAssertImpl.new(signal_name)\
Expand All @@ -27,8 +34,8 @@ static func await_signal_on(source :Object, signal_name :String, args :Array = [
# signal_name: signal name
# args: the expected signal arguments as an array
# timeout: the timeout in ms, default is set to 2000ms
static func await_signal_idle_frames(source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> Variant:
var line_number := GdUnitAssertImpl._get_line_number()
func await_signal_idle_frames(source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> Variant:
var line_number := GdUnitAssert._get_line_number()
# fail fast if the given source instance invalid
if not is_instance_valid(source):
GdUnitAssertImpl.new(signal_name)\
Expand All @@ -47,17 +54,17 @@ static func await_signal_idle_frames(source :Object, signal_name :String, args :
# # waits for 100ms
# await GdUnitAwaiter.await_millis(myNode, 100).completed
# use this waiter and not `await get_tree().create_timer().timeout to prevent errors when a test case is timed out
static func await_millis(milliSec :int) -> void:
func await_millis(milliSec :int) -> void:
var timer :Timer = Timer.new()
timer.set_name("gdunit_await_millis_timer_%d" % timer.get_instance_id())
Engine.get_main_loop().root.add_child(timer)
timer.add_to_group("GdUnitTimers")
timer.set_one_shot(true)
timer.start(milliSec * 0.001)
timer.start(milliSec / 1000.0)
await timer.timeout
timer.queue_free()


# Waits until the next idle frame
static func await_idle_frame() -> void:
func await_idle_frame() -> void:
await Engine.get_main_loop().process_frame
Loading

0 comments on commit fbf4b65

Please sign in to comment.