diff --git a/Assets/Mirror/Tests.meta b/Assets/Mirror/Tests.meta
new file mode 100644
index 000000000..a519cf7ae
--- /dev/null
+++ b/Assets/Mirror/Tests.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4de157ac7e1594c758ce6dc401674f5c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common.meta b/Assets/Mirror/Tests/Common.meta
new file mode 100644
index 000000000..cb52e9878
--- /dev/null
+++ b/Assets/Mirror/Tests/Common.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dd4f310377c5a4ad39bd31546c95c2a2
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/Castle.Core.dll b/Assets/Mirror/Tests/Common/Castle.Core.dll
new file mode 100644
index 000000000..dbc4b29de
Binary files /dev/null and b/Assets/Mirror/Tests/Common/Castle.Core.dll differ
diff --git a/Assets/Mirror/Tests/Common/Castle.Core.dll.meta b/Assets/Mirror/Tests/Common/Castle.Core.dll.meta
new file mode 100644
index 000000000..5189874d6
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/Castle.Core.dll.meta
@@ -0,0 +1,112 @@
+fileFormatVersion: 2
+guid: 739a02265856e4e4b8a3ae587a908479
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ '': Any
+ second:
+ enabled: 0
+ settings:
+ Exclude Android: 1
+ Exclude Editor: 0
+ Exclude Linux: 1
+ Exclude Linux64: 1
+ Exclude LinuxUniversal: 1
+ Exclude OSXUniversal: 1
+ Exclude WebGL: 1
+ Exclude Win: 1
+ Exclude Win64: 1
+ Exclude iOS: 1
+ - first:
+ Android: Android
+ second:
+ enabled: 0
+ settings:
+ CPU: ARMv7
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ DefaultValueInitialized: true
+ OS: AnyOS
+ - first:
+ Facebook: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Facebook: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Linux
+ second:
+ enabled: 0
+ settings:
+ CPU: x86
+ - first:
+ Standalone: Linux64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: LinuxUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Windows Store Apps: WindowsStoreApps
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 0
+ settings:
+ AddToEmbeddedBinaries: false
+ CompileFlags:
+ FrameworkDependencies:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs b/Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs
new file mode 100644
index 000000000..2d4a1634e
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs
@@ -0,0 +1,62 @@
+using System;
+using NUnit.Framework;
+using UnityEditor;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+
+ ///
+ /// Used by both runtime and edit time tests
+ ///
+ [TestFixture]
+ public abstract class ClientSceneTestsBase : MirrorEditModeTest
+ {
+ // use guid to find asset so that the path does not matter
+ protected const string ValidPrefabAssetGuid = "33169286da0313d45ab5bfccc6cf3775";
+ protected const string PrefabWithChildrenAssetGuid = "a78e009e3f2dee44e8859516974ede43";
+ protected const string InvalidPrefabAssetGuid = "78f0a3f755d35324e959f3ecdd993fb0";
+ // random guid, not used anywhere
+ protected const string AnotherGuidString = "5794128cdfda04542985151f82990d05";
+
+ protected GameObject validPrefab;
+ protected NetworkIdentity validPrefabNetworkIdentity;
+ protected GameObject prefabWithChildren;
+ protected GameObject invalidPrefab;
+ protected Guid validPrefabGuid;
+ protected Guid anotherGuid;
+
+ static GameObject LoadPrefab(string guid)
+ {
+ return AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid));
+ }
+
+ [OneTimeSetUp]
+ public void OneTimeSetUp()
+ {
+ validPrefab = LoadPrefab(ValidPrefabAssetGuid);
+ validPrefabNetworkIdentity = validPrefab.GetComponent();
+ prefabWithChildren = LoadPrefab(PrefabWithChildrenAssetGuid);
+ invalidPrefab = LoadPrefab(InvalidPrefabAssetGuid);
+ validPrefabGuid = new Guid(ValidPrefabAssetGuid);
+ anotherGuid = new Guid(AnotherGuidString);
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ // reset asset id in case they are changed by tests
+ validPrefabNetworkIdentity.assetId = validPrefabGuid;
+
+ base.TearDown();
+ }
+
+ [OneTimeTearDown]
+ public void OneTimeTearDown()
+ {
+ validPrefab = null;
+ prefabWithChildren = null;
+ invalidPrefab = null;
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs.meta b/Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs.meta
new file mode 100644
index 000000000..9be790649
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bf741fb5970e5e048aea5ff3e396d24c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/ClientSceneTests_RegisterPrefabBase.cs b/Assets/Mirror/Tests/Common/ClientSceneTests_RegisterPrefabBase.cs
new file mode 100644
index 000000000..cd7131049
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/ClientSceneTests_RegisterPrefabBase.cs
@@ -0,0 +1,212 @@
+using System;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ ///
+ /// Used by both runtime and edit time tests
+ ///
+ [TestFixture]
+ public abstract class ClientSceneTests_RegisterPrefabBase : ClientSceneTestsBase
+ {
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab, false)]
+ [TestCase(RegisterPrefabOverload.Prefab_NewAssetId, true)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate, false)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId, true)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate, false)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId, true)]
+ public void CheckOverloadWithAssetId(RegisterPrefabOverload overload, bool expected)
+ {
+ // test to make sure OverloadWithAssetId correctly works with flags
+ Assert.That(OverloadWithAssetId(overload), Is.EqualTo(expected));
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab, false)]
+ [TestCase(RegisterPrefabOverload.Prefab_NewAssetId, false)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate, true)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId, true)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate, true)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId, true)]
+ public void CheckOverloadWithHandler(RegisterPrefabOverload overload, bool expected)
+ {
+ // test to make sure OverloadWithHandler correctly works with flags
+ Assert.That(OverloadWithHandler(overload), Is.EqualTo(expected));
+ }
+
+ ///
+ /// Allows TestCases to call different overloads for RegisterPrefab.
+ /// Without this we would need duplicate tests for each overload
+ ///
+ [Flags]
+ public enum RegisterPrefabOverload
+ {
+ Prefab = 1,
+ Prefab_NewAssetId = 2,
+ Prefab_SpawnDelegate = 4,
+ Prefab_SpawnDelegate_NewAssetId = 8,
+ Prefab_SpawnHandlerDelegate = 16,
+ Prefab_SpawnHandlerDelegate_NewAssetId = 32,
+
+ WithAssetId = Prefab_NewAssetId | Prefab_SpawnDelegate_NewAssetId | Prefab_SpawnHandlerDelegate_NewAssetId,
+ WithHandler = Prefab_SpawnDelegate | Prefab_SpawnDelegate_NewAssetId | Prefab_SpawnHandlerDelegate | Prefab_SpawnHandlerDelegate_NewAssetId
+ }
+
+ protected static bool OverloadWithAssetId(RegisterPrefabOverload overload)
+ {
+ return (overload & RegisterPrefabOverload.WithAssetId) != 0;
+ }
+
+ protected static bool OverloadWithHandler(RegisterPrefabOverload overload)
+ {
+ return (overload & RegisterPrefabOverload.WithHandler) != 0;
+ }
+
+ protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload)
+ {
+ SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
+ SpawnHandlerDelegate spawnHandlerDelegate = new SpawnHandlerDelegate(x => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ switch (overload)
+ {
+ case RegisterPrefabOverload.Prefab:
+ NetworkClient.RegisterPrefab(prefab);
+ break;
+ case RegisterPrefabOverload.Prefab_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, anotherGuid);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnDelegate:
+ NetworkClient.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandler, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
+ NetworkClient.RegisterPrefab(prefab, spawnHandlerDelegate, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandlerDelegate, unspawnHandler);
+ break;
+
+ default:
+ Debug.LogError("Overload not found");
+ break;
+ }
+ }
+
+ protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload, Guid guid)
+ {
+ SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
+ SpawnHandlerDelegate spawnHandlerDelegate = new SpawnHandlerDelegate(x => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ switch (overload)
+ {
+ case RegisterPrefabOverload.Prefab_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, guid);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, guid, spawnHandler, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, guid, spawnHandlerDelegate, unspawnHandler);
+ break;
+
+ case RegisterPrefabOverload.Prefab:
+ case RegisterPrefabOverload.Prefab_SpawnDelegate:
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
+ Debug.LogError("Overload did not have guid parameter");
+ break;
+ default:
+ Debug.LogError("Overload not found");
+ break;
+ }
+ }
+
+ protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload, SpawnDelegate spawnHandler)
+ {
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ switch (overload)
+ {
+ case RegisterPrefabOverload.Prefab_SpawnDelegate:
+ NetworkClient.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandler, unspawnHandler);
+ break;
+
+ case RegisterPrefabOverload.Prefab:
+ case RegisterPrefabOverload.Prefab_NewAssetId:
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
+ Debug.LogError("Overload did not have SpawnDelegate parameter");
+ break;
+ default:
+ Debug.LogError("Overload not found");
+ break;
+ }
+ }
+
+ protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload, SpawnHandlerDelegate spawnHandlerDelegate)
+ {
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ switch (overload)
+ {
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
+ NetworkClient.RegisterPrefab(prefab, spawnHandlerDelegate, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandlerDelegate, unspawnHandler);
+ break;
+
+ case RegisterPrefabOverload.Prefab:
+ case RegisterPrefabOverload.Prefab_NewAssetId:
+ case RegisterPrefabOverload.Prefab_SpawnDelegate:
+ case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
+ Debug.LogError("Overload did not have SpawnHandlerDelegate parameter");
+ break;
+ default:
+ Debug.LogError("Overload not found");
+ break;
+ }
+ }
+
+ protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload, UnSpawnDelegate unspawnHandler)
+ {
+ SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
+ SpawnHandlerDelegate spawnHandlerDelegate = new SpawnHandlerDelegate(x => null);
+
+ switch (overload)
+ {
+
+ case RegisterPrefabOverload.Prefab_SpawnDelegate:
+ NetworkClient.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandler, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
+ NetworkClient.RegisterPrefab(prefab, spawnHandlerDelegate, unspawnHandler);
+ break;
+ case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
+ NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandlerDelegate, unspawnHandler);
+ break;
+
+ case RegisterPrefabOverload.Prefab:
+ case RegisterPrefabOverload.Prefab_NewAssetId:
+ Debug.LogError("Overload did not have UnSpawnDelegate parameter");
+ break;
+ default:
+ Debug.LogError("Overload not found");
+ break;
+ }
+ }
+
+ protected Guid GuidForOverload(RegisterPrefabOverload overload) => OverloadWithAssetId(overload) ? anotherGuid : validPrefabGuid;
+ }
+}
diff --git a/Assets/Mirror/Tests/Common/ClientSceneTests_RegisterPrefabBase.cs.meta b/Assets/Mirror/Tests/Common/ClientSceneTests_RegisterPrefabBase.cs.meta
new file mode 100644
index 000000000..8324dc240
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/ClientSceneTests_RegisterPrefabBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8eb53689226946640bc49bb962b13638
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs b/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs
new file mode 100644
index 000000000..58ea0a434
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Mirror.Tests
+{
+ public class FakeNetworkConnection : NetworkConnectionToClient
+ {
+ public FakeNetworkConnection() : base(1) {}
+ public override string address => "Test";
+ public override void Disconnect() {}
+ internal override void Send(ArraySegment segment, int channelId = 0) {}
+ }
+}
diff --git a/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs.meta b/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs.meta
new file mode 100644
index 000000000..129765a98
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/FakeNetworkConnection.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 935b1eb49c500674eaaf88982952a69e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/MemoryTransport.cs b/Assets/Mirror/Tests/Common/MemoryTransport.cs
new file mode 100644
index 000000000..6f0ace3bc
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/MemoryTransport.cs
@@ -0,0 +1,208 @@
+// memory transport for easier testing
+// note: file needs to be outside of Editor folder, otherwise AddComponent
+// can't be called with MemoryTransport
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ public class MemoryTransport : Transport
+ {
+ public enum EventType { Connected, Data, Disconnected }
+ public struct Message
+ {
+ public int connectionId;
+ public EventType eventType;
+ public byte[] data;
+ public Message(int connectionId, EventType eventType, byte[] data)
+ {
+ this.connectionId = connectionId;
+ this.eventType = eventType;
+ this.data = data;
+ }
+ }
+
+ bool clientConnected;
+ public Queue clientIncoming = new Queue();
+ bool serverActive;
+ public Queue serverIncoming = new Queue();
+
+ public override bool Available() => true;
+ // limit max size to something reasonable so pool doesn't allocate
+ // int.MaxValue = 2GB each time.
+ public override int GetMaxPacketSize(int channelId) => ushort.MaxValue;
+ // 1400 max batch size
+ // -> need something != GetMaxPacketSize for testing
+ // -> MTU aka 1400 is used a lot anyway
+ public override int GetBatchThreshold(int channelId) => 1400;
+ public override void Shutdown() {}
+ public override bool ClientConnected() => clientConnected;
+ public override void ClientConnect(string address)
+ {
+ // only if server is running
+ if (serverActive)
+ {
+ // add server connected message with connId=1 because 0 is reserved
+ serverIncoming.Enqueue(new Message(1, EventType.Connected, null));
+
+ // add client connected message
+ clientIncoming.Enqueue(new Message(0, EventType.Connected, null));
+
+ clientConnected = true;
+ }
+ }
+ public override void ClientSend(ArraySegment segment, int channelId)
+ {
+ // only if client connected
+ if (clientConnected)
+ {
+ // a real transport fails for > max sized messages.
+ // mirror checks it, but let's guarantee that we catch > max
+ // sized message send attempts just like a real transport would.
+ // => helps to cover packet size issues i.e. for timestamp
+ // batching tests
+ int max = GetMaxPacketSize(channelId);
+ if (segment.Count > max)
+ throw new Exception($"MemoryTransport ClientSend of {segment.Count} bytes exceeds max of {max} bytes");
+
+ // copy segment data because it's only valid until return
+ byte[] data = new byte[segment.Count];
+ Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count);
+
+ // add server data message with connId=1 because 0 is reserved
+ serverIncoming.Enqueue(new Message(1, EventType.Data, data));
+ }
+ }
+ public override void ClientDisconnect()
+ {
+ // only if client connected
+ if (clientConnected)
+ {
+ // clear all pending messages that we may have received.
+ // over the wire, we wouldn't receive any more pending messages
+ // ether after calling disconnect.
+ clientIncoming.Clear();
+
+ // add server disconnected message with connId=1 because 0 is reserved
+ serverIncoming.Enqueue(new Message(1, EventType.Disconnected, null));
+
+ // add client disconnected message
+ clientIncoming.Enqueue(new Message(0, EventType.Disconnected, null));
+
+ // not connected anymore
+ clientConnected = false;
+ }
+ }
+ // messages should always be processed in early update
+ public override void ClientEarlyUpdate()
+ {
+ // note: process even if not connected because when calling
+ // Disconnect, we add a Disconnected event which still needs to be
+ // processed here.
+ while (clientIncoming.Count > 0)
+ {
+ Message message = clientIncoming.Dequeue();
+ switch (message.eventType)
+ {
+ case EventType.Connected:
+ Debug.Log("MemoryTransport Client Message: Connected");
+ OnClientConnected.Invoke();
+ break;
+ case EventType.Data:
+ Debug.Log($"MemoryTransport Client Message: Data: {BitConverter.ToString(message.data)}");
+ OnClientDataReceived.Invoke(new ArraySegment(message.data), 0);
+ break;
+ case EventType.Disconnected:
+ Debug.Log("MemoryTransport Client Message: Disconnected");
+ OnClientDisconnected.Invoke();
+ break;
+ }
+ }
+ }
+
+ public override bool ServerActive() => serverActive;
+ public override Uri ServerUri() => throw new NotImplementedException();
+ public override void ServerStart() { serverActive = true; }
+ public override void ServerSend(int connectionId, ArraySegment segment, int channelId)
+ {
+ // only if server is running and client is connected
+ if (serverActive && clientConnected)
+ {
+ // a real transport fails for > max sized messages.
+ // mirror checks it, but let's guarantee that we catch > max
+ // sized message send attempts just like a real transport would.
+ // => helps to cover packet size issues i.e. for timestamp
+ // batching tests
+ int max = GetMaxPacketSize(channelId);
+ if (segment.Count > max)
+ throw new Exception($"MemoryTransport ServerSend of {segment.Count} bytes exceeds max of {max} bytes");
+
+ // copy segment data because it's only valid until return
+ byte[] data = new byte[segment.Count];
+ Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count);
+
+ // add client data message
+ clientIncoming.Enqueue(new Message(0, EventType.Data, data));
+ }
+ }
+
+ public override void ServerDisconnect(int connectionId)
+ {
+ // clear all pending messages that we may have received.
+ // over the wire, we wouldn't receive any more pending messages
+ // ether after calling disconnect.
+ serverIncoming.Clear();
+
+ // add client disconnected message with connectionId
+ clientIncoming.Enqueue(new Message(connectionId, EventType.Disconnected, null));
+
+ // add server disconnected message with connectionId
+ serverIncoming.Enqueue(new Message(connectionId, EventType.Disconnected, null));
+
+ // not active anymore
+ serverActive = false;
+ }
+
+ public override string ServerGetClientAddress(int connectionId) => string.Empty;
+ public override void ServerStop()
+ {
+ // clear all pending messages that we may have received.
+ // over the wire, we wouldn't receive any more pending messages
+ // ether after calling stop.
+ serverIncoming.Clear();
+
+ // add client disconnected message
+ clientIncoming.Enqueue(new Message(0, EventType.Disconnected, null));
+
+ // add server disconnected message with connId=1 because 0 is reserved
+ serverIncoming.Enqueue(new Message(1, EventType.Disconnected, null));
+
+ // not active anymore
+ serverActive = false;
+ }
+ // messages should always be processed in early update
+ public override void ServerEarlyUpdate()
+ {
+ while (serverIncoming.Count > 0)
+ {
+ Message message = serverIncoming.Dequeue();
+ switch (message.eventType)
+ {
+ case EventType.Connected:
+ Debug.Log("MemoryTransport Server Message: Connected");
+ OnServerConnected.Invoke(message.connectionId);
+ break;
+ case EventType.Data:
+ Debug.Log($"MemoryTransport Server Message: Data: {BitConverter.ToString(message.data)}");
+ OnServerDataReceived.Invoke(message.connectionId, new ArraySegment(message.data), 0);
+ break;
+ case EventType.Disconnected:
+ Debug.Log("MemoryTransport Server Message: Disconnected");
+ OnServerDisconnected.Invoke(message.connectionId);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Common/MemoryTransport.cs.meta b/Assets/Mirror/Tests/Common/MemoryTransport.cs.meta
new file mode 100644
index 000000000..d624b49ff
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/MemoryTransport.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6131cf1e8a1c14ef5b5253f86f3fc9c9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/Mirror.Tests.Common.asmdef b/Assets/Mirror/Tests/Common/Mirror.Tests.Common.asmdef
new file mode 100644
index 000000000..ca39e3a96
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/Mirror.Tests.Common.asmdef
@@ -0,0 +1,16 @@
+{
+ "name": "Mirror.Tests.Common",
+ "references": [
+ "Mirror"
+ ],
+ "optionalUnityReferences": [
+ "TestAssemblies"
+ ],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": []
+}
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Common/Mirror.Tests.Common.asmdef.meta b/Assets/Mirror/Tests/Common/Mirror.Tests.Common.asmdef.meta
new file mode 100644
index 000000000..e06568a88
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/Mirror.Tests.Common.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4e9aca8a359ab48de906aedbfa1ffe21
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/MirrorEditModeTest.cs b/Assets/Mirror/Tests/Common/MirrorEditModeTest.cs
new file mode 100644
index 000000000..57db52499
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/MirrorEditModeTest.cs
@@ -0,0 +1,14 @@
+// base class for networking tests to make things easier.
+using NUnit.Framework;
+
+namespace Mirror.Tests
+{
+ public abstract class MirrorEditModeTest : MirrorTest
+ {
+ [SetUp]
+ public override void SetUp() => base.SetUp();
+
+ [TearDown]
+ public override void TearDown() => base.TearDown();
+ }
+}
diff --git a/Assets/Mirror/Tests/Common/MirrorEditModeTest.cs.meta b/Assets/Mirror/Tests/Common/MirrorEditModeTest.cs.meta
new file mode 100644
index 000000000..2f51f7e36
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/MirrorEditModeTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a6110480a9c07423290301aedafb2a93
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs b/Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs
new file mode 100644
index 000000000..a63dc836a
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs
@@ -0,0 +1,27 @@
+// base class for networking tests to make things easier.
+using System.Collections;
+using UnityEngine.TestTools;
+
+namespace Mirror.Tests
+{
+ public abstract class MirrorPlayModeTest : MirrorTest
+ {
+ // when overwriting, call it like this:
+ // yield return base.UnitySetUp();
+ [UnitySetUp]
+ public virtual IEnumerator UnitySetUp()
+ {
+ base.SetUp();
+ yield return null;
+ }
+
+ // when overwriting, call it like this:
+ // yield return base.UnityTearDown();
+ [UnityTearDown]
+ public virtual IEnumerator UnityTearDown()
+ {
+ base.TearDown();
+ yield return null;
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs.meta b/Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs.meta
new file mode 100644
index 000000000..5314431b2
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: be3f9e24bcdb748728f846e88eea29f3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/MirrorTest.cs b/Assets/Mirror/Tests/Common/MirrorTest.cs
new file mode 100644
index 000000000..b8b9ccd25
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/MirrorTest.cs
@@ -0,0 +1,557 @@
+// base class for networking tests to make things easier.
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ // inherited by MirrorEditModeTest / MirrorPlayModeTest
+ // to call SetUp/TearDown by [SetUp]/[UnitySetUp] as needed
+ public abstract class MirrorTest
+ {
+ // keep track of networked GameObjects so we don't have to clean them
+ // up manually each time.
+ // CreateNetworked() adds to the list automatically.
+ public List instantiated;
+
+ // we usually need the memory transport
+ public MemoryTransport transport;
+
+ public virtual void SetUp()
+ {
+ instantiated = new List();
+
+ // need a transport to send & receive
+ Transport.activeTransport = transport = new GameObject().AddComponent();
+ }
+
+ public virtual void TearDown()
+ {
+ NetworkClient.Shutdown();
+ NetworkServer.Shutdown();
+
+ // some tests might modify NetworkServer.connections without ever
+ // starting the server.
+ // NetworkServer.Shutdown() only clears connections if it was started.
+ // so let's do it manually for proper test cleanup here.
+ NetworkServer.connections.Clear();
+
+ foreach (GameObject go in instantiated)
+ if (go != null)
+ GameObject.DestroyImmediate(go);
+
+ GameObject.DestroyImmediate(transport.gameObject);
+ Transport.activeTransport = null;
+ }
+
+ // create a tracked GameObject for tests without Networkidentity
+ // add to tracker list if needed (useful for cleanups afterwards)
+ protected void CreateGameObject(out GameObject go)
+ {
+ go = new GameObject();
+ // track
+ instantiated.Add(go);
+ }
+
+ // create GameObject + MonoBehaviour
+ // add to tracker list if needed (useful for cleanups afterwards)
+ protected void CreateGameObject(out GameObject go, out T component)
+ where T : MonoBehaviour
+ {
+ CreateGameObject(out go);
+ component = go.AddComponent();
+ }
+
+ // create GameObject + NetworkIdentity
+ // add to tracker list if needed (useful for cleanups afterwards)
+ protected void CreateNetworked(out GameObject go, out NetworkIdentity identity)
+ {
+ go = new GameObject();
+ identity = go.AddComponent();
+ // Awake is only called in play mode.
+ // call manually for initialization.
+ identity.Awake();
+ // track
+ instantiated.Add(go);
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour
+ // add to tracker list if needed (useful for cleanups afterwards)
+ protected void CreateNetworked(out GameObject go, out NetworkIdentity identity, out T component)
+ where T : NetworkBehaviour
+ {
+ go = new GameObject();
+ identity = go.AddComponent();
+ component = go.AddComponent();
+ // always set syncinterval = 0 for immediate testing
+ component.syncInterval = 0;
+ // Awake is only called in play mode.
+ // call manually for initialization.
+ identity.Awake();
+ // track
+ instantiated.Add(go);
+ }
+
+ // create GameObject + NetworkIdentity + 2x NetworkBehaviour
+ // add to tracker list if needed (useful for cleanups afterwards)
+ protected void CreateNetworked(out GameObject go, out NetworkIdentity identity, out T componentA, out U componentB)
+ where T : NetworkBehaviour
+ where U : NetworkBehaviour
+ {
+ go = new GameObject();
+ identity = go.AddComponent();
+ componentA = go.AddComponent();
+ componentB = go.AddComponent();
+ // always set syncinterval = 0 for immediate testing
+ componentA.syncInterval = 0;
+ componentB.syncInterval = 0;
+ // Awake is only called in play mode.
+ // call manually for initialization.
+ identity.Awake();
+ // track
+ instantiated.Add(go);
+ }
+
+ // create GameObject + NetworkIdentity + 2x NetworkBehaviour
+ // add to tracker list if needed (useful for cleanups afterwards)
+ protected void CreateNetworked(out GameObject go, out NetworkIdentity identity, out T componentA, out U componentB, out V componentC)
+ where T : NetworkBehaviour
+ where U : NetworkBehaviour
+ where V : NetworkBehaviour
+ {
+ go = new GameObject();
+ identity = go.AddComponent();
+ componentA = go.AddComponent();
+ componentB = go.AddComponent();
+ componentC = go.AddComponent();
+ // always set syncinterval = 0 for immediate testing
+ componentA.syncInterval = 0;
+ componentB.syncInterval = 0;
+ componentC.syncInterval = 0;
+ // Awake is only called in play mode.
+ // call manually for initialization.
+ identity.Awake();
+ // track
+ instantiated.Add(go);
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
+ // => ownerConnection can be NetworkServer.localConnection if needed.
+ protected void CreateNetworkedAndSpawn(out GameObject go, out NetworkIdentity identity, NetworkConnection ownerConnection = null)
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ CreateNetworked(out go, out identity);
+
+ // spawn
+ NetworkServer.Spawn(go, ownerConnection);
+ ProcessMessages();
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
+ // => ownerConnection can be NetworkServer.localConnection if needed.
+ // => returns objects from client and from server.
+ // will be same in host mode.
+ protected void CreateNetworkedAndSpawn(
+ out GameObject serverGO, out NetworkIdentity serverIdentity,
+ out GameObject clientGO, out NetworkIdentity clientIdentity,
+ NetworkConnection ownerConnection = null)
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // create one on server, one on client
+ // (spawning has to find it on client, it doesn't create it)
+ CreateNetworked(out serverGO, out serverIdentity);
+ CreateNetworked(out clientGO, out clientIdentity);
+
+ // give both a scene id and register it on client for spawnables
+ clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
+ NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
+
+ // spawn
+ NetworkServer.Spawn(serverGO, ownerConnection);
+ ProcessMessages();
+
+ // make sure the client really spawned it.
+ Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
+ // => ownerConnection can be NetworkServer.localConnection if needed.
+ protected void CreateNetworkedAndSpawn(out GameObject go, out NetworkIdentity identity, out T component, NetworkConnection ownerConnection = null)
+ where T : NetworkBehaviour
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ CreateNetworked(out go, out identity, out component);
+
+ // spawn
+ NetworkServer.Spawn(go, ownerConnection);
+ ProcessMessages();
+
+ // double check that we have authority if we passed an owner connection
+ if (ownerConnection != null)
+ Debug.Assert(component.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
+ // => ownerConnection can be NetworkServer.localConnection if needed.
+ // => returns objects from client and from server.
+ // will be same in host mode.
+ protected void CreateNetworkedAndSpawn(
+ out GameObject serverGO, out NetworkIdentity serverIdentity, out T serverComponent,
+ out GameObject clientGO, out NetworkIdentity clientIdentity, out T clientComponent,
+ NetworkConnection ownerConnection = null)
+ where T : NetworkBehaviour
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // create one on server, one on client
+ // (spawning has to find it on client, it doesn't create it)
+ CreateNetworked(out serverGO, out serverIdentity, out serverComponent);
+ CreateNetworked(out clientGO, out clientIdentity, out clientComponent);
+
+ // give both a scene id and register it on client for spawnables
+ clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
+ NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
+
+ // spawn
+ NetworkServer.Spawn(serverGO, ownerConnection);
+ ProcessMessages();
+
+ // double check that we have authority if we passed an owner connection
+ if (ownerConnection != null)
+ Debug.Assert(serverComponent.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+
+ // make sure the client really spawned it.
+ Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
+ // => ownerConnection can be NetworkServer.localConnection if needed.
+ protected void CreateNetworkedAndSpawn(out GameObject go, out NetworkIdentity identity, out T componentA, out U componentB, NetworkConnection ownerConnection = null)
+ where T : NetworkBehaviour
+ where U : NetworkBehaviour
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ CreateNetworked(out go, out identity, out componentA, out componentB);
+
+ // spawn
+ NetworkServer.Spawn(go, ownerConnection);
+ ProcessMessages();
+
+ // double check that we have authority if we passed an owner connection
+ if (ownerConnection != null)
+ {
+ Debug.Assert(componentA.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ Debug.Assert(componentB.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ }
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
+ // => ownerConnection can be NetworkServer.localConnection if needed.
+ // => returns objects from client and from server.
+ // will be same in host mode.
+ protected void CreateNetworkedAndSpawn(
+ out GameObject serverGO, out NetworkIdentity serverIdentity, out T serverComponentA, out U serverComponentB,
+ out GameObject clientGO, out NetworkIdentity clientIdentity, out T clientComponentA, out U clientComponentB,
+ NetworkConnection ownerConnection = null)
+ where T : NetworkBehaviour
+ where U : NetworkBehaviour
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // create one on server, one on client
+ // (spawning has to find it on client, it doesn't create it)
+ CreateNetworked(out serverGO, out serverIdentity, out serverComponentA, out serverComponentB);
+ CreateNetworked(out clientGO, out clientIdentity, out clientComponentA, out clientComponentB);
+
+ // give both a scene id and register it on client for spawnables
+ clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
+ NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
+
+ // spawn
+ NetworkServer.Spawn(serverGO, ownerConnection);
+ ProcessMessages();
+
+ // double check that we have authority if we passed an owner connection
+ if (ownerConnection != null)
+ {
+ Debug.Assert(serverComponentA.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ Debug.Assert(serverComponentB.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ }
+
+ // make sure the client really spawned it.
+ Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
+ // => ownerConnection can be NetworkServer.localConnection if needed.
+ protected void CreateNetworkedAndSpawn(out GameObject go, out NetworkIdentity identity, out T componentA, out U componentB, out V componentC, NetworkConnection ownerConnection = null)
+ where T : NetworkBehaviour
+ where U : NetworkBehaviour
+ where V : NetworkBehaviour
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ CreateNetworked(out go, out identity, out componentA, out componentB, out componentC);
+
+ // spawn
+ NetworkServer.Spawn(go, ownerConnection);
+ ProcessMessages();
+
+ // double check that we have authority if we passed an owner connection
+ if (ownerConnection != null)
+ {
+ Debug.Assert(componentA.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ Debug.Assert(componentB.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ Debug.Assert(componentC.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ }
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
+ // => ownerConnection can be NetworkServer.localConnection if needed.
+ // => returns objects from client and from server.
+ // will be same in host mode.
+ protected void CreateNetworkedAndSpawn(
+ out GameObject serverGO, out NetworkIdentity serverIdentity, out T serverComponentA, out U serverComponentB, out V serverComponentC,
+ out GameObject clientGO, out NetworkIdentity clientIdentity, out T clientComponentA, out U clientComponentB, out V clientComponentC,
+ NetworkConnection ownerConnection = null)
+ where T : NetworkBehaviour
+ where U : NetworkBehaviour
+ where V : NetworkBehaviour
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // create one on server, one on client
+ // (spawning has to find it on client, it doesn't create it)
+ CreateNetworked(out serverGO, out serverIdentity, out serverComponentA, out serverComponentB, out serverComponentC);
+ CreateNetworked(out clientGO, out clientIdentity, out clientComponentA, out clientComponentB, out clientComponentC);
+
+ // give both a scene id and register it on client for spawnables
+ clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
+ NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
+
+ // spawn
+ NetworkServer.Spawn(serverGO, ownerConnection);
+ ProcessMessages();
+
+ // double check that we have authority if we passed an owner connection
+ if (ownerConnection != null)
+ {
+ Debug.Assert(serverComponentA.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ Debug.Assert(serverComponentB.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ Debug.Assert(serverComponentC.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
+ }
+
+ // make sure the client really spawned it.
+ Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN PLAYER.
+ // often times, we really need a player object for the client to receive
+ // certain messages.
+ protected void CreateNetworkedAndSpawnPlayer(out GameObject go, out NetworkIdentity identity, NetworkConnection ownerConnection)
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // create a networked object
+ CreateNetworked(out go, out identity);
+
+ // add as player & process spawn message on client.
+ NetworkServer.AddPlayerForConnection(ownerConnection, go);
+ ProcessMessages();
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN PLAYER.
+ // often times, we really need a player object for the client to receive
+ // certain messages.
+ // => returns objects from client and from server.
+ // will be same in host mode.
+ protected void CreateNetworkedAndSpawnPlayer(
+ out GameObject serverGO, out NetworkIdentity serverIdentity,
+ out GameObject clientGO, out NetworkIdentity clientIdentity,
+ NetworkConnection ownerConnection)
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // create one on server, one on client
+ // (spawning has to find it on client, it doesn't create it)
+ CreateNetworked(out serverGO, out serverIdentity);
+ CreateNetworked(out clientGO, out clientIdentity);
+
+ // give both a scene id and register it on client for spawnables
+ clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
+ NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
+
+ // add as player & process spawn message on client.
+ NetworkServer.AddPlayerForConnection(ownerConnection, serverGO);
+ ProcessMessages();
+
+ // make sure the client really spawned it.
+ Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN PLAYER.
+ // often times, we really need a player object for the client to receive
+ // certain messages.
+ protected void CreateNetworkedAndSpawnPlayer(out GameObject go, out NetworkIdentity identity, out T component, NetworkConnection ownerConnection)
+ where T : NetworkBehaviour
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // create a networked object
+ CreateNetworked(out go, out identity, out component);
+
+ // add as player & process spawn message on client.
+ NetworkServer.AddPlayerForConnection(ownerConnection, go);
+ ProcessMessages();
+ }
+
+ // create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN PLAYER.
+ // often times, we really need a player object for the client to receive
+ // certain messages.
+ // => returns objects from client and from server.
+ // will be same in host mode.
+ protected void CreateNetworkedAndSpawnPlayer(
+ out GameObject serverGO, out NetworkIdentity serverIdentity, out T serverComponent,
+ out GameObject clientGO, out NetworkIdentity clientIdentity, out T clientComponent,
+ NetworkConnection ownerConnection)
+ where T : NetworkBehaviour
+ {
+ // server & client need to be active before spawning
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // create one on server, one on client
+ // (spawning has to find it on client, it doesn't create it)
+ CreateNetworked(out serverGO, out serverIdentity, out serverComponent);
+ CreateNetworked(out clientGO, out clientIdentity, out clientComponent);
+
+ // give both a scene id and register it on client for spawnables
+ clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
+ NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
+
+ // add as player & process spawn message on client.
+ NetworkServer.AddPlayerForConnection(ownerConnection, serverGO);
+ ProcessMessages();
+
+ // make sure the client really spawned it.
+ Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
+ }
+
+ // fully connect client to local server
+ // gives out the server's connection to client for convenience if needed
+ protected void ConnectClientBlocking(out NetworkConnectionToClient connectionToClient)
+ {
+ NetworkClient.Connect("127.0.0.1");
+ UpdateTransport();
+
+ Assert.That(NetworkServer.connections.Count, Is.EqualTo(1));
+ connectionToClient = NetworkServer.connections.Values.First();
+ }
+
+ // fully connect client to local server & authenticate
+ protected void ConnectClientBlockingAuthenticated(out NetworkConnectionToClient connectionToClient)
+ {
+ ConnectClientBlocking(out connectionToClient);
+
+ // authenticate server & client connections
+ connectionToClient.isAuthenticated = true;
+ NetworkClient.connection.isAuthenticated = true;
+ }
+
+ // fully connect client to local server & authenticate & set read
+ protected void ConnectClientBlockingAuthenticatedAndReady(out NetworkConnectionToClient connectionToClient)
+ {
+ ConnectClientBlocking(out connectionToClient);
+
+ // authenticate server & client connections
+ connectionToClient.isAuthenticated = true;
+ NetworkClient.connection.isAuthenticated = true;
+
+ // set ready
+ NetworkClient.Ready();
+ ProcessMessages();
+ Assert.That(connectionToClient.isReady, Is.True);
+ }
+
+ // fully connect HOST client to local server
+ // sets NetworkServer.localConnection / NetworkClient.connection.
+ protected void ConnectHostClientBlocking()
+ {
+ NetworkClient.ConnectHost();
+ NetworkClient.ConnectLocalServer();
+ UpdateTransport();
+ Assert.That(NetworkServer.connections.Count, Is.EqualTo(1));
+ }
+
+ // fully connect client to local server & authenticate & set read
+ protected void ConnectHostClientBlockingAuthenticatedAndReady()
+ {
+ ConnectHostClientBlocking();
+
+ // authenticate server & client connections
+ NetworkServer.localConnection.isAuthenticated = true;
+ NetworkClient.connection.isAuthenticated = true;
+
+ // set ready
+ NetworkClient.Ready();
+ ProcessMessages();
+ Assert.That(NetworkServer.localConnection.isReady, Is.True);
+ }
+
+ protected void UpdateTransport()
+ {
+ transport.ClientEarlyUpdate();
+ transport.ServerEarlyUpdate();
+ }
+
+ protected void ProcessMessages()
+ {
+ // server & client need to be active
+ Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
+ Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
+
+ // update server & client so batched messages are flushed
+ NetworkClient.NetworkLateUpdate();
+ NetworkServer.NetworkLateUpdate();
+
+ // update transport so sent messages are received
+ UpdateTransport();
+ }
+
+ // helper function to create local connection pair
+ protected void CreateLocalConnectionPair(out LocalConnectionToClient connectionToClient, out LocalConnectionToServer connectionToServer)
+ {
+ connectionToClient = new LocalConnectionToClient();
+ connectionToServer = new LocalConnectionToServer();
+ connectionToClient.connectionToServer = connectionToServer;
+ connectionToServer.connectionToClient = connectionToClient;
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Common/MirrorTest.cs.meta b/Assets/Mirror/Tests/Common/MirrorTest.cs.meta
new file mode 100644
index 000000000..d7b13dbe2
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/MirrorTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 67c5177a4b35749b8b9c4ca7107d8c25
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/NSubstitute.dll b/Assets/Mirror/Tests/Common/NSubstitute.dll
new file mode 100644
index 000000000..010169440
Binary files /dev/null and b/Assets/Mirror/Tests/Common/NSubstitute.dll differ
diff --git a/Assets/Mirror/Tests/Common/NSubstitute.dll.meta b/Assets/Mirror/Tests/Common/NSubstitute.dll.meta
new file mode 100644
index 000000000..5fe9de787
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/NSubstitute.dll.meta
@@ -0,0 +1,112 @@
+fileFormatVersion: 2
+guid: 601589975b5ca43179df797ffa3b468d
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ '': Any
+ second:
+ enabled: 0
+ settings:
+ Exclude Android: 1
+ Exclude Editor: 0
+ Exclude Linux: 1
+ Exclude Linux64: 1
+ Exclude LinuxUniversal: 1
+ Exclude OSXUniversal: 1
+ Exclude WebGL: 1
+ Exclude Win: 1
+ Exclude Win64: 1
+ Exclude iOS: 1
+ - first:
+ Android: Android
+ second:
+ enabled: 0
+ settings:
+ CPU: ARMv7
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ DefaultValueInitialized: true
+ OS: AnyOS
+ - first:
+ Facebook: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Facebook: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Linux
+ second:
+ enabled: 0
+ settings:
+ CPU: x86
+ - first:
+ Standalone: Linux64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: LinuxUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Windows Store Apps: WindowsStoreApps
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 0
+ settings:
+ AddToEmbeddedBinaries: false
+ CompileFlags:
+ FrameworkDependencies:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Common/System.Threading.Tasks.Extensions.dll b/Assets/Mirror/Tests/Common/System.Threading.Tasks.Extensions.dll
new file mode 100644
index 000000000..a1234ce81
Binary files /dev/null and b/Assets/Mirror/Tests/Common/System.Threading.Tasks.Extensions.dll differ
diff --git a/Assets/Mirror/Tests/Common/System.Threading.Tasks.Extensions.dll.meta b/Assets/Mirror/Tests/Common/System.Threading.Tasks.Extensions.dll.meta
new file mode 100644
index 000000000..7637cff41
--- /dev/null
+++ b/Assets/Mirror/Tests/Common/System.Threading.Tasks.Extensions.dll.meta
@@ -0,0 +1,117 @@
+fileFormatVersion: 2
+guid: 00713e0dc7f8d4ed2906179677779859
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ '': Any
+ second:
+ enabled: 0
+ settings:
+ Exclude Android: 1
+ Exclude Editor: 0
+ Exclude Linux: 1
+ Exclude Linux64: 1
+ Exclude LinuxUniversal: 1
+ Exclude OSXUniversal: 1
+ Exclude WebGL: 1
+ Exclude Win: 1
+ Exclude Win64: 1
+ Exclude iOS: 1
+ - first:
+ Android: Android
+ second:
+ enabled: 0
+ settings:
+ CPU: ARMv7
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ CPU: AnyCPU
+ DefaultValueInitialized: true
+ OS: AnyOS
+ - first:
+ Facebook: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Facebook: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Linux
+ second:
+ enabled: 0
+ settings:
+ CPU: x86
+ - first:
+ Standalone: Linux64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: LinuxUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: None
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ WebGL: WebGL
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Windows Store Apps: WindowsStoreApps
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 0
+ settings:
+ AddToEmbeddedBinaries: false
+ CompileFlags:
+ FrameworkDependencies:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor.meta b/Assets/Mirror/Tests/Editor.meta
new file mode 100644
index 000000000..e516951e1
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1d3db979f8f114547977d68180a77080
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/Batching.meta b/Assets/Mirror/Tests/Editor/Batching.meta
new file mode 100644
index 000000000..76b1f836c
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Batching.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6d113040314b4578b93a6f140f064f09
+timeCreated: 1623240703
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs b/Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs
new file mode 100644
index 000000000..4c5bc21e8
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs
@@ -0,0 +1,230 @@
+using System;
+using System.Linq;
+using NUnit.Framework;
+
+namespace Mirror.Tests.Batching
+{
+ public class BatcherTests
+ {
+ Batcher batcher;
+ const int Threshold = 8 + 4; // 8 bytes timestamp + 4 bytes message
+ NetworkWriter writer;
+
+ // timestamp and serialized timestamp for convenience
+ const double TimeStamp = Math.PI;
+
+ [SetUp]
+ public void SetUp()
+ {
+ batcher = new Batcher(Threshold);
+ writer = new NetworkWriter();
+ }
+
+ // helper function to create a batch prefixed by timestamp
+ public static byte[] ConcatTimestamp(double tickTimeStamp, byte[] data)
+ {
+ NetworkWriter writer = new NetworkWriter();
+ writer.WriteDouble(tickTimeStamp);
+ writer.WriteBytes(data, 0, data.Length);
+ return writer.ToArray();
+ }
+
+ [Test]
+ public void AddMessage()
+ {
+ byte[] message = {0x01, 0x02};
+ batcher.AddMessage(new ArraySegment(message));
+ }
+
+ [Test]
+ public void MakeNextBatch_OnlyAcceptsFreshWriter()
+ {
+ batcher.AddMessage(new ArraySegment(new byte[]{0x01}));
+
+ writer.WriteByte(0);
+ Assert.Throws(() => {
+ batcher.MakeNextBatch(writer, TimeStamp);
+ });
+ }
+
+ [Test]
+ public void MakeNextBatch_NoMessage()
+ {
+ // make batch with no message
+ bool result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(false));
+ }
+
+ [Test]
+ public void MakeNextBatch_OneMessage()
+ {
+ // add message
+ byte[] message = {0x01, 0x02};
+ batcher.AddMessage(new ArraySegment(message));
+
+ // make batch
+ bool result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+
+ // check result: <>
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, message)));
+ }
+
+ [Test]
+ public void MakeNextBatch_MultipleMessages_AlmostFullBatch()
+ {
+ batcher.AddMessage(new ArraySegment(new byte[]{0x01, 0x02}));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x03}));
+
+ // make batch
+ bool result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+
+ // check result: <>
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02, 0x03})));
+
+ // there should be no more batches to make
+ Assert.That(batcher.MakeNextBatch(writer, TimeStamp), Is.False);
+ }
+
+ [Test]
+ public void MakeNextBatch_MultipleMessages_ExactlyFullBatch()
+ {
+ batcher.AddMessage(new ArraySegment(new byte[]{0x01, 0x02}));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x03, 0x04}));
+
+ // make batch
+ bool result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+
+ // check result: <>
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02, 0x03, 0x04})));
+
+ // there should be no more batches to make
+ Assert.That(batcher.MakeNextBatch(writer, TimeStamp), Is.False);
+ }
+
+ [Test]
+ public void MakeNextBatch_MultipleMessages_MoreThanOneBatch()
+ {
+ batcher.AddMessage(new ArraySegment(new byte[]{0x01, 0x02}));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x03, 0x04}));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x05}));
+
+ // first batch
+ bool result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+
+ // check result: <>
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02, 0x03, 0x04})));
+
+ // reset writer
+ writer.Position = 0;
+
+ // second batch
+ result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+
+ // check result: <>
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x05})));
+ }
+
+ [Test]
+ public void MakeNextBatch_MultipleMessages_Small_Giant_Small()
+ {
+ // small, too big to include in batch, small
+ batcher.AddMessage(new ArraySegment(new byte[]{0x01}));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x02, 0x03, 0x04, 0x05}));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x06, 0x07}));
+
+ // first batch
+ bool result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+
+ // check result: <>
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01})));
+
+ // reset writer
+ writer.Position = 0;
+
+ // second batch
+ result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+
+ // check result: <>
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x02, 0x03, 0x04, 0x05})));
+
+ // reset writer
+ writer.Position = 0;
+
+ // third batch
+ result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+
+ // check result: <>
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x06, 0x07})));
+ }
+
+ // messages > threshold should simply be single batches.
+ // those need to be supported too, for example:
+ // kcp prefers MTU sized batches
+ // but we still allow up to 144 KB max message size
+ [Test]
+ public void MakeNextBatch_LargerThanThreshold()
+ {
+ // make a larger than threshold message
+ byte[] large = new byte[Threshold + 1];
+ for (int i = 0; i < Threshold + 1; ++i)
+ large[i] = (byte)i;
+ batcher.AddMessage(new ArraySegment(large));
+
+ // result should be only the large message
+ bool result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, large)));
+ }
+
+ // messages > threshold should simply be single batches.
+ // those need to be supported too, for example:
+ // kcp prefers MTU sized batches
+ // but we still allow up to 144 KB max message size
+ [Test]
+ public void MakeNextBatch_LargerThanThreshold_BetweenSmallerMessages()
+ {
+ // make a larger than threshold message
+ byte[] large = new byte[Threshold + 1];
+ for (int i = 0; i < Threshold + 1; ++i)
+ large[i] = (byte)i;
+
+ // add two small, one large, two small messages.
+ // to make sure everything around it is still batched,
+ // and the large one is a separate batch.
+ batcher.AddMessage(new ArraySegment(new byte[]{0x01}));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x02}));
+ batcher.AddMessage(new ArraySegment(large));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x03}));
+ batcher.AddMessage(new ArraySegment(new byte[]{0x04}));
+
+ // first batch should be the two small messages
+ bool result = batcher.MakeNextBatch(writer, TimeStamp);
+ Assert.That(result, Is.EqualTo(true));
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02})));
+
+ // reset writer
+ writer.Position = 0;
+
+ // second batch should be only the large message
+ result = batcher.MakeNextBatch(writer, TimeStamp + 1);
+ Assert.That(result, Is.EqualTo(true));
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp + 1, large)));
+
+ // reset writer
+ writer.Position = 0;
+
+ // third batch be the two small messages
+ result = batcher.MakeNextBatch(writer, TimeStamp + 2);
+ Assert.That(result, Is.EqualTo(true));
+ Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp + 2, new byte[]{0x03, 0x04})));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs.meta b/Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs.meta
new file mode 100644
index 000000000..9d19de00b
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 787d83b7e2ca4547aca251617d91f7d8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/Batching/UnbatcherTests.cs b/Assets/Mirror/Tests/Editor/Batching/UnbatcherTests.cs
new file mode 100644
index 000000000..e4b7e02ab
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Batching/UnbatcherTests.cs
@@ -0,0 +1,138 @@
+using System;
+using NUnit.Framework;
+
+namespace Mirror.Tests.Batching
+{
+ public class UnbatcherTests
+ {
+ Unbatcher unbatcher;
+ const double TimeStamp = Math.PI;
+
+ [SetUp]
+ public void SetUp()
+ {
+ unbatcher = new Unbatcher();
+ }
+
+ [Test]
+ public void GetNextMessage_NoBatches()
+ {
+ bool result = unbatcher.GetNextMessage(out _, out _);
+ Assert.That(result, Is.False);
+ }
+
+ // test for nimoyd bug, where calling getnextmessage after the previous
+ // call already returned false would cause an InvalidOperationException.
+ [Test]
+ public void GetNextMessage_True_False_False_InvalidOperationException()
+ {
+ // add batch
+ byte[] batch = BatcherTests.ConcatTimestamp(TimeStamp, new byte[2]);
+ unbatcher.AddBatch(new ArraySegment(batch));
+
+ // get next message, pretend we read the whole thing
+ bool result = unbatcher.GetNextMessage(out NetworkReader reader, out _);
+ Assert.That(result, Is.True);
+ reader.Position = reader.Length;
+
+ // shouldn't get another one
+ result = unbatcher.GetNextMessage(out reader, out _);
+ Assert.That(result, Is.False);
+
+ // calling it again was causing "InvalidOperationException: Queue empty"
+ result = unbatcher.GetNextMessage(out reader, out _);
+ Assert.That(result, Is.False);
+ }
+
+ [Test]
+ public void GetNextMessage_OneBatch()
+ {
+ // add one batch
+ byte[] batch = BatcherTests.ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02});
+ unbatcher.AddBatch(new ArraySegment(batch));
+
+ // get next message, read first byte
+ bool result = unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimeStamp);
+ Assert.That(result, Is.True);
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x01));
+ Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp));
+
+ // get next message, read last byte
+ result = unbatcher.GetNextMessage(out reader, out remoteTimeStamp);
+ Assert.That(result, Is.True);
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x02));
+ Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp));
+
+ // there should be no more messages
+ result = unbatcher.GetNextMessage(out _, out _);
+ Assert.That(result, Is.False);
+ }
+
+ [Test]
+ public void GetNextMessage_MultipleBatches()
+ {
+ // add first batch
+ byte[] firstBatch = BatcherTests.ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02});
+ unbatcher.AddBatch(new ArraySegment(firstBatch));
+
+ // add second batch
+ byte[] secondBatch = BatcherTests.ConcatTimestamp(TimeStamp + 1, new byte[]{0x03, 0x04});
+ unbatcher.AddBatch(new ArraySegment(secondBatch));
+
+ // get next message, read everything
+ bool result = unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimeStamp);
+ Assert.That(result, Is.True);
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x01));
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x02));
+ Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp));
+
+ // get next message, should point to next batch at Timestamp + 1
+ result = unbatcher.GetNextMessage(out reader, out remoteTimeStamp);
+ Assert.That(result, Is.True);
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x03));
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x04));
+ Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp + 1));
+
+ // there should be no more messages
+ result = unbatcher.GetNextMessage(out _, out _);
+ Assert.That(result, Is.False);
+ }
+
+ // make sure that retiring a batch, then adding a new batch works.
+ // previously there was a bug where the batch was retired,
+ // the reader still pointed to the old batch with pos=len,
+ // a new batch was added
+ // GetNextMessage() still returned false because reader still pointed to
+ // the old batch with pos=len.
+ [Test]
+ public void RetireBatchAndTryNewBatch()
+ {
+ // add first batch
+ byte[] firstBatch = BatcherTests.ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02});
+ unbatcher.AddBatch(new ArraySegment(firstBatch));
+
+ // read everything
+ bool result = unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimeStamp);
+ Assert.That(result, Is.True);
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x01));
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x02));
+ Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp));
+
+ // try to read again.
+ // reader will be at limit, which should retire the batch.
+ result = unbatcher.GetNextMessage(out _, out _);
+ Assert.That(result, Is.False);
+
+ // add new batch
+ byte[] secondBatch = BatcherTests.ConcatTimestamp(TimeStamp + 1, new byte[]{0x03, 0x04});
+ unbatcher.AddBatch(new ArraySegment(secondBatch));
+
+ // read everything
+ result = unbatcher.GetNextMessage(out reader, out remoteTimeStamp);
+ Assert.That(result, Is.True);
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x03));
+ Assert.That(reader.ReadByte(), Is.EqualTo(0x04));
+ Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp + 1));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/Batching/UnbatcherTests.cs.meta b/Assets/Mirror/Tests/Editor/Batching/UnbatcherTests.cs.meta
new file mode 100644
index 000000000..b3cf32232
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Batching/UnbatcherTests.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: ccc928bb22f5469886cef8c6132aa717
+timeCreated: 1623240730
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs b/Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs
new file mode 100644
index 000000000..613b006c9
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs
@@ -0,0 +1,134 @@
+using System;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests.RemoteAttrributeTest
+{
+ class VirtualClientRpc : NetworkBehaviour
+ {
+ public event Action onVirtualSendInt;
+
+ [ClientRpc]
+ public virtual void RpcSendInt(int someInt) =>
+ onVirtualSendInt?.Invoke(someInt);
+ }
+
+ class VirtualNoOverrideClientRpc : VirtualClientRpc {}
+
+ class VirtualOverrideClientRpc : VirtualClientRpc
+ {
+ public event Action onOverrideSendInt;
+
+ [ClientRpc]
+ public override void RpcSendInt(int someInt) =>
+ onOverrideSendInt?.Invoke(someInt);
+ }
+
+ class VirtualOverrideClientRpcWithBase : VirtualClientRpc
+ {
+ public event Action onOverrideSendInt;
+
+ [ClientRpc]
+ public override void RpcSendInt(int someInt)
+ {
+ base.RpcSendInt(someInt);
+ onOverrideSendInt?.Invoke(someInt);
+ }
+ }
+
+ public class ClientRpcOverrideTest : RemoteTestBase
+ {
+ [Test]
+ public void VirtualRpcIsCalled()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualClientRpc hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+ hostBehaviour.RpcSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void VirtualCommandWithNoOverrideIsCalled()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualNoOverrideClientRpc hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+ hostBehaviour.RpcSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void OverrideVirtualRpcIsCalled()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideClientRpc hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ int overrideCallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ };
+ hostBehaviour.onOverrideSendInt += incomingInt =>
+ {
+ overrideCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+ hostBehaviour.RpcSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(0));
+ Assert.That(overrideCallCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void OverrideVirtualWithBaseCallsBothVirtualAndBase()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideClientRpcWithBase hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ int overrideCallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.onOverrideSendInt += incomingInt =>
+ {
+ overrideCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+ hostBehaviour.RpcSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(1));
+ Assert.That(overrideCallCount, Is.EqualTo(1));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs.meta b/Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs.meta
new file mode 100644
index 000000000..68e53470b
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9759f0eddb9731c4b881ac30bacc0de0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientRpcTest.cs b/Assets/Mirror/Tests/Editor/ClientRpcTest.cs
new file mode 100644
index 000000000..86e1e47c6
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientRpcTest.cs
@@ -0,0 +1,155 @@
+using System;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests.RemoteAttrributeTest
+{
+ class ClientRpcBehaviour : NetworkBehaviour
+ {
+ public event Action onSendInt;
+
+ [ClientRpc]
+ public void SendInt(int someInt) =>
+ onSendInt?.Invoke(someInt);
+ }
+
+ class ExcludeOwnerBehaviour : NetworkBehaviour
+ {
+ public event Action onSendInt;
+
+ [ClientRpc(includeOwner = false)]
+ public void RpcSendInt(int someInt) =>
+ onSendInt?.Invoke(someInt);
+ }
+
+ class AbstractNetworkBehaviourClientRpcBehaviour : NetworkBehaviour
+ {
+ public abstract class MockMonsterBase : NetworkBehaviour {}
+ public class MockZombie : MockMonsterBase {}
+ public class MockWolf : MockMonsterBase {}
+
+ public event Action onSendMonsterBase;
+
+ [ClientRpc]
+ public void RpcSendMonster(MockMonsterBase someMonster) =>
+ onSendMonsterBase?.Invoke(someMonster);
+ }
+
+ class RpcOverloads : NetworkBehaviour
+ {
+ public int firstCalled = 0;
+ public int secondCalled = 0;
+
+ [ClientRpc]
+ public void RpcTest(int _) => ++firstCalled;
+
+ [ClientRpc]
+ public void RpcTest(string _) => ++secondCalled;
+ }
+
+ public class ClientRpcTest : RemoteTestBase
+ {
+ [Test]
+ public void RpcIsCalled()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out ClientRpcBehaviour hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int called = 0;
+ hostBehaviour.onSendInt += incomingInt =>
+ {
+ called++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.SendInt(someInt);
+ ProcessMessages();
+ Assert.That(called, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void RpcIsCalledForNotOwner()
+ {
+ // spawn without owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out ExcludeOwnerBehaviour hostBehaviour);
+
+ const int someInt = 20;
+
+ int called = 0;
+ hostBehaviour.onSendInt += incomingInt =>
+ {
+ called++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.RpcSendInt(someInt);
+ ProcessMessages();
+ Assert.That(called, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void RpcNotCalledForOwner()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out ExcludeOwnerBehaviour hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int called = 0;
+ hostBehaviour.onSendInt += incomingInt =>
+ {
+ called++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.RpcSendInt(someInt);
+ ProcessMessages();
+ Assert.That(called, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void RpcIsCalledWithAbstractNetworkBehaviourParameter()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out AbstractNetworkBehaviourClientRpcBehaviour hostBehaviour, NetworkServer.localConnection);
+
+ // spawn clientrpc parameter targets
+ CreateNetworkedAndSpawn(out _, out _, out AbstractNetworkBehaviourClientRpcBehaviour.MockWolf wolf, NetworkServer.localConnection);
+ CreateNetworkedAndSpawn(out _, out _, out AbstractNetworkBehaviourClientRpcBehaviour.MockZombie zombie, NetworkServer.localConnection);
+
+ AbstractNetworkBehaviourClientRpcBehaviour.MockMonsterBase currentMonster = null;
+
+ int called = 0;
+ hostBehaviour.onSendMonsterBase += incomingMonster =>
+ {
+ called++;
+ Assert.That(incomingMonster, Is.EqualTo(currentMonster));
+ };
+
+ currentMonster = wolf;
+ hostBehaviour.RpcSendMonster(currentMonster);
+ ProcessMessages();
+ Assert.That(called, Is.EqualTo(1));
+
+ currentMonster = zombie;
+ hostBehaviour.RpcSendMonster(currentMonster);
+ ProcessMessages();
+ Assert.That(called, Is.EqualTo(2));
+ }
+
+ // RemoteCalls uses md.FullName which gives us the full command/rpc name
+ // like "System.Void Mirror.Tests.RemoteAttrributeTest.AuthorityBehaviour::SendInt(System.Int32)"
+ // which means overloads with same name but different types should work.
+ [Test]
+ public void RpcOverload()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out RpcOverloads hostBehaviour, NetworkServer.localConnection);
+
+ hostBehaviour.RpcTest(42);
+ hostBehaviour.RpcTest("A");
+ ProcessMessages();
+ Assert.That(hostBehaviour.firstCalled, Is.EqualTo(1));
+ Assert.That(hostBehaviour.secondCalled, Is.EqualTo(1));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientRpcTest.cs.meta b/Assets/Mirror/Tests/Editor/ClientRpcTest.cs.meta
new file mode 100644
index 000000000..36ea9394d
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientRpcTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2928376e56382b646975dd00b68c2287
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_ClearSpawners.cs b/Assets/Mirror/Tests/Editor/ClientSceneTests_ClearSpawners.cs
new file mode 100644
index 000000000..1b6cdbc71
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_ClearSpawners.cs
@@ -0,0 +1,58 @@
+using System;
+using NUnit.Framework;
+
+namespace Mirror.Tests.ClientSceneTests
+{
+ public class ClientSceneTests_ClearSpawners : ClientSceneTestsBase
+ {
+ [Test]
+ public void RemovesAllPrefabsFromDictionary()
+ {
+ NetworkClient.prefabs.Add(Guid.NewGuid(), null);
+ NetworkClient.prefabs.Add(Guid.NewGuid(), null);
+
+ NetworkClient.ClearSpawners();
+ Assert.IsEmpty(NetworkClient.prefabs);
+ }
+
+ [Test]
+ public void RemovesAllSpawnHandlersFromDictionary()
+ {
+ NetworkClient.spawnHandlers.Add(Guid.NewGuid(), null);
+ NetworkClient.spawnHandlers.Add(Guid.NewGuid(), null);
+
+ NetworkClient.ClearSpawners();
+ Assert.IsEmpty(NetworkClient.spawnHandlers);
+ }
+
+ [Test]
+ public void RemovesAllUnspawnHandlersFromDictionary()
+ {
+ NetworkClient.unspawnHandlers.Add(Guid.NewGuid(), null);
+ NetworkClient.unspawnHandlers.Add(Guid.NewGuid(), null);
+
+ NetworkClient.ClearSpawners();
+
+ Assert.IsEmpty(NetworkClient.unspawnHandlers);
+ }
+
+ [Test]
+ public void ClearsAllDictionary()
+ {
+ NetworkClient.prefabs.Add(Guid.NewGuid(), null);
+ NetworkClient.prefabs.Add(Guid.NewGuid(), null);
+
+ NetworkClient.spawnHandlers.Add(Guid.NewGuid(), null);
+ NetworkClient.spawnHandlers.Add(Guid.NewGuid(), null);
+
+ NetworkClient.unspawnHandlers.Add(Guid.NewGuid(), null);
+ NetworkClient.unspawnHandlers.Add(Guid.NewGuid(), null);
+
+ NetworkClient.ClearSpawners();
+
+ Assert.IsEmpty(NetworkClient.prefabs);
+ Assert.IsEmpty(NetworkClient.spawnHandlers);
+ Assert.IsEmpty(NetworkClient.unspawnHandlers);
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_ClearSpawners.cs.meta b/Assets/Mirror/Tests/Editor/ClientSceneTests_ClearSpawners.cs.meta
new file mode 100644
index 000000000..3a955eb07
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_ClearSpawners.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ad2fe5633a9652045a5f7eb2643b6956
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_GetPrefab.cs b/Assets/Mirror/Tests/Editor/ClientSceneTests_GetPrefab.cs
new file mode 100644
index 000000000..9fb848785
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_GetPrefab.cs
@@ -0,0 +1,62 @@
+using System;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests.ClientSceneTests
+{
+ public class ClientSceneTests_GetPrefab : ClientSceneTestsBase
+ {
+ [Test]
+ public void ReturnsFalseForEmptyGuid()
+ {
+ bool result = NetworkClient.GetPrefab(new Guid(), out GameObject prefab);
+
+ Assert.IsFalse(result);
+ Assert.IsNull(prefab);
+ }
+
+ [Test]
+ public void ReturnsFalseForPrefabNotFound()
+ {
+ Guid guid = Guid.NewGuid();
+ bool result = NetworkClient.GetPrefab(guid, out GameObject prefab);
+
+ Assert.IsFalse(result);
+ Assert.IsNull(prefab);
+ }
+
+ [Test]
+ public void ReturnsFalseForPrefabIsNull()
+ {
+ Guid guid = Guid.NewGuid();
+ NetworkClient.prefabs.Add(guid, null);
+ bool result = NetworkClient.GetPrefab(guid, out GameObject prefab);
+
+ Assert.IsFalse(result);
+ Assert.IsNull(prefab);
+ }
+
+ [Test]
+ public void ReturnsTrueWhenPrefabIsFound()
+ {
+ NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
+ bool result = NetworkClient.GetPrefab(validPrefabGuid, out GameObject prefab);
+
+ Assert.IsTrue(result);
+ Assert.NotNull(prefab);
+ }
+
+ [Test]
+ public void HasOutPrefabWithCorrectGuid()
+ {
+ NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
+ NetworkClient.GetPrefab(validPrefabGuid, out GameObject prefab);
+
+
+ Assert.NotNull(prefab);
+
+ NetworkIdentity networkID = prefab.GetComponent();
+ Assert.AreEqual(networkID.assetId, validPrefabGuid);
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_GetPrefab.cs.meta b/Assets/Mirror/Tests/Editor/ClientSceneTests_GetPrefab.cs.meta
new file mode 100644
index 000000000..2dde78154
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_GetPrefab.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 27cbff3906928974bb20c3f50eacbbb0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs b/Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs
new file mode 100644
index 000000000..054151d94
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs
@@ -0,0 +1,736 @@
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+
+namespace Mirror.Tests.ClientSceneTests
+{
+ public class PayloadTestBehaviour : NetworkBehaviour
+ {
+ public int value;
+ public Vector3 direction;
+
+ public event Action OnDeserializeCalled;
+ public event Action OnSerializeCalled;
+
+ public override bool OnSerialize(NetworkWriter writer, bool initialState)
+ {
+ base.OnSerialize(writer, initialState);
+
+ writer.WriteInt(value);
+ writer.WriteVector3(direction);
+
+ OnSerializeCalled?.Invoke();
+
+ return true;
+ }
+ public override void OnDeserialize(NetworkReader reader, bool initialState)
+ {
+ base.OnDeserialize(reader, initialState);
+
+ value = reader.ReadInt();
+ direction = reader.ReadVector3();
+
+ OnDeserializeCalled?.Invoke();
+ }
+ }
+
+ public class BehaviourWithEvents : NetworkBehaviour
+ {
+ public event Action OnStartAuthorityCalled;
+ public event Action OnStartClientCalled;
+ public event Action OnStartLocalPlayerCalled;
+
+ public override void OnStartAuthority()
+ {
+ OnStartAuthorityCalled?.Invoke();
+ }
+ public override void OnStartClient()
+ {
+ OnStartClientCalled?.Invoke();
+ }
+ public override void OnStartLocalPlayer()
+ {
+ OnStartLocalPlayerCalled?.Invoke();
+ }
+ }
+
+ public class ClientSceneTests_OnSpawn : ClientSceneTestsBase
+ {
+ Dictionary spawned => NetworkClient.spawned;
+
+ [TearDown]
+ public override void TearDown()
+ {
+ spawned.Clear();
+ base.TearDown();
+ }
+
+ [Test]
+ public void FindOrSpawnObject_FindExistingObject()
+ {
+ CreateNetworked(out _, out NetworkIdentity existing);
+ const uint netId = 1000;
+ existing.netId = netId;
+ spawned.Add(netId, existing);
+
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId
+ };
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity found);
+
+ Assert.IsTrue(success);
+ Assert.That(found, Is.EqualTo(existing));
+ }
+
+ [Test]
+ public void FindOrSpawnObject_ErrorWhenNoExistingAndAssetIdAndSceneIdAreBothEmpty()
+ {
+ const uint netId = 1001;
+ SpawnMessage msg = new SpawnMessage
+ {
+ assetId = new Guid(),
+ sceneId = 0,
+ netId = netId
+ };
+
+ LogAssert.Expect(LogType.Error, $"OnSpawn message with netId '{netId}' has no AssetId or sceneId");
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsFalse(success);
+ Assert.IsNull(networkIdentity);
+ }
+
+ [Test]
+ public void FindOrSpawnObject_SpawnsFromPrefabDictionary()
+ {
+ const uint netId = 1002;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ assetId = validPrefabGuid
+
+ };
+
+ NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
+
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsTrue(success);
+ Assert.IsNotNull(networkIdentity);
+ Assert.That(networkIdentity.name, Is.EqualTo($"{validPrefab.name}(Clone)"));
+
+ // cleanup
+ GameObject.DestroyImmediate(networkIdentity.gameObject);
+ }
+
+ [Test]
+ public void FindOrSpawnObject_ErrorWhenPrefabInNullInDictionary()
+ {
+ const uint netId = 1002;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ assetId = validPrefabGuid
+ };
+
+ // could happen if the prefab is destroyed or unloaded
+ NetworkClient.prefabs.Add(validPrefabGuid, null);
+
+ LogAssert.Expect(LogType.Error, $"Failed to spawn server object, did you forget to add it to the NetworkManager? assetId={msg.assetId} netId={msg.netId}");
+ LogAssert.Expect(LogType.Error, $"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}");
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+
+ Assert.IsFalse(success);
+ Assert.IsNull(networkIdentity);
+ }
+
+ [Test]
+ public void FindOrSpawnObject_SpawnsFromPrefabIfBothPrefabAndHandlerExists()
+ {
+ const uint netId = 1003;
+ int handlerCalled = 0;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ assetId = validPrefabGuid
+ };
+
+ NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
+ NetworkClient.spawnHandlers.Add(validPrefabGuid, x =>
+ {
+ handlerCalled++;
+ CreateNetworked(out GameObject go, out NetworkIdentity _);
+ return go;
+ });
+
+
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsTrue(success);
+ Assert.IsNotNull(networkIdentity);
+ Assert.That(networkIdentity.name, Is.EqualTo($"{validPrefab.name}(Clone)"));
+ Assert.That(handlerCalled, Is.EqualTo(0), "Handler should not have been called");
+ }
+
+ [Test]
+ public void FindOrSpawnObject_SpawnHandlerCalledFromDictionary()
+ {
+ const uint netId = 1003;
+ int handlerCalled = 0;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ assetId = validPrefabGuid
+ };
+
+ GameObject createdInhandler = null;
+
+ NetworkClient.spawnHandlers.Add(validPrefabGuid, x =>
+ {
+ handlerCalled++;
+ Assert.That(x, Is.EqualTo(msg));
+ CreateNetworked(out createdInhandler, out NetworkIdentity _);
+ return createdInhandler;
+ });
+
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsTrue(success);
+ Assert.IsNotNull(networkIdentity);
+ Assert.That(handlerCalled, Is.EqualTo(1));
+ Assert.That(networkIdentity.gameObject, Is.EqualTo(createdInhandler), "Object returned should be the same object created by the spawn handler");
+ }
+
+ [Test]
+ public void FindOrSpawnObject_ErrorWhenSpawnHanlderReturnsNull()
+ {
+ const uint netId = 1003;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ assetId = validPrefabGuid
+ };
+
+ NetworkClient.spawnHandlers.Add(validPrefabGuid, (x) => null);
+
+ LogAssert.Expect(LogType.Error, $"Spawn Handler returned null, Handler assetId '{msg.assetId}'");
+ LogAssert.Expect(LogType.Error, $"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}");
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsFalse(success);
+ Assert.IsNull(networkIdentity);
+ }
+ [Test]
+ public void FindOrSpawnObject_ErrorWhenSpawnHanlderReturnsWithoutNetworkIdentity()
+ {
+ const uint netId = 1003;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ assetId = validPrefabGuid
+ };
+
+ NetworkClient.spawnHandlers.Add(validPrefabGuid, (x) =>
+ {
+ CreateGameObject(out GameObject go);
+ return go;
+ });
+
+ LogAssert.Expect(LogType.Error, $"Object Spawned by handler did not have a NetworkIdentity, Handler assetId '{validPrefabGuid}'");
+ LogAssert.Expect(LogType.Error, $"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}");
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsFalse(success);
+ Assert.IsNull(networkIdentity);
+ }
+
+ NetworkIdentity CreateSceneObject(ulong sceneId)
+ {
+ CreateNetworked(out _, out NetworkIdentity identity);
+ // set sceneId to zero as it is set in onvalidate (does not set id at runtime)
+ identity.sceneId = sceneId;
+ NetworkClient.spawnableObjects.Add(sceneId, identity);
+ return identity;
+ }
+
+ [Test]
+ public void FindOrSpawnObject_UsesSceneIdToSpawnFromSpawnableObjectsDictionary()
+ {
+ const uint netId = 1003;
+ const int sceneId = 100020;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ sceneId = sceneId
+ };
+
+ NetworkIdentity sceneObject = CreateSceneObject(sceneId);
+
+
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsTrue(success);
+ Assert.IsNotNull(networkIdentity);
+ Assert.That(networkIdentity, Is.EqualTo(sceneObject));
+ }
+
+ [Test]
+ public void FindOrSpawnObject_SpawnsUsingSceneIdInsteadOfAssetId()
+ {
+ const uint netId = 1003;
+ const int sceneId = 100020;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ sceneId = sceneId,
+ assetId = validPrefabGuid
+ };
+
+ NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
+ NetworkIdentity sceneObject = CreateSceneObject(sceneId);
+
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsTrue(success);
+ Assert.IsNotNull(networkIdentity);
+ Assert.That(networkIdentity, Is.EqualTo(sceneObject));
+ }
+
+ [Test]
+ public void FindOrSpawnObject_ErrorWhenSceneIdIsNotInSpawnableObjectsDictionary()
+ {
+ const uint netId = 1004;
+ const int sceneId = 100021;
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ sceneId = sceneId,
+ };
+
+ LogAssert.Expect(LogType.Error, $"Spawn scene object not found for {msg.sceneId:X}. Make sure that client and server use exactly the same project. This only happens if the hierarchy gets out of sync.");
+ LogAssert.Expect(LogType.Error, $"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}");
+ bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
+
+ Assert.IsFalse(success);
+ Assert.IsNull(networkIdentity);
+ }
+
+
+ [Test]
+ public void ApplyPayload_AppliesTransform()
+ {
+ const uint netId = 1000;
+
+ CreateNetworked(out GameObject _, out NetworkIdentity identity);
+
+ Vector3 position = new Vector3(10, 0, 20);
+ Quaternion rotation = Quaternion.Euler(0, 45, 0);
+ Vector3 scale = new Vector3(1.5f, 1.5f, 1.5f);
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = false,
+ isOwner = false,
+ sceneId = 0,
+ assetId = Guid.Empty,
+ // use local values for VR support
+ position = position,
+ rotation = rotation,
+ scale = scale,
+
+ payload = default,
+ };
+
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ Assert.That(identity.transform.position, Is.EqualTo(position));
+ // use angle because of floating point numbers
+ // only need to check if rotations are approximately equal
+ Assert.That(Quaternion.Angle(identity.transform.rotation, rotation), Is.LessThan(0.0001f));
+ Assert.That(identity.transform.localScale, Is.EqualTo(scale));
+ }
+
+ [Test]
+ public void ApplyPayload_AppliesLocalValuesToTransform()
+ {
+ const uint netId = 1000;
+ CreateGameObject(out GameObject parent);
+ parent.transform.position = new Vector3(100, 20, 0);
+ parent.transform.rotation = Quaternion.LookRotation(Vector3.left);
+ parent.transform.localScale = Vector3.one * 2;
+
+ CreateNetworked(out GameObject go, out NetworkIdentity identity);
+ go.transform.parent = parent.transform;
+
+ Vector3 position = new Vector3(10, 0, 20);
+ Quaternion rotation = Quaternion.Euler(0, 45, 0);
+ Vector3 scale = new Vector3(1.5f, 1.5f, 1.5f);
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = false,
+ isOwner = false,
+ sceneId = 0,
+ assetId = Guid.Empty,
+ // use local values for VR support
+ position = position,
+ rotation = rotation,
+ scale = scale,
+
+ payload = default,
+ };
+
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ Assert.That(identity.transform.localPosition, Is.EqualTo(position));
+ // use angle because of floating point numbers
+ // only need to check if rotations are approximately equal
+ Assert.That(Quaternion.Angle(identity.transform.localRotation, rotation), Is.LessThan(0.0001f));
+ Assert.That(identity.transform.localScale, Is.EqualTo(scale));
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ApplyPayload_AppliesAuthority(bool isOwner)
+ {
+ const uint netId = 1000;
+
+ CreateNetworked(out _, out NetworkIdentity identity);
+
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = false,
+ isOwner = isOwner,
+ sceneId = 0,
+ assetId = Guid.Empty,
+ // use local values for VR support
+ position = Vector3.zero,
+ rotation = Quaternion.identity,
+ scale = Vector3.one,
+
+ payload = default
+ };
+
+ // set to opposite to make sure it is changed
+ identity.hasAuthority = !isOwner;
+
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ Assert.That(identity.hasAuthority, Is.EqualTo(isOwner));
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ApplyPayload_EnablesObject(bool startActive)
+ {
+ const uint netId = 1000;
+
+ CreateNetworked(out GameObject go, out NetworkIdentity identity);
+ go.SetActive(startActive);
+
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = false,
+ isOwner = false,
+ sceneId = 0,
+ assetId = Guid.Empty,
+ // use local values for VR support
+ position = Vector3.zero,
+ rotation = Quaternion.identity,
+ scale = Vector3.one,
+
+ payload = default,
+ };
+
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ Assert.IsTrue(identity.gameObject.activeSelf);
+ }
+
+ [Test]
+ public void ApplyPayload_SetsAssetId()
+ {
+ const uint netId = 1000;
+
+ CreateNetworked(out _, out NetworkIdentity identity);
+
+ Guid guid = Guid.NewGuid();
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = false,
+ isOwner = false,
+ sceneId = 0,
+ assetId = guid,
+ // use local values for VR support
+ position = Vector3.zero,
+ rotation = Quaternion.identity,
+ scale = Vector3.one,
+
+ payload = default
+ };
+
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ Assert.IsTrue(identity.gameObject.activeSelf);
+
+ Assert.That(identity.assetId, Is.EqualTo(guid));
+ }
+
+ [Test]
+ public void ApplyPayload_DoesNotSetAssetIdToEmpty()
+ {
+ const uint netId = 1000;
+
+ CreateNetworked(out _, out NetworkIdentity identity);
+ Guid guid = Guid.NewGuid();
+ identity.assetId = guid;
+
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = false,
+ isOwner = false,
+ sceneId = 0,
+ assetId = Guid.Empty,
+ // use local values for VR support
+ position = Vector3.zero,
+ rotation = Quaternion.identity,
+ scale = Vector3.one,
+
+ payload = default
+ };
+
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ Assert.That(identity.assetId, Is.EqualTo(guid), "AssetId should not have changed");
+ }
+
+ [Test]
+ public void ApplyPayload_SendsDataToNetworkBehaviourDeserialize()
+ {
+ const int value = 12;
+ Vector3 direction = new Vector3(0, 1, 1);
+
+ const uint netId = 1000;
+
+ // server object
+ CreateNetworked(out _, out NetworkIdentity serverIdentity, out PayloadTestBehaviour serverPayloadBehaviour);
+
+ // client object
+ CreateNetworked(out _, out NetworkIdentity clientIdentity, out PayloadTestBehaviour clientPayloadBehaviour);
+
+ int onSerializeCalled = 0;
+ serverPayloadBehaviour.OnSerializeCalled += () => { onSerializeCalled++; };
+
+ int onDeserializeCalled = 0;
+ clientPayloadBehaviour.OnDeserializeCalled += () => { onDeserializeCalled++; };
+
+ serverPayloadBehaviour.value = value;
+ serverPayloadBehaviour.direction = direction;
+
+ NetworkWriter ownerWriter = new NetworkWriter();
+ NetworkWriter observersWriter = new NetworkWriter();
+ serverIdentity.OnSerializeAllSafely(true, ownerWriter, observersWriter);
+
+ // check that Serialize was called
+ Assert.That(onSerializeCalled, Is.EqualTo(1));
+
+ // create spawn message
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ payload = ownerWriter.ToArraySegment(),
+ };
+
+ // check values start default
+ Assert.That(onDeserializeCalled, Is.EqualTo(0));
+ Assert.That(clientPayloadBehaviour.value, Is.EqualTo(0));
+ Assert.That(clientPayloadBehaviour.direction, Is.EqualTo(Vector3.zero));
+
+ NetworkClient.ApplySpawnPayload(clientIdentity, msg);
+
+ // check values have been set by payload
+ Assert.That(onDeserializeCalled, Is.EqualTo(1));
+ Assert.That(clientPayloadBehaviour.value, Is.EqualTo(value));
+ Assert.That(clientPayloadBehaviour.direction, Is.EqualTo(direction));
+ }
+
+ [Test]
+ public void ApplyPayload_LocalPlayerAddsIdentityToConnection()
+ {
+ Debug.Assert(NetworkClient.localPlayer == null, "LocalPlayer should be null before this test");
+ const uint netId = 1000;
+
+ CreateNetworked(out _, out NetworkIdentity identity);
+
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = true,
+ isOwner = true,
+ sceneId = 0,
+ assetId = Guid.Empty,
+ // use local values for VR support
+ position = Vector3.zero,
+ rotation = Quaternion.identity,
+ scale = Vector3.one,
+
+ payload = default,
+ };
+
+ NetworkClient.connection = new FakeNetworkConnection();
+ NetworkClient.ready = true;
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ Assert.That(NetworkClient.localPlayer, Is.EqualTo(identity));
+ Assert.That(NetworkClient.connection.identity, Is.EqualTo(identity));
+ }
+
+ [Test]
+ public void ApplyPayload_LocalPlayerWarningWhenNoReadyConnection()
+ {
+ Debug.Assert(NetworkClient.localPlayer == null, "LocalPlayer should be null before this test");
+ const uint netId = 1000;
+
+ CreateNetworked(out _, out NetworkIdentity identity);
+
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = true,
+ isOwner = true,
+ sceneId = 0,
+ assetId = Guid.Empty,
+ // use local values for VR support
+ position = Vector3.zero,
+ rotation = Quaternion.identity,
+ scale = Vector3.one,
+
+ payload = default,
+ };
+
+
+ LogAssert.Expect(LogType.Warning, "No ready connection found for setting player controller during InternalAddPlayer");
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ Assert.That(NetworkClient.localPlayer, Is.EqualTo(identity));
+ }
+
+ [Flags]
+ public enum SpawnFinishedState
+ {
+ isSpawnFinished = 1,
+ hasAuthority = 2,
+ isLocalPlayer = 4
+ }
+ [Test]
+ [TestCase(0)]
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(3)]
+ [TestCase(4)]
+ [TestCase(5)]
+ [TestCase(6)]
+ [TestCase(7)]
+ public void ApplyPayload_isSpawnFinished(SpawnFinishedState flag)
+ {
+ bool isSpawnFinished = flag.HasFlag(SpawnFinishedState.isSpawnFinished);
+ bool hasAuthority = flag.HasFlag(SpawnFinishedState.hasAuthority);
+ bool isLocalPlayer = flag.HasFlag(SpawnFinishedState.isLocalPlayer);
+
+ if (isSpawnFinished)
+ {
+ NetworkClient.OnObjectSpawnFinished(new ObjectSpawnFinishedMessage());
+ }
+
+ const uint netId = 1000;
+ CreateNetworked(out _, out NetworkIdentity identity, out BehaviourWithEvents events);
+
+ int onStartAuthorityCalled = 0;
+ int onStartClientCalled = 0;
+ int onStartLocalPlayerCalled = 0;
+ events.OnStartAuthorityCalled += () => { onStartAuthorityCalled++; };
+ events.OnStartClientCalled += () => { onStartClientCalled++; };
+ events.OnStartLocalPlayerCalled += () => { onStartLocalPlayerCalled++; };
+
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ isLocalPlayer = isLocalPlayer,
+ isOwner = hasAuthority,
+ };
+
+ NetworkClient.ApplySpawnPayload(identity, msg);
+
+ if (isSpawnFinished)
+ {
+ Assert.That(onStartClientCalled, Is.EqualTo(1));
+ Assert.That(onStartAuthorityCalled, Is.EqualTo(hasAuthority ? 1 : 0));
+ Assert.That(onStartLocalPlayerCalled, Is.EqualTo(isLocalPlayer ? 1 : 0));
+ }
+ else
+ {
+ Assert.That(onStartAuthorityCalled, Is.Zero);
+ Assert.That(onStartClientCalled, Is.Zero);
+ Assert.That(onStartLocalPlayerCalled, Is.Zero);
+ }
+ }
+
+ [Test]
+ public void OnSpawn_SpawnsAndAppliesPayload()
+ {
+ const int netId = 1;
+ Debug.Assert(spawned.Count == 0, "There should be no spawned objects before test");
+
+ Vector3 position = new Vector3(30, 20, 10);
+ Quaternion rotation = Quaternion.Euler(0, 0, 90);
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ assetId = validPrefabGuid,
+ position = position,
+ rotation = rotation
+ };
+ NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
+
+ NetworkClient.OnSpawn(msg);
+
+ Assert.That(spawned.Count, Is.EqualTo(1));
+ Assert.IsTrue(spawned.ContainsKey(netId));
+
+ NetworkIdentity identity = spawned[netId];
+ Assert.IsNotNull(identity);
+ Assert.That(identity.name, Is.EqualTo($"{validPrefab.name}(Clone)"));
+ Assert.That(identity.transform.position, Is.EqualTo(position));
+ // use angle because of floating point numbers
+ // only need to check if rotations are approximately equal
+ Assert.That(Quaternion.Angle(identity.transform.rotation, rotation), Is.LessThan(0.0001f));
+ }
+
+ [Test]
+ public void OnSpawn_GiveNoExtraErrorsWhenPrefabIsntSpawned()
+ {
+ const int netId = 20033;
+ Debug.Assert(spawned.Count == 0, "There should be no spawned objects before test");
+ SpawnMessage msg = new SpawnMessage
+ {
+ netId = netId,
+ };
+
+ // Check for log that FindOrSpawnObject gives, and make sure there are no other error logs
+ LogAssert.Expect(LogType.Error, $"OnSpawn message with netId '{netId}' has no AssetId or sceneId");
+ NetworkClient.OnSpawn(msg);
+
+ Assert.That(spawned, Is.Empty);
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs.meta b/Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs.meta
new file mode 100644
index 000000000..03d445c2d
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b85d949dccc6ab4498da187264323dcc
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_PrepareToSpawnSceneObjects.cs b/Assets/Mirror/Tests/Editor/ClientSceneTests_PrepareToSpawnSceneObjects.cs
new file mode 100644
index 000000000..4f9532c28
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_PrepareToSpawnSceneObjects.cs
@@ -0,0 +1,104 @@
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests.ClientSceneTests
+{
+ public class ClientSceneTests_PrepareToSpawnSceneObjects : ClientSceneTestsBase
+ {
+ NetworkIdentity CreateSceneObject(ulong sceneId)
+ {
+ CreateNetworked(out GameObject gameObject, out NetworkIdentity identity);
+ gameObject.name = "Runtime GameObject";
+ // set sceneId to zero as it is set in onvalidate (does not set id at runtime)
+ identity.sceneId = sceneId;
+ return identity;
+ }
+
+ [Test]
+ public void AddsAllInactiveIdentitiesInSceneWithSceneIdToDictionary()
+ {
+ NetworkIdentity obj1 = CreateSceneObject(10);
+ NetworkIdentity obj2 = CreateSceneObject(11);
+
+ obj1.gameObject.SetActive(false);
+ obj2.gameObject.SetActive(false);
+
+ NetworkClient.PrepareToSpawnSceneObjects();
+
+ Assert.That(NetworkClient.spawnableObjects, Has.Count.EqualTo(2));
+
+ Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(obj1));
+ Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(obj2));
+ }
+
+ [Test]
+ public void DoesNotAddActiveObjectsToDictionary()
+ {
+ NetworkIdentity active = CreateSceneObject(30);
+ NetworkIdentity inactive = CreateSceneObject(32);
+
+ active.gameObject.SetActive(true);
+ inactive.gameObject.SetActive(false);
+
+ NetworkClient.PrepareToSpawnSceneObjects();
+
+ Assert.That(NetworkClient.spawnableObjects, Has.Count.EqualTo(1));
+ Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(inactive));
+ Assert.IsFalse(NetworkClient.spawnableObjects.ContainsValue(active));
+ }
+
+ [Test]
+ public void DoesNotAddObjectsWithNoSceneId()
+ {
+ NetworkIdentity noId = CreateSceneObject(0);
+ NetworkIdentity hasId = CreateSceneObject(40);
+
+ noId.gameObject.SetActive(false);
+ hasId.gameObject.SetActive(false);
+
+ NetworkClient.PrepareToSpawnSceneObjects();
+
+ Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(hasId));
+ Assert.IsFalse(NetworkClient.spawnableObjects.ContainsValue(noId));
+ }
+
+ [Test]
+ public void AddsIdentitiesToDictionaryUsingSceneId()
+ {
+ NetworkIdentity obj1 = CreateSceneObject(20);
+ NetworkIdentity obj2 = CreateSceneObject(21);
+ obj1.gameObject.SetActive(false);
+ obj2.gameObject.SetActive(false);
+
+ NetworkClient.PrepareToSpawnSceneObjects();
+
+ Assert.IsTrue(NetworkClient.spawnableObjects.ContainsKey(20));
+ Assert.That(NetworkClient.spawnableObjects[20], Is.EqualTo(obj1));
+
+ Assert.IsTrue(NetworkClient.spawnableObjects.ContainsKey(21));
+ Assert.That(NetworkClient.spawnableObjects[21], Is.EqualTo(obj2));
+ }
+
+ [Test]
+ public void ClearsExistingItemsFromDictionary()
+ {
+ // destroyed objects from old scene
+ NetworkClient.spawnableObjects.Add(60, null);
+ NetworkClient.spawnableObjects.Add(62, null);
+
+ // active object
+ NetworkIdentity obj1 = CreateSceneObject(61);
+ NetworkClient.spawnableObjects.Add(61, obj1);
+
+ // new disabled object
+ NetworkIdentity obj2 = CreateSceneObject(63);
+ obj2.gameObject.SetActive(false);
+
+ NetworkClient.PrepareToSpawnSceneObjects();
+
+ Assert.That(NetworkClient.spawnableObjects, Has.Count.EqualTo(1));
+ Assert.IsFalse(NetworkClient.spawnableObjects.ContainsValue(null));
+ Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(obj2));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_PrepareToSpawnSceneObjects.cs.meta b/Assets/Mirror/Tests/Editor/ClientSceneTests_PrepareToSpawnSceneObjects.cs.meta
new file mode 100644
index 000000000..9652845b1
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_PrepareToSpawnSceneObjects.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 546931b1b1c38d5498f2c189e68b63aa
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterPrefab.cs b/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterPrefab.cs
new file mode 100644
index 000000000..a63b1f628
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterPrefab.cs
@@ -0,0 +1,300 @@
+using System;
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+
+namespace Mirror.Tests.ClientSceneTests
+{
+ public class ClientSceneTests_RegisterPrefab : ClientSceneTests_RegisterPrefabBase
+ {
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab)]
+ public void Prefab_AddsPrefabToDictionary(RegisterPrefabOverload overload)
+ {
+ Guid guid = GuidForOverload(overload);
+
+ CallRegisterPrefab(validPrefab, overload);
+
+ Assert.IsTrue(NetworkClient.prefabs.ContainsKey(guid));
+ Assert.AreEqual(NetworkClient.prefabs[guid], validPrefab);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
+ public void PrefabNewGuid_ErrorDoesNotChangePrefabsAssetId(RegisterPrefabOverload overload)
+ {
+ Guid guid = anotherGuid;
+
+ LogAssert.Expect(LogType.Error, $"Could not register '{validPrefab.name}' to {guid} because it already had an AssetId, Existing assetId {validPrefabGuid}");
+ CallRegisterPrefab(validPrefab, overload);
+
+ Assert.IsFalse(NetworkClient.prefabs.ContainsKey(guid));
+
+ NetworkIdentity netId = validPrefab.GetComponent();
+
+ Assert.AreEqual(netId.assetId, validPrefabGuid);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
+ public void HandlerNewGuid_ErrorDoesNotChangePrefabsAssetId(RegisterPrefabOverload overload)
+ {
+ Guid guid = anotherGuid;
+
+ LogAssert.Expect(LogType.Error, $"Could not register Handler for '{validPrefab.name}' to {guid} because it already had an AssetId, Existing assetId {validPrefabGuid}");
+ CallRegisterPrefab(validPrefab, overload);
+
+ Assert.IsFalse(NetworkClient.spawnHandlers.ContainsKey(guid));
+ Assert.IsFalse(NetworkClient.unspawnHandlers.ContainsKey(guid));
+
+ NetworkIdentity netId = validPrefab.GetComponent();
+
+ Assert.AreEqual(netId.assetId, validPrefabGuid);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
+ public void PrefabNewGuid_NoErrorWhenNewAssetIdIsSameAsCurrentPrefab(RegisterPrefabOverload overload)
+ {
+ Guid guid = validPrefabGuid;
+
+ CallRegisterPrefab(validPrefab, overload, guid);
+
+ Assert.IsTrue(NetworkClient.prefabs.ContainsKey(guid));
+
+ NetworkIdentity netId = validPrefab.GetComponent();
+
+ Assert.AreEqual(netId.assetId, validPrefabGuid);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
+ public void HandlerNewGuid_NoErrorWhenAssetIdIsSameAsCurrentPrefab(RegisterPrefabOverload overload)
+ {
+ Guid guid = validPrefabGuid;
+
+ CallRegisterPrefab(validPrefab, overload, guid);
+
+ Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
+ Assert.IsTrue(NetworkClient.unspawnHandlers.ContainsKey(guid));
+
+ NetworkIdentity netId = validPrefab.GetComponent();
+
+ Assert.AreEqual(netId.assetId, validPrefabGuid);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab)]
+ [TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
+ public void ErrorForNullPrefab(RegisterPrefabOverload overload)
+ {
+ string msg = OverloadWithHandler(overload)
+ ? "Could not register handler for prefab because the prefab was null"
+ : "Could not register prefab because it was null";
+
+ LogAssert.Expect(LogType.Error, msg);
+ CallRegisterPrefab(null, overload);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab)]
+ [TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
+ public void ErrorForPrefabWithoutNetworkIdentity(RegisterPrefabOverload overload)
+ {
+ string msg = OverloadWithHandler(overload)
+ ? $"Could not register handler for '{invalidPrefab.name}' since it contains no NetworkIdentity component"
+ : $"Could not register '{invalidPrefab.name}' since it contains no NetworkIdentity component";
+
+ LogAssert.Expect(LogType.Error, msg);
+ CallRegisterPrefab(invalidPrefab, overload);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
+ public void NewGuid_ErrorForEmptyGuid(RegisterPrefabOverload overload)
+ {
+ string msg = OverloadWithHandler(overload)
+ ? $"Could not register handler for '{validPrefab.name}' with new assetId because the new assetId was empty"
+ : $"Could not register '{validPrefab.name}' with new assetId because the new assetId was empty";
+ LogAssert.Expect(LogType.Error, msg);
+ CallRegisterPrefab(validPrefab, overload, new Guid());
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ public void ErrorIfPrefabHadSceneId(RegisterPrefabOverload overload)
+ {
+ GameObject clone = GameObject.Instantiate(validPrefab);
+ NetworkIdentity netId = clone.GetComponent();
+ // Scene Id needs to not be zero for this test
+ netId.sceneId = 20;
+
+ LogAssert.Expect(LogType.Error, $"Can not Register '{clone.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
+ CallRegisterPrefab(clone, overload);
+
+ GameObject.DestroyImmediate(clone);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ public void ErrorForNetworkIdentityInChildren(RegisterPrefabOverload overload)
+ {
+ LogAssert.Expect(LogType.Error, $"Prefab '{prefabWithChildren.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
+ CallRegisterPrefab(prefabWithChildren, overload);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab)]
+ public void Prefab_WarningForAssetIdAlreadyExistingInPrefabsDictionary(RegisterPrefabOverload overload)
+ {
+ Guid guid = GuidForOverload(overload);
+
+ NetworkClient.prefabs.Add(guid, validPrefab);
+
+ LogAssert.Expect(LogType.Warning, $"Replacing existing prefab with assetId '{guid}'. Old prefab '{validPrefab.name}', New prefab '{validPrefab.name}'");
+ CallRegisterPrefab(validPrefab, overload);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ public void Handler_ErrorForAssetIdAlreadyExistingInPrefabsDictionary(RegisterPrefabOverload overload)
+ {
+ Guid guid = GuidForOverload(overload);
+
+ NetworkClient.prefabs.Add(guid, validPrefab);
+
+ LogAssert.Expect(LogType.Error, $"assetId '{guid}' is already used by prefab '{validPrefab.name}', unregister the prefab first before trying to add handler");
+ CallRegisterPrefab(validPrefab, overload);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ public void WarningForAssetIdAlreadyExistingInHandlersDictionary(RegisterPrefabOverload overload)
+ {
+ Guid guid = GuidForOverload(overload);
+
+ NetworkClient.spawnHandlers.Add(guid, x => null);
+ NetworkClient.unspawnHandlers.Add(guid, x => {});
+
+ string msg = OverloadWithHandler(overload)
+ ? $"Replacing existing spawnHandlers for prefab '{validPrefab.name}' with assetId '{guid}'"
+ : $"Adding prefab '{validPrefab.name}' with assetId '{guid}' when spawnHandlers with same assetId already exists.";
+
+ LogAssert.Expect(LogType.Warning, msg);
+ CallRegisterPrefab(validPrefab, overload);
+ }
+
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ public void SpawnDelegate_AddsHandlerToSpawnHandlers(RegisterPrefabOverload overload)
+ {
+ int handlerCalled = 0;
+
+ Guid guid = GuidForOverload(overload);
+ SpawnDelegate handler = new SpawnDelegate((pos, rot) =>
+ {
+ handlerCalled++;
+ return null;
+ });
+
+ CallRegisterPrefab(validPrefab, overload, handler);
+
+
+ Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
+
+ // check spawnHandler above is called
+ SpawnHandlerDelegate handlerInDictionary = NetworkClient.spawnHandlers[guid];
+ handlerInDictionary.Invoke(default);
+ Assert.That(handlerCalled, Is.EqualTo(1));
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ public void SpawnDelegate_AddsHandlerToSpawnHandlersWithCorrectArguments(RegisterPrefabOverload overload)
+ {
+ int handlerCalled = 0;
+ Vector3 somePosition = new Vector3(10, 20, 3);
+
+ Guid guid = GuidForOverload(overload);
+ SpawnDelegate handler = new SpawnDelegate((pos, assetId) =>
+ {
+ handlerCalled++;
+ Assert.That(pos, Is.EqualTo(somePosition));
+ Assert.That(assetId, Is.EqualTo(guid));
+ return null;
+ });
+
+ CallRegisterPrefab(validPrefab, overload, handler);
+
+ Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
+
+ // check spawnHandler above is called
+ SpawnHandlerDelegate handlerInDictionary = NetworkClient.spawnHandlers[guid];
+ handlerInDictionary.Invoke(new SpawnMessage { position = somePosition, assetId = guid });
+ Assert.That(handlerCalled, Is.EqualTo(1));
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
+ public void SpawnDelegate_ErrorWhenSpawnHandlerIsNull(RegisterPrefabOverload overload)
+ {
+ Guid guid = GuidForOverload(overload);
+ LogAssert.Expect(LogType.Error, $"Can not Register null SpawnHandler for {guid}");
+ CallRegisterPrefab(validPrefab, overload, spawnHandler: null);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ public void SpawnHandleDelegate_AddsHandlerToSpawnHandlers(RegisterPrefabOverload overload)
+ {
+ Guid guid = GuidForOverload(overload);
+
+ SpawnHandlerDelegate handler = new SpawnHandlerDelegate(x => null);
+
+ CallRegisterPrefab(validPrefab, overload, handler);
+
+ Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
+ Assert.AreEqual(NetworkClient.spawnHandlers[guid], handler);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ public void SpawnHandleDelegate_ErrorWhenSpawnHandlerIsNull(RegisterPrefabOverload overload)
+ {
+ Guid guid = GuidForOverload(overload);
+ LogAssert.Expect(LogType.Error, $"Can not Register null SpawnHandler for {guid}");
+ CallRegisterPrefab(validPrefab, overload, spawnHandlerDelegate: null);
+ }
+
+ [Test]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
+ [TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
+ public void Handler_ErrorWhenUnSpawnHandlerIsNull(RegisterPrefabOverload overload)
+ {
+ Guid guid = GuidForOverload(overload);
+ LogAssert.Expect(LogType.Error, $"Can not Register null UnSpawnHandler for {guid}");
+ CallRegisterPrefab(validPrefab, overload, unspawnHandler: null);
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterPrefab.cs.meta b/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterPrefab.cs.meta
new file mode 100644
index 000000000..803aa0ab5
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterPrefab.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bdfdcfafb85b3be418f2085e38663006
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterSpawnHandler.cs b/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterSpawnHandler.cs
new file mode 100644
index 000000000..fce157b0d
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterSpawnHandler.cs
@@ -0,0 +1,224 @@
+using System;
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+
+namespace Mirror.Tests.ClientSceneTests
+{
+ public class ClientSceneTests_RegisterSpawnHandler : ClientSceneTestsBase
+ {
+ [Test]
+ public void SpawnDelegate_AddsHandlerToSpawnHandlers()
+ {
+ int handlerCalled = 0;
+
+ Guid guid = Guid.NewGuid();
+ SpawnDelegate spawnHandler = new SpawnDelegate((pos, rot) =>
+ {
+ handlerCalled++;
+ return null;
+ });
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+
+ Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
+
+ // check spawnHandler above is called
+ SpawnHandlerDelegate handler = NetworkClient.spawnHandlers[guid];
+ handler.Invoke(default);
+ Assert.That(handlerCalled, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void SpawnDelegate_AddsHandlerToSpawnHandlersWithCorrectArguments()
+ {
+ int handlerCalled = 0;
+ Vector3 somePosition = new Vector3(10, 20, 3);
+
+ Guid guid = Guid.NewGuid();
+ SpawnDelegate spawnHandler = new SpawnDelegate((pos, assetId) =>
+ {
+ handlerCalled++;
+ Assert.That(pos, Is.EqualTo(somePosition));
+ Assert.That(assetId, Is.EqualTo(guid));
+ return null;
+ });
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+
+ Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
+
+ // check spawnHandler above is called
+ SpawnHandlerDelegate handler = NetworkClient.spawnHandlers[guid];
+ handler.Invoke(new SpawnMessage { position = somePosition, assetId = guid });
+ Assert.That(handlerCalled, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void SpawnDelegate_AddsHandlerToUnSpawnHandlers()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+
+ Assert.IsTrue(NetworkClient.unspawnHandlers.ContainsKey(guid));
+ Assert.AreEqual(NetworkClient.unspawnHandlers[guid], unspawnHandler);
+ }
+
+ [Test]
+ public void SpawnDelegate_ErrorWhenSpawnHandlerIsNull()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnDelegate spawnHandler = null;
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ LogAssert.Expect(LogType.Error, $"Can not Register null SpawnHandler for {guid}");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+ }
+
+ [Test]
+ public void SpawnDelegate_ErrorWhenUnSpawnHandlerIsNull()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
+ UnSpawnDelegate unspawnHandler = null;
+
+ LogAssert.Expect(LogType.Error, $"Can not Register null UnSpawnHandler for {guid}");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+ }
+
+ [Test]
+ public void SpawnDelegate_ErrorWhenAssetIdIsEmpty()
+ {
+ Guid guid = new Guid();
+ SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ LogAssert.Expect(LogType.Error, "Can not Register SpawnHandler for empty Guid");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+ }
+
+ [Test]
+ public void SpawnDelegate_WarningWhenHandlerForGuidAlreadyExistsInHandlerDictionary()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+
+ SpawnDelegate spawnHandler2 = new SpawnDelegate((x, y) => new GameObject());
+ UnSpawnDelegate unspawnHandler2 = new UnSpawnDelegate(x => UnityEngine.Object.Destroy(x));
+
+ LogAssert.Expect(LogType.Warning, $"Replacing existing spawnHandlers for {guid}");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler2, unspawnHandler2);
+ }
+
+ [Test]
+ public void SpawnDelegate_ErrorWhenHandlerForGuidAlreadyExistsInPrefabDictionary()
+ {
+ Guid guid = Guid.NewGuid();
+ NetworkClient.prefabs.Add(guid, validPrefab);
+
+ SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ LogAssert.Expect(LogType.Error, $"assetId '{guid}' is already used by prefab '{validPrefab.name}'");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+ }
+
+
+ [Test]
+ public void SpawnHandlerDelegate_AddsHandlerToSpawnHandlers()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+
+ Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
+ Assert.AreEqual(NetworkClient.spawnHandlers[guid], spawnHandler);
+ }
+
+ [Test]
+ public void SpawnHandlerDelegate_AddsHandlerToUnSpawnHandlers()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+
+ Assert.IsTrue(NetworkClient.unspawnHandlers.ContainsKey(guid));
+ Assert.AreEqual(NetworkClient.unspawnHandlers[guid], unspawnHandler);
+ }
+
+ [Test]
+ public void SpawnHandlerDelegate_ErrorWhenSpawnHandlerIsNull()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnHandlerDelegate spawnHandler = null;
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ LogAssert.Expect(LogType.Error, $"Can not Register null SpawnHandler for {guid}");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+ }
+
+ [Test]
+ public void SpawnHandlerDelegate_ErrorWhenUnSpawnHandlerIsNull()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
+ UnSpawnDelegate unspawnHandler = null;
+
+ LogAssert.Expect(LogType.Error, $"Can not Register null UnSpawnHandler for {guid}");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+ }
+
+ [Test]
+ public void SpawnHandlerDelegate_ErrorWhenAssetIdIsEmpty()
+ {
+ Guid guid = new Guid();
+ SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ LogAssert.Expect(LogType.Error, "Can not Register SpawnHandler for empty Guid");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+ }
+
+ [Test]
+ public void SpawnHandlerDelegate_WarningWhenHandlerForGuidAlreadyExistsInHandlerDictionary()
+ {
+ Guid guid = Guid.NewGuid();
+ SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
+
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+
+ SpawnHandlerDelegate spawnHandler2 = new SpawnHandlerDelegate(x => new GameObject());
+ UnSpawnDelegate unspawnHandler2 = new UnSpawnDelegate(x => UnityEngine.Object.Destroy(x));
+
+ LogAssert.Expect(LogType.Warning, $"Replacing existing spawnHandlers for {guid}");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler2, unspawnHandler2);
+ }
+
+ [Test]
+ public void SpawnHandlerDelegate_ErrorWhenHandlerForGuidAlreadyExistsInPrefabDictionary()
+ {
+ Guid guid = Guid.NewGuid();
+ NetworkClient.prefabs.Add(guid, validPrefab);
+
+ SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => new GameObject());
+ UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => UnityEngine.Object.Destroy(x));
+
+ LogAssert.Expect(LogType.Error, $"assetId '{guid}' is already used by prefab '{validPrefab.name}'");
+ NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
+ }
+
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterSpawnHandler.cs.meta b/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterSpawnHandler.cs.meta
new file mode 100644
index 000000000..ec826b7c5
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterSpawnHandler.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c7e6577e8c2e64e41ae255edc61e91a2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterPrefab.cs b/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterPrefab.cs
new file mode 100644
index 000000000..ec1b7a6a5
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterPrefab.cs
@@ -0,0 +1,48 @@
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+
+namespace Mirror.Tests.ClientSceneTests
+{
+ public class ClientSceneTests_UnregisterPrefab : ClientSceneTestsBase
+ {
+ [Test]
+ public void RemovesPrefabFromDictionary()
+ {
+ NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
+ NetworkClient.UnregisterPrefab(validPrefab);
+ Assert.IsFalse(NetworkClient.prefabs.ContainsKey(validPrefabGuid));
+ }
+
+ [Test]
+ public void RemovesSpawnHandlerFromDictionary()
+ {
+ NetworkClient.spawnHandlers.Add(validPrefabGuid, new SpawnHandlerDelegate(x => null));
+ NetworkClient.UnregisterPrefab(validPrefab);
+ Assert.IsFalse(NetworkClient.spawnHandlers.ContainsKey(validPrefabGuid));
+ }
+
+ [Test]
+ public void RemovesUnSpawnHandlerFromDictionary()
+ {
+ NetworkClient.unspawnHandlers.Add(validPrefabGuid, new UnSpawnDelegate(x => {}));
+ NetworkClient.UnregisterPrefab(validPrefab);
+ Assert.IsFalse(NetworkClient.unspawnHandlers.ContainsKey(validPrefabGuid));
+ }
+
+ [Test]
+ public void ErrorWhenPrefabIsNull()
+ {
+ LogAssert.Expect(LogType.Error, "Could not unregister prefab because it was null");
+ NetworkClient.UnregisterPrefab(null);
+ }
+
+ [Test]
+ public void ErrorWhenPrefabHasNoNetworkIdentity()
+ {
+ LogAssert.Expect(LogType.Error, $"Could not unregister '{invalidPrefab.name}' since it contains no NetworkIdentity component");
+ NetworkClient.UnregisterPrefab(invalidPrefab);
+ }
+
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterPrefab.cs.meta b/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterPrefab.cs.meta
new file mode 100644
index 000000000..8478bffbc
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterPrefab.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: aa6fa692d80eaf8419e559c35034f016
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterSpawnHandler.cs b/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterSpawnHandler.cs
new file mode 100644
index 000000000..7e1f6e3d3
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterSpawnHandler.cs
@@ -0,0 +1,33 @@
+using NUnit.Framework;
+
+namespace Mirror.Tests.ClientSceneTests
+{
+ public class ClientSceneTests_UnregisterSpawnHandler : ClientSceneTestsBase
+ {
+ [Test]
+ public void RemovesSpawnHandlersFromDictionary()
+ {
+ NetworkClient.spawnHandlers.Add(validPrefabGuid, new SpawnHandlerDelegate(x => null));
+ NetworkClient.UnregisterSpawnHandler(validPrefabGuid);
+ Assert.IsFalse(NetworkClient.unspawnHandlers.ContainsKey(validPrefabGuid));
+ }
+
+ [Test]
+ public void RemovesUnSpawnHandlersFromDictionary()
+ {
+ NetworkClient.unspawnHandlers.Add(validPrefabGuid, new UnSpawnDelegate(x => {}));
+ NetworkClient.UnregisterSpawnHandler(validPrefabGuid);
+ Assert.IsFalse(NetworkClient.unspawnHandlers.ContainsKey(validPrefabGuid));
+ }
+
+ [Test]
+ public void DoesNotRemovePrefabDictionary()
+ {
+ NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
+ NetworkClient.UnregisterSpawnHandler(validPrefabGuid);
+ // Should not be removed
+ Assert.IsTrue(NetworkClient.prefabs.ContainsKey(validPrefabGuid));
+ }
+
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterSpawnHandler.cs.meta b/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterSpawnHandler.cs.meta
new file mode 100644
index 000000000..006dad00a
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ClientSceneTests_UnregisterSpawnHandler.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 49ef76b8883ba3845942503683c9a9b3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/CommandOverrideTest.cs b/Assets/Mirror/Tests/Editor/CommandOverrideTest.cs
new file mode 100644
index 000000000..c9c57d54e
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/CommandOverrideTest.cs
@@ -0,0 +1,182 @@
+using System;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests.RemoteAttrributeTest
+{
+ class VirtualCommand : NetworkBehaviour
+ {
+ public event Action onVirtualSendInt;
+
+ [Command]
+ public virtual void CmdSendInt(int someInt) =>
+ onVirtualSendInt?.Invoke(someInt);
+ }
+
+ class VirtualNoOverrideCommand : VirtualCommand {}
+
+ class VirtualOverrideCommand : VirtualCommand
+ {
+ public event Action onOverrideSendInt;
+
+ [Command]
+ public override void CmdSendInt(int someInt) =>
+ onOverrideSendInt?.Invoke(someInt);
+ }
+
+ class VirtualOverrideCommandWithBase : VirtualCommand
+ {
+ public event Action onOverrideSendInt;
+
+ [Command]
+ public override void CmdSendInt(int someInt)
+ {
+ base.CmdSendInt(someInt);
+ onOverrideSendInt?.Invoke(someInt);
+ }
+ }
+
+ // test for 2 overrides
+ class VirtualOverrideCommandWithBase2 : VirtualOverrideCommandWithBase
+ {
+ public event Action onOverrideSendInt2;
+
+ [Command]
+ public override void CmdSendInt(int someInt)
+ {
+ base.CmdSendInt(someInt);
+ onOverrideSendInt2?.Invoke(someInt);
+ }
+ }
+
+ public class CommandOverrideTest : RemoteTestBase
+ {
+ [Test]
+ public void VirtualCommandIsCalled()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualCommand hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void VirtualCommandWithNoOverrideIsCalled()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualNoOverrideCommand hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void OverrideVirtualCommandIsCalled()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideCommand hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ int overrideCallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ };
+ hostBehaviour.onOverrideSendInt += incomingInt =>
+ {
+ overrideCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(0));
+ Assert.That(overrideCallCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void OverrideVirtualWithBaseCallsBothVirtualAndBase()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideCommandWithBase hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ int overrideCallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.onOverrideSendInt += incomingInt =>
+ {
+ overrideCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(1));
+ Assert.That(overrideCallCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void OverrideVirtualWithBaseCallsAllMethodsThatCallBase()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideCommandWithBase2 hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int virtualCallCount = 0;
+ int overrideCallCount = 0;
+ int override2CallCount = 0;
+ hostBehaviour.onVirtualSendInt += incomingInt =>
+ {
+ virtualCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.onOverrideSendInt += incomingInt =>
+ {
+ overrideCallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.onOverrideSendInt2 += incomingInt =>
+ {
+ override2CallCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+
+
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(virtualCallCount, Is.EqualTo(1));
+ Assert.That(overrideCallCount, Is.EqualTo(1));
+ Assert.That(override2CallCount, Is.EqualTo(1));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/CommandOverrideTest.cs.meta b/Assets/Mirror/Tests/Editor/CommandOverrideTest.cs.meta
new file mode 100644
index 000000000..2afb7834e
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/CommandOverrideTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 881c801c26e90df43b3558a23c96e0ea
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/CommandTest.cs b/Assets/Mirror/Tests/Editor/CommandTest.cs
new file mode 100644
index 000000000..3c6b4b884
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/CommandTest.cs
@@ -0,0 +1,247 @@
+using System;
+using System.Text.RegularExpressions;
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+
+namespace Mirror.Tests.RemoteAttrributeTest
+{
+ class AuthorityBehaviour : NetworkBehaviour
+ {
+ public event Action onSendInt;
+
+ [Command]
+ public void SendInt(int someInt) =>
+ onSendInt?.Invoke(someInt);
+ }
+
+ class IgnoreAuthorityBehaviour : NetworkBehaviour
+ {
+ public event Action onSendInt;
+
+ [Command(requiresAuthority = false)]
+ public void CmdSendInt(int someInt) =>
+ onSendInt?.Invoke(someInt);
+ }
+
+ class SenderConnectionBehaviour : NetworkBehaviour
+ {
+ public event Action onSendInt;
+
+ [Command]
+ public void CmdSendInt(int someInt, NetworkConnectionToClient conn = null) =>
+ onSendInt?.Invoke(someInt, conn);
+ }
+
+ class SenderConnectionIgnoreAuthorityBehaviour : NetworkBehaviour
+ {
+ public event Action onSendInt;
+
+ [Command(requiresAuthority = false)]
+ public void CmdSendInt(int someInt, NetworkConnectionToClient conn = null) =>
+ onSendInt?.Invoke(someInt, conn);
+ }
+
+ class ThrowBehaviour : NetworkBehaviour
+ {
+ public const string ErrorMessage = "Bad things happened";
+
+ [Command]
+ public void SendThrow(int _) => throw new Exception(ErrorMessage);
+ }
+
+ class CommandOverloads : NetworkBehaviour
+ {
+ public int firstCalled = 0;
+ public int secondCalled = 0;
+
+ [Command]
+ public void TheCommand(int _) => ++firstCalled;
+
+ [Command]
+ public void TheCommand(string _) => ++secondCalled;
+ }
+
+ public class CommandTest : RemoteTestBase
+ {
+ [Test]
+ public void CommandIsSentWithAuthority()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out _, out _, out AuthorityBehaviour hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int callCount = 0;
+ hostBehaviour.onSendInt += incomingInt =>
+ {
+ callCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.SendInt(someInt);
+ ProcessMessages();
+ Assert.That(callCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void WarningForCommandSentWithoutAuthority()
+ {
+ // spawn without owner
+ CreateNetworkedAndSpawn(out _, out _, out AuthorityBehaviour hostBehaviour);
+
+ const int someInt = 20;
+
+ int callCount = 0;
+ hostBehaviour.onSendInt += incomingInt =>
+ {
+ callCount++;
+ };
+ LogAssert.Expect(LogType.Warning, $"Trying to send command for object without authority. System.Void Mirror.Tests.RemoteAttrributeTest.AuthorityBehaviour::SendInt(System.Int32)");
+ hostBehaviour.SendInt(someInt);
+ ProcessMessages();
+ Assert.That(callCount, Is.Zero);
+ }
+
+
+ [Test]
+ public void CommandIsSentWithAuthorityWhenIgnoringAuthority()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out _, out _, out IgnoreAuthorityBehaviour hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+
+ int callCount = 0;
+ hostBehaviour.onSendInt += incomingInt =>
+ {
+ callCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(callCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void CommandIsSentWithoutAuthorityWhenIgnoringAuthority()
+ {
+ // spawn without owner
+ CreateNetworkedAndSpawn(out _, out _, out IgnoreAuthorityBehaviour hostBehaviour);
+
+ const int someInt = 20;
+
+ int callCount = 0;
+ hostBehaviour.onSendInt += incomingInt =>
+ {
+ callCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ };
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(callCount, Is.EqualTo(1));
+ }
+
+ // test to prevent https://github.com/vis2k/Mirror/issues/2629
+ // from happening again in the future
+ // -> [Command]s can be called on other objects with requiresAuthority=false.
+ // -> those objects don't have a .connectionToServer
+ // -> we broke it when using .connectionToServer instead of
+ // NetworkClient.connection in SendCommandInternal.
+ [Test]
+ public void Command_RequiresAuthorityFalse_ForOtherObjectWithoutConnectionToServer()
+ {
+ // spawn without owner (= without connectionToClient)
+ CreateNetworkedAndSpawn(out _, out _, out IgnoreAuthorityBehaviour comp);
+
+ // setup callback
+ int called = 0;
+ comp.onSendInt += _ => { ++called; };
+
+ // call command. don't require authority.
+ // the object doesn't have a .connectionToServer (like a scene object)
+ Assert.That(comp.connectionToServer, Is.Null);
+ comp.CmdSendInt(0);
+ Assert.That(called, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void SenderConnectionIsSetWhenCommandIsRecieved()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out _, out _, out SenderConnectionBehaviour hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+ NetworkConnectionToClient connectionToClient = NetworkServer.connections[0];
+ Debug.Assert(connectionToClient != null, $"connectionToClient was null, This means that the test is broken and will give the wrong results");
+
+
+ int callCount = 0;
+ hostBehaviour.onSendInt += (incomingInt, incomingConn) =>
+ {
+ callCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ Assert.That(incomingConn, Is.EqualTo(connectionToClient));
+ };
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(callCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void SenderConnectionIsSetWhenCommandIsRecievedWithIgnoreAuthority()
+ {
+ // spawn without owner
+ CreateNetworkedAndSpawn(out _, out _, out SenderConnectionIgnoreAuthorityBehaviour hostBehaviour);
+
+ const int someInt = 20;
+ NetworkConnectionToClient connectionToClient = NetworkServer.connections[0];
+ Debug.Assert(connectionToClient != null, $"connectionToClient was null, This means that the test is broken and will give the wrong results");
+
+ int callCount = 0;
+ hostBehaviour.onSendInt += (incomingInt, incomingConn) =>
+ {
+ callCount++;
+ Assert.That(incomingInt, Is.EqualTo(someInt));
+ Assert.That(incomingConn, Is.EqualTo(connectionToClient));
+ };
+ hostBehaviour.CmdSendInt(someInt);
+ ProcessMessages();
+ Assert.That(callCount, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void CommandThatThrowsShouldBeCaught()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out _, out _, out ThrowBehaviour hostBehaviour, NetworkServer.localConnection);
+
+ const int someInt = 20;
+ NetworkConnectionToClient connectionToClient = NetworkServer.connections[0];
+ Debug.Assert(connectionToClient != null, $"connectionToClient was null, This means that the test is broken and will give the wrong results");
+
+ LogAssert.Expect(LogType.Error, new Regex($".*{ThrowBehaviour.ErrorMessage}.*"));
+ Assert.DoesNotThrow(() =>
+ {
+ hostBehaviour.SendThrow(someInt);
+ ProcessMessages();
+ }, "Processing new message should not throw, the exception from SendThrow should be caught");
+ }
+
+ // RemoteCalls uses md.FullName which gives us the full command/rpc name
+ // like "System.Void Mirror.Tests.RemoteAttrributeTest.AuthorityBehaviour::SendInt(System.Int32)"
+ // which means overloads with same name but different types should work.
+ [Test]
+ public void CommandOverloads()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out _, out _, out CommandOverloads comp, NetworkServer.localConnection);
+
+ // call both overloads once
+ comp.TheCommand(42);
+ comp.TheCommand("A");
+ ProcessMessages();
+ Assert.That(comp.firstCalled, Is.EqualTo(1));
+ Assert.That(comp.secondCalled, Is.EqualTo(1));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/CommandTest.cs.meta b/Assets/Mirror/Tests/Editor/CommandTest.cs.meta
new file mode 100644
index 000000000..4d4917ddf
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/CommandTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1dd3f8a95eee6f74997bc8abcd43a401
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/CompressionTests.cs b/Assets/Mirror/Tests/Editor/CompressionTests.cs
new file mode 100644
index 000000000..b03ec36f0
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/CompressionTests.cs
@@ -0,0 +1,257 @@
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ public class CompressionTests
+ {
+ [Test]
+ public void LargestAbsoluteComponentIndex()
+ {
+ // positive value & xyw smallest
+ Vector4 value = new Vector4(1, 3, 4, 2);
+ int index = Compression.LargestAbsoluteComponentIndex(value, out float largest, out Vector3 withoutLargest);
+ Assert.That(index, Is.EqualTo(2));
+ Assert.That(largest, Is.EqualTo(Mathf.Abs(value.z)));
+ Assert.That(withoutLargest, Is.EqualTo(new Vector3(value.x, value.y, value.w)));
+
+ // negative value should use abs & xzw smallest
+ value = new Vector4(1, -5, 4, 0);
+ index = Compression.LargestAbsoluteComponentIndex(value, out largest, out withoutLargest);
+ Assert.That(index, Is.EqualTo(1));
+ Assert.That(largest, Is.EqualTo(Mathf.Abs(value.y)));
+ Assert.That(withoutLargest, Is.EqualTo(new Vector3(value.x, value.z, value.w)));
+
+ // positive value & yzw smallest
+ value = new Vector4(5, 2, 3, 4);
+ index = Compression.LargestAbsoluteComponentIndex(value, out largest, out withoutLargest);
+ Assert.That(index, Is.EqualTo(0));
+ Assert.That(largest, Is.EqualTo(Mathf.Abs(value.x)));
+ Assert.That(withoutLargest, Is.EqualTo(new Vector3(value.y, value.z, value.w)));
+
+ // test to guarantee it uses 'abs' for first value
+ // to reproduce https://github.com/vis2k/Mirror/issues/2674
+ // IF all values are properly 'abs', THEN first one should be largest
+ value = new Vector4(-3, 0, 1, 2);
+ index = Compression.LargestAbsoluteComponentIndex(value, out largest, out withoutLargest);
+ Assert.That(index, Is.EqualTo(0));
+ Assert.That(largest, Is.EqualTo(Mathf.Abs(value.x)));
+ Assert.That(withoutLargest, Is.EqualTo(new Vector3(value.y, value.z, value.w)));
+ }
+
+ [Test, Ignore("Enable when needed.")]
+ public void LargestAbsoluteComponentIndexBenchmark()
+ {
+ Vector4 value = new Vector4(1, 2, 3, 4);
+ for (int i = 0; i < 100000; ++i)
+ Compression.LargestAbsoluteComponentIndex(value, out float _, out Vector3 _);
+ }
+
+ [Test]
+ public void ScaleFloatToUShort()
+ {
+ Assert.That(Compression.ScaleFloatToUShort(-1f, -1f, 1f, ushort.MinValue, ushort.MaxValue), Is.EqualTo(0));
+ Assert.That(Compression.ScaleFloatToUShort(0f, -1f, 1f, ushort.MinValue, ushort.MaxValue), Is.EqualTo(32767));
+ Assert.That(Compression.ScaleFloatToUShort(0.5f, -1f, 1f, ushort.MinValue, ushort.MaxValue), Is.EqualTo(49151));
+ Assert.That(Compression.ScaleFloatToUShort(1f, -1f, 1f, ushort.MinValue, ushort.MaxValue), Is.EqualTo(65535));
+ }
+
+ [Test]
+ public void ScaleUShortToFloat()
+ {
+ Assert.That(Compression.ScaleUShortToFloat(0, ushort.MinValue, ushort.MaxValue, -1, 1), Is.EqualTo(-1).Within(0.0001f));
+ Assert.That(Compression.ScaleUShortToFloat(32767, ushort.MinValue, ushort.MaxValue, -1, 1), Is.EqualTo(-0f).Within(0.0001f));
+ Assert.That(Compression.ScaleUShortToFloat(49151, ushort.MinValue, ushort.MaxValue, -1, 1), Is.EqualTo(0.5f).Within(0.0001f));
+ Assert.That(Compression.ScaleUShortToFloat(65535, ushort.MinValue, ushort.MaxValue, -1, 1), Is.EqualTo(1).Within(0.0001f));
+ }
+
+ [Test]
+ public void CompressAndDecompressQuaternion()
+ {
+ // we need a normalized value
+ Quaternion value = new Quaternion(1, 3, 4, 2).normalized;
+
+ // compress
+ uint data = Compression.CompressQuaternion(value);
+ Assert.That(data, Is.EqualTo(0xA83E2F07));
+
+ // decompress
+ Quaternion decompressed = Compression.DecompressQuaternion(data);
+ Assert.That(decompressed.x, Is.EqualTo(value.x).Within(0.005f));
+ Assert.That(decompressed.y, Is.EqualTo(value.y).Within(0.005f));
+ Assert.That(decompressed.z, Is.EqualTo(value.z).Within(0.005f));
+ Assert.That(decompressed.w, Is.EqualTo(value.w).Within(0.005f));
+ }
+
+ // iterate all [0..360] euler angles for x, y, z
+ // to make sure it all works and we missed nothing.
+ [Test]
+ public void CompressAndDecompressQuaternion_Iterate_0_to_360()
+ {
+ // stepSize 1: 360 * 360 * 360 = 46 million [takes 96 s]
+ // stepSize 5: 72 * 72 * 72 = 373 thousand [takes 700 ms]
+ // stepSize 10: 36 * 36 * 36 = 46 thousand [takes 100 ms]
+ //
+ // => 10 is enough. 700ms accumulates in hours of time waited over
+ // the years..
+ const int stepSize = 10;
+
+ for (int x = 0; x <= 360; x += stepSize)
+ {
+ for (int y = 0; y <= 360; y += stepSize)
+ {
+ for (int z = 0; z <= 360; z += stepSize)
+ {
+ // we need a normalized value
+ Quaternion value = Quaternion.Euler(x, y, z).normalized;
+
+ // compress
+ uint data = Compression.CompressQuaternion(value);
+
+ // decompress
+ Quaternion decompressed = Compression.DecompressQuaternion(data);
+
+ // compare them. Quaternion.Angle is easiest to get the angle
+ // between them. using .eulerAngles would give 0, 90, 360 which is
+ // hard to compare.
+ float angle = Quaternion.Angle(value, decompressed);
+ // 1 degree tolerance
+ Assert.That(Mathf.Abs(angle), Is.LessThanOrEqualTo(1));
+ }
+ }
+ }
+ }
+
+ // someone mentioned issues with 90 degree euler becoming -90 degree
+ [Test]
+ public void CompressAndDecompressQuaternion_90DegreeEuler()
+ {
+ // we need a normalized value
+ Quaternion value = Quaternion.Euler(0, 90, 0).normalized;
+
+ // compress
+ uint data = Compression.CompressQuaternion(value);
+
+ // decompress
+ Quaternion decompressed = Compression.DecompressQuaternion(data);
+
+ // compare them. Quaternion.Angle is easiest to get the angle
+ // between them. using .eulerAngles would give 0, 90, 360 which is
+ // hard to compare.
+ Debug.Log($"euler={decompressed.eulerAngles}");
+ float angle = Quaternion.Angle(value, decompressed);
+ // 1 degree tolerance
+ Assert.That(Mathf.Abs(angle), Is.LessThanOrEqualTo(1));
+ }
+
+ // test for issue https://github.com/vis2k/Mirror/issues/2674
+ [Test]
+ public void CompressAndDecompressQuaternion_2674()
+ {
+ // we need a normalized value
+ Quaternion value = Quaternion.Euler(338.850037f, 170.609955f, 182.979996f).normalized;
+ Debug.Log($"original={value.eulerAngles}");
+
+ // compress
+ uint data = Compression.CompressQuaternion(value);
+
+ // decompress
+ Quaternion decompressed = Compression.DecompressQuaternion(data);
+
+ // compare them. Quaternion.Angle is easiest to get the angle
+ // between them. using .eulerAngles would give 0, 90, 360 which is
+ // hard to compare.
+
+ // (51.6, 355.5, 348.1)
+ Debug.Log($"euler={decompressed.eulerAngles}");
+ float angle = Quaternion.Angle(value, decompressed);
+ // 1 degree tolerance
+ Assert.That(Mathf.Abs(angle), Is.LessThanOrEqualTo(1));
+ }
+
+ // client sending invalid data should still produce valid quaternions to
+ // avoid any possible bugs on server
+ [Test]
+ public void DecompressQuaternionInvalidData()
+ {
+ // decompress
+ // 0xFFFFFFFF will decompress to (0.7, 0.7, 0.7, NaN)
+ Quaternion decompressed = Compression.DecompressQuaternion(0xFFFFFFFF);
+ Assert.That(decompressed, Is.EqualTo(Quaternion.identity));
+ }
+
+ [Test]
+ public void VarInt()
+ {
+ NetworkWriter writer = new NetworkWriter();
+ Compression.CompressVarUInt(writer, 0);
+ Compression.CompressVarUInt(writer, 234);
+ Compression.CompressVarUInt(writer, 2284);
+ Compression.CompressVarUInt(writer, 67821);
+ Compression.CompressVarUInt(writer, 16777210);
+ Compression.CompressVarUInt(writer, 16777219);
+ Compression.CompressVarUInt(writer, 4294967295);
+ Compression.CompressVarUInt(writer, 1099511627775);
+ Compression.CompressVarUInt(writer, 281474976710655);
+ Compression.CompressVarUInt(writer, 72057594037927935);
+ Compression.CompressVarUInt(writer, ulong.MaxValue);
+
+ Compression.CompressVarInt(writer, long.MinValue);
+ Compression.CompressVarInt(writer, -72057594037927935);
+ Compression.CompressVarInt(writer, -281474976710655);
+ Compression.CompressVarInt(writer, -1099511627775);
+ Compression.CompressVarInt(writer, -4294967295);
+ Compression.CompressVarInt(writer, -16777219);
+ Compression.CompressVarInt(writer, -16777210);
+ Compression.CompressVarInt(writer, -67821);
+ Compression.CompressVarInt(writer, -2284);
+ Compression.CompressVarInt(writer, -234);
+ Compression.CompressVarInt(writer, 0);
+ Compression.CompressVarInt(writer, 234);
+ Compression.CompressVarInt(writer, 2284);
+ Compression.CompressVarInt(writer, 67821);
+ Compression.CompressVarInt(writer, 16777210);
+ Compression.CompressVarInt(writer, 16777219);
+ Compression.CompressVarInt(writer, 4294967295);
+ Compression.CompressVarInt(writer, 1099511627775);
+ Compression.CompressVarInt(writer, 281474976710655);
+ Compression.CompressVarInt(writer, 72057594037927935);
+ Compression.CompressVarInt(writer, long.MaxValue);
+
+ NetworkReader reader = new NetworkReader(writer.ToArray());
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(0));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(234));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(2284));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(67821));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(16777210));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(16777219));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(4294967295));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(1099511627775));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(281474976710655));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(72057594037927935));
+ Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(ulong.MaxValue));
+
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(long.MinValue));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-72057594037927935));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-281474976710655));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-1099511627775));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-4294967295));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-16777219));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-16777210));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-67821));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-2284));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-234));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(0));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(234));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(2284));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(67821));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(16777210));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(16777219));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(4294967295));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(1099511627775));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(281474976710655));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(72057594037927935));
+ Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(long.MaxValue));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/CompressionTests.cs.meta b/Assets/Mirror/Tests/Editor/CompressionTests.cs.meta
new file mode 100644
index 000000000..b1487c00a
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/CompressionTests.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 541cf2bc89fe4395b2a50d921c91424a
+timeCreated: 1613190697
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/CustomRWTest.cs b/Assets/Mirror/Tests/Editor/CustomRWTest.cs
new file mode 100644
index 000000000..3b015b383
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/CustomRWTest.cs
@@ -0,0 +1,53 @@
+using NUnit.Framework;
+
+namespace Mirror.Tests
+{
+ public class MockQuest
+ {
+ public int Id;
+
+ public MockQuest(int id)
+ {
+ Id = id;
+ }
+
+ public MockQuest()
+ {
+ Id = 0;
+ }
+ }
+
+ public static class MockQuestReaderWriter
+ {
+ public static void WriteQuest(this NetworkWriter writer, MockQuest quest)
+ {
+ writer.WriteInt(quest.Id);
+ }
+ public static MockQuest WriteQuest(this NetworkReader reader)
+ {
+ return new MockQuest(reader.ReadInt());
+ }
+ }
+
+ [TestFixture]
+ public class CustomRWTest
+ {
+ public struct QuestMessage : NetworkMessage
+ {
+ public MockQuest quest;
+ }
+
+ [Test]
+ public void TestCustomRW()
+ {
+ QuestMessage message = new QuestMessage
+ {
+ quest = new MockQuest(100)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+ QuestMessage unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ Assert.That(unpacked.quest.Id, Is.EqualTo(100));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/CustomRWTest.cs.meta b/Assets/Mirror/Tests/Editor/CustomRWTest.cs.meta
new file mode 100644
index 000000000..d1adf21d0
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/CustomRWTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3d74d53ca2c8c4b1195833376f9f6bb6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs b/Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs
new file mode 100644
index 000000000..a37e18245
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs
@@ -0,0 +1,91 @@
+using NUnit.Framework;
+
+namespace Mirror.Tests
+{
+ public static class MyCustomEnumReadWrite
+ {
+ public static void WriteMyCustomEnum(this NetworkWriter networkWriter, EnumReadWriteTests.MyCustomEnum customEnum)
+ {
+ // if O write N
+ if (customEnum == EnumReadWriteTests.MyCustomEnum.O)
+ {
+ networkWriter.WriteInt((int)EnumReadWriteTests.MyCustomEnum.N);
+ }
+ else
+ {
+ networkWriter.WriteInt((int)customEnum);
+ }
+ }
+ public static EnumReadWriteTests.MyCustomEnum ReadMyCustomEnum(this NetworkReader networkReader)
+ {
+ return (EnumReadWriteTests.MyCustomEnum)networkReader.ReadInt();
+ }
+ }
+ public class EnumReadWriteTests
+ {
+ public struct ByteMessage : NetworkMessage { public MyByteEnum byteEnum; }
+ public enum MyByteEnum : byte
+ {
+ A, B, C, D
+ }
+
+ public struct ShortMessage : NetworkMessage { public MyShortEnum shortEnum; }
+ public enum MyShortEnum : short
+ {
+ E, F, G, H
+ }
+
+ public struct CustomMessage : NetworkMessage { public MyCustomEnum customEnum; }
+
+ public enum MyCustomEnum
+ {
+ M, N, O, P
+ }
+
+
+ [Test]
+ public void ByteIsSentForByteEnum()
+ {
+ ByteMessage msg = new ByteMessage() { byteEnum = MyByteEnum.B };
+
+ NetworkWriter writer = new NetworkWriter();
+ writer.Write(msg);
+
+ // should be 1 byte for data
+ Assert.That(writer.Position, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void ShortIsSentForShortEnum()
+ {
+ ShortMessage msg = new ShortMessage() { shortEnum = MyShortEnum.G };
+
+ NetworkWriter writer = new NetworkWriter();
+ writer.Write(msg);
+
+ // should be 2 bytes for data
+ Assert.That(writer.Position, Is.EqualTo(2));
+ }
+
+ [Test]
+ public void CustomWriterIsUsedForEnum()
+ {
+ CustomMessage serverMsg = new CustomMessage() { customEnum = MyCustomEnum.O };
+ CustomMessage clientMsg = SerializeAndDeserializeMessage(serverMsg);
+
+ // custom writer should write N if it sees O
+ Assert.That(clientMsg.customEnum, Is.EqualTo(MyCustomEnum.N));
+ }
+ T SerializeAndDeserializeMessage(T msg)
+ where T : struct, NetworkMessage
+ {
+ NetworkWriter writer = new NetworkWriter();
+
+ writer.Write(msg);
+
+ NetworkReader reader = new NetworkReader(writer.ToArraySegment());
+
+ return reader.Read();
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs.meta b/Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs.meta
new file mode 100644
index 000000000..5832f084c
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 79e6cd90456eed340a72b1bdb6fe7e49
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ExponentialMovingAverageTest.cs b/Assets/Mirror/Tests/Editor/ExponentialMovingAverageTest.cs
new file mode 100644
index 000000000..3b55264c4
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ExponentialMovingAverageTest.cs
@@ -0,0 +1,42 @@
+using NUnit.Framework;
+namespace Mirror.Tests
+{
+ [TestFixture]
+ public class ExponentialMovingAverageTest
+ {
+ [Test]
+ public void TestInitial()
+ {
+ ExponentialMovingAverage ema = new ExponentialMovingAverage(10);
+
+ ema.Add(3);
+
+ Assert.That(ema.Value, Is.EqualTo(3));
+ Assert.That(ema.Var, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void TestMovingAverage()
+ {
+ ExponentialMovingAverage ema = new ExponentialMovingAverage(10);
+
+ ema.Add(5);
+ ema.Add(6);
+
+ Assert.That(ema.Value, Is.EqualTo(5.1818).Within(0.0001f));
+ Assert.That(ema.Var, Is.EqualTo(0.1487).Within(0.0001f));
+ }
+
+ [Test]
+ public void TestVar()
+ {
+ ExponentialMovingAverage ema = new ExponentialMovingAverage(10);
+
+ ema.Add(5);
+ ema.Add(6);
+ ema.Add(7);
+
+ Assert.That(ema.Var, Is.EqualTo(0.6134).Within(0.0001f));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ExponentialMovingAverageTest.cs.meta b/Assets/Mirror/Tests/Editor/ExponentialMovingAverageTest.cs.meta
new file mode 100644
index 000000000..535f33d77
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ExponentialMovingAverageTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8e3f2ecadd13149f29cd3e83ef6a4bff
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/ExtensionsTest.cs b/Assets/Mirror/Tests/Editor/ExtensionsTest.cs
new file mode 100644
index 000000000..ef1e0d8ab
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ExtensionsTest.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+
+namespace Mirror.Tests
+{
+ public class ExtensionsTest
+ {
+ // supposed to return same result on all platforms
+ [Test]
+ public void GetStableHashHode()
+ {
+ Assert.That("".GetStableHashCode(), Is.EqualTo(23));
+ Assert.That("Test".GetStableHashCode(), Is.EqualTo(23844169));
+ }
+
+ [Test]
+ public void CopyToList()
+ {
+ List source = new List{1, 2, 3};
+ List destination = new List();
+ source.CopyTo(destination);
+ Assert.That(destination.SequenceEqual(source), Is.True);
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/ExtensionsTest.cs.meta b/Assets/Mirror/Tests/Editor/ExtensionsTest.cs.meta
new file mode 100644
index 000000000..bc31df854
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/ExtensionsTest.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 21e1452d6f734618a9364a2c6c116922
+timeCreated: 1621762116
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs b/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs
new file mode 100644
index 000000000..8d1ee0fe7
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs
@@ -0,0 +1,56 @@
+using System;
+using Mirror.Tests.RemoteAttrributeTest;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests.GeneratedWriterTests
+{
+ public class BaseData
+ {
+ public bool toggle;
+ }
+ public class SomeOtherData : BaseData
+ {
+ public int usefulNumber;
+ }
+
+ public class DataSenderBehaviour : NetworkBehaviour
+ {
+ public event Action onData;
+
+ [Command]
+ public void CmdSendData(SomeOtherData otherData)
+ {
+ onData?.Invoke(otherData);
+ }
+ }
+
+ public class FieldsInBaseClasses : RemoteTestBase
+ {
+ [Test, Ignore("Destroy is needed for the code. Can't be called in Edit mode.")]
+ public void WriterShouldIncludeFieldsInBaseClass()
+ {
+ // spawn with owner
+ CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out DataSenderBehaviour hostBehaviour, NetworkServer.localConnection);
+
+ const bool toggle = true;
+ const int usefulNumber = 10;
+
+ int called = 0;
+ hostBehaviour.onData += data =>
+ {
+ called++;
+ Assert.That(data.usefulNumber, Is.EqualTo(usefulNumber));
+ Assert.That(data.toggle, Is.EqualTo(toggle));
+ };
+ hostBehaviour.CmdSendData(new SomeOtherData
+ {
+ usefulNumber = usefulNumber,
+ toggle = toggle
+ });
+
+ ProcessMessages();
+ Assert.That(called, Is.EqualTo(1));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs.meta b/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs.meta
new file mode 100644
index 000000000..67a428572
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 518288ffe7c7215458a98466131fc7af
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/Generated.meta b/Assets/Mirror/Tests/Editor/Generated.meta
new file mode 100644
index 000000000..be2f418af
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Generated.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f1a04c2c41f19ea46b0b1a33c8f2ae89
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/Generated/AttritubeTest.gen.cs b/Assets/Mirror/Tests/Editor/Generated/AttritubeTest.gen.cs
new file mode 100644
index 000000000..773567b10
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Generated/AttritubeTest.gen.cs
@@ -0,0 +1,5946 @@
+// Generated by AttributeTestGenerator.cs
+using NUnit.Framework;
+using UnityEngine;
+using UnityEngine.TestTools;
+
+namespace Mirror.Tests.Generated.Attributes
+{
+ public class ClassWithNoConstructor
+ {
+ public int a;
+ }
+
+ public class ClassWithConstructor
+ {
+ public int a;
+
+ public ClassWithConstructor(int a)
+ {
+ this.a = a;
+ }
+ }
+
+ public class AttributeBehaviour_NetworkBehaviour : NetworkBehaviour
+ {
+ public static readonly float Expected_float = 2020f;
+ public static readonly double Expected_double = 2.54;
+ public static readonly bool Expected_bool = true;
+ public static readonly char Expected_char = 'a';
+ public static readonly byte Expected_byte = 224;
+ public static readonly int Expected_int = 103;
+ public static readonly long Expected_long = -123456789L;
+ public static readonly ulong Expected_ulong = 123456789UL;
+ public static readonly Vector3 Expected_Vector3 = new Vector3(29, 1, 10);
+ public static readonly ClassWithNoConstructor Expected_ClassWithNoConstructor = new ClassWithNoConstructor { a = 10 };
+ public static readonly ClassWithConstructor Expected_ClassWithConstructor = new ClassWithConstructor(29);
+
+
+ [Client]
+ public float Client_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [Client]
+ public void Client_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [Client]
+ public double Client_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [Client]
+ public void Client_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [Client]
+ public bool Client_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [Client]
+ public void Client_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [Client]
+ public char Client_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [Client]
+ public void Client_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [Client]
+ public byte Client_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [Client]
+ public void Client_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [Client]
+ public int Client_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [Client]
+ public void Client_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [Client]
+ public long Client_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [Client]
+ public void Client_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [Client]
+ public ulong Client_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [Client]
+ public void Client_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [Client]
+ public Vector3 Client_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [Client]
+ public void Client_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [Client]
+ public ClassWithNoConstructor Client_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [Client]
+ public void Client_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [Client]
+ public ClassWithConstructor Client_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [Client]
+ public void Client_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [Server]
+ public float Server_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [Server]
+ public void Server_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [Server]
+ public double Server_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [Server]
+ public void Server_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [Server]
+ public bool Server_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [Server]
+ public void Server_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [Server]
+ public char Server_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [Server]
+ public void Server_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [Server]
+ public byte Server_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [Server]
+ public void Server_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [Server]
+ public int Server_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [Server]
+ public void Server_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [Server]
+ public long Server_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [Server]
+ public void Server_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [Server]
+ public ulong Server_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [Server]
+ public void Server_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [Server]
+ public Vector3 Server_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [Server]
+ public void Server_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [Server]
+ public ClassWithNoConstructor Server_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [Server]
+ public void Server_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [Server]
+ public ClassWithConstructor Server_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [Server]
+ public void Server_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [ClientCallback]
+ public float ClientCallback_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [ClientCallback]
+ public double ClientCallback_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [ClientCallback]
+ public bool ClientCallback_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [ClientCallback]
+ public char ClientCallback_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [ClientCallback]
+ public byte ClientCallback_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [ClientCallback]
+ public int ClientCallback_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [ClientCallback]
+ public long ClientCallback_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [ClientCallback]
+ public ulong ClientCallback_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [ClientCallback]
+ public Vector3 ClientCallback_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [ClientCallback]
+ public ClassWithNoConstructor ClientCallback_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [ClientCallback]
+ public ClassWithConstructor ClientCallback_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [ServerCallback]
+ public float ServerCallback_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [ServerCallback]
+ public double ServerCallback_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [ServerCallback]
+ public bool ServerCallback_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [ServerCallback]
+ public char ServerCallback_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [ServerCallback]
+ public byte ServerCallback_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [ServerCallback]
+ public int ServerCallback_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [ServerCallback]
+ public long ServerCallback_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [ServerCallback]
+ public ulong ServerCallback_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [ServerCallback]
+ public Vector3 ServerCallback_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [ServerCallback]
+ public ClassWithNoConstructor ServerCallback_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [ServerCallback]
+ public ClassWithConstructor ServerCallback_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+ }
+
+
+ public class AttributeTest_NetworkBehaviour
+ {
+ AttributeBehaviour_NetworkBehaviour behaviour;
+ GameObject go;
+
+ [OneTimeSetUp]
+ public void SetUp()
+ {
+ go = new GameObject();
+ behaviour = go.AddComponent();
+ }
+
+ [OneTimeTearDown]
+ public void TearDown()
+ {
+ UnityEngine.Object.DestroyImmediate(go);
+ NetworkClient.connectState = ConnectState.None;
+ NetworkServer.active = false;
+ }
+
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_float_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Single Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_float_Function()' called when client was not active");
+ }
+ float actual = behaviour.Client_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_float_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_float_out_Function(System.Single&)' called when client was not active");
+ }
+ behaviour.Client_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_double_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Double Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_double_Function()' called when client was not active");
+ }
+ double actual = behaviour.Client_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_double_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_double_out_Function(System.Double&)' called when client was not active");
+ }
+ behaviour.Client_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_bool_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Boolean Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_bool_Function()' called when client was not active");
+ }
+ bool actual = behaviour.Client_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_bool_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_bool_out_Function(System.Boolean&)' called when client was not active");
+ }
+ behaviour.Client_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_char_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Char Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_char_Function()' called when client was not active");
+ }
+ char actual = behaviour.Client_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_char_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_char_out_Function(System.Char&)' called when client was not active");
+ }
+ behaviour.Client_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_byte_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Byte Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_byte_Function()' called when client was not active");
+ }
+ byte actual = behaviour.Client_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_byte_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_byte_out_Function(System.Byte&)' called when client was not active");
+ }
+ behaviour.Client_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_int_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Int32 Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_int_Function()' called when client was not active");
+ }
+ int actual = behaviour.Client_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_int_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_int_out_Function(System.Int32&)' called when client was not active");
+ }
+ behaviour.Client_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_long_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Int64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_long_Function()' called when client was not active");
+ }
+ long actual = behaviour.Client_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_long_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_long_out_Function(System.Int64&)' called when client was not active");
+ }
+ behaviour.Client_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ulong_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.UInt64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_ulong_Function()' called when client was not active");
+ }
+ ulong actual = behaviour.Client_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ulong_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_ulong_out_Function(System.UInt64&)' called when client was not active");
+ }
+ behaviour.Client_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_Vector3_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'UnityEngine.Vector3 Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_Vector3_Function()' called when client was not active");
+ }
+ Vector3 actual = behaviour.Client_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_Vector3_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_Vector3_out_Function(UnityEngine.Vector3&)' called when client was not active");
+ }
+ behaviour.Client_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'Mirror.Tests.Generated.Attributes.ClassWithNoConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_ClassWithNoConstructor_Function()' called when client was not active");
+ }
+ ClassWithNoConstructor actual = behaviour.Client_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_ClassWithNoConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithNoConstructor&)' called when client was not active");
+ }
+ behaviour.Client_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'Mirror.Tests.Generated.Attributes.ClassWithConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_ClassWithConstructor_Function()' called when client was not active");
+ }
+ ClassWithConstructor actual = behaviour.Client_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Client_ClassWithConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithConstructor&)' called when client was not active");
+ }
+ behaviour.Client_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_float_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Single Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_float_Function()' called when server was not active");
+ }
+ float actual = behaviour.Server_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_float_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_float_out_Function(System.Single&)' called when server was not active");
+ }
+ behaviour.Server_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_double_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Double Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_double_Function()' called when server was not active");
+ }
+ double actual = behaviour.Server_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_double_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_double_out_Function(System.Double&)' called when server was not active");
+ }
+ behaviour.Server_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_bool_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Boolean Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_bool_Function()' called when server was not active");
+ }
+ bool actual = behaviour.Server_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_bool_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_bool_out_Function(System.Boolean&)' called when server was not active");
+ }
+ behaviour.Server_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_char_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Char Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_char_Function()' called when server was not active");
+ }
+ char actual = behaviour.Server_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_char_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_char_out_Function(System.Char&)' called when server was not active");
+ }
+ behaviour.Server_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_byte_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Byte Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_byte_Function()' called when server was not active");
+ }
+ byte actual = behaviour.Server_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_byte_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_byte_out_Function(System.Byte&)' called when server was not active");
+ }
+ behaviour.Server_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_int_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Int32 Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_int_Function()' called when server was not active");
+ }
+ int actual = behaviour.Server_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_int_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_int_out_Function(System.Int32&)' called when server was not active");
+ }
+ behaviour.Server_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_long_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Int64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_long_Function()' called when server was not active");
+ }
+ long actual = behaviour.Server_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_long_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_long_out_Function(System.Int64&)' called when server was not active");
+ }
+ behaviour.Server_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ulong_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.UInt64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_ulong_Function()' called when server was not active");
+ }
+ ulong actual = behaviour.Server_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ulong_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_ulong_out_Function(System.UInt64&)' called when server was not active");
+ }
+ behaviour.Server_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_Vector3_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'UnityEngine.Vector3 Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_Vector3_Function()' called when server was not active");
+ }
+ Vector3 actual = behaviour.Server_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_Vector3_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_Vector3_out_Function(UnityEngine.Vector3&)' called when server was not active");
+ }
+ behaviour.Server_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'Mirror.Tests.Generated.Attributes.ClassWithNoConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_ClassWithNoConstructor_Function()' called when server was not active");
+ }
+ ClassWithNoConstructor actual = behaviour.Server_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_ClassWithNoConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithNoConstructor&)' called when server was not active");
+ }
+ behaviour.Server_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'Mirror.Tests.Generated.Attributes.ClassWithConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_ClassWithConstructor_Function()' called when server was not active");
+ }
+ ClassWithConstructor actual = behaviour.Server_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_NetworkBehaviour::Server_ClassWithConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithConstructor&)' called when server was not active");
+ }
+ behaviour.Server_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_float_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_float : default;
+
+ float actual = behaviour.ClientCallback_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_float_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_float : default;
+
+ behaviour.ClientCallback_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_double_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_double : default;
+
+ double actual = behaviour.ClientCallback_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_double_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_double : default;
+
+ behaviour.ClientCallback_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_bool_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_bool : default;
+
+ bool actual = behaviour.ClientCallback_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_bool_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_bool : default;
+
+ behaviour.ClientCallback_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_char_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_char : default;
+
+ char actual = behaviour.ClientCallback_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_char_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_char : default;
+
+ behaviour.ClientCallback_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_byte_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_byte : default;
+
+ byte actual = behaviour.ClientCallback_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_byte_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_byte : default;
+
+ behaviour.ClientCallback_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_int_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_int : default;
+
+ int actual = behaviour.ClientCallback_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_int_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_int : default;
+
+ behaviour.ClientCallback_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_long_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_long : default;
+
+ long actual = behaviour.ClientCallback_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_long_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_long : default;
+
+ behaviour.ClientCallback_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ulong_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ulong : default;
+
+ ulong actual = behaviour.ClientCallback_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ulong_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ulong : default;
+
+ behaviour.ClientCallback_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_Vector3_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_Vector3 : default;
+
+ Vector3 actual = behaviour.ClientCallback_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_Vector3_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_Vector3 : default;
+
+ behaviour.ClientCallback_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithNoConstructor : default;
+
+ ClassWithNoConstructor actual = behaviour.ClientCallback_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithNoConstructor : default;
+
+ behaviour.ClientCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithConstructor : default;
+
+ ClassWithConstructor actual = behaviour.ClientCallback_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithConstructor : default;
+
+ behaviour.ClientCallback_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_float_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_float : default;
+
+ float actual = behaviour.ServerCallback_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_float_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_float : default;
+
+ behaviour.ServerCallback_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_double_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_double : default;
+
+ double actual = behaviour.ServerCallback_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_double_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_double : default;
+
+ behaviour.ServerCallback_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_bool_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_bool : default;
+
+ bool actual = behaviour.ServerCallback_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_bool_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_bool : default;
+
+ behaviour.ServerCallback_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_char_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_char : default;
+
+ char actual = behaviour.ServerCallback_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_char_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_char : default;
+
+ behaviour.ServerCallback_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_byte_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_byte : default;
+
+ byte actual = behaviour.ServerCallback_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_byte_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_byte : default;
+
+ behaviour.ServerCallback_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_int_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_int : default;
+
+ int actual = behaviour.ServerCallback_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_int_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_int : default;
+
+ behaviour.ServerCallback_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_long_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_long : default;
+
+ long actual = behaviour.ServerCallback_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_long_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_long : default;
+
+ behaviour.ServerCallback_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ulong_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ulong : default;
+
+ ulong actual = behaviour.ServerCallback_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ulong_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ulong : default;
+
+ behaviour.ServerCallback_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_Vector3_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_Vector3 : default;
+
+ Vector3 actual = behaviour.ServerCallback_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_Vector3_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_Vector3 : default;
+
+ behaviour.ServerCallback_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithNoConstructor : default;
+
+ ClassWithNoConstructor actual = behaviour.ServerCallback_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithNoConstructor : default;
+
+ behaviour.ServerCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithConstructor : default;
+
+ ClassWithConstructor actual = behaviour.ServerCallback_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_NetworkBehaviour.Expected_ClassWithConstructor : default;
+
+ behaviour.ServerCallback_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+ }
+
+ public class AttributeBehaviour_MonoBehaviour : MonoBehaviour
+ {
+ public static readonly float Expected_float = 2020f;
+ public static readonly double Expected_double = 2.54;
+ public static readonly bool Expected_bool = true;
+ public static readonly char Expected_char = 'a';
+ public static readonly byte Expected_byte = 224;
+ public static readonly int Expected_int = 103;
+ public static readonly long Expected_long = -123456789L;
+ public static readonly ulong Expected_ulong = 123456789UL;
+ public static readonly Vector3 Expected_Vector3 = new Vector3(29, 1, 10);
+ public static readonly ClassWithNoConstructor Expected_ClassWithNoConstructor = new ClassWithNoConstructor { a = 10 };
+ public static readonly ClassWithConstructor Expected_ClassWithConstructor = new ClassWithConstructor(29);
+
+
+ [Client]
+ public float Client_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [Client]
+ public void Client_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [Client]
+ public double Client_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [Client]
+ public void Client_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [Client]
+ public bool Client_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [Client]
+ public void Client_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [Client]
+ public char Client_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [Client]
+ public void Client_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [Client]
+ public byte Client_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [Client]
+ public void Client_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [Client]
+ public int Client_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [Client]
+ public void Client_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [Client]
+ public long Client_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [Client]
+ public void Client_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [Client]
+ public ulong Client_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [Client]
+ public void Client_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [Client]
+ public Vector3 Client_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [Client]
+ public void Client_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [Client]
+ public ClassWithNoConstructor Client_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [Client]
+ public void Client_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [Client]
+ public ClassWithConstructor Client_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [Client]
+ public void Client_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [Server]
+ public float Server_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [Server]
+ public void Server_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [Server]
+ public double Server_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [Server]
+ public void Server_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [Server]
+ public bool Server_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [Server]
+ public void Server_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [Server]
+ public char Server_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [Server]
+ public void Server_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [Server]
+ public byte Server_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [Server]
+ public void Server_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [Server]
+ public int Server_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [Server]
+ public void Server_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [Server]
+ public long Server_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [Server]
+ public void Server_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [Server]
+ public ulong Server_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [Server]
+ public void Server_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [Server]
+ public Vector3 Server_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [Server]
+ public void Server_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [Server]
+ public ClassWithNoConstructor Server_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [Server]
+ public void Server_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [Server]
+ public ClassWithConstructor Server_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [Server]
+ public void Server_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [ClientCallback]
+ public float ClientCallback_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [ClientCallback]
+ public double ClientCallback_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [ClientCallback]
+ public bool ClientCallback_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [ClientCallback]
+ public char ClientCallback_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [ClientCallback]
+ public byte ClientCallback_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [ClientCallback]
+ public int ClientCallback_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [ClientCallback]
+ public long ClientCallback_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [ClientCallback]
+ public ulong ClientCallback_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [ClientCallback]
+ public Vector3 ClientCallback_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [ClientCallback]
+ public ClassWithNoConstructor ClientCallback_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [ClientCallback]
+ public ClassWithConstructor ClientCallback_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [ServerCallback]
+ public float ServerCallback_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [ServerCallback]
+ public double ServerCallback_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [ServerCallback]
+ public bool ServerCallback_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [ServerCallback]
+ public char ServerCallback_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [ServerCallback]
+ public byte ServerCallback_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [ServerCallback]
+ public int ServerCallback_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [ServerCallback]
+ public long ServerCallback_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [ServerCallback]
+ public ulong ServerCallback_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [ServerCallback]
+ public Vector3 ServerCallback_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [ServerCallback]
+ public ClassWithNoConstructor ServerCallback_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [ServerCallback]
+ public ClassWithConstructor ServerCallback_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+ }
+
+
+ public class AttributeTest_MonoBehaviour
+ {
+ AttributeBehaviour_MonoBehaviour behaviour;
+ GameObject go;
+
+ [OneTimeSetUp]
+ public void SetUp()
+ {
+ go = new GameObject();
+ behaviour = go.AddComponent();
+ }
+
+ [OneTimeTearDown]
+ public void TearDown()
+ {
+ UnityEngine.Object.DestroyImmediate(go);
+ NetworkClient.connectState = ConnectState.None;
+ NetworkServer.active = false;
+ }
+
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_float_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_MonoBehaviour.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Single Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_float_Function()' called when client was not active");
+ }
+ float actual = behaviour.Client_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_float_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_MonoBehaviour.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_float_out_Function(System.Single&)' called when client was not active");
+ }
+ behaviour.Client_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_double_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_MonoBehaviour.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Double Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_double_Function()' called when client was not active");
+ }
+ double actual = behaviour.Client_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_double_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_MonoBehaviour.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_double_out_Function(System.Double&)' called when client was not active");
+ }
+ behaviour.Client_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_bool_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_MonoBehaviour.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Boolean Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_bool_Function()' called when client was not active");
+ }
+ bool actual = behaviour.Client_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_bool_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_MonoBehaviour.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_bool_out_Function(System.Boolean&)' called when client was not active");
+ }
+ behaviour.Client_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_char_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_MonoBehaviour.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Char Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_char_Function()' called when client was not active");
+ }
+ char actual = behaviour.Client_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_char_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_MonoBehaviour.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_char_out_Function(System.Char&)' called when client was not active");
+ }
+ behaviour.Client_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_byte_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_MonoBehaviour.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Byte Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_byte_Function()' called when client was not active");
+ }
+ byte actual = behaviour.Client_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_byte_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_MonoBehaviour.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_byte_out_Function(System.Byte&)' called when client was not active");
+ }
+ behaviour.Client_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_int_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_MonoBehaviour.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Int32 Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_int_Function()' called when client was not active");
+ }
+ int actual = behaviour.Client_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_int_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_MonoBehaviour.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_int_out_Function(System.Int32&)' called when client was not active");
+ }
+ behaviour.Client_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_long_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_MonoBehaviour.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Int64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_long_Function()' called when client was not active");
+ }
+ long actual = behaviour.Client_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_long_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_MonoBehaviour.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_long_out_Function(System.Int64&)' called when client was not active");
+ }
+ behaviour.Client_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ulong_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.UInt64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_ulong_Function()' called when client was not active");
+ }
+ ulong actual = behaviour.Client_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ulong_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_ulong_out_Function(System.UInt64&)' called when client was not active");
+ }
+ behaviour.Client_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_Vector3_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_MonoBehaviour.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'UnityEngine.Vector3 Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_Vector3_Function()' called when client was not active");
+ }
+ Vector3 actual = behaviour.Client_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_Vector3_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_MonoBehaviour.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_Vector3_out_Function(UnityEngine.Vector3&)' called when client was not active");
+ }
+ behaviour.Client_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'Mirror.Tests.Generated.Attributes.ClassWithNoConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_ClassWithNoConstructor_Function()' called when client was not active");
+ }
+ ClassWithNoConstructor actual = behaviour.Client_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_ClassWithNoConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithNoConstructor&)' called when client was not active");
+ }
+ behaviour.Client_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'Mirror.Tests.Generated.Attributes.ClassWithConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_ClassWithConstructor_Function()' called when client was not active");
+ }
+ ClassWithConstructor actual = behaviour.Client_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Client_ClassWithConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithConstructor&)' called when client was not active");
+ }
+ behaviour.Client_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_float_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_MonoBehaviour.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Single Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_float_Function()' called when server was not active");
+ }
+ float actual = behaviour.Server_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_float_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_MonoBehaviour.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_float_out_Function(System.Single&)' called when server was not active");
+ }
+ behaviour.Server_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_double_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_MonoBehaviour.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Double Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_double_Function()' called when server was not active");
+ }
+ double actual = behaviour.Server_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_double_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_MonoBehaviour.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_double_out_Function(System.Double&)' called when server was not active");
+ }
+ behaviour.Server_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_bool_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_MonoBehaviour.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Boolean Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_bool_Function()' called when server was not active");
+ }
+ bool actual = behaviour.Server_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_bool_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_MonoBehaviour.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_bool_out_Function(System.Boolean&)' called when server was not active");
+ }
+ behaviour.Server_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_char_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_MonoBehaviour.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Char Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_char_Function()' called when server was not active");
+ }
+ char actual = behaviour.Server_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_char_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_MonoBehaviour.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_char_out_Function(System.Char&)' called when server was not active");
+ }
+ behaviour.Server_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_byte_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_MonoBehaviour.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Byte Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_byte_Function()' called when server was not active");
+ }
+ byte actual = behaviour.Server_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_byte_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_MonoBehaviour.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_byte_out_Function(System.Byte&)' called when server was not active");
+ }
+ behaviour.Server_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_int_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_MonoBehaviour.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Int32 Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_int_Function()' called when server was not active");
+ }
+ int actual = behaviour.Server_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_int_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_MonoBehaviour.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_int_out_Function(System.Int32&)' called when server was not active");
+ }
+ behaviour.Server_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_long_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_MonoBehaviour.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Int64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_long_Function()' called when server was not active");
+ }
+ long actual = behaviour.Server_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_long_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_MonoBehaviour.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_long_out_Function(System.Int64&)' called when server was not active");
+ }
+ behaviour.Server_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ulong_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.UInt64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_ulong_Function()' called when server was not active");
+ }
+ ulong actual = behaviour.Server_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ulong_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_ulong_out_Function(System.UInt64&)' called when server was not active");
+ }
+ behaviour.Server_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_Vector3_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_MonoBehaviour.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'UnityEngine.Vector3 Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_Vector3_Function()' called when server was not active");
+ }
+ Vector3 actual = behaviour.Server_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_Vector3_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_MonoBehaviour.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_Vector3_out_Function(UnityEngine.Vector3&)' called when server was not active");
+ }
+ behaviour.Server_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'Mirror.Tests.Generated.Attributes.ClassWithNoConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_ClassWithNoConstructor_Function()' called when server was not active");
+ }
+ ClassWithNoConstructor actual = behaviour.Server_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_ClassWithNoConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithNoConstructor&)' called when server was not active");
+ }
+ behaviour.Server_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'Mirror.Tests.Generated.Attributes.ClassWithConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_ClassWithConstructor_Function()' called when server was not active");
+ }
+ ClassWithConstructor actual = behaviour.Server_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_MonoBehaviour::Server_ClassWithConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithConstructor&)' called when server was not active");
+ }
+ behaviour.Server_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_float_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_MonoBehaviour.Expected_float : default;
+
+ float actual = behaviour.ClientCallback_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_float_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_MonoBehaviour.Expected_float : default;
+
+ behaviour.ClientCallback_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_double_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_MonoBehaviour.Expected_double : default;
+
+ double actual = behaviour.ClientCallback_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_double_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_MonoBehaviour.Expected_double : default;
+
+ behaviour.ClientCallback_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_bool_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_MonoBehaviour.Expected_bool : default;
+
+ bool actual = behaviour.ClientCallback_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_bool_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_MonoBehaviour.Expected_bool : default;
+
+ behaviour.ClientCallback_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_char_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_MonoBehaviour.Expected_char : default;
+
+ char actual = behaviour.ClientCallback_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_char_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_MonoBehaviour.Expected_char : default;
+
+ behaviour.ClientCallback_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_byte_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_MonoBehaviour.Expected_byte : default;
+
+ byte actual = behaviour.ClientCallback_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_byte_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_MonoBehaviour.Expected_byte : default;
+
+ behaviour.ClientCallback_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_int_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_MonoBehaviour.Expected_int : default;
+
+ int actual = behaviour.ClientCallback_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_int_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_MonoBehaviour.Expected_int : default;
+
+ behaviour.ClientCallback_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_long_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_MonoBehaviour.Expected_long : default;
+
+ long actual = behaviour.ClientCallback_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_long_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_MonoBehaviour.Expected_long : default;
+
+ behaviour.ClientCallback_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ulong_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ulong : default;
+
+ ulong actual = behaviour.ClientCallback_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ulong_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ulong : default;
+
+ behaviour.ClientCallback_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_Vector3_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_MonoBehaviour.Expected_Vector3 : default;
+
+ Vector3 actual = behaviour.ClientCallback_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_Vector3_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_MonoBehaviour.Expected_Vector3 : default;
+
+ behaviour.ClientCallback_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithNoConstructor : default;
+
+ ClassWithNoConstructor actual = behaviour.ClientCallback_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithNoConstructor : default;
+
+ behaviour.ClientCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithConstructor : default;
+
+ ClassWithConstructor actual = behaviour.ClientCallback_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithConstructor : default;
+
+ behaviour.ClientCallback_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_float_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_MonoBehaviour.Expected_float : default;
+
+ float actual = behaviour.ServerCallback_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_float_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_MonoBehaviour.Expected_float : default;
+
+ behaviour.ServerCallback_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_double_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_MonoBehaviour.Expected_double : default;
+
+ double actual = behaviour.ServerCallback_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_double_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_MonoBehaviour.Expected_double : default;
+
+ behaviour.ServerCallback_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_bool_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_MonoBehaviour.Expected_bool : default;
+
+ bool actual = behaviour.ServerCallback_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_bool_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_MonoBehaviour.Expected_bool : default;
+
+ behaviour.ServerCallback_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_char_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_MonoBehaviour.Expected_char : default;
+
+ char actual = behaviour.ServerCallback_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_char_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_MonoBehaviour.Expected_char : default;
+
+ behaviour.ServerCallback_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_byte_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_MonoBehaviour.Expected_byte : default;
+
+ byte actual = behaviour.ServerCallback_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_byte_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_MonoBehaviour.Expected_byte : default;
+
+ behaviour.ServerCallback_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_int_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_MonoBehaviour.Expected_int : default;
+
+ int actual = behaviour.ServerCallback_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_int_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_MonoBehaviour.Expected_int : default;
+
+ behaviour.ServerCallback_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_long_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_MonoBehaviour.Expected_long : default;
+
+ long actual = behaviour.ServerCallback_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_long_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_MonoBehaviour.Expected_long : default;
+
+ behaviour.ServerCallback_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ulong_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ulong : default;
+
+ ulong actual = behaviour.ServerCallback_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ulong_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ulong : default;
+
+ behaviour.ServerCallback_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_Vector3_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_MonoBehaviour.Expected_Vector3 : default;
+
+ Vector3 actual = behaviour.ServerCallback_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_Vector3_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_MonoBehaviour.Expected_Vector3 : default;
+
+ behaviour.ServerCallback_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithNoConstructor : default;
+
+ ClassWithNoConstructor actual = behaviour.ServerCallback_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithNoConstructor : default;
+
+ behaviour.ServerCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithConstructor : default;
+
+ ClassWithConstructor actual = behaviour.ServerCallback_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_MonoBehaviour.Expected_ClassWithConstructor : default;
+
+ behaviour.ServerCallback_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+ }
+
+ public class AttributeBehaviour_ClassWithNoConstructor : ClassWithNoConstructor
+ {
+ public static readonly float Expected_float = 2020f;
+ public static readonly double Expected_double = 2.54;
+ public static readonly bool Expected_bool = true;
+ public static readonly char Expected_char = 'a';
+ public static readonly byte Expected_byte = 224;
+ public static readonly int Expected_int = 103;
+ public static readonly long Expected_long = -123456789L;
+ public static readonly ulong Expected_ulong = 123456789UL;
+ public static readonly Vector3 Expected_Vector3 = new Vector3(29, 1, 10);
+ public static readonly ClassWithNoConstructor Expected_ClassWithNoConstructor = new ClassWithNoConstructor { a = 10 };
+ public static readonly ClassWithConstructor Expected_ClassWithConstructor = new ClassWithConstructor(29);
+
+
+ [Client]
+ public float Client_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [Client]
+ public void Client_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [Client]
+ public double Client_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [Client]
+ public void Client_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [Client]
+ public bool Client_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [Client]
+ public void Client_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [Client]
+ public char Client_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [Client]
+ public void Client_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [Client]
+ public byte Client_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [Client]
+ public void Client_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [Client]
+ public int Client_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [Client]
+ public void Client_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [Client]
+ public long Client_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [Client]
+ public void Client_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [Client]
+ public ulong Client_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [Client]
+ public void Client_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [Client]
+ public Vector3 Client_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [Client]
+ public void Client_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [Client]
+ public ClassWithNoConstructor Client_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [Client]
+ public void Client_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [Client]
+ public ClassWithConstructor Client_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [Client]
+ public void Client_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [Server]
+ public float Server_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [Server]
+ public void Server_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [Server]
+ public double Server_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [Server]
+ public void Server_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [Server]
+ public bool Server_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [Server]
+ public void Server_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [Server]
+ public char Server_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [Server]
+ public void Server_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [Server]
+ public byte Server_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [Server]
+ public void Server_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [Server]
+ public int Server_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [Server]
+ public void Server_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [Server]
+ public long Server_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [Server]
+ public void Server_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [Server]
+ public ulong Server_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [Server]
+ public void Server_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [Server]
+ public Vector3 Server_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [Server]
+ public void Server_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [Server]
+ public ClassWithNoConstructor Server_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [Server]
+ public void Server_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [Server]
+ public ClassWithConstructor Server_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [Server]
+ public void Server_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [ClientCallback]
+ public float ClientCallback_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [ClientCallback]
+ public double ClientCallback_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [ClientCallback]
+ public bool ClientCallback_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [ClientCallback]
+ public char ClientCallback_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [ClientCallback]
+ public byte ClientCallback_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [ClientCallback]
+ public int ClientCallback_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [ClientCallback]
+ public long ClientCallback_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [ClientCallback]
+ public ulong ClientCallback_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [ClientCallback]
+ public Vector3 ClientCallback_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [ClientCallback]
+ public ClassWithNoConstructor ClientCallback_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [ClientCallback]
+ public ClassWithConstructor ClientCallback_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [ClientCallback]
+ public void ClientCallback_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+
+ [ServerCallback]
+ public float ServerCallback_float_Function()
+ {
+ return Expected_float;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_float_out_Function(out float value)
+ {
+ value = Expected_float;
+ }
+
+ [ServerCallback]
+ public double ServerCallback_double_Function()
+ {
+ return Expected_double;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_double_out_Function(out double value)
+ {
+ value = Expected_double;
+ }
+
+ [ServerCallback]
+ public bool ServerCallback_bool_Function()
+ {
+ return Expected_bool;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_bool_out_Function(out bool value)
+ {
+ value = Expected_bool;
+ }
+
+ [ServerCallback]
+ public char ServerCallback_char_Function()
+ {
+ return Expected_char;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_char_out_Function(out char value)
+ {
+ value = Expected_char;
+ }
+
+ [ServerCallback]
+ public byte ServerCallback_byte_Function()
+ {
+ return Expected_byte;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_byte_out_Function(out byte value)
+ {
+ value = Expected_byte;
+ }
+
+ [ServerCallback]
+ public int ServerCallback_int_Function()
+ {
+ return Expected_int;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_int_out_Function(out int value)
+ {
+ value = Expected_int;
+ }
+
+ [ServerCallback]
+ public long ServerCallback_long_Function()
+ {
+ return Expected_long;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_long_out_Function(out long value)
+ {
+ value = Expected_long;
+ }
+
+ [ServerCallback]
+ public ulong ServerCallback_ulong_Function()
+ {
+ return Expected_ulong;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ulong_out_Function(out ulong value)
+ {
+ value = Expected_ulong;
+ }
+
+ [ServerCallback]
+ public Vector3 ServerCallback_Vector3_Function()
+ {
+ return Expected_Vector3;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_Vector3_out_Function(out Vector3 value)
+ {
+ value = Expected_Vector3;
+ }
+
+ [ServerCallback]
+ public ClassWithNoConstructor ServerCallback_ClassWithNoConstructor_Function()
+ {
+ return Expected_ClassWithNoConstructor;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor value)
+ {
+ value = Expected_ClassWithNoConstructor;
+ }
+
+ [ServerCallback]
+ public ClassWithConstructor ServerCallback_ClassWithConstructor_Function()
+ {
+ return Expected_ClassWithConstructor;
+ }
+
+ [ServerCallback]
+ public void ServerCallback_ClassWithConstructor_out_Function(out ClassWithConstructor value)
+ {
+ value = Expected_ClassWithConstructor;
+ }
+ }
+
+
+ public class AttributeTest_ClassWithNoConstructor
+ {
+ AttributeBehaviour_ClassWithNoConstructor behaviour;
+ GameObject go;
+
+ [OneTimeSetUp]
+ public void SetUp()
+ {
+ behaviour = new AttributeBehaviour_ClassWithNoConstructor();
+ }
+
+ [OneTimeTearDown]
+ public void TearDown()
+ {
+
+ NetworkClient.connectState = ConnectState.None;
+ NetworkServer.active = false;
+ }
+
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_float_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Single Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_float_Function()' called when client was not active");
+ }
+ float actual = behaviour.Client_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_float_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_float_out_Function(System.Single&)' called when client was not active");
+ }
+ behaviour.Client_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_double_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Double Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_double_Function()' called when client was not active");
+ }
+ double actual = behaviour.Client_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_double_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_double_out_Function(System.Double&)' called when client was not active");
+ }
+ behaviour.Client_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_bool_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Boolean Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_bool_Function()' called when client was not active");
+ }
+ bool actual = behaviour.Client_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_bool_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_bool_out_Function(System.Boolean&)' called when client was not active");
+ }
+ behaviour.Client_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_char_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Char Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_char_Function()' called when client was not active");
+ }
+ char actual = behaviour.Client_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_char_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_char_out_Function(System.Char&)' called when client was not active");
+ }
+ behaviour.Client_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_byte_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Byte Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_byte_Function()' called when client was not active");
+ }
+ byte actual = behaviour.Client_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_byte_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_byte_out_Function(System.Byte&)' called when client was not active");
+ }
+ behaviour.Client_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_int_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Int32 Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_int_Function()' called when client was not active");
+ }
+ int actual = behaviour.Client_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_int_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_int_out_Function(System.Int32&)' called when client was not active");
+ }
+ behaviour.Client_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_long_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Int64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_long_Function()' called when client was not active");
+ }
+ long actual = behaviour.Client_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_long_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_long_out_Function(System.Int64&)' called when client was not active");
+ }
+ behaviour.Client_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ulong_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.UInt64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_ulong_Function()' called when client was not active");
+ }
+ ulong actual = behaviour.Client_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ulong_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_ulong_out_Function(System.UInt64&)' called when client was not active");
+ }
+ behaviour.Client_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_Vector3_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'UnityEngine.Vector3 Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_Vector3_Function()' called when client was not active");
+ }
+ Vector3 actual = behaviour.Client_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_Vector3_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_Vector3_out_Function(UnityEngine.Vector3&)' called when client was not active");
+ }
+ behaviour.Client_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'Mirror.Tests.Generated.Attributes.ClassWithNoConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_ClassWithNoConstructor_Function()' called when client was not active");
+ }
+ ClassWithNoConstructor actual = behaviour.Client_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_ClassWithNoConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithNoConstructor&)' called when client was not active");
+ }
+ behaviour.Client_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'Mirror.Tests.Generated.Attributes.ClassWithConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_ClassWithConstructor_Function()' called when client was not active");
+ }
+ ClassWithConstructor actual = behaviour.Client_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Client_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Client] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Client_ClassWithConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithConstructor&)' called when client was not active");
+ }
+ behaviour.Client_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_float_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Single Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_float_Function()' called when server was not active");
+ }
+ float actual = behaviour.Server_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_float_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_float : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_float_out_Function(System.Single&)' called when server was not active");
+ }
+ behaviour.Server_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_double_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Double Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_double_Function()' called when server was not active");
+ }
+ double actual = behaviour.Server_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_double_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_double : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_double_out_Function(System.Double&)' called when server was not active");
+ }
+ behaviour.Server_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_bool_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Boolean Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_bool_Function()' called when server was not active");
+ }
+ bool actual = behaviour.Server_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_bool_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_bool : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_bool_out_Function(System.Boolean&)' called when server was not active");
+ }
+ behaviour.Server_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_char_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Char Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_char_Function()' called when server was not active");
+ }
+ char actual = behaviour.Server_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_char_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_char : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_char_out_Function(System.Char&)' called when server was not active");
+ }
+ behaviour.Server_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_byte_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Byte Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_byte_Function()' called when server was not active");
+ }
+ byte actual = behaviour.Server_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_byte_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_byte : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_byte_out_Function(System.Byte&)' called when server was not active");
+ }
+ behaviour.Server_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_int_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Int32 Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_int_Function()' called when server was not active");
+ }
+ int actual = behaviour.Server_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_int_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_int : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_int_out_Function(System.Int32&)' called when server was not active");
+ }
+ behaviour.Server_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_long_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Int64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_long_Function()' called when server was not active");
+ }
+ long actual = behaviour.Server_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_long_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_long : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_long_out_Function(System.Int64&)' called when server was not active");
+ }
+ behaviour.Server_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ulong_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.UInt64 Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_ulong_Function()' called when server was not active");
+ }
+ ulong actual = behaviour.Server_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ulong_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ulong : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_ulong_out_Function(System.UInt64&)' called when server was not active");
+ }
+ behaviour.Server_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_Vector3_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'UnityEngine.Vector3 Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_Vector3_Function()' called when server was not active");
+ }
+ Vector3 actual = behaviour.Server_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_Vector3_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_Vector3 : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_Vector3_out_Function(UnityEngine.Vector3&)' called when server was not active");
+ }
+ behaviour.Server_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'Mirror.Tests.Generated.Attributes.ClassWithNoConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_ClassWithNoConstructor_Function()' called when server was not active");
+ }
+ ClassWithNoConstructor actual = behaviour.Server_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithNoConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_ClassWithNoConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithNoConstructor&)' called when server was not active");
+ }
+ behaviour.Server_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'Mirror.Tests.Generated.Attributes.ClassWithConstructor Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_ClassWithConstructor_Function()' called when server was not active");
+ }
+ ClassWithConstructor actual = behaviour.Server_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Server_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithConstructor : default;
+
+ if (!active)
+ {
+ LogAssert.Expect(LogType.Warning, "[Server] function 'System.Void Mirror.Tests.Generated.Attributes.AttributeBehaviour_ClassWithNoConstructor::Server_ClassWithConstructor_out_Function(Mirror.Tests.Generated.Attributes.ClassWithConstructor&)' called when server was not active");
+ }
+ behaviour.Server_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_float_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_float : default;
+
+ float actual = behaviour.ClientCallback_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_float_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ float expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_float : default;
+
+ behaviour.ClientCallback_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_double_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_double : default;
+
+ double actual = behaviour.ClientCallback_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_double_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ double expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_double : default;
+
+ behaviour.ClientCallback_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_bool_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_bool : default;
+
+ bool actual = behaviour.ClientCallback_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_bool_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ bool expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_bool : default;
+
+ behaviour.ClientCallback_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_char_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_char : default;
+
+ char actual = behaviour.ClientCallback_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_char_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ char expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_char : default;
+
+ behaviour.ClientCallback_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_byte_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_byte : default;
+
+ byte actual = behaviour.ClientCallback_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_byte_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ byte expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_byte : default;
+
+ behaviour.ClientCallback_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_int_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_int : default;
+
+ int actual = behaviour.ClientCallback_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_int_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ int expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_int : default;
+
+ behaviour.ClientCallback_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_long_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_long : default;
+
+ long actual = behaviour.ClientCallback_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_long_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ long expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_long : default;
+
+ behaviour.ClientCallback_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ulong_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ulong : default;
+
+ ulong actual = behaviour.ClientCallback_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ulong_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ulong expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ulong : default;
+
+ behaviour.ClientCallback_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_Vector3_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_Vector3 : default;
+
+ Vector3 actual = behaviour.ClientCallback_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_Vector3_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ Vector3 expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_Vector3 : default;
+
+ behaviour.ClientCallback_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithNoConstructor : default;
+
+ ClassWithNoConstructor actual = behaviour.ClientCallback_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithNoConstructor : default;
+
+ behaviour.ClientCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithConstructor : default;
+
+ ClassWithConstructor actual = behaviour.ClientCallback_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ClientCallback_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithConstructor : default;
+
+ behaviour.ClientCallback_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_float_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_float : default;
+
+ float actual = behaviour.ServerCallback_float_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_float_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ float expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_float : default;
+
+ behaviour.ServerCallback_float_out_Function(out float actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_double_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_double : default;
+
+ double actual = behaviour.ServerCallback_double_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_double_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ double expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_double : default;
+
+ behaviour.ServerCallback_double_out_Function(out double actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_bool_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_bool : default;
+
+ bool actual = behaviour.ServerCallback_bool_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_bool_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ bool expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_bool : default;
+
+ behaviour.ServerCallback_bool_out_Function(out bool actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_char_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_char : default;
+
+ char actual = behaviour.ServerCallback_char_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_char_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ char expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_char : default;
+
+ behaviour.ServerCallback_char_out_Function(out char actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_byte_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_byte : default;
+
+ byte actual = behaviour.ServerCallback_byte_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_byte_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ byte expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_byte : default;
+
+ behaviour.ServerCallback_byte_out_Function(out byte actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_int_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_int : default;
+
+ int actual = behaviour.ServerCallback_int_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_int_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ int expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_int : default;
+
+ behaviour.ServerCallback_int_out_Function(out int actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_long_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_long : default;
+
+ long actual = behaviour.ServerCallback_long_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_long_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ long expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_long : default;
+
+ behaviour.ServerCallback_long_out_Function(out long actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ulong_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ulong : default;
+
+ ulong actual = behaviour.ServerCallback_ulong_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ulong_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ulong expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ulong : default;
+
+ behaviour.ServerCallback_ulong_out_Function(out ulong actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_Vector3_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_Vector3 : default;
+
+ Vector3 actual = behaviour.ServerCallback_Vector3_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_Vector3_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ Vector3 expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_Vector3 : default;
+
+ behaviour.ServerCallback_Vector3_out_Function(out Vector3 actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithNoConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithNoConstructor : default;
+
+ ClassWithNoConstructor actual = behaviour.ServerCallback_ClassWithNoConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithNoConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithNoConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithNoConstructor : default;
+
+ behaviour.ServerCallback_ClassWithNoConstructor_out_Function(out ClassWithNoConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithConstructor_returnsValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithConstructor : default;
+
+ ClassWithConstructor actual = behaviour.ServerCallback_ClassWithConstructor_Function();
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void ServerCallback_ClassWithConstructor_setsOutValue(bool active)
+ {
+ NetworkServer.active = active;
+
+ ClassWithConstructor expected = active ? AttributeBehaviour_ClassWithNoConstructor.Expected_ClassWithConstructor : default;
+
+ behaviour.ServerCallback_ClassWithConstructor_out_Function(out ClassWithConstructor actual);
+
+ Assert.AreEqual(expected, actual);
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/Generated/AttritubeTest.gen.cs.meta b/Assets/Mirror/Tests/Editor/Generated/AttritubeTest.gen.cs.meta
new file mode 100644
index 000000000..3e05bedb0
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Generated/AttritubeTest.gen.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e49c298f22d4292439dc17f7e59f08b7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/Generated/CollectionWriterTests.gen.cs b/Assets/Mirror/Tests/Editor/Generated/CollectionWriterTests.gen.cs
new file mode 100644
index 000000000..081b7f4c0
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Generated/CollectionWriterTests.gen.cs
@@ -0,0 +1,1049 @@
+// Generated by CollectionWriterGenerator.cs
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests.Generated.CollectionWriters
+{
+ public struct FloatStringStruct
+ {
+ public float value;
+ public string anotherValue;
+ }
+
+ public class ClassWithNoConstructor
+ {
+ public int a;
+ }
+
+ public class Array_int_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public int[] collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ int[] unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new int[] {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ int[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new int[]
+ {
+ 3, 4, 5
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ int[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0], Is.EqualTo(3));
+ Assert.That(unpackedCollection[1], Is.EqualTo(4));
+ Assert.That(unpackedCollection[2], Is.EqualTo(5));
+ }
+ }
+
+ public class Array_string_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public string[] collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ string[] unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new string[] {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ string[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new string[]
+ {
+ "Some", "String", "Value"
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ string[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0], Is.EqualTo("Some"));
+ Assert.That(unpackedCollection[1], Is.EqualTo("String"));
+ Assert.That(unpackedCollection[2], Is.EqualTo("Value"));
+ }
+ }
+
+ public class Array_Vector3_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public Vector3[] collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ Vector3[] unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new Vector3[] {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ Vector3[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new Vector3[]
+ {
+ new Vector3(1, 2, 3), new Vector3(4, 5, 6), new Vector3(7, 8, 9)
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ Vector3[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0], Is.EqualTo(new Vector3(1, 2, 3)));
+ Assert.That(unpackedCollection[1], Is.EqualTo(new Vector3(4, 5, 6)));
+ Assert.That(unpackedCollection[2], Is.EqualTo(new Vector3(7, 8, 9)));
+ }
+ }
+
+ public class Array_FloatStringStruct_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public FloatStringStruct[] collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ FloatStringStruct[] unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new FloatStringStruct[] {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ FloatStringStruct[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new FloatStringStruct[]
+ {
+ new FloatStringStruct { value = 3, anotherValue = "Some" }, new FloatStringStruct { value = 4, anotherValue = "String" }, new FloatStringStruct { value = 5, anotherValue = "Values" }
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ FloatStringStruct[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0], Is.EqualTo(new FloatStringStruct { value = 3, anotherValue = "Some" }));
+ Assert.That(unpackedCollection[1], Is.EqualTo(new FloatStringStruct { value = 4, anotherValue = "String" }));
+ Assert.That(unpackedCollection[2], Is.EqualTo(new FloatStringStruct { value = 5, anotherValue = "Values" }));
+ }
+ }
+
+ public class Array_ClassWithNoConstructor_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public ClassWithNoConstructor[] collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ClassWithNoConstructor[] unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new ClassWithNoConstructor[] {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ClassWithNoConstructor[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new ClassWithNoConstructor[]
+ {
+ new ClassWithNoConstructor { a = 3 }, new ClassWithNoConstructor { a = 4 }, new ClassWithNoConstructor { a = 5 }
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ClassWithNoConstructor[] unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0].a, Is.EqualTo(new ClassWithNoConstructor { a = 3 }.a));
+ Assert.That(unpackedCollection[1].a, Is.EqualTo(new ClassWithNoConstructor { a = 4 }.a));
+ Assert.That(unpackedCollection[2].a, Is.EqualTo(new ClassWithNoConstructor { a = 5 }.a));
+ }
+ }
+
+ public class ArraySegment_int_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public ArraySegment collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection.Array, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ int[] array = new int[]
+ {
+ default,
+ default,
+ default,
+ };
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 0, 0)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsEmpty(unpackedCollection.Array);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ int[] array = new int[]
+ {
+ default,
+ 3, 4, 5,
+ default,
+ default,
+ default,
+ };
+
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 1, 3)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsNotEmpty(unpackedCollection.Array);
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 0], Is.EqualTo(3));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 1], Is.EqualTo(4));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 2], Is.EqualTo(5));
+ }
+ }
+
+ public class ArraySegment_string_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public ArraySegment collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection.Array, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ string[] array = new string[]
+ {
+ default,
+ default,
+ default,
+ };
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 0, 0)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsEmpty(unpackedCollection.Array);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ string[] array = new string[]
+ {
+ default,
+ "Some", "String", "Value",
+ default,
+ default,
+ default,
+ };
+
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 1, 3)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsNotEmpty(unpackedCollection.Array);
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 0], Is.EqualTo("Some"));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 1], Is.EqualTo("String"));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 2], Is.EqualTo("Value"));
+ }
+ }
+
+ public class ArraySegment_Vector3_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public ArraySegment collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection.Array, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Vector3[] array = new Vector3[]
+ {
+ default,
+ default,
+ default,
+ };
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 0, 0)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsEmpty(unpackedCollection.Array);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Vector3[] array = new Vector3[]
+ {
+ default,
+ new Vector3(1, 2, 3), new Vector3(4, 5, 6), new Vector3(7, 8, 9),
+ default,
+ default,
+ default,
+ };
+
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 1, 3)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsNotEmpty(unpackedCollection.Array);
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 0], Is.EqualTo(new Vector3(1, 2, 3)));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 1], Is.EqualTo(new Vector3(4, 5, 6)));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 2], Is.EqualTo(new Vector3(7, 8, 9)));
+ }
+ }
+
+ public class ArraySegment_FloatStringStruct_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public ArraySegment collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection.Array, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ FloatStringStruct[] array = new FloatStringStruct[]
+ {
+ default,
+ default,
+ default,
+ };
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 0, 0)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsEmpty(unpackedCollection.Array);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ FloatStringStruct[] array = new FloatStringStruct[]
+ {
+ default,
+ new FloatStringStruct { value = 3, anotherValue = "Some" }, new FloatStringStruct { value = 4, anotherValue = "String" }, new FloatStringStruct { value = 5, anotherValue = "Values" },
+ default,
+ default,
+ default,
+ };
+
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 1, 3)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsNotEmpty(unpackedCollection.Array);
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 0], Is.EqualTo(new FloatStringStruct { value = 3, anotherValue = "Some" }));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 1], Is.EqualTo(new FloatStringStruct { value = 4, anotherValue = "String" }));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 2], Is.EqualTo(new FloatStringStruct { value = 5, anotherValue = "Values" }));
+ }
+ }
+
+ public class ArraySegment_ClassWithNoConstructor_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public ArraySegment collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection.Array, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ ClassWithNoConstructor[] array = new ClassWithNoConstructor[]
+ {
+ default,
+ default,
+ default,
+ };
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 0, 0)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsEmpty(unpackedCollection.Array);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ ClassWithNoConstructor[] array = new ClassWithNoConstructor[]
+ {
+ default,
+ new ClassWithNoConstructor { a = 3 }, new ClassWithNoConstructor { a = 4 }, new ClassWithNoConstructor { a = 5 },
+ default,
+ default,
+ default,
+ };
+
+
+ Message message = new Message
+ {
+ collection = new ArraySegment(array, 1, 3)
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ ArraySegment unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection.Array);
+ Assert.IsNotEmpty(unpackedCollection.Array);
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 0].a, Is.EqualTo(new ClassWithNoConstructor { a = 3 }.a));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 1].a, Is.EqualTo(new ClassWithNoConstructor { a = 4 }.a));
+ Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 2].a, Is.EqualTo(new ClassWithNoConstructor { a = 5 }.a));
+ }
+ }
+
+ public class List_int_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public List collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new List {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new List
+ {
+ 3, 4, 5
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0], Is.EqualTo(3));
+ Assert.That(unpackedCollection[1], Is.EqualTo(4));
+ Assert.That(unpackedCollection[2], Is.EqualTo(5));
+ }
+ }
+
+ public class List_string_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public List collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new List {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new List
+ {
+ "Some", "String", "Value"
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0], Is.EqualTo("Some"));
+ Assert.That(unpackedCollection[1], Is.EqualTo("String"));
+ Assert.That(unpackedCollection[2], Is.EqualTo("Value"));
+ }
+ }
+
+ public class List_Vector3_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public List collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new List {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new List
+ {
+ new Vector3(1, 2, 3), new Vector3(4, 5, 6), new Vector3(7, 8, 9)
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0], Is.EqualTo(new Vector3(1, 2, 3)));
+ Assert.That(unpackedCollection[1], Is.EqualTo(new Vector3(4, 5, 6)));
+ Assert.That(unpackedCollection[2], Is.EqualTo(new Vector3(7, 8, 9)));
+ }
+ }
+
+ public class List_FloatStringStruct_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public List collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new List {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new List
+ {
+ new FloatStringStruct { value = 3, anotherValue = "Some" }, new FloatStringStruct { value = 4, anotherValue = "String" }, new FloatStringStruct { value = 5, anotherValue = "Values" }
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0], Is.EqualTo(new FloatStringStruct { value = 3, anotherValue = "Some" }));
+ Assert.That(unpackedCollection[1], Is.EqualTo(new FloatStringStruct { value = 4, anotherValue = "String" }));
+ Assert.That(unpackedCollection[2], Is.EqualTo(new FloatStringStruct { value = 5, anotherValue = "Values" }));
+ }
+ }
+
+ public class List_ClassWithNoConstructor_Test
+ {
+ public struct Message : NetworkMessage
+ {
+ public List collection;
+ }
+
+ [Test]
+ public void SendsNull()
+ {
+ Message message = new Message
+ {
+ collection = default
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.That(unpackedCollection, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void SendsEmpty()
+ {
+ Message message = new Message
+ {
+ collection = new List {}
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsEmpty(unpackedCollection);
+ }
+
+ [Test]
+ public void SendsData()
+ {
+ Message message = new Message
+ {
+ collection = new List
+ {
+ new ClassWithNoConstructor { a = 3 }, new ClassWithNoConstructor { a = 4 }, new ClassWithNoConstructor { a = 5 }
+ }
+ };
+
+ byte[] data = MessagePackingTest.PackToByteArray(message);
+
+ Message unpacked = MessagePackingTest.UnpackFromByteArray(data);
+ List unpackedCollection = unpacked.collection;
+
+ Assert.IsNotNull(unpackedCollection);
+ Assert.IsNotEmpty(unpackedCollection);
+ Assert.That(unpackedCollection[0].a, Is.EqualTo(new ClassWithNoConstructor { a = 3 }.a));
+ Assert.That(unpackedCollection[1].a, Is.EqualTo(new ClassWithNoConstructor { a = 4 }.a));
+ Assert.That(unpackedCollection[2].a, Is.EqualTo(new ClassWithNoConstructor { a = 5 }.a));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/Generated/CollectionWriterTests.gen.cs.meta b/Assets/Mirror/Tests/Editor/Generated/CollectionWriterTests.gen.cs.meta
new file mode 100644
index 000000000..28a873611
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Generated/CollectionWriterTests.gen.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c573b90d8949dec4cafb4f7401be9950
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/Grid2DTests.cs b/Assets/Mirror/Tests/Editor/Grid2DTests.cs
new file mode 100644
index 000000000..b3a608542
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Grid2DTests.cs
@@ -0,0 +1,58 @@
+using System.Collections.Generic;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ public class Grid2DTests
+ {
+ Grid2D grid = new Grid2D();
+
+ [Test]
+ public void AddAndGetNeighbours()
+ {
+ // add two at (0, 0)
+ grid.Add(Vector2Int.zero, 1);
+ grid.Add(Vector2Int.zero, 2);
+ HashSet result = new HashSet();
+ grid.GetWithNeighbours(Vector2Int.zero, result);
+ Assert.That(result.Count, Is.EqualTo(2));
+ Assert.That(result.Contains(1), Is.True);
+ Assert.That(result.Contains(2), Is.True);
+
+ // add a neighbour at (1, 1)
+ grid.Add(new Vector2Int(1, 1), 3);
+ grid.GetWithNeighbours(Vector2Int.zero, result);
+ Assert.That(result.Count, Is.EqualTo(3));
+ Assert.That(result.Contains(1), Is.True);
+ Assert.That(result.Contains(2), Is.True);
+ Assert.That(result.Contains(3), Is.True);
+ }
+
+ [Test]
+ public void GetIgnoresTooFarNeighbours()
+ {
+ // add at (0, 0)
+ grid.Add(Vector2Int.zero, 1);
+
+ // get at (2, 0) which is out of 9 neighbour radius
+ HashSet result = new HashSet();
+ grid.GetWithNeighbours(new Vector2Int(2, 0), result);
+ Assert.That(result.Count, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void ClearNonAlloc()
+ {
+ // add some
+ grid.Add(Vector2Int.zero, 1);
+ grid.Add(Vector2Int.zero, 2);
+
+ // clear and check if empty now
+ grid.ClearNonAlloc();
+ HashSet result = new HashSet();
+ grid.GetWithNeighbours(Vector2Int.zero, result);
+ Assert.That(result.Count, Is.EqualTo(0));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/Grid2DTests.cs.meta b/Assets/Mirror/Tests/Editor/Grid2DTests.cs.meta
new file mode 100644
index 000000000..2f71bbdc1
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Grid2DTests.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f8f3c4f37bb54824b5dfe70e0984b3d3
+timeCreated: 1613188745
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/InterestManagementTests_Common.cs b/Assets/Mirror/Tests/Editor/InterestManagementTests_Common.cs
new file mode 100644
index 000000000..8b57a8966
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/InterestManagementTests_Common.cs
@@ -0,0 +1,95 @@
+// default = no component = everyone sees everyone
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ public abstract class InterestManagementTests_Common : MirrorEditModeTest
+ {
+ protected GameObject gameObjectA;
+ protected NetworkIdentity identityA;
+ protected NetworkConnectionToClient connectionA;
+
+ protected GameObject gameObjectB;
+ protected NetworkIdentity identityB;
+ protected NetworkConnectionToClient connectionB;
+
+ [SetUp]
+ public override void SetUp()
+ {
+ base.SetUp();
+
+ // A with connectionId = 0x0A, netId = 0xAA
+ CreateNetworked(out gameObjectA, out identityA);
+ connectionA = new NetworkConnectionToClient(0x0A);
+ connectionA.isAuthenticated = true;
+ connectionA.isReady = true;
+ connectionA.identity = identityA;
+ NetworkServer.spawned[0xAA] = identityA;
+
+ // B
+ CreateNetworked(out gameObjectB, out identityB);
+ connectionB = new NetworkConnectionToClient(0x0B);
+ connectionB.isAuthenticated = true;
+ connectionB.isReady = true;
+ connectionB.identity = identityB;
+ NetworkServer.spawned[0xBB] = identityB;
+
+ // need to start server so that interest management works
+ NetworkServer.Listen(10);
+
+ // add both connections
+ NetworkServer.connections[connectionA.connectionId] = connectionA;
+ NetworkServer.connections[connectionB.connectionId] = connectionB;
+
+ // spawn both so that .observers is created
+ NetworkServer.Spawn(gameObjectA, connectionA);
+ NetworkServer.Spawn(gameObjectB, connectionB);
+
+ // spawn already runs interest management once
+ // clear observers and observing so tests can start from scratch
+ identityA.observers.Clear();
+ identityB.observers.Clear();
+ connectionA.observing.Clear();
+ connectionB.observing.Clear();
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ // set isServer is false. otherwise Destroy instead of
+ // DestroyImmediate is called internally, giving an error in Editor
+ identityA.isServer = false;
+
+ // set isServer is false. otherwise Destroy instead of
+ // DestroyImmediate is called internally, giving an error in Editor
+ identityB.isServer = false;
+
+ // clear connections first. calling OnDisconnect wouldn't work since
+ // we have no real clients.
+ NetworkServer.connections.Clear();
+
+ base.TearDown();
+ }
+
+ // player should always see self no matter what
+ [Test]
+ public void PlayerAlwaysSeesSelf_Initial()
+ {
+ // rebuild for A
+ // initial rebuild adds all connections if no interest management available
+ NetworkServer.RebuildObservers(identityA, true);
+
+ // should see self
+ Assert.That(identityA.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // forceHidden should still work
+ [Test]
+ public abstract void ForceHidden_Initial();
+
+ // forceShown should still work
+ [Test]
+ public abstract void ForceShown_Initial();
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/InterestManagementTests_Common.cs.meta b/Assets/Mirror/Tests/Editor/InterestManagementTests_Common.cs.meta
new file mode 100644
index 000000000..fa5a3884a
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/InterestManagementTests_Common.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f0349d2e3a74454e9dc8badec1db0289
+timeCreated: 1613049868
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/InterestManagementTests_Default.cs b/Assets/Mirror/Tests/Editor/InterestManagementTests_Default.cs
new file mode 100644
index 000000000..f33505d40
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/InterestManagementTests_Default.cs
@@ -0,0 +1,62 @@
+// default = no component = everyone sees everyone
+using NUnit.Framework;
+
+namespace Mirror.Tests
+{
+ public class InterestManagementTests_Default : InterestManagementTests_Common
+ {
+ // no interest management (default)
+ // => forceHidden should still work
+ [Test]
+ public override void ForceHidden_Initial()
+ {
+ // force hide A
+ identityA.visible = Visibility.ForceHidden;
+
+ // rebuild for both
+ // initial rebuild adds all connections if no interest management available
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // A should not be seen by B because A is force hidden
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
+ // B should be seen by A because
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // no interest management (default)
+ // => forceShown should still work
+ [Test]
+ public override void ForceShown_Initial()
+ {
+ // force show A
+ identityA.visible = Visibility.ForceShown;
+
+ // rebuild for both
+ // initial rebuild adds all connections if no interest management available
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // both should see each other because by default, everyone sees everyone
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // no interest management (default)
+ // => everyone should see everyone
+ [Test]
+ public void EveryoneSeesEveryone_Initial()
+ {
+ // rebuild for both
+ // initial rebuild adds all connections if no interest management available
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // both should see each other
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // TODO add tests to make sure old observers are removed etc.
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/InterestManagementTests_Default.cs.meta b/Assets/Mirror/Tests/Editor/InterestManagementTests_Default.cs.meta
new file mode 100644
index 000000000..96ed6142a
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/InterestManagementTests_Default.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: c5ac1fc2c25043378f80bc02d868a5d6
+timeCreated: 1613042576
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/InterestManagementTests_Distance.cs b/Assets/Mirror/Tests/Editor/InterestManagementTests_Distance.cs
new file mode 100644
index 000000000..9d8cf35a6
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/InterestManagementTests_Distance.cs
@@ -0,0 +1,142 @@
+// Vector3.Distance based
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ public class InterestManagementTests_Distance : InterestManagementTests_Common
+ {
+ DistanceInterestManagement aoi;
+
+ [SetUp]
+ public override void SetUp()
+ {
+ base.SetUp();
+
+ // create AOI GameObject
+ CreateGameObject(out GameObject go, out aoi);
+ aoi.visRange = 10;
+ // setup server aoi since InterestManagement Awake isn't called
+ NetworkServer.aoi = aoi;
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ base.TearDown();
+ // clear server aoi again
+ NetworkServer.aoi = null;
+ }
+
+ // brute force interest management
+ // => forceHidden should still work
+ [Test]
+ public override void ForceHidden_Initial()
+ {
+ // A and B are at (0,0,0) so within range!
+
+ // force hide A
+ identityA.visible = Visibility.ForceHidden;
+
+ // rebuild for both
+ // initial rebuild while both are within range
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // A should not be seen by B because A is force hidden
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
+ // B should be seen by A because
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // brute force interest management
+ // => forceHidden should still work
+ [Test]
+ public override void ForceShown_Initial()
+ {
+ // A and B are too far from each other
+ identityB.transform.position = Vector3.right * (aoi.visRange + 1);
+
+ // force show A
+ identityA.visible = Visibility.ForceShown;
+
+ // rebuild for both
+ // initial rebuild while both are within range
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // A should see B because A is force shown
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
+ // B should not be seen by A because they are too far from each other
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
+ }
+
+ // brute force interest management
+ // => everyone should see everyone if in range
+ [Test]
+ public void InRange_Initial()
+ {
+ // A and B are at (0,0,0) so within range!
+
+ // rebuild for both
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // both should see each other because they are in range
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // brute force interest management
+ // => everyone should see everyone if in range
+ [Test]
+ public void InRange_NotInitial()
+ {
+ // A and B are at (0,0,0) so within range!
+
+ // rebuild for both
+ NetworkServer.RebuildObservers(identityA, false);
+ NetworkServer.RebuildObservers(identityB, false);
+
+ // both should see each other because they are in range
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // brute force interest management
+ // => everyone should see everyone if in range
+ [Test]
+ public void OutOfRange_Initial()
+ {
+ // A and B are too far from each other
+ identityB.transform.position = Vector3.right * (aoi.visRange + 1);
+
+ // rebuild for boths
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // both should not see each other
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
+ }
+
+ // brute force interest management
+ // => everyone should see everyone if in range
+ [Test]
+ public void OutOfRange_NotInitial()
+ {
+ // A and B are too far from each other
+ identityB.transform.position = Vector3.right * (aoi.visRange + 1);
+
+ // rebuild for boths
+ NetworkServer.RebuildObservers(identityA, false);
+ NetworkServer.RebuildObservers(identityB, false);
+
+ // both should not see each other
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
+ }
+
+ // TODO add tests to make sure old observers are removed etc.
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/InterestManagementTests_Distance.cs.meta b/Assets/Mirror/Tests/Editor/InterestManagementTests_Distance.cs.meta
new file mode 100644
index 000000000..269736062
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/InterestManagementTests_Distance.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: ffb9dc0ff01e4f979c216984d7fc48d0
+timeCreated: 1613049838
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/InterestManagementTests_SpatialHashing.cs b/Assets/Mirror/Tests/Editor/InterestManagementTests_SpatialHashing.cs
new file mode 100644
index 000000000..78a3b9090
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/InterestManagementTests_SpatialHashing.cs
@@ -0,0 +1,154 @@
+// default = no component = everyone sees everyone
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ public class InterestManagementTests_SpatialHashing : InterestManagementTests_Common
+ {
+ SpatialHashingInterestManagement aoi;
+
+ [SetUp]
+ public override void SetUp()
+ {
+ base.SetUp();
+
+ // create spatial hashing object & component
+ CreateGameObject(out GameObject go, out aoi);
+ aoi.visRange = 10;
+ // setup server aoi since InterestManagement Awake isn't called
+ NetworkServer.aoi = aoi;
+
+ // rebuild grid once so the two connections are in there
+ aoi.Update();
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ base.TearDown();
+ // clear server aoi again
+ NetworkServer.aoi = null;
+ }
+
+ // brute force interest management
+ // => forceHidden should still work
+ [Test]
+ public override void ForceHidden_Initial()
+ {
+ // A and B are at (0,0,0) so within range!
+
+ // force hide A
+ identityA.visible = Visibility.ForceHidden;
+
+ // rebuild for both
+ // initial rebuild while both are within range
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // A should not be seen by B because A is force hidden
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
+ // B should be seen by A because
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // brute force interest management
+ // => forceShown should still work
+ [Test]
+ public override void ForceShown_Initial()
+ {
+ // A and B are too far from each other
+ identityB.transform.position = Vector3.right * (aoi.visRange + 1);
+
+ // force show A
+ identityA.visible = Visibility.ForceShown;
+
+ // update grid now that positions were changed
+ aoi.Update();
+
+ // rebuild for both
+ // initial rebuild while both are within range
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // A should see B because A is force shown
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
+ // B should not be seen by A because they are too far from each other
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
+ }
+
+ // brute force interest management
+ // => everyone should see everyone if in range
+ [Test]
+ public void InRange_Initial()
+ {
+ // A and B are at (0,0,0) so within range!
+
+ // rebuild for both
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // both should see each other because they are in range
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // brute force interest management
+ // => everyone should see everyone if in range
+ [Test]
+ public void InRange_NotInitial()
+ {
+ // A and B are at (0,0,0) so within range!
+
+ // rebuild for both
+ NetworkServer.RebuildObservers(identityA, false);
+ NetworkServer.RebuildObservers(identityB, false);
+
+ // both should see each other because they are in range
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
+ }
+
+ // brute force interest management
+ // => everyone should see everyone if in range
+ [Test]
+ public void OutOfRange_Initial()
+ {
+ // A and B are too far from each other
+ identityB.transform.position = Vector3.right * (aoi.visRange + 1);
+
+ // update grid now that positions were changed
+ aoi.Update();
+
+ // rebuild for boths
+ NetworkServer.RebuildObservers(identityA, true);
+ NetworkServer.RebuildObservers(identityB, true);
+
+ // both should not see each other
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
+ }
+
+ // brute force interest management
+ // => everyone should see everyone if in range
+ [Test]
+ public void OutOfRange_NotInitial()
+ {
+ // A and B are too far from each other
+ identityB.transform.position = Vector3.right * (aoi.visRange + 1);
+
+ // update grid now that positions were changed
+ aoi.Update();
+
+ // rebuild for boths
+ NetworkServer.RebuildObservers(identityA, false);
+ NetworkServer.RebuildObservers(identityB, false);
+
+ // both should not see each other
+ Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
+ Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
+ }
+
+ // TODO add tests to make sure old observers are removed etc.
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/InterestManagementTests_SpatialHashing.cs.meta b/Assets/Mirror/Tests/Editor/InterestManagementTests_SpatialHashing.cs.meta
new file mode 100644
index 000000000..8f145f0a4
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/InterestManagementTests_SpatialHashing.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 63d9e0d6aa9a4eec8b4e2db07e6261bf
+timeCreated: 1613117841
\ No newline at end of file
diff --git a/Assets/Mirror/Tests/Editor/LocalConnectionTest.cs b/Assets/Mirror/Tests/Editor/LocalConnectionTest.cs
new file mode 100644
index 000000000..9fe986b94
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/LocalConnectionTest.cs
@@ -0,0 +1,71 @@
+using NUnit.Framework;
+
+namespace Mirror.Tests
+{
+ public class LocalConnectionTest : MirrorTest
+ {
+ struct TestMessage : NetworkMessage {}
+
+ LocalConnectionToClient connectionToClient;
+ LocalConnectionToServer connectionToServer;
+
+ [SetUp]
+ public override void SetUp()
+ {
+ base.SetUp();
+
+ CreateLocalConnectionPair(out connectionToClient, out connectionToServer);
+
+ // set up server/client connections so message handling works
+ NetworkClient.connection = connectionToServer;
+ NetworkServer.connections[connectionToClient.connectionId] = connectionToClient;
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ connectionToServer.Disconnect();
+ base.TearDown();
+ }
+
+ [Test]
+ public void ClientToServerTest()
+ {
+ Assert.That(connectionToClient.address, Is.EqualTo("localhost"));
+
+ bool invoked = false;
+ void Handler(NetworkConnection conn, TestMessage message)
+ {
+ invoked = true;
+ }
+
+ // set up handler on the server connection
+ NetworkServer.RegisterHandler(Handler, false);
+
+ connectionToServer.Send(new TestMessage());
+ connectionToServer.Update();
+
+ Assert.True(invoked, "handler should have been invoked");
+ }
+
+ [Test]
+ public void ServerToClient()
+ {
+ Assert.That(connectionToServer.address, Is.EqualTo("localhost"));
+
+ bool invoked = false;
+ void Handler(TestMessage message)
+ {
+ invoked = true;
+ }
+
+ // set up handler on the client connection
+ NetworkClient.RegisterHandler(Handler, false);
+
+ connectionToClient.Send(new TestMessage());
+ connectionToServer.Update();
+
+ Assert.True(invoked, "handler should have been invoked");
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/LocalConnectionTest.cs.meta b/Assets/Mirror/Tests/Editor/LocalConnectionTest.cs.meta
new file mode 100644
index 000000000..a1a525792
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/LocalConnectionTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 405841e2a21c64d7585d5c71d06ffff2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs b/Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs
new file mode 100644
index 000000000..89a84b7a5
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs
@@ -0,0 +1,125 @@
+// TODO Send only supports structs. Consider removing those tests.
+using NUnit.Framework;
+
+namespace Mirror.Tests.MessageTests
+{
+ class ParentMessage : NetworkMessage
+ {
+ public int parentValue;
+ }
+
+ class ChildMessage : ParentMessage
+ {
+ public int childValue;
+ }
+
+
+ public abstract class RequestMessageBase : NetworkMessage
+ {
+ public int responseId = 0;
+ }
+ public class ResponseMessage : RequestMessageBase
+ {
+ public int state;
+ public string message = "";
+ public int errorCode = 0; // optional for error codes
+ }
+
+ //reverseOrder to test this https://github.com/vis2k/Mirror/issues/1925
+ public class ResponseMessageReverse : RequestMessageBaseReverse
+ {
+ public int state;
+ public string message = "";
+ public int errorCode = 0; // optional for error codes
+ }
+ public abstract class RequestMessageBaseReverse : NetworkMessage
+ {
+ public int responseId = 0;
+ }
+
+ [TestFixture]
+ public class MessageInheritanceTest
+ {
+ [Test]
+ public void SendsVauesInParentAndChildClass()
+ {
+ NetworkWriter writer = new NetworkWriter();
+
+ writer.Write(new ChildMessage
+ {
+ parentValue = 3,
+ childValue = 4
+ });
+
+ byte[] arr = writer.ToArray();
+
+ NetworkReader reader = new NetworkReader(arr);
+ ChildMessage received = reader.Read();
+
+ Assert.AreEqual(3, received.parentValue);
+ Assert.AreEqual(4, received.childValue);
+
+ int writeLength = writer.Position;
+ int readLength = reader.Position;
+ Assert.That(writeLength == readLength, $"OnSerializeAll and OnDeserializeAll calls write the same amount of data\n writeLength={writeLength}\n readLength={readLength}");
+ }
+
+ [Test]
+ public void SendsVauesWhenUsingAbstractClass()
+ {
+ NetworkWriter writer = new NetworkWriter();
+
+ const int state = 2;
+ const string message = "hello world";
+ const int responseId = 5;
+ writer.Write(new ResponseMessage
+ {
+ state = state,
+ message = message,
+ responseId = responseId,
+ });
+
+ byte[] arr = writer.ToArray();
+
+ NetworkReader reader = new NetworkReader(arr);
+ ResponseMessage received = reader.Read();
+
+ Assert.AreEqual(state, received.state);
+ Assert.AreEqual(message, received.message);
+ Assert.AreEqual(responseId, received.responseId);
+
+ int writeLength = writer.Position;
+ int readLength = reader.Position;
+ Assert.That(writeLength == readLength, $"OnSerializeAll and OnDeserializeAll calls write the same amount of data\n writeLength={writeLength}\n readLength={readLength}");
+ }
+
+ [Test]
+ public void SendsVauesWhenUsingAbstractClassReverseDefineOrder()
+ {
+ NetworkWriter writer = new NetworkWriter();
+
+ const int state = 2;
+ const string message = "hello world";
+ const int responseId = 5;
+ writer.Write(new ResponseMessageReverse
+ {
+ state = state,
+ message = message,
+ responseId = responseId,
+ });
+
+ byte[] arr = writer.ToArray();
+
+ NetworkReader reader = new NetworkReader(arr);
+ ResponseMessageReverse received = reader.Read();
+
+ Assert.AreEqual(state, received.state);
+ Assert.AreEqual(message, received.message);
+ Assert.AreEqual(responseId, received.responseId);
+
+ int writeLength = writer.Position;
+ int readLength = reader.Position;
+ Assert.That(writeLength == readLength, $"OnSerializeAll and OnDeserializeAll calls write the same amount of data\n writeLength={writeLength}\n readLength={readLength}");
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs.meta b/Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs.meta
new file mode 100644
index 000000000..4e78acae8
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 808855b645f9843d2b3077ab1304b2b3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/MessagePackingTest.cs b/Assets/Mirror/Tests/Editor/MessagePackingTest.cs
new file mode 100644
index 000000000..570edb435
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/MessagePackingTest.cs
@@ -0,0 +1,143 @@
+using System;
+using Mirror.Tests.MessageTests;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ [TestFixture]
+ public class MessagePackingTest
+ {
+ public struct EmptyMessage : NetworkMessage {}
+
+ // helper function to pack message into a simple byte[]
+ public static byte[] PackToByteArray(T message)
+ where T : struct, NetworkMessage
+ {
+ using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
+ {
+ MessagePacking.Pack(message, writer);
+ return writer.ToArray();
+ }
+ }
+
+ // unpack a message we received
+ public static T UnpackFromByteArray(byte[] data)
+ where T : struct, NetworkMessage
+ {
+ using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(data))
+ {
+ int msgType = MessagePacking.GetId();
+
+ int id = networkReader.ReadUShort();
+ if (id != msgType)
+ throw new FormatException($"Invalid message, could not unpack {typeof(T).FullName}");
+
+ return networkReader.Read();
+ }
+ }
+
+ // message id is generated from message.FullName.
+ // should be consistent across all platforms.
+ [Test]
+ public void GetId()
+ {
+ // "Mirror.Tests.MessageTests.TestMessage"
+ Debug.Log(typeof(TestMessage).FullName);
+ Assert.That(MessagePacking.GetId(), Is.EqualTo(0x8706));
+ }
+
+ [Test]
+ public void TestPacking()
+ {
+ SceneMessage message = new SceneMessage()
+ {
+ sceneName = "Hello world",
+ sceneOperation = SceneOperation.LoadAdditive
+ };
+
+ byte[] data = PackToByteArray(message);
+
+ SceneMessage unpacked = UnpackFromByteArray(data);
+
+ Assert.That(unpacked.sceneName, Is.EqualTo("Hello world"));
+ Assert.That(unpacked.sceneOperation, Is.EqualTo(SceneOperation.LoadAdditive));
+ }
+
+ [Test]
+ public void UnpackWrongMessage()
+ {
+ SpawnMessage message = new SpawnMessage();
+
+ byte[] data = PackToByteArray(message);
+
+ Assert.Throws(() =>
+ {
+ ReadyMessage unpacked = UnpackFromByteArray(data);
+ });
+ }
+
+ [Test]
+ public void TestUnpackIdMismatch()
+ {
+ // Unpack has a id != msgType case that throws a FormatException.
+ // let's try to trigger it.
+
+ SceneMessage message = new SceneMessage()
+ {
+ sceneName = "Hello world",
+ sceneOperation = SceneOperation.LoadAdditive
+ };
+
+ byte[] data = PackToByteArray(message);
+
+ // overwrite the id
+ data[0] = 0x01;
+ data[1] = 0x02;
+
+ Assert.Throws(() =>
+ {
+ SceneMessage unpacked = UnpackFromByteArray(data);
+ });
+ }
+
+ [Test]
+ public void TestUnpackMessageNonGeneric()
+ {
+ // try a regular message
+ SceneMessage message = new SceneMessage()
+ {
+ sceneName = "Hello world",
+ sceneOperation = SceneOperation.LoadAdditive
+ };
+
+ byte[] data = PackToByteArray(message);
+ NetworkReader reader = new NetworkReader(data);
+
+ bool result = MessagePacking.Unpack(reader, out ushort msgType);
+ Assert.That(result, Is.EqualTo(true));
+ Assert.That(msgType, Is.EqualTo(BitConverter.ToUInt16(data, 0)));
+ }
+
+ [Test]
+ public void UnpackInvalidMessage()
+ {
+ // try an invalid message
+ NetworkReader reader2 = new NetworkReader(new byte[0]);
+ bool result2 = MessagePacking.Unpack(reader2, out ushort msgType2);
+ Assert.That(result2, Is.EqualTo(false));
+ Assert.That(msgType2, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void MessageIdIsCorrectLength()
+ {
+ NetworkWriter writer = new NetworkWriter();
+ MessagePacking.Pack(new EmptyMessage(), writer);
+
+ ArraySegment segment = writer.ToArraySegment();
+
+ Assert.That(segment.Count, Is.EqualTo(MessagePacking.HeaderSize), "Empty message should have same size as HeaderSize");
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/MessagePackingTest.cs.meta b/Assets/Mirror/Tests/Editor/MessagePackingTest.cs.meta
new file mode 100644
index 000000000..70e62403b
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/MessagePackingTest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8d57c17d9ee7c49e6bacc54ddbeac751
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/MiddlewareTransportTest.cs b/Assets/Mirror/Tests/Editor/MiddlewareTransportTest.cs
new file mode 100644
index 000000000..bb24fd8d9
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/MiddlewareTransportTest.cs
@@ -0,0 +1,386 @@
+using System;
+using System.IO;
+using NSubstitute;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Mirror.Tests
+{
+ public class MyMiddleware : MiddlewareTransport {}
+
+ [Description("Test to make sure inner methods are called when using Middleware Transport")]
+ public class MiddlewareTransportTest
+ {
+ Transport inner;
+ MyMiddleware middleware;
+
+ [SetUp]
+ public void Setup()
+ {
+ inner = Substitute.For();
+
+ GameObject gameObject = new GameObject();
+
+ middleware = gameObject.AddComponent();
+ middleware.inner = inner;
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ GameObject.DestroyImmediate(middleware.gameObject);
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void TestAvailable(bool available)
+ {
+ inner.Available().Returns(available);
+
+ Assert.That(middleware.Available(), Is.EqualTo(available));
+
+ inner.Received(1).Available();
+ }
+
+ [Test]
+ [TestCase(Channels.Reliable, 4000)]
+ [TestCase(Channels.Reliable, 2000)]
+ [TestCase(Channels.Unreliable, 4000)]
+ public void TestGetMaxPacketSize(int channel, int packageSize)
+ {
+ inner.GetMaxPacketSize(Arg.Any()).Returns(packageSize);
+
+ Assert.That(middleware.GetMaxPacketSize(channel), Is.EqualTo(packageSize));
+
+ inner.Received(1).GetMaxPacketSize(Arg.Is(x => x == channel));
+ inner.Received(0).GetMaxPacketSize(Arg.Is(x => x != channel));
+ }
+
+ [Test]
+ public void TestShutdown()
+ {
+ middleware.Shutdown();
+
+ inner.Received(1).Shutdown();
+ }
+
+ [Test]
+ [TestCase("localhost")]
+ [TestCase("example.com")]
+ public void TestClientConnect(string address)
+ {
+ middleware.ClientConnect(address);
+
+ inner.Received(1).ClientConnect(address);
+ inner.Received(0).ClientConnect(Arg.Is(x => x != address));
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void TestClientConnected(bool connected)
+ {
+ inner.ClientConnected().Returns(connected);
+
+ Assert.That(middleware.ClientConnected(), Is.EqualTo(connected));
+
+ inner.Received(1).ClientConnected();
+ }
+
+ [Test]
+ public void TestClientDisconnect()
+ {
+ middleware.ClientDisconnect();
+
+ inner.Received(1).ClientDisconnect();
+ }
+
+ [Test]
+ [TestCase(Channels.Reliable)]
+ [TestCase(Channels.Unreliable)]
+ public void TestClientSend(int channel)
+ {
+ byte[] array = new byte[10];
+ const int offset = 2;
+ const int count = 5;
+ ArraySegment segment = new ArraySegment(array, offset, count);
+
+ middleware.ClientSend(segment, channel);
+
+ inner.Received(1).ClientSend(Arg.Is>(x => x.Array == array && x.Offset == offset && x.Count == count), channel);
+ inner.Received(0).ClientSend(Arg.Any>(), Arg.Is(x => x != channel));
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void TestServerActive(bool active)
+ {
+ inner.ServerActive().Returns(active);
+
+ Assert.That(middleware.ServerActive(), Is.EqualTo(active));
+
+ inner.Received(1).ServerActive();
+ }
+
+ [Test]
+ public void TestServerStart()
+ {
+ middleware.ServerStart();
+
+ inner.Received(1).ServerStart();
+ }
+
+ [Test]
+ public void TestServerStop()
+ {
+ middleware.ServerStop();
+
+ inner.Received(1).ServerStop();
+ }
+
+ [Test]
+ [TestCase(0, 0)]
+ [TestCase(1, 0)]
+ [TestCase(0, 1)]
+ [TestCase(19, 1)]
+ public void TestServerSend(int id, int channel)
+ {
+ byte[] array = new byte[10];
+ const int offset = 2;
+ const int count = 5;
+ ArraySegment segment = new ArraySegment(array, offset, count);
+
+ middleware.ServerSend(id, segment, channel);
+
+ inner.Received(1).ServerSend(id, Arg.Is>(x => x.Array == array && x.Offset == offset && x.Count == count), channel);
+ // only need to check first arg,
+ inner.Received(0).ServerSend(Arg.Is(x => x != id), Arg.Any>(), Arg.Any());
+ }
+
+ [Test]
+ [TestCase(0, "tcp4://localhost:7777")]
+ [TestCase(19, "tcp4://example.com:7777")]
+ public void TestServerGetClientAddress(int id, string result)
+ {
+ inner.ServerGetClientAddress(id).Returns(result);
+
+ Assert.That(middleware.ServerGetClientAddress(id), Is.EqualTo(result));
+
+ inner.Received(1).ServerGetClientAddress(id);
+ inner.Received(0).ServerGetClientAddress(Arg.Is(x => x != id));
+
+ }
+
+ [Test]
+ [TestCase("tcp4://localhost:7777")]
+ [TestCase("tcp4://example.com:7777")]
+ public void TestServerUri(string address)
+ {
+ Uri uri = new Uri(address);
+ inner.ServerUri().Returns(uri);
+
+ Assert.That(middleware.ServerUri(), Is.EqualTo(uri));
+
+ inner.Received(1).ServerUri();
+ }
+
+ [Test]
+ public void TestClientConnectedCallback()
+ {
+ int called = 0;
+ middleware.OnClientConnected = () =>
+ {
+ called++;
+ };
+ // connect to give callback to inner
+ middleware.ClientConnect("localhost");
+
+ inner.OnClientConnected.Invoke();
+ Assert.That(called, Is.EqualTo(1));
+
+ inner.OnClientConnected.Invoke();
+ Assert.That(called, Is.EqualTo(2));
+ }
+
+ [Test]
+ [TestCase(0)]
+ [TestCase(1)]
+ public void TestClientDataReceivedCallback(int channel)
+ {
+ byte[] data = new byte[4];
+ ArraySegment