using System; using UnitTestSharp; namespace Clave.UnitTests { public class ChordTests : TestFixture { public static KeySnapshot Snapshot(KeyState held = default, KeyState pressed = default, KeyState released = default, KeyState repeated = default) { return new KeySnapshot(held, pressed, released, repeated); } public static KeyState StateOf(params KeyCode[] keys) { return new KeyState(keys); } public class PressTests : TestFixture { public void Key_MatchesWhenItIsPressed() { Check(Chord.Press(KeyCode.Z).Matches(Snapshot(pressed: StateOf(KeyCode.Z)))); } public void Key_DoesNotMatchWhenAnotherKeyIsPressed() { CheckFalse(Chord.Press(KeyCode.Z).Matches(Snapshot(pressed: StateOf(KeyCode.X)))); } public void Key_DoesNotMatchWhenItIsOnlyHeld() { CheckFalse(Chord.Press(KeyCode.Z).Matches(Snapshot(held: StateOf(KeyCode.Z)))); } public void Key_DoesNotMatchWhenItIsOnlyReleased() { CheckFalse(Chord.Press(KeyCode.Z).Matches(Snapshot(released: StateOf(KeyCode.Z)))); } public void Key_IgnoresEveryOtherKeyInEverySet() { Check(Chord.Press(KeyCode.Z).Matches(Snapshot(held: StateOf(KeyCode.W, KeyCode.Numpad9), pressed: StateOf(KeyCode.Z, KeyCode.X), released: StateOf(KeyCode.A)))); } public void Key_MatchesATapWithinOneSample() { Check(Chord.Press(KeyCode.Z).Matches(Snapshot(pressed: StateOf(KeyCode.Z), released: StateOf(KeyCode.Z)))); } public void NoneKey_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Chord.Press(KeyCode.None); } } public class PressAnyTests : TestFixture { public void MatchesWhenAnyOneIsPressed() { Chord chord = Chord.PressAny(KeyState.Enter); Check(chord.Matches(Snapshot(pressed: StateOf(KeyCode.MainEnter)))); Check(chord.Matches(Snapshot(pressed: StateOf(KeyCode.NumpadEnter)))); CheckFalse(chord.Matches(Snapshot(pressed: StateOf(KeyCode.Z)))); } public void NoKeys_Throws() { CheckThrow(typeof(ArgumentException)); Chord.PressAny(default(KeyState)); } } public class ReleaseTests : TestFixture { public void Key_MatchesWhenItIsReleased() { Check(Chord.Release(KeyCode.Z).Matches(Snapshot(released: StateOf(KeyCode.Z)))); } public void Key_DoesNotMatchWhenItIsOnlyPressed() { CheckFalse(Chord.Release(KeyCode.Z).Matches(Snapshot(pressed: StateOf(KeyCode.Z)))); } public void NoneKey_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Chord.Release(KeyCode.None); } } public class ReleaseAnyTests : TestFixture { public void MatchesWhenAnyOneIsReleased() { Chord chord = Chord.ReleaseAny(KeyState.Enter); Check(chord.Matches(Snapshot(released: StateOf(KeyCode.MainEnter)))); Check(chord.Matches(Snapshot(released: StateOf(KeyCode.NumpadEnter)))); CheckFalse(chord.Matches(Snapshot(released: StateOf(KeyCode.Z)))); } public void NoKeys_Throws() { CheckThrow(typeof(ArgumentException)); Chord.ReleaseAny(default(KeyState)); } } public class RepeatTests : TestFixture { public void Key_MatchesWhenItRepeats() { Check(Chord.Repeat(KeyCode.Z).Matches(Snapshot(held: StateOf(KeyCode.Z), repeated: StateOf(KeyCode.Z)))); } public void Key_DoesNotMatchWhenItIsOnlyPressedOrHeld() { CheckFalse(Chord.Repeat(KeyCode.Z).Matches(Snapshot(held: StateOf(KeyCode.Z), pressed: StateOf(KeyCode.Z)))); CheckFalse(Chord.Repeat(KeyCode.Z).Matches(Snapshot(held: StateOf(KeyCode.Z)))); } public void WithPressOfTheSameKey_Throws() { CheckThrow(typeof(ArgumentException)); Chord unused = Chord.Press(KeyCode.Z) & Chord.Repeat(KeyCode.Z); } public void OrPress_MatchesTheKeyPressedOrRepeating() { Chord pressOrRepeat = Chord.Press(KeyCode.Backspace) | Chord.Repeat(KeyCode.Backspace); Check(pressOrRepeat.Matches(Snapshot(held: StateOf(KeyCode.Backspace), pressed: StateOf(KeyCode.Backspace)))); Check(pressOrRepeat.Matches(Snapshot(held: StateOf(KeyCode.Backspace), repeated: StateOf(KeyCode.Backspace)))); CheckFalse(pressOrRepeat.Matches(Snapshot(held: StateOf(KeyCode.Backspace)))); } public void NoneKey_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Chord.Repeat(KeyCode.None); } } public class RepeatAnyTests : TestFixture { public void MatchesWhenAnyOneRepeats() { Chord chord = Chord.RepeatAny(KeyState.Enter); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.MainEnter), repeated: StateOf(KeyCode.MainEnter)))); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.NumpadEnter), repeated: StateOf(KeyCode.NumpadEnter)))); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.Z), repeated: StateOf(KeyCode.Z)))); } public void NoKeys_Throws() { CheckThrow(typeof(ArgumentException)); Chord.RepeatAny(default(KeyState)); } } public class HoldTests : TestFixture { public void Key_MatchesWhileItIsHeld() { Check(Chord.Hold(KeyCode.Z).Matches(Snapshot(held: StateOf(KeyCode.Z)))); } public void Key_KeepsMatchingWhenAnotherKeyIsPressed() { Check(Chord.Hold(KeyCode.Z).Matches(Snapshot(held: StateOf(KeyCode.Z, KeyCode.Q), pressed: StateOf(KeyCode.Q)))); } public void Key_DoesNotMatchWhenAnotherKeyIsHeld() { CheckFalse(Chord.Hold(KeyCode.Z).Matches(Snapshot(held: StateOf(KeyCode.X)))); } public void Key_DoesNotMatchWhenItIsOnlyPressedOrReleased() { CheckFalse(Chord.Hold(KeyCode.Z).Matches(Snapshot(pressed: StateOf(KeyCode.Z), released: StateOf(KeyCode.Z)))); } public void Key_IsEquivalentToAllHeldOfThatOneKey() { Check(Chord.Hold(KeyCode.Z).IsEquivalentTo(Chord.HoldAll(StateOf(KeyCode.Z)))); } public void NoneKey_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Chord.Hold(KeyCode.None); } } public class HoldAllTests : TestFixture { public void MatchesWhenEveryKeyIsHeld() { Chord chord = Chord.HoldAll(KeyState.Control); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.ControlLeft, KeyCode.ControlRight)))); } public void DoesNotMatchWhenOneKeyIsMissing() { CheckFalse(Chord.HoldAll(KeyState.Control).Matches(Snapshot(held: StateOf(KeyCode.ControlLeft)))); } public void NoKeys_MatchesEverything() { Check(Chord.HoldAll(default(KeyState)).Matches(Snapshot())); } } public class HoldAnyTests : TestFixture { public void MatchesWhenAnyKeyIsHeld() { Chord chord = Chord.HoldAny(KeyState.Control); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.ControlLeft)))); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.ControlRight)))); } public void DoesNotMatchWhenNoneIsHeld() { CheckFalse(Chord.HoldAny(KeyState.Control).Matches(Snapshot(held: StateOf(KeyCode.A)))); } public void NoKeys_Throws() { CheckThrow(typeof(ArgumentException)); Chord.HoldAny(default(KeyState)); } } public class HoldNoneTests : TestFixture { public void MatchesWhenNoKeyIsHeld() { Check(Chord.HoldNone(KeyState.Shift).Matches(Snapshot(held: StateOf(KeyCode.A)))); } public void DoesNotMatchWhenAnyKeyIsHeld() { CheckFalse(Chord.HoldNone(KeyState.Shift).Matches(Snapshot(held: StateOf(KeyCode.ShiftRight)))); } } public class AndTests : TestFixture { public void MatchesWhenBothDo() { Chord chord = Chord.Press(KeyCode.Z) & Chord.HoldAny(KeyState.Control); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.ControlRight, KeyCode.Z), pressed: StateOf(KeyCode.Z)))); } public void DoesNotMatchWhenOneDoesNot() { Chord chord = Chord.Press(KeyCode.Z) & Chord.HoldAny(KeyState.Control); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.Z), pressed: StateOf(KeyCode.Z)))); } public void ControlWithoutShift_RejectsShift() { Chord chord = Chord.Press(KeyCode.Z) & Chord.HoldAny(KeyState.Control) & Chord.HoldNone(KeyState.Shift); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.ControlLeft, KeyCode.ShiftRight, KeyCode.Z), pressed: StateOf(KeyCode.Z)))); } public void KeyRequiredByOneAndForbiddenByTheOther_Throws() { CheckThrow(typeof(ArgumentException)); Chord unused = Chord.HoldAll(KeyState.Control) & Chord.HoldNone(StateOf(KeyCode.ControlLeft)); } public void SatisfiableOnlyByASnapshotNoKeyboardCouldProduce_Throws() { CheckThrow(typeof(ArgumentException)); Chord unused = Chord.Press(KeyCode.Z) & Chord.HoldNone(StateOf(KeyCode.Z)) & ~Chord.Release(KeyCode.Z); } public void NullLeft_Throws() { CheckThrow(typeof(ArgumentNullException)); Chord unused = null & Chord.Press(KeyCode.Z); } public void NullRight_Throws() { CheckThrow(typeof(ArgumentNullException)); Chord unused = Chord.Press(KeyCode.Z) & null; } } public class OrTests : TestFixture { public void MatchesWhenEitherDoes() { Chord chord = Chord.Press(KeyCode.Z) | Chord.Press(KeyCode.X); Check(chord.Matches(Snapshot(pressed: StateOf(KeyCode.Z)))); Check(chord.Matches(Snapshot(pressed: StateOf(KeyCode.X)))); CheckFalse(chord.Matches(Snapshot(pressed: StateOf(KeyCode.C)))); } public void NullLeft_Throws() { CheckThrow(typeof(ArgumentNullException)); Chord unused = null | Chord.Press(KeyCode.Z); } public void NullRight_Throws() { CheckThrow(typeof(ArgumentNullException)); Chord unused = Chord.Press(KeyCode.Z) | null; } } public class XorTests : TestFixture { public void MatchesWhenExactlyOneDoes() { Chord chord = Chord.HoldAny(StateOf(KeyCode.A)) ^ Chord.HoldAny(StateOf(KeyCode.B)); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.A)))); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.B)))); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.A, KeyCode.B)))); } public void NullLeft_Throws() { CheckThrow(typeof(ArgumentNullException)); Chord unused = null ^ Chord.Press(KeyCode.Z); } public void NullRight_Throws() { CheckThrow(typeof(ArgumentNullException)); Chord unused = Chord.Press(KeyCode.Z) ^ null; } } public class NotTests : TestFixture { public void MatchesWhatTheOperandDoesNot() { Chord chord = ~Chord.HoldAny(KeyState.Shift); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.A)))); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.ShiftLeft)))); } public void OfAChordThatAlwaysMatches_Throws() { CheckThrow(typeof(ArgumentException)); Chord unused = ~Chord.HoldAll(default(KeyState)); } public void Null_Throws() { CheckThrow(typeof(ArgumentNullException)); Chord unused = ~(Chord)null; } } public class MatchesTests : TestFixture { public void NoTrigger_KeepsMatchingWhileTheKeysAreHeld() { Chord right = Chord.HoldAll(StateOf(KeyCode.ArrowRight)); Check(right.Matches(Snapshot(held: StateOf(KeyCode.ArrowRight)))); Check(right.Matches(Snapshot(held: StateOf(KeyCode.ArrowRight, KeyCode.Q), pressed: StateOf(KeyCode.Q)))); } public void KeyPressedWhileAnotherIsHeld_MatchesInEitherOrder() { Chord chord = (Chord.Press(KeyCode.A) & Chord.HoldAny(StateOf(KeyCode.B))) | (Chord.Press(KeyCode.B) & Chord.HoldAny(StateOf(KeyCode.A))); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.A, KeyCode.B), pressed: StateOf(KeyCode.B)))); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.A, KeyCode.B), pressed: StateOf(KeyCode.A)))); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.A), pressed: StateOf(KeyCode.A)))); } } public class PressOrRepeatTests : TestFixture { public void Key_MatchesWhenItIsPressed() { Check(Chord.PressOrRepeat(KeyCode.Backspace).Matches(Snapshot(held: StateOf(KeyCode.Backspace), pressed: StateOf(KeyCode.Backspace)))); } public void Key_MatchesWhenItRepeats() { Check(Chord.PressOrRepeat(KeyCode.Backspace).Matches(Snapshot(held: StateOf(KeyCode.Backspace), repeated: StateOf(KeyCode.Backspace)))); } public void Key_DoesNotMatchWhenItIsOnlyHeldOrReleased() { Chord chord = Chord.PressOrRepeat(KeyCode.Backspace); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.Backspace)))); CheckFalse(chord.Matches(Snapshot(released: StateOf(KeyCode.Backspace)))); } public void Key_DoesNotMatchWhenAnotherKeyIsPressedOrRepeats() { Chord chord = Chord.PressOrRepeat(KeyCode.Backspace); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.Delete), pressed: StateOf(KeyCode.Delete)))); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.Delete), repeated: StateOf(KeyCode.Delete)))); } public void NoneKey_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); Chord.PressOrRepeat(KeyCode.None); } } public class PressOrRepeatAnyTests : TestFixture { public void MatchesWhenAnyOneIsPressedOrRepeats() { Chord chord = Chord.PressOrRepeatAny(KeyState.Enter); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.MainEnter), pressed: StateOf(KeyCode.MainEnter)))); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.NumpadEnter), repeated: StateOf(KeyCode.NumpadEnter)))); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.Z), pressed: StateOf(KeyCode.Z)))); } public void NoKeys_Throws() { CheckThrow(typeof(ArgumentException)); Chord.PressOrRepeatAny(default(KeyState)); } } public class WithAnyHeldTests : TestFixture { public void WholeModifier_AcceptsEitherSide() { Chord undo = Chord.PressOrRepeat(KeyCode.Z).WithAnyHeld(KeyState.Control); Check(undo.Matches(Snapshot(held: StateOf(KeyCode.ControlLeft, KeyCode.Z), pressed: StateOf(KeyCode.Z)))); Check(undo.Matches(Snapshot(held: StateOf(KeyCode.ControlRight, KeyCode.Z), repeated: StateOf(KeyCode.Z)))); } public void NoKeyHeld_DoesNotMatch() { Chord undo = Chord.PressOrRepeat(KeyCode.Z).WithAnyHeld(KeyState.Control); CheckFalse(undo.Matches(Snapshot(held: StateOf(KeyCode.Z), pressed: StateOf(KeyCode.Z)))); } public void ExtraKeysHeld_StillMatches() { Chord undo = Chord.PressOrRepeat(KeyCode.Z).WithAnyHeld(KeyState.Control); Check(undo.Matches(Snapshot(held: StateOf(KeyCode.ControlLeft, KeyCode.ShiftRight, KeyCode.Z), pressed: StateOf(KeyCode.Z)))); } public void OneKey_RequiresThatKey() { Chord chord = Chord.Press(KeyCode.Z).WithAnyHeld(StateOf(KeyCode.ControlLeft)); Check(chord.Matches(Snapshot(held: StateOf(KeyCode.ControlLeft, KeyCode.Z), pressed: StateOf(KeyCode.Z)))); CheckFalse(chord.Matches(Snapshot(held: StateOf(KeyCode.ControlRight, KeyCode.Z), pressed: StateOf(KeyCode.Z)))); } public void Chained_NeedsOneKeyFromEachCall() { Chord chord = Chord.Press(KeyCode.A).WithAnyHeld(KeyState.Control).WithAnyHeld(StateOf(KeyCode.R)); KeyState a = StateOf(KeyCode.A); Check(chord.Matches(Snapshot(held: a | StateOf(KeyCode.ControlRight, KeyCode.R), pressed: a))); CheckFalse(chord.Matches(Snapshot(held: a | StateOf(KeyCode.ControlRight), pressed: a))); CheckFalse(chord.Matches(Snapshot(held: a | StateOf(KeyCode.R), pressed: a))); } public void IsTheChordAndedWithHoldAny() { Chord expected = Chord.Press(KeyCode.A) & Chord.HoldAny(KeyState.Control); Check(Chord.Press(KeyCode.A).WithAnyHeld(KeyState.Control).IsEquivalentTo(expected)); } public void MoreSpecificChords_SupersedeFewer() { Chord plain = Chord.PressOrRepeat(KeyCode.Z); Chord undo = plain.WithAnyHeld(KeyState.Control); Chord redo = undo.WithAnyHeld(KeyState.Shift); Check(undo.Supersedes(plain)); Check(redo.Supersedes(undo)); CheckFalse(plain.Supersedes(undo)); } public void NoKeys_Throws() { CheckThrow(typeof(ArgumentException)); Chord.Press(KeyCode.A).WithAnyHeld(default(KeyState)); } } public class WithAllHeldTests : TestFixture { public void EveryKeyHeld_Matches() { Chord chord = Chord.Press(KeyCode.A).WithAllHeld(StateOf(KeyCode.R, KeyCode.Y)); KeyState a = StateOf(KeyCode.A); Check(chord.Matches(Snapshot(held: a | StateOf(KeyCode.R, KeyCode.Y), pressed: a))); } public void OneKeyMissing_DoesNotMatch() { Chord chord = Chord.Press(KeyCode.A).WithAllHeld(StateOf(KeyCode.R, KeyCode.Y)); KeyState a = StateOf(KeyCode.A); CheckFalse(chord.Matches(Snapshot(held: a | StateOf(KeyCode.R), pressed: a))); CheckFalse(chord.Matches(Snapshot(held: a | StateOf(KeyCode.Y), pressed: a))); } public void WholeModifier_NeedsBothSides() { Chord chord = Chord.Press(KeyCode.A).WithAllHeld(KeyState.Control); KeyState a = StateOf(KeyCode.A); Check(chord.Matches(Snapshot(held: a | KeyState.Control, pressed: a))); CheckFalse(chord.Matches(Snapshot(held: a | StateOf(KeyCode.ControlLeft), pressed: a))); } public void ExtraKeysHeld_StillMatches() { Chord chord = Chord.Press(KeyCode.A).WithAllHeld(StateOf(KeyCode.R)); KeyState a = StateOf(KeyCode.A); Check(chord.Matches(Snapshot(held: a | StateOf(KeyCode.R, KeyCode.ShiftLeft), pressed: a))); } public void IsTheChordAndedWithHoldAll() { Chord expected = Chord.Press(KeyCode.A) & Chord.HoldAll(StateOf(KeyCode.R, KeyCode.Y)); Check(Chord.Press(KeyCode.A).WithAllHeld(StateOf(KeyCode.R, KeyCode.Y)).IsEquivalentTo(expected)); } } public class RequiresEdgeTests : TestFixture { public void PressAndRelease_RequireOne() { Check(Chord.Press(KeyCode.Z).RequiresEdge()); Check(Chord.Release(KeyCode.Z).RequiresEdge()); } public void Repeat_RequiresOne() { Check(Chord.Repeat(KeyCode.Z).RequiresEdge()); } public void HeldOnly_DoesNot() { CheckFalse(Chord.Hold(KeyCode.ArrowRight).RequiresEdge()); CheckFalse(Chord.HoldAll(StateOf(KeyCode.ArrowRight)).RequiresEdge()); CheckFalse(Chord.HoldNone(KeyState.Shift).RequiresEdge()); } public void PressWithAHeldCondition_RequiresOne() { Check((Chord.Press(KeyCode.Z) & Chord.HoldNone(KeyState.Shift)).RequiresEdge()); } } public class SupersedesTests : TestFixture { private static readonly Chord Delete = Chord.Press(KeyCode.Delete); private static readonly Chord ShiftDelete = Delete & Chord.HoldAny(KeyState.Shift); public void MoreSpecific_SupersedesLessSpecific() { Check(ShiftDelete.Supersedes(Delete)); CheckFalse(Delete.Supersedes(ShiftDelete)); } public void Itself_IsNotSuperseded() { CheckFalse(ShiftDelete.Supersedes(ShiftDelete)); } public void ChordsEquivalentOnARealKeyboard_NeitherSupersedes() { Chord tap = Chord.Press(KeyCode.Z) & Chord.HoldNone(StateOf(KeyCode.Z)); Chord tapWithItsRelease = tap & Chord.Release(KeyCode.Z); CheckFalse(tap.Supersedes(tapWithItsRelease)); CheckFalse(tapWithItsRelease.Supersedes(tap)); } public void OneSpecificKeyInsteadOfAGroup_SupersedesIt() { Check(Chord.Press(KeyCode.NumpadEnter).Supersedes(Chord.PressAny(KeyState.Enter))); Check(Chord.Release(KeyCode.NumpadEnter).Supersedes(Chord.ReleaseAny(KeyState.Enter))); } public void TheSameKeyInADifferentSet_DoesNotSupersede() { CheckFalse(Chord.Press(KeyCode.Z).Supersedes(Chord.HoldAll(StateOf(KeyCode.Z)))); CheckFalse(Chord.HoldAll(StateOf(KeyCode.Z)).Supersedes(Chord.Press(KeyCode.Z))); CheckFalse(Chord.Press(KeyCode.Z).Supersedes(Chord.Release(KeyCode.Z))); CheckFalse(Chord.Release(KeyCode.Z).Supersedes(Chord.Press(KeyCode.Z))); } public void UnrelatedChords_DoNotSupersedeEachOther() { CheckFalse(Chord.Press(KeyCode.Z).Supersedes(Chord.Press(KeyCode.X))); } public void ATapThatImpliesARelease_SupersedesPlainRelease() { Chord tap = Chord.Press(KeyCode.Z) & Chord.HoldNone(StateOf(KeyCode.Z)); Check(tap.Supersedes(Chord.Release(KeyCode.Z))); } public void Null_Throws() { CheckThrow(typeof(ArgumentNullException)); Delete.Supersedes(null); } public void PressOrRepeatWithAModifier_SupersedesWithout() { Chord pressOrRepeat = Chord.Press(KeyCode.Z) | Chord.Repeat(KeyCode.Z); Chord controlPressOrRepeat = pressOrRepeat & Chord.HoldAny(KeyState.Control); Check(controlPressOrRepeat.Supersedes(pressOrRepeat)); CheckFalse(pressOrRepeat.Supersedes(controlPressOrRepeat)); } public void PressSupersedesPressOrRepeat() { Chord pressOrRepeat = Chord.Press(KeyCode.Z) | Chord.Repeat(KeyCode.Z); Check(Chord.Press(KeyCode.Z).Supersedes(pressOrRepeat)); Check(Chord.Repeat(KeyCode.Z).Supersedes(pressOrRepeat)); } public void PressAndRepeat_NeitherSupersedes() { CheckFalse(Chord.Press(KeyCode.Z).Supersedes(Chord.Repeat(KeyCode.Z))); CheckFalse(Chord.Repeat(KeyCode.Z).Supersedes(Chord.Press(KeyCode.Z))); } } public class IsEquivalentToTests : TestFixture { public void Itself_IsEquivalent() { Chord chord = Chord.Press(KeyCode.Z) & Chord.HoldAny(KeyState.Control); Check(chord.IsEquivalentTo(chord)); } public void ATapWrittenTwoWays_IsEquivalent() { Chord notHeld = Chord.Press(KeyCode.Z) & Chord.HoldNone(StateOf(KeyCode.Z)); Chord alsoReleased = notHeld & Chord.Release(KeyCode.Z); Check(notHeld.IsEquivalentTo(alsoReleased)); } public void DifferentChords_AreNotEquivalent() { CheckFalse(Chord.Press(KeyCode.Z).IsEquivalentTo(Chord.Press(KeyCode.X))); } public void OneMoreSpecificThanTheOther_IsNotEquivalent() { Chord delete = Chord.Press(KeyCode.Delete); Chord shiftDelete = delete & Chord.HoldAny(KeyState.Shift); CheckFalse(delete.IsEquivalentTo(shiftDelete)); CheckFalse(shiftDelete.IsEquivalentTo(delete)); } public void Null_Throws() { CheckThrow(typeof(ArgumentNullException)); Chord.Press(KeyCode.Z).IsEquivalentTo(null); } } public class RelationToTests : TestFixture { private static readonly Chord Delete = Chord.Press(KeyCode.Delete); private static readonly Chord ShiftDelete = Delete & Chord.HoldAny(KeyState.Shift); public void MoreSpecific_Supersedes() { CheckEqual(ChordRelation.Supersedes, ShiftDelete.RelationTo(Delete)); } public void LessSpecific_IsSupersededBy() { CheckEqual(ChordRelation.SupersededBy, Delete.RelationTo(ShiftDelete)); } public void Itself_IsEquivalent() { CheckEqual(ChordRelation.Equivalent, ShiftDelete.RelationTo(ShiftDelete)); } public void TheSameChordBuiltTwice_IsEquivalent() { CheckEqual(ChordRelation.Equivalent, Chord.Press(KeyCode.Z).RelationTo(Chord.Press(KeyCode.Z))); } public void ATapWrittenTwoWays_IsEquivalent() { Chord notHeld = Chord.Press(KeyCode.Z) & Chord.HoldNone(StateOf(KeyCode.Z)); Chord alsoReleased = notHeld & Chord.Release(KeyCode.Z); CheckEqual(ChordRelation.Equivalent, notHeld.RelationTo(alsoReleased)); } public void DifferentKeys_AreUnrelated() { CheckEqual(ChordRelation.Unrelated, Chord.Press(KeyCode.Z).RelationTo(Chord.Press(KeyCode.X))); } public void OverlappingChordsNeitherSuperseding_AreUnrelated() { Chord controlZ = Chord.Press(KeyCode.Z) & Chord.HoldAny(KeyState.Control); Chord shiftZ = Chord.Press(KeyCode.Z) & Chord.HoldAny(KeyState.Shift); CheckEqual(ChordRelation.Unrelated, controlZ.RelationTo(shiftZ)); } public void AChordWhoseFirstDiagramMatchNoKeyboardProduces_StillRelatesCorrectly() { Chord tapAndRelease = Chord.HoldNone(StateOf(KeyCode.A)) & Chord.Press(KeyCode.A) & Chord.Release(KeyCode.A); Chord heldAndReleasedOrTapped = (Chord.Hold(KeyCode.A) & Chord.Release(KeyCode.A)) | tapAndRelease; CheckEqual(ChordRelation.Equivalent, heldAndReleasedOrTapped.RelationTo(heldAndReleasedOrTapped)); CheckEqual(ChordRelation.Supersedes, tapAndRelease.RelationTo(heldAndReleasedOrTapped)); CheckEqual(ChordRelation.SupersededBy, heldAndReleasedOrTapped.RelationTo(tapAndRelease)); CheckEqual(ChordRelation.Supersedes, heldAndReleasedOrTapped.RelationTo(Chord.Release(KeyCode.A))); CheckEqual(ChordRelation.Unrelated, heldAndReleasedOrTapped.RelationTo(Chord.Press(KeyCode.B))); } public void Null_Throws() { CheckThrow(typeof(ArgumentNullException)); Delete.RelationTo(null); } } public class FormulaTests : TestFixture { public void IsWhatTheChordMatchesWith() { CheckEqual(KeyFormula.Key(KeyCode.Z, KeyStateKind.Pressed), Chord.Press(KeyCode.Z).Formula); } } public class ToStringTests : TestFixture { public void DescribesTheKeysInEachSet() { CheckEqual("Pressed(Z)", Chord.Press(KeyCode.Z).ToString()); } } } }