314 lines
10 KiB
C#
314 lines
10 KiB
C#
|
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|||
|
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|||
|
|
|
|||
|
|
using System;
|
|||
|
|
using NUnit.Framework;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
|
|||
|
|
namespace ICSharpCode.AvalonEdit.Document
|
|||
|
|
{
|
|||
|
|
[TestFixture]
|
|||
|
|
public class TextAnchorTest
|
|||
|
|
{
|
|||
|
|
TextDocument document;
|
|||
|
|
|
|||
|
|
[SetUp]
|
|||
|
|
public void SetUp()
|
|||
|
|
{
|
|||
|
|
document = new TextDocument();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void AnchorInEmptyDocument()
|
|||
|
|
{
|
|||
|
|
TextAnchor a1 = document.CreateAnchor(0);
|
|||
|
|
TextAnchor a2 = document.CreateAnchor(0);
|
|||
|
|
a1.MovementType = AnchorMovementType.BeforeInsertion;
|
|||
|
|
a2.MovementType = AnchorMovementType.AfterInsertion;
|
|||
|
|
Assert.AreEqual(0, a1.Offset);
|
|||
|
|
Assert.AreEqual(0, a2.Offset);
|
|||
|
|
document.Insert(0, "x");
|
|||
|
|
Assert.AreEqual(0, a1.Offset);
|
|||
|
|
Assert.AreEqual(1, a2.Offset);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void AnchorsSurviveDeletion()
|
|||
|
|
{
|
|||
|
|
document.Text = new string(' ', 10);
|
|||
|
|
TextAnchor[] a1 = new TextAnchor[11];
|
|||
|
|
TextAnchor[] a2 = new TextAnchor[11];
|
|||
|
|
for (int i = 0; i < 11; i++) {
|
|||
|
|
//Console.WriteLine("Insert first at i = " + i);
|
|||
|
|
a1[i] = document.CreateAnchor(i);
|
|||
|
|
a1[i].SurviveDeletion = true;
|
|||
|
|
//Console.WriteLine(document.GetTextAnchorTreeAsString());
|
|||
|
|
//Console.WriteLine("Insert second at i = " + i);
|
|||
|
|
a2[i] = document.CreateAnchor(i);
|
|||
|
|
a2[i].SurviveDeletion = false;
|
|||
|
|
//Console.WriteLine(document.GetTextAnchorTreeAsString());
|
|||
|
|
}
|
|||
|
|
for (int i = 0; i < 11; i++) {
|
|||
|
|
Assert.AreEqual(i, a1[i].Offset);
|
|||
|
|
Assert.AreEqual(i, a2[i].Offset);
|
|||
|
|
}
|
|||
|
|
document.Remove(1, 8);
|
|||
|
|
for (int i = 0; i < 11; i++) {
|
|||
|
|
if (i <= 1) {
|
|||
|
|
Assert.IsFalse(a1[i].IsDeleted);
|
|||
|
|
Assert.IsFalse(a2[i].IsDeleted);
|
|||
|
|
Assert.AreEqual(i, a1[i].Offset);
|
|||
|
|
Assert.AreEqual(i, a2[i].Offset);
|
|||
|
|
} else if (i <= 8) {
|
|||
|
|
Assert.IsFalse(a1[i].IsDeleted);
|
|||
|
|
Assert.IsTrue(a2[i].IsDeleted);
|
|||
|
|
Assert.AreEqual(1, a1[i].Offset);
|
|||
|
|
} else {
|
|||
|
|
Assert.IsFalse(a1[i].IsDeleted);
|
|||
|
|
Assert.IsFalse(a2[i].IsDeleted);
|
|||
|
|
Assert.AreEqual(i - 8, a1[i].Offset);
|
|||
|
|
Assert.AreEqual(i - 8, a2[i].Offset);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
Random rnd;
|
|||
|
|
|
|||
|
|
[TestFixtureSetUp]
|
|||
|
|
public void FixtureSetup()
|
|||
|
|
{
|
|||
|
|
int seed = Environment.TickCount;
|
|||
|
|
Console.WriteLine("TextAnchorTest Seed: " + seed);
|
|||
|
|
rnd = new Random(seed);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void CreateAnchors()
|
|||
|
|
{
|
|||
|
|
List<TextAnchor> anchors = new List<TextAnchor>();
|
|||
|
|
List<int> expectedOffsets = new List<int>();
|
|||
|
|
document.Text = new string(' ', 1000);
|
|||
|
|
for (int i = 0; i < 1000; i++) {
|
|||
|
|
int offset = rnd.Next(1000);
|
|||
|
|
anchors.Add(document.CreateAnchor(offset));
|
|||
|
|
expectedOffsets.Add(offset);
|
|||
|
|
}
|
|||
|
|
for (int i = 0; i < anchors.Count; i++) {
|
|||
|
|
Assert.AreEqual(expectedOffsets[i], anchors[i].Offset);
|
|||
|
|
}
|
|||
|
|
GC.KeepAlive(anchors);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void CreateAndGCAnchors()
|
|||
|
|
{
|
|||
|
|
List<TextAnchor> anchors = new List<TextAnchor>();
|
|||
|
|
List<int> expectedOffsets = new List<int>();
|
|||
|
|
document.Text = new string(' ', 1000);
|
|||
|
|
for (int t = 0; t < 250; t++) {
|
|||
|
|
int c = rnd.Next(50);
|
|||
|
|
if (rnd.Next(2) == 0) {
|
|||
|
|
for (int i = 0; i < c; i++) {
|
|||
|
|
int offset = rnd.Next(1000);
|
|||
|
|
anchors.Add(document.CreateAnchor(offset));
|
|||
|
|
expectedOffsets.Add(offset);
|
|||
|
|
}
|
|||
|
|
} else if (c <= anchors.Count) {
|
|||
|
|
anchors.RemoveRange(0, c);
|
|||
|
|
expectedOffsets.RemoveRange(0, c);
|
|||
|
|
GC.Collect();
|
|||
|
|
}
|
|||
|
|
for (int j = 0; j < anchors.Count; j++) {
|
|||
|
|
Assert.AreEqual(expectedOffsets[j], anchors[j].Offset);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
GC.KeepAlive(anchors);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void MoveAnchorsDuringReplace()
|
|||
|
|
{
|
|||
|
|
document.Text = "abcd";
|
|||
|
|
TextAnchor start = document.CreateAnchor(1);
|
|||
|
|
TextAnchor middleDeletable = document.CreateAnchor(2);
|
|||
|
|
TextAnchor middleSurvivorLeft = document.CreateAnchor(2);
|
|||
|
|
middleSurvivorLeft.SurviveDeletion = true;
|
|||
|
|
middleSurvivorLeft.MovementType = AnchorMovementType.BeforeInsertion;
|
|||
|
|
TextAnchor middleSurvivorRight = document.CreateAnchor(2);
|
|||
|
|
middleSurvivorRight.SurviveDeletion = true;
|
|||
|
|
middleSurvivorRight.MovementType = AnchorMovementType.AfterInsertion;
|
|||
|
|
TextAnchor end = document.CreateAnchor(3);
|
|||
|
|
document.Replace(1, 2, "BxC");
|
|||
|
|
|
|||
|
|
Assert.AreEqual(1, start.Offset);
|
|||
|
|
Assert.IsTrue(middleDeletable.IsDeleted);
|
|||
|
|
Assert.AreEqual(1, middleSurvivorLeft.Offset);
|
|||
|
|
Assert.AreEqual(4, middleSurvivorRight.Offset);
|
|||
|
|
Assert.AreEqual(4, end.Offset);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void CreateAndMoveAnchors()
|
|||
|
|
{
|
|||
|
|
List<TextAnchor> anchors = new List<TextAnchor>();
|
|||
|
|
List<int> expectedOffsets = new List<int>();
|
|||
|
|
document.Text = new string(' ', 1000);
|
|||
|
|
for (int t = 0; t < 250; t++) {
|
|||
|
|
//Console.Write("t = " + t + " ");
|
|||
|
|
int c = rnd.Next(50);
|
|||
|
|
switch (rnd.Next(5)) {
|
|||
|
|
case 0:
|
|||
|
|
//Console.WriteLine("Add c=" + c + " anchors");
|
|||
|
|
for (int i = 0; i < c; i++) {
|
|||
|
|
int offset = rnd.Next(document.TextLength);
|
|||
|
|
TextAnchor anchor = document.CreateAnchor(offset);
|
|||
|
|
if (rnd.Next(2) == 0)
|
|||
|
|
anchor.MovementType = AnchorMovementType.BeforeInsertion;
|
|||
|
|
else
|
|||
|
|
anchor.MovementType = AnchorMovementType.AfterInsertion;
|
|||
|
|
anchor.SurviveDeletion = rnd.Next(2) == 0;
|
|||
|
|
anchors.Add(anchor);
|
|||
|
|
expectedOffsets.Add(offset);
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 1:
|
|||
|
|
if (c <= anchors.Count) {
|
|||
|
|
//Console.WriteLine("Remove c=" + c + " anchors");
|
|||
|
|
anchors.RemoveRange(0, c);
|
|||
|
|
expectedOffsets.RemoveRange(0, c);
|
|||
|
|
GC.Collect();
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 2:
|
|||
|
|
int insertOffset = rnd.Next(document.TextLength);
|
|||
|
|
int insertLength = rnd.Next(1000);
|
|||
|
|
//Console.WriteLine("insertOffset=" + insertOffset + " insertLength="+insertLength);
|
|||
|
|
document.Insert(insertOffset, new string(' ', insertLength));
|
|||
|
|
for (int i = 0; i < anchors.Count; i++) {
|
|||
|
|
if (anchors[i].MovementType == AnchorMovementType.BeforeInsertion) {
|
|||
|
|
if (expectedOffsets[i] > insertOffset)
|
|||
|
|
expectedOffsets[i] += insertLength;
|
|||
|
|
} else {
|
|||
|
|
if (expectedOffsets[i] >= insertOffset)
|
|||
|
|
expectedOffsets[i] += insertLength;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 3:
|
|||
|
|
int removalOffset = rnd.Next(document.TextLength);
|
|||
|
|
int removalLength = rnd.Next(document.TextLength - removalOffset);
|
|||
|
|
//Console.WriteLine("RemovalOffset=" + removalOffset + " RemovalLength="+removalLength);
|
|||
|
|
document.Remove(removalOffset, removalLength);
|
|||
|
|
for (int i = anchors.Count - 1; i >= 0; i--) {
|
|||
|
|
if (expectedOffsets[i] > removalOffset && expectedOffsets[i] < removalOffset + removalLength) {
|
|||
|
|
if (anchors[i].SurviveDeletion) {
|
|||
|
|
expectedOffsets[i] = removalOffset;
|
|||
|
|
} else {
|
|||
|
|
Assert.IsTrue(anchors[i].IsDeleted);
|
|||
|
|
anchors.RemoveAt(i);
|
|||
|
|
expectedOffsets.RemoveAt(i);
|
|||
|
|
}
|
|||
|
|
} else if (expectedOffsets[i] > removalOffset) {
|
|||
|
|
expectedOffsets[i] -= removalLength;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 4:
|
|||
|
|
int replaceOffset = rnd.Next(document.TextLength);
|
|||
|
|
int replaceRemovalLength = rnd.Next(document.TextLength - replaceOffset);
|
|||
|
|
int replaceInsertLength = rnd.Next(1000);
|
|||
|
|
//Console.WriteLine("ReplaceOffset=" + replaceOffset + " RemovalLength="+replaceRemovalLength + " InsertLength=" + replaceInsertLength);
|
|||
|
|
document.Replace(replaceOffset, replaceRemovalLength, new string(' ', replaceInsertLength));
|
|||
|
|
for (int i = anchors.Count - 1; i >= 0; i--) {
|
|||
|
|
if (expectedOffsets[i] > replaceOffset && expectedOffsets[i] < replaceOffset + replaceRemovalLength) {
|
|||
|
|
if (anchors[i].SurviveDeletion) {
|
|||
|
|
if (anchors[i].MovementType == AnchorMovementType.AfterInsertion)
|
|||
|
|
expectedOffsets[i] = replaceOffset + replaceInsertLength;
|
|||
|
|
else
|
|||
|
|
expectedOffsets[i] = replaceOffset;
|
|||
|
|
} else {
|
|||
|
|
Assert.IsTrue(anchors[i].IsDeleted);
|
|||
|
|
anchors.RemoveAt(i);
|
|||
|
|
expectedOffsets.RemoveAt(i);
|
|||
|
|
}
|
|||
|
|
} else if (expectedOffsets[i] > replaceOffset) {
|
|||
|
|
expectedOffsets[i] += replaceInsertLength - replaceRemovalLength;
|
|||
|
|
} else if (expectedOffsets[i] == replaceOffset && replaceRemovalLength == 0 && anchors[i].MovementType == AnchorMovementType.AfterInsertion) {
|
|||
|
|
expectedOffsets[i] += replaceInsertLength - replaceRemovalLength;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
Assert.AreEqual(anchors.Count, expectedOffsets.Count);
|
|||
|
|
for (int j = 0; j < anchors.Count; j++) {
|
|||
|
|
Assert.AreEqual(expectedOffsets[j], anchors[j].Offset);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
GC.KeepAlive(anchors);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void RepeatedTextDragDrop()
|
|||
|
|
{
|
|||
|
|
document.Text = new string(' ', 1000);
|
|||
|
|
for (int i = 0; i < 20; i++) {
|
|||
|
|
TextAnchor a = document.CreateAnchor(144);
|
|||
|
|
TextAnchor b = document.CreateAnchor(157);
|
|||
|
|
document.Insert(128, new string('a', 13));
|
|||
|
|
document.Remove(157, 13);
|
|||
|
|
a = document.CreateAnchor(128);
|
|||
|
|
b = document.CreateAnchor(141);
|
|||
|
|
|
|||
|
|
document.Insert(157, new string('b', 13));
|
|||
|
|
document.Remove(128, 13);
|
|||
|
|
|
|||
|
|
a = null;
|
|||
|
|
b = null;
|
|||
|
|
if ((i % 5) == 0)
|
|||
|
|
GC.Collect();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void ReplaceSpacesWithTab()
|
|||
|
|
{
|
|||
|
|
document.Text = "a b";
|
|||
|
|
TextAnchor before = document.CreateAnchor(1);
|
|||
|
|
before.MovementType = AnchorMovementType.AfterInsertion;
|
|||
|
|
TextAnchor after = document.CreateAnchor(5);
|
|||
|
|
TextAnchor survivingMiddle = document.CreateAnchor(2);
|
|||
|
|
TextAnchor deletedMiddle = document.CreateAnchor(3);
|
|||
|
|
|
|||
|
|
document.Replace(1, 4, "\t", OffsetChangeMappingType.CharacterReplace);
|
|||
|
|
Assert.AreEqual("a\tb", document.Text);
|
|||
|
|
// yes, the movement is a bit strange; but that's how CharacterReplace works when the text gets shorter
|
|||
|
|
Assert.AreEqual(1, before.Offset);
|
|||
|
|
Assert.AreEqual(2, after.Offset);
|
|||
|
|
Assert.AreEqual(2, survivingMiddle.Offset);
|
|||
|
|
Assert.AreEqual(2, deletedMiddle.Offset);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Test]
|
|||
|
|
public void ReplaceTwoCharactersWithThree()
|
|||
|
|
{
|
|||
|
|
document.Text = "a12b";
|
|||
|
|
TextAnchor before = document.CreateAnchor(1);
|
|||
|
|
before.MovementType = AnchorMovementType.AfterInsertion;
|
|||
|
|
TextAnchor after = document.CreateAnchor(3);
|
|||
|
|
before.MovementType = AnchorMovementType.BeforeInsertion;
|
|||
|
|
TextAnchor middleB = document.CreateAnchor(2);
|
|||
|
|
before.MovementType = AnchorMovementType.BeforeInsertion;
|
|||
|
|
TextAnchor middleA = document.CreateAnchor(2);
|
|||
|
|
before.MovementType = AnchorMovementType.AfterInsertion;
|
|||
|
|
|
|||
|
|
document.Replace(1, 2, "123", OffsetChangeMappingType.CharacterReplace);
|
|||
|
|
Assert.AreEqual("a123b", document.Text);
|
|||
|
|
Assert.AreEqual(1, before.Offset);
|
|||
|
|
Assert.AreEqual(4, after.Offset);
|
|||
|
|
Assert.AreEqual(2, middleA.Offset);
|
|||
|
|
Assert.AreEqual(2, middleB.Offset);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|