A game about forced loneliness, made by TACStudios
1using System;
2using NUnit.Framework;
3using Unity.Collections;
4using Unity.Collections.LowLevel.Unsafe;
5using System.Text;
6using Unity.Burst;
7using Unity.Jobs;
8
9namespace Unity.Collections.Tests
10{
11 internal class NativeTextTests
12 {
13 [Test]
14 public void NativeTextFixedStringCtors()
15 {
16 using (NativeText aa = new NativeText(new FixedString32Bytes("test32"), Allocator.Temp))
17 {
18 Assert.True(aa != new FixedString32Bytes("test"));
19 Assert.True(aa.Value == "test32");
20 Assert.AreEqual("test32", aa);
21 }
22
23 using (NativeText aa = new NativeText(new FixedString64Bytes("test64"), Allocator.Temp))
24 {
25 Assert.True(aa != new FixedString64Bytes("test"));
26 Assert.True(aa.Value == "test64");
27 Assert.AreEqual("test64", aa);
28 }
29
30 using (NativeText aa = new NativeText(new FixedString128Bytes("test128"), Allocator.Temp))
31 {
32 Assert.True(aa != new FixedString128Bytes("test"));
33 Assert.True(aa.Value == "test128");
34 Assert.AreEqual("test128", aa);
35 }
36
37 using (NativeText aa = new NativeText(new FixedString512Bytes("test512"), Allocator.Temp))
38 {
39 Assert.True(aa != new FixedString512Bytes("test"));
40 Assert.True(aa.Value == "test512");
41 Assert.AreEqual("test512", aa);
42 }
43
44 using (NativeText aa = new NativeText(new FixedString4096Bytes("test4096"), Allocator.Temp))
45 {
46 Assert.True(aa != new FixedString4096Bytes("test"));
47 Assert.True(aa.Value == "test4096");
48 Assert.AreEqual("test4096", aa);
49 }
50
51 using (NativeText aa = new NativeText("testString", Allocator.Temp))
52 {
53 var s = "testString";
54 Assert.AreEqual(aa, s);
55 Assert.True(aa.Value == "testString");
56 Assert.AreEqual("testString", aa);
57 }
58 }
59
60 [Test]
61 public void NativeTextCorrectLengthAfterClear()
62 {
63 NativeText aa = new NativeText(4, Allocator.Temp);
64 Assert.True(aa.IsCreated);
65 Assert.AreEqual(0, aa.Length, "Length after creation is not 0");
66 aa.AssertNullTerminated();
67
68 aa.Junk();
69
70 aa.Clear();
71 Assert.AreEqual(0, aa.Length, "Length after clear is not 0");
72 aa.AssertNullTerminated();
73
74 aa.Dispose();
75 }
76
77 [Test]
78 public void NativeTextFormatExtension1Params()
79 {
80 NativeText aa = new NativeText(4, Allocator.Temp);
81 Assert.True(aa.IsCreated);
82 aa.Junk();
83 FixedString32Bytes format = "{0}";
84 FixedString32Bytes arg0 = "a";
85 aa.AppendFormat(format, arg0);
86 aa.Add(0x61);
87 Assert.AreEqual("aa", aa);
88 aa.AssertNullTerminated();
89 aa.Dispose();
90 }
91
92
93 [Test]
94 public void NativeTextFormatExtension2Params()
95 {
96 NativeText aa = new NativeText(4, Allocator.Temp);
97 aa.Junk();
98 FixedString32Bytes format = "{0} {1}";
99 FixedString32Bytes arg0 = "a";
100 FixedString32Bytes arg1 = "b";
101 aa.AppendFormat(format, arg0, arg1);
102 Assert.AreEqual("a b", aa);
103 aa.AssertNullTerminated();
104 aa.Dispose();
105 }
106
107
108 [Test]
109 public void NativeTextFormatExtension3Params()
110 {
111 NativeText aa = new NativeText(4, Allocator.Temp);
112 aa.Junk();
113 FixedString32Bytes format = "{0} {1} {2}";
114 FixedString32Bytes arg0 = "a";
115 FixedString32Bytes arg1 = "b";
116 FixedString32Bytes arg2 = "c";
117 aa.AppendFormat(format, arg0, arg1, arg2);
118 Assert.AreEqual("a b c", aa);
119 aa.AssertNullTerminated();
120 aa.Dispose();
121 }
122
123
124 [Test]
125 public void NativeTextFormatExtension4Params()
126 {
127 NativeText aa = new NativeText(Allocator.Temp);
128 aa.Junk();
129 FixedString32Bytes format = "{0} {1} {2} {3}";
130 FixedString32Bytes arg0 = "a";
131 FixedString32Bytes arg1 = "b";
132 FixedString32Bytes arg2 = "c";
133 FixedString32Bytes arg3 = "d";
134 aa.AppendFormat(format, arg0, arg1, arg2, arg3);
135 Assert.AreEqual("a b c d", aa);
136 aa.AssertNullTerminated();
137 aa.Dispose();
138 }
139
140
141 [Test]
142 public void NativeTextFormatExtension5Params()
143 {
144 NativeText aa = new NativeText(4, Allocator.Temp);
145 aa.Junk();
146 FixedString32Bytes format = "{0} {1} {2} {3} {4}";
147 FixedString32Bytes arg0 = "a";
148 FixedString32Bytes arg1 = "b";
149 FixedString32Bytes arg2 = "c";
150 FixedString32Bytes arg3 = "d";
151 FixedString32Bytes arg4 = "e";
152 aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4);
153 Assert.AreEqual("a b c d e", aa);
154 aa.AssertNullTerminated();
155 aa.Dispose();
156 }
157
158
159 [Test]
160 public void NativeTextFormatExtension6Params()
161 {
162 NativeText aa = new NativeText(4, Allocator.Temp);
163 aa.Junk();
164 FixedString32Bytes format = "{0} {1} {2} {3} {4} {5}";
165 FixedString32Bytes arg0 = "a";
166 FixedString32Bytes arg1 = "b";
167 FixedString32Bytes arg2 = "c";
168 FixedString32Bytes arg3 = "d";
169 FixedString32Bytes arg4 = "e";
170 FixedString32Bytes arg5 = "f";
171 aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5);
172 Assert.AreEqual("a b c d e f", aa);
173 aa.AssertNullTerminated();
174 aa.Dispose();
175 }
176
177
178 [Test]
179 public void NativeTextFormatExtension7Params()
180 {
181 NativeText aa = new NativeText(4, Allocator.Temp);
182 aa.Junk();
183 FixedString32Bytes format = "{0} {1} {2} {3} {4} {5} {6}";
184 FixedString32Bytes arg0 = "a";
185 FixedString32Bytes arg1 = "b";
186 FixedString32Bytes arg2 = "c";
187 FixedString32Bytes arg3 = "d";
188 FixedString32Bytes arg4 = "e";
189 FixedString32Bytes arg5 = "f";
190 FixedString32Bytes arg6 = "g";
191 aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
192 Assert.AreEqual("a b c d e f g", aa);
193 aa.AssertNullTerminated();
194 aa.Dispose();
195 }
196
197
198 [Test]
199 public void NativeTextFormatExtension8Params()
200 {
201 NativeText aa = new NativeText(4, Allocator.Temp);
202 aa.Junk();
203 FixedString128Bytes format = "{0} {1} {2} {3} {4} {5} {6} {7}";
204 FixedString32Bytes arg0 = "a";
205 FixedString32Bytes arg1 = "b";
206 FixedString32Bytes arg2 = "c";
207 FixedString32Bytes arg3 = "d";
208 FixedString32Bytes arg4 = "e";
209 FixedString32Bytes arg5 = "f";
210 FixedString32Bytes arg6 = "g";
211 FixedString32Bytes arg7 = "h";
212 aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
213 Assert.AreEqual("a b c d e f g h", aa);
214 aa.AssertNullTerminated();
215 aa.Dispose();
216 }
217
218
219 [Test]
220 public void NativeTextFormatExtension9Params()
221 {
222 NativeText aa = new NativeText(4, Allocator.Temp);
223 aa.Junk();
224 FixedString128Bytes format = "{0} {1} {2} {3} {4} {5} {6} {7} {8}";
225 FixedString32Bytes arg0 = "a";
226 FixedString32Bytes arg1 = "b";
227 FixedString32Bytes arg2 = "c";
228 FixedString32Bytes arg3 = "d";
229 FixedString32Bytes arg4 = "e";
230 FixedString32Bytes arg5 = "f";
231 FixedString32Bytes arg6 = "g";
232 FixedString32Bytes arg7 = "h";
233 FixedString32Bytes arg8 = "i";
234 aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
235 Assert.AreEqual("a b c d e f g h i", aa);
236 aa.AssertNullTerminated();
237 aa.Dispose();
238 }
239
240
241 [Test]
242 public void NativeTextFormatExtension10Params()
243 {
244 NativeText aa = new NativeText(4, Allocator.Temp);
245 aa.Junk();
246 FixedString128Bytes format = "{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}";
247 FixedString32Bytes arg0 = "a";
248 FixedString32Bytes arg1 = "b";
249 FixedString32Bytes arg2 = "c";
250 FixedString32Bytes arg3 = "d";
251 FixedString32Bytes arg4 = "e";
252 FixedString32Bytes arg5 = "f";
253 FixedString32Bytes arg6 = "g";
254 FixedString32Bytes arg7 = "h";
255 FixedString32Bytes arg8 = "i";
256 FixedString32Bytes arg9 = "j";
257 aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
258 Assert.AreEqual("a b c d e f g h i j", aa);
259 aa.AssertNullTerminated();
260 aa.Dispose();
261 }
262
263 [Test]
264 public void NativeTextAppendGrows()
265 {
266 NativeText aa = new NativeText(1, Allocator.Temp);
267 var origCapacity = aa.Capacity;
268 for (int i = 0; i < origCapacity; ++i)
269 aa.Append('a');
270 Assert.AreEqual(origCapacity, aa.Capacity);
271 aa.Append('b');
272 Assert.GreaterOrEqual(aa.Capacity, origCapacity);
273 Assert.AreEqual(new String('a', origCapacity) + "b", aa.ToString());
274 aa.Dispose();
275 }
276
277 [Test]
278 public void NativeTextAppendString()
279 {
280 NativeText aa = new NativeText(4, Allocator.Temp);
281 aa.Append("aa");
282 Assert.AreEqual("aa", aa.ToString());
283 aa.Append("bb");
284 Assert.AreEqual("aabb", aa.ToString());
285 aa.Dispose();
286 }
287
288
289 [TestCase("Antidisestablishmentarianism")]
290 [TestCase("🌹🌻🌷🌿🌵🌾")]
291 public void NativeTextCopyFromBytesWorks(String a)
292 {
293 NativeText aa = new NativeText(4, Allocator.Temp);
294 aa.Junk();
295 var utf8 = Encoding.UTF8.GetBytes(a);
296 unsafe
297 {
298 fixed (byte* b = utf8)
299 aa.Append(b, (ushort) utf8.Length);
300 }
301
302 Assert.AreEqual(a, aa.ToString());
303 aa.AssertNullTerminated();
304
305 aa.Append("tail");
306 Assert.AreEqual(a + "tail", aa.ToString());
307 aa.AssertNullTerminated();
308
309 aa.Dispose();
310 }
311
312 [TestCase("red")]
313 [TestCase("紅色", TestName = "{m}(Chinese-Red)")]
314 [TestCase("George Washington")]
315 [TestCase("村上春樹", TestName = "{m}(HarukiMurakami)")]
316 public void NativeTextToStringWorks(String a)
317 {
318 NativeText aa = new NativeText(4, Allocator.Temp);
319 aa.Append(new FixedString128Bytes(a));
320 Assert.AreEqual(a, aa.ToString());
321 aa.AssertNullTerminated();
322 aa.Dispose();
323 }
324
325 [TestCase("monkey", "monkey")]
326 [TestCase("yellow", "green")]
327 [TestCase("violet", "紅色", TestName = "{m}(Violet-Chinese-Red")]
328 [TestCase("绿色", "蓝色", TestName = "{m}(Chinese-Green-Blue")]
329 [TestCase("靛蓝色", "紫罗兰色", TestName = "{m}(Chinese-Indigo-Violet")]
330 [TestCase("James Monroe", "John Quincy Adams")]
331 [TestCase("Andrew Jackson", "村上春樹", TestName = "{m}(AndrewJackson-HarukiMurakami")]
332 [TestCase("三島 由紀夫", "吉本ばなな", TestName = "{m}(MishimaYukio-YoshimotoBanana")]
333 public void NativeTextEqualsWorks(String a, String b)
334 {
335 using (var aa = new NativeText(new FixedString128Bytes(a), Allocator.Temp))
336 using (var bb = new NativeText(new FixedString128Bytes(b), Allocator.Temp))
337 {
338 Assert.AreEqual(aa.Equals(bb), a.Equals(b));
339 aa.AssertNullTerminated();
340 bb.AssertNullTerminated();
341 }
342 }
343
344 [Test]
345 public void NativeTextForEach()
346 {
347 NativeText actual = new NativeText("A🌕Z🌑D𒁃 𒁃𒁃𒁃𒁃𒁃", Allocator.Temp);
348 FixedList128Bytes<uint> expected = default;
349 expected.Add('A');
350 expected.Add(0x1F315);
351 expected.Add('Z');
352 expected.Add(0x1F311);
353 expected.Add('D');
354 expected.Add(0x12043);
355 expected.Add(' ');
356 expected.Add(0x12043);
357 expected.Add(0x12043);
358 expected.Add(0x12043);
359 expected.Add(0x12043);
360 expected.Add(0x12043);
361 int index = 0;
362 foreach (var rune in actual)
363 {
364 Assert.AreEqual(expected[index], rune.value);
365 ++index;
366 }
367
368 actual.Dispose();
369 }
370
371 [Test]
372 public void NativeTextNSubstring()
373 {
374 NativeText a = new NativeText("This is substring.", Allocator.Temp);
375
376#if ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG
377 Assert.Throws<ArgumentOutOfRangeException>(() => a.Substring(-8, 9));
378 Assert.Throws<ArgumentOutOfRangeException>(() => a.Substring(200, 9));
379 Assert.Throws<ArgumentOutOfRangeException>(() => a.Substring(8, -9));
380#endif
381
382 {
383 NativeText b = a.Substring(8, 9);
384 Assert.IsTrue(b.Equals("substring"));
385 }
386
387 {
388 NativeText b = a.Substring(8, 100);
389 Assert.IsTrue(b.Equals("substring."));
390 }
391 }
392
393 [Test]
394 public void NativeTextIndexOf()
395 {
396 NativeText a = new NativeText("bookkeeper bookkeeper", Allocator.Temp);
397 NativeText b = new NativeText("ookkee", Allocator.Temp);
398 Assert.AreEqual(1, a.IndexOf(b));
399 Assert.AreEqual(-1, b.IndexOf(a));
400 a.Dispose();
401 b.Dispose();
402 }
403
404 [Test]
405 public void NativeTextLastIndexOf()
406 {
407 NativeText a = new NativeText("bookkeeper bookkeeper", Allocator.Temp);
408 NativeText b = new NativeText("ookkee", Allocator.Temp);
409 Assert.AreEqual(12, a.LastIndexOf(b));
410 Assert.AreEqual(-1, b.LastIndexOf(a));
411 a.Dispose();
412 b.Dispose();
413 }
414
415 [Test]
416 public void NativeTextContains()
417 {
418 NativeText a = new NativeText("bookkeeper", Allocator.Temp);
419 NativeText b = new NativeText("ookkee", Allocator.Temp);
420 Assert.AreEqual(true, a.Contains(b));
421 a.Dispose();
422 b.Dispose();
423 }
424
425 [Test]
426 public void NativeTextComparisons()
427 {
428 using (var a = new NativeText("apple", Allocator.Temp))
429 using (var b = new NativeText("banana", Allocator.Temp))
430 {
431 Assert.AreEqual(false, a.Equals(b));
432 Assert.AreEqual(true, !b.Equals(a));
433 }
434 }
435
436 [Test]
437 public void NativeTextCustomAllocatorTest()
438 {
439 AllocatorManager.Initialize();
440 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
441 ref var allocator = ref allocatorHelper.Allocator;
442 allocator.Initialize();
443
444 using (var container = new NativeText(allocator.Handle))
445 {
446 }
447
448 Assert.IsTrue(allocator.WasUsed);
449 allocator.Dispose();
450 allocatorHelper.Dispose();
451 AllocatorManager.Shutdown();
452 }
453
454 [BurstCompile]
455 struct BurstedCustomAllocatorJob : IJob
456 {
457 [NativeDisableUnsafePtrRestriction]
458 public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
459
460 public void Execute()
461 {
462 unsafe
463 {
464 using (var container = new NativeText(Allocator->Handle))
465 {
466 }
467 }
468 }
469 }
470
471 [Test]
472 public unsafe void NativeTextBurstedCustomAllocatorTest()
473 {
474 AllocatorManager.Initialize();
475 var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
476 ref var allocator = ref allocatorHelper.Allocator;
477 allocator.Initialize();
478
479 var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
480 unsafe
481 {
482 var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
483 handle.Complete();
484 }
485
486 Assert.IsTrue(allocator.WasUsed);
487 allocator.Dispose();
488 allocatorHelper.Dispose();
489 AllocatorManager.Shutdown();
490 }
491
492 [Test]
493 public void NativeTextIsEmpty()
494 {
495 var a = new NativeText("", Allocator.Temp);
496 Assert.IsTrue(a.IsEmpty);
497 a.CopyFrom("hello");
498 Assert.IsFalse(a.IsEmpty);
499 a.Dispose();
500 }
501
502 [Test]
503 public void NativeTextIsEmptyReturnsTrueForNotConstructed()
504 {
505 NativeText a = default;
506 Assert.IsTrue(a.IsEmpty);
507 }
508
509 [Test]
510 public void NativeTextReadonlyCtor()
511 {
512 using (NativeText aa = new NativeText(new FixedString32Bytes("test32"), Allocator.Temp))
513 {
514 var ro = aa.AsReadOnly();
515 Assert.True(ro != new FixedString32Bytes("test"));
516 Assert.True(ro.Value == "test32");
517 Assert.AreEqual("test32", ro);
518 }
519
520 using (NativeText aa = new NativeText(new FixedString64Bytes("test64"), Allocator.Temp))
521 {
522 var ro = aa.AsReadOnly();
523 Assert.True(ro != new FixedString64Bytes("test"));
524 Assert.True(ro.Value == "test64");
525 Assert.AreEqual("test64", ro);
526 }
527
528 using (NativeText aa = new NativeText(new FixedString128Bytes("test128"), Allocator.Temp))
529 {
530 var ro = aa.AsReadOnly();
531 Assert.True(ro != new FixedString128Bytes("test"));
532 Assert.True(ro.Value == "test128");
533 Assert.AreEqual("test128", ro);
534 }
535
536 using (NativeText aa = new NativeText(new FixedString512Bytes("test512"), Allocator.Temp))
537 {
538 var ro = aa.AsReadOnly();
539 Assert.True(ro != new FixedString512Bytes("test"));
540 Assert.True(ro.Value == "test512");
541 Assert.AreEqual("test512", ro);
542 }
543
544 using (NativeText aa = new NativeText(new FixedString4096Bytes("test4096"), Allocator.Temp))
545 {
546 var ro = aa.AsReadOnly();
547 Assert.True(ro != new FixedString4096Bytes("test"));
548 Assert.True(ro.Value == "test4096");
549 Assert.AreEqual("test4096", ro);
550 }
551
552 using (var aa = new NativeText("Hello", Allocator.Temp))
553 {
554 var ro = aa.AsReadOnly();
555
556 Assert.AreEqual(aa.Equals(ro), ro.Equals(aa));
557 aa.AssertNullTerminated();
558 ro.AssertNullTerminated();
559 }
560 }
561
562 [TestCase("monkey", "monkey")]
563 [TestCase("yellow", "green")]
564 [TestCase("violet", "紅色", TestName = "{m}(Violet-Chinese-Red")]
565 [TestCase("绿色", "蓝色", TestName = "{m}(Chinese-Green-Blue")]
566 [TestCase("靛蓝色", "紫罗兰色", TestName = "{m}(Chinese-Indigo-Violet")]
567 [TestCase("James Monroe", "John Quincy Adams")]
568 [TestCase("Andrew Jackson", "村上春樹", TestName = "{m}(AndrewJackson-HarukiMurakami")]
569 [TestCase("三島 由紀夫", "吉本ばなな", TestName = "{m}(MishimaYukio-YoshimotoBanana")]
570 public void NativeTextReadOnlyEqualsWorks(String a, String b)
571 {
572 using (var aa = new NativeText(new FixedString128Bytes(a), Allocator.Temp))
573 using (var bb = new NativeText(new FixedString128Bytes(b), Allocator.Temp))
574 {
575 var aaRO = aa.AsReadOnly();
576 var bbRO = bb.AsReadOnly();
577 Assert.AreEqual(aaRO.Equals(bbRO), a.Equals(b));
578 aaRO.AssertNullTerminated();
579 bbRO.AssertNullTerminated();
580 }
581 }
582
583 [Test]
584 public void NativeTextReadOnlyIndexOf()
585 {
586 using (var a = new NativeText("bookkeeper bookkeeper", Allocator.Temp))
587 using (var b = new NativeText("ookkee", Allocator.Temp))
588 {
589 var aRO = a.AsReadOnly();
590 var bRO = b.AsReadOnly();
591 Assert.AreEqual(1, aRO.IndexOf(bRO));
592 Assert.AreEqual(-1, bRO.IndexOf(aRO));
593 }
594 }
595
596 [Test]
597 public void NativeTextReadOnlyLastIndexOf()
598 {
599 using (var a = new NativeText("bookkeeper bookkeeper", Allocator.Temp))
600 using (var b = new NativeText("ookkee", Allocator.Temp))
601 {
602 var aRO = a.AsReadOnly();
603 var bRO = b.AsReadOnly();
604 Assert.AreEqual(12, aRO.LastIndexOf(bRO));
605 Assert.AreEqual(-1, bRO.LastIndexOf(aRO));
606 }
607 }
608
609 [Test]
610 public void NativeTextReadOnlyContains()
611 {
612 using (var a = new NativeText("bookkeeper", Allocator.Temp))
613 using (var b = new NativeText("ookkee", Allocator.Temp))
614 {
615 var aRO = a.AsReadOnly();
616 var bRO = b.AsReadOnly();
617 Assert.AreEqual(true, aRO.Contains(bRO));
618 }
619 }
620
621 [Test]
622 public void NativeTextReadOnlyComparisons()
623 {
624 using (var a = new NativeText("apple", Allocator.Temp))
625 using (var b = new NativeText("banana", Allocator.Temp))
626 {
627 var aRO = a.AsReadOnly();
628 var bRO = b.AsReadOnly();
629 Assert.AreEqual(false, aRO.Equals(bRO));
630 Assert.AreEqual(true, !bRO.Equals(aRO));
631 }
632 }
633
634 [Test]
635 public void NativeTextReadOnlyMakeMoreThanOne()
636 {
637 using (var a = new NativeText("apple", Allocator.Temp))
638 {
639 var aRO1 = a.AsReadOnly();
640 var aRO2 = a.AsReadOnly();
641 Assert.IsTrue(a.Equals(aRO1));
642 Assert.IsTrue(aRO1.Equals(aRO2));
643 Assert.IsTrue(aRO2.Equals(aRO1));
644 }
645 }
646
647 [Test]
648 public void NativeTextReadOnlyIsNotACopy()
649 {
650 using (var a = new NativeText("apple", Allocator.Temp))
651 {
652 var aRO = a.AsReadOnly();
653 Assert.AreEqual(true, aRO.Equals(a));
654
655 unsafe
656 {
657 Assert.IsTrue(aRO.GetUnsafePtr() == a.GetUnsafePtr());
658 }
659 }
660 }
661
662
663 [Test]
664 public void NativeTextReadOnlyIsEmpty()
665 {
666 var a = new NativeText("", Allocator.Temp);
667 var aRO = a.AsReadOnly();
668 Assert.IsTrue(aRO.IsEmpty);
669 a.Dispose();
670
671 a = new NativeText("not empty", Allocator.Temp);
672 aRO = a.AsReadOnly();
673 Assert.IsFalse(aRO.IsEmpty);
674 a.Dispose();
675 }
676
677 [Test]
678 public void NativeTextReadOnlyIsEmptyReturnsTrueOrThrowsForNotConstructed()
679 {
680 NativeText.ReadOnly aRO = default;
681 Assert.IsTrue(aRO.IsEmpty);
682
683#if ENABLE_UNITY_COLLECTIONS_CHECKS
684 NativeText aa = default;
685 NativeText.ReadOnly aaRO = aa.AsReadOnly();
686 Assert.IsTrue(aaRO.IsEmpty);
687#endif
688 }
689
690 [Test]
691 [TestRequiresDotsDebugOrCollectionChecks]
692 public void NativeTextReadOnlyIsNotWritable()
693 {
694 using (var a = new NativeText("apple", Allocator.Temp))
695 {
696 var aRO = a.AsReadOnly();
697 Assert.AreEqual(true, aRO.Equals(a));
698
699 Assert.Throws<NotSupportedException>(() => { aRO.IsEmpty = true; });
700 Assert.Throws<NotSupportedException>(() => { aRO.Length = 0; });
701 Assert.Throws<NotSupportedException>(() => { aRO.Capacity = 0; });
702 Assert.Throws<NotSupportedException>(() => { aRO.ElementAt(0); });
703 Assert.Throws<NotSupportedException>(() => { aRO.Clear(); });
704 Assert.Throws<NotSupportedException>(() => { aRO.Append("won't work"); });
705 FixedString32Bytes format = "{0}";
706 FixedString32Bytes arg0 = "a";
707 Assert.Throws<NotSupportedException>(() => { aRO.AppendFormat(format, arg0); });
708 Assert.Throws<NotSupportedException>(() => { aRO.AppendRawByte(1); });
709 Assert.Throws<NotSupportedException>(() => { aRO.TryResize(0); });
710 }
711 }
712
713 [Test]
714 public void NativeTextReadOnlyCannotBeUsedAfterSourceIsDisposed()
715 {
716 AllocatorManager.Initialize();
717 using (var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent))
718 {
719 ref var allocator = ref allocatorHelper.Allocator;
720 allocator.Initialize();
721
722 var a = new NativeText("Keep it secret, ", allocator.Handle);
723 var ro = a.AsReadOnly();
724 a.Dispose(); // Invalidate the string we are referring to
725#if ENABLE_UNITY_COLLECTIONS_CHECKS
726 Assert.Throws<ObjectDisposedException>(() => { UnityEngine.Debug.Log(ro.ToString()); });
727#endif
728
729 Assert.IsTrue(allocator.WasUsed);
730 allocator.Dispose();
731 }
732
733 AllocatorManager.Shutdown();
734 }
735
736 [Test]
737 public void NativeTextReadOnlyCannotBeUsedAfterSourceIsChanged()
738 {
739 AllocatorManager.Initialize();
740 using (var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent))
741 {
742 ref var allocator = ref allocatorHelper.Allocator;
743 allocator.Initialize();
744
745 var a = new NativeText("Keep it secret, ", allocator.Handle);
746 var ro = a.AsReadOnly();
747
748 a.Clear(); // Change the string we are referring to
749
750 Assert.DoesNotThrow(() => { UnityEngine.Debug.Log(ro.ToString()); });
751
752 a.Dispose();
753
754#if ENABLE_UNITY_COLLECTIONS_CHECKS
755 Assert.Throws<ObjectDisposedException>(() => { UnityEngine.Debug.Log(ro.ToString()); });
756#endif
757
758 Assert.IsTrue(allocator.WasUsed);
759 allocator.Dispose();
760 }
761
762 AllocatorManager.Shutdown();
763 }
764
765
766 [Test]
767 [TestRequiresCollectionChecks]
768 public void NativeTextReadOnlyModificationDuringEnumerationThrows()
769 {
770 AllocatorManager.Initialize();
771 using (var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent))
772 {
773 ref var allocator = ref allocatorHelper.Allocator;
774 allocator.Initialize();
775
776 var a = new NativeText("Keep it secret, ", allocator.Handle);
777 var ro = a.AsReadOnly();
778
779 int iterations = 0;
780 Assert.Throws<ObjectDisposedException>(() =>
781 {
782 // Mutate the source string while iterating. Can append once but when we use the iterator
783 // again it will now be invalid and should throw
784 foreach (var c in ro)
785 {
786 iterations++;
787 a.Append("keep it safe, ");
788 }
789 });
790 Assert.AreEqual(1, iterations);
791
792 a.Dispose();
793
794 Assert.IsTrue(allocator.WasUsed);
795 allocator.Dispose();
796 }
797
798 AllocatorManager.Shutdown();
799 }
800
801 struct TestWriteOfTextMappedToReadOnly : IJob
802 {
803 public NativeText Text;
804 public void Execute() { }
805 }
806
807 struct TestClearTextMappedToReadOnly : IJob
808 {
809 public NativeText Text;
810 public void Execute()
811 {
812 Text.Clear();
813 }
814 }
815
816 [Test]
817 [TestRequiresCollectionChecks]
818 public void NativeTextReadOnlyCannotScheduledSourceTextForWrite()
819 {
820 AllocatorManager.Initialize();
821 using (var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent))
822 {
823 ref var allocator = ref allocatorHelper.Allocator;
824 allocator.Initialize();
825
826 var a = new NativeText("Keep it secret, ", allocator.Handle);
827 var ro = a.AsReadOnly();
828 var job = new TestWriteOfTextMappedToReadOnly
829 {
830 Text = a
831 };
832
833 var handle = job.Schedule();
834
835 Assert.Throws<InvalidOperationException>(() =>
836 {
837 UnityEngine.Debug.Log(ro.ToString());
838 });
839
840 Assert.Throws<InvalidOperationException>(() =>
841 {
842 a.Dispose();
843 });
844 handle.Complete();
845
846 a.Dispose();
847
848 Assert.IsTrue(allocator.WasUsed);
849 allocator.Dispose();
850 }
851
852 AllocatorManager.Shutdown();
853 }
854
855 [Test]
856 public void NativeTextReadOnlyCanReadFromSourceTextModifiedInJob()
857 {
858 AllocatorManager.Initialize();
859 using (var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent))
860 {
861 ref var allocator = ref allocatorHelper.Allocator;
862 allocator.Initialize();
863
864 var a = new NativeText("Keep it secret, ", allocator.Handle);
865 var ro = a.AsReadOnly();
866 var job = new TestClearTextMappedToReadOnly
867 {
868 Text = a
869 };
870
871 var handle = job.Schedule();
872 handle.Complete();
873
874 Assert.DoesNotThrow(() =>
875 {
876 UnityEngine.Debug.Log(ro.ToString());
877 });
878
879 a.Dispose();
880
881 Assert.IsTrue(allocator.WasUsed);
882 allocator.Dispose();
883 }
884
885 AllocatorManager.Shutdown();
886 }
887
888 struct TestReadOfTextMappedToReadOnly : IJob
889 {
890 [ReadOnly]
891 public NativeText Text;
892 public void Execute() { }
893 }
894
895 [Test]
896 public void NativeTextReadOnlyCanScheduledSourceTextForRead()
897 {
898 AllocatorManager.Initialize();
899 using (var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent))
900 {
901 ref var allocator = ref allocatorHelper.Allocator;
902 allocator.Initialize();
903
904 var a = new NativeText("Keep it secret, ", allocator.Handle);
905 var ro = a.AsReadOnly();
906 var job = new TestReadOfTextMappedToReadOnly
907 {
908 Text = a
909 };
910
911 Assert.DoesNotThrow(() =>
912 {
913 job.Schedule().Complete();
914 });
915
916 a.Dispose();
917
918 Assert.IsTrue(allocator.WasUsed);
919 allocator.Dispose();
920 }
921
922 AllocatorManager.Shutdown();
923 }
924
925 struct TestReadFromReadOnly : IJob
926 {
927 [ReadOnly] public NativeText.ReadOnly RO;
928 public void Execute()
929 {
930 UnityEngine.Debug.Log($"{RO.Length}");
931 }
932 }
933
934 [Test]
935 [TestRequiresCollectionChecks]
936 public void NativeTextReadOnlyThrowWhenUsingReadOnlyInJobAfterSourceHasBeenDisposed()
937 {
938 AllocatorManager.Initialize();
939 using (var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent))
940 {
941 ref var allocator = ref allocatorHelper.Allocator;
942 allocator.Initialize();
943
944 var a = new NativeText("Keep it secret, ", allocator.Handle);
945 var job = new TestReadFromReadOnly
946 {
947 RO = a.AsReadOnly()
948 };
949
950 var handle = job.Schedule();
951
952 Assert.Throws<InvalidOperationException>(() =>
953 {
954 a.Dispose();
955 });
956
957 handle.Complete();
958 a.Dispose();
959
960 Assert.IsTrue(allocator.WasUsed);
961 allocator.Dispose();
962 }
963
964 AllocatorManager.Shutdown();
965 }
966 }
967}