Geen omschrijving
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NativeQueueTests.cs 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. using System;
  2. using NUnit.Framework;
  3. using Unity.Burst;
  4. using Unity.Collections;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. using Unity.Collections.Tests;
  7. using Unity.Jobs;
  8. using Assert = FastAssert;
  9. [BurstCompile]
  10. internal class NativeQueueTests : CollectionsTestCommonBase
  11. {
  12. static void ExpectedCount<T>(ref NativeQueue<T> container, int expected) where T : unmanaged
  13. {
  14. Assert.AreEqual(expected == 0, container.IsEmpty());
  15. Assert.AreEqual(expected, container.Count);
  16. }
  17. [Test]
  18. public void Enqueue_Dequeue()
  19. {
  20. var queue = new NativeQueue<int>(Allocator.Temp);
  21. ExpectedCount(ref queue, 0);
  22. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  23. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  24. #endif
  25. for (int i = 0; i < 16; ++i)
  26. queue.Enqueue(i);
  27. ExpectedCount(ref queue, 16);
  28. for (int i = 0; i < 16; ++i)
  29. Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
  30. ExpectedCount(ref queue, 0);
  31. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  32. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  33. #endif
  34. queue.Dispose();
  35. }
  36. [Test]
  37. public void ConcurrentEnqueue_Dequeue()
  38. {
  39. var queue = new NativeQueue<int>(Allocator.Temp);
  40. var cQueue = queue.AsParallelWriter();
  41. ExpectedCount(ref queue, 0);
  42. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  43. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  44. #endif
  45. for (int i = 0; i < 16; ++i)
  46. cQueue.Enqueue(i);
  47. ExpectedCount(ref queue, 16);
  48. for (int i = 0; i < 16; ++i)
  49. Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
  50. ExpectedCount(ref queue, 0);
  51. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  52. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  53. #endif
  54. queue.Dispose();
  55. }
  56. [Test]
  57. public void Enqueue_Dequeue_Peek()
  58. {
  59. var queue = new NativeQueue<int>(Allocator.Temp);
  60. ExpectedCount(ref queue, 0);
  61. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  62. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  63. #endif
  64. for (int i = 0; i < 16; ++i)
  65. queue.Enqueue(i);
  66. ExpectedCount(ref queue, 16);
  67. for (int i = 0; i < 16; ++i)
  68. {
  69. Assert.AreEqual(i, queue.Peek(), "Got the wrong value from the queue");
  70. queue.Dequeue();
  71. }
  72. ExpectedCount(ref queue, 0);
  73. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  74. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  75. #endif
  76. queue.Dispose();
  77. }
  78. [Test]
  79. public void Enqueue_Dequeue_Clear()
  80. {
  81. var queue = new NativeQueue<int>(Allocator.Temp);
  82. ExpectedCount(ref queue, 0);
  83. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  84. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  85. #endif
  86. for (int i = 0; i < 16; ++i)
  87. queue.Enqueue(i);
  88. ExpectedCount(ref queue, 16);
  89. for (int i = 0; i < 8; ++i)
  90. Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
  91. ExpectedCount(ref queue, 8);
  92. queue.Clear();
  93. ExpectedCount(ref queue, 0);
  94. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  95. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  96. #endif
  97. queue.Dispose();
  98. }
  99. [Test]
  100. [TestRequiresCollectionChecks]
  101. public void Double_Deallocate_Throws()
  102. {
  103. var queue = new NativeQueue<int>(CommonRwdAllocator.Handle);
  104. queue.Dispose();
  105. Assert.Throws<ObjectDisposedException>(
  106. () => { queue.Dispose(); });
  107. }
  108. [Test]
  109. public void EnqueueScalability()
  110. {
  111. var queue = new NativeQueue<int>(Allocator.Persistent);
  112. for (int i = 0; i != 1000 * 100; i++)
  113. {
  114. queue.Enqueue(i);
  115. }
  116. ExpectedCount(ref queue, 1000 * 100);
  117. for (int i = 0; i != 1000 * 100; i++)
  118. Assert.AreEqual(i, queue.Dequeue());
  119. ExpectedCount(ref queue, 0);
  120. queue.Dispose();
  121. }
  122. [Test]
  123. public void Enqueue_Wrap()
  124. {
  125. var queue = new NativeQueue<int>(Allocator.Temp);
  126. ExpectedCount(ref queue, 0);
  127. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  128. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  129. #endif
  130. for (int i = 0; i < 256; ++i)
  131. queue.Enqueue(i);
  132. ExpectedCount(ref queue, 256);
  133. for (int i = 0; i < 128; ++i)
  134. Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
  135. ExpectedCount(ref queue, 128);
  136. for (int i = 0; i < 128; ++i)
  137. queue.Enqueue(i);
  138. ExpectedCount(ref queue, 256);
  139. for (int i = 128; i < 256; ++i)
  140. Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
  141. ExpectedCount(ref queue, 128);
  142. for (int i = 0; i < 128; ++i)
  143. Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
  144. ExpectedCount(ref queue, 0);
  145. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  146. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  147. #endif
  148. queue.Dispose();
  149. }
  150. [Test]
  151. public void ConcurrentEnqueue_Wrap()
  152. {
  153. var queue = new NativeQueue<int>(Allocator.Temp);
  154. var cQueue = queue.AsParallelWriter();
  155. ExpectedCount(ref queue, 0);
  156. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  157. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  158. #endif
  159. for (int i = 0; i < 256; ++i)
  160. cQueue.Enqueue(i);
  161. ExpectedCount(ref queue, 256);
  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. for (int i = 0; i < 128; ++i)
  166. cQueue.Enqueue(i);
  167. ExpectedCount(ref queue, 256);
  168. for (int i = 128; i < 256; ++i)
  169. Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
  170. ExpectedCount(ref queue, 128);
  171. for (int i = 0; i < 128; ++i)
  172. Assert.AreEqual(i, queue.Dequeue(), "Got the wrong value from the queue");
  173. ExpectedCount(ref queue, 0);
  174. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  175. Assert.Throws<System.InvalidOperationException>(() => { queue.Dequeue(); });
  176. #endif
  177. queue.Dispose();
  178. }
  179. [Test]
  180. public void NativeQueue_DisposeJob()
  181. {
  182. var container = new NativeQueue<int>(Allocator.Persistent);
  183. Assert.True(container.IsCreated);
  184. Assert.DoesNotThrow(() => { container.Enqueue(0); });
  185. var disposeJob = container.Dispose(default);
  186. Assert.False(container.IsCreated);
  187. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  188. Assert.Throws<ObjectDisposedException>(
  189. () => { container.Enqueue(0); });
  190. #endif
  191. disposeJob.Complete();
  192. }
  193. [Test]
  194. public void TryDequeue_OnEmptyQueueWhichHadElements_RetainsValidState()
  195. {
  196. using (var queue = new NativeQueue<int>(Allocator.Temp))
  197. {
  198. for (int i = 0; i < 3; i++)
  199. {
  200. queue.Enqueue(i);
  201. Assert.AreEqual(1, queue.Count);
  202. int value;
  203. while (queue.TryDequeue(out value))
  204. {
  205. Assert.AreEqual(i, value);
  206. }
  207. Assert.AreEqual(0, queue.Count);
  208. }
  209. }
  210. }
  211. [Test]
  212. public void TryDequeue_OnEmptyQueue_RetainsValidState()
  213. {
  214. using (var queue = new NativeQueue<int>(Allocator.Temp))
  215. {
  216. Assert.IsFalse(queue.TryDequeue(out _));
  217. queue.Enqueue(1);
  218. Assert.AreEqual(1, queue.Count);
  219. }
  220. }
  221. [Test]
  222. public void ToArray_ContainsCorrectElements()
  223. {
  224. using (var queue = new NativeQueue<int>(Allocator.Temp))
  225. {
  226. for (int i = 0; i < 100; i++)
  227. queue.Enqueue(i);
  228. using (var array = queue.ToArray(Allocator.Temp))
  229. {
  230. Assert.AreEqual(queue.Count, array.Length);
  231. for (int i = 0; i < array.Length; i++)
  232. Assert.AreEqual(i, array[i]);
  233. }
  234. }
  235. }
  236. [Test]
  237. public void ToArray_RespectsDequeue()
  238. {
  239. using (var queue = new NativeQueue<int>(Allocator.Temp))
  240. {
  241. for (int i = 0; i < 100; i++)
  242. queue.Enqueue(i);
  243. for (int i = 0; i < 50; i++)
  244. queue.Dequeue();
  245. using (var array = queue.ToArray(Allocator.Temp))
  246. {
  247. Assert.AreEqual(queue.Count, array.Length);
  248. for (int i = 0; i < array.Length; i++)
  249. Assert.AreEqual(50 + i, array[i]);
  250. }
  251. }
  252. }
  253. [Test]
  254. [TestRequiresCollectionChecks]
  255. public void NativeQueue_UseAfterFree_UsesCustomOwnerTypeName()
  256. {
  257. var container = new NativeQueue<int>(CommonRwdAllocator.Handle);
  258. container.Enqueue(123);
  259. container.Dispose();
  260. NUnit.Framework.Assert.That(() => container.Dequeue(),
  261. Throws.Exception.TypeOf<ObjectDisposedException>()
  262. .With.Message.Contains($"The {container.GetType()} has been deallocated"));
  263. }
  264. [Test]
  265. public void NativeQueue_CustomAllocatorTest()
  266. {
  267. AllocatorManager.Initialize();
  268. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  269. ref var allocator = ref allocatorHelper.Allocator;
  270. allocator.Initialize();
  271. using (var container = new NativeQueue<int>(allocator.Handle))
  272. {
  273. }
  274. Assert.IsTrue(allocator.WasUsed);
  275. allocator.Dispose();
  276. allocatorHelper.Dispose();
  277. AllocatorManager.Shutdown();
  278. }
  279. [BurstCompile(CompileSynchronously = true)]
  280. struct BurstedCustomAllocatorJob : IJob
  281. {
  282. [NativeDisableUnsafePtrRestriction]
  283. public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
  284. public void Execute()
  285. {
  286. unsafe
  287. {
  288. using (var container = new NativeQueue<int>(Allocator->Handle))
  289. {
  290. }
  291. }
  292. }
  293. }
  294. [Test]
  295. public unsafe void NativeQueue_BurstedCustomAllocatorTest()
  296. {
  297. AllocatorManager.Initialize();
  298. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  299. ref var allocator = ref allocatorHelper.Allocator;
  300. allocator.Initialize();
  301. var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
  302. unsafe
  303. {
  304. var handle = new BurstedCustomAllocatorJob { Allocator = allocatorPtr }.Schedule();
  305. handle.Complete();
  306. }
  307. Assert.IsTrue(allocator.WasUsed);
  308. allocator.Dispose();
  309. allocatorHelper.Dispose();
  310. AllocatorManager.Shutdown();
  311. }
  312. public struct NestedContainer
  313. {
  314. public NativeQueue<int> data;
  315. }
  316. [Test]
  317. public void NativeQueue_Nested()
  318. {
  319. var inner = new NativeQueue<int>(CommonRwdAllocator.Handle);
  320. NestedContainer nestedStruct = new NestedContainer { data = inner };
  321. var containerNestedStruct = new NativeQueue<NestedContainer>(CommonRwdAllocator.Handle);
  322. var containerNested = new NativeQueue<NativeQueue<int>>(CommonRwdAllocator.Handle);
  323. containerNested.Enqueue(inner);
  324. containerNestedStruct.Enqueue(nestedStruct);
  325. containerNested.Dispose();
  326. containerNestedStruct.Dispose();
  327. inner.Dispose();
  328. }
  329. [Test]
  330. public void NativeQueue_ReadOnly()
  331. {
  332. var container = new NativeQueue<int>(CommonRwdAllocator.Handle);
  333. container.Enqueue(123);
  334. container.Enqueue(456);
  335. container.Enqueue(789);
  336. var ro = container.AsReadOnly();
  337. Assert.AreEqual(3, ro.Count);
  338. Assert.AreEqual(123, ro[0]);
  339. Assert.AreEqual(456, ro[1]);
  340. Assert.AreEqual(789, ro[2]);
  341. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  342. Assert.Throws<IndexOutOfRangeException>(() => { _ = ro[3]; });
  343. Assert.Throws<IndexOutOfRangeException>(() => { _ = ro[-1]; });
  344. Assert.Throws<IndexOutOfRangeException>(() => { _ = ro[int.MaxValue]; });
  345. Assert.Throws<IndexOutOfRangeException>(() => { _ = ro[int.MinValue]; });
  346. #endif
  347. container.Dispose();
  348. }
  349. // Burst error BC1071: Unsupported assert type
  350. // [BurstCompile(CompileSynchronously = true)]
  351. struct NativeQueueTestAsReadOnly : IJob
  352. {
  353. [ReadOnly]
  354. NativeQueue<int>.ReadOnly container;
  355. public NativeQueueTestAsReadOnly(NativeQueue<int>.ReadOnly container) { this.container = container; }
  356. public void Execute()
  357. {
  358. var ro = container;
  359. Assert.AreEqual(3, ro.Count);
  360. Assert.AreEqual(123, ro[0]);
  361. Assert.AreEqual(456, ro[1]);
  362. Assert.AreEqual(789, ro[2]);
  363. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  364. Assert.Throws<IndexOutOfRangeException>(() => { _ = ro[3]; });
  365. Assert.Throws<IndexOutOfRangeException>(() => { _ = ro[-1]; });
  366. Assert.Throws<IndexOutOfRangeException>(() => { _ = ro[int.MaxValue]; });
  367. Assert.Throws<IndexOutOfRangeException>(() => { _ = ro[int.MinValue]; });
  368. #endif
  369. }
  370. }
  371. [Test]
  372. [TestRequiresCollectionChecks]
  373. public void NativeQueue_ReadOnlyJob()
  374. {
  375. var container = new NativeQueue<int>(CommonRwdAllocator.Handle);
  376. container.Enqueue(123);
  377. container.Enqueue(456);
  378. container.Enqueue(789);
  379. var job = new NativeQueueTestAsReadOnly(container.AsReadOnly()).Schedule();
  380. Assert.Throws<InvalidOperationException>(() => { container.Enqueue(987); });
  381. Assert.Throws<InvalidOperationException>(() => { container.Dequeue(); });
  382. Assert.Throws<InvalidOperationException>(() => { container.Dispose(); });
  383. job.Complete();
  384. Assert.DoesNotThrow(() => { container.Enqueue(987); });
  385. Assert.DoesNotThrow(() => { container.Dequeue(); });
  386. Assert.DoesNotThrow(() => { container.Dispose(); });
  387. }
  388. struct NativeQueueTestWriteMappedToReadOnly : IJob
  389. {
  390. [WriteOnly]
  391. public NativeQueue<int>.ParallelWriter Container;
  392. public void Execute() { }
  393. }
  394. [Test]
  395. [TestRequiresCollectionChecks]
  396. public void NativeQueue_ReadOnlyCannotScheduledForWrite()
  397. {
  398. var container = new NativeQueue<int>(CommonRwdAllocator.Handle);
  399. container.Enqueue(123);
  400. container.Enqueue(456);
  401. container.Enqueue(789);
  402. var ro = container.AsReadOnly();
  403. var job = new NativeQueueTestWriteMappedToReadOnly { Container = container.AsParallelWriter() }.Schedule();
  404. Assert.Throws<InvalidOperationException>(() => { _ = ro.Count; });
  405. Assert.Throws<InvalidOperationException>(() => { _ = ro[0]; });
  406. Assert.Throws<InvalidOperationException>(() => { _ = ro[1]; });
  407. Assert.Throws<InvalidOperationException>(() => { _ = ro[2]; });
  408. Assert.Throws<InvalidOperationException>(() => { foreach (var item in ro) { } });
  409. job.Complete();
  410. Assert.AreEqual(3, ro.Count);
  411. Assert.AreEqual(123, ro[0]);
  412. Assert.AreEqual(456, ro[1]);
  413. Assert.AreEqual(789, ro[2]);
  414. Assert.DoesNotThrow(() => { foreach (var item in ro) { } });
  415. container.Dispose();
  416. }
  417. [Test]
  418. public void NativeQueue_ReadOnlyForEach()
  419. {
  420. var container = new NativeQueue<int>(CommonRwdAllocator.Handle);
  421. container.Enqueue(123);
  422. container.Enqueue(456);
  423. container.Enqueue(789);
  424. var ro = container.AsReadOnly();
  425. var idx = 0;
  426. foreach (var item in ro)
  427. {
  428. Assert.AreEqual(item, ro[idx++]);
  429. }
  430. container.Dispose();
  431. }
  432. struct NativeQueue_ForEachIterator : IJob
  433. {
  434. [ReadOnly]
  435. public NativeQueue<int>.Enumerator Iter;
  436. public void Execute()
  437. {
  438. while (Iter.MoveNext())
  439. {
  440. }
  441. }
  442. }
  443. [Test]
  444. [TestRequiresCollectionChecks]
  445. public void NativeQueue_ForEach_Throws_Job_Iterator()
  446. {
  447. using (var container = new NativeQueue<int>(CommonRwdAllocator.Handle))
  448. {
  449. var jobHandle = new NativeQueue_ForEachIterator
  450. {
  451. Iter = container.AsReadOnly().GetEnumerator()
  452. }.Schedule();
  453. Assert.Throws<InvalidOperationException>(() => { container.Enqueue(987); });
  454. jobHandle.Complete();
  455. }
  456. }
  457. struct NativeQueueParallelWriteJob : IJobParallelFor
  458. {
  459. [WriteOnly]
  460. public NativeQueue<int>.ParallelWriter Writer;
  461. public void Execute(int index)
  462. {
  463. Writer.Enqueue(index);
  464. }
  465. }
  466. [Test]
  467. [TestRequiresCollectionChecks]
  468. public void NativeQueue_ForEach_Throws()
  469. {
  470. using (var container = new NativeQueue<int>(CommonRwdAllocator.Handle))
  471. {
  472. var iter = container.AsReadOnly().GetEnumerator();
  473. var jobHandle = new NativeQueueParallelWriteJob
  474. {
  475. Writer = container.AsParallelWriter()
  476. }.Schedule(1, 2);
  477. Assert.Throws<InvalidOperationException>(() =>
  478. {
  479. while (iter.MoveNext())
  480. {
  481. }
  482. });
  483. jobHandle.Complete();
  484. }
  485. }
  486. struct NativeQueue_ForEach_Job : IJob
  487. {
  488. public NativeQueue<int>.ReadOnly Input;
  489. public void Execute()
  490. {
  491. var index = 0;
  492. foreach (var value in Input)
  493. {
  494. Assert.AreEqual(value, Input[index++]);
  495. }
  496. }
  497. }
  498. [Test]
  499. public void NativeQueue_ForEach_From_Job([Values(10, 1000)] int n)
  500. {
  501. var seen = new NativeArray<int>(n, Allocator.Temp);
  502. using (var container = new NativeQueue<int>(CommonRwdAllocator.Handle))
  503. {
  504. for (int i = 0; i < n; i++)
  505. {
  506. container.Enqueue(i * 37);
  507. }
  508. new NativeQueue_ForEach_Job
  509. {
  510. Input = container.AsReadOnly(),
  511. }.Run();
  512. }
  513. }
  514. }