From 2c9e6805a9b8876769a5c81a15b7b35e0a4cf268 Mon Sep 17 00:00:00 2001 From: iisaev Date: Thu, 29 Oct 2026 13:21:41 +0100 Subject: [PATCH] Quit test drivers through ApplicationExit and free test resources Adds tests for freeing the temporary ext_resource sub-scene instance; the animated foreground tests dispose their frame textures. --- .../autoplay/src/DialogAutoDriverNode.cs | 2 +- test_suites/doc_shots/src/DocShotsDriver.cs | 2 +- test_suites/gdscript/src/GdscriptTest.cs | 2 +- tests/ActionAnimatedForegroundTests.cs | 11 ++-- tests/ExtResourcePropertyResolverTests.cs | 52 +++++++++++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 tests/ExtResourcePropertyResolverTests.cs diff --git a/test_suites/autoplay/src/DialogAutoDriverNode.cs b/test_suites/autoplay/src/DialogAutoDriverNode.cs index cb02498..a96c361 100644 --- a/test_suites/autoplay/src/DialogAutoDriverNode.cs +++ b/test_suites/autoplay/src/DialogAutoDriverNode.cs @@ -193,7 +193,7 @@ namespace Mods.TestRunner if (reason != null) GameLogger.Log("TEST", $"DialogAutoDriverNode: {reason}"); GameLogger.Log("TEST", $"[TEST_RESULT] name={ResultName} passed={passed} failed={failed}"); - GetTree().Quit(failed == 0 ? 0 : 1); + Cthangover.Core.Bootstrap.ApplicationExit.Quit(GetTree(), failed == 0 ? 0 : 1); } } } diff --git a/test_suites/doc_shots/src/DocShotsDriver.cs b/test_suites/doc_shots/src/DocShotsDriver.cs index fd013d8..683f6b6 100644 --- a/test_suites/doc_shots/src/DocShotsDriver.cs +++ b/test_suites/doc_shots/src/DocShotsDriver.cs @@ -409,7 +409,7 @@ namespace Cthangover.Mods.Dialog.DocShots { index = -1; GameLogger.Log("TEST", $"[TEST_RESULT] name=doc_shots passed={passed} failed={failures.Count}"); - GetTree().Quit(failures.Count == 0 ? 0 : 1); + Cthangover.Core.Bootstrap.ApplicationExit.Quit(GetTree(), failures.Count == 0 ? 0 : 1); } } } diff --git a/test_suites/gdscript/src/GdscriptTest.cs b/test_suites/gdscript/src/GdscriptTest.cs index 37ec93a..8de1bf1 100644 --- a/test_suites/gdscript/src/GdscriptTest.cs +++ b/test_suites/gdscript/src/GdscriptTest.cs @@ -123,7 +123,7 @@ namespace Mods.DialogBase.Tests { done = true; GameLogger.Log("TEST", $"[TEST_RESULT] name={ResultName} passed={passed} failed={failed}"); - GetTree().Quit(failed == 0 ? 0 : 1); + Cthangover.Core.Bootstrap.ApplicationExit.Quit(GetTree(), failed == 0 ? 0 : 1); } } } diff --git a/tests/ActionAnimatedForegroundTests.cs b/tests/ActionAnimatedForegroundTests.cs index 47dcb55..3bc250c 100644 --- a/tests/ActionAnimatedForegroundTests.cs +++ b/tests/ActionAnimatedForegroundTests.cs @@ -19,9 +19,9 @@ namespace Cthangover.Mods.Dialog.Tests var stage = await DialogStage.Create(); var view = stage.AddViewBox(); await DialogStage.Frames(1); + var frames = Frames(3); try { - var frames = Frames(3); var anim = new ActionAnimatedForeground { Textures = frames, Speed = 20f, NextFrameSpeed = 20f, IsLoop = false }; var dlg = new DialogQueue(); dlg.Queue.Add(anim); @@ -38,6 +38,7 @@ namespace Cthangover.Mods.Dialog.Tests finally { stage.Free(); + foreach (var texture in frames) texture.Dispose(); } } @@ -47,9 +48,9 @@ namespace Cthangover.Mods.Dialog.Tests var stage = await DialogStage.Create(); var view = stage.AddViewBox(); await DialogStage.Frames(1); + var frames = Frames(2); try { - var frames = Frames(2); var anim = new ActionAnimatedForeground { Textures = frames, Speed = 20f, NextFrameSpeed = 20f, IsLoop = true }; var dlg = new DialogQueue(); dlg.Queue.Add(anim); @@ -68,6 +69,7 @@ namespace Cthangover.Mods.Dialog.Tests finally { stage.Free(); + foreach (var texture in frames) texture.Dispose(); } } @@ -75,7 +77,10 @@ namespace Cthangover.Mods.Dialog.Tests { var list = new List(); for (var i = 0; i < count; i++) - list.Add(ImageTexture.CreateFromImage(Image.CreateEmpty(2, 2, false, Image.Format.Rgba8))); + { + using var image = Image.CreateEmpty(2, 2, false, Image.Format.Rgba8); + list.Add(ImageTexture.CreateFromImage(image)); + } return list; } } diff --git a/tests/ExtResourcePropertyResolverTests.cs b/tests/ExtResourcePropertyResolverTests.cs new file mode 100644 index 0000000..1bf2f14 --- /dev/null +++ b/tests/ExtResourcePropertyResolverTests.cs @@ -0,0 +1,52 @@ +namespace Cthangover.Mods.Dialog.Tests +{ + using Cthangover.Core.Mods.Testing; + using Cthangover.Core.Scenes.TscnBuild; + using Cthangover.Core.Scenes.TscnBuild.PropertyResolvers; + using Cthangover.Core.Scenes.TscnParsing; + using Cthangover.Mods.Interface.View; + using Godot; + + /// Packing a nested prefab must release the temporary tree while preserving its children in the packed result. + public class ExtResourcePropertyResolverTests + { + private static Node temporary; + + [ModTest("prefabs/packing_releases_the_temporary_tree")] + static void PackingReleasesTemporaryTree(ModTestContext ctx) + { + var target = new DialogBox(); + try + { + var scene = new ParsedScene(); + scene.ExtResources.Add(new ExtResourceRef { Id = "nested", Type = "PackedScene", Path = "test_nested.tscn" }); + var context = new PropertyContext(scene, CreateTemporary, null); + new ExtResourcePropertyResolver().Apply(target, "answerBoxScene", TscnPropertyValue.FromExtResource("nested"), context); + ModAssert.False(GodotObject.IsInstanceValid(temporary), "packing frees its input instance immediately"); + using var packed = target.Get("answerBoxScene").AsGodotObject() as PackedScene; + ModAssert.NotNull(packed, "the target retains the packed prefab"); + var instance = packed.Instantiate(); + try + { + ModAssert.Equal("PackedRoot", instance.Name.ToString(), "packed root survives freeing the temporary tree"); + ModAssert.Equal(1, instance.GetChildCount(), "packed child is retained"); + ModAssert.Equal("PackedChild", instance.GetChild(0).Name.ToString(), "child owners were assigned before packing"); + } + finally { instance.Free(); } + } + finally + { + target.Free(); + if (GodotObject.IsInstanceValid(temporary)) temporary.Free(); + temporary = null; + } + } + + private static Node CreateTemporary(string path) + { + temporary = new Control { Name = "PackedRoot" }; + temporary.AddChild(new Label { Name = "PackedChild", Text = "nested prefab" }); + return temporary; + } + } +}