A game about forced loneliness, made by TACStudios
1using NUnit.Framework;
2using System;
3using System.Runtime.InteropServices;
4using Unity.Burst;
5using Unity.Collections;
6using Unity.Collections.LowLevel.Unsafe;
7using Unity.Collections.Tests;
8using Unity.Jobs;
9using Unity.Mathematics;
10using UnityEngine;
11using UnityEngine.TestTools;
12using System.Text.RegularExpressions;
13using Assert = FastAssert;
14
15internal class NativeBitArrayTests : CollectionsTestFixture
16{
17 [Test]
18 public void NativeBitArray_Init()
19 {
20 var container = new NativeBitArray(0, Allocator.Persistent, NativeArrayOptions.ClearMemory);
21 Assert.True(container.IsCreated);
22 Assert.True(container.IsEmpty);
23 Assert.DoesNotThrow(() => container.Dispose());
24 }
25
26 [Test]
27 public void NativeBitArray_Get_Set_Long()
28 {
29 var numBits = 256;
30
31 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
32
33 Assert.False(test.IsSet(123));
34 test.Set(123, true);
35 Assert.True(test.IsSet(123));
36
37 Assert.False(test.TestAll(0, numBits));
38 Assert.False(test.TestNone(0, numBits));
39 Assert.True(test.TestAny(0, numBits));
40 Assert.AreEqual(1, test.CountBits(0, numBits));
41
42 Assert.False(test.TestAll(0, 122));
43 Assert.True(test.TestNone(0, 122));
44 Assert.False(test.TestAny(0, 122));
45
46 test.Clear();
47 Assert.False(test.IsSet(123));
48 Assert.AreEqual(0, test.CountBits(0, numBits));
49
50 test.SetBits(40, true, 4);
51 Assert.AreEqual(4, test.CountBits(0, numBits));
52
53 test.SetBits(0, true, numBits);
54 Assert.False(test.TestNone(0, numBits));
55 Assert.True(test.TestAll(0, numBits));
56
57 test.SetBits(0, false, numBits);
58 Assert.True(test.TestNone(0, numBits));
59 Assert.False(test.TestAll(0, numBits));
60
61 test.SetBits(123, true, 7);
62 Assert.True(test.TestAll(123, 7));
63
64 test.Clear();
65 test.SetBits(64, true, 64);
66 Assert.AreEqual(false, test.IsSet(63));
67 Assert.AreEqual(true, test.TestAll(64, 64));
68 Assert.AreEqual(false, test.IsSet(128));
69 Assert.AreEqual(64, test.CountBits(64, 64));
70 Assert.AreEqual(64, test.CountBits(0, numBits));
71
72 test.Clear();
73 test.SetBits(65, true, 62);
74 Assert.AreEqual(false, test.IsSet(64));
75 Assert.AreEqual(true, test.TestAll(65, 62));
76 Assert.AreEqual(false, test.IsSet(127));
77 Assert.AreEqual(62, test.CountBits(64, 64));
78 Assert.AreEqual(62, test.CountBits(0, numBits));
79
80 test.Clear();
81 test.SetBits(66, true, 64);
82 Assert.AreEqual(false, test.IsSet(65));
83 Assert.AreEqual(true, test.TestAll(66, 64));
84 Assert.AreEqual(false, test.IsSet(130));
85 Assert.AreEqual(64, test.CountBits(66, 64));
86 Assert.AreEqual(64, test.CountBits(0, numBits));
87
88 test.Dispose();
89 }
90
91 [Test]
92 public void NativeBitArray_Get_Set_Short()
93 {
94 var numBits = 31;
95
96 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
97
98 Assert.False(test.IsSet(13));
99 test.Set(13, true);
100 Assert.True(test.IsSet(13));
101
102 Assert.False(test.TestAll(0, numBits));
103 Assert.False(test.TestNone(0, numBits));
104 Assert.True(test.TestAny(0, numBits));
105 Assert.AreEqual(1, test.CountBits(0, numBits));
106
107 Assert.False(test.TestAll(0, 12));
108 Assert.True(test.TestNone(0, 12));
109 Assert.False(test.TestAny(0, 12));
110
111 test.Clear();
112 Assert.False(test.IsSet(13));
113 Assert.AreEqual(0, test.CountBits(0, numBits));
114
115 test.SetBits(4, true, 4);
116 Assert.AreEqual(4, test.CountBits(0, numBits));
117
118 test.SetBits(0, true, numBits);
119 Assert.False(test.TestNone(0, numBits));
120 Assert.True(test.TestAll(0, numBits));
121
122 test.SetBits(0, false, numBits);
123 Assert.True(test.TestNone(0, numBits));
124 Assert.False(test.TestAll(0, numBits));
125
126 test.SetBits(13, true, 7);
127 Assert.True(test.TestAll(13, 7));
128
129 test.Clear();
130 test.SetBits(4, true, 4);
131 Assert.AreEqual(false, test.IsSet(3));
132 Assert.AreEqual(true, test.TestAll(4, 4));
133 Assert.AreEqual(false, test.IsSet(18));
134 Assert.AreEqual(4, test.CountBits(4, 4));
135 Assert.AreEqual(4, test.CountBits(0, numBits));
136
137 test.Clear();
138 test.SetBits(5, true, 2);
139 Assert.AreEqual(false, test.IsSet(4));
140 Assert.AreEqual(true, test.TestAll(5, 2));
141 Assert.AreEqual(false, test.IsSet(17));
142 Assert.AreEqual(2, test.CountBits(4, 4));
143 Assert.AreEqual(2, test.CountBits(0, numBits));
144
145 test.Clear();
146 test.SetBits(6, true, 4);
147 Assert.AreEqual(false, test.IsSet(5));
148 Assert.AreEqual(true, test.TestAll(6, 4));
149 Assert.AreEqual(false, test.IsSet(10));
150 Assert.AreEqual(4, test.CountBits(6, 4));
151 Assert.AreEqual(4, test.CountBits(0, numBits));
152
153 test.Dispose();
154 }
155
156 [Test]
157 public void NativeBitArray_Get_Set_Tiny()
158 {
159 var numBits = 7;
160
161 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
162
163 Assert.False(test.IsSet(3));
164 test.Set(3, true);
165 Assert.True(test.IsSet(3));
166
167 Assert.False(test.TestAll(0, numBits));
168 Assert.False(test.TestNone(0, numBits));
169 Assert.True(test.TestAny(0, numBits));
170 Assert.AreEqual(1, test.CountBits(0, numBits));
171
172 Assert.False(test.TestAll(0, 2));
173 Assert.True(test.TestNone(0, 2));
174 Assert.False(test.TestAny(0, 2));
175
176 test.Clear();
177 Assert.False(test.IsSet(3));
178 Assert.AreEqual(0, test.CountBits(0, numBits));
179
180 test.SetBits(3, true, 4);
181 Assert.AreEqual(4, test.CountBits(0, numBits));
182
183 test.SetBits(0, true, numBits);
184 Assert.False(test.TestNone(0, numBits));
185 Assert.True(test.TestAll(0, numBits));
186
187 test.SetBits(0, false, numBits);
188 Assert.True(test.TestNone(0, numBits));
189 Assert.False(test.TestAll(0, numBits));
190
191 test.Dispose();
192 }
193
194 [Test]
195 [TestRequiresDotsDebugOrCollectionChecks]
196 public unsafe void NativeBitArray_Throws()
197 {
198 var numBits = 256;
199
200 Assert.Throws<ArgumentException>(() => { new NativeBitArray(numBits, Allocator.None); });
201
202 using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
203 {
204 Assert.DoesNotThrow(() => { test.TestAll(0, numBits); });
205 Assert.DoesNotThrow(() => { test.TestAny(numBits - 1, numBits); });
206
207 Assert.Throws<ArgumentException>(() => { test.IsSet(-1); });
208 Assert.Throws<ArgumentException>(() => { test.IsSet(numBits); });
209 Assert.Throws<ArgumentException>(() => { test.TestAny(0, 0); });
210 Assert.Throws<ArgumentException>(() => { test.TestAny(numBits, 1); });
211 Assert.Throws<ArgumentException>(() => { test.TestAny(numBits - 1, 0); });
212
213 // GetBits numBits must be 1-64.
214 Assert.Throws<ArgumentException>(() => { test.GetBits(0, 0); });
215 Assert.Throws<ArgumentException>(() => { test.GetBits(0, 65); });
216 Assert.DoesNotThrow(() => { test.GetBits(63, 2); });
217 }
218 }
219
220 void GetBitsTest(ref NativeBitArray test, int pos, int numBits)
221 {
222 test.SetBits(pos, true, numBits);
223 Assert.AreEqual(numBits, test.CountBits(0, test.Length));
224 Assert.AreEqual(0xfffffffffffffffful >> (64 - numBits), test.GetBits(pos, numBits));
225 test.Clear();
226 }
227
228 [Test]
229 public void NativeBitArray_GetBits()
230 {
231 var numBits = 256;
232
233 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
234
235 GetBitsTest(ref test, 0, 5);
236 GetBitsTest(ref test, 1, 3);
237 GetBitsTest(ref test, 0, 63);
238 GetBitsTest(ref test, 0, 64);
239 GetBitsTest(ref test, 1, 63);
240 GetBitsTest(ref test, 1, 64);
241 GetBitsTest(ref test, 62, 5);
242 GetBitsTest(ref test, 127, 3);
243 GetBitsTest(ref test, 250, 6);
244 GetBitsTest(ref test, 254, 2);
245
246 test.Dispose();
247 }
248
249 static void SetBitsTest(ref NativeBitArray test, int pos, ulong value, int numBits)
250 {
251 test.SetBits(pos, value, numBits);
252 if (value != test.GetBits(pos, numBits))
253 throw new Exception("Assert.Equals(value, test.GetBits(pos, numBits)) failed");
254 test.Clear();
255 }
256
257 [Test]
258 public void NativeBitArray_SetBits()
259 {
260 var numBits = 256;
261
262 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
263
264 SetBitsTest(ref test, 0, 16, 5);
265 SetBitsTest(ref test, 1, 7, 3);
266 SetBitsTest(ref test, 1, 32, 64);
267 SetBitsTest(ref test, 62, 6, 5);
268 SetBitsTest(ref test, 127, 1, 3);
269 SetBitsTest(ref test, 60, 0xaa, 8);
270
271 test.Dispose();
272 }
273
274 static void CopyBitsTest(ref NativeBitArray test, int dstPos, int srcPos, int numBits)
275 {
276 for (int pos = 0; pos < test.Length; pos += 64)
277 {
278 test.SetBits(pos, 0xaaaaaaaaaaaaaaaaul, 64);
279 }
280
281 test.SetBits(srcPos, true, numBits);
282 test.Copy(dstPos, srcPos, numBits);
283 Assert.AreEqual(true, test.TestAll(dstPos, numBits));
284
285 for (int pos = 0; pos < test.Length; ++pos)
286 {
287 if ((pos >= dstPos && pos < dstPos + numBits) ||
288 (pos >= srcPos && pos < srcPos + numBits))
289 {
290 Assert.AreEqual(true, test.IsSet(pos));
291 }
292 else
293 {
294 Assert.AreEqual((0 != (pos & 1)), test.IsSet(pos));
295 }
296 }
297
298 test.Clear();
299 }
300
301 static void CopyBitsTests(ref NativeBitArray test)
302 {
303 CopyBitsTest(ref test, 1, 16, 12); // short up to 64-bits copy
304 CopyBitsTest(ref test, 1, 80, 63); // short up to 64-bits copy
305 CopyBitsTest(ref test, 1, 11, 12); // short up to 64-bits copy overlapped
306 CopyBitsTest(ref test, 11, 1, 12); // short up to 64-bits copy overlapped
307
308 CopyBitsTest(ref test, 1, 16, 76); // short up to 128-bits copy
309 CopyBitsTest(ref test, 1, 80, 127); // short up to 128-bits copy
310 CopyBitsTest(ref test, 1, 11, 76); // short up to 128-bits copy overlapped
311 CopyBitsTest(ref test, 11, 1, 76); // short up to 128-bits copy overlapped
312
313 CopyBitsTest(ref test, 1, 81, 255); // long copy aligned
314 CopyBitsTest(ref test, 8, 0, 255); // long copy overlapped aligned
315 CopyBitsTest(ref test, 1, 80, 255); // long copy unaligned
316 CopyBitsTest(ref test, 80, 1, 255); // long copy overlapped unaligned
317 }
318
319 [Test]
320 public void NativeBitArray_Copy()
321 {
322 var numBits = 512;
323
324 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
325 CopyBitsTests(ref test);
326
327 test.Dispose();
328 }
329
330 [Test]
331 public void UnsafeBitArray_Resize()
332 {
333 var test = new NativeBitArray(1, Allocator.Persistent, NativeArrayOptions.ClearMemory);
334 Assert.AreEqual(1, test.Length);
335 Assert.AreEqual(64, test.Capacity);
336
337 test.SetCapacity(200); // expand
338 Assert.AreEqual(1, test.Length);
339 Assert.AreEqual(256, test.Capacity);
340
341 test.Resize(100, NativeArrayOptions.ClearMemory);
342 Assert.True(test.TestNone(0, test.Length));
343
344 // prepare survival test
345 test.Set(0, true);
346 test.Set(99, true);
347 Assert.True(test.IsSet(0));
348 Assert.True(test.TestNone(1, 98));
349 Assert.True(test.IsSet(99));
350
351 test.SetCapacity(1000); // expand
352 Assert.AreEqual(100, test.Length);
353 Assert.AreEqual(1024, test.Capacity);
354
355 // test resize survival
356 Assert.True(test.IsSet(0));
357 Assert.True(test.TestNone(1, 98));
358 Assert.True(test.IsSet(99));
359
360 // manual clear
361 test.Resize(1);
362 test.Set(0, false);
363
364 test.SetCapacity(200); // truncate capacity
365 Assert.AreEqual(1, test.Length);
366 Assert.AreEqual(256, test.Capacity);
367
368 test.Resize(512, NativeArrayOptions.ClearMemory); // resize
369 Assert.AreEqual(512, test.Length);
370 Assert.AreEqual(512, test.Capacity);
371 Assert.True(test.TestNone(0, test.Length));
372
373 CopyBitsTests(ref test);
374
375 test.Resize(256); // truncate length
376 Assert.AreEqual(256, test.Length);
377 Assert.AreEqual(512, test.Capacity);
378
379 test.TrimExcess();
380 Assert.AreEqual(256, test.Length);
381 Assert.AreEqual(256, test.Capacity);
382
383 test.Dispose();
384 }
385
386 [Test]
387 public unsafe void NativeBitArray_CopyBetweenBitArrays()
388 {
389 var numBits = 512;
390
391 var str = new FixedString128Bytes("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ");
392
393 var test0 = NativeBitArrayUnsafeUtility.ConvertExistingDataToNativeBitArray(&str.bytes.offset0000, 64, Allocator.None);
394#if ENABLE_UNITY_COLLECTIONS_CHECKS
395 AtomicSafetyHandle ash = CollectionHelper.CreateSafetyHandle(Allocator.Temp);
396 NativeBitArrayUnsafeUtility.SetAtomicSafetyHandle(ref test0, ash);
397#endif
398
399 var test1 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
400 var test2 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
401
402 for (int pos = 0; pos < test0.Length; pos += 64)
403 {
404 test1.SetBits(pos, 0x5555555555555555ul, 64);
405 test2.SetBits(pos, 0xaaaaaaaaaaaaaaaaul, 64);
406 }
407
408 test1.Copy(1, ref test0, 205, 211);
409 test1.Copy(214, ref test0, 0, 205);
410
411 test2.Copy(205, ref test1, 1, 211);
412 test2.Copy(0, ref test1, 214, 205);
413
414 test0.Copy(0, ref test2, 0, 512);
415
416 Assert.AreEqual(str, "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ");
417
418 test0.Dispose();
419 test1.Dispose();
420 test2.Dispose();
421 }
422
423 [Test]
424 [TestRequiresDotsDebugOrCollectionChecks]
425 public unsafe void NativeBitArray_Copy_Throws()
426 {
427 var numBits = 512;
428
429 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
430
431 Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, 0, numBits - 1, 16); }); // short up to 64-bits copy out of bounds
432 Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, numBits - 1, 0, 16); }); // short up to 64-bits copy out of bounds
433
434 Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, 0, numBits - 1, 80); }); // short up to 128-bits copy out of bounds
435 Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, numBits - 1, 0, 80); }); // short up to 128-bits copy out of bounds
436
437 Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, 1, numBits - 7, 127); }); // long copy aligned
438 Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, numBits - 7, 1, 127); }); // long copy aligned
439
440 Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, 2, numBits - 1, 127); }); // long copy unaligned
441 Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, numBits - 1, 2, 127); }); // long copy unaligned
442
443 test.Dispose();
444 }
445
446 [Test]
447 public unsafe void NativeBitArray_Find()
448 {
449 var numBits = 512;
450
451 using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
452 {
453 test.SetBits(0, true, 11);
454
455 for (var i = 0; i < 256; ++i)
456 {
457 Assert.AreEqual(11, test.Find(0, i + 1));
458 }
459
460 for (var j = 0; j < 64; ++j)
461 {
462 for (var i = 0; i < 256; ++i)
463 {
464 var numBitsToFind = 7 + i;
465 var pos = 37 + j;
466
467 test.SetBits(0, true, test.Length);
468 test.SetBits(pos, false, numBitsToFind);
469
470 Assert.AreEqual(pos, test.Find(0, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
471 Assert.AreEqual(pos, test.Find(pos, numBitsToFind)); //, $"{j}/{i}:pos {pos}, numBitsToFind {numBitsToFind}");
472
473 Assert.AreEqual(pos, test.Find(0, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
474 Assert.AreEqual(pos, test.Find(pos, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
475
476 Assert.IsTrue(test.TestNone(test.Find(0, numBitsToFind), numBitsToFind));
477
478 Assert.AreEqual(int.MaxValue, test.Find(pos + 1, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
479 }
480 }
481 }
482 }
483
484 [Test]
485 public unsafe void NativeBitArray_Find_With_Begin_End()
486 {
487 var numBits = 512;
488
489 using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
490 {
491 Assert.AreEqual(0, test.Find(0, 2, 1));
492 Assert.AreEqual(1, test.Find(1, 2, 1));
493 test.SetBits(0, true, 6);
494 Assert.AreEqual(int.MaxValue, test.Find(0, 2, 1));
495
496 for (var j = 0; j < 64; ++j)
497 {
498 for (var i = 0; i < 256; ++i)
499 {
500 var numBitsToFind = 7 + i;
501 var padding = 11;
502 var begin = 37 + j;
503 var end = begin + padding + numBitsToFind;
504 var count = end - begin;
505
506 test.Clear();
507 test.SetBits(begin, true, count);
508 test.SetBits(begin + padding + 1, false, numBitsToFind - 1);
509
510 Assert.AreEqual(begin + padding + 1, test.Find(begin, count, numBitsToFind - 1)); //, $"{j}/{i}: begin {begin}, end {end}, count {count}, numBitsToFind {numBitsToFind}");
511 Assert.AreEqual(int.MaxValue, test.Find(begin, count, numBitsToFind)); //, $"{j}/{i}: begin {begin}, end {end}, count {count}, numBitsToFind {numBitsToFind}");
512 }
513 }
514 }
515 }
516
517 [Test]
518 [TestRequiresDotsDebugOrCollectionChecks]
519 public unsafe void NativeBitArray_Find_Throws()
520 {
521 var numBits = 512;
522
523 using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
524 {
525 Assert.Throws<ArgumentException>(() => { test.Find(0, 0, 1); }); // empty range
526 Assert.Throws<ArgumentException>(() => { test.Find(0, 1, 0); }); // zero bits
527 Assert.Throws<ArgumentException>(() => { test.Find(0, 1, 2); }); // numBits is larger than range
528 Assert.Throws<ArgumentException>(() => { test.Find(10, 0, 0); }); // empty range, numBits is less than 1
529 Assert.Throws<ArgumentException>(() => { test.Find(1, 10, -2); }); // numBits can't be negative
530 }
531 }
532
533 [Test]
534 public void NativeBitArray_AsNativeArray_Byte()
535 {
536 var numBits = 64;
537
538 var test0 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
539 var test1 = test0.AsNativeArray<byte>();
540 Assert.AreEqual(numBits / 8, test1.Length);
541
542 test1[0] = 0x10;
543 test1[1] = 0x32;
544 test1[2] = 0x54;
545 test1[3] = 0x76;
546 test1[4] = 0x98;
547 test1[5] = 0xba;
548 test1[6] = 0xdc;
549 test1[7] = 0xfe;
550
551 for (var i = 0; i < 16; ++i)
552 {
553 NUnit.Framework.Assert.AreEqual(i, test0.GetBits(i * 4, 4));
554 }
555
556 test1.Dispose();
557 test0.Dispose();
558 }
559
560 [Test]
561 public void NativeBitArray_AsNativeArray_Uint()
562 {
563 var numBits = 64;
564
565 var test0 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
566 var test1 = test0.AsNativeArray<uint>();
567 Assert.AreEqual(numBits / 32, test1.Length);
568
569 test1[0] = 0x76543210;
570 test1[1] = 0xfedcba98;
571
572 for (var i = 0; i < 16; ++i)
573 {
574 NUnit.Framework.Assert.AreEqual(i, test0.GetBits(i * 4, 4));
575 }
576
577 test1.Dispose();
578 test0.Dispose();
579 }
580
581 [Test]
582 public void NativeBitArray_AsNativeArray_Ulong()
583 {
584 var numBits = 64;
585
586 var test0 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
587 var test1 = test0.AsNativeArray<ulong>();
588 Assert.AreEqual(numBits / 64, test1.Length);
589
590 test1[0] = 0xfedcba9876543210;
591
592 for (var i = 0; i < 16; ++i)
593 {
594 NUnit.Framework.Assert.AreEqual(i, test0.GetBits(i * 4, 4));
595 }
596
597 test1.Dispose();
598 test0.Dispose();
599 }
600
601 [StructLayout(LayoutKind.Explicit, Size = 16)]
602 internal struct SizeMismatch128
603 {
604 }
605
606 [StructLayout(LayoutKind.Explicit, Size=7)]
607 internal struct SizeMismatch56
608 {
609 }
610
611 [Test]
612 [TestRequiresDotsDebugOrCollectionChecks]
613 public void NativeBitArray_AsNativeArray_ThrowsOnSizeMismatch()
614 {
615 var numBits = 64;
616
617 var test0 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
618
619 Assert.Throws<InvalidOperationException>(() => { test0.AsNativeArray<SizeMismatch128>(); });
620 Assert.Throws<InvalidOperationException>(() => { test0.AsNativeArray<SizeMismatch56>(); });
621
622 test0.Dispose();
623 }
624
625 // Burst error BC1071: Unsupported assert type
626 // [BurstCompile(CompileSynchronously = true)]
627 struct NativeBitArrayTestReadOnly : IJob
628 {
629 public NativeBitArray.ReadOnly reader;
630
631 public void Execute()
632 {
633 var rd = reader;
634 Assert.True(reader.IsSet(7));
635 Assert.AreEqual(1, reader.CountBits(0, reader.Length));
636 }
637 }
638
639 [Test]
640 [TestRequiresCollectionChecks]
641 public void NativeBitArray_ReadOnly()
642 {
643 var numBits = 256;
644
645 var reader = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
646 reader.Set(7, true);
647
648 var readerJob = new NativeBitArrayTestReadOnly { reader = reader.AsReadOnly() }.Schedule();
649
650 var from = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
651 Assert.Throws<InvalidOperationException>(() => { reader.Copy(7, ref from, 30, 10); } /* attempt to write into reader after job is scheduled */);
652 from.Dispose();
653
654 reader.Dispose(readerJob);
655 readerJob.Complete();
656 }
657
658 [Test]
659 [TestRequiresCollectionChecks]
660 public void NativeBitArray_UseAfterFree_UsesCustomOwnerTypeName()
661 {
662 var numBits = 256;
663
664 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
665 SetBitsTest(ref test, 0, 16, 5);
666 test.Dispose();
667 NUnit.Framework.Assert.That(() => test.IsSet(0),
668 Throws.Exception.TypeOf<ObjectDisposedException>()
669 .With.Message.Contains($"The {test.GetType()} has been deallocated"));
670 }
671
672 [Test]
673 [TestRequiresCollectionChecks]
674 public void NativeBitArray_AtomicSafetyHandle_AllocatorTemp_UniqueStaticSafetyIds()
675 {
676 var numBits = 256;
677
678 var test = new NativeBitArray(numBits, Allocator.Temp, NativeArrayOptions.ClearMemory);
679
680 // All collections that use Allocator.Temp share the same core AtomicSafetyHandle.
681 // This test verifies that containers can proceed to assign unique static safety IDs to each
682 // AtomicSafetyHandle value, which will not be shared by other containers using Allocator.Temp.
683 var test0 = new NativeBitArray(numBits, Allocator.Temp, NativeArrayOptions.ClearMemory);
684 var test1 = new NativeBitArray(numBits, Allocator.Temp, NativeArrayOptions.ClearMemory);
685 SetBitsTest(ref test0, 0, 16, 5);
686 test0.Dispose();
687
688 NUnit.Framework.Assert.That(() => test0.IsSet(0),
689 Throws.Exception.With.TypeOf<ObjectDisposedException>()
690 .With.Message.Contains($"The {test0.GetType()} has been deallocated"));
691 SetBitsTest(ref test1, 0, 16, 5);
692 test1.Dispose();
693 NUnit.Framework.Assert.That(() => test1.IsSet(0),
694 Throws.Exception.With.TypeOf<ObjectDisposedException>()
695 .With.Message.Contains($"The {test1.GetType()} has been deallocated"));
696 }
697
698 [BurstCompile(CompileSynchronously = true)]
699 struct NativeBitArrayCreateAndUseAfterFreeBurst : IJob
700 {
701 public void Execute()
702 {
703 var numBits = 256;
704
705 var test = new NativeBitArray(numBits, Allocator.Temp, NativeArrayOptions.ClearMemory);
706 SetBitsTest(ref test, 0, 16, 5);
707 test.Dispose();
708
709 SetBitsTest(ref test, 0, 16, 5);
710 }
711 }
712
713 [Test]
714 [TestRequiresCollectionChecks]
715 public void NativeBitArray_CreateAndUseAfterFreeInBurstJob_UsesCustomOwnerTypeName()
716 {
717 // Make sure this isn't the first container of this type ever created, so that valid static safety data exists
718 var numBits = 256;
719
720 var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
721 test.Dispose();
722
723 var job = new NativeBitArrayCreateAndUseAfterFreeBurst
724 {
725 };
726
727 // Two things:
728 // 1. This exception is logged, not thrown; thus, we use LogAssert to detect it.
729 // 2. Calling write operation after container.Dispose() emits an unintuitive error message. For now, all this test cares about is whether it contains the
730 // expected type name.
731 job.Run();
732 LogAssert.Expect(LogType.Exception,
733 new Regex($"InvalidOperationException: The {Regex.Escape(test.GetType().ToString())} has been declared as \\[ReadOnly\\] in the job, but you are writing to it"));
734 }
735 void findWithPattern(ref NativeBitArray test, byte pattern, int numBits)
736 {
737 for (int pos = 0; pos < test.Length; pos += 8)
738 {
739 test.SetBits(pos, pattern, 8);
740 }
741
742 var bitCount = math.countbits((int)pattern);
743 var numEmptyBits = test.Length - (test.Length / 8 * bitCount);
744
745 for (int i = 0; i < numEmptyBits; i += numBits)
746 {
747 var pos = test.Find(0, numBits);
748 Assert.AreNotEqual(int.MaxValue, pos, $"{i}");
749 test.SetBits(pos, true, numBits);
750 }
751
752 Assert.True(test.TestAll(0, test.Length));
753 }
754
755 [Test]
756 public void NativeBitArray_FindWithPattern()
757 {
758 var test = new NativeBitArray(512, Allocator.Persistent, NativeArrayOptions.ClearMemory);
759
760 // Separated test for some more interesting patterns
761 findWithPattern(ref test, 0x81, 1);
762 findWithPattern(ref test, 0x81, 2);
763 findWithPattern(ref test, 0x81, 3);
764 findWithPattern(ref test, 0x81, 6);
765 findWithPattern(ref test, 0x88, 3);
766 findWithPattern(ref test, 0x99, 2);
767 findWithPattern(ref test, 0xaa, 1);
768 findWithPattern(ref test, 0xc3, 1);
769 findWithPattern(ref test, 0xc3, 2);
770 findWithPattern(ref test, 0xc3, 4);
771 findWithPattern(ref test, 0xe7, 1);
772 findWithPattern(ref test, 0xe7, 2);
773
774 // Test all patterns
775 for (int i = 0; i < 256; i++)
776 {
777 findWithPattern(ref test, (byte)i, 1);
778 }
779
780 test.Dispose();
781 }
782
783 [Test]
784 public void NativeBitArray_FindInTinyBitArray()
785 {
786 var test = new NativeBitArray(3, Allocator.Persistent, NativeArrayOptions.ClearMemory);
787 Assert.AreEqual(3, test.Length);
788
789 test.SetBits(0, 0x55, test.Length);
790
791 Assert.AreEqual(1, test.Find(0, 1));
792 Assert.AreEqual(1, test.Find(0, test.Length, 1));
793 test.SetBits(1, true, 1);
794 Assert.True(test.TestAll(0, test.Length));
795 Assert.AreEqual(int.MaxValue, test.Find(0, test.Length, 1));
796
797 test.Dispose();
798 }
799
800 [Test]
801 public void NativeBitArray_FindLastUnsetBit([NUnit.Framework.Range(1, 64)] int numBits)
802 {
803 using (var bits = new NativeBitArray(numBits, Allocator.Persistent))
804 {
805 // Set all bits to one then unset a single bit to find.
806 for (int i = 0; i < numBits; ++i)
807 {
808 bits.SetBits(0, true, numBits);
809 bits.Set(i, false);
810 Assert.AreEqual(i, bits.Find(0, 1));
811 }
812 }
813 }
814
815 [Test]
816 public void NativeBitArray_CustomAllocatorTest()
817 {
818 AllocatorManager.Initialize();
819 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
820 allocatorHelper.Allocator.Initialize();
821 using (var bitset = new NativeBitArray(1, allocatorHelper.Allocator.Handle))
822 {
823 }
824
825 Assert.IsTrue(allocatorHelper.Allocator.WasUsed);
826 allocatorHelper.Allocator.Dispose();
827 allocatorHelper.Dispose();
828 AllocatorManager.Shutdown();
829 }
830
831 [BurstCompile]
832 struct BurstedCustomAllocatorJob : IJob
833 {
834 [NativeDisableUnsafePtrRestriction]
835 public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
836
837 public void Execute()
838 {
839 unsafe
840 {
841 using (var container = new NativeBitArray(1, Allocator->Handle))
842 {
843 }
844 }
845 }
846 }
847
848 [Test]
849 public unsafe void NativeBitArray_BurstedCustomAllocatorTest()
850 {
851 AllocatorManager.Initialize();
852 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
853 ref var allocator = ref allocatorHelper.Allocator;
854 allocatorHelper.Allocator.Initialize();
855
856 var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
857 unsafe
858 {
859 var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
860 handle.Complete();
861 }
862
863 Assert.IsTrue(allocator.WasUsed);
864 allocator.Dispose();
865 allocatorHelper.Dispose();
866 AllocatorManager.Shutdown();
867 }
868}