A game about forced loneliness, made by TACStudios
at master 558 lines 16 kB view raw
1using System; 2using NUnit.Framework; 3using Unity.Burst; 4using Unity.Collections; 5using Unity.Collections.LowLevel.Unsafe; 6using Unity.Collections.NotBurstCompatible; 7using Unity.Jobs; 8using Unity.Collections.Tests; 9 10internal class NativeHashSetTests: CollectionsTestFixture 11{ 12 static void ExpectedCount<T>(ref NativeHashSet<T> container, int expected) 13 where T : unmanaged, IEquatable<T> 14 { 15 Assert.AreEqual(expected == 0, container.IsEmpty); 16 Assert.AreEqual(expected, container.Count); 17 } 18 19 [Test] 20 public void NativeHashSet_IsEmpty() 21 { 22 var container = new NativeHashSet<int>(0, Allocator.Persistent); 23 Assert.IsTrue(container.IsEmpty); 24 25 Assert.IsTrue(container.Add(0)); 26 Assert.IsFalse(container.IsEmpty); 27 Assert.AreNotEqual(0, container.Capacity); 28 ExpectedCount(ref container, 1); 29 30 container.Remove(0); 31 Assert.IsTrue(container.IsEmpty); 32 33 Assert.IsTrue(container.Add(0)); 34 container.Clear(); 35 Assert.IsTrue(container.IsEmpty); 36 37 container.Dispose(); 38 } 39 40 [Test] 41 public void NativeHashSet_Capacity() 42 { 43 var container = new NativeHashSet<int>(0, Allocator.Persistent); 44 Assert.IsTrue(container.IsEmpty); 45 46 container.Capacity = 10; 47 Assert.AreNotEqual(0, container.Capacity); 48 49 container.Dispose(); 50 } 51 52 [Test] 53 public void NativeHashSet_CapacityAtLeastCount() 54 { 55 var container = new NativeHashSet<int>(0, Allocator.Persistent); 56 57 for (int i = 0; i < 300; i++) 58 container.Add(i); 59 60 container.Capacity = 3; 61 Assert.IsTrue(container.Capacity >= container.Count); 62 63 container.Dispose(); 64 } 65 66 [Test] 67 public void NativeHashSet_RemoveOnEmptyMap_DoesNotThrow() 68 { 69 var container = new NativeHashSet<int>(0, Allocator.Temp); 70 Assert.DoesNotThrow(() => container.Remove(0)); 71 Assert.DoesNotThrow(() => container.Remove(-425196)); 72 container.Dispose(); 73 } 74 75 [Test] 76 public void NativeHashSet_Collisions() 77 { 78 var container = new NativeHashSet<int>(16, Allocator.Temp); 79 80 Assert.IsFalse(container.Contains(0), "Contains on empty hash map did not fail"); 81 ExpectedCount(ref container, 0); 82 83 // Make sure inserting values work 84 for (int i = 0; i < 8; ++i) 85 { 86 Assert.IsTrue(container.Add(i), "Failed to add value"); 87 } 88 ExpectedCount(ref container, 8); 89 90 // The bucket size is capacity * 2, adding that number should result in hash collisions 91 for (int i = 0; i < 8; ++i) 92 { 93 Assert.IsTrue(container.Add(i + 32), "Failed to add value with potential hash collision"); 94 } 95 96 // Make sure reading the inserted values work 97 for (int i = 0; i < 8; ++i) 98 { 99 Assert.IsTrue(container.Contains(i), "Failed get value from hash set"); 100 } 101 102 for (int i = 0; i < 8; ++i) 103 { 104 Assert.IsTrue(container.Contains(i + 32), "Failed get value from hash set"); 105 } 106 107 container.Dispose(); 108 } 109 110 [Test] 111 public void NativeHashSet_SameElement() 112 { 113 using (var container = new NativeHashSet<int>(0, Allocator.Persistent)) 114 { 115 Assert.IsTrue(container.Add(0)); 116 Assert.IsFalse(container.Add(0)); 117 } 118 } 119 120 [Test] 121 public void NativeHashSet_CanBeReadFromJob() 122 { 123 using (var hashSet = new NativeHashSet<int>(1, CommonRwdAllocator.Handle)) 124 using (var result = new NativeReference<int>(CommonRwdAllocator.Handle)) 125 { 126 hashSet.Add(42); 127 new ReadHashSetJob 128 { 129 Input = hashSet.AsReadOnly(), 130 Output = result, 131 }.Run(); 132 Assert.AreEqual(42, result.Value); 133 } 134 } 135 136 struct TempHashSet : IJob 137 { 138 public void Execute() 139 { 140 using (var stringList = new NativeList<FixedString32Bytes>(10, Allocator.Persistent) { "Hello", ",", "World", "!" }) 141 { 142 var container = new NativeHashSet<FixedString128Bytes>(50, Allocator.Temp); 143 var seen = new NativeArray<int>(stringList.Length, Allocator.Temp); 144 foreach (var str in stringList) 145 { 146 container.Add(str); 147 } 148 149 foreach (var value in container) 150 { 151 int index = stringList.IndexOf(value); 152 Assert.AreEqual(stringList[index], value.ToString()); 153 seen[index] = seen[index] + 1; 154 } 155 156 for (int i = 0; i < stringList.Length; i++) 157 { 158 Assert.AreEqual(1, seen[i], $"Incorrect value count {stringList[i]}"); 159 } 160 } 161 } 162 } 163 164 [Test] 165 public void NativeHashSet_TempHashSetInJob() 166 { 167 new TempHashSet { }.Schedule().Complete(); 168 } 169 170 struct ReadHashSetJob : IJob 171 { 172 [ReadOnly] 173 public NativeHashSet<int>.ReadOnly Input; 174 175 public NativeReference<int> Output; 176 public void Execute() 177 { 178 Output.Value = Input.ToNativeArray(Allocator.Temp)[0]; 179 180 foreach (var value in Input) 181 { 182 Assert.AreEqual(42, value); 183 } 184 } 185 } 186 187 [Test] 188 public void NativeHashSet_ForEach_FixedStringInHashMap() 189 { 190 using (var stringList = new NativeList<FixedString32Bytes>(10, Allocator.Persistent) { "Hello", ",", "World", "!" }) 191 { 192 var container = new NativeHashSet<FixedString128Bytes>(50, Allocator.Temp); 193 var seen = new NativeArray<int>(stringList.Length, Allocator.Temp); 194 foreach (var str in stringList) 195 { 196 container.Add(str); 197 } 198 199 foreach (var value in container) 200 { 201 int index = stringList.IndexOf(value); 202 Assert.AreEqual(stringList[index], value.ToString()); 203 seen[index] = seen[index] + 1; 204 } 205 206 for (int i = 0; i < stringList.Length; i++) 207 { 208 Assert.AreEqual(1, seen[i], $"Incorrect value count {stringList[i]}"); 209 } 210 } 211 } 212 213 [Test] 214 public void NativeHashSet_ForEach([Values(10, 1000)]int n) 215 { 216 var seen = new NativeArray<int>(n, Allocator.Temp); 217 using (var container = new NativeHashSet<int>(32, CommonRwdAllocator.Handle)) 218 { 219 for (int i = 0; i < n; i++) 220 { 221 Assert.True(container.Add(i)); 222 } 223 224 var count = 0; 225 foreach (var item in container) 226 { 227 Assert.True(container.Contains(item)); 228 seen[item] = seen[item] + 1; 229 ++count; 230 } 231 232 Assert.AreEqual(container.Count, count); 233 for (int i = 0; i < n; i++) 234 { 235 Assert.AreEqual(1, seen[i], $"Incorrect item count {i}"); 236 } 237 } 238 } 239 240 struct NativeHashSet_ForEach_Job : IJob 241 { 242 [ReadOnly] 243 public NativeHashSet<int>.ReadOnly Input; 244 245 [ReadOnly] 246 public int Num; 247 248 public void Execute() 249 { 250 var seen = new NativeArray<int>(Num, Allocator.Temp); 251 252 var count = 0; 253 foreach (var item in Input) 254 { 255 Assert.True(Input.Contains(item)); 256 seen[item] = seen[item] + 1; 257 ++count; 258 } 259 260 Assert.AreEqual(Input.Count, count); 261 for (int i = 0; i < Num; i++) 262 { 263 Assert.AreEqual(1, seen[i], $"Incorrect item count {i}"); 264 } 265 266 seen.Dispose(); 267 } 268 } 269 270 [Test] 271 public void NativeHashSet_ForEach_From_Job([Values(10, 1000)] int n) 272 { 273 using (var container = new NativeHashSet<int>(32, CommonRwdAllocator.Handle)) 274 { 275 for (int i = 0; i < n; i++) 276 { 277 container.Add(i); 278 } 279 280 new NativeHashSet_ForEach_Job 281 { 282 Input = container.AsReadOnly(), 283 Num = n, 284 285 }.Run(); 286 } 287 } 288 289 struct NativeHashSet_Write_Job : IJob 290 { 291 public NativeHashSet<int> Input; 292 293 public void Execute() 294 { 295 Input.Clear(); 296 } 297 } 298 299 [Test] 300 public void NativeHashSet_Write_From_Job() 301 { 302 using (var container = new NativeHashSet<int>(32, CommonRwdAllocator.Handle)) 303 { 304 container.Add(0); 305 Assert.IsFalse(container.IsEmpty); 306 new NativeHashSet_Write_Job 307 { 308 Input = container, 309 }.Run(); 310 Assert.IsTrue(container.IsEmpty); 311 } 312 } 313 314 [Test] 315 [TestRequiresCollectionChecks] 316 public void NativeHashSet_ForEach_Throws_When_Modified() 317 { 318 using (var container = new NativeHashSet<int>(32, CommonRwdAllocator.Handle)) 319 { 320 container.Add(0); 321 container.Add(1); 322 container.Add(2); 323 container.Add(3); 324 container.Add(4); 325 container.Add(5); 326 container.Add(6); 327 container.Add(7); 328 container.Add(8); 329 container.Add(9); 330 331 Assert.Throws<ObjectDisposedException>(() => 332 { 333 foreach (var item in container) 334 { 335 container.Add(10); 336 } 337 }); 338 339 Assert.Throws<ObjectDisposedException>(() => 340 { 341 foreach (var item in container) 342 { 343 container.Remove(1); 344 } 345 }); 346 } 347 } 348 349 struct ForEachIterator : IJob 350 { 351 [ReadOnly] 352 public NativeHashSet<int>.Enumerator Iter; 353 354 public void Execute() 355 { 356 while (Iter.MoveNext()) 357 { 358 } 359 } 360 } 361 362 [Test] 363 [TestRequiresCollectionChecks] 364 public void NativeHashSet_ForEach_Throws_Job_Iterator() 365 { 366 using (var container = new NativeHashSet<int>(32, CommonRwdAllocator.Handle)) 367 { 368 var jobHandle = new ForEachIterator 369 { 370 Iter = container.GetEnumerator() 371 372 }.Schedule(); 373 374 Assert.Throws<InvalidOperationException>(() => { container.Add(1); }); 375 376 jobHandle.Complete(); 377 } 378 } 379 380 [Test] 381 public void NativeHashSet_EIU_ExceptWith_Empty() 382 { 383 var setA = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { }; 384 var setB = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { }; 385 setA.ExceptWith(setB); 386 387 ExpectedCount(ref setA, 0); 388 389 setA.Dispose(); 390 setB.Dispose(); 391 } 392 393 [Test] 394 public void NativeHashSet_EIU_ExceptWith_AxB() 395 { 396 var setA = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 }; 397 var setB = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 }; 398 setA.ExceptWith(setB); 399 400 ExpectedCount(ref setA, 3); 401 Assert.True(setA.Contains(0)); 402 Assert.True(setA.Contains(1)); 403 Assert.True(setA.Contains(2)); 404 405 setA.Dispose(); 406 setB.Dispose(); 407 } 408 409 [Test] 410 public void NativeHashSet_EIU_ExceptWith_BxA() 411 { 412 var setA = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 }; 413 var setB = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 }; 414 setB.ExceptWith(setA); 415 416 ExpectedCount(ref setB, 3); 417 Assert.True(setB.Contains(6)); 418 Assert.True(setB.Contains(7)); 419 Assert.True(setB.Contains(8)); 420 421 setA.Dispose(); 422 setB.Dispose(); 423 } 424 425 [Test] 426 public void NativeHashSet_EIU_IntersectWith_Empty() 427 { 428 var setA = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { }; 429 var setB = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { }; 430 setA.IntersectWith(setB); 431 432 ExpectedCount(ref setA, 0); 433 434 setA.Dispose(); 435 setB.Dispose(); 436 } 437 438 [Test] 439 public void NativeHashSet_EIU_IntersectWith() 440 { 441 var setA = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 }; 442 var setB = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 }; 443 setA.IntersectWith(setB); 444 445 ExpectedCount(ref setA, 3); 446 Assert.True(setA.Contains(3)); 447 Assert.True(setA.Contains(4)); 448 Assert.True(setA.Contains(5)); 449 450 setA.Dispose(); 451 setB.Dispose(); 452 } 453 454 [Test] 455 public void NativeHashSet_EIU_UnionWith_Empty() 456 { 457 var setA = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { }; 458 var setB = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { }; 459 setA.UnionWith(setB); 460 461 ExpectedCount(ref setA, 0); 462 463 setA.Dispose(); 464 setB.Dispose(); 465 } 466 467 [Test] 468 public void NativeHashSet_EIU_UnionWith() 469 { 470 var setA = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 }; 471 var setB = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 }; 472 setA.UnionWith(setB); 473 474 ExpectedCount(ref setA, 9); 475 Assert.True(setA.Contains(0)); 476 Assert.True(setA.Contains(1)); 477 Assert.True(setA.Contains(2)); 478 Assert.True(setA.Contains(3)); 479 Assert.True(setA.Contains(4)); 480 Assert.True(setA.Contains(5)); 481 Assert.True(setA.Contains(6)); 482 Assert.True(setA.Contains(7)); 483 Assert.True(setA.Contains(8)); 484 485 setA.Dispose(); 486 setB.Dispose(); 487 } 488 489 [Test] 490 public void NativeHashSet_ToArray() 491 { 492 using (var set = new NativeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 }) 493 { 494 var array = set.ToArray(); 495 Array.Sort(array); 496 for (int i = 0, num = set.Count; i < num; i++) 497 { 498 Assert.AreEqual(array[i], i); 499 } 500 } 501 } 502 503 [Test] 504 public void NativeHashSet_CustomAllocatorTest() 505 { 506 AllocatorManager.Initialize(); 507 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent); 508 ref var allocator = ref allocatorHelper.Allocator; 509 allocator.Initialize(); 510 511 using (var container = new NativeHashSet<int>(1, allocator.Handle)) 512 { 513 } 514 515 FastAssert.IsTrue(allocator.WasUsed); 516 allocator.Dispose(); 517 allocatorHelper.Dispose(); 518 AllocatorManager.Shutdown(); 519 } 520 521 [BurstCompile] 522 struct BurstedCustomAllocatorJob : IJob 523 { 524 [NativeDisableUnsafePtrRestriction] 525 public unsafe CustomAllocatorTests.CountingAllocator* Allocator; 526 527 public void Execute() 528 { 529 unsafe 530 { 531 using (var container = new NativeHashSet<int>(1, Allocator->Handle)) 532 { 533 } 534 } 535 } 536 } 537 538 [Test] 539 public unsafe void NativeHashSet_BurstedCustomAllocatorTest() 540 { 541 AllocatorManager.Initialize(); 542 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent); 543 ref var allocator = ref allocatorHelper.Allocator; 544 allocator.Initialize(); 545 546 var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator); 547 unsafe 548 { 549 var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr }.Schedule(); 550 handle.Complete(); 551 } 552 553 FastAssert.IsTrue(allocator.WasUsed); 554 allocator.Dispose(); 555 allocatorHelper.Dispose(); 556 AllocatorManager.Shutdown(); 557 } 558}