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;
8using Assert = FastAssert;
9
10[BurstCompile]
11internal class UnsafeQueueTests : CollectionsTestCommonBase
12{
13 static void ExpectedCount<T>(ref UnsafeQueue<T> container, int expected) where T : unmanaged
14 {
15 Assert.AreEqual(expected == 0, container.IsEmpty());
16 Assert.AreEqual(expected, container.Count);
17 }
18
19 [Test]
20 public void Enqueue_Dequeue()
21 {
22 var queue = new UnsafeQueue<int>(Allocator.Temp);
23 ExpectedCount(ref queue, 0);
24
25#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
26 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
27#endif
28
29 for (int i = 0; i < 16; ++i)
30 queue.Enqueue(i);
31 ExpectedCount(ref queue, 16);
32 for (int i = 0; i < 16; ++i)
33 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
34 ExpectedCount(ref queue, 0);
35
36#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
37 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
38#endif
39
40 queue.Dispose();
41 }
42
43 [Test]
44 public void ConcurrentEnqueue_Dequeue()
45 {
46 var queue = new UnsafeQueue<int>(Allocator.Temp);
47 var cQueue = queue.AsParallelWriter();
48 ExpectedCount(ref queue, 0);
49
50#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
51 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
52#endif
53
54 for (int i = 0; i < 16; ++i)
55 cQueue.Enqueue(i);
56 ExpectedCount(ref queue, 16);
57 for (int i = 0; i < 16; ++i)
58 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
59 ExpectedCount(ref queue, 0);
60
61#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
62 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
63#endif
64
65 queue.Dispose();
66 }
67
68 [Test]
69 public void Enqueue_Dequeue_Peek()
70 {
71 var queue = new UnsafeQueue<int>(Allocator.Temp);
72 ExpectedCount(ref queue, 0);
73
74#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
75 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
76#endif
77
78 for (int i = 0; i < 16; ++i)
79 queue.Enqueue(i);
80 ExpectedCount(ref queue, 16);
81 for (int i = 0; i < 16; ++i)
82 {
83 Assert.AreEqual(i, queue.Peek(), "Got the wrong value from the queue");
84 queue.Dequeue();
85 }
86 ExpectedCount(ref queue, 0);
87
88#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
89 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
90#endif
91
92 queue.Dispose();
93 }
94
95 [Test]
96 public void Enqueue_Dequeue_Clear()
97 {
98 var queue = new UnsafeQueue<int>(Allocator.Temp);
99 ExpectedCount(ref queue, 0);
100
101#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
102 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
103#endif
104
105 for (int i = 0; i < 16; ++i)
106 queue.Enqueue(i);
107 ExpectedCount(ref queue, 16);
108 for (int i = 0; i < 8; ++i)
109 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
110 ExpectedCount(ref queue, 8);
111 queue.Clear();
112 ExpectedCount(ref queue, 0);
113
114#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
115 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
116#endif
117
118 queue.Dispose();
119 }
120
121 [Test]
122 public void Double_Deallocate_DoesNotThrow()
123 {
124 var queue = new UnsafeQueue<int>(CommonRwdAllocator.Handle);
125 queue.Dispose();
126 Assert.DoesNotThrow(
127 () => { queue.Dispose(); });
128 }
129
130 [Test]
131 public void EnqueueScalability()
132 {
133 var queue = new UnsafeQueue<int>(Allocator.Persistent);
134 for (int i = 0; i != 1000 * 100; i++)
135 {
136 queue.Enqueue(i);
137 }
138
139 ExpectedCount(ref queue, 1000 * 100);
140
141 for (int i = 0; i != 1000 * 100; i++)
142 Assert.AreEqual(i, queue.Dequeue());
143 ExpectedCount(ref queue, 0);
144
145 queue.Dispose();
146 }
147
148 [Test]
149 public void Enqueue_Wrap()
150 {
151 var queue = new UnsafeQueue<int>(Allocator.Temp);
152 ExpectedCount(ref queue, 0);
153
154#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
155 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
156#endif
157
158 for (int i = 0; i < 256; ++i)
159 queue.Enqueue(i);
160 ExpectedCount(ref queue, 256);
161
162 for (int i = 0; i < 128; ++i)
163 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
164 ExpectedCount(ref queue, 128);
165
166 for (int i = 0; i < 128; ++i)
167 queue.Enqueue(i);
168 ExpectedCount(ref queue, 256);
169
170 for (int i = 128; i < 256; ++i)
171 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
172 ExpectedCount(ref queue, 128);
173
174 for (int i = 0; i < 128; ++i)
175 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
176 ExpectedCount(ref queue, 0);
177
178#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
179 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
180#endif
181
182 queue.Dispose();
183 }
184
185 [Test]
186 public void ConcurrentEnqueue_Wrap()
187 {
188 var queue = new UnsafeQueue<int>(Allocator.Temp);
189 var cQueue = queue.AsParallelWriter();
190 ExpectedCount(ref queue, 0);
191
192#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
193 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
194#endif
195
196 for (int i = 0; i < 256; ++i)
197 cQueue.Enqueue(i);
198 ExpectedCount(ref queue, 256);
199
200 for (int i = 0; i < 128; ++i)
201 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
202 ExpectedCount(ref queue, 128);
203
204 for (int i = 0; i < 128; ++i)
205 cQueue.Enqueue(i);
206 ExpectedCount(ref queue, 256);
207
208 for (int i = 128; i < 256; ++i)
209 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
210 ExpectedCount(ref queue, 128);
211
212 for (int i = 0; i < 128; ++i)
213 Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
214 ExpectedCount(ref queue, 0);
215
216#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
217 Assert.Throws<System.InvalidOperationException>(() => {queue.Dequeue(); });
218#endif
219
220 queue.Dispose();
221 }
222
223 [Test]
224 public void TryDequeue_OnEmptyQueueWhichHadElements_RetainsValidState()
225 {
226 using (var queue = new UnsafeQueue<int>(Allocator.Temp))
227 {
228 for (int i = 0; i < 3; i++)
229 {
230 queue.Enqueue(i);
231 Assert.AreEqual(1, queue.Count);
232
233 int value;
234 while (queue.TryDequeue(out value))
235 {
236 Assert.AreEqual(i, value);
237 }
238
239 Assert.AreEqual(0, queue.Count);
240 }
241 }
242 }
243
244 [Test]
245 public void TryDequeue_OnEmptyQueue_RetainsValidState()
246 {
247 using (var queue = new UnsafeQueue<int>(Allocator.Temp))
248 {
249 Assert.IsFalse(queue.TryDequeue(out _));
250 queue.Enqueue(1);
251 Assert.AreEqual(1, queue.Count);
252 }
253 }
254
255 [Test]
256 public void ToArray_ContainsCorrectElements()
257 {
258 using (var queue = new UnsafeQueue<int>(Allocator.Temp))
259 {
260 for (int i = 0; i < 100; i++)
261 queue.Enqueue(i);
262 using (var array = queue.ToArray(Allocator.Temp))
263 {
264 Assert.AreEqual(queue.Count, array.Length);
265 for (int i = 0; i < array.Length; i++)
266 Assert.AreEqual(i, array[i]);
267 }
268 }
269 }
270
271 [Test]
272 public void ToArray_RespectsDequeue()
273 {
274 using (var queue = new UnsafeQueue<int>(Allocator.Temp))
275 {
276 for (int i = 0; i < 100; i++)
277 queue.Enqueue(i);
278 for (int i = 0; i < 50; i++)
279 queue.Dequeue();
280 using (var array = queue.ToArray(Allocator.Temp))
281 {
282 Assert.AreEqual(queue.Count, array.Length);
283 for (int i = 0; i < array.Length; i++)
284 Assert.AreEqual(50 + i, array[i]);
285 }
286 }
287 }
288
289 [Test]
290 public void UnsafeQueue_CustomAllocatorTest()
291 {
292 AllocatorManager.Initialize();
293 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
294 ref var allocator = ref allocatorHelper.Allocator;
295 allocator.Initialize();
296
297 using (var container = new UnsafeQueue<int>(allocator.Handle))
298 {
299 }
300
301 Assert.IsTrue(allocator.WasUsed);
302 allocator.Dispose();
303 allocatorHelper.Dispose();
304 AllocatorManager.Shutdown();
305 }
306
307 [BurstCompile(CompileSynchronously = true)]
308 struct BurstedCustomAllocatorJob : IJob
309 {
310 [NativeDisableUnsafePtrRestriction]
311 public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
312
313 public void Execute()
314 {
315 unsafe
316 {
317 using (var container = new UnsafeQueue<int>(Allocator->Handle))
318 {
319 }
320 }
321 }
322 }
323
324 [Test]
325 public unsafe void UnsafeQueue_BurstedCustomAllocatorTest()
326 {
327 AllocatorManager.Initialize();
328 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
329 ref var allocator = ref allocatorHelper.Allocator;
330
331 allocator.Initialize();
332
333 var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
334 unsafe
335 {
336 var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
337 handle.Complete();
338 }
339
340 Assert.IsTrue(allocator.WasUsed);
341 allocator.Dispose();
342 allocatorHelper.Dispose();
343 AllocatorManager.Shutdown();
344 }
345
346 public struct NestedContainer
347 {
348 public UnsafeQueue<int> data;
349 }
350
351 [Test]
352 public void UnsafeQueue_Nested()
353 {
354 var inner = new UnsafeQueue<int>(CommonRwdAllocator.Handle);
355 NestedContainer nestedStruct = new NestedContainer { data = inner };
356
357 var containerNestedStruct = new UnsafeQueue<NestedContainer>(CommonRwdAllocator.Handle);
358 var containerNested = new UnsafeQueue<UnsafeQueue<int>>(CommonRwdAllocator.Handle);
359
360 containerNested.Enqueue(inner);
361 containerNestedStruct.Enqueue(nestedStruct);
362
363 containerNested.Dispose();
364 containerNestedStruct.Dispose();
365 inner.Dispose();
366 }
367}