using System; using System.Collections.Generic; using System.IO; using Mirror.Tests.RemoteAttrributeTest; using NUnit.Framework; using UnityEngine; namespace Mirror.Tests { [TestFixture] public class NetworkWriterTest : MirrorEditModeTest { [SetUp] public override void SetUp() { base.SetUp(); // start server & connect client because we need spawn functions NetworkServer.Listen(1); ConnectClientBlockingAuthenticatedAndReady(out _); } /* uncomment if needed. commented for faster test workflow. this takes >3s. [Test] public void Benchmark() { // 10 million reads, Unity 2019.3, code coverage disabled // 4014ms ms NetworkWriter writer = new NetworkWriter(); for (int i = 0; i < 10000000; ++i) { writer.SetLength(0); writer.WriteVector3(new Vector3(1, 2, 3)); } } */ // Write/ReadBlittable assumes same endianness on server & client. [Test] public void LittleEndianPlatform() { Assert.That(BitConverter.IsLittleEndian, Is.True); } // some platforms may not support unaligned *(T*) reads/writes. // but it still needs to work with our workaround. // let's have an editor test to maybe catch it early. // Editor runs Win/Mac/Linux and atm the issue only exists on Android, // but let's have a test anyway. // see also: https://github.com/vis2k/Mirror/issues/3044 [Test] public void WriteUnaligned() { NetworkWriter writer = new NetworkWriter(); // make unaligned writer.WriteByte(0xFF); // write a double writer.WriteDouble(Math.PI); // should have written 9 bytes without throwing exceptions Assert.That(writer.Position, Is.EqualTo(9)); } [Test] public void TestWritingSmallMessage() { // try serializing less than 32kb and see what happens NetworkWriter writer = new NetworkWriter(); for (int i = 0; i < 30000 / 4; ++i) writer.WriteInt(i); Assert.That(writer.Position, Is.EqualTo(30000)); } [Test] public void TestWritingLargeMessage() { // try serializing more than 32kb and see what happens NetworkWriter writer = new NetworkWriter(); for (int i = 0; i < 40000 / 4; ++i) writer.WriteInt(i); Assert.That(writer.Position, Is.EqualTo(40000)); } [Test] public void TestWritingHugeArray() { // try serializing array more than 64KB large and see what happens NetworkWriter writer = new NetworkWriter(); writer.WriteBytesAndSize(new byte[100000]); byte[] data = writer.ToArray(); NetworkReader reader = new NetworkReader(data); byte[] deserialized = reader.ReadBytesAndSize(); Assert.That(deserialized.Length, Is.EqualTo(100000)); } [Test] public void TestWritingBytesSegment() { byte[] data = { 1, 2, 3 }; NetworkWriter writer = new NetworkWriter(); writer.WriteBytes(data, 0, data.Length); NetworkReader reader = new NetworkReader(writer.ToArray()); ArraySegment deserialized = reader.ReadBytesSegment(data.Length); Assert.That(deserialized.Count, Is.EqualTo(data.Length)); for (int i = 0; i < data.Length; ++i) Assert.That(deserialized.Array[deserialized.Offset + i], Is.EqualTo(data[i])); } // write byte[], read segment [Test] public void TestWritingBytesAndReadingSegment() { byte[] data = { 1, 2, 3 }; NetworkWriter writer = new NetworkWriter(); writer.WriteBytesAndSize(data); NetworkReader reader = new NetworkReader(writer.ToArray()); ArraySegment deserialized = reader.ReadBytesAndSizeSegment(); Assert.That(deserialized.Count, Is.EqualTo(data.Length)); for (int i = 0; i < data.Length; ++i) Assert.That(deserialized.Array[deserialized.Offset + i], Is.EqualTo(data[i])); } // write segment, read segment [Test] public void TestWritingSegmentAndReadingSegment() { byte[] data = { 1, 2, 3, 4 }; // [2, 3] ArraySegment segment = new ArraySegment(data, 1, 1); NetworkWriter writer = new NetworkWriter(); writer.WriteBytesAndSizeSegment(segment); NetworkReader reader = new NetworkReader(writer.ToArray()); ArraySegment deserialized = reader.ReadBytesAndSizeSegment(); Assert.That(deserialized.Count, Is.EqualTo(segment.Count)); for (int i = 0; i < segment.Count; ++i) Assert.That(deserialized.Array[deserialized.Offset + i], Is.EqualTo(segment.Array[segment.Offset + i])); } [Test] public void TestResetSetsPotionAndLength() { NetworkWriter writer = new NetworkWriter(); writer.WriteString("I saw"); writer.WriteLong(0xA_FADED_DEAD_EEL); writer.WriteString("and ate it"); writer.Reset(); Assert.That(writer.Position, Is.EqualTo(0)); byte[] data = writer.ToArray(); Assert.That(data, Is.Empty); } [Test] public void TestReading0LengthBytesAndSize() { NetworkWriter writer = new NetworkWriter(); writer.WriteBytesAndSize(new byte[] {}); NetworkReader reader = new NetworkReader(writer.ToArray()); Assert.That(reader.ReadBytesAndSize().Length, Is.EqualTo(0)); } [Test] public void TestReading0LengthBytes() { NetworkWriter writer = new NetworkWriter(); writer.WriteBytes(new byte[] {}, 0, 0); NetworkReader reader = new NetworkReader(writer.ToArray()); Assert.That(reader.ReadBytes(0).Length, Is.EqualTo(0)); } [Test] public void TestWritingNegativeBytesAndSizeFailure() { NetworkWriter writer = new NetworkWriter(); Assert.Throws(() => writer.WriteBytesAndSize(new byte[0], 0, -1)); Assert.That(writer.Position, Is.EqualTo(0)); } [Test] public void TestReadingTooMuch() { void EnsureThrows(Action read, byte[] data = null) { Assert.Throws(() => read(new NetworkReader(data ?? new byte[] {}))); } // Try reading more than there is data to be read from // This should throw EndOfStreamException always EnsureThrows(r => r.ReadByte()); EnsureThrows(r => r.ReadSByte()); EnsureThrows(r => r.ReadChar()); EnsureThrows(r => r.ReadBool()); EnsureThrows(r => r.ReadShort()); EnsureThrows(r => r.ReadUShort()); EnsureThrows(r => r.ReadInt()); EnsureThrows(r => r.ReadUInt()); EnsureThrows(r => r.ReadLong()); EnsureThrows(r => r.ReadULong()); EnsureThrows(r => r.ReadDecimal()); EnsureThrows(r => r.ReadFloat()); EnsureThrows(r => r.ReadDouble()); EnsureThrows(r => r.ReadString()); EnsureThrows(r => r.ReadBytes(1)); EnsureThrows(r => r.ReadBytes(2)); EnsureThrows(r => r.ReadBytes(3)); EnsureThrows(r => r.ReadBytes(4)); EnsureThrows(r => r.ReadBytes(8)); EnsureThrows(r => r.ReadBytes(16)); EnsureThrows(r => r.ReadBytes(32)); EnsureThrows(r => r.ReadBytes(100)); EnsureThrows(r => r.ReadBytes(1000)); EnsureThrows(r => r.ReadBytes(10000)); EnsureThrows(r => r.ReadBytes(1000000)); EnsureThrows(r => r.ReadBytes(10000000)); EnsureThrows(r => r.ReadBytesAndSize()); EnsureThrows(r => r.ReadVector2()); EnsureThrows(r => r.ReadVector3()); EnsureThrows(r => r.ReadVector4()); EnsureThrows(r => r.ReadVector2Int()); EnsureThrows(r => r.ReadVector3Int()); EnsureThrows(r => r.ReadColor()); EnsureThrows(r => r.ReadColor32()); EnsureThrows(r => r.ReadQuaternion()); EnsureThrows(r => r.ReadRect()); EnsureThrows(r => r.ReadPlane()); EnsureThrows(r => r.ReadRay()); EnsureThrows(r => r.ReadMatrix4x4()); EnsureThrows(r => r.ReadGuid()); } [Test] public void TestBool() { bool[] inputs = { true, false }; foreach (bool input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteBool(input); NetworkReader reader = new NetworkReader(writer.ToArray()); bool output = reader.ReadBool(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestBoolNullable() { bool? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteBoolNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); bool? output = reader.ReadBoolNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestByte() { byte[] inputs = { 1, 2, 3, 4 }; foreach (byte input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteByte(input); NetworkReader reader = new NetworkReader(writer.ToArray()); byte output = reader.ReadByte(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestByteNullable() { byte? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteByteNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); byte? output = reader.ReadByteNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestSByte() { sbyte[] inputs = { 1, 2, 3, 4 }; foreach (sbyte input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteSByte(input); NetworkReader reader = new NetworkReader(writer.ToArray()); sbyte output = reader.ReadSByte(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestSByteNullable() { sbyte? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteSByteNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); sbyte? output = reader.ReadSByteNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestVector2() { Vector2[] inputs = { Vector2.right, Vector2.up, Vector2.zero, Vector2.one, Vector2.positiveInfinity, new Vector2(0.1f,3.1f) }; foreach (Vector2 input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteVector2(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector2 output = reader.ReadVector2(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestVector2Nullable() { Vector2? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteVector2Nullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector2? output = reader.ReadVector2Nullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestVector3() { Vector3[] inputs = { Vector3.right, Vector3.up, Vector3.zero, Vector3.one, Vector3.positiveInfinity, Vector3.forward, new Vector3(0.1f,3.1f,1.4f) }; foreach (Vector3 input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteVector3(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector3 output = reader.ReadVector3(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestVector3Nullable() { Vector3? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteVector3Nullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector3? output = reader.ReadVector3Nullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestVector4() { Vector4[] inputs = { Vector3.right, Vector3.up, Vector4.zero, Vector4.one, Vector4.positiveInfinity, new Vector4(0.1f,3.1f,1.4f,4.9f) }; foreach (Vector4 input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteVector4(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector4 output = reader.ReadVector4(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestVector4Nullable() { Vector4? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteVector4Nullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector4? output = reader.ReadVector4Nullable(); Assert.That(output, Is.EqualTo(output)); } [Test] public void TestVector2Int() { Vector2Int[] inputs = { Vector2Int.down, Vector2Int.up, Vector2Int.left, Vector2Int.zero, new Vector2Int(-1023,-999999), new Vector2Int(257,12345), new Vector2Int(0x7fffffff,-12345), }; foreach (Vector2Int input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteVector2Int(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector2Int output = reader.ReadVector2Int(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestVector2IntNullable() { Vector2Int? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteVector2IntNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector2Int? output = reader.ReadVector2IntNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestVector3Int() { Vector3Int[] inputs = { Vector3Int.down, Vector3Int.up, Vector3Int.left, Vector3Int.one, Vector3Int.zero, new Vector3Int(-1023,-999999,1392), new Vector3Int(257,12345,-6132), new Vector3Int(0x7fffffff,-12345,-1), }; foreach (Vector3Int input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteVector3Int(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector3Int output = reader.ReadVector3Int(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestVector3IntNullable() { Vector3Int? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteVector3IntNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Vector3Int? output = reader.ReadVector3IntNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestColor() { Color[] inputs = { Color.black, Color.blue, Color.cyan, Color.yellow, Color.magenta, Color.white, new Color(0.401f,0.2f,1.0f,0.123f) }; foreach (Color input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteColor(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Color output = reader.ReadColor(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestColorNullable() { Color? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteColorNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Color? output = reader.ReadColorNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestColor32() { Color32[] inputs = { Color.black, Color.blue, Color.cyan, Color.yellow, Color.magenta, Color.white, new Color32(0xab,0xcd,0xef,0x12), new Color32(125,126,0,255) }; foreach (Color32 input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteColor32(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Color32 output = reader.ReadColor32(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestColor32Nullable() { Color32? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteColor32Nullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Color32? output = reader.ReadColor32Nullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestQuaternion() { Quaternion[] inputs = { Quaternion.identity, default, Quaternion.LookRotation(new Vector3(0.3f,0.4f,0.5f)), Quaternion.Euler(45f,56f,Mathf.PI) }; foreach (Quaternion input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteQuaternion(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Quaternion output = reader.ReadQuaternion(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestQuaternionNullable() { Quaternion? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteQuaternionNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Quaternion? output = reader.ReadQuaternionNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestRect() { Rect[] inputs = { Rect.zero, new Rect(1004.1f,2.001f,4636,400f), new Rect(-100.622f,-200f,300f,975.6f), new Rect(-100f,435,-30.04f,400f), new Rect(55,-200f,-44,-123), }; foreach (Rect input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteRect(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Rect output = reader.ReadRect(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestRectNullable() { Rect? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteRectNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Rect? output = reader.ReadRectNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestPlane() { Plane[] inputs = { new Plane(new Vector3(-0.24f,0.34f,0.2f), 120.2f), new Plane(new Vector3(0.133f,0.34f,0.122f), -10.135f), new Plane(new Vector3(0.133f,-0.0f,float.MaxValue), -13.3f), new Plane(new Vector3(0.1f,-0.2f,0.3f), 14.5f), }; foreach (Plane input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WritePlane(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Plane output = reader.ReadPlane(); // note: Plane constructor does math internally, resulting in // floating point precision loss that causes exact comparison // to fail the test. So we test that the difference is small. Assert.That((output.normal - input.normal).magnitude, Is.LessThan(1e-6f)); Assert.That(output.distance, Is.EqualTo(input.distance)); } } [Test] public void TestPlaneNullable() { Plane? input = null; NetworkWriter writer = new NetworkWriter(); writer.WritePlaneNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Plane? output = reader.ReadPlaneNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestRay() { Ray[] inputs = { new Ray(Vector3.up,Vector3.down), new Ray(new Vector3(0.1f,0.2f,0.3f), new Vector3(0.4f,0.5f,0.6f)), new Ray(new Vector3(-0.3f,0.5f,0.999f), new Vector3(1f,100.1f,20f)), }; foreach (Ray input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteRay(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Ray output = reader.ReadRay(); Assert.That((output.direction - input.direction).magnitude, Is.LessThan(1e-6f)); Assert.That(output.origin, Is.EqualTo(input.origin)); } } [Test] public void TestRayNullable() { Ray? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteRayNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Ray? output = reader.ReadRayNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestMatrix4x4() { Matrix4x4[] inputs = { Matrix4x4.identity, Matrix4x4.zero, Matrix4x4.Scale(Vector3.one * 0.12345f), Matrix4x4.LookAt(Vector2.up,Vector3.right,Vector3.forward), Matrix4x4.Rotate(Quaternion.LookRotation(Vector3.one)), }; foreach (Matrix4x4 input in inputs) { NetworkWriter writer = new NetworkWriter(); writer.WriteMatrix4x4(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Matrix4x4 output = reader.ReadMatrix4x4(); Assert.That(output, Is.EqualTo(input)); } } [Test] public void TestMatrix4x4Nullable() { Matrix4x4? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteMatrix4x4Nullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Matrix4x4? output = reader.ReadMatrix4x4Nullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestReadingInvalidString() { // These are all bytes which never show up in valid UTF8 encodings. // NetworkReader should gracefully handle maliciously crafted input. byte[] invalidUTF8bytes = { 0xC0, 0xC1, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, }; foreach (byte invalid in invalidUTF8bytes) { NetworkWriter writer = new NetworkWriter(); writer.WriteString("an uncorrupted string"); byte[] data = writer.ToArray(); data[10] = invalid; NetworkReader reader = new NetworkReader(data); Assert.Throws(() => reader.ReadString()); } } [Test] public void TestReadingTruncatedString() { NetworkWriter writer = new NetworkWriter(); writer.WriteString("a string longer than 10 bytes"); writer.Reset(); NetworkReader reader = new NetworkReader(writer.ToArray()); Assert.Throws(() => reader.ReadString()); } [Test] public void TestToArray() { // write 2 bytes NetworkWriter writer = new NetworkWriter(); writer.WriteByte(1); writer.WriteByte(2); // .ToArray() length is 2? Assert.That(writer.ToArray().Length, Is.EqualTo(2)); // set position back by one writer.Position = 1; // Changing the position alter the size of the data Assert.That(writer.ToArray().Length, Is.EqualTo(1)); } [Test] public void TestToArraySegment() { NetworkWriter writer = new NetworkWriter(); writer.WriteString("hello"); writer.WriteString("world"); NetworkReader reader = new NetworkReader(writer.ToArraySegment()); Assert.That(reader.ReadString(), Is.EqualTo("hello")); Assert.That(reader.ReadString(), Is.EqualTo("world")); } // sometimes we may serialize nothing, then call ToArraySegment. // make sure this works even if empty. [Test] public void TestToArraySegment_EmptyContent() { NetworkWriter writer = new NetworkWriter(); ArraySegment segment = writer.ToArraySegment(); Assert.That(segment.Count, Is.EqualTo(0)); } [Test] public void TestChar() { char a = 'a'; char u = 'โ“ค'; NetworkWriter writer = new NetworkWriter(); writer.WriteChar(a); writer.WriteChar(u); NetworkReader reader = new NetworkReader(writer.ToArray()); char a2 = reader.ReadChar(); Assert.That(a2, Is.EqualTo(a)); char u2 = reader.ReadChar(); Assert.That(u2, Is.EqualTo(u)); } [Test] public void TestCharNullable() { char? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteCharNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); char? output = reader.ReadCharNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestUnicodeString() { string[] weirdUnicode = { "๐”ฒ๐”ซ๐”ฆ๐” ๐”ฌ๐”ก๐”ข ๐”ฑ๐”ข๐”ฐ๐”ฑ", "๐–š๐–“๐–Ž๐–ˆ๐–”๐–‰๐–Š ๐–™๐–Š๐–˜๐–™", "๐ฎ๐ง๐ข๐œ๐จ๐๐ž ๐ญ๐ž๐ฌ๐ญ", "๐˜ถ๐˜ฏ๐˜ช๐˜ค๐˜ฐ๐˜ฅ๐˜ฆ ๐˜ต๐˜ฆ๐˜ด๐˜ต", "๐™ช๐™ฃ๐™ž๐™˜๐™ค๐™™๐™š ๐™ฉ๐™š๐™จ๐™ฉ", "๐šž๐š—๐š’๐šŒ๐š˜๐š๐šŽ ๐š๐šŽ๐šœ๐š", "๐“Š๐“ƒ๐’พ๐’ธ๐‘œ๐’น๐‘’ ๐“‰๐‘’๐“ˆ๐“‰", "๐“พ๐“ท๐“ฒ๐“ฌ๐“ธ๐“ญ๐“ฎ ๐“ฝ๐“ฎ๐“ผ๐“ฝ", "๐•ฆ๐•Ÿ๐•š๐•”๐• ๐••๐•– ๐•ฅ๐•–๐•ค๐•ฅ", "ะฆะŸIแ„ƒำจDฮฃ ฦฌฮฃฦงฦฌ", "ใ„ฉๅ‡ ไธจๅŒšใ„–แ—ชไน‡ ใ„’ไน‡ไธ‚ใ„’", "ใฒๅˆ€๏พ‰แ„ƒใฎใ‚Šไน‡ ๏ฝฒไน‡ไธ‚๏ฝฒ", "ษ„โ‚ฆล‚โ‚ตร˜ฤษ† โ‚ฎษ†โ‚ดโ‚ฎ", "๏ฝ•๏ฝŽ๏ฝ‰๏ฝƒ๏ฝ๏ฝ„๏ฝ… ๏ฝ”๏ฝ…๏ฝ“๏ฝ”", "แดœษดษชแด„แดแด…แด‡ แด›แด‡๊œฑแด›", "ส‡sวส‡ วpoษ”ฤฑun", "เธขเธ เน€ฯ‚เนเน”ั” ี‡ั”เธฃี‡", "แ‘˜แ˜‰แ“ฐแ‘ขแ“แ•ฒแ˜ฟ แ–ถแ˜ฟSแ–ถ", "ฯ…ษณฮนฦˆฯƒิƒาฝ ฦšาฝส‚ฦš", "สŠีผษจฦˆึ…ษ–ษ› ศถษ›ึ†ศถ", "๐Ÿ†„๐Ÿ…ฝ๐Ÿ…ธ๐Ÿ…ฒ๐Ÿ…พ๐Ÿ…ณ๐Ÿ…ด ๐Ÿ†ƒ๐Ÿ…ด๐Ÿ†‚๐Ÿ†ƒ", "โ“คโ“โ“˜โ“’โ“žโ““โ“” โ“ฃโ“”โ“ขโ“ฃ", "ฬถฬฬณฬฅอˆอ–ฬอŒฬˆอ›ฬฝอŠฬฬšอ ", // test control codes "\r\n", "\n", "\r", "\t", "\\", "\"", "\'", "\u0000\u0001\u0002\u0003", "\u0004\u0005\u0006\u0007", "\u0008\u0009\u000A\u000B", "\u000C\u000D\u000E\u000F", // test invalid bytes as characters "\u00C0\u00C1\u00F5\u00F6", "\u00F7\u00F8\u00F9\u00FA", "\u00FB\u00FC\u00FD\u00FE", "\u00FF", }; foreach (string weird in weirdUnicode) { NetworkWriter writer = new NetworkWriter(); writer.WriteString(weird); byte[] data = writer.ToArray(); NetworkReader reader = new NetworkReader(data); string str = reader.ReadString(); Assert.That(str, Is.EqualTo(weird)); } } [Test] public void TestGuid() { Guid originalGuid = new Guid("0123456789abcdef9876543210fedcba"); NetworkWriter writer = new NetworkWriter(); writer.WriteGuid(originalGuid); NetworkReader reader = new NetworkReader(writer.ToArray()); Guid readGuid = reader.ReadGuid(); Assert.That(readGuid, Is.EqualTo(originalGuid)); } [Test] public void TestGuidNullable() { Guid? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteGuidNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); Guid? output = reader.ReadGuidNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestFloats() { float[] weirdFloats = { 0f, -0f, float.Epsilon, -float.Epsilon, float.MaxValue, float.MinValue, float.NaN, -float.NaN, float.PositiveInfinity, float.NegativeInfinity, (float) double.MaxValue, (float) double.MinValue, (float) decimal.MaxValue, (float) decimal.MinValue, (float) Math.PI, (float) Math.E }; foreach (float weird in weirdFloats) { NetworkWriter writer = new NetworkWriter(); writer.WriteFloat(weird); NetworkReader reader = new NetworkReader(writer.ToArray()); float readFloat = reader.ReadFloat(); Assert.That(readFloat, Is.EqualTo(weird)); } } [Test] public void TestFloatNullable() { float? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteFloatNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); float? output = reader.ReadFloatNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestDoubles() { double[] weirdDoubles = { 0d, -0d, double.Epsilon, -double.Epsilon, double.MaxValue, double.MinValue, double.NaN, -double.NaN, double.PositiveInfinity, double.NegativeInfinity, float.MaxValue, float.MinValue, (double) decimal.MaxValue, (double) decimal.MinValue, Math.PI, Math.E }; foreach (double weird in weirdDoubles) { NetworkWriter writer = new NetworkWriter(); writer.WriteDouble(weird); NetworkReader reader = new NetworkReader(writer.ToArray()); double readDouble = reader.ReadDouble(); Assert.That(readDouble, Is.EqualTo(weird)); } } [Test] public void TestDoubleNullable() { double? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteDoubleNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); double? output = reader.ReadDoubleNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestDecimals() { decimal[] weirdDecimals = { decimal.Zero, -decimal.Zero, decimal.MaxValue, decimal.MinValue, (decimal) Math.PI, (decimal) Math.E }; foreach (decimal weird in weirdDecimals) { NetworkWriter writer = new NetworkWriter(); writer.WriteDecimal(weird); NetworkReader reader = new NetworkReader(writer.ToArray()); decimal readDecimal = reader.ReadDecimal(); Assert.That(readDecimal, Is.EqualTo(weird)); } } [Test] public void TestDecimalNullable() { decimal? input = null; NetworkWriter writer = new NetworkWriter(); writer.WriteDecimalNullable(input); NetworkReader reader = new NetworkReader(writer.ToArray()); decimal? output = reader.ReadDecimalNullable(); Assert.That(output, Is.EqualTo(input)); } [Test] public void TestFloatBinaryCompatibility() { float[] weirdFloats = { ((float) Math.PI) / 3.0f, ((float) Math.E) / 3.0f }; byte[] expected = { 146, 10,134, 63, 197,245,103, 63, }; NetworkWriter writer = new NetworkWriter(); foreach (float weird in weirdFloats) { writer.WriteFloat(weird); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestDoubleBinaryCompatibility() { double[] weirdDoubles = { Math.PI / 3.0d, Math.E / 3.0d }; byte[] expected = { 101,115, 45, 56, 82,193,240, 63, 140,116,112,185,184,254,236, 63, }; NetworkWriter writer = new NetworkWriter(); foreach (double weird in weirdDoubles) { writer.WriteDouble(weird); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestDecimalBinaryCompatibility() { decimal[] weirdDecimals = { ((decimal) Math.PI) / 3.0m, ((decimal) Math.E) / 3.0m }; byte[] expected = { 0x00, 0x00, 0x1C, 0x00, 0x12, 0x37, 0xD6, 0x21, 0xAB, 0xEA, 0x84, 0x0A, 0x5B, 0x5E, 0xB1, 0x03, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x6D, 0xC2, 0xA4, 0x68, 0x52, 0x00, 0x00 }; NetworkWriter writer = new NetworkWriter(); foreach (decimal weird in weirdDecimals) { writer.WriteDecimal(weird); } //Debug.Log(BitConverter.ToString(writer.ToArray())); Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestByteEndianness() { byte[] values = { 0x12, 0x43, 0x00, 0xff, 0xab, 0x02, 0x20 }; byte[] expected = { 0x12, 0x43, 0x00, 0xff, 0xab, 0x02, 0x20 }; NetworkWriter writer = new NetworkWriter(); foreach (byte value in values) { writer.WriteByte(value); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestUShortEndianness() { ushort[] values = { 0x0000, 0x1234, 0xabcd, 0xF00F, 0x0FF0, 0xbeef }; byte[] expected = { 0x00, 0x00, 0x34, 0x12, 0xcd, 0xab, 0x0F, 0xF0, 0xF0, 0x0F, 0xef, 0xbe }; NetworkWriter writer = new NetworkWriter(); foreach (ushort value in values) { writer.WriteUShort(value); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestUIntEndianness() { uint[] values = { 0x12345678, 0xabcdef09, 0xdeadbeef }; byte[] expected = { 0x78, 0x56, 0x34, 0x12, 0x09, 0xef, 0xcd, 0xab, 0xef, 0xbe, 0xad, 0xde }; NetworkWriter writer = new NetworkWriter(); foreach (uint value in values) { writer.WriteUInt(value); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestULongEndianness() { ulong[] values = { 0x0123456789abcdef, 0xdeaded_beef_c0ffee }; byte[] expected = { 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0xee, 0xff, 0xc0, 0xef, 0xbe, 0xed, 0xad, 0xde }; NetworkWriter writer = new NetworkWriter(); foreach (ulong value in values) { writer.WriteULong(value); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestSbyteEndianness() { byte[] values = { 0x12, 0x43, 0x00, 0xff, 0xab, 0x02, 0x20 }; byte[] expected = { 0x12, 0x43, 0x00, 0xff, 0xab, 0x02, 0x20 }; NetworkWriter writer = new NetworkWriter(); foreach (byte value in values) { writer.WriteSByte((sbyte)value); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestShortEndianness() { ushort[] values = { 0x0000, 0x1234, 0xabcd, 0xF00F, 0x0FF0, 0xbeef }; byte[] expected = { 0x00, 0x00, 0x34, 0x12, 0xcd, 0xab, 0x0F, 0xF0, 0xF0, 0x0F, 0xef, 0xbe }; NetworkWriter writer = new NetworkWriter(); foreach (ushort value in values) { writer.WriteShort((short)value); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestIntEndianness() { uint[] values = { 0x12345678, 0xabcdef09, 0xdeadbeef }; byte[] expected = { 0x78, 0x56, 0x34, 0x12, 0x09, 0xef, 0xcd, 0xab, 0xef, 0xbe, 0xad, 0xde }; NetworkWriter writer = new NetworkWriter(); foreach (uint value in values) { writer.WriteInt((int)value); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestLongEndianness() { ulong[] values = { 0x0123456789abcdef, 0xdeaded_beef_c0ffee }; byte[] expected = { 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0xee, 0xff, 0xc0, 0xef, 0xbe, 0xed, 0xad, 0xde }; NetworkWriter writer = new NetworkWriter(); foreach (ulong value in values) { writer.WriteLong((long)value); } Assert.That(writer.ToArray(), Is.EqualTo(expected)); } [Test] public void TestWritingAndReading() { // write all simple types once NetworkWriter writer = new NetworkWriter(); writer.WriteChar((char)1); writer.WriteByte(2); writer.WriteSByte(3); writer.WriteBool(true); writer.WriteShort(4); writer.WriteUShort(5); writer.WriteInt(6); writer.WriteUInt(7U); writer.WriteLong(8L); writer.WriteULong(9UL); writer.WriteFloat(10.0F); writer.WriteDouble(11.0D); writer.WriteDecimal(12); writer.WriteString(null); writer.WriteString(""); writer.WriteString("13"); // just the byte array, no size info etc. writer.WriteBytes(new byte[] { 14, 15 }, 0, 2); // [SyncVar] struct values can have uninitialized byte arrays, null needs to be supported writer.WriteBytesAndSize(null); // buffer, no-offset, count writer.WriteBytesAndSize(new byte[] { 17, 18 }, 0, 2); // buffer, offset, count writer.WriteBytesAndSize(new byte[] { 19, 20, 21 }, 1, 2); // size, buffer writer.WriteBytesAndSize(new byte[] { 22, 23 }, 0, 2); // read them NetworkReader reader = new NetworkReader(writer.ToArray()); Assert.That(reader.ReadChar(), Is.EqualTo(1)); Assert.That(reader.ReadByte(), Is.EqualTo(2)); Assert.That(reader.ReadSByte(), Is.EqualTo(3)); Assert.That(reader.ReadBool(), Is.True); Assert.That(reader.ReadShort(), Is.EqualTo(4)); Assert.That(reader.ReadUShort(), Is.EqualTo(5)); Assert.That(reader.ReadInt(), Is.EqualTo(6)); Assert.That(reader.ReadUInt(), Is.EqualTo(7)); Assert.That(reader.ReadLong(), Is.EqualTo(8)); Assert.That(reader.ReadULong(), Is.EqualTo(9)); Assert.That(reader.ReadFloat(), Is.EqualTo(10)); Assert.That(reader.ReadDouble(), Is.EqualTo(11)); Assert.That(reader.ReadDecimal(), Is.EqualTo(12)); // writing null string should write null in Mirror ("" in original HLAPI) Assert.That(reader.ReadString(), Is.Null); Assert.That(reader.ReadString(), Is.EqualTo("")); Assert.That(reader.ReadString(), Is.EqualTo("13")); Assert.That(reader.ReadBytes(2), Is.EqualTo(new byte[] { 14, 15 })); Assert.That(reader.ReadBytesAndSize(), Is.Null); Assert.That(reader.ReadBytesAndSize(), Is.EqualTo(new byte[] { 17, 18 })); Assert.That(reader.ReadBytesAndSize(), Is.EqualTo(new byte[] { 20, 21 })); Assert.That(reader.ReadBytesAndSize(), Is.EqualTo(new byte[] { 22, 23 })); } [Test] public void TestWritingUri() { Uri testUri = new Uri("https://www.mirror-networking.com?somthing=other"); NetworkWriter writer = new NetworkWriter(); writer.WriteUri(testUri); NetworkReader reader = new NetworkReader(writer.ToArray()); Assert.That(reader.ReadUri(), Is.EqualTo(testUri)); } // URI null support test for https://github.com/vis2k/Mirror/pull/2796/ [Test] public void TestWritingNullUri() { NetworkWriter writer = new NetworkWriter(); writer.WriteUri(null); NetworkReader reader = new NetworkReader(writer.ToArray()); Assert.That(reader.ReadUri(), Is.EqualTo(null)); } [Test] public void TestList() { List original = new List() { 1, 2, 3, 4, 5 }; NetworkWriter writer = new NetworkWriter(); writer.Write(original); NetworkReader reader = new NetworkReader(writer.ToArray()); List readList = reader.Read>(); Assert.That(readList, Is.EqualTo(original)); } [Test] public void TestNullList() { NetworkWriter writer = new NetworkWriter(); writer.Write>(null); NetworkReader reader = new NetworkReader(writer.ToArray()); List readList = reader.Read>(); Assert.That(readList, Is.Null); } const int testArraySize = 4; [Test] [Description("ReadArray should throw if it is trying to read more than length of segment, this is to stop allocation attacks")] public void TestArrayDoesNotThrowWithCorrectLength() { NetworkWriter writer = new NetworkWriter(); WriteGoodArray(); NetworkReader reader = new NetworkReader(writer.ToArray()); Assert.DoesNotThrow(() => { _ = reader.ReadArray(); }); void WriteGoodArray() { writer.WriteInt(testArraySize); int[] array = new int[testArraySize] { 1, 2, 3, 4 }; for (int i = 0; i < array.Length; i++) writer.Write(array[i]); } } [Test] [Description("ReadArray should throw if it is trying to read more than length of segment, this is to stop allocation attacks")] [TestCase(testArraySize * sizeof(int), Description = "max allowed value to allocate array")] [TestCase(testArraySize * 2)] [TestCase(testArraySize + 1, Description = "min allowed to allocate")] public void TestArrayThrowsIfLengthIsWrong(int badLength) { NetworkWriter writer = new NetworkWriter(); WriteBadArray(); NetworkReader reader = new NetworkReader(writer.ToArray()); Assert.Throws(() => { _ = reader.ReadArray(); }); void WriteBadArray() { writer.WriteInt(badLength); int[] array = new int[testArraySize] { 1, 2, 3, 4 }; for (int i = 0; i < array.Length; i++) writer.Write(array[i]); } } [Test] [Description("ReadArray should throw if it is trying to read more than length of segment, this is to stop allocation attacks")] [TestCase(testArraySize * sizeof(int) + 1, Description = "min read count is 1 byte, 16 array bytes are writen so 17 should throw error")] [TestCase(20_000)] [TestCase(int.MaxValue)] [TestCase(int.MaxValue - 1)] // todo add fuzzy testing to check more values public void TestArrayThrowsIfLengthIsTooBig(int badLength) { NetworkWriter writer = new NetworkWriter(); WriteBadArray(); NetworkReader reader = new NetworkReader(writer.ToArray()); EndOfStreamException exception = Assert.Throws(() => { _ = reader.ReadArray(); }); Assert.That(exception, Has.Message.EqualTo($"Received array that is too large: {badLength}")); void WriteBadArray() { writer.WriteInt(badLength); int[] array = new int[testArraySize] { 1, 2, 3, 4 }; for (int i = 0; i < array.Length; i++) writer.Write(array[i]); } } [Test] public void TestNetworkBehaviour() { // create spawned because we will look up netId in .spawned CreateNetworkedAndSpawn(out _, out _, out RpcNetworkIdentityBehaviour behaviour, out _, out _, out _); NetworkWriter writer = new NetworkWriter(); writer.WriteNetworkBehaviour(behaviour); byte[] bytes = writer.ToArray(); Assert.That(bytes.Length, Is.EqualTo(5), "Networkbehaviour should be 5 bytes long."); NetworkReader reader = new NetworkReader(bytes); RpcNetworkIdentityBehaviour actual = reader.ReadNetworkBehaviour(); Assert.That(actual, Is.EqualTo(behaviour), "Read should find the same behaviour as written"); } [Test] public void TestNetworkBehaviourNull() { NetworkWriter writer = new NetworkWriter(); writer.WriteNetworkBehaviour(null); byte[] bytes = writer.ToArray(); Assert.That(bytes.Length, Is.EqualTo(4), "null Networkbehaviour should be 4 bytes long."); NetworkReader reader = new NetworkReader(bytes); RpcNetworkIdentityBehaviour actual = reader.ReadNetworkBehaviour(); Assert.That(actual, Is.Null, "should read null"); Assert.That(reader.Position, Is.EqualTo(4), "should read 4 bytes when netid is 0"); } [Test] [Description("Uses Generic read function to check weaver correctly creates it")] public void TestNetworkBehaviourWeaverGenerated() { // create spawned because we will look up netId in .spawned CreateNetworkedAndSpawn(out _, out _, out RpcNetworkIdentityBehaviour behaviour, out _, out _, out _); NetworkWriter writer = new NetworkWriter(); writer.Write(behaviour); byte[] bytes = writer.ToArray(); Assert.That(bytes.Length, Is.EqualTo(5), "Networkbehaviour should be 5 bytes long."); NetworkReader reader = new NetworkReader(bytes); RpcNetworkIdentityBehaviour actual = reader.Read(); Assert.That(actual, Is.EqualTo(behaviour), "Read should find the same behaviour as written"); } } }