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}