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.

JobTests.cs 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. using System;
  2. using NUnit.Framework;
  3. using UnityEngine.Scripting;
  4. using Unity.Collections;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. using Unity.Jobs;
  7. using Unity.Jobs.LowLevel.Unsafe;
  8. using Unity.Burst;
  9. using System.Diagnostics;
  10. using Unity.Collections.Tests;
  11. [assembly: RegisterGenericJobType(typeof(Unity.Jobs.Tests.ManagedJobs.MyGenericJobDefer<int>))]
  12. [assembly: RegisterGenericJobType(typeof(Unity.Jobs.Tests.ManagedJobs.MyGenericJobDefer<double>))]
  13. [assembly: RegisterGenericJobType(typeof(Unity.Jobs.Tests.ManagedJobs.MyGenericJobDefer<float>))]
  14. [assembly: RegisterGenericJobType(typeof(Unity.Jobs.Tests.ManagedJobs.GenericContainerJobDefer<NativeList<int>, int>))]
  15. namespace Unity.Jobs.Tests.ManagedJobs
  16. {
  17. internal enum JobRunType
  18. {
  19. Schedule,
  20. ScheduleByRef,
  21. Run,
  22. RunByRef,
  23. }
  24. [JobProducerType(typeof(IJobTestExtensions.JobTestProducer<>))]
  25. internal interface IJobTest
  26. {
  27. void Execute();
  28. }
  29. internal interface IJobTestInherit : IJob
  30. {
  31. }
  32. internal static class IJobTestExtensions
  33. {
  34. internal struct JobTestWrapper<T> where T : struct
  35. {
  36. internal T JobData;
  37. [NativeDisableContainerSafetyRestriction]
  38. internal NativeArray<byte> ProducerResourceToClean;
  39. }
  40. internal struct JobTestProducer<T> where T : struct, IJobTest
  41. {
  42. internal static readonly SharedStatic<IntPtr> s_JobReflectionData = SharedStatic<IntPtr>.GetOrCreate<JobTestProducer<T>>();
  43. [BurstDiscard]
  44. internal static void Initialize()
  45. {
  46. if (s_JobReflectionData.Data == IntPtr.Zero)
  47. s_JobReflectionData.Data = JobsUtility.CreateJobReflectionData(typeof(JobTestWrapper<T>), typeof(T), (ExecuteJobFunction)Execute);
  48. }
  49. public delegate void ExecuteJobFunction(ref JobTestWrapper<T> jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex);
  50. public unsafe static void Execute(ref JobTestWrapper<T> jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex)
  51. {
  52. jobWrapper.JobData.Execute();
  53. }
  54. }
  55. public static void EarlyJobInit<T>()
  56. where T : struct, IJobTest
  57. {
  58. JobTestProducer<T>.Initialize();
  59. }
  60. static IntPtr GetReflectionData<T>()
  61. where T : struct, IJobTest
  62. {
  63. JobTestProducer<T>.Initialize();
  64. var reflectionData = JobTestProducer<T>.s_JobReflectionData.Data;
  65. CollectionHelper.CheckReflectionDataCorrect<T>(reflectionData);
  66. return reflectionData;
  67. }
  68. public static unsafe JobHandle ScheduleTest<T>(this T jobData, NativeArray<byte> dataForProducer, JobHandle dependsOn = new JobHandle()) where T : struct, IJobTest
  69. {
  70. JobTestWrapper<T> jobTestWrapper = new JobTestWrapper<T>
  71. {
  72. JobData = jobData,
  73. ProducerResourceToClean = dataForProducer
  74. };
  75. var scheduleParams = new JobsUtility.JobScheduleParameters(
  76. UnsafeUtility.AddressOf(ref jobTestWrapper),
  77. GetReflectionData<T>(),
  78. dependsOn,
  79. ScheduleMode.Parallel
  80. );
  81. return JobsUtility.Schedule(ref scheduleParams);
  82. }
  83. }
  84. [JobProducerType(typeof(IJobTestInheritProducerExtensions.JobTestProducer<>))]
  85. internal interface IJobTestInheritWithProducer : IJob
  86. {
  87. void Execute(bool empty);
  88. }
  89. internal static class IJobTestInheritProducerExtensions
  90. {
  91. internal struct JobTestWrapper<T> where T : struct
  92. {
  93. internal T JobData;
  94. internal byte Empty;
  95. }
  96. internal struct JobTestProducer<T> where T : struct, IJobTestInheritWithProducer
  97. {
  98. internal static readonly SharedStatic<IntPtr> jobReflectionData = SharedStatic<IntPtr>.GetOrCreate<JobTestProducer<T>>();
  99. [BurstDiscard]
  100. internal static void Initialize()
  101. {
  102. if (jobReflectionData.Data == IntPtr.Zero)
  103. jobReflectionData.Data = JobsUtility.CreateJobReflectionData(typeof(JobTestWrapper<T>), typeof(T), (ExecuteJobFunction)Execute);
  104. }
  105. public delegate void ExecuteJobFunction(ref JobTestWrapper<T> jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex);
  106. public unsafe static void Execute(ref JobTestWrapper<T> jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex)
  107. {
  108. jobWrapper.JobData.Execute(jobWrapper.Empty != 0);
  109. }
  110. }
  111. public static void EarlyJobInit<T>()
  112. where T : struct, IJobTestInheritWithProducer
  113. {
  114. JobTestProducer<T>.Initialize();
  115. }
  116. static IntPtr GetReflectionData<T>()
  117. where T : struct, IJobTestInheritWithProducer
  118. {
  119. JobTestProducer<T>.Initialize();
  120. var reflectionData = JobTestProducer<T>.jobReflectionData.Data;
  121. CollectionHelper.CheckReflectionDataCorrect<T>(reflectionData);
  122. return reflectionData;
  123. }
  124. unsafe public static JobHandle Schedule<T>(this T jobData, bool empty, JobHandle dependsOn = new JobHandle()) where T : struct, IJobTestInheritWithProducer
  125. {
  126. JobTestWrapper<T> jobTestWrapper = new JobTestWrapper<T>
  127. {
  128. JobData = jobData,
  129. Empty = (byte)(empty ? 1 : 0)
  130. };
  131. var scheduleParams = new JobsUtility.JobScheduleParameters(
  132. UnsafeUtility.AddressOf(ref jobTestWrapper),
  133. GetReflectionData<T>(),
  134. dependsOn,
  135. ScheduleMode.Parallel
  136. );
  137. return JobsUtility.Schedule(ref scheduleParams);
  138. }
  139. }
  140. internal struct MyGenericResizeJob<T> : IJob where T : unmanaged
  141. {
  142. public int m_ListLength;
  143. public NativeList<T> m_GenericList;
  144. public void Execute()
  145. {
  146. m_GenericList.Resize(m_ListLength, NativeArrayOptions.UninitializedMemory);
  147. }
  148. }
  149. internal struct MyGenericJobDefer<T> : IJobParallelForDefer where T: unmanaged
  150. {
  151. public T m_Value;
  152. [NativeDisableParallelForRestriction]
  153. public NativeList<T> m_GenericList;
  154. public void Execute(int index)
  155. {
  156. m_GenericList[index] = m_Value;
  157. }
  158. }
  159. internal struct GenericContainerResizeJob<T, U> : IJob
  160. where T : unmanaged, INativeList<U>
  161. where U : unmanaged
  162. {
  163. public int m_ListLength;
  164. public T m_GenericList;
  165. public void Execute()
  166. {
  167. m_GenericList.Length = m_ListLength;
  168. }
  169. }
  170. internal struct GenericContainerJobDefer<T, U> : IJobParallelForDefer
  171. where T : unmanaged, INativeList<U>
  172. where U : unmanaged
  173. {
  174. public U m_Value;
  175. [NativeDisableParallelForRestriction]
  176. public T m_GenericList;
  177. public void Execute(int index)
  178. {
  179. m_GenericList[index] = m_Value;
  180. }
  181. }
  182. internal class JobTests : JobTestsFixture
  183. {
  184. public void ScheduleGenericContainerJob<T, U>(T container, U value)
  185. where T : unmanaged, INativeList<U>
  186. where U : unmanaged
  187. {
  188. var j0 = new GenericContainerResizeJob<T, U>();
  189. var length = 5;
  190. j0.m_ListLength = length;
  191. j0.m_GenericList = container;
  192. var handle0 = j0.Schedule();
  193. var j1 = new GenericContainerJobDefer<T, U>();
  194. j1.m_Value = value;
  195. j1.m_GenericList = j0.m_GenericList;
  196. INativeList<U> iList = j0.m_GenericList;
  197. j1.Schedule((NativeList<U>)iList, 1, handle0).Complete();
  198. Assert.AreEqual(length, j1.m_GenericList.Length);
  199. for (int i = 0; i != j1.m_GenericList.Length; i++)
  200. Assert.AreEqual(value, j1.m_GenericList[i]);
  201. }
  202. [Test]
  203. public void ValidateContainerSafetyInGenericJob_ContainerIsGenericParameter()
  204. {
  205. var list = new NativeList<int>(1, RwdAllocator.ToAllocator);
  206. ScheduleGenericContainerJob(list, 5);
  207. }
  208. public void GenericScheduleJobPair<T>(T value) where T : unmanaged
  209. {
  210. var j0 = new MyGenericResizeJob<T>();
  211. var length = 5;
  212. j0.m_ListLength = length;
  213. j0.m_GenericList = new NativeList<T>(1, RwdAllocator.ToAllocator);
  214. var handle0 = j0.Schedule();
  215. var j1 = new MyGenericJobDefer<T>();
  216. j1.m_Value = value;
  217. j1.m_GenericList = j0.m_GenericList;
  218. j1.Schedule(j0.m_GenericList, 1, handle0).Complete();
  219. Assert.AreEqual(length, j1.m_GenericList.Length);
  220. for (int i = 0; i != j1.m_GenericList.Length; i++)
  221. Assert.AreEqual(value, j1.m_GenericList[i]);
  222. }
  223. [Test]
  224. public void ScheduleGenericJobPairFloat()
  225. {
  226. GenericScheduleJobPair(10f);
  227. }
  228. [Test]
  229. public void ScheduleGenericJobPairDouble()
  230. {
  231. GenericScheduleJobPair<double>(10.0);
  232. }
  233. [Test]
  234. public void ScheduleGenericJobPairInt()
  235. {
  236. GenericScheduleJobPair(20);
  237. }
  238. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  239. [Test]
  240. public void SchedulingGenericJobUnsafelyThrows()
  241. {
  242. var j0 = new MyGenericResizeJob<int>();
  243. var length = 5;
  244. j0.m_ListLength = length;
  245. j0.m_GenericList = new NativeList<int>(1, RwdAllocator.ToAllocator);
  246. var handle0 = j0.Schedule();
  247. var j1 = new MyGenericJobDefer<int>();
  248. j1.m_Value = 6;
  249. j1.m_GenericList = j0.m_GenericList;
  250. Assert.Throws<InvalidOperationException>(()=>j1.Schedule(j0.m_GenericList, 1).Complete());
  251. handle0.Complete();
  252. }
  253. #endif
  254. struct DontReferenceThisTypeOutsideOfThisTest { public int v; }
  255. [Test]
  256. [TestRequiresCollectionChecks]
  257. public void SchedulingGenericJobFromGenericContextUnsafelyThrows()
  258. {
  259. var list = new NativeList<DontReferenceThisTypeOutsideOfThisTest>(1, RwdAllocator.ToAllocator);
  260. ScheduleGenericJobUnsafely(list, new DontReferenceThisTypeOutsideOfThisTest { v = 5 });
  261. }
  262. void ScheduleGenericJobUnsafely<T, U>(T container, U value)
  263. where T : unmanaged, INativeList<U>
  264. where U : unmanaged
  265. {
  266. var j0 = new GenericContainerResizeJob<T, U>();
  267. var length = 5;
  268. j0.m_ListLength = length;
  269. j0.m_GenericList = container;
  270. var handle0 = j0.Schedule();
  271. var j1 = new GenericContainerJobDefer<T, U>();
  272. j1.m_Value = value;
  273. j1.m_GenericList = j0.m_GenericList;
  274. INativeList<U> iList = j0.m_GenericList;
  275. Assert.Throws<InvalidOperationException>(()=>j1.Schedule((NativeList<U>)iList, 1).Complete());
  276. handle0.Complete(); // complete this so we can dispose the nativelist
  277. }
  278. /*
  279. * these two tests used to test that a job that inherited from both IJob and IJobParallelFor would work as expected
  280. * but that's probably crazy.
  281. */
  282. /*[Test]
  283. public void Scheduling()
  284. {
  285. var job = data.Schedule();
  286. job.Complete();
  287. ExpectOutputSumOfInput0And1();
  288. }*/
  289. /*[Test]
  290. public void Scheduling_With_Dependencies()
  291. {
  292. data.input0 = input0;
  293. data.input1 = input1;
  294. data.output = output2;
  295. var job1 = data.Schedule();
  296. // Schedule job2 with dependency against the first job
  297. data.input0 = output2;
  298. data.input1 = input2;
  299. data.output = output;
  300. var job2 = data.Schedule(job1);
  301. // Wait for completion
  302. job2.Complete();
  303. ExpectOutputSumOfInput0And1And2();
  304. }*/
  305. [Test]
  306. public void ForEach_Scheduling_With_Dependencies()
  307. {
  308. data.input0 = input0;
  309. data.input1 = input1;
  310. data.output = output2;
  311. var job1 = data.Schedule(output.Length, 1);
  312. // Schedule job2 with dependency against the first job
  313. data.input0 = output2;
  314. data.input1 = input2;
  315. data.output = output;
  316. var job2 = data.Schedule(output.Length, 1, job1);
  317. // Wait for completion
  318. job2.Complete();
  319. ExpectOutputSumOfInput0And1And2();
  320. }
  321. struct EmptyComputeParallelForJob : IJobParallelFor
  322. {
  323. public void Execute(int i)
  324. {
  325. }
  326. }
  327. [Test]
  328. public void ForEach_Scheduling_With_Zero_Size()
  329. {
  330. var test = new EmptyComputeParallelForJob();
  331. var job = test.Schedule(0, 1);
  332. job.Complete();
  333. }
  334. [Test]
  335. public void Deallocate_Temp_NativeArray_From_Job()
  336. {
  337. TestDeallocateNativeArrayFromJob(RwdAllocator.ToAllocator);
  338. }
  339. [Test]
  340. public void Deallocate_Persistent_NativeArray_From_Job()
  341. {
  342. TestDeallocateNativeArrayFromJob(Allocator.Persistent);
  343. }
  344. private void TestDeallocateNativeArrayFromJob(Allocator label)
  345. {
  346. var tempNativeArray = CollectionHelper.CreateNativeArray<int>(expectedInput0, label);
  347. var copyAndDestroyJob = new CopyAndDestroyNativeArrayParallelForJob
  348. {
  349. input = tempNativeArray,
  350. output = output
  351. };
  352. // NativeArray can safely be accessed before scheduling
  353. Assert.AreEqual(10, tempNativeArray.Length);
  354. tempNativeArray[0] = tempNativeArray[0];
  355. var job = copyAndDestroyJob.Schedule(copyAndDestroyJob.input.Length, 1);
  356. job.Complete();
  357. // Need to dispose because the allocator may be Allocator.Persistent.
  358. tempNativeArray.Dispose();
  359. Assert.AreEqual(expectedInput0, copyAndDestroyJob.output.ToArray());
  360. }
  361. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  362. public struct NestedDeallocateStruct
  363. {
  364. public NativeArray<int> input;
  365. }
  366. public struct TestNestedDeallocate : IJob
  367. {
  368. public NestedDeallocateStruct nested;
  369. public NativeArray<int> output;
  370. public void Execute()
  371. {
  372. for (int i = 0; i < nested.input.Length; ++i)
  373. output[i] = nested.input[i];
  374. }
  375. }
  376. [Test]
  377. public void TestNestedDeallocateOnJobCompletion()
  378. {
  379. var tempNativeArray = CollectionHelper.CreateNativeArray<int>(10, RwdAllocator.ToAllocator);
  380. var outNativeArray = CollectionHelper.CreateNativeArray<int>(10, RwdAllocator.ToAllocator);
  381. for (int i = 0; i < 10; i++)
  382. tempNativeArray[i] = i;
  383. var job = new TestNestedDeallocate
  384. {
  385. nested = new NestedDeallocateStruct() { input = tempNativeArray },
  386. output = outNativeArray
  387. };
  388. var handle = job.Schedule();
  389. handle.Complete();
  390. RwdAllocator.Rewind();
  391. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  392. // Ensure released safety handle indicating invalid buffer
  393. Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(tempNativeArray)); });
  394. Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(job.nested.input)); });
  395. #endif
  396. }
  397. public struct TestJobProducerJob : IJobTest
  398. {
  399. public NativeArray<int> jobStructData;
  400. public void Execute()
  401. {
  402. }
  403. }
  404. [Test]
  405. public void TestJobProducerCleansUp()
  406. {
  407. var tempNativeArray = CollectionHelper.CreateNativeArray<int>(10, RwdAllocator.ToAllocator);
  408. var tempNativeArray2 = CollectionHelper.CreateNativeArray<byte>(16, RwdAllocator.ToAllocator);
  409. var job = new TestJobProducerJob
  410. {
  411. jobStructData = tempNativeArray,
  412. };
  413. var handle = job.ScheduleTest(tempNativeArray2);
  414. handle.Complete();
  415. RwdAllocator.Rewind();
  416. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  417. // Check job data
  418. Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(tempNativeArray)); });
  419. Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(job.jobStructData)); });
  420. // Check job producer
  421. Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(tempNativeArray2)); });
  422. #endif
  423. }
  424. public struct CopyJob : IJob
  425. {
  426. public NativeList<int> List1;
  427. public NativeList<int> List2;
  428. public void Execute()
  429. {
  430. List1 = List2;
  431. }
  432. }
  433. [Test]
  434. public unsafe void TestContainerCopy_EnsureSafetyHandlesCopyAndDisposeProperly()
  435. {
  436. var list1 = new NativeList<int>(10, RwdAllocator.ToAllocator);
  437. var list2 = new NativeList<int>(10, RwdAllocator.ToAllocator);
  438. list1.Add(1);
  439. list2.Add(2);
  440. var job = new CopyJob
  441. {
  442. List1 = list1,
  443. List2 = list2
  444. };
  445. job.Schedule().Complete();
  446. list1.Dispose();
  447. list2.Dispose();
  448. }
  449. #endif
  450. struct LargeJobParallelForDefer : IJobParallelForDefer
  451. {
  452. public FixedString4096Bytes StrA;
  453. public FixedString4096Bytes StrB;
  454. public FixedString4096Bytes StrC;
  455. public FixedString4096Bytes StrD;
  456. [NativeDisableParallelForRestriction]
  457. public NativeArray<int> TotalLengths;
  458. [ReadOnly]
  459. public NativeList<float> Unused; // Schedule() from NativeList.Length requires that the list be passed into the job
  460. public void Execute(int index)
  461. {
  462. TotalLengths[0] = StrA.Length + StrB.Length + StrC.Length + StrD.Length;
  463. }
  464. }
  465. public enum IterationCountMode
  466. {
  467. List, Pointer
  468. }
  469. [Test]
  470. public unsafe void IJobParallelForDefer_LargeJobStruct_ScheduleRefWorks(
  471. [Values(IterationCountMode.List, IterationCountMode.Pointer)] IterationCountMode countMode)
  472. {
  473. using(var lengths = CollectionHelper.CreateNativeArray<int>(1, RwdAllocator.ToAllocator))
  474. {
  475. var dummyList = new NativeList<float>(RwdAllocator.ToAllocator);
  476. dummyList.Add(5.0f);
  477. var job = new LargeJobParallelForDefer
  478. {
  479. StrA = "A",
  480. StrB = "BB",
  481. StrC = "CCC",
  482. StrD = "DDDD",
  483. TotalLengths = lengths,
  484. Unused = dummyList,
  485. };
  486. if (countMode == IterationCountMode.List)
  487. {
  488. Assert.DoesNotThrow(() => job.ScheduleByRef(dummyList, 1).Complete());
  489. }
  490. else if (countMode == IterationCountMode.Pointer)
  491. {
  492. var lengthArray = CollectionHelper.CreateNativeArray<int>(1, RwdAllocator.ToAllocator);
  493. lengthArray[0] = 1;
  494. Assert.DoesNotThrow(() => job.ScheduleByRef((int*)lengthArray.GetUnsafePtr(), 1).Complete());
  495. }
  496. }
  497. }
  498. [BurstCompile(CompileSynchronously = true)]
  499. public struct InheritJob : IJobTestInherit
  500. {
  501. public NativeList<int> List1;
  502. public NativeList<int> List2;
  503. public void Execute()
  504. {
  505. List1[0] = List2[0];
  506. }
  507. }
  508. [Test]
  509. public void InheritInterfaceJobWorks()
  510. {
  511. var l1 = new NativeList<int>(4, RwdAllocator.ToAllocator);
  512. l1.Add(3);
  513. var l2 = new NativeList<int>(4, RwdAllocator.ToAllocator);
  514. l2.Add(17);
  515. var job = new InheritJob { List1 = l1, List2 = l2 };
  516. job.Schedule().Complete();
  517. Assert.IsTrue(l1[0] == 17);
  518. l2.Dispose();
  519. l1.Dispose();
  520. }
  521. [BurstCompile(CompileSynchronously = true)]
  522. public struct InheritWithProducerJob : IJobTestInheritWithProducer
  523. {
  524. public NativeList<int> List1;
  525. public NativeList<int> List2;
  526. public void Execute()
  527. {
  528. List2[0] = List1[0];
  529. }
  530. public void Execute(bool empty)
  531. {
  532. List1[0] = List2[0];
  533. }
  534. }
  535. [Test]
  536. public void InheritInterfaceWithProducerJobWorks()
  537. {
  538. var l1 = new NativeList<int>(4, RwdAllocator.ToAllocator);
  539. l1.Add(3);
  540. var l2 = new NativeList<int>(4, RwdAllocator.ToAllocator);
  541. l2.Add(17);
  542. var job = new InheritWithProducerJob { List1 = l1, List2 = l2 };
  543. job.Schedule(false).Complete();
  544. Assert.IsTrue(l1[0] == 17);
  545. l1[0] = 3;
  546. job.Schedule().Complete();
  547. Assert.IsTrue(l2[0] == 3);
  548. l2.Dispose();
  549. l1.Dispose();
  550. }
  551. }
  552. }