using Annulus;
using Azimuth;
using System;
using System.Collections.Generic;
using UnitTestSharp;
namespace Glass.UnitTests
{
public class DropdownTests : TestFixture
{
public static readonly Rect ScreenRect = DropdownPopupTests.ScreenRect;
public static readonly Rect DropdownBounds = DropdownPopupTests.AnchorRect;
public static readonly Material NarrowLabel = new ScrollViewTests.SizedSolidMaterial(new Vector(40, 16));
public static readonly Material WideLabel = new ScrollViewTests.SizedSolidMaterial(new Vector(90, 16));
public static Dropdown NewDropdown()
{
var dropdown = new Dropdown { Bounds = DropdownBounds };
dropdown.Popup.ScrollViewMaterial = ScrollViewTests.WithBars(DropdownPopupTests.Thickness);
dropdown.Popup.ContentSize = DropdownPopupTests.ContentSize;
return dropdown;
}
public static void Walk(Control root)
{
root.UpdateInSubtree(TimeSpan.Zero, new UpdateState
{
ScreenSize = ScreenRect.Size,
ParentCanvasRect = ScreenRect,
ParentViewportRect = ScreenRect,
ParentBounds = ScreenRect,
});
}
public static Material Bordered3 => ScrollViewTests.Bordered(3, "face");
public static Rect Box(Scalar x, Scalar y, Scalar width, Scalar height)
{
return DropdownPopupTests.Box(x, y, width, height);
}
public static ButtonMaterial Arrow(Scalar width, Scalar height)
{
return new ScrollViewTests.SizedSolidMaterial(new Vector(width, height));
}
public static Dropdown NewSizedFace(ButtonMaterial arrow = default, Material background = null,
Scalar arrowGap = default)
{
var dropdown = new Dropdown { Bounds = Box(0, 0, 200, 40) };
dropdown.DropdownMaterial = new DropdownMaterial
{
Background = background,
ArrowButton = arrow,
ArrowGap = arrowGap,
};
return dropdown;
}
public static Dropdown OpenedAndPlaced()
{
Dropdown dropdown = NewDropdown();
dropdown.Open();
Walk(dropdown);
return dropdown;
}
///
/// The label a popup row frames, i.e. what its item was built from.
///
[IgnoreTest]
public static Material LabelMaterialOf(Control row)
{
// A missing chrome state leaves the label unframed.
Material nominal = ((Button)row).ButtonMaterial.NominalMaterial;
return nominal is FramedMaterial framed ? framed.Body : nominal;
}
[IgnoreTest]
public static Control[] Rows(Dropdown dropdown)
{
var rows = new List();
foreach (Control row in dropdown.Popup.CanvasChildren.BackToFront())
{
rows.Add(row);
}
return rows.ToArray();
}
[IgnoreTest]
public static int DrawsOf(RendererTests.TestRenderer renderer, Material material)
{
int returnMe = 0;
foreach (RendererTests.TestRenderer.RenderArguments call in renderer.renderCalls)
{
if (ReferenceEquals(call.material, material))
{
++returnMe;
}
}
return returnMe;
}
///
/// The local rect a material was drawn at, for a material drawn exactly once.
///
[IgnoreTest]
public static Rect RectOf(RendererTests.TestRenderer renderer, Material material)
{
foreach (RendererTests.TestRenderer.RenderArguments call in renderer.renderCalls)
{
if (ReferenceEquals(call.material, material))
{
return call.rect;
}
}
throw new InvalidOperationException($"{material} was never drawn.");
}
public class CtorTests : TestFixture
{
public void Always_OwnsAClosedPopup()
{
Dropdown dropdown = NewDropdown();
CheckNotNull(dropdown.Popup);
CheckFalse(dropdown.IsOpen);
}
public void Always_HoldsTheArrowAndThePopupBeneathItself()
{
Dropdown dropdown = NewDropdown();
bool foundArrow = false;
bool foundPopup = false;
foreach (Control child in dropdown.DirectChildren.BackToFront())
{
foundArrow = foundArrow || child == dropdown.ArrowButton;
foundPopup = foundPopup || child == dropdown.Popup;
}
CheckTrue(foundArrow);
CheckTrue(foundPopup);
}
public void Always_HasNoItemsUntilRebuilt()
{
CheckEqual(0, NewDropdown().Popup.CanvasChildren.Count);
}
}
public class ArrowButtonTests : TestFixture
{
public void Always_DocksOnTheRightAtItsPreferredSizeCenteredVertically()
{
CheckEqual(Box(180, 10, 20, 20), NewSizedFace(Arrow(20, 20)).ArrowButton.Bounds);
}
public void BorderedBackground_InsetsIt()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20), Bordered3);
CheckEqual(Box(174, 7, 20, 20), dropdown.ArrowButton.Bounds);
}
public void TallerThanTheFace_ShrinksToFit()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 30));
dropdown.Bounds = Box(0, 0, 200, 10);
CheckEqual(Box(180, 0, 20, 10), dropdown.ArrowButton.Bounds);
}
public void WiderThanTheFace_TakesTheWholeWidth()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20));
dropdown.Bounds = Box(0, 0, 15, 40);
CheckEqual(Box(0, 10, 15, 20), dropdown.ArrowButton.Bounds);
}
public void NoMaterial_HasNoSize()
{
CheckEqual(Vector.Zero, NewSizedFace().ArrowButton.Bounds.Size);
}
public void ChangingItsMaterial_RelaysOutTheArrow()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20));
dropdown.ArrowButton.ButtonMaterial = Arrow(40, 20);
CheckEqual(Box(160, 10, 40, 20), dropdown.ArrowButton.Bounds);
}
}
public class ArrowAnchorTests : TestFixture
{
public void Default_IsRight()
{
CheckEqual(Anchor.Right, NewDropdown().ArrowAnchor);
}
public void Left_DocksTheArrowOnTheLeftCenteredVertically()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20));
dropdown.ArrowAnchor = Anchor.Left;
CheckEqual(Box(0, 10, 20, 20), dropdown.ArrowButton.Bounds);
}
public void Left_WithABorderedBackground_InsetsTheArrowVertically()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20), Bordered3);
dropdown.ArrowAnchor = Anchor.Left;
CheckEqual(Box(0, 7, 20, 20), dropdown.ArrowButton.Bounds);
}
public void Left_WiderThanTheFace_TakesTheWholeWidth()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20));
dropdown.ArrowAnchor = Anchor.Left;
dropdown.Bounds = Box(0, 0, 15, 40);
CheckEqual(Box(0, 10, 15, 20), dropdown.ArrowButton.Bounds);
}
public void ChangingBackAndForth_RelaysOutTheFaceEachTime()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20));
dropdown.ArrowAnchor = Anchor.Left;
dropdown.ArrowAnchor = Anchor.Right;
CheckEqual(Box(180, 10, 20, 20), dropdown.ArrowButton.Bounds);
}
public void Top_Throws()
{
Dropdown dropdown = NewDropdown();
CheckThrow(typeof(ArgumentOutOfRangeException));
dropdown.ArrowAnchor = Anchor.Top;
}
public void Bottom_Throws()
{
Dropdown dropdown = NewDropdown();
CheckThrow(typeof(ArgumentOutOfRangeException));
dropdown.ArrowAnchor = Anchor.Bottom;
}
}
public class BoundsTests : TestFixture
{
public void Setting_RelaysOutTheArrow()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20));
dropdown.Bounds = Box(0, 0, 300, 60);
CheckEqual(Box(280, 20, 20, 20), dropdown.ArrowButton.Bounds);
}
public void Setting_RelaysOutTheItemsToTheNewWidth()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel });
dropdown.Bounds = Box(0, 0, 300, 40);
CheckEqual(300, Rows(dropdown)[0].Bounds.Width);
}
}
public class MaterialTests : TestFixture
{
public void Getting_ReturnsWhatWasSet()
{
Material background = Bordered3;
Dropdown dropdown = NewSizedFace();
dropdown.Material = background;
CheckEqual(background, dropdown.Material);
}
public void Setting_RelaysOutTheArrow()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20));
dropdown.Material = Bordered3;
CheckEqual(Box(174, 7, 20, 20), dropdown.ArrowButton.Bounds);
}
}
public class DropdownMaterialTests : TestFixture
{
public void Getting_GathersEachPartFromItsControl()
{
Material background = Bordered3;
ButtonMaterial arrow = Arrow(20, 20);
ButtonMaterial item = Arrow(10, 10);
ButtonMaterial selected = Arrow(12, 12);
Material popupBackground = ScrollViewTests.Bordered(2, "popup");
Dropdown dropdown = NewSizedFace();
dropdown.Material = background;
dropdown.ArrowButton.ButtonMaterial = arrow;
dropdown.Popup.ItemButtonMaterial = item;
dropdown.Popup.SelectedItemButtonMaterial = selected;
dropdown.Popup.ScrollViewMaterial = new ScrollViewMaterial { Background = popupBackground };
DropdownMaterial gathered = dropdown.DropdownMaterial;
CheckEqual(background, gathered.Background);
CheckEqual(arrow, gathered.ArrowButton);
CheckEqual(item, gathered.Popup.ItemButton);
CheckEqual(selected, gathered.Popup.SelectedItemButton);
CheckEqual(popupBackground, gathered.Popup.ScrollView.Background);
}
public void Setting_SpreadsEachPartToItsControl()
{
Material background = Bordered3;
ButtonMaterial arrow = Arrow(20, 20);
ButtonMaterial item = Arrow(10, 10);
ButtonMaterial selected = Arrow(12, 12);
Material popupBackground = ScrollViewTests.Bordered(2, "popup");
Dropdown dropdown = NewSizedFace();
dropdown.DropdownMaterial = new DropdownMaterial
{
Background = background,
ArrowButton = arrow,
Popup = new DropdownPopupMaterial
{
ItemButton = item,
SelectedItemButton = selected,
ScrollView = new ScrollViewMaterial { Background = popupBackground },
},
};
CheckEqual(background, dropdown.Material);
CheckEqual(arrow, dropdown.ArrowButton.ButtonMaterial);
CheckEqual(item, dropdown.Popup.ItemButtonMaterial);
CheckEqual(selected, dropdown.Popup.SelectedItemButtonMaterial);
CheckEqual(popupBackground, dropdown.Popup.ScrollViewMaterial.Background);
}
public void Setting_RelaysOutTheArrow()
{
Dropdown dropdown = NewSizedFace();
dropdown.DropdownMaterial = new DropdownMaterial
{
Background = Bordered3,
ArrowButton = Arrow(20, 20),
};
CheckEqual(Box(174, 7, 20, 20), dropdown.ArrowButton.Bounds);
}
public void Setting_RelaysOutExistingItemsToTheNewPopupChrome()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel });
dropdown.DropdownMaterial = new DropdownMaterial
{
Popup = new DropdownPopupMaterial
{
ScrollView = new ScrollViewMaterial { Background = Bordered3 },
},
};
CheckEqual(194, Rows(dropdown)[0].Bounds.Width);
}
public void Setting_RelaysOutExistingItemsToTheNewItemChrome()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel });
dropdown.DropdownMaterial = new DropdownMaterial
{
Popup = new DropdownPopupMaterial { ItemButton = new ButtonMaterial(Bordered3) },
};
CheckEqual(new Vector(200, 22), Rows(dropdown)[0].Bounds.Size);
}
public void RoundTrips_TheArrowGap()
{
Dropdown dropdown = NewSizedFace();
dropdown.DropdownMaterial = new DropdownMaterial { ArrowGap = 8 };
CheckEqual(8, dropdown.DropdownMaterial.ArrowGap);
}
// ArrowGap moves the boundary between the label and the arrow, which is only observable in what the
// (otherwise private) label area draws — ArrowButton.Bounds stays flush against its anchored edge either
// way, so it can't tell these cases apart.
public void Setting_ArrowGap_NarrowsTheLabelBehindTheArrow()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20), arrowGap: 8);
dropdown.Rebuild(new[] { NarrowLabel });
dropdown.Select(0);
var renderer = new RendererTests.NullTestRenderer();
renderer.RenderSubtree(context: 0, dropdown, new DrawState());
CheckEqual(172, RectOf(renderer, NarrowLabel).Width);
}
public void Setting_ArrowGap_ClampsSoATightFaceNeverThrows()
{
Dropdown dropdown = NewSizedFace(Arrow(20, 20), arrowGap: 8);
dropdown.Rebuild(new[] { NarrowLabel });
dropdown.Select(0);
dropdown.Bounds = Box(0, 0, 24, 40);
var renderer = new RendererTests.NullTestRenderer();
renderer.RenderSubtree(context: 0, dropdown, new DrawState());
CheckEqual(0, DrawsOf(renderer, NarrowLabel));
}
}
public class RebuildTests : TestFixture
{
public void RowsNarrowerThanTheFace_StretchToFillIt()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel });
CheckEqual(dropdown.Bounds.Width, Rows(dropdown)[0].Bounds.Width);
}
public void Always_ClearsAnyPriorSelection()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Select(1);
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
CheckNull(dropdown.SelectedIndex);
CheckNull(dropdown.Popup.SelectedIndex);
}
public void Null_Throws()
{
Dropdown dropdown = NewSizedFace();
CheckThrow(typeof(ArgumentNullException));
dropdown.Rebuild(null);
}
public void GenericOverload_MapsEachItemThroughLabelForInOrder()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { "first", "second" }, item => item == "first" ? NarrowLabel : WideLabel);
Control[] rows = Rows(dropdown);
CheckEqual(NarrowLabel, LabelMaterialOf(rows[0]));
CheckEqual(WideLabel, LabelMaterialOf(rows[1]));
}
public void GenericOverload_EmptyList_LeavesThePopupWithNoRows()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(Array.Empty(), item => NarrowLabel);
CheckEqual(0, dropdown.Popup.CanvasChildren.Count);
}
public void GenericOverload_NullItems_Throws()
{
Dropdown dropdown = NewSizedFace();
CheckThrow(typeof(ArgumentNullException));
dropdown.Rebuild(null, item => NarrowLabel);
}
public void GenericOverload_NullLabelFor_Throws()
{
Dropdown dropdown = NewSizedFace();
CheckThrow(typeof(ArgumentNullException));
dropdown.Rebuild(new[] { "first" }, null);
}
public void ClickingARow_SelectsThatIndex()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
Rows(dropdown)[1].Click(default, MouseButtonFlags.Left);
CheckEqual(1, dropdown.SelectedIndex);
}
public void ClickingARow_ClosesThePopup()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Open();
Rows(dropdown)[0].Click(default, MouseButtonFlags.Left);
CheckFalse(dropdown.IsOpen);
}
}
public class SelectedIndexTests : TestFixture
{
public void BeforeAnySelection_IsNull()
{
CheckNull(NewDropdown().SelectedIndex);
}
}
public class SelectTests : TestFixture
{
public void ValidIndex_SetsSelectedIndex()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Select(1);
CheckEqual(1, dropdown.SelectedIndex);
}
public void ValidIndex_ClosesThePopup()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Open();
dropdown.Select(0);
CheckFalse(dropdown.IsOpen);
}
public void Null_ClearsTheSelection()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Select(0);
dropdown.Select(null);
CheckNull(dropdown.SelectedIndex);
}
public void NullWithNoItems_DoesNotThrow()
{
NewDropdown().Select(null);
}
public void ValidIndex_SelectsThatRowInTheList()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Select(1);
CheckEqual(1, dropdown.Popup.SelectedIndex);
}
public void Null_ClearsTheListsSelection()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Select(1);
dropdown.Select(null);
CheckNull(dropdown.Popup.SelectedIndex);
}
public void ClickingARow_SelectsItInTheList()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
Rows(dropdown)[1].Click(default, MouseButtonFlags.Left);
CheckEqual(1, dropdown.Popup.SelectedIndex);
}
public void ValidIndex_FiresTheEventWithThatIndex()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
int? firedWith = null;
dropdown.OnSelectionChanged += index => firedWith = index;
dropdown.Select(1);
CheckEqual(1, firedWith);
}
public void Null_FiresTheEventWithNull()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Select(0);
int timesFired = 0;
int? firedWith = 0;
dropdown.OnSelectionChanged += index =>
{
++timesFired;
firedWith = index;
};
dropdown.Select(null);
CheckEqual(1, timesFired);
CheckNull(firedWith);
}
public void IndexEqualToCount_Throws()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
CheckThrow(typeof(ArgumentOutOfRangeException));
dropdown.Select(2);
}
public void NegativeIndex_Throws()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
CheckThrow(typeof(ArgumentOutOfRangeException));
dropdown.Select(-1);
}
public void ValidIndex_ShowsThatLabelOnTheFace()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Select(1);
var renderer = new RendererTests.NullTestRenderer();
renderer.RenderSubtree(context: 0, dropdown, new DrawState());
CheckEqual(1, DrawsOf(renderer, WideLabel));
}
public void Null_DrawsNeitherLabel()
{
Dropdown dropdown = NewSizedFace();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Select(0);
dropdown.Select(null);
var renderer = new RendererTests.NullTestRenderer();
renderer.RenderSubtree(context: 0, dropdown, new DrawState());
CheckEqual(0, DrawsOf(renderer, NarrowLabel));
CheckEqual(0, DrawsOf(renderer, WideLabel));
}
}
public class UpdateTests : TestFixture
{
public void WhileOpen_ShowsTheArrowPressed()
{
CheckTrue(OpenedAndPlaced().ArrowButton.Pressed);
}
public void ClosingIt_ReleasesTheArrow()
{
Dropdown dropdown = OpenedAndPlaced();
dropdown.Close();
Walk(dropdown);
CheckFalse(dropdown.ArrowButton.Pressed);
}
public void ThePopupClosingItself_ReleasesTheArrow()
{
Dropdown dropdown = OpenedAndPlaced();
dropdown.Popup.MouseDown(DropdownPopupTests.At(DropdownPopupTests.OutsideThePopup),
MouseButtonFlags.Left);
Walk(dropdown);
CheckFalse(dropdown.ArrowButton.Pressed);
}
public void WhileClosed_LeavesAPressInProgressOnTheArrowAlone()
{
Dropdown dropdown = NewDropdown();
dropdown.ArrowButton.ButtonsDown = MouseButtonFlags.Left;
Walk(dropdown);
CheckTrue(dropdown.ArrowButton.Pressed);
}
}
public class MouseDownTests : TestFixture
{
public void Enabled_ClaimsTheEvent()
{
CheckTrue(NewDropdown().MouseDown(DropdownPopupTests.At(new Vector(120, 210)), MouseButtonFlags.Left));
}
public void Disabled_LetsTheEventThrough()
{
Dropdown dropdown = NewDropdown();
dropdown.Enabled = false;
CheckFalse(dropdown.MouseDown(DropdownPopupTests.At(new Vector(120, 210)), MouseButtonFlags.Left));
}
public void Always_StillFiresTheHandler()
{
Dropdown dropdown = NewDropdown();
int fired = 0;
dropdown.OnMouseDown += (in MouseState _, MouseButtonFlags __) => ++fired;
dropdown.MouseDown(DropdownPopupTests.At(new Vector(120, 210)), MouseButtonFlags.Left);
CheckEqual(1, fired);
}
}
public class ClickTests : TestFixture
{
public void Enabled_OpensThePopupAndClaimsTheEvent()
{
Dropdown dropdown = NewDropdown();
CheckTrue(dropdown.Click(DropdownPopupTests.At(new Vector(120, 210)), MouseButtonFlags.Left));
CheckTrue(dropdown.IsOpen);
}
public void Disabled_LeavesItClosedAndLetsTheEventThrough()
{
Dropdown dropdown = NewDropdown();
dropdown.Enabled = false;
CheckFalse(dropdown.Click(DropdownPopupTests.At(new Vector(120, 210)), MouseButtonFlags.Left));
CheckFalse(dropdown.IsOpen);
}
public void Always_StillFiresTheHandler()
{
Dropdown dropdown = NewDropdown();
int fired = 0;
dropdown.OnClick += (in MouseState _, MouseButtonFlags __) => ++fired;
dropdown.Click(DropdownPopupTests.At(new Vector(120, 210)), MouseButtonFlags.Left);
CheckEqual(1, fired);
}
}
public class FaceInputTests : TestFixture
{
private static readonly Vector OnTheFace = new Vector(120, 210);
private static readonly Vector OnTheArrow = new Vector(240, 215);
private static readonly Vector OnTheLeftArrow = new Vector(110, 215);
private MouseManager manager;
private Dropdown dropdown;
public override void TestSetup()
{
manager = new MouseManager();
dropdown = NewDropdown();
dropdown.ArrowButton.ButtonMaterial = Arrow(20, 20);
manager.Controls.Add(dropdown);
}
[IgnoreTest]
private void Click(Vector position)
{
manager.MouseDown(DropdownPopupTests.At(position), MouseButtonFlags.Left);
manager.MouseUp(DropdownPopupTests.At(position), MouseButtonFlags.Left);
}
public void ClickingTheFace_OpensThePopup()
{
Click(OnTheFace);
CheckTrue(dropdown.IsOpen);
}
public void ClickingTheArrow_OpensThePopup()
{
Click(OnTheArrow);
CheckTrue(dropdown.IsOpen);
}
public void PressingTheArrow_ReachesTheArrowButton()
{
Control reached = manager.MouseDown(DropdownPopupTests.At(OnTheArrow), MouseButtonFlags.Left);
CheckEqual(dropdown.ArrowButton, reached);
}
public void PressingTheArrowOnTheLeft_ReachesTheArrowButton()
{
dropdown.ArrowAnchor = Anchor.Left;
Control reached = manager.MouseDown(DropdownPopupTests.At(OnTheLeftArrow), MouseButtonFlags.Left);
CheckEqual(dropdown.ArrowButton, reached);
}
public void PressingTheFaceButReleasingElsewhere_LeavesItClosed()
{
manager.MouseDown(DropdownPopupTests.At(OnTheFace), MouseButtonFlags.Left);
manager.MouseUp(DropdownPopupTests.At(DropdownPopupTests.OutsideThePopup), MouseButtonFlags.Left);
CheckFalse(dropdown.IsOpen);
}
public void ClickingADisabledFace_LeavesItClosed()
{
dropdown.Enabled = false;
Click(OnTheFace);
CheckFalse(dropdown.IsOpen);
}
public void ClickingTheFaceWhileOpen_ClosesIt()
{
Click(OnTheFace);
Walk(dropdown);
Click(OnTheFace);
CheckFalse(dropdown.IsOpen);
}
public void ClickingTheArrowWhileOpen_ClosesIt()
{
Click(OnTheArrow);
Walk(dropdown);
Click(OnTheArrow);
CheckFalse(dropdown.IsOpen);
}
}
public class OpenTests : TestFixture
{
public void Always_IsOpenAtOnce()
{
Dropdown dropdown = NewDropdown();
dropdown.Open();
CheckTrue(dropdown.IsOpen);
}
public void Always_ShowsThePopupBesideItOnTheNextUpdate()
{
Dropdown dropdown = NewDropdown();
dropdown.Open();
CheckFalse(dropdown.Popup.Visible);
Walk(dropdown);
CheckTrue(dropdown.Popup.Visible);
CheckEqual(Box(100, 230, 150, 100), dropdown.Popup.Bounds);
}
public void InsideAnOffsetParent_PlacesThePopupBesideItsOnScreenBounds()
{
var parent = new Panel
{
Material = Material.Invisible,
Bounds = Box(50, 40, 500, 500),
};
Dropdown dropdown = NewDropdown();
dropdown.Bounds = Box(100, 200, 150, 30);
parent.CanvasChildren.Add(dropdown);
dropdown.Open();
Walk(parent);
CheckEqual(Box(150, 270, 150, 100), dropdown.Popup.Bounds);
}
public void OpeningAScrollingList_WidensThePopupBesideTheRowsRatherThanNarrowingThem()
{
Dropdown dropdown = NewSizedFace();
dropdown.Popup.ScrollViewMaterial = new ScrollViewMaterial
{
VerticalScrollBar = ScrollViewTests.WithBars(20).VerticalScrollBar,
};
dropdown.Popup.MaxHeight = 10;
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Open();
Walk(dropdown);
CheckEqual(200, Rows(dropdown)[0].Bounds.Width);
CheckEqual(220, dropdown.Popup.Bounds.Width);
}
}
public class CloseTests : TestFixture
{
public void WhileOpen_ClosesAndHidesThePopup()
{
Dropdown dropdown = OpenedAndPlaced();
dropdown.Close();
CheckFalse(dropdown.IsOpen);
CheckFalse(dropdown.Popup.Visible);
}
}
public class EnabledTests : TestFixture
{
public void Disabling_ClosesAnOpenPopup()
{
Dropdown dropdown = OpenedAndPlaced();
dropdown.Enabled = false;
CheckFalse(dropdown.IsOpen);
CheckFalse(dropdown.Popup.Visible);
}
public void Enabling_DoesNotReopenIt()
{
Dropdown dropdown = OpenedAndPlaced();
dropdown.Enabled = false;
dropdown.Enabled = true;
Walk(dropdown);
CheckFalse(dropdown.IsOpen);
CheckFalse(dropdown.Popup.Visible);
}
public void Disabling_LeavesAClosedDropdownClosed()
{
Dropdown dropdown = NewDropdown();
dropdown.Enabled = false;
CheckFalse(dropdown.IsOpen);
CheckFalse(dropdown.Enabled);
}
public void Disabling_DisablesTheArrow()
{
Dropdown dropdown = NewDropdown();
dropdown.Enabled = false;
CheckFalse(dropdown.ArrowButton.Enabled);
}
public void Enabling_EnablesTheArrowAgain()
{
Dropdown dropdown = NewDropdown();
dropdown.Enabled = false;
dropdown.Enabled = true;
CheckTrue(dropdown.ArrowButton.Enabled);
}
public void Disabling_DisablesEachItem()
{
Dropdown dropdown = NewDropdown();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Enabled = false;
foreach (Control item in dropdown.Popup.CanvasChildren.BackToFront())
{
CheckFalse(item.Enabled);
}
}
public void Enabling_EnablesEachItemAgain()
{
Dropdown dropdown = NewDropdown();
dropdown.Rebuild(new[] { NarrowLabel, WideLabel });
dropdown.Enabled = false;
dropdown.Enabled = true;
foreach (Control item in dropdown.Popup.CanvasChildren.BackToFront())
{
CheckTrue(item.Enabled);
}
}
}
public class VisibleTests : TestFixture
{
public void Hiding_ClosesAnOpenPopup()
{
Dropdown dropdown = OpenedAndPlaced();
dropdown.Visible = false;
CheckFalse(dropdown.IsOpen);
CheckFalse(dropdown.Popup.Visible);
}
public void Showing_DoesNotReopenIt()
{
Dropdown dropdown = OpenedAndPlaced();
dropdown.Visible = false;
dropdown.Visible = true;
Walk(dropdown);
CheckFalse(dropdown.IsOpen);
CheckFalse(dropdown.Popup.Visible);
}
public void Hiding_LeavesAClosedDropdownClosed()
{
Dropdown dropdown = NewDropdown();
dropdown.Visible = false;
CheckFalse(dropdown.IsOpen);
CheckFalse(dropdown.Visible);
}
}
public class ModalInputTests : TestFixture
{
private static readonly Vector OnTheOwner = new Vector(120, 210);
private static readonly Vector OutsideThePopup = DropdownPopupTests.OutsideThePopup;
private static readonly Vector OnTheItem = new Vector(110, 240);
private static readonly Vector InAGapBetweenItems = new Vector(200, 300);
private MouseManager manager;
private MouseManagerTests.RecordingControl backdrop;
private MouseManagerTests.RecordingControl item;
private Dropdown dropdown;
private int ownerClicks;
public override void TestSetup()
{
ownerClicks = 0;
manager = new MouseManager();
backdrop = new MouseManagerTests.RecordingControl("backdrop") { Handles = true, Bounds = ScreenRect };
item = new MouseManagerTests.RecordingControl("item")
{
Handles = true,
Bounds = Box(0, 0, 100, 20),
};
dropdown = NewDropdown();
dropdown.Popup.CanvasChildren.Add(item);
dropdown.OnClick += (in MouseState _, MouseButtonFlags __) => ++ownerClicks;
manager.Controls.Add(backdrop);
manager.Controls.Add(dropdown);
}
[IgnoreTest]
private void OpenAndPlace()
{
dropdown.Open();
Walk(dropdown);
}
[IgnoreTest]
private Control Press(Vector position)
{
return manager.MouseDown(DropdownPopupTests.At(position), MouseButtonFlags.Left);
}
[IgnoreTest]
private void Release(Vector position)
{
manager.MouseUp(DropdownPopupTests.At(position), MouseButtonFlags.Left);
}
public void PressingOutsideThePopup_ClosesItWithoutReachingAnythingBeneath()
{
OpenAndPlace();
CheckEqual(dropdown.Popup, Press(OutsideThePopup));
CheckFalse(dropdown.IsOpen);
CheckEqual(0, backdrop.MouseDownCount);
}
public void PressingTheOwnerWhileOpen_ClosesItWithoutTheOwnerHearingIt()
{
OpenAndPlace();
Press(OnTheOwner);
Release(OnTheOwner);
CheckFalse(dropdown.IsOpen);
CheckEqual(0, ownerClicks);
}
public void ClickingTheOwnerOnceItIsClosed_ReachesTheOwner()
{
OpenAndPlace();
Press(OnTheOwner);
Release(OnTheOwner);
Press(OnTheOwner);
Release(OnTheOwner);
CheckEqual(1, ownerClicks);
}
public void PressingAnItem_ReachesTheItemAndLeavesThePopupOpen()
{
OpenAndPlace();
CheckEqual(item, Press(OnTheItem));
CheckEqual(1, item.MouseDownCount);
CheckTrue(dropdown.IsOpen);
}
public void PressingBetweenItems_IsClaimedByThePopupRatherThanPassedThrough()
{
OpenAndPlace();
CheckEqual(dropdown.Popup, Press(InAGapBetweenItems));
CheckEqual(0, backdrop.MouseDownCount);
CheckTrue(dropdown.IsOpen);
}
public void MovingThePointer_DoesNotReachAnythingBeneath()
{
OpenAndPlace();
CheckEqual(dropdown.Popup, manager.MouseMove(DropdownPopupTests.At(OutsideThePopup)));
CheckEqual(0, backdrop.MouseMoveStartCount);
}
public void TheWheelOverThePopup_DoesNotReachAnythingBeneath()
{
OpenAndPlace();
CheckEqual(dropdown.Popup, manager.MouseWheel(DropdownPopupTests.At(InAGapBetweenItems), -1));
CheckEqual(0, backdrop.MouseWheelCount);
}
public void TheWheelOutsideThePopup_DoesNotReachAnythingBeneathAndLeavesItOpen()
{
OpenAndPlace();
CheckEqual(dropdown.Popup, manager.MouseWheel(DropdownPopupTests.At(OutsideThePopup), -1));
CheckEqual(0, backdrop.MouseWheelCount);
CheckTrue(dropdown.IsOpen);
}
public void WhileClosed_LetsInputReachWhatIsBeneath()
{
Walk(dropdown);
CheckEqual(backdrop, Press(OutsideThePopup));
}
}
}
}