Bez popisu
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.

UnsafeTextTests.cs 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. using System;
  2. using NUnit.Framework;
  3. using Unity.Collections;
  4. using Unity.Collections.LowLevel.Unsafe;
  5. using System.Text;
  6. using Unity.Burst;
  7. using Unity.Jobs;
  8. namespace Unity.Collections.Tests
  9. {
  10. internal class UnsafeTextTests
  11. {
  12. void AssertAreEqualInTest(string expected, in UnsafeText actual)
  13. {
  14. var actualString = actual.ToString();
  15. Assert.AreEqual(expected, actualString);
  16. }
  17. // NOTE: If you call this function from Mono and T is not marshalable - your app (Editor or the player built with Mono scripting backend) could/will crash.
  18. bool IsMarshalable<T>() where T : unmanaged
  19. {
  20. try
  21. {
  22. unsafe
  23. {
  24. var size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
  25. IntPtr memoryIntPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size);
  26. try
  27. {
  28. var obj = new T();
  29. System.Runtime.InteropServices.Marshal.StructureToPtr(obj, memoryIntPtr, false);
  30. System.Runtime.InteropServices.Marshal.DestroyStructure<T>(memoryIntPtr);
  31. }
  32. finally
  33. {
  34. System.Runtime.InteropServices.Marshal.FreeHGlobal(memoryIntPtr);
  35. }
  36. return true;
  37. }
  38. }
  39. catch (Exception e)
  40. {
  41. UnityEngine.Debug.LogError("ERROR in IsMarshalable<" + typeof(T).FullName + "> " + e);
  42. return false;
  43. }
  44. }
  45. [Test]
  46. public void UnsafeTextIsMarshalable()
  47. {
  48. var result = IsMarshalable<UnsafeText>();
  49. Assert.IsTrue(result);
  50. }
  51. [Test]
  52. public unsafe void UnsafeTextCorrectBinaryHeader()
  53. {
  54. var text = new UnsafeText(42, Allocator.Persistent);
  55. var ptr = text.GetUnsafePtr();
  56. Assert.AreEqual(0 + 1, text.m_UntypedListData.m_length);
  57. Assert.AreEqual(Allocator.Persistent, text.m_UntypedListData.Allocator.ToAllocator);
  58. Assert.IsTrue(ptr == text.m_UntypedListData.Ptr, "ptr != text.m_UntypedListData.Ptr");
  59. var listOfBytesCast = text.AsUnsafeListOfBytes();
  60. Assert.AreEqual(0 + 1, listOfBytesCast.Length);
  61. Assert.AreEqual(Allocator.Persistent, listOfBytesCast.Allocator.ToAllocator);
  62. Assert.IsTrue(ptr == listOfBytesCast.Ptr, "ptr != listOfBytesCast.Ptr");
  63. Assert.AreEqual(text.m_UntypedListData.m_capacity, listOfBytesCast.Capacity);
  64. text.Dispose();
  65. }
  66. [Test]
  67. public void UnsafeTextCorrectLengthAfterClear()
  68. {
  69. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  70. Assert.True(aa.IsCreated);
  71. Assert.AreEqual(0, aa.Length, "Length after creation is not 0");
  72. aa.AssertNullTerminated();
  73. aa.Junk();
  74. aa.Clear();
  75. Assert.AreEqual(0, aa.Length, "Length after clear is not 0");
  76. aa.AssertNullTerminated();
  77. aa.Dispose();
  78. }
  79. [Test]
  80. public void UnsafeTextFormatExtension1Params()
  81. {
  82. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  83. Assert.True(aa.IsCreated);
  84. aa.Junk();
  85. FixedString32Bytes format = "{0}";
  86. FixedString32Bytes arg0 = "a";
  87. aa.AppendFormat(format, arg0);
  88. aa.Append('a');
  89. aa.AssertNullTerminated();
  90. AssertAreEqualInTest("aa", aa);
  91. aa.Dispose();
  92. }
  93. [Test]
  94. public void UnsafeTextFormatExtension2Params()
  95. {
  96. UnsafeText aa = new UnsafeText(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. AssertAreEqualInTest("a b", aa);
  103. aa.AssertNullTerminated();
  104. aa.Dispose();
  105. }
  106. [Test]
  107. public void UnsafeTextFormatExtension3Params()
  108. {
  109. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  110. aa.Junk();
  111. FixedString32Bytes format = "{0} {1} {2}";
  112. FixedString32Bytes arg0 = "a";
  113. FixedString32Bytes arg1 = "b";
  114. FixedString32Bytes arg2 = "c";
  115. aa.AppendFormat(format, arg0, arg1, arg2);
  116. AssertAreEqualInTest("a b c", aa);
  117. aa.AssertNullTerminated();
  118. aa.Dispose();
  119. }
  120. [Test]
  121. public void UnsafeTextFormatExtension4Params()
  122. {
  123. UnsafeText aa = new UnsafeText(512, Allocator.Temp);
  124. aa.Junk();
  125. FixedString32Bytes format = "{0} {1} {2} {3}";
  126. FixedString32Bytes arg0 = "a";
  127. FixedString32Bytes arg1 = "b";
  128. FixedString32Bytes arg2 = "c";
  129. FixedString32Bytes arg3 = "d";
  130. aa.AppendFormat(format, arg0, arg1, arg2, arg3);
  131. AssertAreEqualInTest("a b c d", aa);
  132. aa.AssertNullTerminated();
  133. aa.Dispose();
  134. }
  135. [Test]
  136. public void UnsafeTextFormatExtension5Params()
  137. {
  138. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  139. aa.Junk();
  140. FixedString32Bytes format = "{0} {1} {2} {3} {4}";
  141. FixedString32Bytes arg0 = "a";
  142. FixedString32Bytes arg1 = "b";
  143. FixedString32Bytes arg2 = "c";
  144. FixedString32Bytes arg3 = "d";
  145. FixedString32Bytes arg4 = "e";
  146. aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4);
  147. AssertAreEqualInTest("a b c d e", aa);
  148. aa.AssertNullTerminated();
  149. aa.Dispose();
  150. }
  151. [Test]
  152. public void UnsafeTextFormatExtension6Params()
  153. {
  154. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  155. aa.Junk();
  156. FixedString32Bytes format = "{0} {1} {2} {3} {4} {5}";
  157. FixedString32Bytes arg0 = "a";
  158. FixedString32Bytes arg1 = "b";
  159. FixedString32Bytes arg2 = "c";
  160. FixedString32Bytes arg3 = "d";
  161. FixedString32Bytes arg4 = "e";
  162. FixedString32Bytes arg5 = "f";
  163. aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5);
  164. AssertAreEqualInTest("a b c d e f", aa);
  165. aa.AssertNullTerminated();
  166. aa.Dispose();
  167. }
  168. [Test]
  169. public void UnsafeTextFormatExtension7Params()
  170. {
  171. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  172. aa.Junk();
  173. FixedString32Bytes format = "{0} {1} {2} {3} {4} {5} {6}";
  174. FixedString32Bytes arg0 = "a";
  175. FixedString32Bytes arg1 = "b";
  176. FixedString32Bytes arg2 = "c";
  177. FixedString32Bytes arg3 = "d";
  178. FixedString32Bytes arg4 = "e";
  179. FixedString32Bytes arg5 = "f";
  180. FixedString32Bytes arg6 = "g";
  181. aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
  182. AssertAreEqualInTest("a b c d e f g", aa);
  183. aa.AssertNullTerminated();
  184. aa.Dispose();
  185. }
  186. [Test]
  187. public void UnsafeTextFormatExtension8Params()
  188. {
  189. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  190. aa.Junk();
  191. FixedString128Bytes format = "{0} {1} {2} {3} {4} {5} {6} {7}";
  192. FixedString32Bytes arg0 = "a";
  193. FixedString32Bytes arg1 = "b";
  194. FixedString32Bytes arg2 = "c";
  195. FixedString32Bytes arg3 = "d";
  196. FixedString32Bytes arg4 = "e";
  197. FixedString32Bytes arg5 = "f";
  198. FixedString32Bytes arg6 = "g";
  199. FixedString32Bytes arg7 = "h";
  200. aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
  201. AssertAreEqualInTest("a b c d e f g h", aa);
  202. aa.AssertNullTerminated();
  203. aa.Dispose();
  204. }
  205. [Test]
  206. public void UnsafeTextFormatExtension9Params()
  207. {
  208. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  209. aa.Junk();
  210. FixedString128Bytes format = "{0} {1} {2} {3} {4} {5} {6} {7} {8}";
  211. FixedString32Bytes arg0 = "a";
  212. FixedString32Bytes arg1 = "b";
  213. FixedString32Bytes arg2 = "c";
  214. FixedString32Bytes arg3 = "d";
  215. FixedString32Bytes arg4 = "e";
  216. FixedString32Bytes arg5 = "f";
  217. FixedString32Bytes arg6 = "g";
  218. FixedString32Bytes arg7 = "h";
  219. FixedString32Bytes arg8 = "i";
  220. aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
  221. AssertAreEqualInTest("a b c d e f g h i", aa);
  222. aa.AssertNullTerminated();
  223. aa.Dispose();
  224. }
  225. [Test]
  226. public void UnsafeTextFormatExtension10Params()
  227. {
  228. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  229. aa.Junk();
  230. FixedString128Bytes format = "{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}";
  231. FixedString32Bytes arg0 = "a";
  232. FixedString32Bytes arg1 = "b";
  233. FixedString32Bytes arg2 = "c";
  234. FixedString32Bytes arg3 = "d";
  235. FixedString32Bytes arg4 = "e";
  236. FixedString32Bytes arg5 = "f";
  237. FixedString32Bytes arg6 = "g";
  238. FixedString32Bytes arg7 = "h";
  239. FixedString32Bytes arg8 = "i";
  240. FixedString32Bytes arg9 = "j";
  241. aa.AppendFormat(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
  242. AssertAreEqualInTest("a b c d e f g h i j", aa);
  243. aa.AssertNullTerminated();
  244. aa.Dispose();
  245. }
  246. [Test]
  247. public void UnsafeTextAppendGrows()
  248. {
  249. UnsafeText aa = new UnsafeText(1, Allocator.Temp);
  250. var origCapacity = aa.Capacity;
  251. for (int i = 0; i < origCapacity; ++i)
  252. aa.Append('a');
  253. Assert.AreEqual(origCapacity, aa.Capacity);
  254. aa.Append('b');
  255. Assert.GreaterOrEqual(aa.Capacity, origCapacity);
  256. Assert.AreEqual(new String('a', origCapacity) + "b", aa.ToString());
  257. aa.Dispose();
  258. }
  259. [Test]
  260. public void UnsafeTextAppendString()
  261. {
  262. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  263. aa.Append("aa");
  264. Assert.AreEqual("aa", aa.ToString());
  265. aa.Append("bb");
  266. Assert.AreEqual("aabb", aa.ToString());
  267. aa.Dispose();
  268. }
  269. [TestCase("Antidisestablishmentarianism")]
  270. [TestCase("⁣🌹🌻🌷🌿🌵🌾⁣")]
  271. public void UnsafeTextCopyFromBytesWorks(String a)
  272. {
  273. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  274. aa.Junk();
  275. var utf8 = Encoding.UTF8.GetBytes(a);
  276. unsafe
  277. {
  278. fixed (byte* b = utf8)
  279. aa.Append(b, (ushort) utf8.Length);
  280. }
  281. Assert.AreEqual(a, aa.ToString());
  282. aa.AssertNullTerminated();
  283. aa.Append("tail");
  284. Assert.AreEqual(a + "tail", aa.ToString());
  285. aa.AssertNullTerminated();
  286. aa.Dispose();
  287. }
  288. [TestCase("red")]
  289. [TestCase("紅色", TestName = "{m}(Chinese-Red)")]
  290. [TestCase("George Washington")]
  291. [TestCase("村上春樹", TestName = "{m}(HarukiMurakami)")]
  292. public void UnsafeTextToStringWorks(String a)
  293. {
  294. UnsafeText aa = new UnsafeText(4, Allocator.Temp);
  295. aa.Append(new FixedString128Bytes(a));
  296. Assert.AreEqual(a, aa.ToString());
  297. aa.AssertNullTerminated();
  298. aa.Dispose();
  299. }
  300. [Test]
  301. public void UnsafeTextIndexOf()
  302. {
  303. UnsafeText a = new UnsafeText(16, Allocator.Temp);
  304. a.Append((FixedString64Bytes) "bookkeeper bookkeeper");
  305. UnsafeText b = new UnsafeText(8, Allocator.Temp);
  306. b.Append((FixedString32Bytes) "ookkee");
  307. Assert.AreEqual(1, a.IndexOf(b));
  308. Assert.AreEqual(-1, b.IndexOf(a));
  309. a.Dispose();
  310. b.Dispose();
  311. }
  312. [Test]
  313. public void UnsafeTextLastIndexOf()
  314. {
  315. UnsafeText a = new UnsafeText(16, Allocator.Temp);
  316. a.Append((FixedString64Bytes) "bookkeeper bookkeeper");
  317. UnsafeText b = new UnsafeText(8, Allocator.Temp);
  318. b.Append((FixedString32Bytes) "ookkee");
  319. Assert.AreEqual(12, a.LastIndexOf(b));
  320. Assert.AreEqual(-1, b.LastIndexOf(a));
  321. a.Dispose();
  322. b.Dispose();
  323. }
  324. [Test]
  325. public void UnsafeTextContains()
  326. {
  327. UnsafeText a = new UnsafeText(16, Allocator.Temp);
  328. a.Append((FixedString64Bytes) "bookkeeper bookkeeper");
  329. UnsafeText b = new UnsafeText(8, Allocator.Temp);
  330. b.Append((FixedString32Bytes) "ookkee");
  331. Assert.AreEqual(true, a.Contains(b));
  332. a.Dispose();
  333. b.Dispose();
  334. }
  335. [Test]
  336. public void UnsafeTextComparisons()
  337. {
  338. UnsafeText a = new UnsafeText(16, Allocator.Temp);
  339. a.Append((FixedString64Bytes) "apple");
  340. UnsafeText b = new UnsafeText(8, Allocator.Temp);
  341. b.Append((FixedString32Bytes) "banana");
  342. Assert.AreEqual(false, a.Equals(b));
  343. Assert.AreEqual(true, !b.Equals(a));
  344. a.Dispose();
  345. b.Dispose();
  346. }
  347. [Test]
  348. public void UnsafeText_CustomAllocatorTest()
  349. {
  350. AllocatorManager.Initialize();
  351. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  352. ref var allocator = ref allocatorHelper.Allocator;
  353. allocator.Initialize();
  354. using (var container = new UnsafeText(1, allocator.Handle))
  355. {
  356. }
  357. Assert.IsTrue(allocator.WasUsed);
  358. allocator.Dispose();
  359. allocatorHelper.Dispose();
  360. AllocatorManager.Shutdown();
  361. }
  362. [BurstCompile]
  363. struct BurstedCustomAllocatorJob : IJob
  364. {
  365. [NativeDisableUnsafePtrRestriction]
  366. public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
  367. public void Execute()
  368. {
  369. unsafe
  370. {
  371. using (var container = new UnsafeText(1, Allocator->Handle))
  372. {
  373. }
  374. }
  375. }
  376. }
  377. [Test]
  378. public unsafe void UnsafeText_BurstedCustomAllocatorTest()
  379. {
  380. AllocatorManager.Initialize();
  381. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  382. ref var allocator = ref allocatorHelper.Allocator;
  383. allocator.Initialize();
  384. var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
  385. unsafe
  386. {
  387. var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
  388. handle.Complete();
  389. }
  390. Assert.IsTrue(allocator.WasUsed);
  391. allocator.Dispose();
  392. allocatorHelper.Dispose();
  393. AllocatorManager.Shutdown();
  394. }
  395. [TestCase("red", 'r', 'd')]
  396. [TestCase("紅色", '紅', '色')]
  397. [TestCase("црвена", 'ц', 'а')]
  398. [TestCase("George Washington", 'G', 'n')]
  399. [TestCase("村上春樹", '村', '樹')]
  400. [TestCase("로마는 하루아침에 이루어진 것이 아니다", '로', '다')]
  401. [TestCase("Лако ти је плитку воду замутити и будалу наљутити", 'Л', 'и')]
  402. [TestCase("Үнэн үг хэлсэн хүнд ноёд өстэй, үхэр унасан хүнд ноход өстэй.", 'Ү', '.')]
  403. public void UnsafeText_StartsEndsWithChar(String a, char starts, char ends)
  404. {
  405. UnsafeText actual = new UnsafeText(16, Allocator.Temp);
  406. actual.Append(a);
  407. Assert.True(actual.StartsWith(starts));
  408. Assert.True(actual.EndsWith(ends));
  409. }
  410. [TestCase("red", "r", "d")]
  411. [TestCase("紅色", "紅", "色")]
  412. [TestCase("црвена", "црв", "ена")]
  413. [TestCase("George Washington", "George", "Washington")]
  414. [TestCase("村上春樹", "村上", "春樹")]
  415. [TestCase("🌕🌖🌗🌘🌑🌒🌓🌔", "🌕🌖🌗", "🌒🌓🌔")]
  416. [TestCase("𝒞𝒯𝒮𝒟𝒳𝒩𝒫𝒢", "𝒞𝒯𝒮", "𝒩𝒫𝒢")]
  417. [TestCase("로마는 하루아침에 이루어진 것이 아니다", "로마는", "아니다")]
  418. [TestCase("Лако ти је плитку воду замутити и будалу наљутити", "Лако", "наљутити")]
  419. [TestCase("Үнэн үг хэлсэн хүнд ноёд өстэй, үхэр унасан хүнд ноход өстэй.", "Үнэн", "өстэй.")]
  420. public void UnsafeText_StartsEndsWithString(String a, String starts, String ends)
  421. {
  422. UnsafeText actual = new UnsafeText(16, Allocator.Temp);
  423. actual.Append(a);
  424. Assert.True(actual.StartsWith((FixedString64Bytes)starts));
  425. Assert.True(actual.EndsWith((FixedString64Bytes)ends));
  426. }
  427. [TestCase("red ", ' ', "red ", "red", "red")]
  428. [TestCase(" red ", ' ', "red ", " red", "red")]
  429. [TestCase(" ", ' ', "", "", "")]
  430. public void UnsafeText_TrimStart(String a, char trim, String expectedStart, String expectedEnd, String expected)
  431. {
  432. UnsafeText actual = new UnsafeText(16, Allocator.Temp);
  433. actual.Append(a);
  434. Assert.AreEqual(expectedStart, actual.TrimStart(Allocator.Temp).ToString());
  435. Assert.AreEqual(expectedEnd, actual.TrimEnd(Allocator.Temp).ToString());
  436. Assert.AreEqual(expected, actual.Trim(Allocator.Temp).ToString());
  437. }
  438. [TestCase(" red ", "ed ", " red", "ed")]
  439. [TestCase("црвена", "црвена", "црвена", "црвена")]
  440. [TestCase(" ", "", "", "")]
  441. public void UnsafeText_TrimStartWithRunes(String a, String expectedStart, String expectedEnd, String expected)
  442. {
  443. UnsafeText actual = new UnsafeText(16, Allocator.Temp);
  444. actual.Append(a);
  445. Assert.AreEqual(expectedStart, actual.TrimStart(Allocator.Temp, new Unicode.Rune[] { ' ', 'r' }).ToString());
  446. Assert.AreEqual(expectedEnd, actual.TrimEnd(Allocator.Temp, new Unicode.Rune[] { ' ', 'r' }).ToString());
  447. Assert.AreEqual(expected, actual.Trim(Allocator.Temp, new Unicode.Rune[] { ' ', 'r' }).ToString());
  448. }
  449. [TestCase("Red", "red", "RED")]
  450. [TestCase("црвена", "црвена", "црвена")]
  451. [TestCase(" ", " ", " ")]
  452. public void UnsafeText_ToLowerUpperAscii(String a, String expectedLower, String expectedUpped)
  453. {
  454. UnsafeText actual = new UnsafeText(16, Allocator.Temp);
  455. actual.Append(a);
  456. Assert.AreEqual(expectedLower, actual.ToLowerAscii(Allocator.Temp).ToString());
  457. Assert.AreEqual(expectedUpped, actual.ToUpperAscii(Allocator.Temp).ToString());
  458. }
  459. }
  460. }