using System; using NUnit.Framework; using Unity.Collections.NotBurstCompatible; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using UnityEngine.TestTools; using UnityEngine; namespace Unity.Collections.Tests { internal class DataStreamTests { internal class ReadAndWrite { [TestCase(ushort.MaxValue)] [TestCase(ushort.MinValue)] public void UShort(ushort expected) { bool Write(ref DataStreamWriter writer) => writer.WriteUShort(expected); CheckReadWrite(sizeof(ushort), reader => reader.ReadUShort(), Write, expected); } [TestCase((uint) 0b101010)] [TestCase((uint) 0b111111)] public void RawBits(uint expected) { bool Write(ref DataStreamWriter writer) => writer.WriteRawBits(expected, 6); CheckReadWrite(6, reader => reader.ReadRawBits(6), Write, expected); } [Test] public void RawBits_OutOfCapacity() { const uint expected = 0b101011001; var writer = new DataStreamWriter(1, Allocator.Temp); Assert.False(writer.WriteRawBits(expected, 9)); Assert.True(writer.HasFailedWrites); } [TestCase(uint.MaxValue)] [TestCase(uint.MinValue)] public void UInt(uint expected) { bool Write(ref DataStreamWriter writer) => writer.WriteUInt(expected); CheckReadWrite(sizeof(uint), reader => reader.ReadUInt(), Write, expected); } [TestCase(float.MaxValue)] [TestCase(float.MinValue)] public void Float(float expected) { bool Write(ref DataStreamWriter writer) => writer.WriteFloat(expected); CheckReadWrite(sizeof(float), reader => reader.ReadFloat(), Write, expected); } [TestCase(short.MaxValue)] [TestCase(short.MinValue)] public void Short(short expected) { bool Write(ref DataStreamWriter writer) => writer.WriteShort(expected); CheckReadWrite(sizeof(short), reader => reader.ReadShort(), Write, expected); } [Test] public void FixedString32() { var expected = new FixedString32Bytes("This is a string"); bool Write(ref DataStreamWriter writer) => writer.WriteFixedString32(expected); CheckReadWrite(expected.Length + FixedStringHeader, reader => reader.ReadFixedString32(), Write, expected); } [Test] public void FixedString64() { var expected = new FixedString64Bytes("This is a string"); bool Write(ref DataStreamWriter writer) => writer.WriteFixedString64(expected); CheckReadWrite(expected.Length + FixedStringHeader, reader => reader.ReadFixedString64(), Write, expected); } [Test] public void FixedString128() { var expected = new FixedString128Bytes("This is a string"); bool Write(ref DataStreamWriter writer) => writer.WriteFixedString128(expected); CheckReadWrite(expected.Length + FixedStringHeader, reader => reader.ReadFixedString128(), Write, expected); } [Test] public void FixedString512() { var expected = new FixedString512Bytes("This is a string"); bool Write(ref DataStreamWriter writer) => writer.WriteFixedString512(expected); CheckReadWrite(expected.Length + FixedStringHeader, reader => reader.ReadFixedString512(), Write, expected); } [Test] public void FixedString4096() { var expected = new FixedString4096Bytes("This is a string"); bool Write(ref DataStreamWriter writer) => writer.WriteFixedString4096(expected); CheckReadWrite(expected.Length + FixedStringHeader, reader => reader.ReadFixedString4096(), Write, expected); } [Test] public void LongLooped() { const long baseVal = -99; const long expected = -1979; bool Write(ref DataStreamWriter writer, long value) => writer.WriteLong(value); long Read(ref DataStreamReader reader) => reader.ReadLong(); CheckReadWriteLooped(sizeof(long), baseVal, expected, Write, Read, (l, u) => l + u); } } internal class ReadAndWriteNetworkOrder { [TestCase(int.MaxValue)] [TestCase(int.MinValue)] public void Int(int expected) { bool Write(ref DataStreamWriter writer) => writer.WriteIntNetworkByteOrder(expected); CheckReadWrite(sizeof(int), reader => reader.ReadIntNetworkByteOrder(), Write, expected); } [TestCase(uint.MaxValue)] [TestCase(uint.MinValue)] public void UInt(uint expected) { bool Write(ref DataStreamWriter writer) => writer.WriteUIntNetworkByteOrder(expected); CheckReadWrite(sizeof(uint), reader => reader.ReadUIntNetworkByteOrder(), Write, expected); } [TestCase(short.MaxValue)] [TestCase(short.MinValue)] public void Short(short expected) { bool Write(ref DataStreamWriter writer) => writer.WriteShortNetworkByteOrder(expected); CheckReadWrite(sizeof(short), reader => reader.ReadShortNetworkByteOrder(), Write, expected); } [TestCase(ushort.MaxValue)] [TestCase(ushort.MinValue)] public void UShort(ushort expected) { bool Write(ref DataStreamWriter writer) => writer.WriteUShortNetworkByteOrder(expected); CheckReadWrite(sizeof(ushort), reader => reader.ReadUShortNetworkByteOrder(), Write, expected); } [Test] public void ReadIncorrect() { var dataStream = new DataStreamWriter(4, Allocator.Temp); dataStream.WriteIntNetworkByteOrder(1979); dataStream.Flush(); var reader = new DataStreamReader(dataStream.AsNativeArray()); Assert.AreNotEqual(1979, reader.ReadInt()); } } internal class ReadWritePacked { [Test] public void UInt() { const uint expected = 1979; const uint baseVal = 2000; bool Write(ref DataStreamWriter writer) => writer.WriteUInt(expected); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model, uint value) => writer.WritePackedUInt(value, model); uint Read(ref DataStreamReader reader) => reader.ReadUInt(); uint ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedUInt(model); CheckReadWritePackedLooped(sizeof(uint), baseVal, expected, Write, WritePacked, Read, ReadPacked, (l, u) => l + u); } [Test] public void IntExistingData() { unsafe { var n = 300 * 4; var data = stackalloc byte[n]; var compressionModel = StreamCompressionModel.Default; var dataStream = new DataStreamWriter(data, n); const int base_val = -10; const int count = 20; for (int i = 0; i < count; ++i) dataStream.WritePackedInt(base_val + i, compressionModel); dataStream.WriteInt((int)1979); dataStream.Flush(); var na = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(data, n, Allocator.Invalid); #if ENABLE_UNITY_COLLECTIONS_CHECKS NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref na, AtomicSafetyHandle.GetTempMemoryHandle()); #endif var reader = new DataStreamReader(na); for (int i = 0; i < count; ++i) { var val = reader.ReadPackedInt(compressionModel); Assert.AreEqual(base_val + i, val); } Assert.AreEqual(1979, reader.ReadInt()); } } [Test] public void Int() { const int expected = -1979; const int baseVal = -10; bool Write(ref DataStreamWriter writer) => writer.WriteInt(expected); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model, int value) => writer.WritePackedInt(value, model); int Read(ref DataStreamReader reader) => reader.ReadInt(); int ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedInt(model); CheckReadWritePackedLooped(sizeof(int), baseVal, expected, Write, WritePacked, Read, ReadPacked, (i, u) => (int)(i + u)); } [Test] public void Long() { const long expected = -1979; const long baseVal = -99; bool Write(ref DataStreamWriter writer) => writer.WriteLong(expected); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model, long value) => writer.WritePackedLong(value, model); long Read(ref DataStreamReader reader) => reader.ReadLong(); long ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedLong(model); CheckReadWritePackedLooped(sizeof(long), baseVal, expected, Write, WritePacked, Read, ReadPacked, (l, u) => l + u); } [Test] public void ULong() { const ulong expected = 1979; const ulong baseVal = 2000; bool Write(ref DataStreamWriter writer) => writer.WriteULong(expected); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model, ulong value) => writer.WritePackedULong(value, model); ulong Read(ref DataStreamReader reader) => reader.ReadULong(); ulong ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedULong(model); CheckReadWritePackedLooped(sizeof(ulong), baseVal, expected, Write, WritePacked, Read, ReadPacked, (l, u) => l + u); } [Test] public void Float() { const float expected = 1979.1f; const float baseVal = 2000.1f; bool Write(ref DataStreamWriter writer) => writer.WriteFloat(expected); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model, float value) => writer.WritePackedFloat(value, model); float Read(ref DataStreamReader reader) => reader.ReadFloat(); float ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedFloat(model); CheckReadWritePackedLooped(sizeof(float), baseVal, expected, Write, WritePacked, Read, ReadPacked, (l, u) => l + u); } [Test] public void Double() { const double expected = 1979.1989; const double baseVal = 2000.2000; bool Write(ref DataStreamWriter writer) => writer.WriteDouble(expected); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model, double value) => writer.WritePackedDouble(value, model); double Read(ref DataStreamReader reader) => reader.ReadDouble(); double ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedDouble(model); CheckReadWritePackedLooped(sizeof(double), baseVal, expected, Write, WritePacked, Read, ReadPacked, (l, u) => l + u); } [Test] public void WriteOutSideOfCapacity_Fails() { var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(sizeof(uint) / 2, Allocator.Temp); Assert.False(writer.HasFailedWrites); Assert.False(writer.WritePackedUInt(uint.MaxValue, model), "Writing a uint where there is no room should fail."); Assert.That(writer.HasFailedWrites); } [Test] [TestRequiresDotsDebugOrCollectionChecks] public void ReadOutSideOfCapacity_Fails() { var model = StreamCompressionModel.Default; var reader = new DataStreamReader(new NativeArray(0, Allocator.Temp)); LogAssert.Expect(LogType.Error, "Trying to read 2 bits from a stream where only 0 are available"); Assert.That(reader.ReadPackedUInt(model), Is.EqualTo(0)); Assert.That(reader.HasFailedReads); } } internal class ReadWritePackedDelta { [Test] public void Int() { const int expected = int.MaxValue; const int baseline = int.MinValue; bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedIntDelta(expected, baseline, model); int ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedIntDelta(baseline, model); CheckReadWritePacked(sizeof(int), ReadPacked, WritePacked, expected); } [Test] public void Long() { const long expected = long.MaxValue; const long baseline = long.MinValue; bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedLongDelta(expected, baseline, model); long ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedLongDelta(baseline, model); CheckReadWritePacked(sizeof(long), ReadPacked, WritePacked, expected); } [Test] public void ULong() { const ulong expected = ulong.MaxValue; const ulong baseline = ulong.MinValue; bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedULongDelta(expected, baseline, model); ulong ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedULongDelta(baseline, model); CheckReadWritePacked(sizeof(ulong), ReadPacked, WritePacked, expected); } [Test] public void FixedString32() { var expected = new FixedString32Bytes("This is a string"); var baseline = new FixedString32Bytes("This is another string"); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedFixedString32Delta(expected, baseline, model); FixedString32Bytes ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedFixedString32Delta(baseline, model); CheckReadWritePacked(expected.Length + FixedStringHeader, ReadPacked, WritePacked, expected); } [Test] public void FixedString32_LargerBaseline() { var expected = new FixedString32Bytes("This is another string"); var baseline = new FixedString32Bytes("This is a string"); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedFixedString32Delta(expected, baseline, model); FixedString32Bytes ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedFixedString32Delta(baseline, model); CheckReadWritePacked(expected.Length + FixedStringHeader, ReadPacked, WritePacked, expected); } [Test] public void FixedString64() { var expected = new FixedString64Bytes("This is a string"); var baseline = new FixedString64Bytes("This is another string"); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedFixedString64Delta(expected, baseline, model); FixedString64Bytes ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedFixedString64Delta(baseline, model); CheckReadWritePacked(expected.Length + FixedStringHeader, ReadPacked, WritePacked, expected); } [Test] public void FixedString128() { var expected = new FixedString128Bytes("This is a string"); var baseline = new FixedString128Bytes("This is another string"); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedFixedString128Delta(expected, baseline, model); FixedString128Bytes ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedFixedString128Delta(baseline, model); CheckReadWritePacked(expected.Length + FixedStringHeader, ReadPacked, WritePacked, expected); } [Test] public void FixedString512() { var expected = new FixedString512Bytes("This is a string"); var baseline = new FixedString512Bytes("This is another string"); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedFixedString512Delta(expected, baseline, model); FixedString512Bytes ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedFixedString512Delta(baseline, model); CheckReadWritePacked(expected.Length + FixedStringHeader, ReadPacked, WritePacked, expected); } [Test] public void FixedString4096() { var expected = new FixedString4096Bytes("This is a string"); var baseline = new FixedString4096Bytes("This is another string"); bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model) => writer.WritePackedFixedString4096Delta(expected, baseline, model); FixedString4096Bytes ReadPacked(ref DataStreamReader reader, StreamCompressionModel model) => reader.ReadPackedFixedString4096Delta(baseline, model); CheckReadWritePacked(expected.Length + FixedStringHeader, ReadPacked, WritePacked, expected); } [Test] public void Float_OutOfBoundsFails() { const float expected = float.MaxValue; const float baseline = float.MinValue; var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(sizeof(float) / 2, Allocator.Temp); Assert.False(writer.HasFailedWrites); Assert.False(writer.WritePackedFloatDelta(expected, baseline, model)); Assert.That(writer.HasFailedWrites); } [Test] public void Float_UnchangedData() { const float expected = float.MaxValue; const float baseline = float.MaxValue; var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(1, Allocator.Temp); Assert.True(writer.WritePackedFloatDelta(expected, baseline, model)); var reader = new DataStreamReader(writer.AsNativeArray()); Assert.AreEqual(baseline, reader.ReadPackedFloatDelta(baseline, model)); Assert.That(reader.GetBitsRead(), Is.EqualTo(1)); } [Test] public void Float_ChangedData() { const float expected = float.MaxValue; const float baseline = float.MinValue; var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(sizeof(float) + 1, Allocator.Temp); Assert.True(writer.WritePackedFloatDelta(expected, baseline, model)); var reader = new DataStreamReader(writer.AsNativeArray()); Assert.AreEqual(1, reader.ReadRawBits(1)); var uf = new UIntFloat { intValue = reader.ReadRawBits(32) }; Assert.AreEqual(expected, uf.floatValue); } [Test] [TestRequiresDotsDebugOrCollectionChecks] public void UInt_OutOfCapacity() { var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(0, Allocator.Temp); var reader = new DataStreamReader(writer.AsNativeArray()); LogAssert.Expect(LogType.Error, "Trying to read 2 bits from a stream where only 0 are available"); Assert.That(reader.ReadPackedUInt(model), Is.EqualTo(0)); Assert.That(reader.HasFailedReads); } // We test with a variable amount of writes to ensure we overflow the internal ulong bitBuffer. [Test] public void Flush_Works([Values(1, 7, 24, 65)]int numWrites) { const int baseline = 100; var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(512, Allocator.Temp); // Writer: for(int i = 0; i < numWrites; i++) writer.WritePackedUIntDelta((uint) (100 + i), baseline, model); // Flush, and write another sentinel value in. writer.Flush(); writer.WritePackedUIntDelta(45, baseline, model); writer.Flush(); Assert.IsFalse(writer.HasFailedWrites, "Sanity: writer.HasFailedWrites"); // Reader: var reader = new DataStreamReader(writer.AsNativeArray()); for(int i = 0; i < numWrites; i++) { var read = reader.ReadPackedUIntDelta(baseline, model); Assert.AreEqual((uint)(100 + i), read, "100 + i"); } // When we flush the reader, we expect to now be aligned. reader.Flush(); var read45 = reader.ReadPackedUIntDelta(baseline, model); Assert.AreEqual(45, read45, "45"); reader.Flush(); Assert.IsFalse(reader.HasFailedReads, "reader.HasFailedReads"); Assert.AreEqual(writer.LengthInBits, reader.GetBitsRead(), "writer.LengthInBits vs reader.GetBitsRead()"); LogAssert.NoUnexpectedReceived(); } [Test] public void NotMirroringFlushCall_Fails() { const int baseline = 100; var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(512, Allocator.Temp); // Writer: writer.WritePackedUIntDelta(100, baseline, model); Assert.AreNotEqual(0, writer.LengthInBits % 8, "Sanity: Not byte aligned!"); writer.Flush(); writer.WritePackedUIntDelta(45, baseline, model); writer.Flush(); Assert.IsFalse(writer.HasFailedWrites, "Sanity: writer.HasFailedWrites"); // Reader: var reader = new DataStreamReader(writer.AsNativeArray()); var read = reader.ReadPackedUIntDelta(baseline, model); Assert.AreEqual(100u, read, "100u"); // SKIPPED: reader.Flush(); // THUS: Read pointer alignment should be wrong. LogAssert.ignoreFailingMessages = true; // Defensive: Technically we're reading too FEW bits, // so we shouldn't get error logs here. Assert.AreNotEqual(45, reader.ReadPackedIntDelta(baseline, model), "!45"); Assert.AreNotEqual(writer.LengthInBits, reader.GetBitsRead(), "writer.LengthInBits vs reader.GetBitsRead()"); } [Test] public void CanMixPackedAndNonPacked() { const int baseline = 200; var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(12, Allocator.Temp); writer.WritePackedIntDelta(201, baseline, model); Assert.AreNotEqual(0, writer.LengthInBits % 8, "Sanity: This test is invalid if we accidentally byte-align."); writer.WriteInt(202); writer.WritePackedInt(203, model); writer.WriteInt(204); Assert.IsFalse(writer.HasFailedWrites, "Sanity: writer.HasFailedWrites"); var reader = new DataStreamReader(writer.AsNativeArray()); Assert.AreEqual(201, reader.ReadPackedIntDelta(baseline, model)); Assert.AreEqual(202, reader.ReadInt()); Assert.AreEqual(203, reader.ReadPackedInt(model)); Assert.AreEqual(204, reader.ReadInt()); Assert.IsFalse(reader.HasFailedReads, "reader.HasFailedReads"); } } [Test] public void IsCreated_ReturnsTrueAfterConstructor() { var dataStream = new DataStreamWriter(4, Allocator.Temp); Assert.True(dataStream.IsCreated, "Buffer must be created after calling constructor."); } [Test] public void LengthInBits_MatchesWrittenCount() { var dataStream = new DataStreamWriter(4, Allocator.Temp); dataStream.WriteByte(0); Assert.That(dataStream.LengthInBits, Is.EqualTo(1 * 8)); dataStream.WriteByte(1); dataStream.WriteByte(1); Assert.That(dataStream.LengthInBits, Is.EqualTo(3 * 8)); } [Test] public void CreateStreamWithPartOfSourceByteArray() { byte[] byteArray = { (byte)'s', (byte)'o', (byte)'m', (byte)'e', (byte)' ', (byte)'d', (byte)'a', (byte)'t', (byte)'a' }; DataStreamWriter dataStream; dataStream = new DataStreamWriter(4, Allocator.Temp); dataStream.WriteBytes(new NativeArray(byteArray, Allocator.Temp).GetSubArray(0, 4)); Assert.AreEqual(dataStream.Length, 4); var reader = new DataStreamReader(dataStream.AsNativeArray()); for (int i = 0; i < dataStream.Length; ++i) { Assert.AreEqual(byteArray[i], reader.ReadByte()); } #if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG LogAssert.Expect(LogType.Error, "Trying to read 1 bytes from a stream where only 0 are available"); Assert.AreEqual(0, reader.ReadByte()); #endif } [Test] public void CreateStreamWithSourceByteArray() { byte[] byteArray = new byte[100]; byteArray[0] = (byte)'a'; byteArray[1] = (byte)'b'; byteArray[2] = (byte)'c'; DataStreamWriter dataStream1, dataStream2; dataStream1 = new DataStreamWriter(byteArray.Length, Allocator.Temp); dataStream2 = new DataStreamWriter(byteArray.Length, Allocator.Temp); dataStream1.WriteBytes(new NativeArray(byteArray, Allocator.Temp)); dataStream2.WriteBytes(byteArray); var arr1 = dataStream1.AsNativeArray(); var arr2 = dataStream2.AsNativeArray(); var reader1 = new DataStreamReader(arr1); var reader2 = new DataStreamReader(arr2); for (var i = 0; i < byteArray.Length; ++i) { Assert.AreEqual(byteArray[i], reader1.ReadByte()); Assert.AreEqual(byteArray[i], reader2.ReadByte()); } } [Test] public void ReadIntoExistingNativeByteArray() { var byteArray = new NativeArray(100, Allocator.Temp); DataStreamWriter dataStream; dataStream = new DataStreamWriter(3, Allocator.Temp); { dataStream.WriteByte((byte)'a'); dataStream.WriteByte((byte)'b'); dataStream.WriteByte((byte)'c'); var reader = new DataStreamReader(dataStream.AsNativeArray()); reader.ReadBytes(byteArray.GetSubArray(0, dataStream.Length)); reader = new DataStreamReader(dataStream.AsNativeArray()); for (int i = 0; i < reader.Length; ++i) { Assert.AreEqual(byteArray[i], reader.ReadByte()); } } } [Test] public void ReadIntoExistingByteArray() { var byteArray = new byte[3]; DataStreamWriter dataStream; dataStream = new DataStreamWriter(3, Allocator.Temp); { dataStream.WriteByte((byte)'a'); dataStream.WriteByte((byte)'b'); dataStream.WriteByte((byte)'c'); var reader = new DataStreamReader(dataStream.AsNativeArray()); reader.ReadBytes(byteArray); reader = new DataStreamReader(dataStream.AsNativeArray()); for (int i = 0; i < reader.Length; ++i) { Assert.AreEqual(byteArray[i], reader.ReadByte()); } } } [Test] public void ReadingDataFromStreamWithSliceOffset() { var dataStream = new DataStreamWriter(100, Allocator.Temp); dataStream.WriteByte((byte)'a'); dataStream.WriteByte((byte)'b'); dataStream.WriteByte((byte)'c'); dataStream.WriteByte((byte)'d'); dataStream.WriteByte((byte)'e'); dataStream.WriteByte((byte)'f'); var reader = new DataStreamReader(dataStream.AsNativeArray().GetSubArray(3, 3)); Assert.AreEqual('d', reader.ReadByte()); Assert.AreEqual('e', reader.ReadByte()); Assert.AreEqual('f', reader.ReadByte()); } [Test] public void GetStreamReaderUnsafePtr() { var a = new NativeArray(1, Allocator.Temp); a[0] = (byte)42; var reader = new DataStreamReader(a); unsafe { var ptr = (byte*)reader.GetUnsafeReadOnlyPtr(); Assert.AreEqual((byte)42, *ptr); } } [Test] public void WriteOutOfBounds() { var dataStream = new DataStreamWriter(9, Allocator.Temp); Assert.IsTrue(dataStream.WriteInt(42)); Assert.AreEqual(4, dataStream.Length); Assert.IsTrue(dataStream.WriteInt(42)); Assert.AreEqual(8, dataStream.Length); Assert.IsFalse(dataStream.HasFailedWrites); Assert.IsFalse(dataStream.WriteInt(42)); Assert.AreEqual(8, dataStream.Length); Assert.IsTrue(dataStream.HasFailedWrites); Assert.IsFalse(dataStream.WriteShort(42)); Assert.AreEqual(8, dataStream.Length); Assert.IsTrue(dataStream.HasFailedWrites); Assert.IsTrue(dataStream.WriteByte(42)); Assert.AreEqual(9, dataStream.Length); Assert.IsTrue(dataStream.HasFailedWrites); Assert.IsFalse(dataStream.WriteByte(42)); Assert.AreEqual(9, dataStream.Length); Assert.IsTrue(dataStream.HasFailedWrites); } [Test] public void ReadWritePackedUIntWithDeferred() { var compressionModel = StreamCompressionModel.Default; var dataStream = new DataStreamWriter(300 * 4, Allocator.Temp); uint base_val = 2000; uint count = 277; var def = dataStream; dataStream.WriteInt((int)0); for (uint i = 0; i < count; ++i) dataStream.WritePackedUInt(base_val + i, compressionModel); dataStream.Flush(); def.WriteInt(1979); def = dataStream; dataStream.WriteInt((int)0); def.WriteInt(1979); dataStream.Flush(); var reader = new DataStreamReader(dataStream.AsNativeArray()); Assert.AreEqual(1979, reader.ReadInt()); for (uint i = 0; i < count; ++i) { var val = reader.ReadPackedUInt(compressionModel); Assert.AreEqual(base_val + i, val); } Assert.AreEqual(1979, reader.ReadInt()); } [Test] public void PassDataStreamReaderToJob() { using (var returnValue = new NativeArray(1, Allocator.TempJob)) { var writer = new DataStreamWriter(sizeof(int), Allocator.Temp); writer.WriteInt(42); var reader = new DataStreamReader(writer.AsNativeArray()); new ReaderTestJob { Reader = reader, ReturnValue = returnValue }.Run(); Assert.AreEqual(42, returnValue[0]); } } private struct ReaderTestJob : IJob { public DataStreamReader Reader; public NativeArray ReturnValue; public void Execute() { ReturnValue[0] = Reader.ReadInt(); } } delegate T Read(ref DataStreamReader reader); delegate T ReadPacked(ref DataStreamReader reader, StreamCompressionModel model); delegate bool Write(ref DataStreamWriter writer); delegate T Sum(T x, uint y); delegate bool WriteWithValue(ref DataStreamWriter writer, T value); delegate bool WritePacked(ref DataStreamWriter writer, StreamCompressionModel model); delegate bool WritePackedWithValue(ref DataStreamWriter writer, StreamCompressionModel model, T value); const int FixedStringHeader = 2; static void CheckReadWritePackedLooped(int size, T baseVal, T expected, Write write, WritePackedWithValue writePackedWithValue, Read read, ReadPacked readPacked, Sum sum) { var compressionModel = StreamCompressionModel.Default; var dataStream = new DataStreamWriter(300 * size, Allocator.Temp); const int count = 277; for (uint i = 0; i < count; ++i) { T res = sum(baseVal, i); writePackedWithValue(ref dataStream, compressionModel, res); } write(ref dataStream); dataStream.Flush(); var reader = new DataStreamReader(dataStream.AsNativeArray()); for (uint i = 0; i < count; ++i) { var val = readPacked(ref reader, compressionModel); Assert.AreEqual(sum(baseVal, i), val); } Assert.AreEqual(expected, read(ref reader)); } static void CheckReadWritePacked(int size, ReadPacked read, WritePacked write, T value) { var model = StreamCompressionModel.Default; var writer = new DataStreamWriter(size, Allocator.Temp); write(ref writer, model); writer.Flush(); var reader = new DataStreamReader(writer.AsNativeArray()); Assert.That(read(ref reader, model), Is.EqualTo(value)); } static void CheckReadWrite(int size, Func read, Write write, T value) { var writer = new DataStreamWriter(size, Allocator.Temp); write(ref writer); writer.Flush(); Assert.That(read(new DataStreamReader(writer.AsNativeArray())), Is.EqualTo(value)); } static void CheckReadWriteLooped(int size, T baseVal, T expected, WriteWithValue write, Read read, Sum sum) { var writer = new DataStreamWriter(300 * size, Allocator.Temp); const int count = 277; for (uint i = 0; i < count; ++i) { write(ref writer, sum(baseVal, i)); } write(ref writer, expected); writer.Flush(); var reader = new DataStreamReader(writer.AsNativeArray()); for (uint i = 0; i < count; ++i) { var val = read(ref reader); Assert.AreEqual(sum(baseVal, i), val); } Assert.AreEqual(expected, read(ref reader)); } [Test] public void MiNiCheck() { var model = StreamCompressionModel.Default; Assert.That(model.ToString(), Is.EqualTo("Unity.Collections.StreamCompressionModel")); } } }