using Amphora;
using Annulus;
using Azimuth;
using Clave;
using System;
using System.Collections.Generic;
using UnitTestSharp;
namespace Glass.UnitTests
{
public class SliderTests : TestFixture
{
///
/// A 120x20 slider at the origin with a 20 wide thumb, holding 0 to 10 in whole steps with a coarse step of 5.
/// The thumb travels 100, so one unit of value is ten pixels.
///
public static Slider NewSlider()
{
var slider = new Slider
{
Grid = new NumberGrid { Max = 10, CoarseStep = 5 },
};
slider.Thumb.ButtonMaterial = new ScrollTrackTests.FixedSizeMaterial(new Vector(20, 20));
slider.Bounds = Rect.FromPositionAndSize(Vector.Zero, new Vector(120, 20));
return slider;
}
///
/// A look that wants a size but has no minimum, as a stretchy sprite does.
///
public record PreferredOnlyMaterial : Material
{
private readonly Vector size;
public PreferredOnlyMaterial(Vector size)
{
this.size = size;
}
protected override Vector PreferredSizeInModelSpace(Constraints constraints) => constraints.Constrain(size);
}
public static MouseState At(Scalar x, Scalar y) => new MouseState { Position = new Vector(x, y) };
public static List Watch(Slider slider)
{
var returnMe = new List();
slider.OnValueChanged += returnMe.Add;
return returnMe;
}
public static void Drag(Slider slider, Scalar fromX, Scalar toX)
{
slider.Thumb.MouseDown(At(fromX, 10), MouseButtonFlags.Left, NoKeys.Held, NoKeys.Manager);
slider.Thumb.MouseMove(At(toX, 10), NoKeys.Held, NoKeys.Manager);
}
public class CtorTests : TestFixture
{
public void IsFocusableAndTakesFocusOnClick()
{
var slider = new Slider();
CheckTrue(slider.Focusable);
CheckTrue(slider.FocusOnClick);
}
public void StartsAtTheGridsMinimum()
{
CheckEqual(0m, new Slider().Value);
}
public void DefaultsToZeroThroughOneHundred()
{
var slider = new Slider();
CheckEqual(0m, slider.Grid.Min);
CheckEqual(100m, slider.Grid.Max);
}
public void KeepsTheBehaviorItWasGiven()
{
var behavior = new SliderBehavior();
CheckTrue(ReferenceEquals(behavior, new Slider(behavior).Behavior));
}
public void WithoutOne_UsesTheDefaultBehavior()
{
CheckTrue(ReferenceEquals(SliderBehavior.Default, new Slider().Behavior));
}
public void NullBehavior_Throws()
{
CheckThrow(typeof(ArgumentNullException));
new Slider(null);
}
public void DrawsNothingOfItsOwn()
{
CheckEqual(Material.Invisible, new Slider().Material);
}
public void HoldsTheTrackAsAChild()
{
var slider = new Slider();
CheckTrue(slider.Track.Thumb == slider.Thumb);
CheckEqual(1, slider.CanvasChildren.Count);
}
}
public class GridTests : TestFixture
{
public void InvalidGrid_Throws()
{
var slider = new Slider();
CheckThrow(typeof(ArgumentException));
slider.Grid = new NumberGrid { Min = 5, Max = 1 };
}
public void InvalidGrid_LeavesTheOldOneInPlace()
{
Slider slider = NewSlider();
try
{
slider.Grid = new NumberGrid { Min = 5, Max = 1 };
}
catch (ArgumentException)
{
}
CheckEqual(10m, slider.Grid.Max);
}
public void ValueOutsideTheNewGrid_MovesOntoIt()
{
Slider slider = NewSlider();
slider.Value = 8;
slider.Grid = new NumberGrid { Max = 5 };
CheckEqual(5m, slider.Value);
}
public void ValueMovedByTheNewGrid_RaisesTheEvent()
{
Slider slider = NewSlider();
slider.Value = 8;
List seen = Watch(slider);
slider.Grid = new NumberGrid { Max = 5 };
CheckEqual(1, seen.Count);
CheckEqual(5m, seen[0]);
}
public void ValueAlreadyOnTheNewGrid_RaisesNothing()
{
Slider slider = NewSlider();
slider.Value = 3;
List seen = Watch(slider);
slider.Grid = new NumberGrid { Max = 20 };
CheckEqual(0, seen.Count);
}
public void ValueOffTheNewResolution_SnapsOntoIt()
{
Slider slider = NewSlider();
slider.Value = 3;
slider.Grid = new NumberGrid { Max = 10, Resolution = 5 };
CheckEqual(5m, slider.Value);
}
public void RescalesTheThumb()
{
Slider slider = NewSlider();
slider.Value = 5;
CheckEqual(50, slider.Thumb.Bounds.TopLeft.X);
slider.Grid = new NumberGrid { Max = 20 };
CheckEqual(25, slider.Thumb.Bounds.TopLeft.X);
}
public void PagesByTheNewCoarseStep()
{
Slider slider = NewSlider();
slider.Grid = new NumberGrid { Max = 10, CoarseStep = 2 };
slider.Track.MouseDown(At(110, 10), MouseButtonFlags.Left, NoKeys.Held, NoKeys.Manager);
CheckEqual(2m, slider.Value);
}
public void MinAboveZero_MeasuresTheThumbFromMin()
{
Slider slider = NewSlider();
slider.Grid = new NumberGrid { Min = 10, Max = 20 };
slider.Value = 15;
CheckEqual(50, slider.Thumb.Bounds.TopLeft.X);
}
public void SingleValueGrid_PutsTheThumbAtTheStart()
{
Slider slider = NewSlider();
slider.Grid = new NumberGrid { Min = 4, Max = 4 };
CheckEqual(4m, slider.Value);
CheckEqual(0, slider.Thumb.Bounds.TopLeft.X);
}
}
public class ValueTests : TestFixture
{
public void SnapsOntoTheGrid()
{
Slider slider = NewSlider();
slider.Grid = new NumberGrid { Max = 10, Resolution = 2 };
slider.Value = 5;
CheckEqual(6m, slider.Value);
}
public void ClampsIntoTheRange()
{
Slider slider = NewSlider();
slider.Value = 99;
CheckEqual(10m, slider.Value);
slider.Value = -4;
CheckEqual(0m, slider.Value);
}
public void Change_RaisesTheEventWithTheNewValue()
{
Slider slider = NewSlider();
List seen = Watch(slider);
slider.Value = 7;
CheckEqual(1, seen.Count);
CheckEqual(7m, seen[0]);
}
public void SnappedToTheCurrentValue_RaisesNothing()
{
Slider slider = NewSlider();
slider.Value = 3;
List seen = Watch(slider);
slider.Value = 3.2m;
CheckEqual(0, seen.Count);
}
public void MovesTheThumbAlongTheTrack()
{
Slider slider = NewSlider();
slider.Value = 0;
CheckEqual(0, slider.Thumb.Bounds.TopLeft.X);
slider.Value = 5;
CheckEqual(50, slider.Thumb.Bounds.TopLeft.X);
slider.Value = 10;
CheckEqual(100, slider.Thumb.Bounds.TopLeft.X);
}
public void ThumbKeepsItsLengthAcrossTheRange()
{
Slider slider = NewSlider();
slider.Value = 0;
CheckEqual(20, slider.Thumb.Bounds.Size.X);
slider.Value = 10;
CheckEqual(20, slider.Thumb.Bounds.Size.X);
}
}
public class SetValueWithoutNotifyTests : TestFixture
{
public void ChangesTheValue()
{
Slider slider = NewSlider();
slider.SetValueWithoutNotify(7);
CheckEqual(7m, slider.Value);
}
public void RaisesNothing()
{
Slider slider = NewSlider();
List seen = Watch(slider);
slider.SetValueWithoutNotify(7);
CheckEqual(0, seen.Count);
}
public void SnapsOntoTheGridAndClamps()
{
Slider slider = NewSlider();
slider.Grid = new NumberGrid { Max = 10, Resolution = 2 };
slider.SetValueWithoutNotify(5);
CheckEqual(6m, slider.Value);
slider.SetValueWithoutNotify(99);
CheckEqual(10m, slider.Value);
}
public void MovesTheThumb()
{
Slider slider = NewSlider();
slider.SetValueWithoutNotify(5);
CheckEqual(50, slider.Thumb.Bounds.TopLeft.X);
}
public void LaterChangesStillRaiseTheEvent()
{
Slider slider = NewSlider();
List seen = Watch(slider);
slider.SetValueWithoutNotify(7);
slider.Value = 8;
CheckEqual(1, seen.Count);
CheckEqual(8m, seen[0]);
}
public void SettingTheValueItAlreadyHasThroughTheNotifyingSetter_RaisesNothing()
{
Slider slider = NewSlider();
slider.SetValueWithoutNotify(7);
List seen = Watch(slider);
slider.Value = 7;
CheckEqual(0, seen.Count);
}
}
public class OrientationTests : TestFixture
{
public void Vertical_MovesTheThumbDownTheTrack()
{
Slider slider = NewSlider();
slider.Orientation = Orientation.Vertical;
slider.Bounds = Rect.FromPositionAndSize(Vector.Zero, new Vector(20, 120));
slider.Value = 5;
CheckEqual(50, slider.Thumb.Bounds.TopLeft.Y);
CheckEqual(0, slider.Thumb.Bounds.TopLeft.X);
}
public void ChangingIt_ResizesTheTrackToFillTheSlider()
{
Slider slider = NewSlider();
slider.Orientation = Orientation.Vertical;
CheckEqual(slider.CanvasRect.Size, slider.Track.Bounds.Size);
}
}
public class BoundsTests : TestFixture
{
public void TrackFillsTheSlider()
{
Slider slider = NewSlider();
slider.Bounds = Rect.FromPositionAndSize(new Vector(30, 40), new Vector(200, 24));
CheckEqual(new Vector(200, 24), slider.Track.Bounds.Size);
CheckEqual(Vector.Zero, slider.Track.Bounds.TopLeft);
}
}
public class EnabledTests : TestFixture
{
public void Disabling_DisablesTheTrackAndThumb()
{
Slider slider = NewSlider();
slider.Enabled = false;
CheckFalse(slider.Track.Enabled);
CheckFalse(slider.Thumb.Enabled);
}
public void ReEnabling_EnablesThemAgain()
{
Slider slider = NewSlider();
slider.Enabled = false;
slider.Enabled = true;
CheckTrue(slider.Track.Enabled);
CheckTrue(slider.Thumb.Enabled);
}
}
public class SliderMaterialTests : TestFixture
{
public void RoundTripsTheTrackAndThumbLooks()
{
var slider = new Slider();
var track = new Material();
ButtonMaterial thumb = new ScrollTrackTests.FixedSizeMaterial(new Vector(8, 8));
slider.SliderMaterial = new SliderMaterial { Track = track, Thumb = thumb };
CheckEqual(track, slider.SliderMaterial.Track);
CheckEqual(thumb, slider.SliderMaterial.Thumb);
}
public void ThumbTakesItsPreferredLengthEvenWithNoMinimum()
{
Slider slider = NewSlider();
slider.Thumb.ButtonMaterial = new PreferredOnlyMaterial(new Vector(16, 20));
slider.Value = 0;
CheckEqual(16, slider.Thumb.Bounds.Size.X);
slider.Value = 10;
CheckEqual(16, slider.Thumb.Bounds.Size.X);
CheckEqual(104, slider.Thumb.Bounds.TopLeft.X);
}
public void ThumbLengthFollowsTheTrackWhenTheSliderIsResized()
{
Slider slider = NewSlider();
slider.Value = 10;
slider.Bounds = Rect.FromPositionAndSize(Vector.Zero, new Vector(220, 20));
CheckEqual(200, slider.Thumb.Bounds.TopLeft.X);
CheckEqual(20, slider.Thumb.Bounds.Size.X);
}
public void ThumbTakesTheTracksWholeLengthWhenItIsNoLongerThanTheThumb()
{
Slider slider = NewSlider();
slider.Bounds = Rect.FromPositionAndSize(Vector.Zero, new Vector(15, 20));
CheckEqual(15, slider.Thumb.Bounds.Size.X);
}
public void SizesTheThumbFromItsMaterial()
{
Slider slider = NewSlider();
slider.SliderMaterial = new SliderMaterial
{
Track = null,
Thumb = new ScrollTrackTests.FixedSizeMaterial(new Vector(30, 20)),
};
CheckEqual(30, slider.Thumb.Bounds.Size.X);
}
}
public class KeyDownTests : TestFixture
{
[IgnoreTest]
private void CheckKeyMoves(KeyCode key, decimal from, decimal expected)
{
Slider slider = NewSlider();
slider.Value = from;
var keys = new FocusedKeys(slider);
CheckTrue(keys.Press(key));
CheckEqual(expected, slider.Value);
}
public void ArrowRight_StepsUp()
{
CheckKeyMoves(KeyCode.ArrowRight, from: 3, expected: 4);
}
public void ArrowUp_StepsUp()
{
CheckKeyMoves(KeyCode.ArrowUp, from: 3, expected: 4);
}
public void ArrowLeft_StepsDown()
{
CheckKeyMoves(KeyCode.ArrowLeft, from: 3, expected: 2);
}
public void ArrowDown_StepsDown()
{
CheckKeyMoves(KeyCode.ArrowDown, from: 3, expected: 2);
}
public void PageUp_StepsUpByTheCoarseStep()
{
CheckKeyMoves(KeyCode.PageUp, from: 1, expected: 5);
}
public void PageDown_StepsDownByTheCoarseStep()
{
CheckKeyMoves(KeyCode.PageDown, from: 8, expected: 5);
}
public void Home_JumpsToTheMinimum()
{
CheckKeyMoves(KeyCode.Home, from: 6, expected: 0);
}
public void End_JumpsToTheMaximum()
{
CheckKeyMoves(KeyCode.End, from: 6, expected: 10);
}
public void StepUpAtTheMaximum_ClaimsTheKeyAndStaysPut()
{
CheckKeyMoves(KeyCode.ArrowRight, from: 10, expected: 10);
}
public void StepDownAtTheMinimum_ClaimsTheKeyAndStaysPut()
{
CheckKeyMoves(KeyCode.ArrowLeft, from: 0, expected: 0);
}
public void StepAtTheLimit_RaisesNoEvent()
{
Slider slider = NewSlider();
slider.Value = 10;
List seen = Watch(slider);
new FocusedKeys(slider).Press(KeyCode.ArrowRight);
CheckEqual(0, seen.Count);
}
public void HeldKey_StepsAgainOnEachRepeat()
{
Slider slider = NewSlider();
var keys = new FocusedKeys(slider);
keys.Press(KeyCode.ArrowRight);
CheckTrue(keys.Repeat(KeyCode.ArrowRight));
CheckTrue(keys.Repeat(KeyCode.ArrowRight));
CheckEqual(3m, slider.Value);
}
public void StepsOffTheGridValue_ByTheGridsRules()
{
Slider slider = NewSlider();
slider.Grid = new NumberGrid { Max = 10, Resolution = 1, Step = 2 };
slider.Value = 3;
new FocusedKeys(slider).Press(KeyCode.ArrowRight);
CheckEqual(4m, slider.Value);
}
public void BehaviorsKeys_ReplaceTheDefaultOnes()
{
var slider = new Slider(SliderBehavior.Default with
{
IncreaseChords = SliderBehaviorTests.Pressing(KeyCode.E),
});
slider.Grid = new NumberGrid { Max = 10 };
var keys = new FocusedKeys(slider);
CheckFalse(keys.Press(KeyCode.ArrowRight));
CheckEqual(0m, slider.Value);
CheckTrue(keys.Press(KeyCode.E));
CheckEqual(1m, slider.Value);
}
public void OtherKeys_AreLeftUnclaimed()
{
Slider slider = NewSlider();
var keys = new FocusedKeys(slider);
CheckFalse(keys.Press(KeyCode.A));
CheckFalse(keys.Press(KeyCode.Space));
CheckEqual(0m, slider.Value);
}
public void WhenDisabled_LeavesTheKeyUnclaimed()
{
Slider slider = NewSlider();
var keys = new FocusedKeys(slider);
slider.Enabled = false;
CheckFalse(keys.Press(KeyCode.ArrowRight));
CheckEqual(0m, slider.Value);
}
public void GameShortcutOnTheSameKey_LosesToTheSlider()
{
Slider slider = NewSlider();
var keys = new FocusedKeys(slider);
Chord shortcut = keys.Manager.AddShortcut(Chord.PressOrRepeat(KeyCode.ArrowRight));
KeyboardSnapshot snapshot = keys.Tracker.KeyDown(KeyCode.ArrowRight, KeyCode.None, isRepeat: false);
CheckTrue(keys.Manager.KeyDown(snapshot));
CheckFalse(keys.Manager.ShouldFire(shortcut, snapshot));
CheckEqual(1m, slider.Value);
}
}
public class ThumbDragTests : TestFixture
{
public void DraggingHalfwayAcrossTheTravel_HoldsHalfTheRange()
{
Slider slider = NewSlider();
Drag(slider, fromX: 10, toX: 60);
CheckEqual(5m, slider.Value);
CheckEqual(50, slider.Thumb.Bounds.TopLeft.X);
}
public void DraggingBetweenGridPoints_SnapsTheValueAndTheThumb()
{
Slider slider = NewSlider();
Drag(slider, fromX: 10, toX: 64);
CheckEqual(5m, slider.Value);
CheckEqual(50, slider.Thumb.Bounds.TopLeft.X);
}
public void DraggingPastTheEnd_StopsAtTheMaximum()
{
Slider slider = NewSlider();
Drag(slider, fromX: 10, toX: 500);
CheckEqual(10m, slider.Value);
CheckEqual(100, slider.Thumb.Bounds.TopLeft.X);
}
public void DraggingBackBeforeTheStart_StopsAtTheMinimum()
{
Slider slider = NewSlider();
slider.Value = 5;
Drag(slider, fromX: 60, toX: -300);
CheckEqual(0m, slider.Value);
}
public void RaisesTheEventOnlyWhenTheValueReachesANewGridPoint()
{
Slider slider = NewSlider();
List seen = Watch(slider);
slider.Thumb.MouseDown(At(10, 10), MouseButtonFlags.Left, NoKeys.Held, NoKeys.Manager);
slider.Thumb.MouseMove(At(14, 10), NoKeys.Held, NoKeys.Manager);
slider.Thumb.MouseMove(At(16, 10), NoKeys.Held, NoKeys.Manager);
slider.Thumb.MouseMove(At(18, 10), NoKeys.Held, NoKeys.Manager);
slider.Thumb.MouseMove(At(31, 10), NoKeys.Held, NoKeys.Manager);
CheckEqual(2, seen.Count);
CheckEqual(1m, seen[0]);
CheckEqual(2m, seen[1]);
}
public void ADragThatCrossesSeveralPointsAtOnce_RaisesOneEvent()
{
Slider slider = NewSlider();
List seen = Watch(slider);
Drag(slider, fromX: 10, toX: 90);
CheckEqual(1, seen.Count);
CheckEqual(8m, seen[0]);
}
public void ExactValueOnAFinerGrid_IsKeptWithoutFloatingPointNoise()
{
Slider slider = NewSlider();
slider.Grid = new NumberGrid { Max = 1, Resolution = 0.1m };
Drag(slider, fromX: 10, toX: 40);
CheckEqual(0.3m, slider.Value);
}
}
public class TrackClickTests : TestFixture
{
public void BeyondTheThumb_PagesUpByTheCoarseStep()
{
Slider slider = NewSlider();
slider.Track.MouseDown(At(110, 10), MouseButtonFlags.Left, NoKeys.Held, NoKeys.Manager);
CheckEqual(5m, slider.Value);
}
public void BeforeTheThumb_PagesDownByTheCoarseStep()
{
Slider slider = NewSlider();
slider.Value = 8;
slider.Track.MouseDown(At(10, 10), MouseButtonFlags.Left, NoKeys.Held, NoKeys.Manager);
CheckEqual(3m, slider.Value);
}
public void PastTheEnd_StopsAtTheMaximum()
{
Slider slider = NewSlider();
slider.Value = 8;
slider.Track.MouseDown(At(115, 10), MouseButtonFlags.Left, NoKeys.Held, NoKeys.Manager);
CheckEqual(10m, slider.Value);
}
public void OnAFinerGrid_PagesOntoAGridPoint()
{
Slider slider = NewSlider();
slider.Grid = new NumberGrid { Max = 1, Resolution = 0.1m, CoarseStep = 0.3m };
slider.Track.MouseDown(At(110, 10), MouseButtonFlags.Left, NoKeys.Held, NoKeys.Manager);
CheckEqual(0.3m, slider.Value);
}
public void WhenDisabled_DoesNothing()
{
Slider slider = NewSlider();
slider.Enabled = false;
slider.Track.MouseDown(At(110, 10), MouseButtonFlags.Left, NoKeys.Held, NoKeys.Manager);
CheckEqual(0m, slider.Value);
}
}
}
}