using System.Collections.Generic; using UnitTestSharp; namespace Glass.UnitTests { public class FocusScopeTests : TestFixture { public static Control Focusable(string debugName = null) { return KeyboardManagerTests.Focusable(debugName); } public static Control Scope(string debugName = null) { return new Control(debugName) { FocusScope = new FocusScope() }; } public class DeactivationVersionTests : TestFixture { public void ByDefault_IsZero() { CheckEqual(0, new FocusScope().DeactivationVersion); } } /// /// Records every OnActiveChanged a scope raises. /// public class ActiveChanges { public readonly List Raised = new List(); public ActiveChanges(FocusScope scope) { scope.OnActiveChanged += Raised.Add; } } public class ActiveTests : TestFixture { public void ByDefault_IsFalse() { CheckFalse(new FocusScope().Active); } } public class ActivateTests : TestFixture { public void WhenInactive_MakesItActiveAndRaisesTrue() { var scope = new FocusScope(); var changes = new ActiveChanges(scope); scope.Activate(); CheckTrue(scope.Active); CheckEqual(new[] { true }, changes.Raised); } public void WhenAlreadyActive_RaisesNothing() { var scope = new FocusScope(); scope.Activate(); var changes = new ActiveChanges(scope); scope.Activate(); CheckEqual(0, changes.Raised.Count); } } public class DeactivateTests : TestFixture { public void WhenActive_MakesItInactiveAndRaisesFalse() { var scope = new FocusScope(); scope.Activate(); var changes = new ActiveChanges(scope); scope.Deactivate(); CheckFalse(scope.Active); CheckEqual(new[] { false }, changes.Raised); } public void WhenInactive_RaisesNothing() { var scope = new FocusScope(); var changes = new ActiveChanges(scope); scope.Deactivate(); CheckEqual(0, changes.Raised.Count); } public void Always_BumpsTheVersion() { var scope = new FocusScope(); scope.Deactivate(); scope.Deactivate(); CheckEqual(2, scope.DeactivationVersion); } } public class ResumeTargetTests : TestFixture { public void ByDefault_IsNull() { CheckNull(new FocusScope().ResumeTarget); } public void AfterTheRememberedControlsFocusIsCancelled_IsNull() { var scope = new FocusScope(); var control = Focusable(); scope.SetResumeTarget(control); control.CancelFocus(); CheckNull(scope.ResumeTarget); } } public class SetResumeTargetTests : TestFixture { public void Always_MakesResumeTargetThatControl() { var scope = new FocusScope(); var control = Focusable(); scope.SetResumeTarget(control); CheckEqual(control, scope.ResumeTarget); } public void Again_ReplacesTheEarlierControl() { var scope = new FocusScope(); var later = Focusable("later"); scope.SetResumeTarget(Focusable("earlier")); scope.SetResumeTarget(later); CheckEqual(later, scope.ResumeTarget); } } public class ClearResumeTargetTests : TestFixture { public void Always_MakesResumeTargetNull() { var scope = new FocusScope(); scope.SetResumeTarget(Focusable()); scope.ClearResumeTarget(); CheckNull(scope.ResumeTarget); } } public class FindScopeOfTests : TestFixture { public void ControlInAScope_ReturnsTheScope() { var contents = new ControlContainer(); var scope = contents.Add(Scope("scope")); var control = Focusable("control"); scope.CanvasChildren.Add(control); CheckEqual(scope, FocusScope.FindScopeOf(contents, control)); } public void TheScopeItself_ReturnsItself() { var contents = new ControlContainer(); var scope = contents.Add(Scope()); CheckEqual(scope, FocusScope.FindScopeOf(contents, scope)); } public void ControlOutsideEveryScope_ReturnsNull() { var contents = new ControlContainer(); contents.Add(Scope("scope")); var outside = contents.Add(Focusable("outside")); CheckNull(FocusScope.FindScopeOf(contents, outside)); } public void ControlNotAmongTheContents_ReturnsNull() { var contents = new ControlContainer(); var scope = contents.Add(Scope("scope")); scope.CanvasChildren.Add(Focusable("inside")); CheckNull(FocusScope.FindScopeOf(contents, Focusable("elsewhere"))); } public void ControlAfterAnUnscopedSiblingThatHasChildren_ReturnsItsScope() { var contents = new ControlContainer(); var unscoped = contents.Add(new Control("unscoped")); unscoped.CanvasChildren.Add(Focusable("inside unscoped")); var scope = contents.Add(Scope("scope")); var control = Focusable("control"); scope.CanvasChildren.Add(control); CheckEqual(scope, FocusScope.FindScopeOf(contents, control)); } public void ControlInNestedScopes_ReturnsTheInnermost() { var contents = new ControlContainer(); var outer = contents.Add(Scope("outer")); var inner = Scope("inner"); var control = Focusable("control"); outer.CanvasChildren.Add(inner); inner.CanvasChildren.Add(control); CheckEqual(inner, FocusScope.FindScopeOf(contents, control)); } public void ControlInAnUnscopedChildOfAScope_ReturnsTheScope() { var contents = new ControlContainer(); var scope = contents.Add(Scope("scope")); var panel = new Control("panel"); var control = Focusable("control"); scope.CanvasChildren.Add(panel); panel.CanvasChildren.Add(control); CheckEqual(scope, FocusScope.FindScopeOf(contents, control)); } public void ControlInAWindowsChrome_ReturnsTheWindow() { var contents = new ControlContainer(); var window = contents.Add(new Window()); CheckEqual(window, FocusScope.FindScopeOf(contents, window.CloseButton)); } public void WithAnEnclosingScope_ControlNothingNearerHolds_ReturnsTheEnclosingScope() { var contents = new ControlContainer(); var control = contents.Add(Focusable("control")); var enclosing = Scope("enclosing"); CheckEqual(enclosing, FocusScope.FindScopeOf(contents, control, enclosing)); } public void WithAnEnclosingScope_ControlNotAmongTheContents_ReturnsNull() { var contents = new ControlContainer(); contents.Add(Focusable("control")); CheckNull(FocusScope.FindScopeOf(contents, Focusable("elsewhere"), Scope("enclosing"))); } } public class NextFocusableTests : TestFixture { public void NoFocusableControls_ReturnsNull() { var contents = new ControlContainer(); contents.Add(new Control()); CheckNull(FocusScope.NextFocusable(contents, current: null, forward: true)); } public void NoCurrent_Forward_ReturnsTheFirstOne() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); contents.Add(Focusable("second")); CheckEqual(first, FocusScope.NextFocusable(contents, current: null, forward: true)); } public void NoCurrent_Backward_ReturnsTheLastOne() { var contents = new ControlContainer(); contents.Add(Focusable("first")); var second = contents.Add(Focusable("second")); CheckEqual(second, FocusScope.NextFocusable(contents, current: null, forward: false)); } public void CurrentNotAmongThem_ReturnsTheFirstOne() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); contents.Add(Focusable("second")); CheckEqual(first, FocusScope.NextFocusable(contents, Focusable("elsewhere"), forward: true)); } public void MiddleCurrent_Forward_ReturnsTheNextOne() { var contents = new ControlContainer(); contents.Add(Focusable("first")); var second = contents.Add(Focusable("second")); var third = contents.Add(Focusable("third")); CheckEqual(third, FocusScope.NextFocusable(contents, second, forward: true)); } public void MiddleCurrent_Backward_ReturnsThePreviousOne() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); var second = contents.Add(Focusable("second")); contents.Add(Focusable("third")); CheckEqual(first, FocusScope.NextFocusable(contents, second, forward: false)); } public void LastCurrent_Forward_WrapsToTheFirstOne() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); var second = contents.Add(Focusable("second")); CheckEqual(first, FocusScope.NextFocusable(contents, second, forward: true)); } public void FirstCurrent_Backward_WrapsToTheLastOne() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); var second = contents.Add(Focusable("second")); CheckEqual(second, FocusScope.NextFocusable(contents, first, forward: false)); } public void SingleFocusableControl_WrapsToItself() { var contents = new ControlContainer(); var only = contents.Add(Focusable()); CheckEqual(only, FocusScope.NextFocusable(contents, only, forward: true)); } public void SkipsNonFocusableControls() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); contents.Add(new Control("second")); var third = contents.Add(Focusable("third")); CheckEqual(third, FocusScope.NextFocusable(contents, first, forward: true)); } public void SkipsDisabledControls() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); contents.Add(Focusable("second")).Enabled = false; var third = contents.Add(Focusable("third")); CheckEqual(third, FocusScope.NextFocusable(contents, first, forward: true)); } public void SkipsHiddenControls() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); contents.Add(Focusable("second")).Visible = false; var third = contents.Add(Focusable("third")); CheckEqual(third, FocusScope.NextFocusable(contents, first, forward: true)); } public void SkipsEverythingInsideAHiddenControl() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); var hidden = contents.Add(new Control("hidden")); hidden.CanvasChildren.Add(Focusable("inside hidden")); hidden.Visible = false; CheckEqual(first, FocusScope.NextFocusable(contents, first, forward: true)); } public void VisitsAFocusableParentBeforeItsFocusableChildren() { var contents = new ControlContainer(); var parent = contents.Add(Focusable("parent")); var child = Focusable("child"); parent.CanvasChildren.Add(child); CheckEqual(parent, FocusScope.NextFocusable(contents, current: null, forward: true)); CheckEqual(child, FocusScope.NextFocusable(contents, parent, forward: true)); } public void SkipsNestedScopesAndEverythingInThem() { var contents = new ControlContainer(); var first = contents.Add(Focusable("first")); var nested = contents.Add(Scope("nested")); nested.Focusable = true; nested.CanvasChildren.Add(Focusable("inside nested")); CheckEqual(first, FocusScope.NextFocusable(contents, first, forward: true)); } } public class NextFocusableCurrentFoundTests : TestFixture { [IgnoreTest] public static ControlContainer Row(out Control a, out Control b, out Control c) { var contents = new ControlContainer(); a = contents.Add(Focusable("a")); b = contents.Add(Focusable("b")); c = contents.Add(Focusable("c")); return contents; } public void ACurrentInTheOrder_IsFound() { ControlContainer contents = Row(out _, out Control b, out _); FocusScope.NextFocusable(contents, b, forward: true, out bool found); CheckTrue(found); } public void AnAbsentCurrent_IsNotFound() { ControlContainer contents = Row(out _, out _, out _); FocusScope.NextFocusable(contents, Focusable("elsewhere"), forward: true, out bool found); CheckFalse(found); } public void ANullCurrent_IsNotFound() { ControlContainer contents = Row(out _, out _, out _); FocusScope.NextFocusable(contents, current: null, forward: true, out bool found); CheckFalse(found); } public void ADisabledCurrent_IsFoundAndSteppedPast() { ControlContainer contents = Row(out Control a, out Control b, out Control c); b.Enabled = false; Control next = FocusScope.NextFocusable(contents, b, forward: true, out bool found); CheckTrue(found); CheckEqual(c, next); } public void AHiddenCurrent_IsFoundAndSteppedPast() { ControlContainer contents = Row(out Control a, out Control b, out Control c); b.Visible = false; Control next = FocusScope.NextFocusable(contents, b, forward: true, out bool found); CheckTrue(found); CheckEqual(c, next); } public void AHiddenCurrent_GoingBackward_StepsToTheOneBefore() { ControlContainer contents = Row(out Control a, out Control b, out Control c); b.Visible = false; CheckEqual(a, FocusScope.NextFocusable(contents, b, forward: false, out _)); } public void AHiddenLastCurrent_WrapsToTheFirst() { ControlContainer contents = Row(out Control a, out Control b, out Control c); c.Visible = false; CheckEqual(a, FocusScope.NextFocusable(contents, c, forward: true, out _)); } public void ACurrentInsideAHiddenPanel_IsFoundAndSteppedPast() { var contents = new ControlContainer(); var panel = contents.Add(new Control()); Control inside = panel.CanvasChildren.Add(Focusable("inside")); panel.CanvasChildren.Add(Focusable("also inside")); Control after = contents.Add(Focusable("after")); panel.Visible = false; Control next = FocusScope.NextFocusable(contents, inside, forward: true, out bool found); CheckTrue(found); CheckEqual(after, next); } public void ControlsInsideAHiddenPanel_AreNeverTheAnswer() { var contents = new ControlContainer(); var panel = contents.Add(new Control()); panel.CanvasChildren.Add(Focusable("inside")); Control only = contents.Add(Focusable("only")); panel.Visible = false; CheckEqual(only, FocusScope.NextFocusable(contents, only, forward: true, out _)); } public void ACurrentInsideANestedScope_IsNotFound() { var contents = new ControlContainer(); Control nested = contents.Add(Scope("nested")); Control inside = nested.CanvasChildren.Add(Focusable("inside")); contents.Add(Focusable("other")); FocusScope.NextFocusable(contents, inside, forward: true, out bool found); CheckFalse(found); } } } }