using Glass.Editing; using UnitTestSharp; namespace Glass.UnitTests.Editing { public class TextChangeTests : TestFixture { public static string Describe(TextChange change) { return $"({change.Start},{change.RemovedLength},{change.InsertedLength})"; } public static string Apply(string text, TextChange change, string inserted) { return text.Substring(0, change.Start) + inserted + text.Substring(change.Start + change.RemovedLength); } public class CtorTests : TestFixture { public void StoresTheStartAndBothLengths() { var change = new TextChange(start: 3, removedLength: 4, insertedLength: 5); CheckEqual(3, change.Start); CheckEqual(4, change.RemovedLength); CheckEqual(5, change.InsertedLength); } } public class ThenTests : TestFixture { public void AdjacentInserts_JoinIntoOne() { CheckEqual("(0,0,2)", Describe(new TextChange(0, 0, 1).Then(new TextChange(1, 0, 1)))); } public void AnEditInsideTheFirstInsert_ShrinksIt() { CheckEqual("(5,0,2)", Describe(new TextChange(5, 0, 3).Then(new TextChange(6, 1, 0)))); } public void AnEditBeforeTheFirst_CoversTheTextBetween() { CheckEqual("(4,8,9)", Describe(new TextChange(10, 2, 3).Then(new TextChange(4, 1, 1)))); } public void AnEditAfterTheFirst_CoversTheTextBetween() { CheckEqual("(0,9,11)", Describe(new TextChange(0, 0, 1).Then(new TextChange(10, 0, 1)))); } public void ADeleteThatSwallowsTheFirstInsertAndMore_ReachesIntoTheOldText() { CheckEqual("(0,7,0)", Describe(new TextChange(2, 0, 3).Then(new TextChange(0, 10, 0)))); } public void ADeleteThatUndoesTheFirstInsert_LeavesNothing() { CheckEqual("(3,0,0)", Describe(new TextChange(3, 0, 2).Then(new TextChange(3, 2, 0)))); } public void AnInsertWhereTheFirstDeleted_ReplacesWhatWasDeleted() { CheckEqual("(4,3,2)", Describe(new TextChange(4, 3, 0).Then(new TextChange(4, 0, 2)))); } public void AnEditThatStartsInsideTheFirstInsertAndEndsPastIt_ReachesIntoTheOldText() { CheckEqual("(2,4,3)", Describe(new TextChange(2, 1, 4).Then(new TextChange(4, 5, 1)))); } public void TwoEmptyChanges_StayEmpty() { CheckEqual("(5,0,0)", Describe(new TextChange(5, 0, 0).Then(new TextChange(5, 0, 0)))); } public void EveryPairOfSmallChanges_LeavesTheTextOutsideItUntouched() { const string original = "abcde"; var failures = new System.Collections.Generic.List(); for (int firstStart = 0; firstStart <= original.Length; ++firstStart) { for (int firstRemoved = 0; firstStart + firstRemoved <= original.Length; ++firstRemoved) { for (int firstInserted = 0; firstInserted <= 2; ++firstInserted) { var first = new TextChange(firstStart, firstRemoved, firstInserted); string middle = Apply(original, first, new string('1', firstInserted)); for (int secondStart = 0; secondStart <= middle.Length; ++secondStart) { for (int secondRemoved = 0; secondStart + secondRemoved <= middle.Length; ++secondRemoved) { for (int secondInserted = 0; secondInserted <= 2; ++secondInserted) { var second = new TextChange(secondStart, secondRemoved, secondInserted); string final = Apply(middle, second, new string('2', secondInserted)); TextChange folded = first.Then(second); bool headKept = original.Substring(0, folded.Start) == final.Substring(0, folded.Start); bool tailKept = original.Substring(folded.Start + folded.RemovedLength) == final.Substring(folded.Start + folded.InsertedLength); if (!headKept || !tailKept) { failures.Add(Describe(first) + " then " + Describe(second) + " gave " + Describe(folded)); } } } } } } } CheckEqual("", string.Join(", ", failures)); } } } }