No Description
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.

NativeListTests_JobDebugger.cs 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  2. using UnityEngine;
  3. using NUnit.Framework;
  4. using System;
  5. using Unity.Jobs;
  6. using Unity.Burst;
  7. using Unity.Collections;
  8. using Unity.Collections.NotBurstCompatible;
  9. using Unity.Collections.Tests;
  10. #pragma warning disable 0219
  11. #pragma warning disable 0414
  12. internal class NativeListJobDebuggerTests : CollectionsTestFixture
  13. {
  14. [BurstCompile(CompileSynchronously = true)]
  15. struct NativeListAddJob : IJob
  16. {
  17. NativeList<int> list;
  18. public NativeListAddJob(NativeList<int> list) { this.list = list; }
  19. public void Execute()
  20. {
  21. list.Add(1);
  22. }
  23. }
  24. [BurstCompile(CompileSynchronously = true)]
  25. struct NativeArrayTest : IJob
  26. {
  27. NativeArray<int> array;
  28. public NativeArrayTest(NativeArray<int> array) { this.array = array; }
  29. public void Execute()
  30. {
  31. }
  32. }
  33. struct NestedContainerJob : IJob
  34. {
  35. public NativeList<NativeList<int>> nestedContainer;
  36. public void Execute()
  37. {
  38. nestedContainer.Clear();
  39. }
  40. }
  41. [Test]
  42. [TestRequiresCollectionChecks]
  43. public void NativeList_NestedJob_Error()
  44. {
  45. var container = new NativeList<NativeList<int>>(CommonRwdAllocator.Handle);
  46. var nestedJob = new NestedContainerJob
  47. {
  48. nestedContainer = container
  49. };
  50. JobHandle job = default;
  51. Assert.Throws<InvalidOperationException>(() => { job = nestedJob.Schedule(); });
  52. job.Complete();
  53. container.Dispose();
  54. }
  55. [Test]
  56. [TestRequiresCollectionChecks]
  57. public void AddElementToListFromJobInvalidatesArray()
  58. {
  59. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  60. list.Add(0);
  61. NativeArray<int> arrayBeforeSchedule = list.AsArray();
  62. Assert.AreEqual(list.Length, 1);
  63. var jobData = new NativeListAddJob(list);
  64. var job = jobData.Schedule();
  65. Assert.Throws<ObjectDisposedException>(
  66. () => {
  67. int readVal = arrayBeforeSchedule[0];
  68. });
  69. Assert.Throws<InvalidOperationException>(() => { NativeArray<int> array = list.AsArray(); Debug.Log(array.Length); });
  70. Assert.Throws<InvalidOperationException>(() => { int readVal = list.Capacity; });
  71. Assert.Throws<InvalidOperationException>(() => { list.Dispose(); });
  72. Assert.Throws<InvalidOperationException>(() => { int readVal = list[0]; });
  73. job.Complete();
  74. // Assert.AreEqual(1, arrayBeforeSchedule.Length); - temporarily commenting out updated assert checks to ensure editor version promotion succeeds
  75. Assert.Throws<ObjectDisposedException>(
  76. () => {
  77. int readVal = arrayBeforeSchedule[0];
  78. });
  79. Assert.AreEqual(2, list.Length);
  80. Assert.AreEqual(0, list[0]);
  81. Assert.AreEqual(1, list[1]);
  82. NativeArray<int> arrayAfter = list.AsArray();
  83. Assert.AreEqual(2, arrayAfter.Length);
  84. Assert.AreEqual(0, arrayAfter[0]);
  85. Assert.AreEqual(1, arrayAfter[1]);
  86. list.Dispose();
  87. }
  88. [Test]
  89. [TestRequiresCollectionChecks]
  90. public void AccessBefore()
  91. {
  92. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  93. var jobHandle = new NativeListAddJob(list).Schedule();
  94. Assert.Throws<InvalidOperationException>(() =>
  95. {
  96. list.AsArray();
  97. });
  98. jobHandle.Complete();
  99. list.Dispose();
  100. }
  101. [Test]
  102. [TestRequiresCollectionChecks]
  103. public void AccessAfter()
  104. {
  105. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  106. var array = list.AsArray();
  107. var jobHandle = new NativeListAddJob(list).Schedule();
  108. Assert.Throws<InvalidOperationException>(() =>
  109. {
  110. new NativeArrayTest(array).Schedule(jobHandle);
  111. });
  112. jobHandle.Complete();
  113. list.Dispose();
  114. }
  115. [Test]
  116. public void ScheduleDerivedArrayAllowDerivingArrayAgain()
  117. {
  118. var list = new NativeList<int>(1, Allocator.Persistent);
  119. // The scheduled job only receives a NativeArray thus it can't be resized
  120. var writeJobHandle = new NativeArrayTest(list.AsArray()).Schedule();
  121. // For that reason casting here is legal, as opposed to AddElementToListFromJobInvalidatesArray case where it is not legal
  122. // Since we NativeList is passed to the job
  123. #pragma warning disable 0219 // assigned but its value is never used
  124. NativeArray<int> array = list.AsArray();
  125. #pragma warning restore 0219
  126. list.Dispose(writeJobHandle);
  127. }
  128. [Test]
  129. [TestRequiresCollectionChecks]
  130. public void ScheduleDerivedArrayExceptions()
  131. {
  132. var list = new NativeList<int>(1, Allocator.Persistent);
  133. var addListJobHandle = new NativeListAddJob(list).Schedule();
  134. #pragma warning disable 0219 // assigned but its value is never used
  135. Assert.Throws<InvalidOperationException>(() => { NativeArray<int> array = list.AsArray(); });
  136. #pragma warning restore 0219
  137. addListJobHandle.Complete();
  138. list.Dispose();
  139. }
  140. [Test]
  141. [TestRequiresCollectionChecks]
  142. public void ScheduleDerivedArrayExceptions2()
  143. {
  144. var list = new NativeList<int>(1, Allocator.Persistent);
  145. NativeArray<int> array = list.AsArray();
  146. var addListJobHandle = new NativeListAddJob(list).Schedule();
  147. // The array previously cast should become invalid
  148. // as soon as the job is scheduled, since we can't predict if an element will be added or not
  149. Assert.Throws<InvalidOperationException>(() => { new NativeArrayTest(array).Schedule(); });
  150. addListJobHandle.Complete();
  151. list.Dispose();
  152. }
  153. [BurstCompile(CompileSynchronously = true)]
  154. struct ReadOnlyListAccess : IJob
  155. {
  156. [ReadOnly]
  157. NativeList<int> list;
  158. public ReadOnlyListAccess(NativeList<int> list) { this.list = list; }
  159. public void Execute()
  160. {
  161. }
  162. }
  163. [Test]
  164. public void ReadOnlyListInJobKeepsAsArrayValid()
  165. {
  166. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  167. list.Add(0);
  168. var arrayBeforeSchedule = list.AsArray();
  169. var jobData = new ReadOnlyListAccess(list);
  170. var job = jobData.Schedule();
  171. job.Complete();
  172. Assert.AreEqual(0, arrayBeforeSchedule[0]);
  173. list.Dispose();
  174. }
  175. [Test]
  176. public void AsArrayJobKeepsAsArrayValid()
  177. {
  178. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  179. list.Add(0);
  180. var arrayBeforeSchedule = list.AsArray();
  181. var jobData = new NativeArrayTest(list.AsArray());
  182. var job = jobData.Schedule();
  183. job.Complete();
  184. Assert.AreEqual(0, arrayBeforeSchedule[0]);
  185. list.Dispose();
  186. }
  187. [BurstCompile(CompileSynchronously = true)]
  188. struct NativeListToArrayConversionFromJob : IJob
  189. {
  190. public NativeList<int> list;
  191. public void Execute()
  192. {
  193. list.Add(0);
  194. list.Add(0);
  195. NativeArray<int> arr = list.AsArray();
  196. arr[0] = 1;
  197. arr[1] = 2;
  198. }
  199. }
  200. [Test]
  201. public void CastListToArrayInsideJob()
  202. {
  203. var jobData = new NativeListToArrayConversionFromJob();
  204. jobData.list = new NativeList<int>(1, Allocator.Persistent);
  205. jobData.Schedule().Complete();
  206. Assert.AreEqual(new int[] { 1, 2 }, jobData.list.ToArrayNBC());
  207. jobData.list.Dispose();
  208. }
  209. [BurstCompile(CompileSynchronously = true)]
  210. struct WriteJob : IJobParallelFor
  211. {
  212. public NativeArray<float> output;
  213. public void Execute(int i)
  214. {
  215. output[i] = i;
  216. }
  217. }
  218. [Test]
  219. [TestRequiresCollectionChecks]
  220. public void WriteToArrayFromJobThenReadListFromMainThread()
  221. {
  222. var list = new NativeList<float>(1, Allocator.Persistent);
  223. list.Add(0);
  224. list.Add(1);
  225. for (int i = 0; i < 2; i++)
  226. {
  227. var writeJob = new WriteJob();
  228. writeJob.output = list.AsArray();
  229. var writeJobHandle = writeJob.Schedule(list.Length, 1);
  230. Assert.Throws<InvalidOperationException>(() => { float val = writeJob.output[0]; });
  231. writeJobHandle.Complete();
  232. }
  233. list.Dispose();
  234. }
  235. [Test]
  236. public void NativeList_DisposeJob()
  237. {
  238. var list = new NativeList<int>(Allocator.Persistent);
  239. var deps = new NativeListAddJob(list).Schedule();
  240. deps = list.Dispose(deps);
  241. Assert.IsFalse(list.IsCreated);
  242. deps.Complete();
  243. }
  244. struct InvalidArrayAccessFromListJob : IJob
  245. {
  246. public NativeList<int> list;
  247. public void Execute()
  248. {
  249. list.Add(1);
  250. NativeArray<int> array = list.AsArray();
  251. list.Add(2);
  252. // Assert.Throws<InvalidOperationException>(() => { array[0] = 5; }); - temporarily commenting out updated assert checks to ensure editor version promotion succeeds
  253. }
  254. }
  255. [Test]
  256. [TestRequiresCollectionChecks]
  257. public void InvalidatedArrayAccessFromListThrowsInsideJob()
  258. {
  259. var job = new InvalidArrayAccessFromListJob { list = new NativeList<int>(CommonRwdAllocator.Handle) };
  260. job.Schedule().Complete();
  261. job.list.Dispose();
  262. }
  263. [Test]
  264. public void DisposeAliasedArrayDoesNotThrow()
  265. {
  266. var list = new NativeList<int>(Allocator.Persistent);
  267. var array = list.AsArray();
  268. Assert.DoesNotThrow(() => { array.Dispose(); });
  269. list.Dispose();
  270. }
  271. // Burst error BC1071: Unsupported assert type
  272. // [BurstCompile(CompileSynchronously = true)]
  273. struct NativeArrayTestReadOnly : IJob
  274. {
  275. [ReadOnly]
  276. NativeArray<int> array;
  277. public NativeArrayTestReadOnly(NativeArray<int> array) { this.array = array; }
  278. public void Execute()
  279. {
  280. var arr = array;
  281. Assert.Throws<InvalidOperationException>(() => { arr[0] = 5; });
  282. Assert.AreEqual(7, array[0]);
  283. }
  284. }
  285. // Burst error BC1071: Unsupported assert type
  286. // [BurstCompile(CompileSynchronously = true)]
  287. struct NativeArrayTestAsReadOnly : IJob
  288. {
  289. [ReadOnly]
  290. NativeArray<int>.ReadOnly array;
  291. public NativeArrayTestAsReadOnly(NativeArray<int>.ReadOnly array) { this.array = array; }
  292. public void Execute()
  293. {
  294. var arr = array;
  295. Assert.AreEqual(7, array[0]);
  296. }
  297. }
  298. [Test]
  299. [TestRequiresCollectionChecks]
  300. public void ReadOnlyAliasedArrayThrows()
  301. {
  302. var list = new NativeList<int>(Allocator.Persistent);
  303. list.Add(7);
  304. new NativeArrayTestReadOnly(list.AsArray()).Schedule().Complete();
  305. list.Dispose();
  306. }
  307. // Burst error BC1071: Unsupported assert type
  308. // [BurstCompile(CompileSynchronously = true)]
  309. struct NativeArrayTestWriteOnly : IJob
  310. {
  311. [WriteOnly]
  312. NativeArray<int> array;
  313. public NativeArrayTestWriteOnly(NativeArray<int> array) { this.array = array; }
  314. public void Execute()
  315. {
  316. var arr = array;
  317. Assert.Throws<InvalidOperationException>(() => { int read = arr[0]; });
  318. arr[0] = 7;
  319. }
  320. }
  321. [Test]
  322. [TestRequiresCollectionChecks]
  323. public void NativeList_AsArray_Jobs()
  324. {
  325. var list = new NativeList<int>(Allocator.Persistent);
  326. list.Add(0);
  327. var writer = list.AsArray();
  328. var writerJob = new NativeArrayTestWriteOnly(writer).Schedule();
  329. var reader = list.AsArray();
  330. var readerJob = new NativeArrayTestReadOnly(reader).Schedule(writerJob);
  331. // Tests that read only container safety check trows...
  332. var writerJob2 = new NativeArrayTestWriteOnly(reader).Schedule(readerJob);
  333. // Tests that write only container safety check trows...
  334. var readerJob2 = new NativeArrayTestReadOnly(writer).Schedule(writerJob2);
  335. readerJob2.Complete();
  336. list.Dispose();
  337. }
  338. [Test]
  339. [TestRequiresCollectionChecks]
  340. public void NativeList_AsReadOnly_Jobs()
  341. {
  342. var list = new NativeList<int>(Allocator.Persistent);
  343. list.Add(0);
  344. var writer = list.AsArray();
  345. var writerJob = new NativeArrayTestWriteOnly(writer).Schedule();
  346. var reader = list.AsReadOnly();
  347. var readerJob = new NativeArrayTestAsReadOnly(reader).Schedule(writerJob);
  348. readerJob.Complete();
  349. list.Dispose();
  350. }
  351. // Burst error BC1071: Unsupported assert type
  352. // [BurstCompile(CompileSynchronously = true)]
  353. struct NativeListTestReadOnly : IJob
  354. {
  355. [ReadOnly]
  356. public NativeArray<int>.ReadOnly reader;
  357. public void Execute()
  358. {
  359. Assert.True(reader.Contains(7));
  360. Assert.AreEqual(7, reader[0]);
  361. }
  362. }
  363. [Test]
  364. public void NativeList_AsReadOnly()
  365. {
  366. NativeList<int> list;
  367. JobHandle readerJob;
  368. {
  369. list = new NativeList<int>(Allocator.Persistent);
  370. list.Add(7);
  371. var reader = list.AsReadOnly();
  372. list.Dispose(); // <- cause invalid use
  373. Assert.Throws<InvalidOperationException>(() => { readerJob = new NativeListTestReadOnly { reader = reader }.Schedule(); });
  374. }
  375. {
  376. list = new NativeList<int>(Allocator.Persistent);
  377. list.Add(7);
  378. var reader = list.AsReadOnly();
  379. readerJob = new NativeListTestReadOnly { reader = reader }.Schedule();
  380. }
  381. list.Dispose(readerJob);
  382. readerJob.Complete();
  383. }
  384. [BurstCompile(CompileSynchronously = true)]
  385. struct NativeListTestParallelWriter : IJob
  386. {
  387. [WriteOnly]
  388. public NativeList<int>.ParallelWriter writer;
  389. public unsafe void Execute()
  390. {
  391. var range = stackalloc int[2] { 7, 3 };
  392. writer.AddNoResize(range[0]);
  393. writer.AddRangeNoResize(range, 1);
  394. }
  395. }
  396. [Test]
  397. public void NativeList_ParallelWriter()
  398. {
  399. NativeList<int> list;
  400. {
  401. list = new NativeList<int>(2, Allocator.Persistent);
  402. var writer = list.AsParallelWriter();
  403. list.Dispose(); // <- cause invalid use
  404. Assert.Throws<InvalidOperationException>(() =>
  405. {
  406. var writerJob = new NativeListTestParallelWriter { writer = writer }.Schedule();
  407. writerJob.Complete();
  408. });
  409. }
  410. {
  411. list = new NativeList<int>(2, Allocator.Persistent);
  412. var writer = list.AsParallelWriter();
  413. var writerJob = new NativeListTestParallelWriter { writer = writer }.Schedule();
  414. writerJob.Complete();
  415. }
  416. Assert.AreEqual(2, list.Length);
  417. Assert.AreEqual(7, list[0]);
  418. Assert.AreEqual(7, list[1]);
  419. list.Dispose();
  420. }
  421. [Test]
  422. public void NativeList_ParallelWriter_NoPtrCaching()
  423. {
  424. NativeList<int> list;
  425. {
  426. list = new NativeList<int>(2, Allocator.Persistent);
  427. var writer = list.AsParallelWriter();
  428. list.Capacity = 100;
  429. var writerJob = new NativeListTestParallelWriter { writer = writer }.Schedule();
  430. writerJob.Complete();
  431. }
  432. Assert.AreEqual(2, list.Length);
  433. Assert.AreEqual(7, list[0]);
  434. Assert.AreEqual(7, list[1]);
  435. list.Dispose();
  436. }
  437. [Test]
  438. [TestRequiresCollectionChecks]
  439. public void NativeList_AsReadOnlyAndParallelWriter()
  440. {
  441. NativeList<int> list;
  442. JobHandle jobHandle;
  443. list = new NativeList<int>(Allocator.Persistent);
  444. list.Add(7);
  445. jobHandle = new NativeListTestReadOnly { reader = list.AsReadOnly() }.Schedule();
  446. jobHandle = new NativeListTestParallelWriter { writer = list.AsParallelWriter() }.Schedule(jobHandle);
  447. jobHandle = new NativeListTestReadOnly { reader = list.AsReadOnly() }.Schedule(jobHandle);
  448. jobHandle = new NativeListTestParallelWriter { writer = list.AsParallelWriter() }.Schedule(jobHandle);
  449. list.Dispose(jobHandle);
  450. jobHandle.Complete();
  451. }
  452. unsafe void Expected(ref NativeList<int> list, int expectedLength, int[] expected)
  453. {
  454. Assert.AreEqual(0 == expectedLength, list.IsEmpty);
  455. Assert.AreEqual(list.Length, expectedLength);
  456. for (var i = 0; i < list.Length; ++i)
  457. {
  458. var value = list[i];
  459. Assert.AreEqual(expected[i], value);
  460. }
  461. }
  462. [Test]
  463. public unsafe void NativeList_RemoveRange()
  464. {
  465. var list = new NativeList<int>(10, Allocator.Persistent);
  466. int[] range = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  467. // test removing from the end
  468. fixed (int* r = range) list.AddRange(r, 10);
  469. list.RemoveRange(6, 3);
  470. Expected(ref list, 7, new int[] { 0, 1, 2, 3, 4, 5, 9 });
  471. list.Clear();
  472. // test removing all but one
  473. fixed (int* r = range) list.AddRange(r, 10);
  474. list.RemoveRange(0, 9);
  475. Expected(ref list, 1, new int[] { 9 });
  476. list.Clear();
  477. // test removing from the front
  478. fixed (int* r = range) list.AddRange(r, 10);
  479. list.RemoveRange(0, 3);
  480. Expected(ref list, 7, new int[] { 3, 4, 5, 6, 7, 8, 9 });
  481. list.Clear();
  482. // test removing from the middle
  483. fixed (int* r = range) list.AddRange(r, 10);
  484. list.RemoveRange(0, 3);
  485. Expected(ref list, 7, new int[] { 3, 4, 5, 6, 7, 8, 9 });
  486. list.Clear();
  487. // test removing whole range
  488. fixed (int* r = range) list.AddRange(r, 10);
  489. list.RemoveRange(0, 10);
  490. Expected(ref list, 0, new int[] { 0 });
  491. list.Clear();
  492. list.Dispose();
  493. }
  494. }
  495. #endif