PageRenderTime 23ms CodeModel.GetById 3ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 19using System;
 20using System.Collections.Generic;
 21#if NREFACTORY
 22using ICSharpCode.NRefactory.Editor;
 23#endif
 24using NUnit.Framework;
 25
 26namespace ICSharpCode.AvalonEdit.Document
 27{
 28	[TestFixture]
 29	public class TextAnchorTest
 30	{
 31		TextDocument document;
 32		
 33		[SetUp]
 34		public void SetUp()
 35		{
 36			document = new TextDocument();
 37		}
 38		
 39		[Test]
 40		public void AnchorInEmptyDocument()
 41		{
 42			TextAnchor a1 = document.CreateAnchor(0);
 43			TextAnchor a2 = document.CreateAnchor(0);
 44			a1.MovementType = AnchorMovementType.BeforeInsertion;
 45			a2.MovementType = AnchorMovementType.AfterInsertion;
 46			Assert.AreEqual(0, a1.Offset);
 47			Assert.AreEqual(0, a2.Offset);
 48			document.Insert(0, "x");
 49			Assert.AreEqual(0, a1.Offset);
 50			Assert.AreEqual(1, a2.Offset);
 51		}
 52		
 53		[Test]
 54		public void AnchorsSurviveDeletion()
 55		{
 56			document.Text = new string(' ', 10);
 57			TextAnchor[] a1 = new TextAnchor[11];
 58			TextAnchor[] a2 = new TextAnchor[11];
 59			for (int i = 0; i < 11; i++) {
 60				//Console.WriteLine("Insert first at i = " + i);
 61				a1[i] = document.CreateAnchor(i);
 62				a1[i].SurviveDeletion = true;
 63				//Console.WriteLine(document.GetTextAnchorTreeAsString());
 64				//Console.WriteLine("Insert second at i = " + i);
 65				a2[i] = document.CreateAnchor(i);
 66				a2[i].SurviveDeletion = false;
 67				//Console.WriteLine(document.GetTextAnchorTreeAsString());
 68			}
 69			for (int i = 0; i < 11; i++) {
 70				Assert.AreEqual(i, a1[i].Offset);
 71				Assert.AreEqual(i, a2[i].Offset);
 72			}
 73			document.Remove(1, 8);
 74			for (int i = 0; i < 11; i++) {
 75				if (i <= 1) {
 76					Assert.IsFalse(a1[i].IsDeleted);
 77					Assert.IsFalse(a2[i].IsDeleted);
 78					Assert.AreEqual(i, a1[i].Offset);
 79					Assert.AreEqual(i, a2[i].Offset);
 80				} else if (i <= 8) {
 81					Assert.IsFalse(a1[i].IsDeleted);
 82					Assert.IsTrue(a2[i].IsDeleted);
 83					Assert.AreEqual(1, a1[i].Offset);
 84				} else {
 85					Assert.IsFalse(a1[i].IsDeleted);
 86					Assert.IsFalse(a2[i].IsDeleted);
 87					Assert.AreEqual(i - 8, a1[i].Offset);
 88					Assert.AreEqual(i - 8, a2[i].Offset);
 89				}
 90			}
 91		}
 92		
 93		
 94		Random rnd;
 95		
 96		[TestFixtureSetUp]
 97		public void FixtureSetup()
 98		{
 99			int seed = Environment.TickCount;
100			Console.WriteLine("TextAnchorTest Seed: " + seed);
101			rnd = new Random(seed);
102		}
103		
104		[Test]
105		public void CreateAnchors()
106		{
107			List<TextAnchor> anchors = new List<TextAnchor>();
108			List<int> expectedOffsets = new List<int>();
109			document.Text = new string(' ', 1000);
110			for (int i = 0; i < 1000; i++) {
111				int offset = rnd.Next(1000);
112				anchors.Add(document.CreateAnchor(offset));
113				expectedOffsets.Add(offset);
114			}
115			for (int i = 0; i < anchors.Count; i++) {
116				Assert.AreEqual(expectedOffsets[i], anchors[i].Offset);
117			}
118			GC.KeepAlive(anchors);
119		}
120		
121		[Test]
122		public void CreateAndGCAnchors()
123		{
124			List<TextAnchor> anchors = new List<TextAnchor>();
125			List<int> expectedOffsets = new List<int>();
126			document.Text = new string(' ', 1000);
127			for (int t = 0; t < 250; t++) {
128				int c = rnd.Next(50);
129				if (rnd.Next(2) == 0) {
130					for (int i = 0; i < c; i++) {
131						int offset = rnd.Next(1000);
132						anchors.Add(document.CreateAnchor(offset));
133						expectedOffsets.Add(offset);
134					}
135				} else if (c <= anchors.Count) {
136					anchors.RemoveRange(0, c);
137					expectedOffsets.RemoveRange(0, c);
138					GC.Collect();
139				}
140				for (int j = 0; j < anchors.Count; j++) {
141					Assert.AreEqual(expectedOffsets[j], anchors[j].Offset);
142				}
143			}
144			GC.KeepAlive(anchors);
145		}
146		
147		[Test]
148		public void MoveAnchorsDuringReplace()
149		{
150			document.Text = "abcd";
151			TextAnchor start = document.CreateAnchor(1);
152			TextAnchor middleDeletable = document.CreateAnchor(2);
153			TextAnchor middleSurvivorLeft = document.CreateAnchor(2);
154			middleSurvivorLeft.SurviveDeletion = true;
155			middleSurvivorLeft.MovementType = AnchorMovementType.BeforeInsertion;
156			TextAnchor middleSurvivorRight = document.CreateAnchor(2);
157			middleSurvivorRight.SurviveDeletion = true;
158			middleSurvivorRight.MovementType = AnchorMovementType.AfterInsertion;
159			TextAnchor end = document.CreateAnchor(3);
160			document.Replace(1, 2, "BxC");
161			
162			Assert.AreEqual(1, start.Offset);
163			Assert.IsTrue(middleDeletable.IsDeleted);
164			Assert.AreEqual(1, middleSurvivorLeft.Offset);
165			Assert.AreEqual(4, middleSurvivorRight.Offset);
166			Assert.AreEqual(4, end.Offset);
167		}
168		
169		[Test]
170		public void CreateAndMoveAnchors()
171		{
172			List<TextAnchor> anchors = new List<TextAnchor>();
173			List<int> expectedOffsets = new List<int>();
174			document.Text = new string(' ', 1000);
175			for (int t = 0; t < 250; t++) {
176				//Console.Write("t = " + t + " ");
177				int c = rnd.Next(50);
178				switch (rnd.Next(5)) {
179					case 0:
180						//Console.WriteLine("Add c=" + c + " anchors");
181						for (int i = 0; i < c; i++) {
182							int offset = rnd.Next(document.TextLength);
183							TextAnchor anchor = document.CreateAnchor(offset);
184							if (rnd.Next(2) == 0)
185								anchor.MovementType = AnchorMovementType.BeforeInsertion;
186							else
187								anchor.MovementType = AnchorMovementType.AfterInsertion;
188							anchor.SurviveDeletion = rnd.Next(2) == 0;
189							anchors.Add(anchor);
190							expectedOffsets.Add(offset);
191						}
192						break;
193					case 1:
194						if (c <= anchors.Count) {
195							//Console.WriteLine("Remove c=" + c + " anchors");
196							anchors.RemoveRange(0, c);
197							expectedOffsets.RemoveRange(0, c);
198							GC.Collect();
199						}
200						break;
201					case 2:
202						int insertOffset = rnd.Next(document.TextLength);
203						int insertLength = rnd.Next(1000);
204						//Console.WriteLine("insertOffset=" + insertOffset + " insertLength="+insertLength);
205						document.Insert(insertOffset, new string(' ', insertLength));
206						for (int i = 0; i < anchors.Count; i++) {
207							if (anchors[i].MovementType == AnchorMovementType.BeforeInsertion) {
208								if (expectedOffsets[i] > insertOffset)
209									expectedOffsets[i] += insertLength;
210							} else {
211								if (expectedOffsets[i] >= insertOffset)
212									expectedOffsets[i] += insertLength;
213							}
214						}
215						break;
216					case 3:
217						int removalOffset = rnd.Next(document.TextLength);
218						int removalLength = rnd.Next(document.TextLength - removalOffset);
219						//Console.WriteLine("RemovalOffset=" + removalOffset + " RemovalLength="+removalLength);
220						document.Remove(removalOffset, removalLength);
221						for (int i = anchors.Count - 1; i >= 0; i--) {
222							if (expectedOffsets[i] > removalOffset && expectedOffsets[i] < removalOffset + removalLength) {
223								if (anchors[i].SurviveDeletion) {
224									expectedOffsets[i] = removalOffset;
225								} else {
226									Assert.IsTrue(anchors[i].IsDeleted);
227									anchors.RemoveAt(i);
228									expectedOffsets.RemoveAt(i);
229								}
230							} else if (expectedOffsets[i] > removalOffset) {
231								expectedOffsets[i] -= removalLength;
232							}
233						}
234						break;
235					case 4:
236						int replaceOffset = rnd.Next(document.TextLength);
237						int replaceRemovalLength = rnd.Next(document.TextLength - replaceOffset);
238						int replaceInsertLength = rnd.Next(1000);
239						//Console.WriteLine("ReplaceOffset=" + replaceOffset + " RemovalLength="+replaceRemovalLength + " InsertLength=" + replaceInsertLength);
240						document.Replace(replaceOffset, replaceRemovalLength, new string(' ', replaceInsertLength));
241						for (int i = anchors.Count - 1; i >= 0; i--) {
242							if (expectedOffsets[i] > replaceOffset && expectedOffsets[i] < replaceOffset + replaceRemovalLength) {
243								if (anchors[i].SurviveDeletion) {
244									if (anchors[i].MovementType == AnchorMovementType.AfterInsertion)
245										expectedOffsets[i] = replaceOffset + replaceInsertLength;
246									else
247										expectedOffsets[i] = replaceOffset;
248								} else {
249									Assert.IsTrue(anchors[i].IsDeleted);
250									anchors.RemoveAt(i);
251									expectedOffsets.RemoveAt(i);
252								}
253							} else if (expectedOffsets[i] > replaceOffset) {
254								expectedOffsets[i] += replaceInsertLength - replaceRemovalLength;
255							} else if (expectedOffsets[i] == replaceOffset && replaceRemovalLength == 0 && anchors[i].MovementType == AnchorMovementType.AfterInsertion) {
256								expectedOffsets[i] += replaceInsertLength - replaceRemovalLength;
257							}
258						}
259						break;
260				}
261				Assert.AreEqual(anchors.Count, expectedOffsets.Count);
262				for (int j = 0; j < anchors.Count; j++) {
263					Assert.AreEqual(expectedOffsets[j], anchors[j].Offset);
264				}
265			}
266			GC.KeepAlive(anchors);
267		}
268		
269		[Test]
270		public void RepeatedTextDragDrop()
271		{
272			document.Text = new string(' ', 1000);
273			for (int i = 0; i < 20; i++) {
274				TextAnchor a = document.CreateAnchor(144);
275				TextAnchor b = document.CreateAnchor(157);
276				document.Insert(128, new string('a', 13));
277				document.Remove(157, 13);
278				a = document.CreateAnchor(128);
279				b = document.CreateAnchor(141);
280				
281				document.Insert(157, new string('b', 13));
282				document.Remove(128, 13);
283				
284				a = null;
285				b = null;
286				if ((i % 5) == 0)
287					GC.Collect();
288			}
289		}
290		
291		[Test]
292		public void ReplaceSpacesWithTab()
293		{
294			document.Text = "a    b";
295			TextAnchor before = document.CreateAnchor(1);
296			before.MovementType = AnchorMovementType.AfterInsertion;
297			TextAnchor after = document.CreateAnchor(5);
298			TextAnchor survivingMiddle = document.CreateAnchor(2);
299			TextAnchor deletedMiddle = document.CreateAnchor(3);
300			
301			document.Replace(1, 4, "\t", OffsetChangeMappingType.CharacterReplace);
302			Assert.AreEqual("a\tb", document.Text);
303			// yes, the movement is a bit strange; but that's how CharacterReplace works when the text gets shorter
304			Assert.AreEqual(1, before.Offset);
305			Assert.AreEqual(2, after.Offset);
306			Assert.AreEqual(2, survivingMiddle.Offset);
307			Assert.AreEqual(2, deletedMiddle.Offset);
308		}
309		
310		[Test]
311		public void ReplaceTwoCharactersWithThree()
312		{
313			document.Text = "a12b";
314			TextAnchor before = document.CreateAnchor(1);
315			before.MovementType = AnchorMovementType.AfterInsertion;
316			TextAnchor after = document.CreateAnchor(3);
317			before.MovementType = AnchorMovementType.BeforeInsertion;
318			TextAnchor middleB = document.CreateAnchor(2);
319			before.MovementType = AnchorMovementType.BeforeInsertion;
320			TextAnchor middleA = document.CreateAnchor(2);
321			before.MovementType = AnchorMovementType.AfterInsertion;
322			
323			document.Replace(1, 2, "123", OffsetChangeMappingType.CharacterReplace);
324			Assert.AreEqual("a123b", document.Text);
325			Assert.AreEqual(1, before.Offset);
326			Assert.AreEqual(4, after.Offset);
327			Assert.AreEqual(2, middleA.Offset);
328			Assert.AreEqual(2, middleB.Offset);
329		}
330	}
331}