using System; using System.Collections.Generic; using UnitTestSharp; namespace Clave.UnitTests { public class KeyLabelerTests : TestFixture { // Names every physical letter in lower case, as a host naming the keys its layout prints might. public class LowerCaseLabeler : KeyLabeler { public override string LabelOf(KeyCode key) { return IsPrintable(key) ? base.LabelOf(key).ToLowerInvariant() : base.LabelOf(key); } } public static string SortedAlternatives(string label) { string[] parts = label.Split(new[] { KeyLabeler.AlternativeSeparator }, StringSplitOptions.None); Array.Sort(parts, StringComparer.Ordinal); return string.Join(KeyLabeler.AlternativeSeparator, parts); } public class IsPrintableTests : TestFixture { public void Letters_AreThere() { CheckTrue(KeyLabeler.IsPrintable(KeyCode.A)); CheckTrue(KeyLabeler.IsPrintable(KeyCode.Z)); } public void Digits_AreThere() { CheckTrue(KeyLabeler.IsPrintable(KeyCode.Digit0)); CheckTrue(KeyLabeler.IsPrintable(KeyCode.Digit9)); } public void Punctuation_IsThere() { CheckTrue(KeyLabeler.IsPrintable(KeyCode.Minus)); CheckTrue(KeyLabeler.IsPrintable(KeyCode.Backquote)); } public void KeysThatPrintNothing_AreNot() { CheckFalse(KeyLabeler.IsPrintable(KeyCode.None)); CheckFalse(KeyLabeler.IsPrintable(KeyCode.Space)); CheckFalse(KeyLabeler.IsPrintable(KeyCode.Escape)); CheckFalse(KeyLabeler.IsPrintable(KeyCode.ArrowUp)); CheckFalse(KeyLabeler.IsPrintable(KeyCode.F1)); CheckFalse(KeyLabeler.IsPrintable(KeyCode.ShiftLeft)); CheckFalse(KeyLabeler.IsPrintable(KeyCode.Numpad4)); CheckFalse(KeyLabeler.IsPrintable(KeyCode.NumpadEnter)); } } public class EnglishNameTests : TestFixture { public void EveryKey_HasAName() { foreach (KeyCode key in Enum.GetValues(typeof(KeyCode))) { if (key != KeyCode.None) { CheckFalse(string.IsNullOrEmpty(KeyLabeler.EnglishName(key))); } } } public void NoTwoKeys_ShareAName() { var seen = new HashSet(); foreach (KeyCode key in Enum.GetValues(typeof(KeyCode))) { if (key != KeyCode.None) { CheckTrue(seen.Add(KeyLabeler.EnglishName(key))); } } } public void Letters_AreCapitals() { CheckEqual("A", KeyLabeler.EnglishName(KeyCode.A)); CheckEqual("Z", KeyLabeler.EnglishName(KeyCode.Z)); } public void Digits_AreTheDigit() { CheckEqual("0", KeyLabeler.EnglishName(KeyCode.Digit0)); CheckEqual("9", KeyLabeler.EnglishName(KeyCode.Digit9)); } public void Keypad_IsPrefixedWithNum() { CheckEqual("Num 4", KeyLabeler.EnglishName(KeyCode.Numpad4)); CheckEqual("Num +", KeyLabeler.EnglishName(KeyCode.NumpadAdd)); CheckEqual("Num Enter", KeyLabeler.EnglishName(KeyCode.NumpadEnter)); } public void NavigationAndEditingKeys_AreWordsPeopleKnow() { CheckEqual("Up", KeyLabeler.EnglishName(KeyCode.ArrowUp)); CheckEqual("Page Down", KeyLabeler.EnglishName(KeyCode.PageDown)); CheckEqual("Esc", KeyLabeler.EnglishName(KeyCode.Escape)); CheckEqual("Enter", KeyLabeler.EnglishName(KeyCode.MainEnter)); CheckEqual("Backspace", KeyLabeler.EnglishName(KeyCode.Backspace)); CheckEqual("Caps Lock", KeyLabeler.EnglishName(KeyCode.CapsLock)); } public void ModifiersAndPunctuation_AreNamed() { CheckEqual("Left Shift", KeyLabeler.EnglishName(KeyCode.ShiftLeft)); CheckEqual("Right Ctrl", KeyLabeler.EnglishName(KeyCode.ControlRight)); CheckEqual("Left Alt", KeyLabeler.EnglishName(KeyCode.AltLeft)); CheckEqual("[", KeyLabeler.EnglishName(KeyCode.BracketLeft)); CheckEqual("\\", KeyLabeler.EnglishName(KeyCode.Backslash)); } public void None_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); KeyLabeler.EnglishName(KeyCode.None); } } public class LabelOfKeyTests : TestFixture { public void Default_IsTheEnglishName() { CheckEqual("Esc", new KeyLabeler().LabelOf(KeyCode.Escape)); } public void Override_ReplacesIt() { CheckEqual("w", new LowerCaseLabeler().LabelOf(KeyCode.W)); } } public class LabelOfKeyInSpaceTests : TestFixture { public void Physical_UsesTheHostsName() { CheckEqual("w", new LowerCaseLabeler().LabelOf(KeyCode.W, KeySpace.Physical)); } public void Layout_UsesTheEnglishNameOfTheCode() { CheckEqual("W", new LowerCaseLabeler().LabelOf(KeyCode.W, KeySpace.Layout)); } public void UnknownSpace_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new KeyLabeler().LabelOf(KeyCode.W, (KeySpace)99); } } public class LabelOfChordTests : TestFixture { public static string Label(Chord chord) { return new KeyLabeler().LabelOf(chord); } public void SingleKey_IsItsName() { CheckEqual("Z", Label(Chord.Press(KeyCode.Z))); } public void Kind_IsLeftOut() { CheckEqual("Z", Label(Chord.Hold(KeyCode.Z))); CheckEqual("Z", Label(Chord.Release(KeyCode.Z))); CheckEqual("Z", Label(Chord.PressOrRepeat(KeyCode.Z))); } public void LayoutKey_IsItsName() { CheckEqual("Z", Label(Chord.Press(KeyCode.Z, KeySpace.Layout))); } public void HeldKey_PrecedesTheTrigger() { Chord chord = Chord.Press(KeyCode.Z).WithAllHeld(new KeyState(KeyCode.ControlLeft)); CheckEqual("Left Ctrl+Z", Label(chord)); } public void Modifiers_GoCtrlAltShiftBeforeTheKey() { Chord chord = Chord.Press(KeyCode.X) .WithAllHeld(new KeyState(KeyCode.ShiftLeft, KeyCode.AltLeft, KeyCode.ControlLeft)); CheckEqual("Left Ctrl+Left Alt+Left Shift+X", Label(chord)); } public void ModifierPressedLast_StillLeadsTheLabel() { Chord chord = Chord.Press(KeyCode.ShiftLeft).WithAllHeld(new KeyState(KeyCode.Z)); CheckEqual("Left Shift+Z", Label(chord)); } public void EitherModifier_ReadsAsThePlainName() { Chord chord = Chord.Press(KeyCode.Z).WithAnyHeld(KeyState.Control); CheckEqual("Ctrl+Z", Label(chord)); } public void SeveralEitherModifiers_ReadAsTheirPlainNames() { Chord chord = Chord.Press(KeyCode.Z).WithAnyHeld(KeyState.Control).WithAnyHeld(KeyState.Shift); CheckEqual("Ctrl+Shift+Z", Label(chord)); } public void OneSidedModifier_KeepsItsSide() { Chord chord = Chord.Press(KeyCode.Z).WithAllHeld(new KeyState(KeyCode.ControlRight)); CheckEqual("Right Ctrl+Z", Label(chord)); } public void DifferentModifiersOnDifferentSides_AreNotMerged() { Chord chord = Chord.Press(KeyCode.Z).WithAllHeld(new KeyState(KeyCode.ControlLeft, KeyCode.ShiftRight)); CheckEqual("Left Ctrl+Right Shift+Z", Label(chord)); } public void ModifiersInAnotherSpace_AreNamedInThatSpace() { Chord chord = Chord.Press(KeyCode.Z, KeySpace.Layout) .WithAllHeld(new KeyState(KeyCode.ControlLeft), KeySpace.Layout); CheckEqual("Left Ctrl+Z", Label(chord)); } public void KeysRequiredUp_AreLeftOut() { Chord chord = Chord.Press(KeyCode.Z) & Chord.HoldNone(KeyState.Shift); CheckEqual("Z", Label(chord)); } public void SeveralWaysToFire_AreListedWithSlashes() { Chord chord = Chord.Press(KeyCode.Z) | Chord.Press(KeyCode.X); CheckEqual("X / Z", SortedAlternatives(Label(chord))); } public void WaysThatReadTheSame_AreListedOnce() { Chord chord = Chord.Press(KeyCode.Z) | Chord.Hold(KeyCode.Z); CheckEqual("Z", Label(chord)); } public void ChordHoldingNoKey_SaysSo() { Chord chord = Chord.FromFormula(~KeyFormula.Key(KeyCode.A, KeyStateKind.Held)); CheckEqual(KeyLabeler.NoKeys, Label(chord)); } public void Override_NamesPhysicalKeysAndNotLayoutOnes() { Chord physical = Chord.Press(KeyCode.W); Chord layout = Chord.Press(KeyCode.W, KeySpace.Layout); var labeler = new LowerCaseLabeler(); CheckEqual("w", labeler.LabelOf(physical)); CheckEqual("W", labeler.LabelOf(layout)); } public void NeedingMoreThanTheMaximumTerms_Throws() { KeyFormula parity = KeyFormula.Never; for (int i = 0; i < 12; ++i) { parity ^= KeyFormula.Key(KeyCode.A + i, KeyStateKind.Held); } CheckThrow(typeof(InvalidOperationException)); Label(Chord.FromFormula(parity)); } public void NullChord_Throws() { CheckThrow(typeof(ArgumentNullException)); new KeyLabeler().LabelOf((Chord)null); } } } }