From 1340d012a6f5315eb08e141f250f7300f214f813 Mon Sep 17 00:00:00 2001 From: Nullpointer Date: Sat, 10 Feb 2024 21:52:55 +0100 Subject: [PATCH] GD-343: Fix `.NET: Failed to unload assemblies` error when unload the plugin (#344) # Why Some GdUnit4 users reported these errors on discord -> https://discordapp.com/channels/885149082119733269/1201435634875764756 # What * do not extend anymore from the gdunit assembly, we only load the class and use the static methods * rename classes from `mono` to `csharp` (mono is outdated) --- .github/workflows/ci-pr.yml | 4 ++- addons/gdUnit4/bin/GdUnitCmdTool.gd | 6 ++-- addons/gdUnit4/plugin.gd | 4 +-- addons/gdUnit4/src/core/GdObjects.gd | 2 +- addons/gdUnit4/src/core/GdUnitRunner.gd | 2 +- .../src/core/GdUnitTestSuiteBuilder.gd | 2 +- .../src/core/GdUnitTestSuiteScanner.gd | 6 ++-- addons/gdUnit4/src/mono/GdUnit4CSharpApi.cs | 19 ++++++++++++ ...ApiLoader.gd => GdUnit4CSharpApiLoader.gd} | 26 ++++++++--------- addons/gdUnit4/src/mono/GdUnit4MonoApi.cs | 17 ----------- addons/gdUnit4/test/GdUnitScriptTypeTest.gd | 2 +- .../gdUnit4/test/GdUnitTestResourceLoader.gd | 4 +-- ...rTest.gd => GdUnit4CSharpApiLoaderTest.gd} | 29 ++++++++++--------- .../gdUnit4/test/mono/GdUnit4CSharpApiTest.cs | 22 ++++++++++++++ .../gdUnit4/test/mono/GdUnit4MonoApiTest.cs | 23 --------------- 15 files changed, 86 insertions(+), 82 deletions(-) create mode 100644 addons/gdUnit4/src/mono/GdUnit4CSharpApi.cs rename addons/gdUnit4/src/mono/{GdUnit4MonoApiLoader.gd => GdUnit4CSharpApiLoader.gd} (67%) delete mode 100644 addons/gdUnit4/src/mono/GdUnit4MonoApi.cs rename addons/gdUnit4/test/mono/{GdUnit4MonoApiLoaderTest.gd => GdUnit4CSharpApiLoaderTest.gd} (62%) create mode 100644 addons/gdUnit4/test/mono/GdUnit4CSharpApiTest.cs delete mode 100644 addons/gdUnit4/test/mono/GdUnit4MonoApiTest.cs diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml index 0ed9f433..3a0ae28c 100644 --- a/.github/workflows/ci-pr.yml +++ b/.github/workflows/ci-pr.yml @@ -33,8 +33,10 @@ jobs: godot-status: ['stable'] godot-net: ['.Net', ''] include: + - godot-version: '4.2.2' + godot-status: 'rc1' - godot-version: '4.3' - godot-status: 'dev2' + godot-status: 'dev3' permissions: actions: write diff --git a/addons/gdUnit4/bin/GdUnitCmdTool.gd b/addons/gdUnit4/bin/GdUnitCmdTool.gd index 8ade567d..00d5ad95 100644 --- a/addons/gdUnit4/bin/GdUnitCmdTool.gd +++ b/addons/gdUnit4/bin/GdUnitCmdTool.gd @@ -101,9 +101,9 @@ class CLIRunner: _executor = load("res://addons/gdUnit4/src/core/execution/GdUnitTestSuiteExecutor.gd").new() # stop checked first test failure to fail fast _executor.fail_fast(true) - if GdUnit4MonoApiLoader.is_mono_supported(): - prints("GdUnit4Mono Version %s loaded." % GdUnit4MonoApiLoader.version()) - _cs_executor = GdUnit4MonoApiLoader.create_executor(self) + if GdUnit4CSharpApiLoader.is_mono_supported(): + prints("GdUnit4Mono Version %s loaded." % GdUnit4CSharpApiLoader.version()) + _cs_executor = GdUnit4CSharpApiLoader.create_executor(self) var err := GdUnitSignals.instance().gdunit_event.connect(_on_gdunit_event) if err != OK: prints("gdUnitSignals failed") diff --git a/addons/gdUnit4/plugin.gd b/addons/gdUnit4/plugin.gd index c04b593f..963673ef 100644 --- a/addons/gdUnit4/plugin.gd +++ b/addons/gdUnit4/plugin.gd @@ -26,8 +26,8 @@ func _enter_tree() -> void: if GdUnitSettings.is_update_notification_enabled(): var update_tool :Node = 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()) + if GdUnit4CSharpApiLoader.is_mono_supported(): + prints("GdUnit4Mono Version %s loaded." % GdUnit4CSharpApiLoader.version()) func _exit_tree() -> void: diff --git a/addons/gdUnit4/src/core/GdObjects.gd b/addons/gdUnit4/src/core/GdObjects.gd index 999cfa46..94de509d 100644 --- a/addons/gdUnit4/src/core/GdObjects.gd +++ b/addons/gdUnit4/src/core/GdObjects.gd @@ -380,7 +380,7 @@ static func is_script(value :Variant) -> bool: static func is_test_suite(script :Script) -> bool: - return is_gd_testsuite(script) or GdUnit4MonoApiLoader.is_test_suite(script.resource_path) + return is_gd_testsuite(script) or GdUnit4CSharpApiLoader.is_test_suite(script.resource_path) static func is_native_class(value :Variant) -> bool: diff --git a/addons/gdUnit4/src/core/GdUnitRunner.gd b/addons/gdUnit4/src/core/GdUnitRunner.gd index 9fb66285..686e4f89 100644 --- a/addons/gdUnit4/src/core/GdUnitRunner.gd +++ b/addons/gdUnit4/src/core/GdUnitRunner.gd @@ -30,7 +30,7 @@ func _init() -> void: 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) - _cs_executor = GdUnit4MonoApiLoader.create_executor(self) + _cs_executor = GdUnit4CSharpApiLoader.create_executor(self) func _ready() -> void: diff --git a/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd b/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd index 7cd5dfdd..5e49c41c 100644 --- a/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd +++ b/addons/gdUnit4/src/core/GdUnitTestSuiteBuilder.gd @@ -8,7 +8,7 @@ static func create(source :Script, line_number :int) -> GdUnitResult: ScriptEditorControls.save_an_open_script(source.resource_path) ScriptEditorControls.save_an_open_script(test_suite_path, true) if GdObjects.is_cs_script(source): - return GdUnit4MonoApiLoader.create_test_suite(source.resource_path, line_number+1, test_suite_path) + return GdUnit4CSharpApiLoader.create_test_suite(source.resource_path, line_number+1, test_suite_path) var parser := GdScriptParser.new() var lines := source.source_code.split("\n") var current_line := lines[line_number] diff --git a/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd b/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd index ff7ab6df..75945587 100644 --- a/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd +++ b/addons/gdUnit4/src/core/GdUnitTestSuiteScanner.gd @@ -79,8 +79,8 @@ static func _file(dir :DirAccess, file_name :String) -> String: func _parse_is_test_suite(resource_path :String) -> Node: if not GdUnitTestSuiteScanner._is_script_format_supported(resource_path): return null - if GdUnit4MonoApiLoader.is_test_suite(resource_path): - return GdUnit4MonoApiLoader.parse_test_suite(resource_path) + if GdUnit4CSharpApiLoader.is_test_suite(resource_path): + return GdUnit4CSharpApiLoader.parse_test_suite(resource_path) var script :Script = ResourceLoader.load(resource_path) if not GdObjects.is_test_suite(script): return null @@ -93,7 +93,7 @@ static func _is_script_format_supported(resource_path :String) -> bool: var ext := resource_path.get_extension() if ext == "gd": return true - return GdUnit4MonoApiLoader.is_csharp_file(resource_path) + return GdUnit4CSharpApiLoader.is_csharp_file(resource_path) func _parse_test_suite(script :GDScript) -> GdUnitTestSuite: diff --git a/addons/gdUnit4/src/mono/GdUnit4CSharpApi.cs b/addons/gdUnit4/src/mono/GdUnit4CSharpApi.cs new file mode 100644 index 00000000..6c27132c --- /dev/null +++ b/addons/gdUnit4/src/mono/GdUnit4CSharpApi.cs @@ -0,0 +1,19 @@ +using Godot; +using Godot.Collections; + +using GdUnit4; + +// GdUnit4 GDScript - C# API wrapper +public partial class GdUnit4CSharpApi : RefCounted +{ + public static string Version() => GdUnit4MonoAPI.Version(); + + public static bool IsTestSuite(string classPath) => GdUnit4MonoAPI.IsTestSuite(classPath); + + public static RefCounted Executor(Node listener) => (RefCounted)GdUnit4MonoAPI.Executor(listener); + + public static GdUnit4.CsNode? ParseTestSuite(string classPath) => GdUnit4MonoAPI.ParseTestSuite(classPath); + + public static Dictionary CreateTestSuite(string sourcePath, int lineNumber, string testSuitePath) => + GdUnit4MonoAPI.CreateTestSuite(sourcePath, lineNumber, testSuitePath); +} diff --git a/addons/gdUnit4/src/mono/GdUnit4MonoApiLoader.gd b/addons/gdUnit4/src/mono/GdUnit4CSharpApiLoader.gd similarity index 67% rename from addons/gdUnit4/src/mono/GdUnit4MonoApiLoader.gd rename to addons/gdUnit4/src/mono/GdUnit4CSharpApiLoader.gd index 4940d76d..2eff8c96 100644 --- a/addons/gdUnit4/src/mono/GdUnit4MonoApiLoader.gd +++ b/addons/gdUnit4/src/mono/GdUnit4CSharpApiLoader.gd @@ -1,18 +1,17 @@ extends RefCounted -class_name GdUnit4MonoApiLoader +class_name GdUnit4CSharpApiLoader static func instance() -> Object: - return GdUnitSingleton.instance("GdUnit4MonoAPI", func() -> Object: - if not GdUnit4MonoApiLoader.is_mono_supported(): + return GdUnitSingleton.instance("GdUnit4CSharpApi", func() -> Object: + if not GdUnit4CSharpApiLoader.is_mono_supported(): return null - var GdUnit4MonoApi := load("res://addons/gdUnit4/src/mono/GdUnit4MonoApi.cs") - return GdUnit4MonoApi.new() + return load("res://addons/gdUnit4/src/mono/GdUnit4CSharpApi.cs") ) static func is_engine_version_supported(engine_version :int = Engine.get_version_info().hex) -> bool: - return engine_version >= 0x40100 + return engine_version >= 0x40200 # test is Godot mono running @@ -21,14 +20,14 @@ static func is_mono_supported() -> bool: static func version() -> String: - if not GdUnit4MonoApiLoader.is_mono_supported(): + if not GdUnit4CSharpApiLoader.is_mono_supported(): return "unknown" return instance().Version() static func create_test_suite(source_path :String, line_number :int, test_suite_path :String) -> GdUnitResult: - if not GdUnit4MonoApiLoader.is_mono_supported(): - return GdUnitResult.error("Can't create test suite. No c# support found.") + if not GdUnit4CSharpApiLoader.is_mono_supported(): + return GdUnitResult.error("Can't create test suite. No C# support found.") var result := instance().CreateTestSuite(source_path, line_number, test_suite_path) as Dictionary if result.has("error"): return GdUnitResult.error(result.get("error")) @@ -36,8 +35,9 @@ static func create_test_suite(source_path :String, line_number :int, test_suite_ static func is_test_suite(resource_path :String) -> bool: - if not is_csharp_file(resource_path) or not GdUnit4MonoApiLoader.is_mono_supported(): + if not is_csharp_file(resource_path) or not GdUnit4CSharpApiLoader.is_mono_supported(): return false + if resource_path.is_empty(): if GdUnitSettings.is_report_push_errors(): push_error("Can't create test suite. Missing resource path.") @@ -46,7 +46,7 @@ static func is_test_suite(resource_path :String) -> bool: static func parse_test_suite(source_path :String) -> Node: - if not GdUnit4MonoApiLoader.is_mono_supported(): + if not GdUnit4CSharpApiLoader.is_mono_supported(): if GdUnitSettings.is_report_push_errors(): push_error("Can't create test suite. No c# support found.") return null @@ -54,11 +54,11 @@ static func parse_test_suite(source_path :String) -> Node: static func create_executor(listener :Node) -> RefCounted: - if not GdUnit4MonoApiLoader.is_mono_supported(): + if not GdUnit4CSharpApiLoader.is_mono_supported(): return null return instance().Executor(listener) static func is_csharp_file(resource_path :String) -> bool: var ext := resource_path.get_extension() - return ext == "cs" and GdUnit4MonoApiLoader.is_mono_supported() + return ext == "cs" and GdUnit4CSharpApiLoader.is_mono_supported() diff --git a/addons/gdUnit4/src/mono/GdUnit4MonoApi.cs b/addons/gdUnit4/src/mono/GdUnit4MonoApi.cs deleted file mode 100644 index 0563ef92..00000000 --- a/addons/gdUnit4/src/mono/GdUnit4MonoApi.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Godot; -using Godot.Collections; - -// GdUnit4 C# API wrapper -public partial class GdUnit4MonoApi : GdUnit4.GdUnit4MonoAPI -{ - public new string Version() => GdUnit4.GdUnit4MonoAPI.Version(); - - public new bool IsTestSuite(string classPath) => GdUnit4.GdUnit4MonoAPI.IsTestSuite(classPath); - - public new RefCounted Executor(Node listener) => (RefCounted)GdUnit4.GdUnit4MonoAPI.Executor(listener); - - public new GdUnit4.CsNode? ParseTestSuite(string classPath) => GdUnit4.GdUnit4MonoAPI.ParseTestSuite(classPath); - - public new Dictionary CreateTestSuite(string sourcePath, int lineNumber, string testSuitePath) => - GdUnit4.GdUnit4MonoAPI.CreateTestSuite(sourcePath, lineNumber, testSuitePath); -} diff --git a/addons/gdUnit4/test/GdUnitScriptTypeTest.gd b/addons/gdUnit4/test/GdUnitScriptTypeTest.gd index f67a1601..39943f9d 100644 --- a/addons/gdUnit4/test/GdUnitScriptTypeTest.gd +++ b/addons/gdUnit4/test/GdUnitScriptTypeTest.gd @@ -10,7 +10,7 @@ const __source = 'res://addons/gdUnit4/src/core/GdUnitScriptType.gd' func test_type_of() -> void: assert_str(GdUnitScriptType.type_of(null)).is_equal(GdUnitScriptType.UNKNOWN) assert_str(GdUnitScriptType.type_of(ClassDB.instantiate("GDScript"))).is_equal(GdUnitScriptType.GD) - #if GdUnit4MonoApiLoader.is_mono_supported(): + #if GdUnit4CSharpApiLoader.is_mono_supported(): # assert_str(GdUnitScriptType.type_of(ClassDB.instantiate("CSharpScript"))).is_equal(GdUnitScriptType.CS) #assert_str(GdUnitScriptType.type_of(ClassDB.instantiate("VisualScript"))).is_equal(GdUnitScriptType.VS) #assert_str(GdUnitScriptType.type_of(ClassDB.instantiate("NativeScript"))).is_equal(GdUnitScriptType.NATIVE) diff --git a/addons/gdUnit4/test/GdUnitTestResourceLoader.gd b/addons/gdUnit4/test/GdUnitTestResourceLoader.gd index 57027216..665c1eed 100644 --- a/addons/gdUnit4/test/GdUnitTestResourceLoader.gd +++ b/addons/gdUnit4/test/GdUnitTestResourceLoader.gd @@ -32,7 +32,7 @@ static func load_test_suite_gd(resource_path :String) -> GdUnitTestSuite: static func load_test_suite_cs(resource_path :String) -> Node: - if not GdUnit4MonoApiLoader.is_mono_supported(): + if not GdUnit4CSharpApiLoader.is_mono_supported(): return null var script = ClassDB.instantiate("CSharpScript") script.source_code = GdUnitFileAccess.resource_as_string(resource_path) @@ -42,7 +42,7 @@ static func load_test_suite_cs(resource_path :String) -> Node: static func load_cs_script(resource_path :String, debug_write := false) -> Script: - if not GdUnit4MonoApiLoader.is_mono_supported(): + if not GdUnit4CSharpApiLoader.is_mono_supported(): return null var script = ClassDB.instantiate("CSharpScript") script.source_code = GdUnitFileAccess.resource_as_string(resource_path) diff --git a/addons/gdUnit4/test/mono/GdUnit4MonoApiLoaderTest.gd b/addons/gdUnit4/test/mono/GdUnit4CSharpApiLoaderTest.gd similarity index 62% rename from addons/gdUnit4/test/mono/GdUnit4MonoApiLoaderTest.gd rename to addons/gdUnit4/test/mono/GdUnit4CSharpApiLoaderTest.gd index 38b30ff6..f4b507b4 100644 --- a/addons/gdUnit4/test/mono/GdUnit4MonoApiLoaderTest.gd +++ b/addons/gdUnit4/test/mono/GdUnit4CSharpApiLoaderTest.gd @@ -1,16 +1,16 @@ # GdUnit generated TestSuite #warning-ignore-all:unused_argument #warning-ignore-all:return_value_discarded -class_name GdUnit4MonoApiLoaderTest +class_name GdUnit4CSharpApiLoaderTest extends GdUnitTestSuite # TestSuite generated from const GdUnitTools := preload("res://addons/gdUnit4/src/core/GdUnitTools.gd") -const __source = 'res://addons/gdUnit4/src/mono/GdUnit4MonoApiLoader.gd' +const __source = 'res://addons/gdUnit4/src/mono/GdUnit4CSharpApiLoader.gd' @warning_ignore("unused_parameter") -func before(do_skip = not GdUnit4MonoApiLoader.is_mono_supported(), skip_reason = "Do run only for Godot Mono version"): +func before(do_skip = not GdUnit4CSharpApiLoader.is_mono_supported(), skip_reason = "Do run only for Godot Mono version"): pass @@ -19,17 +19,18 @@ func test_is_engine_version_supported(version :int, expected :bool, test_paramet [0x40000, false], [0x40001, false], [0x40002, false], - [0x40100, true], - [0x40101, true], - [0x40102, true], - [0x40100, true], - [0x40200, true]]) -> void: + [0x40100, false], + [0x40101, false], + [0x40102, false], + [0x40100, false], + [0x40200, true], + [0x40201, true]]) -> void: - assert_that(GdUnit4MonoApiLoader.is_engine_version_supported(version)).is_equal(expected) + assert_that(GdUnit4CSharpApiLoader.is_engine_version_supported(version)).is_equal(expected) func test_api_version() -> void: - assert_str(GdUnit4MonoApiLoader.version()).starts_with("4.2") + assert_str(GdUnit4CSharpApiLoader.version()).starts_with("4.2") func test_create_test_suite() -> void: @@ -40,7 +41,7 @@ func test_create_test_suite() -> void: var example_source_cs = result.value() as String var source := load(example_source_cs) var test_suite_path := GdUnitTestSuiteScanner.resolve_test_suite_path(source.resource_path, "test") - result = GdUnit4MonoApiLoader.create_test_suite(source.resource_path, 18, test_suite_path) + result = GdUnit4CSharpApiLoader.create_test_suite(source.resource_path, 18, test_suite_path) assert_result(result).is_success() var info := result.value() as Dictionary @@ -49,7 +50,7 @@ func test_create_test_suite() -> void: func test_parse_test_suite() -> void: - var test_suite := GdUnit4MonoApiLoader.parse_test_suite("res://addons/gdUnit4/test/mono/GdUnit4MonoApiTest.cs") + var test_suite := GdUnit4CSharpApiLoader.parse_test_suite("res://addons/gdUnit4/test/mono/GdUnit4CSharpApiTest.cs") assert_that(test_suite).is_not_null() assert_that(test_suite.get("IsCsTestSuite")).is_true() test_suite.free() @@ -61,10 +62,10 @@ class TestRunListener extends Node: func test_executor() -> void: var listener :TestRunListener = auto_free(TestRunListener.new()) - var executor = GdUnit4MonoApiLoader.create_executor(listener) + var executor = GdUnit4CSharpApiLoader.create_executor(listener) assert_that(executor).is_not_null() - var test_suite := GdUnit4MonoApiLoader.parse_test_suite("res://addons/gdUnit4/test/mono/GdUnit4MonoApiTest.cs") + var test_suite := GdUnit4CSharpApiLoader.parse_test_suite("res://addons/gdUnit4/test/mono/GdUnit4CSharpApiTest.cs") assert_that(executor.IsExecutable(test_suite)).is_true() test_suite.free() diff --git a/addons/gdUnit4/test/mono/GdUnit4CSharpApiTest.cs b/addons/gdUnit4/test/mono/GdUnit4CSharpApiTest.cs new file mode 100644 index 00000000..f2cf34e1 --- /dev/null +++ b/addons/gdUnit4/test/mono/GdUnit4CSharpApiTest.cs @@ -0,0 +1,22 @@ +namespace GdUnit4 +{ + using static Assertions; + + [TestSuite] + public partial class GdUnit4CSharpApiTest + { + + [TestCase] + public void IsTestSuite() + { + AssertThat(GdUnit4CSharpApi.IsTestSuite("res://addons/gdUnit4/src/mono/GdUnit4CSharpApi.cs")).IsFalse(); + AssertThat(GdUnit4CSharpApi.IsTestSuite("res://addons/gdUnit4/test/mono/ExampleTestSuite.cs")).IsTrue(); + } + + [TestCase] + public void GetVersion() + { + AssertThat(GdUnit4CSharpApi.Version()).IsEqual("4.2.0.0"); + } + } +} diff --git a/addons/gdUnit4/test/mono/GdUnit4MonoApiTest.cs b/addons/gdUnit4/test/mono/GdUnit4MonoApiTest.cs deleted file mode 100644 index adb7815d..00000000 --- a/addons/gdUnit4/test/mono/GdUnit4MonoApiTest.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace GdUnit4 -{ - using static Assertions; - - [TestSuite] - public partial class GdUnit4MonoApiTest - { - - [TestCase] - public void IsTestSuite() - { - AssertThat(GdUnit4MonoAPI.IsTestSuite("res://addons/gdUnit4/src/mono/GdUnit4MonoApi.cs")).IsFalse(); - AssertThat(GdUnit4MonoAPI.IsTestSuite("res://addons/gdUnit4/test/mono/ExampleTestSuite.cs")).IsTrue(); - } - - [TestCase] - public void GetVersion() - { - GdUnit4MonoApi api = new GdUnit4MonoApi(); - AssertThat(api.Version()).IsEqual("4.2.0.0"); - } - } -}