using UnitTestSharp; using Azimuth; using Annulus; using System; using System.Collections.Generic; namespace Glass.UnitTests { public class ResizablePanelTests : TestFixture { public static readonly Vector InTheTitleStrip = new Vector(50, 10); [IgnoreTest] private static Rect HundredSquare() { return Rect.FromPositionAndSize(Vector.Zero, new Vector(100, 100)); } public class HandledPanel : ResizablePanel { public Rect Handle { get; set; } public override bool IsDragHandle(Vector position) { return Handle.ContainsPoint(position); } } /// /// A HundredSquare panel whose top 20 rows are its drag handle, overlapping the 6-wide north resize band. /// [IgnoreTest] private static HandledPanel WithTitleStrip() { return new HandledPanel { Bounds = HundredSquare(), Handle = Rect.FromPositionAndSize(Vector.Zero, new Vector(100, 20)), }; } public class UpdateTests : TestFixture { public void Always_StillAdvancesAge() { var control = new ResizablePanel(); control.Update(TimeSpan.FromMilliseconds(16), new UpdateState()); CheckEqual(TimeSpan.FromMilliseconds(16), control.Age); } } public class ViewportRectTests : TestFixture { public void NoMaterial_IsTheFullBounds() { var bounds = Rect.FromPositionAndSize(new Vector(10, 20), new Vector(100, 80)); var control = new ResizablePanel { Bounds = bounds }; CheckEqual(bounds, control.ViewportRect); } public void NotResizable_IsStillTheFullBounds() { var bounds = Rect.FromPositionAndSize(new Vector(10, 20), new Vector(100, 80)); var control = new ResizablePanel { Bounds = bounds, Resizable = false }; CheckEqual(bounds, control.ViewportRect); } public void CustomResizeBorderThickness_DoesNotAffectIt() { var control = new ResizablePanel { Bounds = HundredSquare(), ResizeBorderThickness = 10 }; CheckEqual(HundredSquare(), control.ViewportRect); } public void WithAMaterial_InsetsOnlyByTheMaterialsOwnBorder() { var control = new ResizablePanel { Bounds = Rect.FromPositionAndSize(new Vector(10, 20), new Vector(100, 80)), Material = new Material { BorderSize = new Rect.BorderSize { Left = 10, Top = 2, Right = 3, Bottom = 8 }, }, }; CheckEqual( Rect.FromPositionAndSize(new Vector(20, 22), new Vector(87, 70)), control.ViewportRect); } } public class OnResizedTests : TestFixture { public void NewSize_RaisesWithIt() { var control = new ResizablePanel { Bounds = HundredSquare() }; Vector? raised = null; control.OnResized += sizeNow => raised = sizeNow; control.Bounds = Rect.FromPositionAndSize(Vector.Zero, new Vector(120, 90)); CheckEqual(new Vector(120, 90), raised); } public void SameSizeSomewhereElse_DoesNotRaise() { var control = new ResizablePanel { Bounds = HundredSquare() }; bool raised = false; control.OnResized += _ => raised = true; control.Bounds = Rect.FromPositionAndSize(new Vector(30, 40), new Vector(100, 100)); CheckFalse(raised); } } public class EffectiveMinSizeTests : TestFixture { public void ByDefault_IsMinSize() { var control = new ResizablePanel { MinSize = new Vector(30, 40) }; CheckEqual(new Vector(30, 40), control.EffectiveMinSize); } public void DraggingPastEffectiveMinSize_ClampsToIt() { var control = new SubclassWithAWiderFloor { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(-1000, 50) }); CheckEqual(50, control.Bounds.Size.X); } private sealed class SubclassWithAWiderFloor : ResizablePanel { public override Vector EffectiveMinSize => new Vector(50, 0); } } public class HitTestMarginTests : TestFixture { public void ByDefault_IsResizeBorderThicknessOnEverySide() { CheckEqual(new Rect.BorderSize(6), new ResizablePanel().HitTestMargin); } public void ResizeBorderThicknessChanged_TracksIt() { var control = new ResizablePanel { ResizeBorderThickness = 10 }; CheckEqual(new Rect.BorderSize(10), control.HitTestMargin); } public void NotResizable_IsNull() { CheckNull(new ResizablePanel { Resizable = false }.HitTestMargin); } public void NotResizableThenResizableAgain_RestoresTheCurrentThickness() { var control = new ResizablePanel { Resizable = false, ResizeBorderThickness = 10 }; control.Resizable = true; CheckEqual(new Rect.BorderSize(10), control.HitTestMargin); } } public class ClassifyZoneTests : TestFixture { private static readonly Rect Bounds = Rect.FromPositionAndSize(Vector.Zero, new Vector(100, 100)); private const int Thickness = 10; public void DeepInterior_ReturnsNone() { CheckEqual(ResizeZone.None, ResizablePanel.ClassifyZone(new Vector(50, 50), Bounds, Thickness)); } public void OutsideBounds_ReturnsNone() { CheckEqual(ResizeZone.None, ResizablePanel.ClassifyZone(new Vector(200, 200), Bounds, Thickness)); } public void NorthEdge_ReturnsN() { CheckEqual(ResizeZone.N, ResizablePanel.ClassifyZone(new Vector(50, 5), Bounds, Thickness)); } public void SouthEdge_ReturnsS() { CheckEqual(ResizeZone.S, ResizablePanel.ClassifyZone(new Vector(50, 95), Bounds, Thickness)); } public void WestEdge_ReturnsW() { CheckEqual(ResizeZone.W, ResizablePanel.ClassifyZone(new Vector(5, 50), Bounds, Thickness)); } public void EastEdge_ReturnsE() { CheckEqual(ResizeZone.E, ResizablePanel.ClassifyZone(new Vector(95, 50), Bounds, Thickness)); } public void NorthwestCorner_ReturnsNW() { CheckEqual(ResizeZone.NW, ResizablePanel.ClassifyZone(new Vector(5, 5), Bounds, Thickness)); } public void NortheastCorner_ReturnsNE() { CheckEqual(ResizeZone.NE, ResizablePanel.ClassifyZone(new Vector(95, 5), Bounds, Thickness)); } public void SouthwestCorner_ReturnsSW() { CheckEqual(ResizeZone.SW, ResizablePanel.ClassifyZone(new Vector(5, 95), Bounds, Thickness)); } public void SoutheastCorner_ReturnsSE() { CheckEqual(ResizeZone.SE, ResizablePanel.ClassifyZone(new Vector(95, 95), Bounds, Thickness)); } public void ExactlyAtTheThreshold_CountsAsInTheBand() { CheckEqual(ResizeZone.W, ResizablePanel.ClassifyZone(new Vector(10, 50), Bounds, Thickness)); } public void OneUnitPastTheBand_ReturnsNone() { CheckEqual(ResizeZone.None, ResizablePanel.ClassifyZone(new Vector(11, 50), Bounds, Thickness)); } public void PastTheWestEdgeWithinTheThickness_StillReturnsW() { CheckEqual(ResizeZone.W, ResizablePanel.ClassifyZone(new Vector(-5, 50), Bounds, Thickness)); } public void PastTheNorthwestCornerWithinTheThickness_StillReturnsNW() { CheckEqual(ResizeZone.NW, ResizablePanel.ClassifyZone(new Vector(-5, -5), Bounds, Thickness)); } public void PastTheWestEdgeBeyondTheThickness_ReturnsNone() { CheckEqual(ResizeZone.None, ResizablePanel.ClassifyZone(new Vector(-11, 50), Bounds, Thickness)); } } public class ResizeTests : TestFixture { private static readonly Rect StartBounds = Rect.FromPositionAndSize(new Vector(10, 10), new Vector(100, 80)); // So a test can opt out of the container clamp entirely and isolate whatever it's actually checking. private static readonly Vector Unconstrained = new Vector(Scalar.PositiveInfinity, Scalar.PositiveInfinity); public void East_GrowsFromTheRightEdge() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.E, new Vector(20, 0), Vector.Zero, Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 10), new Vector(120, 80)), result); } public void West_GrowsFromTheLeftEdgeAndMovesPosition() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.W, new Vector(-5, 0), Vector.Zero, Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(5, 10), new Vector(105, 80)), result); } public void North_GrowsFromTheTopEdgeAndMovesPosition() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.N, new Vector(0, -5), Vector.Zero, Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 5), new Vector(100, 85)), result); } public void South_GrowsFromTheBottomEdge() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.S, new Vector(0, 10), Vector.Zero, Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 10), new Vector(100, 90)), result); } public void NorthwestCorner_MovesBothTopAndLeft() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.NW, new Vector(-5, -5), Vector.Zero, Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(5, 5), new Vector(105, 85)), result); } public void SoutheastCorner_MovesBothRightAndBottom() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.SE, new Vector(5, 5), Vector.Zero, Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 10), new Vector(105, 85)), result); } public void WestPastMinSize_PinsTheRightEdgeAndClampsWidth() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.W, new Vector(150, 0), new Vector(20, 0), Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(90, 10), new Vector(20, 80)), result); } public void EastPastMinSize_PinsTheLeftEdgeAndClampsWidth() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.E, new Vector(-150, 0), new Vector(20, 0), Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 10), new Vector(20, 80)), result); } public void NorthPastMinSize_PinsTheBottomEdgeAndClampsHeight() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.N, new Vector(0, 150), new Vector(0, 15), Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 75), new Vector(100, 15)), result); } public void SouthPastMinSize_PinsTheTopEdgeAndClampsHeight() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.S, new Vector(0, -150), new Vector(0, 15), Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 10), new Vector(100, 15)), result); } public void None_LeavesBoundsUnchanged() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.None, new Vector(50, 50), Vector.Zero, Unconstrained); CheckEqual(StartBounds, result); } public void EastPastContainer_PinsTheLeftEdgeAndClampsToContainerWidth() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.E, new Vector(1000, 0), Vector.Zero, new Vector(150, 999)); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 10), new Vector(140, 80)), result); } public void SouthPastContainer_PinsTheTopEdgeAndClampsToContainerHeight() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.S, new Vector(0, 1000), Vector.Zero, new Vector(999, 120)); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 10), new Vector(100, 110)), result); } public void WestPastTheOrigin_ClampsLeftToZero() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.W, new Vector(-1000, 0), Vector.Zero, Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(0, 10), new Vector(110, 80)), result); } public void NorthPastTheOrigin_ClampsTopToZero() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.N, new Vector(0, -1000), Vector.Zero, Unconstrained); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 0), new Vector(100, 90)), result); } public void SoutheastCornerPastContainer_ClampsBothEdgesIndependently() { Rect result = ResizablePanel.Resize( StartBounds, ResizeZone.SE, new Vector(1000, 1000), Vector.Zero, new Vector(150, 120)); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 10), new Vector(140, 110)), result); } } public class MoveTests : TestFixture { private static readonly Rect StartBounds = Rect.FromPositionAndSize(new Vector(10, 10), new Vector(100, 80)); private static readonly Vector Container = new Vector(200, 150); public void InsideTheContainer_TranslatesWithoutResizing() { Rect result = ResizablePanel.Move(StartBounds, new Vector(20, -5), Container); CheckEqual(Rect.FromPositionAndSize(new Vector(30, 5), new Vector(100, 80)), result); } public void PastTheRightEdge_StopsFlushAgainstIt() { Rect result = ResizablePanel.Move(StartBounds, new Vector(1000, 0), Container); CheckEqual(Rect.FromPositionAndSize(new Vector(100, 10), new Vector(100, 80)), result); } public void PastTheBottomEdge_StopsFlushAgainstIt() { Rect result = ResizablePanel.Move(StartBounds, new Vector(0, 1000), Container); CheckEqual(Rect.FromPositionAndSize(new Vector(10, 70), new Vector(100, 80)), result); } public void PastTheOrigin_StopsAtZero() { Rect result = ResizablePanel.Move(StartBounds, new Vector(-1000, -1000), Container); CheckEqual(Rect.FromPositionAndSize(Vector.Zero, new Vector(100, 80)), result); } public void LargerThanTheContainer_PinsTheTopLeftToTheOrigin() { Rect result = ResizablePanel.Move(StartBounds, new Vector(5, 5), new Vector(50, 50)); CheckEqual(Rect.FromPositionAndSize(Vector.Zero, new Vector(100, 80)), result); } public void UnboundedContainer_NeverClampsTheFarEdges() { Rect result = ResizablePanel.Move(StartBounds, new Vector(10000, 10000), maxSize: new Vector(Scalar.PositiveInfinity, Scalar.PositiveInfinity)); CheckEqual(Rect.FromPositionAndSize(new Vector(10010, 10010), new Vector(100, 80)), result); } } public class IsDragHandleTests : TestFixture { public void ByDefault_IsFalseEvenInsideTheBounds() { var control = new ResizablePanel { Bounds = HundredSquare() }; CheckFalse(control.IsDragHandle(new Vector(50, 50))); } } public class MouseDownTests : TestFixture { public void OnTheBorder_ClaimsTheLock() { var control = new ResizablePanel { Bounds = HundredSquare() }; bool claimed = control.MouseDown(new MouseState { Position = new Vector(50, 2) }, MouseButtonFlags.Left); CheckTrue(claimed); } public void InTheInterior_DefersToTheBase() { var control = new ResizablePanel { Bounds = HundredSquare() }; bool claimed = control.MouseDown(new MouseState { Position = new Vector(50, 50) }, MouseButtonFlags.Left); CheckFalse(claimed); } public void InTheInterior_StillCallsOnMouseDown() { var control = new ResizablePanel { Bounds = HundredSquare() }; bool called = false; control.OnMouseDown += (in MouseState _, MouseButtonFlags __) => called = true; control.MouseDown(new MouseState { Position = new Vector(50, 50) }, MouseButtonFlags.Left); Check(called); } public void NotResizable_OnTheBorder_DefersToTheBase() { var control = new ResizablePanel { Bounds = HundredSquare(), Resizable = false }; bool claimed = control.MouseDown(new MouseState { Position = new Vector(50, 2) }, MouseButtonFlags.Left); CheckFalse(claimed); } public void OnTheDragHandle_ClaimsTheLock() { HandledPanel control = WithTitleStrip(); CheckTrue(control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left)); } public void WhereTheDragHandleOverlapsTheBorder_StartsAResizeRatherThanAMove() { HandledPanel control = WithTitleStrip(); control.MouseDown(new MouseState { Position = new Vector(50, 2) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(50, 12) }); CheckEqual(Rect.FromPositionAndSize(new Vector(0, 10), new Vector(100, 90)), control.Bounds); } public void NotResizable_WhereTheDragHandleOverlapsTheBorder_StartsAMove() { HandledPanel control = WithTitleStrip(); control.Resizable = false; control.MouseDown(new MouseState { Position = new Vector(50, 2) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(50, 12) }); CheckEqual(Rect.FromPositionAndSize(new Vector(0, 10), new Vector(100, 100)), control.Bounds); } } public class MouseMoveTests : TestFixture { public void WhileDragging_ResizesFromTheGrabbedEdge() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(120, 50) }); CheckEqual(new Vector(120, 100), control.Bounds.Size); } public void WhileDragging_ReturnsTrue() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); CheckTrue(control.MouseMove(new MouseState { Position = new Vector(120, 50) })); } public void NotDragging_DefersToTheBase() { var control = new ResizablePanel { Bounds = HundredSquare() }; CheckFalse(control.MouseMove(new MouseState { Position = new Vector(50, 50) })); } public void WhileDragging_RecoversCorrectlyAfterAnIntermediateMoveIsClampedByMinSize() { // Regression guard: a move must measure from the drag-start snapshot rather than from the live // (possibly already-clamped) Bounds, or easing back out after hitting MinSize overshoots. var control = new ResizablePanel { Bounds = HundredSquare(), MinSize = new Vector(80, 0) }; control.MouseDown(new MouseState { Position = new Vector(0, 50) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(50, 50) }); CheckEqual(new Vector(80, 100), control.Bounds.Size); control.MouseMove(new MouseState { Position = new Vector(10, 50) }); CheckEqual(new Vector(90, 100), control.Bounds.Size); } public void WhileDragging_ClampsToTheParentCanvasRectSizeCapturedByUpdate() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.Update(TimeSpan.Zero, new UpdateState { ParentCanvasRect = Rect.FromPositionAndSize(Vector.Zero, new Vector(150, 100)), }); control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(1000, 50) }); CheckEqual(new Vector(150, 100), control.Bounds.Size); } public void BeforeAnyUpdate_IsUnconstrained() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(10000, 50) }); CheckEqual(new Vector(10000, 100), control.Bounds.Size); } public void WhileMoving_TranslatesWithoutResizing() { HandledPanel control = WithTitleStrip(); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(30, 40) }); CheckEqual(Rect.FromPositionAndSize(new Vector(30, 40), new Vector(100, 100)), control.Bounds); } public void WhileMoving_ReturnsTrue() { HandledPanel control = WithTitleStrip(); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); CheckTrue(control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(30, 40) })); } public void WhileMoving_MeasuresEachMoveFromWhereTheDragStarted() { HandledPanel control = WithTitleStrip(); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(30, 40) }); control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(10, 20) }); CheckEqual(new Vector(10, 20), control.Bounds.Position); } public void WhileMoving_StaysInsideTheParentCanvasRectCapturedByUpdate() { HandledPanel control = WithTitleStrip(); control.Update(TimeSpan.Zero, new UpdateState { ParentCanvasRect = Rect.FromPositionAndSize(Vector.Zero, new Vector(150, 120)), }); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(1000, 1000) }); CheckEqual(Rect.FromPositionAndSize(new Vector(50, 20), new Vector(100, 100)), control.Bounds); } } public class MouseUpTests : TestFixture { public void EndsTheDrag() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(95, 50) }, MouseButtonFlags.Left); control.MouseUp(new MouseState { Position = new Vector(120, 50) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(200, 50) }); CheckEqual(new Vector(100, 100), control.Bounds.Size); } public void WhileDragging_ReturnsTrue() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(95, 50) }, MouseButtonFlags.Left); CheckTrue(control.MouseUp(new MouseState { Position = new Vector(95, 50) }, MouseButtonFlags.Left)); } public void NotDragging_DefersToTheBase() { var control = new ResizablePanel { Bounds = HundredSquare() }; CheckFalse(control.MouseUp(new MouseState { Position = new Vector(50, 50) }, MouseButtonFlags.Left)); } public void AfterMoving_EndsTheMove() { HandledPanel control = WithTitleStrip(); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(30, 40) }); control.MouseUp(new MouseState { Position = InTheTitleStrip + new Vector(30, 40) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(90, 90) }); CheckEqual(new Vector(30, 40), control.Bounds.Position); } public void WhileMoving_ReturnsTrue() { HandledPanel control = WithTitleStrip(); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); CheckTrue(control.MouseUp(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left)); } } public class CancelMouseInputTests : TestFixture { public void Always_ChangesMouseInputVersion() { var control = new ResizablePanel(); int before = control.MouseInputVersion; control.CancelMouseInput(); CheckNotEqual(before, control.MouseInputVersion); } public void WhileDragging_ForgetsTheGrabbedZoneSoALaterMoveDefersToTheBase() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); control.CancelMouseInput(); CheckFalse(control.MouseMove(new MouseState { Position = new Vector(120, 50) })); CheckEqual(new Vector(100, 100), control.Bounds.Size); } public void WhileDragging_ForgetsTheGrabbedZoneSoCursorAtStopsForcingIt() { var cursor = new SentinelCursor(); var control = new ResizablePanel { Bounds = HundredSquare(), ResizeCursors = new Dictionary { [ResizeZone.E] = cursor }, }; control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); control.CancelMouseInput(); CheckNull(control.CursorAt(new MouseState { Position = new Vector(500, 500) })); } public void WhileDragging_PutsTheBoundsBackWhereTheDragStarted() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(130, 50) }); control.CancelMouseInput(); CheckEqual(HundredSquare(), control.Bounds); } public void NeverDragged_LeavesTheBoundsAlone() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.CancelMouseInput(); CheckEqual(HundredSquare(), control.Bounds); } public void AfterAFinishedDrag_LeavesTheResizedBoundsAlone() { var control = new ResizablePanel { Bounds = HundredSquare() }; control.MouseDown(new MouseState { Position = new Vector(100, 50) }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = new Vector(130, 50) }); control.MouseUp(new MouseState { Position = new Vector(130, 50) }, MouseButtonFlags.Left); control.CancelMouseInput(); CheckEqual(new Vector(130, 100), control.Bounds.Size); } public void WhileMoving_PutsTheBoundsBackWhereTheMoveStarted() { HandledPanel control = WithTitleStrip(); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(30, 40) }); control.CancelMouseInput(); CheckEqual(HundredSquare(), control.Bounds); } public void WhileMoving_ForgetsTheMoveSoALaterMoveDefersToTheBase() { HandledPanel control = WithTitleStrip(); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); control.CancelMouseInput(); CheckFalse(control.MouseMove(new MouseState { Position = InTheTitleStrip + new Vector(30, 40) })); CheckEqual(HundredSquare(), control.Bounds); } private sealed class SentinelCursor : Cursor { } } public class CursorAtTests : TestFixture { private sealed class FakeCursor : Cursor { } [IgnoreTest] private static IReadOnlyDictionary OnlyEast(Cursor cursor) { return new Dictionary { [ResizeZone.E] = cursor }; } public void OnTheBorder_ReturnsTheRegisteredCursorForThatZone() { var cursor = new FakeCursor(); var control = new ResizablePanel { Bounds = HundredSquare(), ResizeCursors = OnlyEast(cursor) }; CheckEqual(cursor, control.CursorAt(new MouseState { Position = new Vector(95, 50) })); } public void OnTheBorderWithNothingRegistered_ReturnsNull() { var control = new ResizablePanel { Bounds = HundredSquare() }; CheckNull(control.CursorAt(new MouseState { Position = new Vector(95, 50) })); } public void InTheInterior_ReturnsNull() { var control = new ResizablePanel { Bounds = HundredSquare(), ResizeCursors = OnlyEast(new FakeCursor()), }; CheckNull(control.CursorAt(new MouseState { Position = new Vector(50, 50) })); } public void NotResizable_ReturnsNullEvenOnTheBorder() { var control = new ResizablePanel { Bounds = HundredSquare(), Resizable = false, ResizeCursors = OnlyEast(new FakeCursor()), }; CheckNull(control.CursorAt(new MouseState { Position = new Vector(95, 50) })); } public void WhileDragging_KeepsTheGrabbedZonesCursorEvenAwayFromTheBorder() { var cursor = new FakeCursor(); var control = new ResizablePanel { Bounds = HundredSquare(), ResizeCursors = OnlyEast(cursor) }; control.MouseDown(new MouseState { Position = new Vector(95, 50) }, MouseButtonFlags.Left); CheckEqual(cursor, control.CursorAt(new MouseState { Position = new Vector(500, 500) })); } public void WhileMoving_ReturnsTheMoveCursorEvenAwayFromTheHandle() { var cursor = new FakeCursor(); HandledPanel control = WithTitleStrip(); control.MoveCursor = cursor; control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); CheckEqual(cursor, control.CursorAt(new MouseState { Position = new Vector(500, 500) })); } public void NotResizableWhileMoving_StillReturnsTheMoveCursor() { var cursor = new FakeCursor(); HandledPanel control = WithTitleStrip(); control.Resizable = false; control.MoveCursor = cursor; control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); CheckEqual(cursor, control.CursorAt(new MouseState { Position = InTheTitleStrip })); } public void WhileMovingWithNoMoveCursor_ReturnsNullEvenOverTheBorder() { HandledPanel control = WithTitleStrip(); control.ResizeCursors = OnlyEast(new FakeCursor()); control.MouseDown(new MouseState { Position = InTheTitleStrip }, MouseButtonFlags.Left); CheckNull(control.CursorAt(new MouseState { Position = new Vector(95, 50) })); } public void HoveringTheDragHandle_ReturnsNull() { HandledPanel control = WithTitleStrip(); control.MoveCursor = new FakeCursor(); CheckNull(control.CursorAt(new MouseState { Position = InTheTitleStrip })); } } } }