Просмотр исходного кода

Added support for managed unit tests and a unit test for managed diff

Marko Pintera 10 лет назад
Родитель
Сommit
fe9db60c5a

+ 1 - 1
MBansheeEditor/DbgCustomInspector.cs

@@ -3,7 +3,7 @@ using BansheeEngine;
 
 namespace BansheeEditor
 {
-    [CustomInspector(typeof(DbgComponent))]
+    [CustomInspector(typeof(Camera))]
     public class DbgCustomInspector : Inspector
     {
         internal override bool Refresh()

+ 2 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -125,6 +125,8 @@
     <Compile Include="Scene\ScaleHandle.cs" />
     <Compile Include="ScriptCompiler.cs" />
     <Compile Include="Selection.cs" />
+    <Compile Include="UnitTests.cs" />
+    <Compile Include="UnitTestTypes.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MBansheeEngine\MBansheeEngine.csproj">

+ 0 - 32
MBansheeEngine/DbgComponent.cs

@@ -1,32 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BansheeEngine
-{
-    public class DbgComponent : Component
-    {
-        public int a;
-        public string b;
-        public DbgSerzObj complex = new DbgSerzObj();
-        public DbgSerzCls complex2 = new DbgSerzCls();
-
-        public int[] arrA;
-        public string[] arrB;
-        public DbgSerzObj[] arrComplex;
-        public DbgSerzCls[] arrComplex2;
-
-        public List<int> listA;
-        public List<string> listB;
-        public List<DbgSerzObj> listComplex;
-        public List<DbgSerzCls> listComplex2;
-
-        public DbgComponent2 otherComponent;
-        public SceneObject otherSO;
-
-        //public int[][][] zeArray;
-        //public List<DbgSerzObj> zeList;
-        //public Dictionary<string, int> zeDict;
-    }
-}

+ 0 - 12
MBansheeEngine/DbgComponent2.cs

@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BansheeEngine
-{
-    public class DbgComponent2 : Component
-    {
-        public int a2;
-    }
-}

+ 0 - 16
MBansheeEngine/DbgSerzCls.cs

@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BansheeEngine
-{
-    [SerializeObject]
-    public class DbgSerzCls
-    {
-        public int someValue2;
-        public string anotherValue2;
-
-        public DbgSerzCls child;
-    }
-}

+ 0 - 20
MBansheeEngine/DbgSerzObj.cs

@@ -1,20 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BansheeEngine
-{
-    [SerializeObject]
-    public struct DbgSerzObj
-    {
-        public DbgSerzObj(int someValue, string anotherValue)
-        {
-            this.someValue = someValue;
-            this.anotherValue = anotherValue;
-        }
-
-        public int someValue;
-        public string anotherValue;
-    }
-}

+ 0 - 4
MBansheeEngine/MBansheeEngine.csproj

@@ -52,10 +52,6 @@
     <Compile Include="Debug.cs" />
     <Compile Include="Color.cs" />
     <Compile Include="Component.cs" />
-    <Compile Include="DbgComponent.cs" />
-    <Compile Include="DbgComponent2.cs" />
-    <Compile Include="DbgSerzCls.cs" />
-    <Compile Include="DbgSerzObj.cs" />
     <Compile Include="DirectoryEx.cs" />
     <Compile Include="DontSerializeField.cs" />
     <Compile Include="FileEx.cs" />

+ 0 - 131
MBansheeEngine/Program.cs

@@ -10,140 +10,9 @@ namespace BansheeEngine
 {
     class Program
     {
-        // TODO: Make this an actual unit test
-        static void UnitTest1_ManagedSerialization()
-        {
-            SceneObject otherSO = new SceneObject("OtherSO");
-            DbgComponent2 dbgComponent2 = otherSO.AddComponent<DbgComponent2>();
-            dbgComponent2.a2 = 33;
-
-            GUIElementStateStyle dbgStyle = new GUIElementStateStyle();
-            SceneObject so = new SceneObject("TestSO");
-            DbgComponent dbgComponent = so.AddComponent<DbgComponent>();
-
-            dbgComponent.a = 5;
-            dbgComponent.b = "SomeTestVal";
-            dbgComponent.complex.someValue = 19;
-            dbgComponent.complex.anotherValue = "AnotherValue";
-            dbgComponent.complex2.someValue2 = 21;
-            dbgComponent.complex2.anotherValue2 = "AnotherValue2";
-
-            dbgComponent.arrA = new int[5];
-            dbgComponent.arrA[4] = 5;
-            dbgComponent.arrB = new string[5];
-            dbgComponent.arrB[4] = "ArrAnotherValue";
-            dbgComponent.arrComplex = new DbgSerzObj[5];
-            dbgComponent.arrComplex[4].someValue = 99;
-            dbgComponent.arrComplex[4].anotherValue = "ArrComplexAnotherValue";
-            dbgComponent.arrComplex2 = new DbgSerzCls[5];
-            dbgComponent.arrComplex2[4] = new DbgSerzCls();
-            dbgComponent.arrComplex2[4].someValue2 = 101;
-            dbgComponent.arrComplex2[4].anotherValue2 = "ArrComplex2AnotherValue";
-
-            dbgComponent.listA = new List<int>();
-            dbgComponent.listA.Add(5);
-            dbgComponent.listB = new List<string>();
-            dbgComponent.listB.Add("ListAnotherValue");
-            dbgComponent.listB.Add(null);
-            dbgComponent.listComplex = new List<DbgSerzObj>();
-            dbgComponent.listComplex.Add(new DbgSerzObj());
-            dbgComponent.listComplex.Add(new DbgSerzObj(99, "ListComplexAnotherValue"));
-            dbgComponent.listComplex2 = new List<DbgSerzCls>();
-            dbgComponent.listComplex2.Add(new DbgSerzCls());
-            dbgComponent.listComplex2[0].someValue2 = 101;
-            dbgComponent.listComplex2[0].anotherValue2 = "ListComplexAnotherValue";
-            dbgComponent.listComplex2.Add(null);
-
-            dbgComponent.otherComponent = dbgComponent2;
-            dbgComponent.otherSO = otherSO;
-
-            //dbgComponent.zeArray = new int[5][][];
-            //dbgComponent.zeList = new List<DbgSerzObj>();
-            //dbgComponent.zeDict = new Dictionary<string, int>();
-
-            //dbgComponent.zeList.Add(new DbgSerzObj());
-            //dbgComponent.zeList.Add(new DbgSerzObj());
-            //dbgComponent.zeList.Add(new DbgSerzObj(101, ""));
-            //dbgComponent.zeList.Add(new DbgSerzObj());
-
-            //dbgComponent.zeDict["supSup"] = 10001;
-            //dbgComponent.zeDict["lolz"] = 696969;
-
-            //var enumerator = dbgComponent.zeDict.GetEnumerator();
-            //int all = 0;
-            //while (enumerator.MoveNext())
-            //{
-            //    all += enumerator.Current.Value;
-            //}
-
-            //for (int i = 0; i < dbgComponent.zeArray.Length; i++)
-            //{
-            //    dbgComponent.zeArray[i] = new int[6][];
-
-            //    for (int j = 0; j < dbgComponent.zeArray[i].Length; j++)
-            //        dbgComponent.zeArray[i][j] = new int[7];
-            //}
-
-            //dbgComponent.zeArray[4][1][3] = 129;
-
-            UnitTest1_GameObjectClone(so);
-
-            System.Diagnostics.Debug.Assert(so.GetNumChildren() == 1);
-
-            for (int i = 0; i < so.GetNumChildren(); i++)
-            {
-                SceneObject childSO = so.GetChild(i);
-
-                DbgComponent otherComponent = childSO.GetComponent<DbgComponent>();
-                System.Diagnostics.Debug.Assert(otherComponent.a == 5);
-                System.Diagnostics.Debug.Assert(otherComponent.b == "SomeTestVal");
-                System.Diagnostics.Debug.Assert(otherComponent.complex.someValue == 19);
-                System.Diagnostics.Debug.Assert(otherComponent.complex2.anotherValue2 == "AnotherValue2");
-
-                System.Diagnostics.Debug.Assert(otherComponent.arrA[4] == 5);
-                System.Diagnostics.Debug.Assert(otherComponent.arrB[4] == "ArrAnotherValue");
-                System.Diagnostics.Debug.Assert(otherComponent.arrComplex[4].someValue == 99);
-                System.Diagnostics.Debug.Assert(otherComponent.arrComplex2[4].anotherValue2 == "ArrComplex2AnotherValue");
-
-                System.Diagnostics.Debug.Assert(otherComponent.listA[0] == 5);
-                System.Diagnostics.Debug.Assert(otherComponent.listB[0] == "ListAnotherValue");
-                System.Diagnostics.Debug.Assert(otherComponent.listComplex[1].someValue == 99);
-                System.Diagnostics.Debug.Assert(otherComponent.listComplex2[0].anotherValue2 == "ListComplexAnotherValue");
-            }
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void UnitTest1_GameObjectClone(SceneObject so);
-
         static void Start()
         {
-            UnitTest1_ManagedSerialization();
-
-            SerializableObject obj = new SerializableObject(typeof(DbgSerzCls), new DbgSerzCls());
-
-            Debug.Log(obj.fields.Length);
-            for (int i = 0; i < obj.fields.Length; i++)
-            {
-                Debug.Log(i + ". " + obj.fields[i].Name + " - " + obj.fields[i].Type.ToString());
-            }
-
-            SerializableProperty prop = obj.fields[0].GetProperty();
-            Debug.Log("Old value: " + prop.GetValue<int>());
-            prop.SetValue<int>(33);
-            Debug.Log("New value: " + prop.GetValue<int>());
 
-            SerializableProperty prop2 = obj.fields[2].GetProperty();
-            Debug.Log("Old value: " + (prop2.GetValue<DbgSerzCls>() == null));
-
-            DbgSerzCls child = new DbgSerzCls();
-            child.anotherValue2 = "ass";
-            prop2.SetValue<DbgSerzCls>(child);
-
-            if (prop2.GetValue<DbgSerzCls>() == null)
-                Debug.Log("New value: null");
-            else
-                Debug.Log("New value: " + prop2.GetValue<DbgSerzCls>().anotherValue2);
         }
-
     }
 }

+ 16 - 0
SBansheeEditor/Include/BsScriptEditorTestSuite.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsTestSuite.h"
+
+namespace BansheeEngine
+{
+	class ScriptEditorTestSuite : public TestSuite
+	{
+	public:
+		ScriptEditorTestSuite();
+
+	private:
+		void runManagedTests();
+	};
+}

+ 24 - 0
SBansheeEditor/Include/BsScriptUnitTests.h

@@ -0,0 +1,24 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BED_EXPORT ScriptUnitTests : public ScriptObject <ScriptUnitTests>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "UnitTests")
+
+		static void runTests();
+
+	private:
+		static void internal_UT1_GameObjectClone(MonoObject* instance);
+		static void internal_UT3_GenerateDiff(MonoObject* oldObj, MonoObject* newObj);
+		static void internal_UT3_ApplyDiff(MonoObject* obj);
+
+		static MonoMethod* RunTestsMethod;
+
+		static SPtr<ManagedSerializableDiff> tempDiff;
+	};
+}

+ 4 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -241,6 +241,7 @@
     <ClInclude Include="Include\BsScriptCodeEditor.h" />
     <ClInclude Include="Include\BsScriptDragDropManager.h" />
     <ClInclude Include="Include\BsScriptDropDownWindow.h" />
+    <ClInclude Include="Include\BsScriptEditorTestSuite.h" />
     <ClInclude Include="Include\BsScriptFolderMonitor.h" />
     <ClInclude Include="Include\BsScriptGUISceneTreeView.h" />
     <ClInclude Include="Include\BsScriptOSDropTarget.h" />
@@ -277,6 +278,7 @@
     <ClInclude Include="Include\BsScriptProjectLibrary.h" />
     <ClInclude Include="Include\BsScriptSceneViewHandler.h" />
     <ClInclude Include="Include\BsScriptSelection.h" />
+    <ClInclude Include="Include\BsScriptUnitTests.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsMenuItemManager.cpp" />
@@ -288,6 +290,7 @@
     <ClCompile Include="Source\BsGUIResourceField.cpp" />
     <ClCompile Include="Source\BsScriptBrowseDialog.cpp" />
     <ClCompile Include="Source\BsScriptDropDownWindow.cpp" />
+    <ClCompile Include="Source\BsScriptEditorTestSuite.cpp" />
     <ClCompile Include="Source\BsScriptFolderMonitor.cpp" />
     <ClCompile Include="Source\BsScriptGUISceneTreeView.cpp" />
     <ClCompile Include="Source\BsScriptOSDropTarget.cpp" />
@@ -324,6 +327,7 @@
     <ClCompile Include="Source\BsScriptProjectLibrary.cpp" />
     <ClCompile Include="Source\BsScriptSceneViewHandler.cpp" />
     <ClCompile Include="Source\BsScriptSelection.cpp" />
+    <ClCompile Include="Source\BsScriptUnitTests.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 12 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -150,6 +150,12 @@
     <ClInclude Include="Include\BsScriptGUISceneTreeView.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptEditorTestSuite.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptUnitTests.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -287,5 +293,11 @@
     <ClCompile Include="Source\BsScriptGUISceneTreeView.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptEditorTestSuite.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptUnitTests.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 7 - 0
SBansheeEditor/Source/BsEditorScriptManager.cpp

@@ -12,9 +12,11 @@
 #include "BsScriptProjectLibrary.h"
 #include "BsMenuItemManager.h"
 #include "BsScriptFolderMonitor.h"
+#include "BsScriptEditorTestSuite.h"
 #include "BsTime.h"
 #include "BsMath.h"
 #include "BsEditorApplication.h"
+#include <BsTestOutput.h>
 
 namespace BansheeEngine
 {
@@ -42,6 +44,11 @@ namespace BansheeEngine
 		// Initial update
 		mLastUpdateTime = gTime().getTime();
 		mUpdateMethod->invoke(nullptr, nullptr);
+
+		// Run tests
+		TestSuitePtr testSuite = TestSuite::create<ScriptEditorTestSuite>();
+		ExceptionTestOutput testOutput;
+		testSuite->run(testOutput);
 	}
 
 	EditorScriptManager::~EditorScriptManager()

+ 15 - 0
SBansheeEditor/Source/BsScriptEditorTestSuite.cpp

@@ -0,0 +1,15 @@
+#include "BsScriptEditorTestSuite.h"
+#include "BsScriptUnitTests.h"
+
+namespace BansheeEngine
+{
+	ScriptEditorTestSuite::ScriptEditorTestSuite()
+	{
+		BS_ADD_TEST(ScriptEditorTestSuite::runManagedTests);
+	}
+
+	void ScriptEditorTestSuite::runManagedTests()
+	{
+		ScriptUnitTests::runTests();
+	}
+}

+ 54 - 0
SBansheeEditor/Source/BsScriptUnitTests.cpp

@@ -0,0 +1,54 @@
+#include "BsScriptUnitTests.h"
+#include "BsScriptMeta.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsSceneObject.h"
+#include "BsScriptSceneObject.h"
+#include "BsManagedSerializableObject.h"
+#include "BsManagedSerializableDiff.h"
+
+namespace BansheeEngine
+{
+	MonoMethod* ScriptUnitTests::RunTestsMethod;
+	SPtr<ManagedSerializableDiff> ScriptUnitTests::tempDiff;
+
+	void ScriptUnitTests::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_UT1_GameObjectClone", &ScriptUnitTests::internal_UT1_GameObjectClone);
+		metaData.scriptClass->addInternalCall("Internal_UT3_GenerateDiff", &ScriptUnitTests::internal_UT3_GenerateDiff);
+		metaData.scriptClass->addInternalCall("Internal_UT3_ApplyDiff", &ScriptUnitTests::internal_UT3_ApplyDiff);
+
+		RunTestsMethod = metaData.scriptClass->getMethod("RunTests");
+	}
+
+	void ScriptUnitTests::runTests()
+	{
+		RunTestsMethod->invoke(nullptr, nullptr);
+	}
+
+	void ScriptUnitTests::internal_UT1_GameObjectClone(MonoObject* instance)
+	{
+		ScriptSceneObject* nativeInstance = ScriptSceneObject::toNative(instance);
+
+		HSceneObject SO = static_object_cast<SceneObject>(nativeInstance->getNativeHandle());
+		HSceneObject cloneSO = SO->clone();
+
+		cloneSO->setParent(SO);
+	}
+
+	void ScriptUnitTests::internal_UT3_GenerateDiff(MonoObject* oldObj, MonoObject* newObj)
+	{
+		ManagedSerializableObjectPtr serializableOldObj = ManagedSerializableObject::createFromExisting(oldObj);
+		ManagedSerializableObjectPtr serializableNewObj = ManagedSerializableObject::createFromExisting(oldObj);
+
+		tempDiff = ManagedSerializableDiff::create(serializableOldObj, serializableNewObj);
+	}
+
+	void ScriptUnitTests::internal_UT3_ApplyDiff(MonoObject* obj)
+	{
+		ManagedSerializableObjectPtr serializableObj = ManagedSerializableObject::createFromExisting(obj);
+		tempDiff->apply(serializableObj);
+
+		tempDiff = nullptr;
+	}
+}

+ 0 - 19
SBansheeEngine/Source/BsScriptEnginePlugin.cpp

@@ -11,24 +11,8 @@
 #include "BsScriptObjectManager.h"
 #include "BsApplication.h"
 
-// DEBUG ONLY
-#include "BsScriptSceneObject.h"
-#include "BsSceneObject.h"
-#include "BsMonoUtil.h"
-#include "BsMonoMethod.h"
-
 namespace BansheeEngine
 {
-	void unitTest1_GameObjectClone(MonoObject* instance)
-	{
-		ScriptSceneObject* nativeInstance = ScriptSceneObject::toNative(instance);
-
-		HSceneObject SO = static_object_cast<SceneObject>(nativeInstance->getNativeHandle());
-		HSceneObject cloneSO = SO->clone();
-
-		cloneSO->setParent(SO);
-	}
-
 	extern "C" BS_SCR_BE_EXPORT const String& getPluginName()
 	{
 		static String pluginName = "SBansheeEngine";
@@ -44,9 +28,6 @@ namespace BansheeEngine
 
 		// TODO - Load Game assembly (gApplication().getGameAssemblyPath())
 
-		// DEBUG ONLY
-		mono_add_internal_call("BansheeEngine.Program::UnitTest1_GameObjectClone", &unitTest1_GameObjectClone);
-
 		ScriptObjectManager::startUp();
 		ManagedResourceManager::startUp();
 		ScriptAssemblyManager::startUp();

+ 14 - 8
TODO.txt

@@ -32,17 +32,23 @@ IMMEDIATE:
  - Create a unit test for managed diff
  - Consider cleaning up ManagedSerializableDiff by moving the smaller classes to a different file
 
+Consider adding prefab support without diffs first (add dummy methods in place)
+ - This might make it easier to understand how will it all fit together
+
 See "Prefabs" gdoc for later goals
 See "Brainstorm" gdoc for ideas about how to solve the ID issue (and see below)
 
-When deserializing diffs do I need to turn on GameObjectManager?
- - Since some could be refrencing scene objects or components whose IDs changed...
- - See ManagedSerializableObjectRTTI
- - THIS IS ANOTHER reason I need to use the new IDs when comparing Game Object handles.
-    e.g. if a game object handle points into a child prefab instance then when I'm comparing a field containing that handle to the original
-    it must have the same ID unless the user manually changed the field value. This won't be true with the current system as that game
-    object will have a different ID each level load (and a different ID compared to its Prefab).
-	  - I will likely need to be able to provide a custom compare method for fields containing GameObjectHandles
+When deserializing diffs I need to turn on GameObjectManager
+ - Since diffs should be part of HSceneObject it should already be active but it is something to pay attention for
+
+GameObjectHandle compare in managed serializable diff won't work for prefabs (will have the same problem for native diff)
+ - Handle comparison compares instanceIDs which will be different between prefab and its instance
+ - Best solution is probably to add a flag that tells the diff system how to deal with game object handles
+   (i.e. compare using instance IDs or use the prefab link IDs)
+
+When I'm saving a prefab instance I need to generate the diff, therefore I need to load the prefab (ManagedSerializable stuff automatically created managed instance on load)
+ - Will there be problems if I load the prefab objects? (e.g. a renderable, or some object might trigger some action on load)
+  - It MIGHT be better to be able to load compare the serialized data, without actually instantiating any objects
 
 ----------------------------------------------------------------------
 Polish stage 1