using Annulus;
using Azimuth;
using System;
using System.Drawing;
using System.Linq;
using UnitTestSharp;
namespace Glass.UnitTests
{
public class DashedFrameMaterialTests : TestFixture
{
public static readonly Material Dash = new SolidColorMaterial { Color = Color.Blue };
///
/// Dashes 3 long, at least 2 apart and 1 thick, with no inset.
///
public static DashedFrameMaterial Standard => new DashedFrameMaterial(Dash);
public static Rect RectAt(Scalar x, Scalar y, Scalar width, Scalar height)
{
return Rect.FromPositionAndSize(new Vector(x, y), new Vector(width, height));
}
public class CtorTests : TestFixture
{
public void KeepsTheDashMaterial()
{
CheckEqual(Dash, Standard.DashMaterial);
}
public void DefaultsToThreeLongTwoApartOneThickAndNoInset()
{
DashedFrameMaterial material = Standard;
CheckEqual(3, material.DashLength);
CheckEqual(2, material.MinGap);
CheckEqual(1, material.Thickness);
CheckEqual(0, material.Inset);
}
}
public class DashLengthTests : TestFixture
{
public void Assigned_IsKept()
{
CheckEqual(5, (Standard with { DashLength = 5 }).DashLength);
}
public void Zero_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { DashLength = 0 };
}
public void Negative_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { DashLength = -1 };
}
public void NaN_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { DashLength = double.NaN };
}
}
public class MinGapTests : TestFixture
{
public void Assigned_IsKept()
{
CheckEqual(4, (Standard with { MinGap = 4 }).MinGap);
}
public void Zero_IsAccepted()
{
CheckEqual(0, (Standard with { MinGap = 0 }).MinGap);
}
public void Negative_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { MinGap = -1 };
}
public void NaN_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { MinGap = double.NaN };
}
}
public class ThicknessTests : TestFixture
{
public void Assigned_IsKept()
{
CheckEqual(2, (Standard with { Thickness = 2 }).Thickness);
}
public void Zero_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { Thickness = 0 };
}
public void Negative_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { Thickness = -1 };
}
public void NaN_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { Thickness = double.NaN };
}
}
public class InsetTests : TestFixture
{
public void Assigned_IsKept()
{
CheckEqual(2, (Standard with { Inset = 2 }).Inset);
}
public void Zero_IsAccepted()
{
CheckEqual(0, (Standard with { Inset = 0 }).Inset);
}
public void Negative_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { Inset = -1 };
}
public void NaN_Throws()
{
CheckThrow(typeof(ArgumentOutOfRangeException));
var unused = Standard with { Inset = double.NaN };
}
}
public class OuterTests : TestFixture
{
public void NoInset_IsTheRect()
{
Rect rect = RectAt(5, 7, 20, 10);
CheckEqual(rect, Standard.Outer(rect));
}
public void Inset_PullsEveryEdgeIn()
{
var material = Standard with { Inset = 2 };
CheckEqual(RectAt(7, 9, 16, 6), material.Outer(RectAt(5, 7, 20, 10)));
}
public void WidthBelowTwoThicknesses_IsNull()
{
var material = Standard with { Thickness = 2 };
CheckNull(material.Outer(RectAt(0, 0, 3, 10)));
}
public void HeightBelowTwoThicknesses_IsNull()
{
var material = Standard with { Thickness = 2 };
CheckNull(material.Outer(RectAt(0, 0, 10, 3)));
}
public void ExactlyTwoThicknesses_IsKept()
{
var material = Standard with { Thickness = 2 };
CheckEqual(RectAt(0, 0, 4, 4), material.Outer(RectAt(0, 0, 4, 4)));
}
public void InsetLeavingNoRoom_IsNull()
{
var material = Standard with { Inset = 5 };
CheckNull(material.Outer(RectAt(0, 0, 10, 10)));
}
}
public class DashCountAlongTests : TestFixture
{
public void ZeroLength_IsZero()
{
CheckEqual(0, Standard.DashCountAlong(0));
}
public void NegativeLength_IsZero()
{
CheckEqual(0, Standard.DashCountAlong(-4));
}
public void ShorterThanADash_IsOne()
{
CheckEqual(1, Standard.DashCountAlong(2));
}
public void RoomForOneDashButNotTwoWithTheGap_IsOne()
{
CheckEqual(1, Standard.DashCountAlong(7));
}
public void ExactlyTwoDashesAndTheGap_IsTwo()
{
CheckEqual(2, Standard.DashCountAlong(8));
}
public void WholePeriods_FitThatManyDashes()
{
CheckEqual(3, Standard.DashCountAlong(13));
}
public void JustUnderThePeriodForAnotherDash_DoesNotAddOne()
{
CheckEqual(2, Standard.DashCountAlong(12));
}
public void ZeroGap_PacksDashesEndToEnd()
{
var material = Standard with { MinGap = 0 };
CheckEqual(4, material.DashCountAlong(12));
}
}
public class DashLengthAlongTests : TestFixture
{
public void LoneDash_CoversTheWholeEdge()
{
CheckEqual(6, Standard.DashLengthAlong(6, count: 1));
}
public void SeveralDashes_AreTheDashLength()
{
CheckEqual(3, Standard.DashLengthAlong(20, count: 4));
}
}
public class DashStartAlongTests : TestFixture
{
public void FirstDash_StartsAtZero()
{
CheckEqual(0, Standard.DashStartAlong(20, count: 4, index: 0));
}
public void LastDash_EndsExactlyAtTheEdgesEnd()
{
CheckEqual(17, Standard.DashStartAlong(20, count: 4, index: 3));
}
public void LastDashOnAFractionalEdge_StillEndsExactlyAtTheEnd()
{
CheckEqual(10.5, Standard.DashStartAlong(13.5, count: 3, index: 2));
}
public void DashesBetween_AreSpreadEvenly()
{
CheckEqual(5, Standard.DashStartAlong(13, count: 3, index: 1));
}
public void DashesBetween_RoundToWholeUnits()
{
CheckEqual(6, Standard.DashStartAlong(20, count: 4, index: 1));
CheckEqual(11, Standard.DashStartAlong(20, count: 4, index: 2));
}
public void LoneDash_StartsAtZero()
{
CheckEqual(0, Standard.DashStartAlong(6, count: 1, index: 0));
}
public void IndexBelowZero_StartsAtZero()
{
CheckEqual(0, Standard.DashStartAlong(20, count: 4, index: -1));
}
public void IndexPastTheLast_IsTheLastStart()
{
CheckEqual(17, Standard.DashStartAlong(20, count: 4, index: 9));
}
}
///
/// The guarantees an edge's dashes make at every length, checked at every whole length so no size is missed.
///
public class EdgeSpacingTests : TestFixture
{
public static readonly DashedFrameMaterial[] Materials =
{
Standard,
Standard with { DashLength = 4, MinGap = 3 },
Standard with { DashLength = 1, MinGap = 1 },
Standard with { MinGap = 0 },
};
public static Scalar GapAfter(DashedFrameMaterial material, Scalar length, int count, int index)
{
Scalar end = material.DashStartAlong(length, count, index) + material.DashLengthAlong(length, count);
return material.DashStartAlong(length, count, index + 1) - end;
}
public void EveryEdgeLongEnoughForADash_GetsOne()
{
foreach (DashedFrameMaterial material in Materials)
{
for (int length = 1; length <= 200; ++length)
{
Check(material.DashCountAlong(length) >= 1);
}
}
}
public void FirstDash_AlwaysStartsFlushWithTheCorner()
{
foreach (DashedFrameMaterial material in Materials)
{
for (int length = 1; length <= 200; ++length)
{
int count = material.DashCountAlong(length);
CheckEqual(0, material.DashStartAlong(length, count, 0));
}
}
}
public void LastDash_AlwaysEndsFlushWithTheCorner()
{
foreach (DashedFrameMaterial material in Materials)
{
for (int length = 1; length <= 200; ++length)
{
int count = material.DashCountAlong(length);
Scalar end = material.DashStartAlong(length, count, count - 1) +
material.DashLengthAlong(length, count);
CheckEqual(length, end);
}
}
}
public void NoGap_IsNarrowerThanTheMinimum()
{
foreach (DashedFrameMaterial material in Materials)
{
for (int length = 1; length <= 200; ++length)
{
int count = material.DashCountAlong(length);
for (int index = 0; index < count - 1; ++index)
{
Check(GapAfter(material, length, count, index) >= material.MinGap);
}
}
}
}
public void GapsOfOneEdge_DifferByAtMostOneUnit()
{
foreach (DashedFrameMaterial material in Materials)
{
for (int length = 1; length <= 200; ++length)
{
int count = material.DashCountAlong(length);
if (count < 3)
{
continue;
}
Scalar[] gaps = Enumerable.Range(0, count - 1)
.Select(index => GapAfter(material, length, count, index))
.ToArray();
Check(gaps.Max() - gaps.Min() <= 1);
}
}
}
public void Dashes_NeverOverlapOneAnother()
{
foreach (DashedFrameMaterial material in Materials)
{
for (int length = 1; length <= 200; ++length)
{
int count = material.DashCountAlong(length);
for (int index = 0; index < count - 1; ++index)
{
Check(GapAfter(material, length, count, index) >= 0);
}
}
}
}
}
public class HorizontalDashTests : TestFixture
{
private static readonly Rect Outer = RectAt(10, 20, 20, 10);
public void TopDash_SitsOnTheTopEdgeFromTheStartOffset()
{
Rect dash = Standard.HorizontalDash(Outer, bottom: false, count: 4, index: 1);
CheckEqual(RectAt(16, 20, 3, 1), dash);
}
public void BottomDash_SitsOnTheBottomEdge()
{
Rect dash = Standard.HorizontalDash(Outer, bottom: true, count: 4, index: 1);
CheckEqual(RectAt(16, 29, 3, 1), dash);
}
public void LastDash_EndsAtTheRightEdge()
{
Rect dash = Standard.HorizontalDash(Outer, bottom: false, count: 4, index: 3);
CheckEqual(30, dash.Right);
}
public void ThicknessSetsTheHeight()
{
var material = Standard with { Thickness = 2 };
CheckEqual(RectAt(10, 28, 3, 2), material.HorizontalDash(Outer, bottom: true, count: 4, index: 0));
}
public void LoneDash_SpansTheWholeEdge()
{
Rect dash = Standard.HorizontalDash(RectAt(0, 0, 6, 10), bottom: false, count: 1, index: 0);
CheckEqual(RectAt(0, 0, 6, 1), dash);
}
}
public class VerticalSpanTests : TestFixture
{
public void ExcludesTheCornersTheHorizontalEdgesOwn()
{
CheckEqual(8, Standard.VerticalSpan(RectAt(0, 0, 20, 10)));
}
public void ThickerEdges_TakeMoreOffTheSpan()
{
var material = Standard with { Thickness = 2 };
CheckEqual(6, material.VerticalSpan(RectAt(0, 0, 20, 10)));
}
}
public class VerticalDashTests : TestFixture
{
private static readonly Rect Outer = RectAt(10, 20, 20, 10);
public void LeftDash_SitsBelowTheTopCornerOnTheLeftEdge()
{
Rect dash = Standard.VerticalDash(Outer, right: false, count: 2, index: 0);
CheckEqual(RectAt(10, 21, 1, 3), dash);
}
public void RightDash_SitsOnTheRightEdge()
{
Rect dash = Standard.VerticalDash(Outer, right: true, count: 2, index: 0);
CheckEqual(RectAt(29, 21, 1, 3), dash);
}
public void LastDash_EndsAboveTheBottomCorner()
{
Rect dash = Standard.VerticalDash(Outer, right: false, count: 2, index: 1);
CheckEqual(29, dash.Bottom);
}
public void LoneDash_SpansTheWholeSpan()
{
Rect dash = Standard.VerticalDash(RectAt(0, 0, 10, 7), right: false, count: 1, index: 0);
CheckEqual(RectAt(0, 1, 1, 5), dash);
}
public void EveryDash_StaysBetweenTheCornersTheHorizontalEdgesOwn()
{
Rect outer = RectAt(0, 0, 20, 10);
DashedFrameMaterial material = Standard;
int down = material.DashCountAlong(material.VerticalSpan(outer));
for (int index = 0; index < down; ++index)
{
Rect dash = material.VerticalDash(outer, right: false, down, index);
Check(dash.Top >= outer.Top + material.Thickness);
Check(dash.Bottom <= outer.Bottom - material.Thickness);
}
}
}
}
}