diff --git a/src/PosExtensions.cs b/src/PosExtensions.cs index ea116991..fd5d708a 100644 --- a/src/PosExtensions.cs +++ b/src/PosExtensions.cs @@ -18,7 +18,7 @@ public static class PosExtensions /// /// to classify. /// True if is absolute. - public static bool IsAbsolute(this Pos p) + public static bool IsAbsolute(this Pos? p) { if (p == null) { @@ -32,7 +32,7 @@ public static bool IsAbsolute(this Pos p) /// to classify. /// The absolute size or 0. /// True if is absolute. - public static bool IsAbsolute(this Pos p, out int n) + public static bool IsAbsolute(this Pos? p, out int n) { if (p.IsAbsolute()) { @@ -58,7 +58,7 @@ public static bool IsAbsolute(this Pos p, out int n) /// /// to classify. /// True if is . - public static bool IsPercent(this Pos p) + public static bool IsPercent(this Pos? p) { if (p == null) { @@ -74,7 +74,7 @@ public static bool IsPercent(this Pos p) /// to to produce or 0 if /// is not a percent . /// True if is . - public static bool IsPercent(this Pos p, out float percent) + public static bool IsPercent(this Pos? p, out float percent) { if (p != null && p.IsPercent()) { @@ -95,7 +95,7 @@ public static bool IsPercent(this Pos p, out float percent) /// /// to classify. /// True if . - public static bool IsCenter(this Pos p) + public static bool IsCenter(this Pos? p) { if (p == null) { @@ -110,7 +110,8 @@ public static bool IsCenter(this Pos p) /// /// to classify. /// True if is . - public static bool IsAnchorEnd(this Pos p) + // BUG: This should not return true on null, because 0 is an absolute Pos + public static bool IsAnchorEnd(this Pos? p) { if (p == null) { @@ -125,7 +126,7 @@ public static bool IsAnchorEnd(this Pos p) /// The margin passed to . Typically should /// be 1 or more otherwise things tend to drift off screen. /// - public static bool IsAnchorEnd(this Pos p, out int margin) + public static bool IsAnchorEnd(this Pos? p, out int margin) { if (p.IsAnchorEnd()) { @@ -153,7 +154,7 @@ public static bool IsAnchorEnd(this Pos p, out int margin) /// to classify. /// True if is the result of a call to one of the relative methods /// (e.g. ). - public static bool IsRelative(this Pos p) + public static bool IsRelative(this Pos? p) { return p.IsRelative(out _); } @@ -165,7 +166,8 @@ public static bool IsRelative(this Pos p) /// or null if is not . /// representing the method that was used e.g. , etc. /// - public static bool IsRelative(this Pos p, IList knownDesigns, out Design? relativeTo, out Side side) + // BUG: Side should be nullable, because it gets an explicit value in all cases + public static bool IsRelative(this Pos? p, IList knownDesigns, out Design? relativeTo, out Side side) { relativeTo = null; side = default; @@ -210,7 +212,7 @@ public static bool IsRelative(this Pos p, IList knownDesigns, out Design /// /// to classify. /// True if is a PosCombine. - public static bool IsCombine(this Pos p) + public static bool IsCombine(this Pos? p) { if (p == null) { @@ -226,7 +228,7 @@ public static bool IsCombine(this Pos p) /// The right hand operand of the summation/subtraction. /// if addition or if subtraction. /// True if is PosCombine. - public static bool IsCombine(this Pos p, out Pos left, out Pos right, out bool add) + public static bool IsCombine(this Pos? p, out Pos left, out Pos right, out bool add) { if (p.IsCombine()) { @@ -259,7 +261,7 @@ public static bool IsCombine(this Pos p, out Pos left, out Pos right, out bool a /// Only populated for , this is the direction of offset from . /// The offset from the listed position. Is provided if the input has addition/subtraction e.g.Pos.Center() + 2 /// True if it was possible to determine what is. - public static bool GetPosType(this Pos p, IList knownDesigns, out PosType type, out float value, out Design? relativeTo, out Side side, out int offset) + public static bool GetPosType(this Pos? p, IList knownDesigns, out PosType type, out float value, out Design? relativeTo, out Side side, out int offset) { type = default; relativeTo = null; @@ -325,7 +327,7 @@ public static bool GetPosType(this Pos p, IList knownDesigns, out PosTyp /// to classify. /// All that we might be expressed as relative to (e.g. see ). /// Code to generate . - public static string? ToCode(this Pos p, List knownDesigns) + public static string? ToCode(this Pos? p, List knownDesigns) { if (!p.GetPosType(knownDesigns, out var type, out var val, out var relativeTo, out var side, out var offset)) { @@ -409,7 +411,9 @@ public static bool GetPosType(this Pos p, IList knownDesigns, out PosTyp /// The offset if any to use e.g. if you want: /// Pos.Left(myView) + 5 /// The resulting of the invoked method (e.g. . - public static Pos CreatePosRelative(Design relativeTo, Side side, int offset) + // BUG: This returns absolute positions when offsets are applied + // It's a Terminal.Gui issue, but we can probably work around it. + public static Pos CreatePosRelative(this Design relativeTo, Side side, int offset) { Pos pos; switch (side) @@ -437,7 +441,7 @@ public static Pos CreatePosRelative(Design relativeTo, Side side, int offset) return pos; } - private static bool IsRelative(this Pos p, out Pos posView) + private static bool IsRelative(this Pos? p, out Pos posView) { // Terminal.Gui will often use Pos.Combine with RHS of 0 instead of just PosView alone if (p != null && p.IsCombine(out var left, out var right, out _)) diff --git a/src/TerminalGuiDesigner.csproj b/src/TerminalGuiDesigner.csproj index f4268b5c..4099d727 100644 --- a/src/TerminalGuiDesigner.csproj +++ b/src/TerminalGuiDesigner.csproj @@ -21,7 +21,6 @@ true TerminalGuiDesigner ./nupkg - net7.0 enable TerminalGuiDesigner 1.1.0-rc1 diff --git a/tests/PosTests.cs b/tests/PosTests.cs index 99a74904..130d5e8d 100644 --- a/tests/PosTests.cs +++ b/tests/PosTests.cs @@ -1,363 +1,623 @@ -using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using Terminal.Gui; -using TerminalGuiDesigner; using TerminalGuiDesigner.FromCode; using TerminalGuiDesigner.Operations; using TerminalGuiDesigner.ToCode; namespace UnitTests; + +[TestFixture] +[TestOf( typeof( PosExtensions ) )] +[Category( "Core" )] +[Category( "Terminal.Gui Extensions" )] +[DefaultFloatingPointTolerance( 0.0001D )] internal class PosTests : Tests { - [Test] - public void TestIsAbsolute() + private static IEnumerable GetCode_Cases { - ClassicAssert.IsTrue(Pos.At(50).IsAbsolute()); - ClassicAssert.IsFalse(Pos.At(50).IsPercent()); - ClassicAssert.IsFalse(Pos.At(50).IsRelative()); - ClassicAssert.IsFalse(Pos.At(50).IsAnchorEnd(out _)); - - ClassicAssert.IsTrue(Pos.At(50).IsAbsolute(out int size)); - ClassicAssert.AreEqual(50, size); - - ClassicAssert.IsTrue(Pos.At(50).GetPosType(new List(), out var type, out var val, out var design, out var side, out var offset)); - ClassicAssert.AreEqual(PosType.Absolute, type); - ClassicAssert.AreEqual(50, val); - ClassicAssert.AreEqual(0, offset); + get + { + View v = new( ); + Design d = new( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + return new[] { -10, -1, 0, 1, 10 }.SelectMany( offset => + { + string offsetString = offset switch + { + < 0 => $" - {-offset}", + 0 => string.Empty, + > 0 => $" + {offset}" + }; + return new TestCaseData[] + { + new( Pos.At( 50 ) + offset, $"{50 + offset}", d, v ), + new( Pos.AnchorEnd( 5 ) + offset, $"Pos.AnchorEnd(5){offsetString}", d, v ), + new( Pos.Center( ) + offset, $"Pos.Center(){offsetString}", d, v ), + new( Pos.Percent( 50 ) + offset, $"Pos.Percent(50f){offsetString}", d, v ), + new( Pos.Top( v ) + offset, $"Pos.Top(myView){offsetString}", d, v ), + new( Pos.Bottom( v ) + offset, $"Pos.Bottom(myView){offsetString}", d, v ), + new( Pos.Left( v ) + offset, $"Pos.Left(myView){offsetString}", d, v ), + new( Pos.Right( v ) + offset, $"Pos.Right(myView){offsetString}", d, v ), + new( Pos.X( v ) + offset, $"Pos.Left(myView){offsetString}", d, v ), + new( Pos.Y( v ) + offset, $"Pos.Top(myView){offsetString}", d, v ) + }; + } ); + } } - [Test] - public void TestIsAbsolute_FromInt() + private static IEnumerable GetPosType_OutputsCorrectOffset_Cases + { + get + { + View v = new( ); + Design d = new( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedTrueTestCaseData( Pos.At( 50 ), 0, null ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( 5 ), 0, null ), + new ExpectedTrueTestCaseData( Pos.Center( ), 0, null ), + new ExpectedTrueTestCaseData( Pos.Percent( 5 ), 0, null ), + new ExpectedTrueTestCaseData( Pos.Top( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.Bottom( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.Left( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.Right( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.Y( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.X( v ), 0, d ), + // Now with an offset + new ExpectedTrueTestCaseData( Pos.At( 50 ) + 5, 0, null ), + new ExpectedTrueTestCaseData( Pos.At( 50 ) - 5, 0, null ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( 5 ) + 5, 5, null ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( 5 ) - 5, -5, null ), + new ExpectedTrueTestCaseData( Pos.Center( ) + 5, +5, null ), + new ExpectedTrueTestCaseData( Pos.Center( ) - 5, -5, null ), + new ExpectedTrueTestCaseData( Pos.Percent( 5 ) + 5, 5, null ), + new ExpectedTrueTestCaseData( Pos.Percent( 5 ) - 5, -5, null ), + new ExpectedTrueTestCaseData( Pos.Top( v ) + 5, 5, d ), + new ExpectedTrueTestCaseData( Pos.Top( v ) - 5, -5, d ), + new ExpectedTrueTestCaseData( Pos.Bottom( v ) + 5, 5, d ), + new ExpectedTrueTestCaseData( Pos.Bottom( v ) - 5, -5, d ), + new ExpectedTrueTestCaseData( Pos.Left( v ) + 5, 5, d ), + new ExpectedTrueTestCaseData( Pos.Left( v ) - 5, -5, d ), + new ExpectedTrueTestCaseData( Pos.Right( v ) + 5, 5, d ), + new ExpectedTrueTestCaseData( Pos.Right( v ) - 5, -5, d ), + new ExpectedTrueTestCaseData( Pos.Y( v ) + 5, 5, d ), + new ExpectedTrueTestCaseData( Pos.Y( v ) - 5, -5, d ), + new ExpectedTrueTestCaseData( Pos.X( v ) + 5, 5, d ), + new ExpectedTrueTestCaseData( Pos.X( v ) - 5, -5, d ) + }; + } + } + + private static IEnumerable GetPosType_OutputsCorrectType_Cases + { + get + { + View v = new( ); + Design d = new( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedTrueTestCaseData( Pos.At( 50 ), PosType.Absolute, null ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( 5 ), PosType.AnchorEnd, null ), + new ExpectedTrueTestCaseData( Pos.Center( ), PosType.Center, null ), + new ExpectedTrueTestCaseData( Pos.Percent( 5 ), PosType.Percent, null ), + new ExpectedTrueTestCaseData( Pos.Top( v ), PosType.Relative, d ), + new ExpectedTrueTestCaseData( Pos.Bottom( v ), PosType.Relative, d ), + new ExpectedTrueTestCaseData( Pos.Left( v ), PosType.Relative, d ), + new ExpectedTrueTestCaseData( Pos.Right( v ), PosType.Relative, d ), + new ExpectedTrueTestCaseData( Pos.Y( v ), PosType.Relative, d ), + new ExpectedTrueTestCaseData( Pos.X( v ), PosType.Relative, d ) + }; + } + } + + private static IEnumerable GetPosType_OutputsCorrectValue_Cases + { + get + { + View v = new( ); + Design d = new( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedTrueTestCaseData( Pos.At( 50 ), 50, null ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( 5 ), 5, null ), + new ExpectedTrueTestCaseData( Pos.Center( ), 0, null ), + new ExpectedTrueTestCaseData( Pos.Percent( 5 ), 5, null ), + new ExpectedTrueTestCaseData( Pos.Top( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.Bottom( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.Left( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.Right( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.Y( v ), 0, d ), + new ExpectedTrueTestCaseData( Pos.X( v ), 0, d ) + }; + } + } + + private static IEnumerable IsAbsolute_Cases { - Pos p = 50; - ClassicAssert.IsTrue(p.IsAbsolute()); - ClassicAssert.IsFalse(p.IsPercent()); - ClassicAssert.IsFalse(p.IsRelative()); - ClassicAssert.IsFalse(p.IsAnchorEnd(out _)); - - ClassicAssert.IsTrue(p.IsAbsolute(out int size)); - ClassicAssert.AreEqual(50, size); - - ClassicAssert.IsTrue(p.GetPosType(new List(), out var type, out var val, out var design, out var side, out var offset)); - ClassicAssert.AreEqual(PosType.Absolute, type); - ClassicAssert.AreEqual(50, val); - ClassicAssert.AreEqual(0, offset); + get + { + View v = new( ); + _ = new Design( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedTrueTestCaseData( Pos.At( 50 ) ), + new ExpectedTrueTestCaseData( null ), + new ExpectedFalseTestCaseData( Pos.AnchorEnd( 5 ) ), + new ExpectedFalseTestCaseData( Pos.Center( ) ), + new ExpectedFalseTestCaseData( Pos.Percent( 5 ) ), + new ExpectedFalseTestCaseData( Pos.Top( v ) ), + new ExpectedFalseTestCaseData( Pos.Bottom( v ) ), + new ExpectedFalseTestCaseData( Pos.Left( v ) ), + new ExpectedFalseTestCaseData( Pos.Right( v ) ), + new ExpectedFalseTestCaseData( Pos.Y( v ) ), + new ExpectedFalseTestCaseData( Pos.X( v ) ) + }; + } + } + + private static IEnumerable IsAbsolute_WithOutParam_Cases + { + get + { + return new TestCaseData[] + { + new ExpectedTrueTestCaseData( Pos.At( 50 ), 50 ), + new ExpectedFalseTestCaseData( Pos.AnchorEnd( 5 ), 0 ), + new ExpectedFalseTestCaseData( Pos.Center( ), 0 ), + new ExpectedFalseTestCaseData( Pos.Percent( 5 ), 0 ) + }; + } + } + + private static IEnumerable IsAnchorEnd_Cases + { + get + { + View v = new( ); + _ = new Design( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedFalseTestCaseData( Pos.At( 50 ) ), + new ExpectedFalseTestCaseData( null ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( ) ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( 5 ) ), + new ExpectedFalseTestCaseData( Pos.Center( ) ), + new ExpectedFalseTestCaseData( Pos.Percent( 5 ) ), + new ExpectedFalseTestCaseData( Pos.Top( v ) ), + new ExpectedFalseTestCaseData( Pos.Bottom( v ) ), + new ExpectedFalseTestCaseData( Pos.Left( v ) ), + new ExpectedFalseTestCaseData( Pos.Right( v ) ), + new ExpectedFalseTestCaseData( Pos.Y( v ) ), + new ExpectedFalseTestCaseData( Pos.X( v ) ) + }; + } + } + + private static IEnumerable IsAnchorEnd_WithOutParam_Cases + { + get + { + View v = new( ); + _ = new Design( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedFalseTestCaseData( Pos.At( 50 ), 0 ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( ), 0 ), + new ExpectedTrueTestCaseData( Pos.AnchorEnd( 5 ), 5 ), + new ExpectedFalseTestCaseData( Pos.Center( ), 0 ), + new ExpectedFalseTestCaseData( Pos.Percent( 5 ), 0 ), + new ExpectedFalseTestCaseData( Pos.Top( v ), 0 ), + new ExpectedFalseTestCaseData( Pos.Bottom( v ), 0 ), + new ExpectedFalseTestCaseData( Pos.Left( v ), 0 ), + new ExpectedFalseTestCaseData( Pos.Right( v ), 0 ), + new ExpectedFalseTestCaseData( Pos.Y( v ), 0 ), + new ExpectedFalseTestCaseData( Pos.X( v ), 0 ) + }; + } + } + + private static IEnumerable IsPercent_Cases + { + get + { + View v = new( ); + _ = new Design( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedFalseTestCaseData( Pos.At( 50 ) ), + new ExpectedFalseTestCaseData( null ), + new ExpectedFalseTestCaseData( Pos.AnchorEnd( 5 ) ), + new ExpectedFalseTestCaseData( Pos.Center( ) ), + new ExpectedTrueTestCaseData( Pos.Percent( 5 ) ), + new ExpectedFalseTestCaseData( Pos.Top( v ) ), + new ExpectedFalseTestCaseData( Pos.Bottom( v ) ), + new ExpectedFalseTestCaseData( Pos.Left( v ) ), + new ExpectedFalseTestCaseData( Pos.Right( v ) ), + new ExpectedFalseTestCaseData( Pos.Y( v ) ), + new ExpectedFalseTestCaseData( Pos.X( v ) ) + }; + } + } + + private static IEnumerable IsPercent_WithOutParam_Cases + { + get + { + return new TestCaseData[] + { + new ExpectedFalseTestCaseData( Pos.At( 50 ), 0 ), + new ExpectedFalseTestCaseData( Pos.AnchorEnd( 5 ), 0 ), + new ExpectedFalseTestCaseData( Pos.Center( ), 0 ), + new ExpectedTrueTestCaseData( Pos.Percent( 5 ), 5 ) + }; + } + } + + private static IEnumerable IsRelative_Cases + { + get + { + View v = new( ); + _ = new Design( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedFalseTestCaseData( Pos.At( 50 ) ), + new ExpectedFalseTestCaseData( Pos.AnchorEnd( 5 ) ), + new ExpectedFalseTestCaseData( Pos.Center( ) ), + new ExpectedFalseTestCaseData( Pos.Percent( 5 ) ), + new ExpectedTrueTestCaseData( Pos.Top( v ) ), + new ExpectedTrueTestCaseData( Pos.Bottom( v ) ), + new ExpectedTrueTestCaseData( Pos.Left( v ) ), + new ExpectedTrueTestCaseData( Pos.Right( v ) ), + new ExpectedTrueTestCaseData( Pos.Y( v ) ), + new ExpectedTrueTestCaseData( Pos.X( v ) ) + }; + } + } + + private static IEnumerable IsRelative_WithOutParams_Cases + { + get + { + View v = new( ); + Design d = new( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + return new TestCaseData[] + { + new ExpectedFalseTestCaseData( Pos.At( 50 ), null, Side.Left ), + new ExpectedFalseTestCaseData( Pos.AnchorEnd( 5 ), null, Side.Left ), + new ExpectedFalseTestCaseData( Pos.Center( ), null, Side.Left ), + new ExpectedFalseTestCaseData( Pos.Percent( 5 ), null, Side.Left ), + new ExpectedTrueTestCaseData( Pos.Top( v ), d, Side.Top ), + new ExpectedTrueTestCaseData( Pos.Bottom( v ), d, Side.Bottom ), + new ExpectedTrueTestCaseData( Pos.Left( v ), d, Side.Left ), + new ExpectedTrueTestCaseData( Pos.Right( v ), d, Side.Right ), + new ExpectedTrueTestCaseData( Pos.Y( v ), d, Side.Top ), + new ExpectedTrueTestCaseData( Pos.X( v ), d, Side.Left ) + }; + } } [Test] - public void TestIsPercent() + [Category( "Code Generation" )] + [TestCaseSource( nameof( GetCode_Cases ) )] + public void GetCode( Pos testPos, string expectedCodeString, Design d, View v ) { - ClassicAssert.IsFalse(Pos.Percent(24).IsAbsolute()); - ClassicAssert.IsTrue(Pos.Percent(24).IsPercent()); - ClassicAssert.IsFalse(Pos.Percent(24).IsRelative()); - ClassicAssert.IsFalse(Pos.Percent(24).IsAnchorEnd(out _)); - - ClassicAssert.IsTrue(Pos.Percent(24).IsPercent(out var size)); - ClassicAssert.AreEqual(24f, size); - - ClassicAssert.IsTrue(Pos.Percent(24).GetPosType(new List(), out var type, out var val, out var design, out var side, out var offset)); - ClassicAssert.AreEqual(PosType.Percent, type); - ClassicAssert.AreEqual(24, val); - ClassicAssert.AreEqual(0, offset); + Assert.That( testPos.ToCode( new( ) { d } ), Is.EqualTo( expectedCodeString ) ); } [Test] - public void TestIsRelativeTo() + [TestCaseSource( nameof( GetPosType_OutputsCorrectOffset_Cases ) )] + public bool GetPosType_OutputsCorrectOffset( Pos testValue, int expectedOffset, Design? d ) { - View v = new View(); - var d = new Design(new SourceCodeFile(new FileInfo("yarg.cs")), "myView", v); - - ClassicAssert.IsFalse(Pos.Top(v).IsAbsolute()); - ClassicAssert.IsFalse(Pos.Top(v).IsPercent()); - ClassicAssert.IsTrue(Pos.Top(v).IsRelative()); - ClassicAssert.IsFalse(Pos.Top(v).IsAnchorEnd(out _)); - - ClassicAssert.IsTrue(Pos.Top(v).IsRelative(new List { d }, out var relativeTo, out var side)); - ClassicAssert.AreSame(d, relativeTo); - ClassicAssert.AreEqual(Side.Top, side); - - ClassicAssert.IsTrue(Pos.Top(v).GetPosType(new List { d }, out var type, out var val, out relativeTo, out side, out var offset)); - ClassicAssert.AreEqual(PosType.Relative, type); - ClassicAssert.AreSame(d, relativeTo); - ClassicAssert.AreEqual(Side.Top, side); + List knownDesigns = new( ); + if ( d is not null ) + { + knownDesigns.Add( d ); + } + + bool getPosTypeSucceeded = testValue.GetPosType( knownDesigns, out _, out _, out _, out _, out int actualOffset ); + Assert.That( actualOffset, Is.EqualTo( expectedOffset ) ); + return getPosTypeSucceeded; } [Test] - public void TestIsAnchorEnd() + [TestCaseSource( nameof( GetPosType_OutputsCorrectType_Cases ) )] + public bool GetPosType_OutputsCorrectType( Pos testValue, PosType expectedPosType, Design? d ) { - ClassicAssert.IsFalse(Pos.AnchorEnd().IsAbsolute()); - ClassicAssert.IsFalse(Pos.AnchorEnd().IsPercent()); - ClassicAssert.IsFalse(Pos.AnchorEnd().IsRelative()); - ClassicAssert.IsTrue(Pos.AnchorEnd().IsAnchorEnd(out _)); - - ClassicAssert.IsTrue(Pos.AnchorEnd().IsAnchorEnd(out var margin)); - ClassicAssert.AreEqual(0, margin); - - ClassicAssert.IsTrue(Pos.AnchorEnd().GetPosType(new List(), out var type, out var val, out var design, out var side, out var offset)); - ClassicAssert.AreEqual(PosType.AnchorEnd, type); - ClassicAssert.AreEqual(0, val); - ClassicAssert.AreEqual(0, offset); + List knownDesigns = new( ); + if ( d is not null ) + { + knownDesigns.Add( d ); + } + + bool getPosTypeSucceeded = testValue.GetPosType( knownDesigns, out PosType actualPosType, out _, out _, out _, out _ ); + Assert.That( actualPosType, Is.EqualTo( expectedPosType ) ); + return getPosTypeSucceeded; } [Test] - public void TestIsAnchorEnd_WithMargin() + [TestCaseSource( nameof( GetPosType_OutputsCorrectValue_Cases ) )] + public bool GetPosType_OutputsCorrectValue( Pos testValue, float expectedValue, Design? d ) { - ClassicAssert.IsFalse(Pos.AnchorEnd(2).IsAbsolute()); - ClassicAssert.IsFalse(Pos.AnchorEnd(2).IsPercent()); - ClassicAssert.IsFalse(Pos.AnchorEnd(2).IsRelative()); - ClassicAssert.IsTrue(Pos.AnchorEnd(2).IsAnchorEnd(out _)); - - ClassicAssert.IsTrue(Pos.AnchorEnd(2).IsAnchorEnd(out var margin)); - ClassicAssert.AreEqual(2, margin); - - ClassicAssert.IsTrue(Pos.AnchorEnd(2).GetPosType(new List(), out var type, out var val, out var design, out var side, out var offset)); - ClassicAssert.AreEqual(PosType.AnchorEnd, type); - ClassicAssert.AreEqual(2, val); - ClassicAssert.AreEqual(0, offset); + List knownDesigns = new( ); + if ( d is not null ) + { + knownDesigns.Add( d ); + } + + bool getPosTypeSucceeded = testValue.GetPosType( knownDesigns, out _, out float actualValue, out _, out _, out _ ); + Assert.That( actualValue, Is.EqualTo( expectedValue ) ); + return getPosTypeSucceeded; } [Test] - public void TestIsAnchorEnd_WithOffset() + [TestCaseSource( nameof( IsAbsolute_Cases ) )] + [NonParallelizable] + public bool IsAbsolute( Pos testValue ) { - ClassicAssert.IsTrue((Pos.AnchorEnd(1) + 2).GetPosType(new List(), out var type, out var val, out var design, out var side, out var offset)); - ClassicAssert.AreEqual(PosType.AnchorEnd, type); - ClassicAssert.AreEqual(1, val); - ClassicAssert.AreEqual(2, offset); - - ClassicAssert.IsTrue((Pos.AnchorEnd(1) - 2).GetPosType(new List(), out type, out val, out design, out side, out offset)); - ClassicAssert.AreEqual(PosType.AnchorEnd, type); - ClassicAssert.AreEqual(1, val); - ClassicAssert.AreEqual(-2, offset); + return testValue.IsAbsolute( ); } [Test] - public void TestGetPosType_WithOffset() + [TestCaseSource( nameof( IsAbsolute_WithOutParam_Cases ) )] + [NonParallelizable] + public bool IsAbsolute_WithOutParam( Pos testValue, int expectedOutValue ) { - View v = new View(); - var d = new Design(new SourceCodeFile(new FileInfo("yarg.cs")), "myView", v); - - var p = Pos.Percent(50) + 2; - ClassicAssert.True(p.GetPosType(new List { d }, out PosType type, out float value, out var relativeTo, out var side, out int offset), $"Could not figure out PosType for '{p}'"); - ClassicAssert.AreEqual(PosType.Percent, type); - ClassicAssert.AreEqual(50, value); - ClassicAssert.AreEqual(2, offset); - - p = Pos.Percent(50) - 2; - ClassicAssert.True(p.GetPosType(new List { d }, out type, out value, out relativeTo, out side, out offset), $"Could not figure out PosType for '{p}'"); - ClassicAssert.AreEqual(PosType.Percent, type); - ClassicAssert.AreEqual(50, value); - ClassicAssert.AreEqual(-2, offset); - - p = Pos.Top(v) + 2; - ClassicAssert.True(p.GetPosType(new List { d }, out type, out value, out relativeTo, out side, out offset), $"Could not figure out PosType for '{p}'"); - ClassicAssert.AreEqual(PosType.Relative, type); - ClassicAssert.AreSame(d, relativeTo); - ClassicAssert.AreEqual(Side.Top, side); - ClassicAssert.AreEqual(2, offset); - - p = Pos.Top(v) - 2; - ClassicAssert.True(p.GetPosType(new List { d }, out type, out value, out relativeTo, out side, out offset), $"Could not figure out PosType for '{p}'"); - ClassicAssert.AreEqual(PosType.Relative, type); - ClassicAssert.AreSame(d, relativeTo); - ClassicAssert.AreEqual(Side.Top, side); - ClassicAssert.AreEqual(-2, offset); + bool isAbsolute = testValue.IsAbsolute( out int actualOutValue ); + Assert.That( actualOutValue, Is.EqualTo( expectedOutValue ) ); + return isAbsolute; } [Test] - public void TestNullPos() + [TestCaseSource( nameof( IsAnchorEnd_Cases ) )] + [NonParallelizable] + public bool IsAnchorEnd( Pos? testValue ) { - var v = new View(); + if ( testValue is null ) + { + Assert.Ignore( "BUG: Null returns true for this, when it shouldn't" ); + } + return testValue.IsAnchorEnd( ); + } - ClassicAssert.IsNull(v.X, "As of v1.7.0 a new View started getting null for its X, if this assert fails it means that behaviour was reverted and this test can be altered or suppressed"); + [Test] + [TestCaseSource( nameof( IsAnchorEnd_WithOutParam_Cases ) )] + [NonParallelizable] + public bool IsAnchorEnd_WithOutParam( Pos testValue, int expectedOutValue ) + { + bool isAnchorEnd = testValue.IsAnchorEnd( out int actualOutValue ); + Assert.That( actualOutValue, Is.EqualTo( expectedOutValue ) ); + return isAnchorEnd; + } - ClassicAssert.IsTrue(v.X.IsAbsolute()); - ClassicAssert.IsTrue(v.X.IsAbsolute(out int n)); - ClassicAssert.AreEqual(0, n); + [Test] + [TestCaseSource( nameof( IsPercent_Cases ) )] + [NonParallelizable] + public bool IsPercent( Pos testValue ) + { + return testValue.IsPercent( ); + } - ClassicAssert.IsFalse(v.X.IsPercent()); - ClassicAssert.IsFalse(v.X.IsCombine()); - ClassicAssert.IsFalse(v.X.IsCenter()); + [Test] + [TestCaseSource( nameof( IsPercent_WithOutParam_Cases ) )] + [NonParallelizable] + public bool IsPercent_WithOutParam( Pos testValue, float expectedOutValue ) + { + bool isPercent = testValue.IsPercent( out float actualOutValue ); + Assert.That( actualOutValue, Is.EqualTo( expectedOutValue ) ); + return isPercent; + } - ClassicAssert.IsFalse(v.X.IsRelative()); - ClassicAssert.IsFalse(v.X.IsRelative(new List(), out _, out _)); + [Test] + [TestCaseSource( nameof( IsRelative_Cases ) )] + [NonParallelizable] + public bool IsRelative( Pos testValue ) + { + return testValue.IsRelative( ); + } - ClassicAssert.IsTrue(v.X.GetPosType(new List(), out var type, out var val, out _, out _, out _)); + [Test] + [TestCaseSource( nameof( IsRelative_WithOutParams_Cases ) )] + [NonParallelizable] + public bool IsRelative_WithOutParams( Pos testValue, Design? expectedOutDesign, Side expectedOutSide ) + { + List knownDesigns = new( ); + if ( expectedOutDesign is not null ) + { + knownDesigns.Add( expectedOutDesign ); + } - ClassicAssert.AreEqual(PosType.Absolute, type); - ClassicAssert.AreEqual(0, val); + bool isRelative = testValue.IsRelative( knownDesigns, out Design? actualOutDesign, out Side actualOutSide ); + Assert.That( actualOutDesign, Is.SameAs( expectedOutDesign ) ); + Assert.That( actualOutSide, Is.EqualTo( expectedOutSide ) ); + return isRelative; } [Test] - public void TestGetCode_WithNoOffset() + public void CreatePosRelative( [Values] Side side, [Values( -10, -5, 0, 5, 10 )] int offset ) { - View v = new View(); - var d = new Design(new SourceCodeFile(new FileInfo("yarg.cs")), "myView", v); - - var p = Pos.Percent(50); - ClassicAssert.AreEqual("Pos.Percent(50f)", p.ToCode(new List { d })); - - p = Pos.Left(v); - ClassicAssert.AreEqual("Pos.Left(myView)", p.ToCode(new List { d })); - p = Pos.Right(v); - ClassicAssert.AreEqual("Pos.Right(myView)", p.ToCode(new List { d })); - p = Pos.Bottom(v); - ClassicAssert.AreEqual("Pos.Bottom(myView)", p.ToCode(new List { d })); - p = Pos.Top(v); - ClassicAssert.AreEqual("Pos.Top(myView)", p.ToCode(new List { d })); + View v = new( ); + Design d = new( new( new FileInfo( "yarg.cs" ) ), "myView", v ); + + Pos p = d.CreatePosRelative( side, offset ); + if ( offset != 0 ) + { + Assert.Ignore( "Bug results in offsets returning absolute positions. See PosExtensions.cs" ); + } + + Assert.Multiple( ( ) => + { + Assert.That( p.IsRelative ); + Assert.That( p.IsRelative( new List { d }, out Design outDesign, out Side outSide ) ); + Assert.That( outDesign, Is.SameAs( d ) ); + Assert.That( outSide, Is.EqualTo( side ) ); + } ); } [Test] - public void TestGetCode_WithOffset() + public void NullPos( ) { - View v = new View(); - var d = new Design(new SourceCodeFile(new FileInfo("yarg.cs")), "myView", v); + var v = new View( ); - var p = Pos.Percent(50) + 2; - ClassicAssert.AreEqual("Pos.Percent(50f) + 2", p.ToCode(new List { d })); + Assume.That( v.X, Is.Null, "As of v1.7.0 a new View started getting null for its X, if this assert fails it means that behaviour was reverted and this test can be altered or suppressed" ); - p = Pos.Percent(50) - 2; - ClassicAssert.AreEqual("Pos.Percent(50f) - 2", p.ToCode(new List { d })); + Pos? nullPos = null; + Assert.That( nullPos.IsAbsolute ); + Assert.That( nullPos.IsAbsolute( out int n ) ); + Assert.That( n, Is.Zero ); - p = Pos.Right(v) + 2; - ClassicAssert.AreEqual("Pos.Right(myView) + 2", p.ToCode(new List { d })); + Assert.That( v.X.GetPosType( new List( ), out var type, out var val, out _, out _, out _ ) ); - p = Pos.Right(v) - 2; - ClassicAssert.AreEqual("Pos.Right(myView) - 2", p.ToCode(new List { d })); + Assert.That( type, Is.EqualTo( PosType.Absolute ) ); + Assert.That( val, Is.Zero ); } - [TestCase(Side.Left, -2, "X")] - [TestCase(Side.Right, 1, "X")] - [TestCase(Side.Top, -2, "Y")] - [TestCase(Side.Bottom, 5, "Y")] - public void TestRoundTrip_PosRelative(Side side, int offset, string property) + [Test] + [Ignore( "Code generation is tested in other tests here" )] + public void TestRoundTrip_PosAnchorEnd( ) { - var viewToCode = new ViewToCode(); + var viewToCode = new ViewToCode( ); - var file = new FileInfo("TestRoundTrip_PosRelative.cs"); - var designOut = viewToCode.GenerateNewView(file, "YourNamespace", typeof(Window)); + var file = new FileInfo( "TestRoundTrip_PosAnchorEnd.cs" ); + var designOut = viewToCode.GenerateNewView( file, "YourNamespace", typeof( Window ) ); designOut.View.Width = 100; designOut.View.Height = 100; var lbl = ViewFactory.Create