A game about forced loneliness, made by TACStudios
1using NUnit.Framework;
2using System;
3using Unity.Burst;
4using Unity.Collections;
5using Unity.Collections.LowLevel.Unsafe;
6using Unity.Collections.Tests;
7using Unity.Jobs;
8
9class NativeReferenceTests : CollectionsTestCommonBase
10{
11 [Test]
12 public void NativeReference_AllocateDeallocate_ReadWrite()
13 {
14 var reference = new NativeReference<int>(Allocator.Persistent);
15 reference.Value = 1;
16
17 Assert.That(reference.Value, Is.EqualTo(1));
18
19 reference.Dispose();
20 }
21
22 [Test]
23 public void NativeReference_CopyFrom()
24 {
25 var referenceA = new NativeReference<TestData>(Allocator.Persistent);
26 var referenceB = new NativeReference<TestData>(Allocator.Persistent);
27
28 referenceA.Value = new TestData { Integer = 42, Float = 3.1416f };
29 referenceB.CopyFrom(referenceA);
30
31 Assert.That(referenceB.Value, Is.EqualTo(referenceA.Value));
32
33 referenceA.Dispose();
34 referenceB.Dispose();
35 }
36
37 [Test]
38 public void NativeReference_CopyTo()
39 {
40 var referenceA = new NativeReference<TestData>(Allocator.Persistent);
41 var referenceB = new NativeReference<TestData>(Allocator.Persistent);
42
43 referenceA.Value = new TestData { Integer = 42, Float = 3.1416f };
44 referenceA.CopyTo(referenceB);
45
46 Assert.That(referenceB.Value, Is.EqualTo(referenceA.Value));
47
48 referenceA.Dispose();
49 referenceB.Dispose();
50 }
51
52 [Test]
53 [TestRequiresCollectionChecks]
54 public void NativeReference_NullThrows()
55 {
56 var reference = new NativeReference<int>();
57 Assert.Throws<NullReferenceException>(() => reference.Value = 5);
58 }
59
60 [Test]
61 public void NativeReference_CopiedIsKeptInSync()
62 {
63 var reference = new NativeReference<int>(Allocator.Persistent);
64 var referenceCopy = reference;
65 reference.Value = 42;
66
67 Assert.That(reference.Value, Is.EqualTo(referenceCopy.Value));
68
69 reference.Dispose();
70 }
71
72 struct TestData
73 {
74 public int Integer;
75 public float Float;
76 }
77
78 [BurstCompile(CompileSynchronously = true)]
79 struct TempNativeReferenceInJob : IJob
80 {
81 public NativeReference<int> Output;
82
83 public void Execute()
84 {
85 var reference = new NativeReference<int>(Allocator.Temp);
86 reference.Value = 42;
87 Output.Value = reference.Value;
88 reference.Dispose();
89 }
90 }
91
92 [Test]
93 public void NativeReference_TempInBurstJob()
94 {
95 var job = new TempNativeReferenceInJob() { Output = new NativeReference<int>(CommonRwdAllocator.Handle) };
96 job.Schedule().Complete();
97
98 Assert.That(job.Output.Value, Is.EqualTo(42));
99
100 job.Output.Dispose();
101 }
102
103 [Test]
104 public unsafe void NativeReference_UnsafePtr()
105 {
106 var reference = new NativeReference<int>(CommonRwdAllocator.Handle);
107 var job = new TempNativeReferenceInJob() { Output = reference };
108 var jobHandle = job.Schedule();
109
110#if ENABLE_UNITY_COLLECTIONS_CHECKS
111 Assert.Throws<InvalidOperationException>(() => reference.GetUnsafePtr());
112 Assert.Throws<InvalidOperationException>(() => reference.GetUnsafeReadOnlyPtr());
113#endif
114 Assert.DoesNotThrow(() => reference.GetUnsafePtrWithoutChecks());
115
116 jobHandle.Complete();
117
118 Assert.AreEqual(*reference.GetUnsafePtr(), 42);
119 Assert.AreEqual(*reference.GetUnsafeReadOnlyPtr(), 42);
120 Assert.AreEqual(*reference.GetUnsafePtrWithoutChecks(), 42);
121
122 Assert.That(job.Output.Value, Is.EqualTo(42));
123
124 job.Output.Dispose();
125 }
126
127 [Test]
128 public void NativeReference_DisposeJob()
129 {
130 var reference = new NativeReference<int>(Allocator.Persistent);
131 Assert.That(reference.IsCreated, Is.True);
132 Assert.DoesNotThrow(() => reference.Value = 99);
133
134 var disposeJob = reference.Dispose(default);
135 Assert.That(reference.IsCreated, Is.False);
136
137#if ENABLE_UNITY_COLLECTIONS_CHECKS
138 Assert.Throws<ObjectDisposedException>(() => reference.Value = 3);
139#endif
140
141 disposeJob.Complete();
142 }
143
144 [Test]
145 public void NativeReference_NoGCAllocations()
146 {
147 var reference = new NativeReference<int>(Allocator.Persistent);
148
149 GCAllocRecorder.ValidateNoGCAllocs(() =>
150 {
151 reference.Value = 1;
152 reference.Value++;
153 });
154
155 Assert.That(reference.Value, Is.EqualTo(2));
156
157 reference.Dispose();
158 }
159
160 [Test]
161 public void NativeReference_Equals()
162 {
163 var referenceA = new NativeReference<int>(12345, Allocator.Persistent);
164 var referenceB = new NativeReference<int>(Allocator.Persistent) { Value = 12345 };
165 Assert.That(referenceA, Is.EqualTo(referenceB));
166
167 referenceB.Value = 54321;
168 Assert.AreNotEqual(referenceA, referenceB);
169
170 referenceA.Dispose();
171 referenceB.Dispose();
172 }
173
174 [Test]
175 public void NativeReference_ReadOnly()
176 {
177 var referenceA = new NativeReference<int>(12345, Allocator.Persistent);
178 var referenceB = new NativeReference<int>(Allocator.Persistent) { Value = 12345 };
179
180 var referenceARO = referenceA.AsReadOnly();
181 Assert.AreEqual(referenceARO.Value, referenceB.Value);
182
183 referenceA.Dispose();
184 referenceB.Dispose();
185 }
186
187 [Test]
188 public void NativeReference_GetHashCode()
189 {
190 var integer = 42;
191 var reference = new NativeReference<int>(integer, Allocator.Persistent);
192 Assert.That(reference.GetHashCode(), Is.EqualTo(integer.GetHashCode()));
193
194 reference.Dispose();
195 }
196
197 [Test]
198 public void NativeReference_CustomAllocatorTest()
199 {
200 AllocatorManager.Initialize();
201 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
202 ref var allocator = ref allocatorHelper.Allocator;
203 allocator.Initialize();
204
205 using (var container = new NativeReference<int>(allocator.Handle))
206 {
207 }
208
209 Assert.IsTrue(allocator.WasUsed);
210 allocator.Dispose();
211 allocatorHelper.Dispose();
212 AllocatorManager.Shutdown();
213 }
214
215 [BurstCompile]
216 struct BurstedCustomAllocatorJob : IJob
217 {
218 [NativeDisableUnsafePtrRestriction]
219 public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
220
221 public void Execute()
222 {
223 unsafe
224 {
225 using (var container = new NativeReference<int>(Allocator->Handle))
226 {
227 }
228 }
229 }
230 }
231
232 [Test]
233 public unsafe void NativeReference_BurstedCustomAllocatorTest()
234 {
235 AllocatorManager.Initialize();
236 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
237 ref var allocator = ref allocatorHelper.Allocator;
238 allocator.Initialize();
239
240 var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
241 unsafe
242 {
243 var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
244 handle.Complete();
245 }
246
247 Assert.IsTrue(allocator.WasUsed);
248 allocator.Dispose();
249 allocatorHelper.Dispose();
250 AllocatorManager.Shutdown();
251 }
252
253 public struct NestedContainer
254 {
255 public NativeReference<int> data;
256 }
257
258 [Test]
259 public void NativeReference_Nested()
260 {
261 var inner = new NativeReference<int>(CommonRwdAllocator.Handle);
262 NestedContainer nestedStruct = new NestedContainer { data = inner };
263
264 var containerNestedStruct = new NativeReference<NestedContainer>(CommonRwdAllocator.Handle);
265 var containerNested = new NativeReference<NativeReference<int>>(CommonRwdAllocator.Handle);
266
267 containerNested.Value = inner;
268 containerNestedStruct.Value = nestedStruct;
269
270 containerNested.Dispose();
271 containerNestedStruct.Dispose();
272 inner.Dispose();
273 }
274
275 struct NestedContainerJob : IJob
276 {
277 public NativeReference<NativeReference<int>> nestedContainer;
278
279 public void Execute()
280 {
281 nestedContainer.Value = default;
282 }
283 }
284
285 [Test]
286 [TestRequiresCollectionChecks]
287 public void NativeReference_NestedJob_Error()
288 {
289 var container = new NativeReference<NativeReference<int>>(CommonRwdAllocator.Handle);
290
291 var nestedJob = new NestedContainerJob
292 {
293 nestedContainer = container
294 };
295
296 JobHandle job = default;
297 Assert.Throws<System.InvalidOperationException>(() => { job = nestedJob.Schedule(); });
298 job.Complete();
299
300 container.Dispose();
301 }
302}