A game about forced loneliness, made by TACStudios
1using System;
2using NUnit.Framework;
3using Unity.Burst;
4using Unity.Collections;
5using Unity.Collections.LowLevel.Unsafe;
6using Unity.Collections.Tests;
7using Unity.Jobs;
8
9internal class UnsafeAppendBufferTests : CollectionsTestCommonBase
10{
11 struct TestHeader
12 {
13 public int Type;
14 public int PayloadSize;
15 }
16
17 [Test]
18 public void UnsafeAppendBuffer_DisposeAllocated()
19 {
20 var buffer = new UnsafeAppendBuffer(1, 8, Allocator.Temp);
21 Assert.True(buffer.IsCreated);
22 Assert.True(buffer.IsEmpty);
23 buffer.Dispose();
24 }
25
26 [Test]
27 unsafe public void UnsafeAppendBuffer_DisposeExternal()
28 {
29 var data = stackalloc int[1];
30 var buffer = new UnsafeAppendBuffer(data, sizeof(int));
31 buffer.Add(5);
32 buffer.Dispose();
33 Assert.AreEqual(5, data[0]);
34 }
35
36 [Test]
37 [TestRequiresDotsDebugOrCollectionChecks]
38 public void UnsafeAppendBuffer_ThrowZeroAlignment()
39 {
40 Assert.Throws<ArgumentException>(() =>
41 {
42 var buffer = new UnsafeAppendBuffer(0, 0, Allocator.Temp);
43 });
44 }
45
46 void AddAndVerify<T>(ref UnsafeAppendBuffer buffer, T value, ref int expectedLength) where T : unmanaged
47 {
48 buffer.Add(value);
49 expectedLength += UnsafeUtility.SizeOf<T>();
50 Assert.AreEqual(expectedLength, buffer.Length);
51 }
52
53 [Test]
54 public unsafe void UnsafeAppendBuffer_AddAndPop_UnalignedRead()
55 {
56 int expectedLength = 0;
57 byte value = 0;
58 var buffer = new UnsafeAppendBuffer(0, 8, Allocator.Temp);
59 Assert.IsTrue(buffer.IsEmpty);
60 Assert.AreEqual(expectedLength, buffer.Length);
61
62 AddAndVerify<int>(ref buffer, value++, ref expectedLength);
63 AddAndVerify<byte>(ref buffer, value++, ref expectedLength);
64 AddAndVerify<int>(ref buffer, value++, ref expectedLength);
65 Assert.AreEqual(9, buffer.Length);
66 AddAndVerify<byte>(ref buffer, value++, ref expectedLength);
67 AddAndVerify<int>(ref buffer, value++, ref expectedLength);
68 Assert.AreEqual(14, buffer.Length);
69
70 {
71 var array = new NativeArray<int>(3, Allocator.Temp);
72 for (int i = 0; i < array.Length; ++i)
73 array[i] = value++;
74
75 int oldLen = buffer.Length;
76 buffer.AddArray<int>(array.GetUnsafePtr(), 3);
77
78 Assert.AreEqual(30, buffer.Length);
79 }
80
81 {
82 var array = new NativeArray<int>(3, Allocator.Temp);
83 for (int i = 0; i < array.Length; ++i)
84 array[i] = value++;
85
86 int oldLen = buffer.Length;
87 buffer.AddArray<int>(array.GetUnsafePtr(), 3);
88
89 Assert.AreEqual(46, buffer.Length);
90 }
91
92 // popping
93
94 // array elements + count
95 for (int i = 0; i < 3; ++i)
96 {
97 Assert.AreEqual(--value, buffer.Pop<int>());
98 }
99 Assert.AreEqual(3, buffer.Pop<int>());
100
101 // array elements + count
102 for (int i = 0; i < 3; ++i)
103 {
104 Assert.AreEqual(--value, buffer.Pop<int>());
105 }
106 Assert.AreEqual(3, buffer.Pop<int>());
107
108 Assert.AreEqual(--value, buffer.Pop<int>());
109 Assert.AreEqual(--value, buffer.Pop<byte>());
110 Assert.AreEqual(--value, buffer.Pop<int>());
111 Assert.AreEqual(--value, buffer.Pop<byte>());
112 Assert.AreEqual(--value, buffer.Pop<int>());
113
114 Assert.IsTrue(buffer.IsEmpty);
115 Assert.AreEqual(0, buffer.Length);
116 }
117
118 [Test]
119 public unsafe void UnsafeAppendBuffer_AddAndRead_UnalignedRead()
120 {
121 var buffer = new UnsafeAppendBuffer(0, 8, Allocator.Temp);
122 buffer.Add<byte>(1);
123 buffer.Add<float>(1.0f);
124 var reader = buffer.AsReader();
125 Assert.AreEqual(reader.ReadNext<byte>(), 1);
126 Assert.AreEqual(reader.ReadNext<float>(), 1.0f);
127 buffer.Dispose();
128 }
129
130 [Test]
131 public unsafe void UnsafeAppendBuffer_PushHeadersWithPackets()
132 {
133 var buffer = new UnsafeAppendBuffer(0, 8, Allocator.Temp);
134 var scratchPayload = stackalloc byte[1024];
135 var expectedSize = 0;
136 for (int i = 0; i < 1024; i++)
137 {
138 var packeType = i;
139 var packetSize = i;
140
141 buffer.Add(new TestHeader
142 {
143 Type = packeType,
144 PayloadSize = packetSize
145 });
146 expectedSize += UnsafeUtility.SizeOf<TestHeader>();
147
148 buffer.Add(scratchPayload, i);
149 expectedSize += i;
150 }
151 Assert.True(expectedSize == buffer.Length);
152
153 buffer.Dispose();
154 }
155
156 [Test]
157 public unsafe void UnsafeAppendBuffer_ReadHeadersWithPackets()
158 {
159 var buffer = new UnsafeAppendBuffer(0, 8, Allocator.Temp);
160 var scratchPayload = stackalloc byte[1024];
161 for (int i = 0; i < 1024; i++)
162 {
163 var packeType = i;
164 var packetSize = i;
165
166 buffer.Add(new TestHeader
167 {
168 Type = packeType,
169 PayloadSize = packetSize
170 });
171
172 UnsafeUtility.MemSet(scratchPayload, (byte)(i & 0xff), packetSize);
173
174 buffer.Add(scratchPayload, i);
175 }
176
177 var reader = buffer.AsReader();
178 for (int i = 0; i < 1024; i++)
179 {
180 var packetHeader = reader.ReadNext<TestHeader>();
181 Assert.AreEqual(i, packetHeader.Type);
182 Assert.AreEqual(i, packetHeader.PayloadSize);
183 if (packetHeader.PayloadSize > 0)
184 {
185 var packetPayload = reader.ReadNext(packetHeader.PayloadSize);
186 Assert.AreEqual((byte)(i & 0xff), *(byte*)packetPayload);
187 }
188 }
189 Assert.True(reader.EndOfBuffer);
190
191 buffer.Dispose();
192 }
193
194 [Test]
195 public unsafe void UnsafeAppendBuffer_AddAndPop()
196 {
197 var buffer = new UnsafeAppendBuffer(0, 8, Allocator.Temp);
198
199 buffer.Add<int>(123);
200 buffer.Add<int>(234);
201 buffer.Add<int>(345);
202
203 {
204 var array = new NativeArray<int>(3, Allocator.Temp);
205 buffer.Pop(array.GetUnsafePtr(), 3 * UnsafeUtility.SizeOf<int>());
206 CollectionAssert.AreEqual(new[] {123, 234, 345}, array);
207 }
208
209 {
210 var array = new NativeArray<int>(4, Allocator.Temp);
211 array.CopyFrom(new[] {987, 876, 765, 654});
212 buffer.Add(array.GetUnsafePtr(), 4 * UnsafeUtility.SizeOf<int>());
213 }
214
215 Assert.AreEqual(654, buffer.Pop<int>());
216 Assert.AreEqual(765, buffer.Pop<int>());
217 Assert.AreEqual(876, buffer.Pop<int>());
218 Assert.AreEqual(987, buffer.Pop<int>());
219
220 buffer.Dispose();
221 }
222
223 [Test]
224 public unsafe void UnsafeAppendBuffer_ReadNextArray()
225 {
226 var values = new NativeArray<int>(new[] {123, 234, 345}, Allocator.Temp);
227 var buffer = new UnsafeAppendBuffer(0, 8, Allocator.Temp);
228 buffer.Add(values);
229
230 var array = (int*)buffer.AsReader().ReadNextArray<int>(out var count);
231
232 Assert.AreEqual(values.Length, count);
233 for (int i = 0; i < count; ++i)
234 {
235 Assert.AreEqual(values[i], array[i]);
236 }
237
238 values.Dispose();
239 buffer.Dispose();
240 }
241
242 [Test]
243 public unsafe void UnsafeAppendBuffer_DisposeJob()
244 {
245 var sizeOf = UnsafeUtility.SizeOf<int>();
246 var alignOf = UnsafeUtility.AlignOf<int>();
247
248 var container = new UnsafeAppendBuffer(5, 16, Allocator.Persistent);
249
250 var disposeJob = container.Dispose(default);
251
252 Assert.IsTrue(container.Ptr == null);
253
254 disposeJob.Complete();
255 }
256
257 [Test]
258 public void UnsafeAppendBuffer_CustomAllocatorTest()
259 {
260 AllocatorManager.Initialize();
261 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
262 ref var allocator = ref allocatorHelper.Allocator;
263 allocator.Initialize();
264
265 using (var container = new UnsafeAppendBuffer(1, 1, allocator.Handle))
266 {
267 }
268
269 Assert.IsTrue(allocator.WasUsed);
270 allocator.Dispose();
271 allocatorHelper.Dispose();
272 AllocatorManager.Shutdown();
273 }
274
275 [BurstCompile]
276 struct BurstedCustomAllocatorJob : IJob
277 {
278 [NativeDisableUnsafePtrRestriction]
279 public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
280
281 public void Execute()
282 {
283 unsafe
284 {
285 using (var container = new UnsafeAppendBuffer(1, 1, Allocator->Handle))
286 {
287 }
288 }
289 }
290 }
291
292 [Test]
293 public unsafe void UnsafeAppendBuffer_BurstedCustomAllocatorTest()
294 {
295 AllocatorManager.Initialize();
296 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
297 ref var allocator = ref allocatorHelper.Allocator;
298 allocator.Initialize();
299
300 var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
301 unsafe
302 {
303 var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
304 handle.Complete();
305 }
306
307 Assert.IsTrue(allocator.WasUsed);
308 allocator.Dispose();
309 allocatorHelper.Dispose();
310 AllocatorManager.Shutdown();
311 }
312}