/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/TextSegmentTreeTest.cs

http://github.com/icsharpcode/ILSpy · C# · 368 lines · 311 code · 31 blank · 26 comment · 16 complexity · 063c8360b18aca23263bc391fe74ce87 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 TextSegmentTreeTest
  28. {
  29. Random rnd;
  30. [TestFixtureSetUp]
  31. public void FixtureSetup()
  32. {
  33. int seed = Environment.TickCount;
  34. Console.WriteLine("TextSegmentTreeTest Seed: " + seed);
  35. rnd = new Random(seed);
  36. }
  37. class TestTextSegment : TextSegment
  38. {
  39. internal int ExpectedOffset, ExpectedLength;
  40. public TestTextSegment(int expectedOffset, int expectedLength)
  41. {
  42. this.ExpectedOffset = expectedOffset;
  43. this.ExpectedLength = expectedLength;
  44. this.StartOffset = expectedOffset;
  45. this.Length = expectedLength;
  46. }
  47. }
  48. TextSegmentCollection<TestTextSegment> tree;
  49. List<TestTextSegment> expectedSegments;
  50. [SetUp]
  51. public void SetUp()
  52. {
  53. tree = new TextSegmentCollection<TestTextSegment>();
  54. expectedSegments = new List<TestTextSegment>();
  55. }
  56. [Test]
  57. public void FindInEmptyTree()
  58. {
  59. Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(0));
  60. Assert.AreEqual(0, tree.FindSegmentsContaining(0).Count);
  61. Assert.AreEqual(0, tree.FindOverlappingSegments(10, 20).Count);
  62. }
  63. [Test]
  64. public void FindFirstSegmentWithStartAfter()
  65. {
  66. var s1 = new TestTextSegment(5, 10);
  67. var s2 = new TestTextSegment(10, 10);
  68. tree.Add(s1);
  69. tree.Add(s2);
  70. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(-100));
  71. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(0));
  72. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(4));
  73. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(5));
  74. Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(6));
  75. Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(9));
  76. Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(10));
  77. Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(11));
  78. Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(100));
  79. }
  80. [Test]
  81. public void FindFirstSegmentWithStartAfterWithDuplicates()
  82. {
  83. var s1 = new TestTextSegment(5, 10);
  84. var s1b = new TestTextSegment(5, 7);
  85. var s2 = new TestTextSegment(10, 10);
  86. var s2b = new TestTextSegment(10, 7);
  87. tree.Add(s1);
  88. tree.Add(s1b);
  89. tree.Add(s2);
  90. tree.Add(s2b);
  91. Assert.AreSame(s1b, tree.GetNextSegment(s1));
  92. Assert.AreSame(s2b, tree.GetNextSegment(s2));
  93. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(-100));
  94. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(0));
  95. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(4));
  96. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(5));
  97. Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(6));
  98. Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(9));
  99. Assert.AreSame(s2, tree.FindFirstSegmentWithStartAfter(10));
  100. Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(11));
  101. Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(100));
  102. }
  103. [Test]
  104. public void FindFirstSegmentWithStartAfterWithDuplicates2()
  105. {
  106. var s1 = new TestTextSegment(5, 1);
  107. var s2 = new TestTextSegment(5, 2);
  108. var s3 = new TestTextSegment(5, 3);
  109. var s4 = new TestTextSegment(5, 4);
  110. tree.Add(s1);
  111. tree.Add(s2);
  112. tree.Add(s3);
  113. tree.Add(s4);
  114. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(0));
  115. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(1));
  116. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(4));
  117. Assert.AreSame(s1, tree.FindFirstSegmentWithStartAfter(5));
  118. Assert.AreSame(null, tree.FindFirstSegmentWithStartAfter(6));
  119. }
  120. TestTextSegment AddSegment(int offset, int length)
  121. {
  122. // Console.WriteLine("Add " + offset + ", " + length);
  123. TestTextSegment s = new TestTextSegment(offset, length);
  124. tree.Add(s);
  125. expectedSegments.Add(s);
  126. return s;
  127. }
  128. void RemoveSegment(TestTextSegment s)
  129. {
  130. // Console.WriteLine("Remove " + s);
  131. expectedSegments.Remove(s);
  132. tree.Remove(s);
  133. }
  134. void TestRetrieval(int offset, int length)
  135. {
  136. HashSet<TestTextSegment> actual = new HashSet<TestTextSegment>(tree.FindOverlappingSegments(offset, length));
  137. HashSet<TestTextSegment> expected = new HashSet<TestTextSegment>();
  138. foreach (TestTextSegment e in expectedSegments) {
  139. if (e.ExpectedOffset + e.ExpectedLength < offset)
  140. continue;
  141. if (e.ExpectedOffset > offset + length)
  142. continue;
  143. expected.Add(e);
  144. }
  145. Assert.IsTrue(actual.IsSubsetOf(expected));
  146. Assert.IsTrue(expected.IsSubsetOf(actual));
  147. }
  148. void CheckSegments()
  149. {
  150. Assert.AreEqual(expectedSegments.Count, tree.Count);
  151. foreach (TestTextSegment s in expectedSegments) {
  152. Assert.AreEqual(s.ExpectedOffset, s.StartOffset /*, "startoffset for " + s*/);
  153. Assert.AreEqual(s.ExpectedLength, s.Length /*, "length for " + s*/);
  154. }
  155. }
  156. [Test]
  157. public void AddSegments()
  158. {
  159. TestTextSegment s1 = AddSegment(10, 20);
  160. TestTextSegment s2 = AddSegment(15, 10);
  161. CheckSegments();
  162. }
  163. void ChangeDocument(OffsetChangeMapEntry change)
  164. {
  165. tree.UpdateOffsets(change);
  166. foreach (TestTextSegment s in expectedSegments) {
  167. int endOffset = s.ExpectedOffset + s.ExpectedLength;
  168. s.ExpectedOffset = change.GetNewOffset(s.ExpectedOffset, AnchorMovementType.AfterInsertion);
  169. s.ExpectedLength = Math.Max(0, change.GetNewOffset(endOffset, AnchorMovementType.BeforeInsertion) - s.ExpectedOffset);
  170. }
  171. }
  172. [Test]
  173. public void InsertionBeforeAllSegments()
  174. {
  175. TestTextSegment s1 = AddSegment(10, 20);
  176. TestTextSegment s2 = AddSegment(15, 10);
  177. ChangeDocument(new OffsetChangeMapEntry(5, 0, 2));
  178. CheckSegments();
  179. }
  180. [Test]
  181. public void ReplacementBeforeAllSegmentsTouchingFirstSegment()
  182. {
  183. TestTextSegment s1 = AddSegment(10, 20);
  184. TestTextSegment s2 = AddSegment(15, 10);
  185. ChangeDocument(new OffsetChangeMapEntry(5, 5, 2));
  186. CheckSegments();
  187. }
  188. [Test]
  189. public void InsertionAfterAllSegments()
  190. {
  191. TestTextSegment s1 = AddSegment(10, 20);
  192. TestTextSegment s2 = AddSegment(15, 10);
  193. ChangeDocument(new OffsetChangeMapEntry(45, 0, 2));
  194. CheckSegments();
  195. }
  196. [Test]
  197. public void ReplacementOverlappingWithStartOfSegment()
  198. {
  199. TestTextSegment s1 = AddSegment(10, 20);
  200. TestTextSegment s2 = AddSegment(15, 10);
  201. ChangeDocument(new OffsetChangeMapEntry(9, 7, 2));
  202. CheckSegments();
  203. }
  204. [Test]
  205. public void ReplacementOfWholeSegment()
  206. {
  207. TestTextSegment s1 = AddSegment(10, 20);
  208. TestTextSegment s2 = AddSegment(15, 10);
  209. ChangeDocument(new OffsetChangeMapEntry(10, 20, 30));
  210. CheckSegments();
  211. }
  212. [Test]
  213. public void ReplacementAtEndOfSegment()
  214. {
  215. TestTextSegment s1 = AddSegment(10, 20);
  216. TestTextSegment s2 = AddSegment(15, 10);
  217. ChangeDocument(new OffsetChangeMapEntry(24, 6, 10));
  218. CheckSegments();
  219. }
  220. [Test]
  221. public void RandomizedNoDocumentChanges()
  222. {
  223. for (int i = 0; i < 1000; i++) {
  224. // Console.WriteLine(tree.GetTreeAsString());
  225. // Console.WriteLine("Iteration " + i);
  226. switch (rnd.Next(3)) {
  227. case 0:
  228. AddSegment(rnd.Next(500), rnd.Next(30));
  229. break;
  230. case 1:
  231. AddSegment(rnd.Next(500), rnd.Next(300));
  232. break;
  233. case 2:
  234. if (tree.Count > 0) {
  235. RemoveSegment(expectedSegments[rnd.Next(tree.Count)]);
  236. }
  237. break;
  238. }
  239. CheckSegments();
  240. }
  241. }
  242. [Test]
  243. public void RandomizedCloseNoDocumentChanges()
  244. {
  245. // Lots of segments in a short document. Tests how the tree copes with multiple identical segments.
  246. for (int i = 0; i < 1000; i++) {
  247. switch (rnd.Next(3)) {
  248. case 0:
  249. AddSegment(rnd.Next(20), rnd.Next(10));
  250. break;
  251. case 1:
  252. AddSegment(rnd.Next(20), rnd.Next(20));
  253. break;
  254. case 2:
  255. if (tree.Count > 0) {
  256. RemoveSegment(expectedSegments[rnd.Next(tree.Count)]);
  257. }
  258. break;
  259. }
  260. CheckSegments();
  261. }
  262. }
  263. [Test]
  264. public void RandomizedRetrievalTest()
  265. {
  266. for (int i = 0; i < 1000; i++) {
  267. AddSegment(rnd.Next(500), rnd.Next(300));
  268. }
  269. CheckSegments();
  270. for (int i = 0; i < 1000; i++) {
  271. TestRetrieval(rnd.Next(1000) - 100, rnd.Next(500));
  272. }
  273. }
  274. [Test]
  275. public void RandomizedWithDocumentChanges()
  276. {
  277. for (int i = 0; i < 500; i++) {
  278. // Console.WriteLine(tree.GetTreeAsString());
  279. // Console.WriteLine("Iteration " + i);
  280. switch (rnd.Next(6)) {
  281. case 0:
  282. AddSegment(rnd.Next(500), rnd.Next(30));
  283. break;
  284. case 1:
  285. AddSegment(rnd.Next(500), rnd.Next(300));
  286. break;
  287. case 2:
  288. if (tree.Count > 0) {
  289. RemoveSegment(expectedSegments[rnd.Next(tree.Count)]);
  290. }
  291. break;
  292. case 3:
  293. ChangeDocument(new OffsetChangeMapEntry(rnd.Next(800), rnd.Next(50), rnd.Next(50)));
  294. break;
  295. case 4:
  296. ChangeDocument(new OffsetChangeMapEntry(rnd.Next(800), 0, rnd.Next(50)));
  297. break;
  298. case 5:
  299. ChangeDocument(new OffsetChangeMapEntry(rnd.Next(800), rnd.Next(50), 0));
  300. break;
  301. }
  302. CheckSegments();
  303. }
  304. }
  305. [Test]
  306. public void RandomizedWithDocumentChangesClose()
  307. {
  308. for (int i = 0; i < 500; i++) {
  309. // Console.WriteLine(tree.GetTreeAsString());
  310. // Console.WriteLine("Iteration " + i);
  311. switch (rnd.Next(6)) {
  312. case 0:
  313. AddSegment(rnd.Next(50), rnd.Next(30));
  314. break;
  315. case 1:
  316. AddSegment(rnd.Next(50), rnd.Next(3));
  317. break;
  318. case 2:
  319. if (tree.Count > 0) {
  320. RemoveSegment(expectedSegments[rnd.Next(tree.Count)]);
  321. }
  322. break;
  323. case 3:
  324. ChangeDocument(new OffsetChangeMapEntry(rnd.Next(80), rnd.Next(10), rnd.Next(10)));
  325. break;
  326. case 4:
  327. ChangeDocument(new OffsetChangeMapEntry(rnd.Next(80), 0, rnd.Next(10)));
  328. break;
  329. case 5:
  330. ChangeDocument(new OffsetChangeMapEntry(rnd.Next(80), rnd.Next(10), 0));
  331. break;
  332. }
  333. CheckSegments();
  334. }
  335. }
  336. }
  337. }