A game about forced loneliness, made by TACStudios
1using NUnit.Framework;
2using Unity.Collections;
3using Unity.Collections.LowLevel.Unsafe;
4using Unity.Collections.Tests;
5using Unity.Jobs;
6using System;
7using Unity.Jobs.Tests.ManagedJobs;
8
9[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeArray<int>>))]
10[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeAppendBuffer>))]
11[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeBitArray>))]
12[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeBitArray>))]
13[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeHashMap<int, int>>))]
14[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeHashMap<int, int>>))]
15[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeHashSet<int>>))]
16[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeHashSet<int>>))]
17[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeList<int>>))]
18[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeList<int>>))]
19[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafePtrList<int>>))]
20[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeParallelHashMap<int, int>>))]
21[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeParallelHashMap<int, int>>))]
22[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeParallelHashSet<int>>))]
23[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeParallelHashSet<int>>))]
24[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeParallelMultiHashMap<int, int>>))]
25[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeParallelMultiHashMap<int, int>>))]
26[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeQueue<int>>))]
27[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeQueue<int>>))]
28[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeReference<int>>))]
29[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeRingQueue<int>>))]
30[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeRingQueue<int>>))]
31[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeStream>))]
32[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeStream>))]
33[assembly: RegisterGenericJobType(typeof(GenericContainerJob<NativeText>))]
34[assembly: RegisterGenericJobType(typeof(GenericContainerJob<UnsafeText>))]
35
36internal struct GenericContainerJob<T> : IJob
37{
38 public T data;
39 public void Execute()
40 {
41 // We just care about creating job dependencies
42 }
43}
44
45internal struct GenericContainerReadonlyJob<T> : IJob
46{
47 [ReadOnly] public T data;
48 public void Execute()
49 {
50 // We just care about creating job dependencies
51 }
52}
53
54internal class GenericContainerTests : CollectionsTestFixture
55{
56 UnsafeAppendBuffer CreateEmpty_UnsafeAppendBuffer()
57 {
58 var container = new UnsafeAppendBuffer(0, 8, Allocator.Persistent);
59 Assert.True(container.IsCreated);
60 Assert.True(container.IsEmpty);
61 return container;
62 }
63
64 NativeBitArray CreateEmpty_NativeBitArray()
65 {
66 var container = new NativeBitArray(0, Allocator.Persistent);
67 Assert.True(container.IsCreated);
68 Assert.True(container.IsEmpty);
69 return container;
70 }
71
72 void NativeBitArray_IsCreated_Uninitialized()
73 {
74 NativeBitArray container = default;
75 Assert.False(container.IsCreated);
76 Assert.True(container.IsEmpty);
77
78 NativeBitArray.ReadOnly containerRo = default;
79 Assert.False(containerRo.IsCreated);
80 Assert.True(containerRo.IsEmpty);
81 }
82
83 UnsafeBitArray CreateEmpty_UnsafeBitArray()
84 {
85 var container = new UnsafeBitArray(0, Allocator.Persistent);
86 Assert.True(container.IsCreated);
87 Assert.True(container.IsEmpty);
88 return container;
89 }
90
91 void UnsafeBitArray_IsCreated_Uninitialized()
92 {
93 UnsafeBitArray container = default;
94 Assert.False(container.IsCreated);
95 Assert.True(container.IsEmpty);
96
97 UnsafeBitArray.ReadOnly containerRo = default;
98 Assert.False(containerRo.IsCreated);
99 Assert.True(containerRo.IsEmpty);
100 }
101
102 NativeHashMap<int, int> CreateEmpty_NativeHashMap()
103 {
104 var container = new NativeHashMap<int, int>(0, Allocator.Persistent);
105 Assert.True(container.IsCreated);
106 Assert.True(container.IsEmpty);
107 return container;
108 }
109
110 void NativeHashMap_IsCreated_Uninitialized()
111 {
112 NativeHashMap<int, int> container = default;
113 Assert.False(container.IsCreated);
114 Assert.True(container.IsEmpty);
115
116 NativeHashMap<int, int>.ReadOnly containerRo = default;
117 Assert.False(containerRo.IsCreated);
118 Assert.True(containerRo.IsEmpty);
119 }
120
121 UnsafeHashMap<int, int> CreateEmpty_UnsafeHashMap()
122 {
123 var container = new UnsafeHashMap<int, int>(0, Allocator.Persistent);
124 Assert.True(container.IsCreated);
125 Assert.True(container.IsEmpty);
126 return container;
127 }
128
129 void UnsafeHashMap_IsCreated_Uninitialized()
130 {
131 UnsafeHashMap<int, int> container = default;
132 Assert.False(container.IsCreated);
133 Assert.True(container.IsEmpty);
134
135 UnsafeHashMap<int, int>.ReadOnly containerRo = default;
136 Assert.False(containerRo.IsCreated);
137 Assert.True(containerRo.IsEmpty);
138 }
139
140 NativeHashSet<int> CreateEmpty_NativeHashSet()
141 {
142 var container = new NativeHashSet<int>(0, Allocator.Persistent);
143 Assert.True(container.IsCreated);
144 Assert.True(container.IsEmpty);
145 return container;
146 }
147
148 void NativeHashSet_IsCreated_Uninitialized()
149 {
150 NativeHashSet<int> container = default;
151 Assert.False(container.IsCreated);
152 Assert.True(container.IsEmpty);
153
154 NativeHashSet<int>.ReadOnly containerRo = default;
155 Assert.False(containerRo.IsCreated);
156 Assert.True(containerRo.IsEmpty);
157 }
158
159 UnsafeHashSet<int> CreateEmpty_UnsafeHashSet()
160 {
161 var container = new UnsafeHashSet<int>(0, Allocator.Persistent);
162 Assert.True(container.IsCreated);
163 Assert.True(container.IsEmpty);
164 return container;
165 }
166
167 void UnsafeHashSet_IsCreated_Uninitialized()
168 {
169 UnsafeHashSet<int> container = default;
170 Assert.False(container.IsCreated);
171 Assert.True(container.IsEmpty);
172
173 UnsafeHashSet<int>.ReadOnly containerRo = default;
174 Assert.False(containerRo.IsCreated);
175 Assert.True(containerRo.IsEmpty);
176 }
177
178 NativeList<int> CreateEmpty_NativeList()
179 {
180 var container = new NativeList<int>(0, Allocator.Persistent);
181 Assert.True(container.IsCreated);
182 Assert.True(container.IsEmpty);
183 return container;
184 }
185
186 void NativeList_IsCreated_Uninitialized()
187 {
188 NativeList<int> container = default;
189 Assert.False(container.IsCreated);
190 Assert.True(container.IsEmpty);
191
192 NativeArray<int>.ReadOnly containerRo = default;
193 Assert.False(containerRo.IsCreated);
194 // NativeArray doesn't have IsEmpty property -> Assert.True(containerRo.IsEmpty);
195 }
196
197 UnsafeList<int> CreateEmpty_UnsafeList()
198 {
199 var container = new UnsafeList<int>(0, Allocator.Persistent);
200 Assert.True(container.IsCreated);
201 Assert.True(container.IsEmpty);
202 return container;
203 }
204
205 void UnsafeList_IsCreated_Uninitialized()
206 {
207 UnsafeList<int> container = default;
208 Assert.False(container.IsCreated);
209 Assert.True(container.IsEmpty);
210
211 UnsafeList<int>.ReadOnly containerRo = default;
212 Assert.False(containerRo.IsCreated);
213 Assert.True(containerRo.IsEmpty);
214 }
215
216 UnsafePtrList<int> CreateEmpty_UnsafePtrList()
217 {
218 var container = new UnsafePtrList<int>(0, Allocator.Persistent);
219 Assert.True(container.IsCreated);
220 Assert.True(container.IsEmpty);
221 return container;
222 }
223
224 void UnsafePtrList_IsCreated_Uninitialized()
225 {
226 UnsafePtrList<int> container = default;
227 Assert.False(container.IsCreated);
228 Assert.True(container.IsEmpty);
229
230 UnsafePtrList<int>.ReadOnly containerRo = default;
231 Assert.False(containerRo.IsCreated);
232 Assert.True(containerRo.IsEmpty);
233 }
234
235 NativeParallelHashMap<int, int> CreateEmpty_NativeParallelHashMap()
236 {
237 var container = new NativeParallelHashMap<int, int>(0, Allocator.Persistent);
238 Assert.True(container.IsCreated);
239 Assert.True(container.IsEmpty);
240 return container;
241 }
242
243 void NativeParallelHashMap_IsCreated_Uninitialized()
244 {
245 NativeParallelHashMap<int, int> container = default;
246 Assert.False(container.IsCreated);
247 Assert.True(container.IsEmpty);
248
249 NativeParallelHashMap<int, int>.ReadOnly containerRo = default;
250 Assert.False(containerRo.IsCreated);
251 Assert.True(containerRo.IsEmpty);
252 }
253
254 UnsafeParallelHashMap<int, int> CreateEmpty_UnsafeParallelHashMap()
255 {
256 var container = new UnsafeParallelHashMap<int, int>(0, Allocator.Persistent);
257 Assert.True(container.IsCreated);
258 Assert.True(container.IsEmpty);
259 return container;
260 }
261
262 void UnsafeParallelHashMap_IsCreated_Uninitialized()
263 {
264 UnsafeParallelHashMap<int, int> container = default;
265 Assert.False(container.IsCreated);
266 Assert.True(container.IsEmpty);
267
268 UnsafeParallelHashMap<int, int>.ReadOnly containerRo = default;
269 Assert.False(containerRo.IsCreated);
270 Assert.True(containerRo.IsEmpty);
271 }
272
273 NativeParallelHashSet<int> CreateEmpty_NativeParallelHashSet()
274 {
275 var container = new NativeParallelHashSet<int>(0, Allocator.Persistent);
276 Assert.True(container.IsCreated);
277 Assert.True(container.IsEmpty);
278 return container;
279 }
280
281 void NativeParallelHashSet_IsCreated_Uninitialized()
282 {
283 NativeParallelHashSet<int> container = default;
284 Assert.False(container.IsCreated);
285 Assert.True(container.IsEmpty);
286
287 NativeParallelHashSet<int>.ReadOnly containerRo = default;
288 Assert.False(containerRo.IsCreated);
289 Assert.True(containerRo.IsEmpty);
290 }
291
292 UnsafeParallelHashSet<int> CreateEmpty_UnsafeParallelHashSet()
293 {
294 var container = new UnsafeParallelHashSet<int>(0, Allocator.Persistent);
295 Assert.True(container.IsCreated);
296 Assert.True(container.IsEmpty);
297 return container;
298 }
299
300 void UnsafeParallelHashSet_IsCreated_Uninitialized()
301 {
302 UnsafeParallelHashSet<int> container = default;
303 Assert.False(container.IsCreated);
304 Assert.True(container.IsEmpty);
305
306 UnsafeParallelHashSet<int>.ReadOnly containerRo = default;
307 Assert.False(containerRo.IsCreated);
308 Assert.True(containerRo.IsEmpty);
309 }
310
311 NativeParallelMultiHashMap<int, int> CreateEmpty_NativeParallelMultiHashMap()
312 {
313 var container = new NativeParallelMultiHashMap<int, int>(0, Allocator.Persistent);
314 Assert.True(container.IsCreated);
315 Assert.True(container.IsEmpty);
316 return container;
317 }
318
319 void NativeParallelMultiHashMap_IsCreated_Uninitialized()
320 {
321 NativeParallelMultiHashMap<int, int> container = default;
322 Assert.False(container.IsCreated);
323 Assert.True(container.IsEmpty);
324
325 NativeParallelMultiHashMap<int, int>.ReadOnly containerRo = default;
326 Assert.False(containerRo.IsCreated);
327 Assert.True(containerRo.IsEmpty);
328 }
329
330 UnsafeParallelMultiHashMap<int, int> CreateEmpty_UnsafeParallelMultiHashMap()
331 {
332 var container = new UnsafeParallelMultiHashMap<int, int>(0, Allocator.Persistent);
333 Assert.True(container.IsCreated);
334 Assert.True(container.IsEmpty);
335 return container;
336 }
337
338 void UnsafeParallelMultiHashMap_IsCreated_Uninitialized()
339 {
340 UnsafeParallelMultiHashMap<int, int> container = default;
341 Assert.False(container.IsCreated);
342 Assert.True(container.IsEmpty);
343
344 UnsafeParallelMultiHashMap<int, int>.ReadOnly containerRo = default;
345 Assert.False(containerRo.IsCreated);
346 Assert.True(containerRo.IsEmpty);
347 }
348
349 NativeQueue<int> CreateEmpty_NativeQueue()
350 {
351 var container = new NativeQueue<int>(Allocator.Persistent);
352 Assert.True(container.IsCreated);
353 Assert.True(container.IsEmpty());
354 return container;
355 }
356
357 void NativeQueue_IsCreated_Uninitialized()
358 {
359 NativeQueue<int> container = default;
360 Assert.False(container.IsCreated);
361
362 NativeQueue<int>.ReadOnly containerRo = default;
363 Assert.False(containerRo.IsCreated);
364 }
365
366 UnsafeQueue<int> CreateEmpty_UnsafeQueue()
367 {
368 var container = new UnsafeQueue<int>(Allocator.Persistent);
369 Assert.True(container.IsCreated);
370 Assert.True(container.IsEmpty());
371 return container;
372 }
373
374 void UnsafeQueue_IsCreated_Uninitialized()
375 {
376 UnsafeQueue<int> container = default;
377 Assert.False(container.IsCreated);
378
379 UnsafeQueue<int>.ReadOnly containerRo = default;
380 Assert.False(containerRo.IsCreated);
381 }
382
383 NativeReference<int> CreateEmpty_NativeReference()
384 {
385 var container = new NativeReference<int>(Allocator.Persistent);
386 Assert.True(container.IsCreated);
387 return container;
388 }
389
390 NativeRingQueue<int> CreateEmpty_NativeRingQueue()
391 {
392 var container = new NativeRingQueue<int>(0, Allocator.Persistent);
393 Assert.True(container.IsCreated);
394 Assert.True(container.IsEmpty);
395 return container;
396 }
397
398 void NativeRingQueue_IsCreated_Uninitialized()
399 {
400 NativeRingQueue<int> container = default;
401 Assert.False(container.IsCreated);
402 Assert.True(container.IsEmpty);
403 }
404
405 UnsafeRingQueue<int> CreateEmpty_UnsafeRingQueue()
406 {
407 var container = new UnsafeRingQueue<int>(0, Allocator.Persistent);
408 Assert.True(container.IsCreated);
409 Assert.True(container.IsEmpty);
410 return container;
411 }
412
413 void UnsafeRingQueue_IsCreated_Uninitialized()
414 {
415 UnsafeRingQueue<int> container = default;
416 Assert.False(container.IsCreated);
417 Assert.True(container.IsEmpty);
418 }
419
420 NativeStream CreateEmpty_NativeStream()
421 {
422 var container = new NativeStream(0, Allocator.Persistent);
423 Assert.True(container.IsCreated);
424 Assert.True(container.IsEmpty());
425 return container;
426 }
427
428 UnsafeStream CreateEmpty_UnsafeStream()
429 {
430 var container = new UnsafeStream(0, Allocator.Persistent);
431 Assert.True(container.IsCreated);
432 Assert.True(container.IsEmpty());
433 return container;
434 }
435
436 NativeText CreateEmpty_NativeText()
437 {
438 var container = new NativeText(0, Allocator.Persistent);
439 Assert.True(container.IsCreated);
440 Assert.True(container.IsEmpty);
441 return container;
442 }
443
444 UnsafeText CreateEmpty_UnsafeText()
445 {
446 var container = new UnsafeText(0, Allocator.Persistent);
447 Assert.True(container.IsCreated);
448 Assert.True(container.IsEmpty);
449 return container;
450 }
451
452 //-------------------------------------------------------------------------------------------------------
453
454 [Test]
455 public void Test_IsCreated_Uninitialized()
456 {
457 NativeBitArray_IsCreated_Uninitialized();
458 UnsafeBitArray_IsCreated_Uninitialized();
459
460 NativeHashMap_IsCreated_Uninitialized();
461 UnsafeHashMap_IsCreated_Uninitialized();
462
463 NativeHashSet_IsCreated_Uninitialized();
464 UnsafeHashSet_IsCreated_Uninitialized();
465
466 NativeList_IsCreated_Uninitialized();
467 UnsafeList_IsCreated_Uninitialized();
468
469 UnsafePtrList_IsCreated_Uninitialized();
470
471 NativeParallelHashMap_IsCreated_Uninitialized();
472 UnsafeParallelHashMap_IsCreated_Uninitialized();
473
474 NativeParallelHashSet_IsCreated_Uninitialized();
475 UnsafeParallelHashSet_IsCreated_Uninitialized();
476
477 NativeParallelMultiHashMap_IsCreated_Uninitialized();
478 UnsafeParallelMultiHashMap_IsCreated_Uninitialized();
479
480 NativeQueue_IsCreated_Uninitialized();
481 UnsafeQueue_IsCreated_Uninitialized();
482
483 NativeRingQueue_IsCreated_Uninitialized();
484 UnsafeRingQueue_IsCreated_Uninitialized();
485 }
486
487 //-------------------------------------------------------------------------------------------------------
488
489 void Test_Dispose_Uninitialized<T>()
490 where T : INativeDisposable
491 {
492 T uninitialized = default;
493 Assert.DoesNotThrow(() => uninitialized.Dispose());
494 Assert.DoesNotThrow(() => uninitialized.Dispose(default));
495 }
496
497 [Test]
498 public void INativeDisposable_Dispose_Uninitialized()
499 {
500 Test_Dispose_Uninitialized<NativeBitArray>();
501 Test_Dispose_Uninitialized<NativeHashMap<int, int>>();
502 Test_Dispose_Uninitialized<NativeHashSet<int>>();
503 Test_Dispose_Uninitialized<NativeList<int>>();
504 Test_Dispose_Uninitialized<NativeParallelHashMap<int, int>>();
505 Test_Dispose_Uninitialized<NativeParallelHashSet<int>>();
506 Test_Dispose_Uninitialized<NativeParallelMultiHashMap<int, int>>();
507 Test_Dispose_Uninitialized<NativeQueue<int>>();
508 Test_Dispose_Uninitialized<NativeReference<int>>();
509 Test_Dispose_Uninitialized<NativeRingQueue<int>>();
510 Test_Dispose_Uninitialized<NativeStream>();
511 Test_Dispose_Uninitialized<NativeText>();
512
513 Test_Dispose_Uninitialized<UnsafeAppendBuffer>();
514 Test_Dispose_Uninitialized<UnsafeBitArray>();
515 Test_Dispose_Uninitialized<UnsafeHashMap<int, int>>();
516 Test_Dispose_Uninitialized<UnsafeHashSet<int>>();
517 Test_Dispose_Uninitialized<UnsafeList<int>>();
518 Test_Dispose_Uninitialized<UnsafePtrList<int>>();
519 Test_Dispose_Uninitialized<UnsafeParallelHashMap<int, int>>();
520 Test_Dispose_Uninitialized<UnsafeParallelHashSet<int>>();
521 Test_Dispose_Uninitialized<UnsafeParallelMultiHashMap<int, int>>();
522 Test_Dispose_Uninitialized<UnsafeQueue<int>>();
523 Test_Dispose_Uninitialized<UnsafeRingQueue<int>>();
524 Test_Dispose_Uninitialized<UnsafeStream>();
525 Test_Dispose_Uninitialized<UnsafeText>();
526 }
527
528 //-------------------------------------------------------------------------------------------------------
529
530 void Test_Unsafe_Double_Dispose<T>(T container)
531 where T : INativeDisposable
532 {
533 Assert.DoesNotThrow(() => container.Dispose());
534 Assert.DoesNotThrow(() => container.Dispose());
535 }
536
537 void Test_Native_Double_Dispose<T>(T container)
538 where T : INativeDisposable
539 {
540 Assert.DoesNotThrow(() => container.Dispose());
541#if ENABLE_UNITY_COLLECTIONS_CHECKS
542 Assert.Throws<ObjectDisposedException>(() => container.Dispose());
543#else
544 Assert.DoesNotThrow(() => container.Dispose());
545#endif
546 }
547
548 [Test]
549 public void INativeDisposable_Init_Double_Dispose()
550 {
551 Test_Native_Double_Dispose(CreateEmpty_NativeBitArray());
552 Test_Native_Double_Dispose(CreateEmpty_NativeHashMap());
553 Test_Native_Double_Dispose(CreateEmpty_NativeHashSet());
554 Test_Native_Double_Dispose(CreateEmpty_NativeList());
555 Test_Native_Double_Dispose(CreateEmpty_NativeParallelHashMap());
556 Test_Native_Double_Dispose(CreateEmpty_NativeParallelHashSet());
557 Test_Native_Double_Dispose(CreateEmpty_NativeParallelMultiHashMap());
558 Test_Native_Double_Dispose(CreateEmpty_NativeQueue());
559 Test_Native_Double_Dispose(CreateEmpty_NativeReference());
560 Test_Native_Double_Dispose(CreateEmpty_NativeRingQueue());
561 Test_Native_Double_Dispose(CreateEmpty_NativeStream());
562 Test_Native_Double_Dispose(CreateEmpty_NativeText());
563
564 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeAppendBuffer());
565 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeBitArray());
566 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeHashMap());
567 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeHashSet());
568 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeList());
569 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafePtrList());
570 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeParallelHashMap());
571 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeParallelHashSet());
572 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeParallelMultiHashMap());
573 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeQueue());
574 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeRingQueue());
575 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeStream());
576 Test_Unsafe_Double_Dispose(CreateEmpty_UnsafeText());
577 }
578
579 //-------------------------------------------------------------------------------------------------------
580
581 void Test_Unsafe_Double_Dispose_Job<T>(T container)
582 where T : INativeDisposable
583 {
584 Assert.DoesNotThrow(() => container.Dispose(default));
585 Assert.DoesNotThrow(() => container.Dispose(default));
586 }
587
588 void Test_Native_Double_Dispose_Job<T>(T container)
589 where T : INativeDisposable
590 {
591 Assert.DoesNotThrow(() => container.Dispose(default));
592#if ENABLE_UNITY_COLLECTIONS_CHECKS
593 Assert.Throws<ObjectDisposedException>(() => container.Dispose(default));
594#else
595 Assert.DoesNotThrow(() => container.Dispose(default));
596#endif
597 }
598
599 [Test]
600 public void INativeDisposable_Init_Double_Dispose_Job()
601 {
602 Test_Native_Double_Dispose_Job(CreateEmpty_NativeBitArray());
603 Test_Native_Double_Dispose_Job(CreateEmpty_NativeHashMap());
604 Test_Native_Double_Dispose_Job(CreateEmpty_NativeHashSet());
605 Test_Native_Double_Dispose_Job(CreateEmpty_NativeList());
606 Test_Native_Double_Dispose_Job(CreateEmpty_NativeParallelHashMap());
607 Test_Native_Double_Dispose_Job(CreateEmpty_NativeParallelHashSet());
608 Test_Native_Double_Dispose_Job(CreateEmpty_NativeParallelMultiHashMap());
609 Test_Native_Double_Dispose_Job(CreateEmpty_NativeQueue());
610 Test_Native_Double_Dispose_Job(CreateEmpty_NativeReference());
611 Test_Native_Double_Dispose_Job(CreateEmpty_NativeRingQueue());
612 Test_Native_Double_Dispose_Job(CreateEmpty_NativeStream());
613 Test_Native_Double_Dispose_Job(CreateEmpty_NativeText());
614
615 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeAppendBuffer());
616 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeBitArray());
617 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeHashMap());
618 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeHashSet());
619 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeList());
620 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafePtrList());
621 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeParallelHashMap());
622 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeParallelHashSet());
623 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeParallelMultiHashMap());
624 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeQueue());
625 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeRingQueue());
626 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeStream());
627 Test_Unsafe_Double_Dispose_Job(CreateEmpty_UnsafeText());
628 }
629
630 //-------------------------------------------------------------------------------------------------------
631
632 void Test_Dispose_Job_Missing_Dependency<T>(T container)
633 where T : INativeDisposable
634 {
635 GenericContainerJob<T> job = new GenericContainerJob<T>() { data = container };
636 JobHandle jobHandle = job.Schedule();
637 Assert.Throws<InvalidOperationException>(() => container.Dispose(default));
638 Assert.DoesNotThrow(() => jobHandle = container.Dispose(jobHandle));
639 jobHandle.Complete();
640 }
641
642 [Test]
643 [TestRequiresCollectionChecks("Tests dispose job while another job is scheduled - crashes without safety system")]
644 public void INativeDisposable_Dispose_Job_Missing_Dependency()
645 {
646 Test_Dispose_Job_Missing_Dependency(new NativeBitArray(16, Allocator.Persistent));
647 Test_Dispose_Job_Missing_Dependency(new NativeHashMap<int, int>(16, Allocator.Persistent));
648 Test_Dispose_Job_Missing_Dependency(new NativeHashSet<int>(16, Allocator.Persistent));
649 Test_Dispose_Job_Missing_Dependency(new NativeList<int>(16, Allocator.Persistent));
650 Test_Dispose_Job_Missing_Dependency(new NativeParallelHashMap<int, int>(16, Allocator.Persistent));
651 Test_Dispose_Job_Missing_Dependency(new NativeParallelHashSet<int>(16, Allocator.Persistent));
652 Test_Dispose_Job_Missing_Dependency(new NativeParallelMultiHashMap<int, int>(16, Allocator.Persistent));
653 Test_Dispose_Job_Missing_Dependency(new NativeQueue<int>(Allocator.Persistent));
654 Test_Dispose_Job_Missing_Dependency(new NativeReference<int>(16, Allocator.Persistent));
655 Test_Dispose_Job_Missing_Dependency(new NativeRingQueue<int>(16, Allocator.Persistent));
656 Test_Dispose_Job_Missing_Dependency(new NativeStream(16, Allocator.Persistent));
657 Test_Dispose_Job_Missing_Dependency(new NativeText(16, Allocator.Persistent));
658 }
659
660 //-------------------------------------------------------------------------------------------------------
661
662 void Test_Dispose_Job_Then_Schedule_Work<T>(T container)
663 where T : INativeDisposable
664 {
665 GenericContainerJob<T> job = new GenericContainerJob<T>() { data = container };
666 JobHandle jobHandle = container.Dispose(default);
667 Assert.Throws<InvalidOperationException>(() => job.Schedule(jobHandle));
668 jobHandle.Complete();
669 }
670
671 [Test]
672 [TestRequiresCollectionChecks("Tests job depending on a dispose job with same data - crashes without safety system")]
673 public void INativeDisposable_Dispose_Job_Then_Schedule_Work()
674 {
675 Test_Dispose_Job_Then_Schedule_Work(new NativeBitArray(16, Allocator.Persistent));
676 Test_Dispose_Job_Then_Schedule_Work(new NativeHashMap<int, int>(16, Allocator.Persistent));
677 Test_Dispose_Job_Then_Schedule_Work(new NativeHashSet<int>(16, Allocator.Persistent));
678 Test_Dispose_Job_Then_Schedule_Work(new NativeList<int>(16, Allocator.Persistent));
679 Test_Dispose_Job_Then_Schedule_Work(new NativeParallelHashMap<int, int>(16, Allocator.Persistent));
680 Test_Dispose_Job_Then_Schedule_Work(new NativeParallelHashSet<int>(16, Allocator.Persistent));
681 Test_Dispose_Job_Then_Schedule_Work(new NativeParallelMultiHashMap<int, int>(16, Allocator.Persistent));
682 Test_Dispose_Job_Then_Schedule_Work(new NativeQueue<int>(Allocator.Persistent));
683 Test_Dispose_Job_Then_Schedule_Work(new NativeReference<int>(16, Allocator.Persistent));
684 Test_Dispose_Job_Then_Schedule_Work(new NativeRingQueue<int>(16, Allocator.Persistent));
685 Test_Dispose_Job_Then_Schedule_Work(new NativeStream(16, Allocator.Persistent));
686 Test_Dispose_Job_Then_Schedule_Work(new NativeText(16, Allocator.Persistent));
687 }
688
689 //-------------------------------------------------------------------------------------------------------
690
691 // Avoid running this test when on older unity releases since those editor versions
692 // used a global safety handle for temp allocations which could lead to invalid safety errors
693 // if we were to perform the safety checks when writing the Length that this test validates
694 // (The test uses Persistent allocations, but the code in NativeList.Length is conditional on
695 // this define so we make the tests conditional as well)
696#if UNITY_2022_2_16F1_OR_NEWER
697 void Test_Change_Length_Missing_Dependency<T, U>(T container)
698 where T : unmanaged, IIndexable<U>
699 where U : unmanaged
700 {
701 int localLength = 0;
702 // Readonly Job
703 {
704 var job = new GenericContainerReadonlyJob<T>() { data = container };
705 var jobHandle = job.Schedule();
706 Assert.DoesNotThrow(() => localLength = container.Length); // Reading is safe
707 Assert.Throws<InvalidOperationException>(() => container.Length = 0); // Writing while a job is in flight it not safe
708 jobHandle.Complete();
709 Assert.DoesNotThrow(() => container.Length = 0);
710 }
711
712 // ReadWrite job
713 {
714 var job = new GenericContainerJob<T>() { data = container };
715 var jobHandle = job.Schedule();
716 Assert.Throws<InvalidOperationException>(() => localLength = container.Length); // Reading is not safe
717 Assert.Throws<InvalidOperationException>(() => container.Length = 0); // Writing while a job is in flight it not safe
718 jobHandle.Complete();
719 Assert.DoesNotThrow(() => localLength = container.Length);
720 Assert.DoesNotThrow(() => container.Length = 0);
721 }
722 }
723
724 [Test]
725 [TestRequiresCollectionChecks()]
726 public void IIndexable_Change_Length_Missing_Dependency()
727 {
728 var container = new NativeList<int>(16, Allocator.Persistent);
729 Test_Change_Length_Missing_Dependency<NativeList<int>, int>(container);
730 container.Dispose();
731 }
732#endif
733 //-------------------------------------------------------------------------------------------------------
734
735 struct NativeHashMapJobForEach : IJob
736 {
737 public NativeHashMap<int, int> input;
738 public void Execute()
739 {
740 foreach (var _ in input) { }
741 }
742 }
743
744 struct NativeHashMapJobForEachReadOnly : IJob
745 {
746 public NativeHashMap<int, int>.ReadOnly input;
747 public void Execute()
748 {
749 foreach (var _ in input) { }
750 }
751 }
752
753 struct NativeHashMapJobForEachEnumerator : IJob
754 {
755 [ReadOnly]
756 public NativeHashMap<int, int>.Enumerator input;
757
758 public void Execute()
759 {
760 while (input.MoveNext()) { }
761 }
762 }
763
764 [Test]
765 [TestRequiresCollectionChecks("Tests depend on safety system to catch incorrect use.")]
766 public void ForEach()
767 {
768 // CreateEmpty_NativeBitArray();
769
770 {
771 var container = CreateEmpty_NativeHashMap();
772 var ro = container.AsReadOnly();
773
774 GCAllocRecorder.ValidateNoGCAllocs(() =>
775 {
776 foreach (var item in container) { }
777 foreach (var item in ro) { }
778 new NativeHashMapJobForEach { input = container }.Run();
779 new NativeHashMapJobForEachReadOnly { input = ro }.Run();
780 new NativeHashMapJobForEachEnumerator { input = container.GetEnumerator() }.Run();
781 new NativeHashMapJobForEachEnumerator { input = ro.GetEnumerator() }.Run();
782 });
783
784 {
785 var job = new NativeHashMapJobForEach { input = container }.Schedule();
786 Assert.Throws<InvalidOperationException>(() => { container.Add(123, 456); });
787 job.Complete();
788 Assert.DoesNotThrow(() => container.Add(123, 456));
789 container.Clear();
790 }
791
792 {
793 var job = new NativeHashMapJobForEachReadOnly { input = ro }.Schedule();
794 Assert.Throws<InvalidOperationException>(() => { container.Add(123, 456); });
795 job.Complete();
796 Assert.DoesNotThrow(() => container.Add(123, 456));
797 container.Clear();
798 }
799
800 {
801 var job = new NativeHashMapJobForEachEnumerator { input = container.GetEnumerator() }.Schedule();
802 Assert.Throws<InvalidOperationException>(() => { container.Add(123, 456); });
803 job.Complete();
804 Assert.DoesNotThrow(() => container.Add(123, 456));
805 container.Clear();
806 }
807
808 {
809 var job = new NativeHashMapJobForEachEnumerator { input = ro.GetEnumerator() }.Schedule();
810 Assert.Throws<InvalidOperationException>(() => { container.Add(123, 456); });
811 job.Complete();
812 Assert.DoesNotThrow(() => container.Add(123, 456));
813 container.Clear();
814 }
815
816 {
817 var iter = container.GetEnumerator();
818 container.Add(123, 456);
819 Assert.Throws<ObjectDisposedException>(() => { while (iter.MoveNext()) { } });
820 Assert.DoesNotThrow(() => container.Remove(123));
821 Assert.AreEqual(0, container.Count);
822 }
823
824 {
825 var iter = container.AsReadOnly().GetEnumerator();
826 container.Add(123, 456);
827 Assert.Throws<ObjectDisposedException>(() => { while (iter.MoveNext()) { } });
828 Assert.DoesNotThrow(() => container.Remove(123));
829 Assert.AreEqual(0, container.Count);
830 }
831
832 container.Dispose();
833 }
834
835 {
836 var container = CreateEmpty_NativeHashSet();
837 var ro = container.AsReadOnly();
838
839 GCAllocRecorder.ValidateNoGCAllocs(() =>
840 {
841 foreach (var item in container) { }
842 foreach (var item in ro) { }
843 });
844
845 container.Dispose();
846 }
847
848 {
849 var container = CreateEmpty_NativeList();
850 var ro = container.AsReadOnly();
851
852 GCAllocRecorder.ValidateNoGCAllocs(() =>
853 {
854 foreach (var item in container) { }
855 foreach (var item in ro) { }
856 });
857
858 container.Dispose();
859 }
860
861 {
862 var container = CreateEmpty_NativeParallelHashMap();
863 var ro = container.AsReadOnly();
864
865 GCAllocRecorder.ValidateNoGCAllocs(() =>
866 {
867 foreach (var item in container) { }
868 foreach (var item in ro) { }
869 });
870
871 container.Dispose();
872 }
873
874 {
875 var container = CreateEmpty_NativeParallelHashSet();
876 var ro = container.AsReadOnly();
877
878 GCAllocRecorder.ValidateNoGCAllocs(() =>
879 {
880 foreach (var item in container) { }
881 foreach (var item in ro) { }
882 });
883
884 container.Dispose();
885 }
886
887 {
888 var container = CreateEmpty_NativeParallelMultiHashMap();
889 var ro = container.AsReadOnly();
890
891 GCAllocRecorder.ValidateNoGCAllocs(() =>
892 {
893 foreach (var item in container) { }
894 foreach (var item in ro) { }
895 });
896
897 container.Dispose();
898 }
899
900 {
901 var container = CreateEmpty_NativeQueue();
902 var ro = container.AsReadOnly();
903
904 GCAllocRecorder.ValidateNoGCAllocs(() =>
905 {
906// foreach (var item in container) { }
907 foreach (var item in ro) { }
908 });
909
910 container.Dispose();
911 }
912
913 // CreateEmpty_NativeReference();
914 // CreateEmpty_NativeRingQueue();
915 // CreateEmpty_NativeStream();
916
917 {
918 var container = CreateEmpty_NativeText();
919 var ro = container.AsReadOnly();
920
921 GCAllocRecorder.ValidateNoGCAllocs(() =>
922 {
923 foreach (var item in container) { }
924 foreach (var item in ro) { }
925 });
926
927 container.Dispose();
928 }
929
930 // CreateEmpty_UnsafeAppendBuffer();
931 // CreateEmpty_UnsafeBitArray
932
933 {
934 var container = CreateEmpty_UnsafeHashMap();
935 var ro = container.AsReadOnly();
936
937 GCAllocRecorder.ValidateNoGCAllocs(() =>
938 {
939 foreach (var item in container) { }
940 foreach (var item in ro) { }
941 });
942
943 container.Dispose();
944 }
945
946 {
947 var container = CreateEmpty_UnsafeHashSet();
948 var ro = container.AsReadOnly();
949
950 GCAllocRecorder.ValidateNoGCAllocs(() =>
951 {
952 foreach (var item in container) { }
953 foreach (var item in ro) { }
954 });
955
956 container.Dispose();
957 }
958
959 {
960 var container = CreateEmpty_UnsafeList();
961 var ro = container.AsReadOnly();
962
963 GCAllocRecorder.ValidateNoGCAllocs(() =>
964 {
965 foreach (var item in container) { }
966 foreach (var item in ro) { }
967 });
968
969 container.Dispose();
970 }
971
972 // CreateEmpty_UnsafePtrList(); - not possible to implement intefrace because container returns T*, and interface wants T as return value.
973
974 {
975 var container = CreateEmpty_UnsafeParallelHashMap();
976 var ro = container.AsReadOnly();
977
978 GCAllocRecorder.ValidateNoGCAllocs(() =>
979 {
980 foreach (var item in container) { }
981 foreach (var item in ro) { }
982 });
983
984 container.Dispose();
985 }
986
987 {
988 var container = CreateEmpty_UnsafeParallelHashSet();
989 var ro = container.AsReadOnly();
990
991 GCAllocRecorder.ValidateNoGCAllocs(() =>
992 {
993 foreach (var item in container) { }
994 foreach (var item in ro) { }
995 });
996
997 container.Dispose();
998 }
999
1000 {
1001 var container = CreateEmpty_UnsafeParallelMultiHashMap();
1002 var ro = container.AsReadOnly();
1003
1004 GCAllocRecorder.ValidateNoGCAllocs(() =>
1005 {
1006 foreach (var item in container) { }
1007 foreach (var item in ro) { }
1008 });
1009
1010 container.Dispose();
1011 }
1012
1013 {
1014 var container = CreateEmpty_UnsafeQueue();
1015 var ro = container.AsReadOnly();
1016
1017 GCAllocRecorder.ValidateNoGCAllocs(() =>
1018 {
1019// foreach (var item in container) { }
1020 foreach (var item in ro) { }
1021 });
1022
1023 container.Dispose();
1024 }
1025
1026 // CreateEmpty_UnsafeRingQueue
1027 // CreateEmpty_UnsafeStream
1028 // CreateEmpty_UnsafeText
1029 }
1030}