diff --git a/.gutconfig.json b/.gutconfig.json
index 6b682b9a..e1455cbb 100644
--- a/.gutconfig.json
+++ b/.gutconfig.json
@@ -3,8 +3,7 @@
"include_subdirs": true,
"dirs": [
- "res://test/unit/",
- "res://test/integration/"
+ "res://test/samples/cs/"
],
"should_exit": true,
"log_level": 3,
diff --git a/Gut.csproj b/Gut.csproj
new file mode 100644
index 00000000..53cc1f18
--- /dev/null
+++ b/Gut.csproj
@@ -0,0 +1,8 @@
+
+
+ net6.0
+ net7.0
+ net8.0
+ true
+
+
\ No newline at end of file
diff --git a/Gut.sln b/Gut.sln
new file mode 100644
index 00000000..a6b04736
--- /dev/null
+++ b/Gut.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gut", "Gut.csproj", "{AED1B5D9-B5A4-4898-9EE6-55B809D51881}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ ExportDebug|Any CPU = ExportDebug|Any CPU
+ ExportRelease|Any CPU = ExportRelease|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AED1B5D9-B5A4-4898-9EE6-55B809D51881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AED1B5D9-B5A4-4898-9EE6-55B809D51881}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AED1B5D9-B5A4-4898-9EE6-55B809D51881}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
+ {AED1B5D9-B5A4-4898-9EE6-55B809D51881}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
+ {AED1B5D9-B5A4-4898-9EE6-55B809D51881}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
+ {AED1B5D9-B5A4-4898-9EE6-55B809D51881}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/addons/gut/CSharpScriptInspector.cs b/addons/gut/CSharpScriptInspector.cs
new file mode 100644
index 00000000..f1c5943a
--- /dev/null
+++ b/addons/gut/CSharpScriptInspector.cs
@@ -0,0 +1,68 @@
+using Godot;
+using System;
+using System.Reflection;
+
+// namespace GutCSharp
+// {
+ ///
+ /// Utility class to handle inspection of C# scripts for the GUT testing framework.
+ /// This provides reflection-based methods that help GUT understand C# class inheritance.
+ ///
+ public partial class CSharpScriptInspector : RefCounted
+ {
+ ///
+ /// Checks if a C# type inherits from GutTest
+ ///
+ /// The Type to check
+ /// True if the type inherits from GutTest
+ private bool TypeInheritsFromGutTest(Type type)
+ {
+ if (type == null)
+ return false;
+
+ // If this is the GutTest class itself (base case for successful inheritance)
+ if (type.FullName == "GutCSharp.GutTest")
+ {
+ GD.Print("FULL NAME: ", type.FullName);
+ return true;
+ }
+
+ // Check the base type
+ return TypeInheritsFromGutTest(type.BaseType);
+ }
+
+ ///
+ /// Determines if a CSharpScript inherits from GutTest
+ ///
+ /// The CSharpScript to check
+ /// True if the script inherits from GutTest
+ public bool InheritsFromTest(CSharpScript script)
+ {
+
+ if (script == null)
+ return false;
+ Variant instance = script.New();
+ var tryCast = instance.As();
+
+ return tryCast != null;
+ }
+
+ ///
+ /// Determines if an object instance inherits from GutTest
+ ///
+ /// The object instance to check
+ /// True if the object inherits from GutTest
+ public bool InheritsFromTest(object instance)
+ {
+
+ GD.Print("here");
+
+
+ if (instance == null)
+ return false;
+
+
+ return TypeInheritsFromGutTest(instance.GetType());
+ }
+ }
+// }
diff --git a/addons/gut/GutRunner.cs b/addons/gut/GutRunner.cs
new file mode 100644
index 00000000..eaae9759
--- /dev/null
+++ b/addons/gut/GutRunner.cs
@@ -0,0 +1,67 @@
+using Godot;
+using System;
+using System.Reflection;
+using System.Collections.Generic;
+
+namespace GutCSharp
+{
+ public partial class GutCSharpRunner : RefCounted
+ {
+ private Node _gut;
+
+ public GutCSharpRunner(Node gut)
+ {
+ _gut = gut;
+ }
+
+ public void RunTests(string scriptPath)
+ {
+ // Load the C# script/class
+ var script = GD.Load(scriptPath);
+ if (script == null) return;
+
+ var instance = script.New().As();
+ if (instance == null) return;
+
+ instance.gut = _gut;
+
+ // Get all methods from the instance
+ Type type = instance.GetType();
+ MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
+
+ // Filter for test methods (prefixed with "Test")
+ List testMethods = new List();
+ foreach (var method in methods)
+ {
+ if (method.Name.StartsWith("Test") && method.GetParameters().Length == 0)
+ {
+ testMethods.Add(method);
+ }
+ }
+
+ // Run lifecycle and test methods
+ try
+ {
+ instance.BeforeAll();
+
+ foreach (var testMethod in testMethods)
+ {
+ string testName = testMethod.Name;
+ _gut.Call("_pre_run_test", testName);
+
+ instance.BeforeEach();
+ testMethod.Invoke(instance, null);
+ instance.AfterEach();
+
+ _gut.Call("_post_run_test");
+ }
+
+ instance.AfterAll();
+ }
+ catch (Exception e)
+ {
+ _gut.Call("_fail", "Error in test: " + e.Message);
+ }
+ }
+ }
+}
diff --git a/addons/gut/GutTest.cs b/addons/gut/GutTest.cs
new file mode 100644
index 00000000..4768f9ee
--- /dev/null
+++ b/addons/gut/GutTest.cs
@@ -0,0 +1,162 @@
+using Godot;
+using System;
+using System.Reflection;
+
+// namespace GutCSharp
+// {
+ public partial class GutTest : Godot.Node
+ {
+ // Public property that proxies to _gdGutTest
+ public Node gut
+ {
+ get
+ {
+ if (_gdGutTest != null)
+ {
+ return (Node)_gdGutTest.Get("gut");
+ }
+ return null;
+ }
+ set
+ {
+ if (_gdGutTest != null)
+ {
+ _gdGutTest.Set("gut", value);
+ }
+ }
+ }
+
+ // Reference to GDScript GutTest instance that will handle the actual implementation
+ private Node _gdGutTest;
+
+ // Flag to track if ready was called
+ public bool _was_ready_called
+ {
+ get
+ {
+ if (_gdGutTest != null)
+ {
+ return (bool)_gdGutTest.Get("_was_ready_called");
+ }
+ return false;
+ }
+ }
+
+ // Constructor - creates the GDScript GutTest instance
+ public GutTest()
+ {
+ // Load the GDScript GutTest scene/script
+ var gdTestScript = GD.Load