using System; using Amphora; using Glass.Editing; using UnitTestSharp; namespace Glass.UnitTests.Editing { public class EditBufferTests : TestFixture { public static readonly string Pair = char.ConvertFromUtf32(0x20BB7); // Combining acute accent, a mark in the Basic Multilingual Plane. public static readonly string Acute = ((char)0x301).ToString(); public static EditBuffer Buffer(string text, int caret, int? anchor = null, int maxLength = EditBuffer.NoLimit) { var returnMe = new EditBuffer(maxLength) { Text = text }; if (anchor.HasValue) { returnMe.MoveTo(anchor.Value, extend: false); returnMe.MoveTo(caret, extend: true); } else { returnMe.MoveTo(caret, extend: false); } return returnMe; } public class CtorTests : TestFixture { public void StartsEmptyWithTheCaretAtZero() { var buffer = new EditBuffer(); CheckEqual("", buffer.Text); CheckEqual(0, buffer.Caret); CheckEqual(0, buffer.Anchor); CheckFalse(buffer.HasSelection); CheckEqual(0, buffer.Version); } public void Defaults_ToNoLimit() { CheckEqual(EditBuffer.NoLimit, new EditBuffer().MaxLength); } public void StoresMaxLength() { CheckEqual(12, new EditBuffer(maxLength: 12).MaxLength); } public void ZeroMaxLength_HoldsNothing() { var buffer = new EditBuffer(maxLength: 0); CheckFalse(buffer.Insert("a")); CheckEqual("", buffer.Text); } public void NegativeMaxLength_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new EditBuffer(maxLength: -1); } } public class SanitizeTests : TestFixture { public static StringView Sanitized(string text) { return EditBuffer.Sanitize(new StringView(text)); } public void TextThatNeedsNothing_IsReturnedAsIs() { string text = "plain text " + Pair; StringView cleaned = Sanitized(text); Check(ReferenceEquals(text, cleaned.Text)); CheckEqual(0, cleaned.StartIndex); CheckEqual(text.Length, cleaned.EndIndex); } public void EveryKindOfLineBreak_IsKept() { string breaks = "a\nb\rc\r\nd" + (char)0x85 + "e" + (char)0x2028 + "f" + (char)0x2029 + "g" + (char)0x0B + "h" + (char)0x0C + "i"; CheckEqual(breaks, Sanitized(breaks).ToString()); } public void OtherControlCharacters_AreDropped() { string text = "a" + (char)9 + "b" + (char)7 + "c" + (char)0x7F + "d" + (char)0x9F; CheckEqual("abcd", Sanitized(text).ToString()); } public void ControlCharactersBesideLineBreaks_AreDroppedAndTheBreaksKept() { CheckEqual("a\r\nb\nc", Sanitized("a" + (char)9 + "\r\nb" + (char)7 + "\nc").ToString()); } public void UnpairedSurrogates_AreDropped() { string text = "a" + (char)0xD842 + "b" + (char)0xDFB7 + "c" + (char)0xD842; CheckEqual("abc", Sanitized(text).ToString()); } public void PairsAmongTheDroppedChars_AreKept() { CheckEqual(Pair + "a" + Pair, Sanitized(Pair + (char)9 + "a" + Pair).ToString()); } public void ASliceOfALargerString_IsCleanedOnItsOwn() { string larger = "xx" + (char)9 + "ab" + (char)9 + "cd" + (char)9 + "yy"; CheckEqual("abcd", EditBuffer.Sanitize(new StringView(larger, 3, 9)).ToString()); } public void ASliceThatNeedsNothing_IsReturnedAsTheSameSlice() { string larger = "xx" + (char)9 + "abcd" + (char)9 + "yy"; var slice = new StringView(larger, 3, 7); StringView cleaned = EditBuffer.Sanitize(slice); Check(ReferenceEquals(larger, cleaned.Text)); CheckEqual(3, cleaned.StartIndex); CheckEqual(7, cleaned.EndIndex); } public void EmptyText_StaysEmpty() { CheckEqual("", Sanitized("").ToString()); } public void DefaultView_Throws() { CheckThrow(typeof(ArgumentNullException)); EditBuffer.Sanitize(default(StringView)); } } public class TextTests : TestFixture { public void Set_ReplacesTheTextAndPutsTheCaretAtTheEnd() { var buffer = Buffer("old", caret: 0); buffer.Text = "brand new"; CheckEqual("brand new", buffer.Text); CheckEqual(9, buffer.Caret); CheckEqual(9, buffer.Anchor); } public void Set_ClearsTheSelection() { var buffer = Buffer("hello", caret: 1, anchor: 4); buffer.Text = "hello"; CheckFalse(buffer.HasSelection); } public void Set_BumpsTheVersion() { var buffer = new EditBuffer(); buffer.Text = "abc"; CheckEqual(1, buffer.Version); } public void Set_TheSameTextWithTheCaretAlreadyAtTheEnd_LeavesTheVersion() { var buffer = new EditBuffer { Text = "abc" }; int version = buffer.Version; buffer.Text = "abc"; CheckEqual(version, buffer.Version); } public void Set_DropsTheCharactersThatCantBeTyped() { var buffer = new EditBuffer(); buffer.Text = "a" + (char)9 + "b" + (char)0xD842; CheckEqual("ab", buffer.Text); } public void Set_KeepsLineBreaksAsTheyWere() { var buffer = new EditBuffer(); buffer.Text = "a\r\nb\rc\nd"; CheckEqual("a\r\nb\rc\nd", buffer.Text); } public void Set_ExactlyMaxLength_Works() { var buffer = new EditBuffer(maxLength: 3); buffer.Text = "abc"; CheckEqual("abc", buffer.Text); } public void Set_LongerThanMaxLength_Throws() { var buffer = new EditBuffer(maxLength: 3); CheckThrow(typeof(ArgumentException)); buffer.Text = "abcd"; } public void Set_LongerThanMaxLength_ChangesNothing() { var buffer = Buffer("ab", caret: 1, maxLength: 3); try { buffer.Text = "abcd"; } catch (ArgumentException) { } CheckEqual("ab", buffer.Text); CheckEqual(1, buffer.Caret); } public void Set_Null_Throws() { var buffer = new EditBuffer(); CheckThrow(typeof(ArgumentNullException)); buffer.Text = null; } } public class VersionTests : TestFixture { public void EditingTheText_ChangesBothVersions() { var buffer = new EditBuffer(); int version = buffer.Version; int textVersion = buffer.TextVersion; buffer.Insert("a"); CheckEqual(version + 1, buffer.Version); CheckEqual(textVersion + 1, buffer.TextVersion); } public void SettingTheText_ChangesBothVersions() { var buffer = new EditBuffer(); buffer.Text = "abc"; CheckEqual(1, buffer.Version); CheckEqual(1, buffer.TextVersion); } public void MovingTheCaret_ChangesOnlyTheVersion() { var buffer = Buffer("abc", caret: 3); int textVersion = buffer.TextVersion; buffer.MoveTo(1, extend: false); CheckEqual(textVersion, buffer.TextVersion); Check(buffer.Version != textVersion); } public void ChangingTheSelection_ChangesOnlyTheVersion() { var buffer = Buffer("abc", caret: 3); int version = buffer.Version; int textVersion = buffer.TextVersion; buffer.SelectAll(); CheckEqual(version + 1, buffer.Version); CheckEqual(textVersion, buffer.TextVersion); } public void NothingChanging_ChangesNeither() { var buffer = Buffer("abc", caret: 3); int version = buffer.Version; int textVersion = buffer.TextVersion; buffer.MoveTo(3, extend: false); CheckEqual(version, buffer.Version); CheckEqual(textVersion, buffer.TextVersion); } public void ReplacingTextWithTheSameText_ChangesOnlyTheVersion() { var buffer = Buffer("abc", caret: 3); int version = buffer.Version; int textVersion = buffer.TextVersion; buffer.Replace(0, 1, "a"); CheckEqual(version + 1, buffer.Version); CheckEqual(textVersion, buffer.TextVersion); } } public class SelectionTests : TestFixture { public void NothingSelected_IsAnEmptyRangeAtTheCaret() { var buffer = Buffer("hello", caret: 2); CheckFalse(buffer.HasSelection); CheckEqual(2, buffer.SelectionStart); CheckEqual(2, buffer.SelectionEnd); CheckEqual(0, buffer.SelectionLength); CheckEqual("", buffer.SelectedText.ToString()); } public void CaretAfterTheAnchor_IsTheRangeBetweenThem() { var buffer = Buffer("hello", caret: 4, anchor: 1); Check(buffer.HasSelection); CheckEqual(1, buffer.SelectionStart); CheckEqual(4, buffer.SelectionEnd); CheckEqual(3, buffer.SelectionLength); CheckEqual("ell", buffer.SelectedText.ToString()); } public void CaretBeforeTheAnchor_IsTheSameRange() { var buffer = Buffer("hello", caret: 1, anchor: 4); CheckEqual(1, buffer.SelectionStart); CheckEqual(4, buffer.SelectionEnd); CheckEqual("ell", buffer.SelectedText.ToString()); } } public class ReplaceTests : TestFixture { public void ReplacesTheRange() { var buffer = Buffer("hello world", caret: 11); Check(buffer.Replace(0, 5, "bye")); CheckEqual("bye world", buffer.Text); } public void PutsTheCaretAfterWhatItInserted() { var buffer = Buffer("hello world", caret: 11); buffer.Replace(0, 5, "bye"); CheckEqual(3, buffer.Caret); CheckEqual(3, buffer.Anchor); } public void ZeroLength_Inserts() { var buffer = Buffer("ab", caret: 0); buffer.Replace(1, 0, "-"); CheckEqual("a-b", buffer.Text); } public void EmptyReplacement_Deletes() { var buffer = Buffer("abcd", caret: 0); buffer.Replace(1, 2, ""); CheckEqual("ad", buffer.Text); CheckEqual(1, buffer.Caret); } public void ClearsTheSelection() { var buffer = Buffer("hello", caret: 1, anchor: 4); buffer.Replace(0, 1, "j"); CheckFalse(buffer.HasSelection); } public void DropsTheCharactersThatCantBeTyped() { var buffer = new EditBuffer(); buffer.Replace(0, 0, "a" + (char)9 + "b"); CheckEqual("ab", buffer.Text); } public void KeepsLineBreaksAsTheyWere() { var buffer = new EditBuffer(); buffer.Replace(0, 0, "a\r\nb"); CheckEqual("a\r\nb", buffer.Text); } public void TakesASliceOfALargerString() { var buffer = Buffer("ab", caret: 0); buffer.Replace(1, 0, new StringView("xx-hello-yy", 3, 8)); CheckEqual("ahellob", buffer.Text); } public void CutsASliceToFitMaxLength() { var buffer = Buffer("ab", caret: 0, maxLength: 5); buffer.Replace(1, 0, new StringView("xx-hello-yy", 3, 8)); CheckEqual("ahelb", buffer.Text); } public void CaretMovesPastACombiningMarkAlreadyAfterTheReplacement() { var buffer = Buffer(Acute + "x", caret: 0); buffer.Replace(0, 0, "e"); CheckEqual("e" + Acute + "x", buffer.Text); CheckEqual(2, buffer.Caret); } public void CaretMovesPastALineFeedThatNowPairsWithTheReplacement() { var buffer = Buffer("\nx", caret: 0); buffer.Replace(0, 0, "\r"); CheckEqual("\r\nx", buffer.Text); CheckEqual(2, buffer.Caret); } public void ReplacingNothingInsideACharacter_MovesTheCaretPastIt() { var buffer = Buffer("e" + Acute, caret: 0); buffer.Replace(1, 0, ""); CheckEqual(2, buffer.Caret); } public void CutsTheReplacementToFitMaxLength() { var buffer = Buffer("abcde", caret: 0, maxLength: 5); buffer.Replace(1, 3, "wxyz"); CheckEqual("awxye", buffer.Text); } public void NothingChanged_ReturnsFalseAndLeavesTheVersion() { var buffer = Buffer("abc", caret: 1); int version = buffer.Version; CheckFalse(buffer.Replace(1, 0, "")); CheckEqual(version, buffer.Version); } public void ReplacingNothingWithNothing_StillMovesTheCaretThere() { var buffer = Buffer("abc", caret: 0); Check(buffer.Replace(2, 0, "")); CheckEqual("abc", buffer.Text); CheckEqual(2, buffer.Caret); } public void SuccessiveEdits_EachStartFromTheTextBeforeIt() { var buffer = Buffer("hello world", caret: 5); buffer.Replace(0, 5, "a much longer greeting"); buffer.Replace(0, 1, ""); buffer.Replace(buffer.Text.Length, 0, "!"); CheckEqual(" much longer greeting world!", buffer.Text); } public void NegativeStart_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentOutOfRangeException)); buffer.Replace(-1, 0, "x"); } public void StartPastTheEnd_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentOutOfRangeException)); buffer.Replace(4, 0, "x"); } public void NegativeLength_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentOutOfRangeException)); buffer.Replace(1, -1, "x"); } public void RangeRunningPastTheEnd_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentOutOfRangeException)); buffer.Replace(2, 2, "x"); } public void RangeStartingInsideAPair_Throws() { var buffer = Buffer("a" + Pair + "b", caret: 0); CheckThrow(typeof(ArgumentException)); buffer.Replace(2, 1, "x"); } public void RangeEndingInsideAPair_Throws() { var buffer = Buffer("a" + Pair + "b", caret: 0); CheckThrow(typeof(ArgumentException)); buffer.Replace(0, 2, "x"); } public void RangeStartingInsideACarriageReturnLineFeed_Throws() { var buffer = Buffer("a\r\nb", caret: 0); CheckThrow(typeof(ArgumentException)); buffer.Replace(2, 1, "x"); } public void RangeEndingInsideACarriageReturnLineFeed_Throws() { var buffer = Buffer("a\r\nb", caret: 0); CheckThrow(typeof(ArgumentException)); buffer.Replace(0, 2, "x"); } public void EmptyRangeInsideACarriageReturnLineFeed_Throws() { var buffer = Buffer("a\r\nb", caret: 0); CheckThrow(typeof(ArgumentException)); buffer.Replace(2, 0, "x"); } public void RangeAroundACarriageReturnLineFeed_Replaces() { var buffer = Buffer("a\r\nb", caret: 0); buffer.Replace(1, 2, "x"); CheckEqual("axb", buffer.Text); } public void NullReplacement_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentNullException)); buffer.Replace(0, 1, (string)null); } } public class InsertTests : TestFixture { public void AtTheCaret() { var buffer = Buffer("ac", caret: 1); Check(buffer.Insert("b")); CheckEqual("abc", buffer.Text); CheckEqual(2, buffer.Caret); } public void OverTheSelection() { var buffer = Buffer("hello world", caret: 0, anchor: 5); buffer.Insert("bye"); CheckEqual("bye world", buffer.Text); CheckEqual(3, buffer.Caret); CheckFalse(buffer.HasSelection); } public void BumpsTheVersion() { var buffer = new EditBuffer(); buffer.Insert("a"); CheckEqual(1, buffer.Version); } public void Nothing_ReturnsFalseAndLeavesTheVersion() { var buffer = Buffer("abc", caret: 1); int version = buffer.Version; CheckFalse(buffer.Insert("")); CheckEqual(version, buffer.Version); } public void APair_ArrivesWhole() { var buffer = new EditBuffer(); buffer.Insert(Pair); CheckEqual(Pair, buffer.Text); CheckEqual(2, buffer.Caret); } public void DropsTheCharactersThatCantBeTyped() { var buffer = new EditBuffer(); buffer.Insert("a" + (char)9 + "b"); CheckEqual("ab", buffer.Text); } public void LineBreaksAreKept() { var buffer = new EditBuffer(); buffer.Insert("a\nb"); CheckEqual("a\nb", buffer.Text); } public void TakesASliceOfALargerString() { var buffer = new EditBuffer(); buffer.Insert(new StringView("xx-hello-yy", 3, 8)); CheckEqual("hello", buffer.Text); CheckEqual(5, buffer.Caret); } public void NullString_Throws() { var buffer = new EditBuffer(); CheckThrow(typeof(ArgumentNullException)); buffer.Insert((string)null); } public void StopsAtMaxLength() { var buffer = new EditBuffer(maxLength: 5); buffer.Insert("abcdefgh"); CheckEqual("abcde", buffer.Text); } public void FillsTheRoomThatIsLeft() { var buffer = Buffer("abc", caret: 3, maxLength: 5); buffer.Insert("defg"); CheckEqual("abcde", buffer.Text); CheckEqual(5, buffer.Caret); } public void AtMaxLength_InsertsNothing() { var buffer = Buffer("abcde", caret: 2, maxLength: 5); int version = buffer.Version; CheckFalse(buffer.Insert("x")); CheckEqual("abcde", buffer.Text); CheckEqual(version, buffer.Version); } public void ReplacingASelectionFreesItsRoom() { var buffer = Buffer("abcde", caret: 4, anchor: 1, maxLength: 5); buffer.Insert("wxyz"); CheckEqual("awxye", buffer.Text); } public void APairThatFitsExactly_IsInserted() { var buffer = Buffer("ab", caret: 2, maxLength: 4); buffer.Insert(Pair); CheckEqual("ab" + Pair, buffer.Text); } public void APairThatWouldBeCutInHalf_IsLeftOut() { var buffer = Buffer("abc", caret: 3, maxLength: 4); CheckFalse(buffer.Insert(Pair)); CheckEqual("abc", buffer.Text); } public void ATextEndingInAPairThatDoesNotFit_KeepsTheCharsBeforeIt() { var buffer = Buffer("a", caret: 1, maxLength: 4); buffer.Insert("bc" + Pair); CheckEqual("abc", buffer.Text); } public void LineBreaksCountForTheirLength() { var buffer = new EditBuffer(maxLength: 4); buffer.Insert("\r\n\r\n\r\n"); CheckEqual("\r\n\r\n", buffer.Text); } public void ACarriageReturnLineFeedThatWouldBeCutInHalf_IsLeftOut() { var buffer = new EditBuffer(maxLength: 2); buffer.Insert("a\r\n"); CheckEqual("a", buffer.Text); } public void ALoneCarriageReturnAtTheCut_IsKept() { var buffer = new EditBuffer(maxLength: 2); buffer.Insert("a\rb"); CheckEqual("a\r", buffer.Text); } public void NeverGrowsPastMaxLengthAcrossManyInserts() { var buffer = new EditBuffer(maxLength: 5); buffer.Insert("ab"); buffer.Insert("ab"); buffer.Insert("ab"); CheckEqual("ababa", buffer.Text); } } public class DeleteTests : TestFixture { public void CharacterBackward_RemovesTheCharBeforeTheCaret() { var buffer = Buffer("abc", caret: 2); Check(buffer.Delete(TextUnit.Character, forward: false)); CheckEqual("ac", buffer.Text); CheckEqual(1, buffer.Caret); } public void CharacterForward_RemovesTheCharAfterTheCaret() { var buffer = Buffer("abc", caret: 1); Check(buffer.Delete(TextUnit.Character, forward: true)); CheckEqual("ac", buffer.Text); CheckEqual(1, buffer.Caret); } public void BackwardAtTheStart_ChangesNothing() { var buffer = Buffer("abc", caret: 0); int version = buffer.Version; CheckFalse(buffer.Delete(TextUnit.Character, forward: false)); CheckEqual(version, buffer.Version); } public void ForwardAtTheEnd_ChangesNothing() { var buffer = Buffer("abc", caret: 3); int version = buffer.Version; CheckFalse(buffer.Delete(TextUnit.Character, forward: true)); CheckEqual(version, buffer.Version); } public void CharacterBackward_RemovesAWholePair() { var buffer = Buffer("a" + Pair + "b", caret: 3); buffer.Delete(TextUnit.Character, forward: false); CheckEqual("ab", buffer.Text); CheckEqual(1, buffer.Caret); } public void CharacterForward_RemovesAWholePair() { var buffer = Buffer("a" + Pair + "b", caret: 1); buffer.Delete(TextUnit.Character, forward: true); CheckEqual("ab", buffer.Text); } public void CharacterBackward_RemovesAWholeCarriageReturnLineFeed() { var buffer = Buffer("a\r\nb", caret: 3); buffer.Delete(TextUnit.Character, forward: false); CheckEqual("ab", buffer.Text); CheckEqual(1, buffer.Caret); } public void CharacterForward_RemovesAWholeCarriageReturnLineFeed() { var buffer = Buffer("a\r\nb", caret: 1); buffer.Delete(TextUnit.Character, forward: true); CheckEqual("ab", buffer.Text); } public void LineBackward_StopsAtAnyKindOfBreak() { var buffer = Buffer("ab\r\ncd" + (char)0x2028 + "ef", caret: 9); buffer.Delete(TextUnit.Line, forward: false); CheckEqual("ab\r\ncd" + (char)0x2028, buffer.Text); } public void CharacterBackward_RemovesTheCharacterAndItsMarks() { var buffer = Buffer("xe" + Acute + Acute, caret: 4); buffer.Delete(TextUnit.Character, forward: false); CheckEqual("x", buffer.Text); CheckEqual(1, buffer.Caret); } public void CharacterForward_RemovesTheCharacterAndItsMarks() { var buffer = Buffer("xe" + Acute + "y", caret: 1); buffer.Delete(TextUnit.Character, forward: true); CheckEqual("xy", buffer.Text); } public void WithASelection_RemovesOnlyTheSelection() { var buffer = Buffer("hello world", caret: 0, anchor: 5); buffer.Delete(TextUnit.Word, forward: false); CheckEqual(" world", buffer.Text); CheckEqual(0, buffer.Caret); } public void WordBackward_RemovesBackToTheStartOfTheWord() { var buffer = Buffer("hello world", caret: 11); buffer.Delete(TextUnit.Word, forward: false); CheckEqual("hello ", buffer.Text); CheckEqual(6, buffer.Caret); } public void WordForward_RemovesUpToTheNextWord() { var buffer = Buffer("hello world", caret: 0); buffer.Delete(TextUnit.Word, forward: true); CheckEqual("world", buffer.Text); CheckEqual(0, buffer.Caret); } public void LineBackward_RemovesBackToTheStartOfTheLine() { var buffer = Buffer("ab\ncd", caret: 4); buffer.Delete(TextUnit.Line, forward: false); CheckEqual("ab\nd", buffer.Text); CheckEqual(3, buffer.Caret); } public void LineForward_RemovesToTheEndOfTheLine() { var buffer = Buffer("ab\ncd", caret: 0); buffer.Delete(TextUnit.Line, forward: true); CheckEqual("\ncd", buffer.Text); } public void LineForwardAtTheEndOfALine_ChangesNothing() { var buffer = Buffer("ab\ncd", caret: 2); CheckFalse(buffer.Delete(TextUnit.Line, forward: true)); } public void DocumentBackward_RemovesEverythingBeforeTheCaret() { var buffer = Buffer("abcd", caret: 2); buffer.Delete(TextUnit.Document, forward: false); CheckEqual("cd", buffer.Text); } public void DocumentForward_RemovesEverythingAfterTheCaret() { var buffer = Buffer("abcd", caret: 2); buffer.Delete(TextUnit.Document, forward: true); CheckEqual("ab", buffer.Text); } public void BumpsTheVersion() { var buffer = Buffer("abc", caret: 3); int version = buffer.Version; buffer.Delete(TextUnit.Character, forward: false); CheckEqual(version + 1, buffer.Version); } } public class MoveToTests : TestFixture { public void PutsTheCaretThereAndClearsTheSelection() { var buffer = Buffer("hello", caret: 1, anchor: 4); Check(buffer.MoveTo(2, extend: false)); CheckEqual(2, buffer.Caret); CheckEqual(2, buffer.Anchor); } public void Extending_KeepsTheAnchor() { var buffer = Buffer("hello", caret: 1); buffer.MoveTo(4, extend: true); CheckEqual(4, buffer.Caret); CheckEqual(1, buffer.Anchor); CheckEqual("ell", buffer.SelectedText.ToString()); } public void IndexInsideAPair_MovesBackToItsStart() { var buffer = Buffer("a" + Pair + "b", caret: 0); buffer.MoveTo(2, extend: false); CheckEqual(1, buffer.Caret); } public void IndexInsideACarriageReturnLineFeed_MovesBackToItsStart() { var buffer = Buffer("a\r\nb", caret: 0); buffer.MoveTo(2, extend: false); CheckEqual(1, buffer.Caret); } public void IndexBetweenACharacterAndItsMark_MovesBackToTheCharacter() { var buffer = Buffer("e" + Acute + "x", caret: 3); buffer.MoveTo(1, extend: false); CheckEqual(0, buffer.Caret); } public void WhereItAlreadyIs_ChangesNothing() { var buffer = Buffer("hello", caret: 2); int version = buffer.Version; CheckFalse(buffer.MoveTo(2, extend: false)); CheckEqual(version, buffer.Version); } public void NegativeIndex_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentOutOfRangeException)); buffer.MoveTo(-1, extend: false); } public void IndexPastTheEnd_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentOutOfRangeException)); buffer.MoveTo(4, extend: false); } } public class MoveTests : TestFixture { public void CharacterForward_StepsRight() { var buffer = Buffer("abc", caret: 1); Check(buffer.Move(TextUnit.Character, forward: true, extend: false)); CheckEqual(2, buffer.Caret); CheckEqual(2, buffer.Anchor); } public void CharacterBackward_StepsLeft() { var buffer = Buffer("abc", caret: 2); buffer.Move(TextUnit.Character, forward: false, extend: false); CheckEqual(1, buffer.Caret); } public void AtTheEdges_ChangesNothing() { var buffer = Buffer("abc", caret: 0); int version = buffer.Version; CheckFalse(buffer.Move(TextUnit.Character, forward: false, extend: false)); CheckEqual(version, buffer.Version); buffer.MoveTo(3, extend: false); version = buffer.Version; CheckFalse(buffer.Move(TextUnit.Character, forward: true, extend: false)); CheckEqual(version, buffer.Version); } public void CharacterForward_StepsOverAWholePair() { var buffer = Buffer("a" + Pair + "b", caret: 1); buffer.Move(TextUnit.Character, forward: true, extend: false); CheckEqual(3, buffer.Caret); } public void CharacterWithASelection_CollapsesToItsLeftEdgeGoingBack() { var buffer = Buffer("hello", caret: 4, anchor: 1); buffer.Move(TextUnit.Character, forward: false, extend: false); CheckEqual(1, buffer.Caret); CheckFalse(buffer.HasSelection); } public void CharacterWithASelection_CollapsesToItsRightEdgeGoingForward() { var buffer = Buffer("hello", caret: 1, anchor: 4); buffer.Move(TextUnit.Character, forward: true, extend: false); CheckEqual(4, buffer.Caret); CheckFalse(buffer.HasSelection); } public void CharacterForward_StepsOverACarriageReturnLineFeed() { var buffer = Buffer("a\r\nb", caret: 1); buffer.Move(TextUnit.Character, forward: true, extend: false); CheckEqual(3, buffer.Caret); } public void LineForward_StopsBeforeACarriageReturnLineFeed() { var buffer = Buffer("ab\r\ncd", caret: 0); buffer.Move(TextUnit.Line, forward: true, extend: false); CheckEqual(2, buffer.Caret); } public void LineBackward_GoesToTheStartAfterACarriageReturnLineFeed() { var buffer = Buffer("ab\r\ncd", caret: 6); buffer.Move(TextUnit.Line, forward: false, extend: false); CheckEqual(4, buffer.Caret); } public void CharacterForward_StepsOverTheMarksToo() { var buffer = Buffer("e" + Acute + Acute + "x", caret: 0); buffer.Move(TextUnit.Character, forward: true, extend: false); CheckEqual(3, buffer.Caret); } public void CharacterBackward_StepsOverTheMarksToo() { var buffer = Buffer("xe" + Acute + Acute, caret: 4); buffer.Move(TextUnit.Character, forward: false, extend: false); CheckEqual(1, buffer.Caret); } public void Extending_GrowsTheSelectionFromTheAnchor() { var buffer = Buffer("hello", caret: 2); buffer.Move(TextUnit.Character, forward: true, extend: true); buffer.Move(TextUnit.Character, forward: true, extend: true); CheckEqual(4, buffer.Caret); CheckEqual(2, buffer.Anchor); } public void Extending_BackPastTheAnchor_FlipsTheSelection() { var buffer = Buffer("hello", caret: 2); buffer.Move(TextUnit.Character, forward: false, extend: true); buffer.Move(TextUnit.Character, forward: false, extend: true); buffer.Move(TextUnit.Character, forward: false, extend: true); CheckEqual(0, buffer.Caret); CheckEqual(2, buffer.Anchor); CheckEqual("he", buffer.SelectedText.ToString()); } public void WordForward_GoesToTheStartOfTheNextWord() { var buffer = Buffer("one two", caret: 0); buffer.Move(TextUnit.Word, forward: true, extend: false); CheckEqual(4, buffer.Caret); } public void WordForward_StepsPastAMarkOnASpace() { var buffer = Buffer("a " + Acute + "b", caret: 0); buffer.Move(TextUnit.Word, forward: true, extend: false); CheckEqual(3, buffer.Caret); buffer.Move(TextUnit.Word, forward: true, extend: false); CheckEqual(4, buffer.Caret); } public void WordBackward_GoesToTheStartOfTheWord() { var buffer = Buffer("one two", caret: 7); buffer.Move(TextUnit.Word, forward: false, extend: false); CheckEqual(4, buffer.Caret); } public void WordWithASelection_MovesFromTheCaret() { var buffer = Buffer("one two three", caret: 7, anchor: 4); buffer.Move(TextUnit.Word, forward: true, extend: false); CheckEqual(8, buffer.Caret); CheckFalse(buffer.HasSelection); } public void LineForward_GoesToTheEndOfTheLine() { var buffer = Buffer("ab\ncd", caret: 3); buffer.Move(TextUnit.Line, forward: true, extend: false); CheckEqual(5, buffer.Caret); } public void LineBackward_GoesToTheStartOfTheLine() { var buffer = Buffer("ab\ncd", caret: 4); buffer.Move(TextUnit.Line, forward: false, extend: false); CheckEqual(3, buffer.Caret); } public void LineExtending_SelectsToTheEdge() { var buffer = Buffer("ab\ncd", caret: 4); buffer.Move(TextUnit.Line, forward: false, extend: true); CheckEqual("c", buffer.SelectedText.ToString()); } public void DocumentForward_GoesToTheEnd() { var buffer = Buffer("ab\ncd", caret: 1); buffer.Move(TextUnit.Document, forward: true, extend: false); CheckEqual(5, buffer.Caret); } public void DocumentBackward_GoesToTheStart() { var buffer = Buffer("ab\ncd", caret: 4); buffer.Move(TextUnit.Document, forward: false, extend: false); CheckEqual(0, buffer.Caret); } } public class SelectAllTests : TestFixture { public void SelectsEverythingWithTheCaretAtTheEnd() { var buffer = Buffer("hello", caret: 2); Check(buffer.SelectAll()); CheckEqual(0, buffer.Anchor); CheckEqual(5, buffer.Caret); CheckEqual("hello", buffer.SelectedText.ToString()); } public void WhenEverythingIsAlreadySelected_ChangesNothing() { var buffer = Buffer("hello", caret: 5, anchor: 0); int version = buffer.Version; CheckFalse(buffer.SelectAll()); CheckEqual(version, buffer.Version); } public void EmptyText_ChangesNothing() { CheckFalse(new EditBuffer().SelectAll()); } } public class SelectUnitAtTests : TestFixture { public void Word_SelectsTheWordAtTheIndex() { var buffer = Buffer("hello world", caret: 0); Check(buffer.SelectUnitAt(8, TextUnit.Word)); CheckEqual("world", buffer.SelectedText.ToString()); CheckEqual(11, buffer.Caret); CheckEqual(6, buffer.Anchor); } public void Word_AfterAMarkOnASpace_SelectsFromAWholeCharacter() { var buffer = Buffer("a " + Acute + "b", caret: 0); buffer.SelectUnitAt(3, TextUnit.Word); CheckEqual("b", buffer.SelectedText.ToString()); } public void Line_SelectsTheLineWithoutItsNewline() { var buffer = Buffer("ab\ncd\nef", caret: 0); buffer.SelectUnitAt(4, TextUnit.Line); CheckEqual("cd", buffer.SelectedText.ToString()); } public void Document_SelectsEverything() { var buffer = Buffer("ab\ncd", caret: 0); buffer.SelectUnitAt(1, TextUnit.Document); CheckEqual("ab\ncd", buffer.SelectedText.ToString()); } public void SelectingTheSameRangeAgain_ChangesNothing() { var buffer = Buffer("hello world", caret: 0); buffer.SelectUnitAt(8, TextUnit.Word); int version = buffer.Version; CheckFalse(buffer.SelectUnitAt(8, TextUnit.Word)); CheckEqual(version, buffer.Version); } public void Character_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentOutOfRangeException)); buffer.SelectUnitAt(1, TextUnit.Character); } public void IndexPastTheEnd_Throws() { var buffer = Buffer("abc", caret: 0); CheckThrow(typeof(ArgumentOutOfRangeException)); buffer.SelectUnitAt(4, TextUnit.Word); } } public class CaretAtLineEndTests : TestFixture { public void NewBuffer_IsFalse() { CheckFalse(new EditBuffer().CaretAtLineEnd); } public void MovingForward_IsFalse() { EditBuffer buffer = Buffer("one two three", caret: 5); buffer.Move(TextUnit.Character, forward: false, extend: false); buffer.Move(TextUnit.Character, forward: true, extend: false); CheckFalse(buffer.CaretAtLineEnd); buffer.Move(TextUnit.Word, forward: false, extend: false); buffer.Move(TextUnit.Word, forward: true, extend: false); CheckFalse(buffer.CaretAtLineEnd); } public void MovingBackward_IsTrue() { EditBuffer buffer = Buffer("one two three", caret: 5); buffer.Move(TextUnit.Character, forward: false, extend: false); Check(buffer.CaretAtLineEnd); buffer.Move(TextUnit.Word, forward: false, extend: false); Check(buffer.CaretAtLineEnd); } public void ExtendingBackward_IsTrue() { EditBuffer buffer = Buffer("one two", caret: 5); buffer.Move(TextUnit.Character, forward: false, extend: true); Check(buffer.CaretAtLineEnd); } public void CollapsingASelectionToItsStart_IsTrue() { EditBuffer buffer = Buffer("one two", caret: 5, anchor: 2); buffer.Move(TextUnit.Character, forward: false, extend: false); Check(buffer.CaretAtLineEnd); } public void CollapsingASelectionToItsEnd_IsFalse() { EditBuffer buffer = Buffer("one two", caret: 2, anchor: 5); buffer.MoveTo(2, extend: false, atLineEnd: true); buffer.MoveTo(5, extend: true, atLineEnd: true); buffer.MoveTo(2, extend: true, atLineEnd: true); buffer.Move(TextUnit.Character, forward: true, extend: false); CheckFalse(buffer.CaretAtLineEnd); } public void MoveTo_TakesTheSideItIsGiven() { EditBuffer buffer = Buffer("one two", caret: 0); buffer.MoveTo(3, extend: false, atLineEnd: true); Check(buffer.CaretAtLineEnd); buffer.MoveTo(3, extend: false); CheckFalse(buffer.CaretAtLineEnd); } public void MoveTo_ExtendingTakesTheSideItIsGiven() { EditBuffer buffer = Buffer("one two", caret: 0); buffer.MoveTo(3, extend: true, atLineEnd: true); Check(buffer.CaretAtLineEnd); } public void ChangingOnlyTheSide_IsAChange() { EditBuffer buffer = Buffer("one two", caret: 3); int version = buffer.Version; int textVersion = buffer.TextVersion; Check(buffer.MoveTo(3, extend: false, atLineEnd: true)); CheckFalse(version == buffer.Version); CheckEqual(textVersion, buffer.TextVersion); } public void RepeatingTheSameSide_ChangesNothing() { EditBuffer buffer = Buffer("one two", caret: 3); buffer.MoveTo(3, extend: false, atLineEnd: true); int version = buffer.Version; CheckFalse(buffer.MoveTo(3, extend: false, atLineEnd: true)); CheckEqual(version, buffer.Version); } public void Typing_IsFalse() { EditBuffer buffer = Buffer("one two", caret: 3); buffer.MoveTo(3, extend: false, atLineEnd: true); buffer.Insert("x"); CheckFalse(buffer.CaretAtLineEnd); } public void ReplacingText_IsFalse() { EditBuffer buffer = Buffer("one two", caret: 3); buffer.MoveTo(3, extend: false, atLineEnd: true); buffer.Replace(0, 1, "x"); CheckFalse(buffer.CaretAtLineEnd); } public void SettingTheText_IsFalse() { EditBuffer buffer = Buffer("one two", caret: 3); buffer.MoveTo(3, extend: false, atLineEnd: true); buffer.Text = "new"; CheckFalse(buffer.CaretAtLineEnd); } public void DeletingBackward_IsTrue() { EditBuffer buffer = Buffer("one two", caret: 3); buffer.Delete(TextUnit.Character, forward: false); Check(buffer.CaretAtLineEnd); } public void DeletingForward_IsFalse() { EditBuffer buffer = Buffer("one two", caret: 3); buffer.MoveTo(3, extend: false, atLineEnd: true); buffer.Delete(TextUnit.Character, forward: true); CheckFalse(buffer.CaretAtLineEnd); } public void DeletingASelection_IsFalse() { EditBuffer buffer = Buffer("one two", caret: 5, anchor: 2); buffer.MoveTo(5, extend: true, atLineEnd: true); buffer.Delete(TextUnit.Character, forward: false); CheckFalse(buffer.CaretAtLineEnd); } public void SelectingAll_KeepsTheSide() { EditBuffer buffer = Buffer("one two", caret: 3); buffer.SelectAll(); CheckFalse(buffer.CaretAtLineEnd); buffer.MoveTo(3, extend: false, atLineEnd: true); buffer.SelectAll(); Check(buffer.CaretAtLineEnd); } public void SelectingAUnit_IsTrue() { EditBuffer buffer = Buffer("one two", caret: 0); buffer.SelectUnitAt(5, TextUnit.Word); Check(buffer.CaretAtLineEnd); } public void NothingChanging_StaysAsItWas() { EditBuffer buffer = Buffer("", caret: 0); CheckFalse(buffer.Delete(TextUnit.Character, forward: false)); CheckFalse(buffer.CaretAtLineEnd); } } } }