From a253e01dbd7b925869bd66c3ae482c9a909c96cd Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 31 Dec 2022 00:21:28 +0100 Subject: [PATCH] Add unit test for scripting event to ensure generated bindings code works fine --- Source/Engine/Tests/TestScripting.cpp | 32 ++++++++++- Source/Engine/Tests/TestScripting.cs | 79 ++++++++++++++++++++++++++- Source/Engine/Tests/TestScripting.h | 22 +++++++- 3 files changed, 128 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Tests/TestScripting.cpp b/Source/Engine/Tests/TestScripting.cpp index ecea80db7..958bb8d8d 100644 --- a/Source/Engine/Tests/TestScripting.cpp +++ b/Source/Engine/Tests/TestScripting.cpp @@ -21,7 +21,9 @@ TEST_CASE("Scripting") CHECK(object->Is()); TestClassNative* testClass = (TestClassNative*)object; CHECK(testClass->SimpleField == 1); - int32 methodResult = testClass->Test(TEXT("123")); + CHECK(testClass->SimpleStruct.Object == nullptr); + CHECK(testClass->SimpleStruct.Vector == Float3::One); + int32 methodResult = testClass->TestMethod(TEXT("123")); CHECK(methodResult == 3); // Test managed class @@ -34,7 +36,33 @@ TEST_CASE("Scripting") MObject* managed = testClass->GetOrCreateManagedInstance(); // Ensure to create C# object and run it's ctor CHECK(managed); CHECK(testClass->SimpleField == 2); - methodResult = testClass->Test(TEXT("123")); + CHECK(testClass->SimpleStruct.Object == testClass); + CHECK(testClass->SimpleStruct.Vector == Float3::UnitX); + methodResult = testClass->TestMethod(TEXT("123")); CHECK(methodResult == 6); } + + SECTION("Test Event") + { + ScriptingTypeHandle type = Scripting::FindScriptingType("FlaxEngine.TestClassManaged"); + CHECK(type); + ScriptingObject* object = Scripting::NewObject(type.GetType().ManagedClass); + CHECK(object); + MObject* managed = object->GetOrCreateManagedInstance(); // Ensure to create C# object and run it's ctor + CHECK(managed); + TestClassNative* testClass = (TestClassNative*)object; + CHECK(testClass->SimpleField == 2); + String str1 = TEXT("1"); + String str2 = TEXT("2"); + Array arr1 = { testClass->SimpleStruct }; + Array arr2 = { testClass->SimpleStruct }; + testClass->SimpleEvent(1, Float3::One, str1, str2, arr1, arr2); + CHECK(testClass->SimpleField == 4); + CHECK(str2 == TEXT("4")); + CHECK(arr2.Count() == 2); + CHECK(arr2[0].Vector == Float3::Half); + CHECK(arr2[0].Object == nullptr); + CHECK(arr2[1].Vector == testClass->SimpleStruct.Vector); + CHECK(arr2[1].Object == testClass); + } } diff --git a/Source/Engine/Tests/TestScripting.cs b/Source/Engine/Tests/TestScripting.cs index 6abc667a1..4f2d9b229 100644 --- a/Source/Engine/Tests/TestScripting.cs +++ b/Source/Engine/Tests/TestScripting.cs @@ -3,6 +3,48 @@ #if FLAX_TESTS namespace FlaxEngine { + partial struct TestStruct : System.IEquatable + { + /// + public static bool operator ==(TestStruct left, TestStruct right) + { + return left.Equals(right); + } + + /// + public static bool operator !=(TestStruct left, TestStruct right) + { + return !left.Equals(right); + } + + /// + public bool Equals(TestStruct other) + { + return Vector.Equals(other.Vector) && Equals(Object, other.Object); + } + + /// + public override bool Equals(object obj) + { + return obj is TestStruct other && Equals(other); + } + + /// + public override int GetHashCode() + { + unchecked + { + return (Vector.GetHashCode() * 397) ^ (Object != null ? Object.GetHashCode() : 0); + } + } + + /// + public override string ToString() + { + return $"Vector={Vector}, Object={Object?.ToString() ?? "null"}"; + } + } + /// /// Test class. /// @@ -10,13 +52,46 @@ namespace FlaxEngine { TestClassManaged() { + // Test setting C++ values from C# SimpleField = 2; + SimpleStruct = new TestStruct + { + Vector = Float3.UnitX, + Object = this, + }; + SimpleEvent += OnSimpleEvent; } /// - public override int Test(string str) + public override int TestMethod(string str) { - return str.Length + base.Test(str); + // Test C++ base method invocation + return str.Length + base.TestMethod(str); + } + + private void OnSimpleEvent(int arg1, Float3 arg2, string arg3, ref string arg4, TestStruct[] arg5, ref TestStruct[] arg6) + { + // Verify that C++ passed proper data to C# via event bindings + if (arg1 == 1 && + arg2 == Float3.One && + arg3 == "1" && + arg4 == "2" && + arg5 != null && arg5.Length == 1 && arg5[0] == SimpleStruct && + arg6 != null && arg6.Length == 1 && arg6[0] == SimpleStruct) + { + // Test passing data back from C# to C++ + SimpleField = 4; + arg4 = "4"; + arg6 = new TestStruct[2] + { + new TestStruct + { + Vector = Float3.Half, + Object = null, + }, + SimpleStruct, + }; + } } } } diff --git a/Source/Engine/Tests/TestScripting.h b/Source/Engine/Tests/TestScripting.h index 06b5dddb5..90996de40 100644 --- a/Source/Engine/Tests/TestScripting.h +++ b/Source/Engine/Tests/TestScripting.h @@ -3,8 +3,22 @@ #pragma once #include "Engine/Core/ISerializable.h" +#include "Engine/Core/Math/Vector3.h" +#include "Engine/Core/Collections/Array.h" #include "Engine/Scripting/ScriptingObject.h" +// Test structure. +API_STRUCT(NoDefault) struct TestStruct : public ISerializable +{ + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_MINIMAL(TestStruct); + + // Var + API_FIELD() Float3 Vector = Float3::One; + // Ref + API_FIELD() ScriptingObject* Object = nullptr; +}; + // Test class. API_CLASS() class TestClassNative : public ScriptingObject, public ISerializable { @@ -15,8 +29,14 @@ public: // Test value API_FIELD() int32 SimpleField = 1; + // Test struct + API_FIELD() TestStruct SimpleStruct; + + // Test event + API_EVENT() Delegate&, Array&> SimpleEvent; + // Test virtual method - API_FUNCTION() virtual int32 Test(const String& str) + API_FUNCTION() virtual int32 TestMethod(const String& str) { return str.Length(); }