using System; using System.Collections.Generic; using Clave; using Glass.Editing; using UnitTestSharp; namespace Glass.UnitTests.Editing { public class EditBindingsTests : TestFixture { public const KeyCode Ctrl = KeyCode.ControlLeft; public const KeyCode Shift = KeyCode.ShiftLeft; public const KeyCode Alt = KeyCode.AltLeft; public static KeyboardSnapshot Press(KeyCode key, params KeyCode[] heldFirst) { return PressOnLayout(key, key, heldFirst); } public static KeyboardSnapshot PressOnLayout(KeyCode physicalKey, KeyCode layoutKey, params KeyCode[] heldFirst) { var tracker = new KeyTracker(); foreach (KeyCode held in heldFirst) { tracker.KeyDown(held, KeyCode.None, isRepeat: false); } return tracker.KeyDown(physicalKey, layoutKey, isRepeat: false); } public static KeyboardSnapshot Repeat(KeyCode key, params KeyCode[] heldFirst) { var tracker = new KeyTracker(); foreach (KeyCode held in heldFirst) { tracker.KeyDown(held, KeyCode.None, isRepeat: false); } tracker.KeyDown(key, KeyCode.None, isRepeat: false); return tracker.KeyDown(key, KeyCode.None, isRepeat: true); } public static KeyboardSnapshot Release(KeyCode key) { var tracker = new KeyTracker(); tracker.KeyDown(key, KeyCode.None, isRepeat: false); return tracker.KeyUp(key); } public static EditCommand? Resolve(EditBindings bindings, KeyboardSnapshot keyboard) { if (bindings.TryGetCommand(keyboard, out EditCommand command)) { return command; } return null; } public static EditCommand Move(TextUnit unit, bool forward, bool extend = false) { return new EditCommand(EditAction.Move, unit, forward, extend); } public static EditCommand Delete(TextUnit unit, bool forward) { return new EditCommand(EditAction.Delete, unit, forward); } public static EditCommand Simple(EditAction action) { return new EditCommand(action); } public static EditBinding Binding(Chord chord, EditAction action) { return new EditBinding(chord, Simple(action)); } public static EditBindings Physical(params EditBinding[] bindings) { return new EditBindings { Physical = bindings }; } public static EditBindings Layout(params EditBinding[] bindings) { return new EditBindings { Layout = bindings }; } public class CtorTests : TestFixture { public void Default_HasNothingBound() { var bindings = new EditBindings(); CheckEqual(0, bindings.Physical.Count); CheckEqual(0, bindings.Layout.Count); CheckFalse(bindings.TryGetCommand(Press(KeyCode.A), out EditCommand command)); CheckEqual(default(EditCommand), command); } } public class PhysicalTests : TestFixture { public void Binding_ResolvesToItsCommand() { EditBindings bindings = Physical(Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Cut)); CheckEqual(Simple(EditAction.Cut), Resolve(bindings, Press(KeyCode.F2))); } public void Binding_IgnoresTheLayout() { EditBindings bindings = Physical(Binding(Chord.PressOrRepeat(KeyCode.Z), EditAction.Cut)); CheckEqual(null, Resolve(bindings, PressOnLayout(KeyCode.Y, KeyCode.Z))); CheckEqual(Simple(EditAction.Cut), Resolve(bindings, PressOnLayout(KeyCode.Z, KeyCode.Y))); } public void MoveBinding_ExtendsWhileShiftIsHeld() { EditBindings bindings = Physical(new EditBinding(Chord.PressOrRepeat(KeyCode.F2), Move(TextUnit.Word, forward: true))); CheckEqual(Move(TextUnit.Word, forward: true), Resolve(bindings, Press(KeyCode.F2))); CheckEqual(Move(TextUnit.Word, forward: true, extend: true), Resolve(bindings, Press(KeyCode.F2, Shift))); } public void DeleteBinding_IgnoresShift() { EditBindings bindings = Physical(new EditBinding(Chord.PressOrRepeat(KeyCode.F2), Delete(TextUnit.Word, forward: true))); CheckEqual(Delete(TextUnit.Word, forward: true), Resolve(bindings, Press(KeyCode.F2, Shift))); } public void WhenUnrelatedChordsBothMatch_TheFirstListedWins() { EditBindings bindings = Physical( Binding(Chord.PressOrRepeat(KeyCode.F2).WithAnyHeld(KeyState.Shift), EditAction.Copy), Binding(Chord.PressOrRepeat(KeyCode.F2).WithAnyHeld(KeyState.Control), EditAction.Paste)); CheckEqual(Simple(EditAction.Copy), Resolve(bindings, Press(KeyCode.F2, Shift, Ctrl))); } public void MoreSpecificChord_HidesTheLessSpecificOne() { EditBindings bindings = Physical( Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Copy), Binding(Chord.PressOrRepeat(KeyCode.F2).WithAnyHeld(KeyState.Control), EditAction.Paste)); CheckEqual(Simple(EditAction.Paste), Resolve(bindings, Press(KeyCode.F2, Ctrl))); CheckEqual(Simple(EditAction.Copy), Resolve(bindings, Press(KeyCode.F2))); } public void LessSpecificChord_StillRunsWhenExtraKeysAreHeld() { EditBindings bindings = Physical( Binding(Chord.PressOrRepeat(KeyCode.F2).WithAnyHeld(KeyState.Control), EditAction.Paste)); CheckEqual(Simple(EditAction.Paste), Resolve(bindings, Press(KeyCode.F2, Ctrl, Alt))); } public void SameChordTwice_Throws() { Chord chord = Chord.PressOrRepeat(KeyCode.F2); CheckThrow(typeof(ArgumentException)); Physical(Binding(chord, EditAction.Copy), Binding(chord, EditAction.Paste)); } public void NullChord_Throws() { CheckThrow(typeof(ArgumentNullException)); Physical(Binding(null, EditAction.Copy)); } public void NullList_Throws() { CheckThrow(typeof(ArgumentNullException)); new EditBindings { Physical = null }; } public void GetsTheBindingsItWasGiven() { EditBinding first = Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Copy); EditBinding second = Binding(Chord.PressOrRepeat(KeyCode.F3), EditAction.Paste); EditBindings bindings = Physical(first, second); CheckEqual(2, bindings.Physical.Count); CheckEqual(first, bindings.Physical[0]); CheckEqual(second, bindings.Physical[1]); } public void ChangingTheListAfterwards_ChangesNothing() { var list = new List { Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Copy) }; var bindings = new EditBindings { Physical = list }; list.Clear(); CheckEqual(Simple(EditAction.Copy), Resolve(bindings, Press(KeyCode.F2))); } public void With_KeepsTheLayoutBindings() { EditBindings bindings = EditBindings.Windows with { Physical = [ .. EditBindings.Windows.Physical, Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Cut), ], }; CheckEqual(Simple(EditAction.Cut), Resolve(bindings, Press(KeyCode.F2))); CheckEqual(Move(TextUnit.Character, forward: false), Resolve(bindings, Press(KeyCode.ArrowLeft))); CheckEqual(Simple(EditAction.Undo), Resolve(bindings, Press(KeyCode.Z, Ctrl))); } public void With_LeavesTheOriginalAlone() { EditBindings original = EditBindings.Windows; EditBindings changed = original with { Physical = [.. original.Physical, Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Cut)], }; CheckEqual(null, Resolve(original, Press(KeyCode.F2))); CheckEqual(original.Physical.Count + 1, changed.Physical.Count); } public void With_AMoreSpecificChordOverridesTheOneItIsAddedTo() { EditBindings bindings = EditBindings.Windows with { Physical = [ .. EditBindings.Windows.Physical, Binding(Chord.PressOrRepeat(KeyCode.ArrowLeft).WithAnyHeld(KeyState.Alt), EditAction.Undo), ], }; CheckEqual(Simple(EditAction.Undo), Resolve(bindings, Press(KeyCode.ArrowLeft, Alt))); CheckEqual(Move(TextUnit.Character, forward: false), Resolve(bindings, Press(KeyCode.ArrowLeft))); } public void With_AChordAlreadyThere_Throws() { Chord chord = Chord.PressOrRepeat(KeyCode.F2); EditBindings bindings = Physical(Binding(chord, EditAction.Copy)); CheckThrow(typeof(ArgumentException)); bindings = bindings with { Physical = [.. bindings.Physical, Binding(chord, EditAction.Paste)] }; } } public class LayoutTests : TestFixture { public void Binding_FollowsTheLayout() { EditBindings bindings = Layout(Binding(Chord.PressOrRepeat(KeyCode.Z), EditAction.Cut)); CheckEqual(Simple(EditAction.Cut), Resolve(bindings, PressOnLayout(KeyCode.Y, KeyCode.Z))); CheckEqual(null, Resolve(bindings, PressOnLayout(KeyCode.Z, KeyCode.Y))); } public void MoveBinding_ExtendsWhileShiftIsHeld() { EditBindings bindings = Layout(new EditBinding(Chord.PressOrRepeat(KeyCode.F2), Move(TextUnit.Word, forward: true))); CheckEqual(Move(TextUnit.Word, forward: true, extend: true), Resolve(bindings, Press(KeyCode.F2, KeyCode.ShiftRight))); } public void SameChordTwice_Throws() { Chord chord = Chord.PressOrRepeat(KeyCode.F2); CheckThrow(typeof(ArgumentException)); Layout(Binding(chord, EditAction.Copy), Binding(chord, EditAction.Paste)); } public void NullChord_Throws() { CheckThrow(typeof(ArgumentNullException)); Layout(Binding(null, EditAction.Copy)); } public void NullList_Throws() { CheckThrow(typeof(ArgumentNullException)); new EditBindings { Layout = null }; } public void GetsTheBindingsItWasGiven() { EditBinding only = Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Copy); EditBindings bindings = Layout(only); CheckEqual(1, bindings.Layout.Count); CheckEqual(only, bindings.Layout[0]); } public void ChangingTheListAfterwards_ChangesNothing() { var list = new List { Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Copy) }; var bindings = new EditBindings { Layout = list }; list.Clear(); CheckEqual(Simple(EditAction.Copy), Resolve(bindings, Press(KeyCode.F2))); } public void With_KeepsThePhysicalBindings() { EditBindings bindings = EditBindings.Windows with { Layout = [.. EditBindings.Windows.Layout, Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Cut)], }; CheckEqual(Simple(EditAction.Cut), Resolve(bindings, Press(KeyCode.F2))); CheckEqual(Move(TextUnit.Character, forward: false), Resolve(bindings, Press(KeyCode.ArrowLeft))); CheckEqual(Simple(EditAction.Undo), Resolve(bindings, Press(KeyCode.Z, Ctrl))); } public void With_LeavesTheOriginalAlone() { EditBindings original = EditBindings.Windows; EditBindings changed = original with { Layout = [.. original.Layout, Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Cut)], }; CheckEqual(null, Resolve(original, Press(KeyCode.F2))); CheckEqual(original.Layout.Count + 1, changed.Layout.Count); } public void With_AMoreSpecificChordOverridesTheOneItIsAddedTo() { EditBindings bindings = EditBindings.Windows with { Layout = [ .. EditBindings.Windows.Layout, Binding(Chord.PressOrRepeat(KeyCode.V).WithAnyHeld(KeyState.Control).WithAnyHeld(KeyState.Alt), EditAction.Cut), ], }; CheckEqual(Simple(EditAction.Cut), Resolve(bindings, Press(KeyCode.V, Ctrl, Alt))); CheckEqual(Simple(EditAction.Paste), Resolve(bindings, Press(KeyCode.V, Ctrl))); } } public class FocusedBindings : Control { private readonly EditBindings bindings; public FocusedBindings(EditBindings bindings) { this.bindings = bindings; Focusable = true; } public override ChordSet KeyChords => bindings.KeyChords; } public class KeyChordsTests : TestFixture { public void HoldsEveryChordOfBothLists() { Chord physical = Chord.PressOrRepeat(KeyCode.F2); Chord layout = Chord.PressOrRepeat(KeyCode.F3); var bindings = new EditBindings { Physical = [Binding(physical, EditAction.Copy)], Layout = [Binding(layout, EditAction.Paste)], }; Check(bindings.KeyChords.Contains(physical)); Check(bindings.KeyChords.Contains(layout)); } public void HoldsAChordInBothListsOnce() { Chord chord = Chord.PressOrRepeat(KeyCode.F2); var bindings = new EditBindings { Physical = [Binding(chord, EditAction.Copy)], Layout = [Binding(chord, EditAction.Paste)], }; Check(bindings.KeyChords.Contains(chord)); } public void FollowsAChangeToEitherList() { Chord added = Chord.PressOrRepeat(KeyCode.F2); EditBindings changed = EditBindings.Windows with { Layout = [Binding(added, EditAction.Copy)] }; Check(changed.KeyChords.Contains(added)); CheckFalse(EditBindings.Windows.KeyChords.Contains(added)); } public void IsEmptyForNoBindings() { CheckFalse(new EditBindings().KeyChords.Contains(Chord.PressOrRepeat(KeyCode.F2))); } } public class TryGetCommandWithKeysTests : TestFixture { public static EditCommand? ResolveWithKeys(EditBindings bindings, KeyboardManager keys, KeyboardSnapshot keyboard) { if (bindings.TryGetCommand(keyboard, keys, out EditCommand command)) { return command; } return null; } public static KeyboardManager Focused(EditBindings bindings) { var keys = new KeyboardManager(); var control = new FocusedBindings(bindings); keys.Controls.Add(control); keys.TrySetFocus(control); return keys; } public void FindsTheSameCommandAsWithoutKeys() { EditBindings bindings = EditBindings.Windows; KeyboardManager keys = Focused(bindings); CheckEqual(Resolve(bindings, Press(KeyCode.Z, Ctrl)), ResolveWithKeys(bindings, keys, Press(KeyCode.Z, Ctrl))); CheckEqual(Resolve(bindings, Press(KeyCode.ArrowLeft)), ResolveWithKeys(bindings, keys, Press(KeyCode.ArrowLeft))); CheckEqual(Resolve(bindings, Press(KeyCode.F5)), ResolveWithKeys(bindings, keys, Press(KeyCode.F5))); } public void ShiftExtendsAMove() { EditBindings bindings = EditBindings.Windows; KeyboardManager keys = Focused(bindings); CheckEqual(Move(TextUnit.Character, forward: false, extend: true), ResolveWithKeys(bindings, keys, Press(KeyCode.ArrowLeft, Shift))); } public void AMoreSpecificChordOfTheSetHidesALessSpecificOne() { EditBindings bindings = EditBindings.Windows; KeyboardManager keys = Focused(bindings); CheckEqual(Move(TextUnit.Word, forward: false), ResolveWithKeys(bindings, keys, Press(KeyCode.ArrowLeft, Ctrl))); } public void AGameShortcutOnTheSameKeys_LosesToIt() { EditBindings bindings = EditBindings.Windows; KeyboardManager keys = Focused(bindings); keys.AddShortcut(Chord.PressOrRepeat(KeyCode.ArrowLeft)); CheckEqual(Move(TextUnit.Character, forward: false), ResolveWithKeys(bindings, keys, Press(KeyCode.ArrowLeft))); } public void AMoreSpecificGameShortcut_Wins() { EditBindings bindings = EditBindings.Windows; KeyboardManager keys = Focused(bindings); keys.AddShortcut(Chord.PressOrRepeat(KeyCode.ArrowLeft).WithAnyHeld(KeyState.Alt)); CheckEqual(null, ResolveWithKeys(bindings, keys, Press(KeyCode.ArrowLeft, Alt))); CheckEqual(Move(TextUnit.Character, forward: false), ResolveWithKeys(bindings, keys, Press(KeyCode.ArrowLeft))); } public void LayoutChordsAreAskedOfTheLayoutKeys() { EditBindings bindings = EditBindings.Windows; KeyboardManager keys = Focused(bindings); CheckEqual(Simple(EditAction.Undo), ResolveWithKeys(bindings, keys, PressOnLayout(KeyCode.Y, KeyCode.Z, Ctrl))); } public void NothingBound_FindsNothing() { var bindings = new EditBindings(); KeyboardManager keys = Focused(bindings); CheckEqual(null, ResolveWithKeys(bindings, keys, Press(KeyCode.A))); } } public class ExtendSelectionTests : TestFixture { public static EditBinding MoveWord() { return new EditBinding(Chord.PressOrRepeat(KeyCode.F2), Move(TextUnit.Word, forward: true)); } public void Default_IsEitherShiftKey() { EditBindings bindings = Physical(MoveWord()); CheckEqual(Move(TextUnit.Word, forward: true, extend: true), Resolve(bindings, Press(KeyCode.F2, KeyCode.ShiftLeft))); CheckEqual(Move(TextUnit.Word, forward: true, extend: true), Resolve(bindings, Press(KeyCode.F2, KeyCode.ShiftRight))); } public void NothingHeld_DoesNotExtend() { CheckEqual(Move(TextUnit.Word, forward: true), Resolve(Physical(MoveWord()), Press(KeyCode.F2))); } public void AnotherChord_ReplacesShift() { EditBindings bindings = Physical(MoveWord()) with { ExtendSelection = Chord.HoldAny(KeyState.Alt) }; CheckEqual(Move(TextUnit.Word, forward: true, extend: true), Resolve(bindings, Press(KeyCode.F2, Alt))); CheckEqual(Move(TextUnit.Word, forward: true), Resolve(bindings, Press(KeyCode.F2, Shift))); } public void ReachesMovesBoundToLayoutChordsToo() { EditBindings bindings = Layout(MoveWord()); CheckEqual(Move(TextUnit.Word, forward: true, extend: true), Resolve(bindings, Press(KeyCode.F2, Shift))); } public void CommandsThatDoNotMove_NeverExtend() { EditBindings bindings = Physical(Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Copy)); CheckEqual(Simple(EditAction.Copy), Resolve(bindings, Press(KeyCode.F2, Shift))); } public void Changing_KeepsTheBindings() { EditBindings changed = EditBindings.Windows with { ExtendSelection = Chord.HoldAny(KeyState.Alt) }; CheckEqual(Simple(EditAction.Undo), Resolve(changed, Press(KeyCode.Z, Ctrl))); CheckEqual(Move(TextUnit.Character, forward: false, extend: true), Resolve(changed, Press(KeyCode.ArrowLeft, Alt))); } public void Changing_LeavesTheOriginalAlone() { EditBindings original = EditBindings.Windows; EditBindings changed = original with { ExtendSelection = Chord.HoldAny(KeyState.Alt) }; CheckEqual(Move(TextUnit.Character, forward: false, extend: true), Resolve(original, Press(KeyCode.ArrowLeft, Shift))); CheckEqual(Move(TextUnit.Character, forward: false), Resolve(changed, Press(KeyCode.ArrowLeft, Shift))); } public void Get_ReturnsTheChordItWasSet() { Chord chord = Chord.HoldAny(KeyState.Alt); EditBindings bindings = new EditBindings { ExtendSelection = chord }; Check(ReferenceEquals(chord, bindings.ExtendSelection)); } public void Null_Throws() { CheckThrow(typeof(ArgumentNullException)); new EditBindings { ExtendSelection = null }; } } public class TryGetCommandTests : TestFixture { public void NothingBound_FindsNothing() { var bindings = new EditBindings { Physical = new EditBinding[0], Layout = new EditBinding[0] }; CheckFalse(bindings.TryGetCommand(Press(KeyCode.A), out EditCommand command)); CheckEqual(default(EditCommand), command); } public void PhysicalBindingsAreTriedBeforeLayoutOnes() { var bindings = new EditBindings { Physical = new[] { Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Paste) }, Layout = new[] { Binding(Chord.PressOrRepeat(KeyCode.F2), EditAction.Copy) }, }; CheckEqual(Simple(EditAction.Paste), Resolve(bindings, Press(KeyCode.F2))); } public void TheSameChordInBothLists_IsAllowed() { Chord chord = Chord.PressOrRepeat(KeyCode.F2); var bindings = new EditBindings { Physical = new[] { Binding(chord, EditAction.Copy) }, Layout = new[] { Binding(chord, EditAction.Paste) }, }; CheckEqual(Simple(EditAction.Copy), Resolve(bindings, Press(KeyCode.F2))); } public void AKeyComingUp_FindsNothing() { CheckEqual(null, Resolve(EditBindings.Windows, Release(KeyCode.ArrowLeft))); } public void AutoRepeat_FindsTheCommandAgain() { CheckEqual(Move(TextUnit.Character, forward: false), Resolve(EditBindings.Windows, Repeat(KeyCode.ArrowLeft))); } public void AKeyHeldWhileAnotherIsPressed_DoesNotRepeatTheFirst() { var tracker = new KeyTracker(); tracker.KeyDown(KeyCode.ArrowLeft, KeyCode.None, isRepeat: false); CheckEqual(null, Resolve(EditBindings.Windows, tracker.KeyDown(KeyCode.F5, KeyCode.None, isRepeat: false))); } } public class CommonTests : TestFixture { public void HasNoShortcutLetters() { CheckEqual(null, Resolve(EditBindings.Common, Press(KeyCode.A, Ctrl))); CheckEqual(null, Resolve(EditBindings.Common, Press(KeyCode.V, Ctrl))); } public void HasTheNavigationKeys() { CheckEqual(Move(TextUnit.Character, forward: true, extend: true), Resolve(EditBindings.Common, Press(KeyCode.ArrowRight, Shift))); CheckEqual(Delete(TextUnit.Character, forward: false), Resolve(EditBindings.Common, Press(KeyCode.Backspace))); } } public class WindowsTests : TestFixture { public static EditCommand? Resolved(KeyCode key, params KeyCode[] heldFirst) { return Resolve(EditBindings.Windows, Press(key, heldFirst)); } public void ArrowKeys_MoveByCharacter() { CheckEqual(Move(TextUnit.Character, forward: false), Resolved(KeyCode.ArrowLeft)); CheckEqual(Move(TextUnit.Character, forward: true), Resolved(KeyCode.ArrowRight)); } public void ShiftWithAnArrow_Extends() { CheckEqual(Move(TextUnit.Character, forward: false, extend: true), Resolved(KeyCode.ArrowLeft, Shift)); CheckEqual(Move(TextUnit.Character, forward: true, extend: true), Resolved(KeyCode.ArrowRight, KeyCode.ShiftRight)); } public void ControlWithAnArrow_MovesByWord() { CheckEqual(Move(TextUnit.Word, forward: false), Resolved(KeyCode.ArrowLeft, Ctrl)); CheckEqual(Move(TextUnit.Word, forward: true), Resolved(KeyCode.ArrowRight, KeyCode.ControlRight)); } public void ControlAndShiftWithAnArrow_ExtendsByWord() { CheckEqual(Move(TextUnit.Word, forward: false, extend: true), Resolved(KeyCode.ArrowLeft, Ctrl, Shift)); } public void HomeAndEnd_MoveToTheEdgesOfTheLine() { CheckEqual(Move(TextUnit.Line, forward: false), Resolved(KeyCode.Home)); CheckEqual(Move(TextUnit.Line, forward: true), Resolved(KeyCode.End)); CheckEqual(Move(TextUnit.Line, forward: true, extend: true), Resolved(KeyCode.End, Shift)); } public void ControlWithHomeAndEnd_MoveToTheEdgesOfTheText() { CheckEqual(Move(TextUnit.Document, forward: false), Resolved(KeyCode.Home, Ctrl)); CheckEqual(Move(TextUnit.Document, forward: true), Resolved(KeyCode.End, Ctrl)); CheckEqual(Move(TextUnit.Document, forward: true, extend: true), Resolved(KeyCode.End, Ctrl, Shift)); } public void BackspaceAndDelete_DeleteACharacter() { CheckEqual(Delete(TextUnit.Character, forward: false), Resolved(KeyCode.Backspace)); CheckEqual(Delete(TextUnit.Character, forward: true), Resolved(KeyCode.Delete)); } public void ShiftWithBackspace_StillDeletesACharacter() { CheckEqual(Delete(TextUnit.Character, forward: false), Resolved(KeyCode.Backspace, Shift)); } public void ControlWithBackspaceAndDelete_DeleteAWord() { CheckEqual(Delete(TextUnit.Word, forward: false), Resolved(KeyCode.Backspace, Ctrl)); CheckEqual(Delete(TextUnit.Word, forward: true), Resolved(KeyCode.Delete, Ctrl)); } public void ControlAndShiftWithDelete_DeleteAWordInsteadOfCutting() { CheckEqual(Delete(TextUnit.Word, forward: true), Resolved(KeyCode.Delete, Ctrl, Shift)); } public void OlderClipboardKeys_Work() { CheckEqual(Simple(EditAction.Copy), Resolved(KeyCode.Insert, Ctrl)); CheckEqual(Simple(EditAction.Paste), Resolved(KeyCode.Insert, Shift)); CheckEqual(Simple(EditAction.Cut), Resolved(KeyCode.Delete, Shift)); } public void InsertAlone_IsNotBound() { CheckEqual(null, Resolved(KeyCode.Insert)); } public void ControlLetters_RunTheShortcuts() { CheckEqual(Simple(EditAction.SelectAll), Resolved(KeyCode.A, Ctrl)); CheckEqual(Simple(EditAction.Copy), Resolved(KeyCode.C, Ctrl)); CheckEqual(Simple(EditAction.Cut), Resolved(KeyCode.X, Ctrl)); CheckEqual(Simple(EditAction.Paste), Resolved(KeyCode.V, Ctrl)); CheckEqual(Simple(EditAction.Undo), Resolved(KeyCode.Z, Ctrl)); CheckEqual(Simple(EditAction.Redo), Resolved(KeyCode.Y, Ctrl)); } public void ControlAndShiftWithZ_Redoes() { CheckEqual(Simple(EditAction.Redo), Resolved(KeyCode.Z, Ctrl, Shift)); } public void ShortcutLetters_FollowTheLayout() { CheckEqual(Simple(EditAction.Undo), Resolve(EditBindings.Windows, PressOnLayout(KeyCode.Y, KeyCode.Z, Ctrl))); CheckEqual(Simple(EditAction.Redo), Resolve(EditBindings.Windows, PressOnLayout(KeyCode.Z, KeyCode.Y, Ctrl))); } public void ArrowKeys_IgnoreTheLayout() { CheckEqual(Move(TextUnit.Character, forward: false), Resolve(EditBindings.Windows, PressOnLayout(KeyCode.ArrowLeft, KeyCode.A))); } public void ALetterWithoutControl_IsNotBound() { CheckEqual(null, Resolved(KeyCode.A)); CheckEqual(null, Resolved(KeyCode.Z, Shift)); } public void ControlWithAlt_StillRunsTheControlShortcut() { CheckEqual(Simple(EditAction.SelectAll), Resolved(KeyCode.A, Ctrl, Alt)); } public void ReadlineLetters_AreNotBound() { CheckEqual(null, Resolved(KeyCode.K, Ctrl)); CheckEqual(null, Resolved(KeyCode.B, Alt)); } } public class ReadlineTests : TestFixture { public static EditCommand? Resolved(KeyCode key, params KeyCode[] heldFirst) { return Resolve(EditBindings.Readline, Press(key, heldFirst)); } public void ControlAAndE_MoveToTheEdgesOfTheLine() { CheckEqual(Move(TextUnit.Line, forward: false), Resolved(KeyCode.A, Ctrl)); CheckEqual(Move(TextUnit.Line, forward: true), Resolved(KeyCode.E, Ctrl)); } public void ControlBAndF_MoveByCharacter() { CheckEqual(Move(TextUnit.Character, forward: false), Resolved(KeyCode.B, Ctrl)); CheckEqual(Move(TextUnit.Character, forward: true), Resolved(KeyCode.F, Ctrl)); } public void AltBAndF_MoveByWord() { CheckEqual(Move(TextUnit.Word, forward: false), Resolved(KeyCode.B, Alt)); CheckEqual(Move(TextUnit.Word, forward: true), Resolved(KeyCode.F, KeyCode.AltRight)); } public void ShiftWithALetterMove_Extends() { CheckEqual(Move(TextUnit.Line, forward: false, extend: true), Resolved(KeyCode.A, Ctrl, Shift)); } public void ControlHAndD_DeleteACharacter() { CheckEqual(Delete(TextUnit.Character, forward: false), Resolved(KeyCode.H, Ctrl)); CheckEqual(Delete(TextUnit.Character, forward: true), Resolved(KeyCode.D, Ctrl)); } public void ControlW_DeletesTheWordBefore() { CheckEqual(Delete(TextUnit.Word, forward: false), Resolved(KeyCode.W, Ctrl)); } public void AltD_DeletesTheWordAfter() { CheckEqual(Delete(TextUnit.Word, forward: true), Resolved(KeyCode.D, Alt)); } public void AltBackspace_DeletesTheWordBefore() { CheckEqual(Delete(TextUnit.Word, forward: false), Resolved(KeyCode.Backspace, Alt)); } public void ControlKAndU_DeleteToTheEdgesOfTheLine() { CheckEqual(Delete(TextUnit.Line, forward: true), Resolved(KeyCode.K, Ctrl)); CheckEqual(Delete(TextUnit.Line, forward: false), Resolved(KeyCode.U, Ctrl)); } public void ControlSlash_Undoes() { CheckEqual(Simple(EditAction.Undo), Resolved(KeyCode.Slash, Ctrl)); } public void ControlAndShiftWithCAndV_UseTheClipboard() { CheckEqual(Simple(EditAction.Copy), Resolved(KeyCode.C, Ctrl, Shift)); CheckEqual(Simple(EditAction.Paste), Resolved(KeyCode.V, Ctrl, Shift)); } public void ControlLettersFromWindows_AreNotBound() { CheckEqual(null, Resolved(KeyCode.C, Ctrl)); CheckEqual(null, Resolved(KeyCode.V, Ctrl)); CheckEqual(null, Resolved(KeyCode.Z, Ctrl)); CheckEqual(null, Resolved(KeyCode.Y, Ctrl)); CheckEqual(null, Resolved(KeyCode.X, Ctrl)); } public void ControlWithAlt_TakesTheControlMeaning() { CheckEqual(Move(TextUnit.Character, forward: false), Resolved(KeyCode.B, Ctrl, Alt)); } public void LettersFollowTheLayout() { CheckEqual(Delete(TextUnit.Line, forward: true), Resolve(EditBindings.Readline, PressOnLayout(KeyCode.Semicolon, KeyCode.K, Ctrl))); } public void TheCommonNavigationKeys_Work() { CheckEqual(Move(TextUnit.Character, forward: false, extend: true), Resolved(KeyCode.ArrowLeft, Shift)); CheckEqual(Move(TextUnit.Word, forward: true), Resolved(KeyCode.ArrowRight, Ctrl)); CheckEqual(Move(TextUnit.Line, forward: false), Resolved(KeyCode.Home)); CheckEqual(Delete(TextUnit.Character, forward: false), Resolved(KeyCode.Backspace)); CheckEqual(Delete(TextUnit.Word, forward: true), Resolved(KeyCode.Delete, Ctrl)); CheckEqual(Simple(EditAction.Paste), Resolved(KeyCode.Insert, Shift)); } public void PlainBackspace_IsNotTakenOverByAltBackspace() { CheckEqual(Delete(TextUnit.Character, forward: false), Resolved(KeyCode.Backspace)); } } } }