/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/TextAnchorTest.cs

http://github.com/icsharpcode/ILSpy · C# · 331 lines · 283 code · 20 blank · 28 comment · 56 complexity · d7099f32c1eea785a0d2e738989894e0 MD5 · raw file

  1. // Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. #if NREFACTORY
  21. using ICSharpCode.NRefactory.Editor;
  22. #endif
  23. using NUnit.Framework;
  24. namespace ICSharpCode.AvalonEdit.Document
  25. {
  26. [TestFixture]
  27. public class TextAnchorTest
  28. {
  29. TextDocument document;
  30. [SetUp]
  31. public void SetUp()
  32. {
  33. document = new TextDocument();
  34. }
  35. [Test]
  36. public void AnchorInEmptyDocument()
  37. {
  38. TextAnchor a1 = document.CreateAnchor(0);
  39. TextAnchor a2 = document.CreateAnchor(0);
  40. a1.MovementType = AnchorMovementType.BeforeInsertion;
  41. a2.MovementType = AnchorMovementType.AfterInsertion;
  42. Assert.AreEqual(0, a1.Offset);
  43. Assert.AreEqual(0, a2.Offset);
  44. document.Insert(0, "x");
  45. Assert.AreEqual(0, a1.Offset);
  46. Assert.AreEqual(1, a2.Offset);
  47. }
  48. [Test]
  49. public void AnchorsSurviveDeletion()
  50. {
  51. document.Text = new string(' ', 10);
  52. TextAnchor[] a1 = new TextAnchor[11];
  53. TextAnchor[] a2 = new TextAnchor[11];
  54. for (int i = 0; i < 11; i++) {
  55. //Console.WriteLine("Insert first at i = " + i);
  56. a1[i] = document.CreateAnchor(i);
  57. a1[i].SurviveDeletion = true;
  58. //Console.WriteLine(document.GetTextAnchorTreeAsString());
  59. //Console.WriteLine("Insert second at i = " + i);
  60. a2[i] = document.CreateAnchor(i);
  61. a2[i].SurviveDeletion = false;
  62. //Console.WriteLine(document.GetTextAnchorTreeAsString());
  63. }
  64. for (int i = 0; i < 11; i++) {
  65. Assert.AreEqual(i, a1[i].Offset);
  66. Assert.AreEqual(i, a2[i].Offset);
  67. }
  68. document.Remove(1, 8);
  69. for (int i = 0; i < 11; i++) {
  70. if (i <= 1) {
  71. Assert.IsFalse(a1[i].IsDeleted);
  72. Assert.IsFalse(a2[i].IsDeleted);
  73. Assert.AreEqual(i, a1[i].Offset);
  74. Assert.AreEqual(i, a2[i].Offset);
  75. } else if (i <= 8) {
  76. Assert.IsFalse(a1[i].IsDeleted);
  77. Assert.IsTrue(a2[i].IsDeleted);
  78. Assert.AreEqual(1, a1[i].Offset);
  79. } else {
  80. Assert.IsFalse(a1[i].IsDeleted);
  81. Assert.IsFalse(a2[i].IsDeleted);
  82. Assert.AreEqual(i - 8, a1[i].Offset);
  83. Assert.AreEqual(i - 8, a2[i].Offset);
  84. }
  85. }
  86. }
  87. Random rnd;
  88. [TestFixtureSetUp]
  89. public void FixtureSetup()
  90. {
  91. int seed = Environment.TickCount;
  92. Console.WriteLine("TextAnchorTest Seed: " + seed);
  93. rnd = new Random(seed);
  94. }
  95. [Test]
  96. public void CreateAnchors()
  97. {
  98. List<TextAnchor> anchors = new List<TextAnchor>();
  99. List<int> expectedOffsets = new List<int>();
  100. document.Text = new string(' ', 1000);
  101. for (int i = 0; i < 1000; i++) {
  102. int offset = rnd.Next(1000);
  103. anchors.Add(document.CreateAnchor(offset));
  104. expectedOffsets.Add(offset);
  105. }
  106. for (int i = 0; i < anchors.Count; i++) {
  107. Assert.AreEqual(expectedOffsets[i], anchors[i].Offset);
  108. }
  109. GC.KeepAlive(anchors);
  110. }
  111. [Test]
  112. public void CreateAndGCAnchors()
  113. {
  114. List<TextAnchor> anchors = new List<TextAnchor>();
  115. List<int> expectedOffsets = new List<int>();
  116. document.Text = new string(' ', 1000);
  117. for (int t = 0; t < 250; t++) {
  118. int c = rnd.Next(50);
  119. if (rnd.Next(2) == 0) {
  120. for (int i = 0; i < c; i++) {
  121. int offset = rnd.Next(1000);
  122. anchors.Add(document.CreateAnchor(offset));
  123. expectedOffsets.Add(offset);
  124. }
  125. } else if (c <= anchors.Count) {
  126. anchors.RemoveRange(0, c);
  127. expectedOffsets.RemoveRange(0, c);
  128. GC.Collect();
  129. }
  130. for (int j = 0; j < anchors.Count; j++) {
  131. Assert.AreEqual(expectedOffsets[j], anchors[j].Offset);
  132. }
  133. }
  134. GC.KeepAlive(anchors);
  135. }
  136. [Test]
  137. public void MoveAnchorsDuringReplace()
  138. {
  139. document.Text = "abcd";
  140. TextAnchor start = document.CreateAnchor(1);
  141. TextAnchor middleDeletable = document.CreateAnchor(2);
  142. TextAnchor middleSurvivorLeft = document.CreateAnchor(2);
  143. middleSurvivorLeft.SurviveDeletion = true;
  144. middleSurvivorLeft.MovementType = AnchorMovementType.BeforeInsertion;
  145. TextAnchor middleSurvivorRight = document.CreateAnchor(2);
  146. middleSurvivorRight.SurviveDeletion = true;
  147. middleSurvivorRight.MovementType = AnchorMovementType.AfterInsertion;
  148. TextAnchor end = document.CreateAnchor(3);
  149. document.Replace(1, 2, "BxC");
  150. Assert.AreEqual(1, start.Offset);
  151. Assert.IsTrue(middleDeletable.IsDeleted);
  152. Assert.AreEqual(1, middleSurvivorLeft.Offset);
  153. Assert.AreEqual(4, middleSurvivorRight.Offset);
  154. Assert.AreEqual(4, end.Offset);
  155. }
  156. [Test]
  157. public void CreateAndMoveAnchors()
  158. {
  159. List<TextAnchor> anchors = new List<TextAnchor>();
  160. List<int> expectedOffsets = new List<int>();
  161. document.Text = new string(' ', 1000);
  162. for (int t = 0; t < 250; t++) {
  163. //Console.Write("t = " + t + " ");
  164. int c = rnd.Next(50);
  165. switch (rnd.Next(5)) {
  166. case 0:
  167. //Console.WriteLine("Add c=" + c + " anchors");
  168. for (int i = 0; i < c; i++) {
  169. int offset = rnd.Next(document.TextLength);
  170. TextAnchor anchor = document.CreateAnchor(offset);
  171. if (rnd.Next(2) == 0)
  172. anchor.MovementType = AnchorMovementType.BeforeInsertion;
  173. else
  174. anchor.MovementType = AnchorMovementType.AfterInsertion;
  175. anchor.SurviveDeletion = rnd.Next(2) == 0;
  176. anchors.Add(anchor);
  177. expectedOffsets.Add(offset);
  178. }
  179. break;
  180. case 1:
  181. if (c <= anchors.Count) {
  182. //Console.WriteLine("Remove c=" + c + " anchors");
  183. anchors.RemoveRange(0, c);
  184. expectedOffsets.RemoveRange(0, c);
  185. GC.Collect();
  186. }
  187. break;
  188. case 2:
  189. int insertOffset = rnd.Next(document.TextLength);
  190. int insertLength = rnd.Next(1000);
  191. //Console.WriteLine("insertOffset=" + insertOffset + " insertLength="+insertLength);
  192. document.Insert(insertOffset, new string(' ', insertLength));
  193. for (int i = 0; i < anchors.Count; i++) {
  194. if (anchors[i].MovementType == AnchorMovementType.BeforeInsertion) {
  195. if (expectedOffsets[i] > insertOffset)
  196. expectedOffsets[i] += insertLength;
  197. } else {
  198. if (expectedOffsets[i] >= insertOffset)
  199. expectedOffsets[i] += insertLength;
  200. }
  201. }
  202. break;
  203. case 3:
  204. int removalOffset = rnd.Next(document.TextLength);
  205. int removalLength = rnd.Next(document.TextLength - removalOffset);
  206. //Console.WriteLine("RemovalOffset=" + removalOffset + " RemovalLength="+removalLength);
  207. document.Remove(removalOffset, removalLength);
  208. for (int i = anchors.Count - 1; i >= 0; i--) {
  209. if (expectedOffsets[i] > removalOffset && expectedOffsets[i] < removalOffset + removalLength) {
  210. if (anchors[i].SurviveDeletion) {
  211. expectedOffsets[i] = removalOffset;
  212. } else {
  213. Assert.IsTrue(anchors[i].IsDeleted);
  214. anchors.RemoveAt(i);
  215. expectedOffsets.RemoveAt(i);
  216. }
  217. } else if (expectedOffsets[i] > removalOffset) {
  218. expectedOffsets[i] -= removalLength;
  219. }
  220. }
  221. break;
  222. case 4:
  223. int replaceOffset = rnd.Next(document.TextLength);
  224. int replaceRemovalLength = rnd.Next(document.TextLength - replaceOffset);
  225. int replaceInsertLength = rnd.Next(1000);
  226. //Console.WriteLine("ReplaceOffset=" + replaceOffset + " RemovalLength="+replaceRemovalLength + " InsertLength=" + replaceInsertLength);
  227. document.Replace(replaceOffset, replaceRemovalLength, new string(' ', replaceInsertLength));
  228. for (int i = anchors.Count - 1; i >= 0; i--) {
  229. if (expectedOffsets[i] > replaceOffset && expectedOffsets[i] < replaceOffset + replaceRemovalLength) {
  230. if (anchors[i].SurviveDeletion) {
  231. if (anchors[i].MovementType == AnchorMovementType.AfterInsertion)
  232. expectedOffsets[i] = replaceOffset + replaceInsertLength;
  233. else
  234. expectedOffsets[i] = replaceOffset;
  235. } else {
  236. Assert.IsTrue(anchors[i].IsDeleted);
  237. anchors.RemoveAt(i);
  238. expectedOffsets.RemoveAt(i);
  239. }
  240. } else if (expectedOffsets[i] > replaceOffset) {
  241. expectedOffsets[i] += replaceInsertLength - replaceRemovalLength;
  242. } else if (expectedOffsets[i] == replaceOffset && replaceRemovalLength == 0 && anchors[i].MovementType == AnchorMovementType.AfterInsertion) {
  243. expectedOffsets[i] += replaceInsertLength - replaceRemovalLength;
  244. }
  245. }
  246. break;
  247. }
  248. Assert.AreEqual(anchors.Count, expectedOffsets.Count);
  249. for (int j = 0; j < anchors.Count; j++) {
  250. Assert.AreEqual(expectedOffsets[j], anchors[j].Offset);
  251. }
  252. }
  253. GC.KeepAlive(anchors);
  254. }
  255. [Test]
  256. public void RepeatedTextDragDrop()
  257. {
  258. document.Text = new string(' ', 1000);
  259. for (int i = 0; i < 20; i++) {
  260. TextAnchor a = document.CreateAnchor(144);
  261. TextAnchor b = document.CreateAnchor(157);
  262. document.Insert(128, new string('a', 13));
  263. document.Remove(157, 13);
  264. a = document.CreateAnchor(128);
  265. b = document.CreateAnchor(141);
  266. document.Insert(157, new string('b', 13));
  267. document.Remove(128, 13);
  268. a = null;
  269. b = null;
  270. if ((i % 5) == 0)
  271. GC.Collect();
  272. }
  273. }
  274. [Test]
  275. public void ReplaceSpacesWithTab()
  276. {
  277. document.Text = "a b";
  278. TextAnchor before = document.CreateAnchor(1);
  279. before.MovementType = AnchorMovementType.AfterInsertion;
  280. TextAnchor after = document.CreateAnchor(5);
  281. TextAnchor survivingMiddle = document.CreateAnchor(2);
  282. TextAnchor deletedMiddle = document.CreateAnchor(3);
  283. document.Replace(1, 4, "\t", OffsetChangeMappingType.CharacterReplace);
  284. Assert.AreEqual("a\tb", document.Text);
  285. // yes, the movement is a bit strange; but that's how CharacterReplace works when the text gets shorter
  286. Assert.AreEqual(1, before.Offset);
  287. Assert.AreEqual(2, after.Offset);
  288. Assert.AreEqual(2, survivingMiddle.Offset);
  289. Assert.AreEqual(2, deletedMiddle.Offset);
  290. }
  291. [Test]
  292. public void ReplaceTwoCharactersWithThree()
  293. {
  294. document.Text = "a12b";
  295. TextAnchor before = document.CreateAnchor(1);
  296. before.MovementType = AnchorMovementType.AfterInsertion;
  297. TextAnchor after = document.CreateAnchor(3);
  298. before.MovementType = AnchorMovementType.BeforeInsertion;
  299. TextAnchor middleB = document.CreateAnchor(2);
  300. before.MovementType = AnchorMovementType.BeforeInsertion;
  301. TextAnchor middleA = document.CreateAnchor(2);
  302. before.MovementType = AnchorMovementType.AfterInsertion;
  303. document.Replace(1, 2, "123", OffsetChangeMappingType.CharacterReplace);
  304. Assert.AreEqual("a123b", document.Text);
  305. Assert.AreEqual(1, before.Offset);
  306. Assert.AreEqual(4, after.Offset);
  307. Assert.AreEqual(2, middleA.Offset);
  308. Assert.AreEqual(2, middleB.Offset);
  309. }
  310. }
  311. }