ProjectZ/Assets/Mirror/Tests/Editor/NetworkWriterTest.cs
2024-02-19 21:00:36 +03:00

1392 lines
51 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<byte> 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<byte> 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<byte> segment = new ArraySegment<byte>(data, 1, 1);
NetworkWriter writer = new NetworkWriter();
writer.WriteBytesAndSizeSegment(segment);
NetworkReader reader = new NetworkReader(writer.ToArray());
ArraySegment<byte> 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<OverflowException>(() => writer.WriteBytesAndSize(new byte[0], 0, -1));
Assert.That(writer.Position, Is.EqualTo(0));
}
[Test]
public void TestReadingTooMuch()
{
void EnsureThrows(Action<NetworkReader> read, byte[] data = null)
{
Assert.Throws<System.IO.EndOfStreamException>(() => 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<System.Text.DecoderFallbackException>(() => 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<System.IO.EndOfStreamException>(() => 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<byte> 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<int> original = new List<int>() { 1, 2, 3, 4, 5 };
NetworkWriter writer = new NetworkWriter();
writer.Write(original);
NetworkReader reader = new NetworkReader(writer.ToArray());
List<int> readList = reader.Read<List<int>>();
Assert.That(readList, Is.EqualTo(original));
}
[Test]
public void TestNullList()
{
NetworkWriter writer = new NetworkWriter();
writer.Write<List<int>>(null);
NetworkReader reader = new NetworkReader(writer.ToArray());
List<int> readList = reader.Read<List<int>>();
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<int>();
});
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<EndOfStreamException>(() => {
_ = reader.ReadArray<int>();
});
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<EndOfStreamException>(() =>
{
_ = reader.ReadArray<int>();
});
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<RpcNetworkIdentityBehaviour>();
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<RpcNetworkIdentityBehaviour>();
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<RpcNetworkIdentityBehaviour>();
Assert.That(actual, Is.EqualTo(behaviour), "Read should find the same behaviour as written");
}
}
}