Browse Source

Merge branch 'v2_develop' into gradients

Thomas Nind 1 year ago
parent
commit
5a548f0805

+ 28 - 23
.github/workflows/dotnet-core.yml

@@ -2,19 +2,24 @@ name: Build & Test Terminal.Gui with .NET Core
 
 
 on:
 on:
   push:
   push:
-    branches: [ main, develop, v2_develop ]
+    branches: [ v2, v2_develop ]
+    paths-ignore:
+      - '**.md'
   pull_request:
   pull_request:
-    branches: [ main, develop, v2_develop ]
-
+    branches: [ v2, v2_develop ]
+    paths-ignore:
+      - '**.md'
+      
 jobs:
 jobs:
   build_and_test:
   build_and_test:
 
 
-    runs-on: windows-latest
-
+    runs-on: ubuntu-latest
+    timeout-minutes: 10
     steps:
     steps:
-    - uses: actions/checkout@v4
     
     
-    - name: Setup dotnet
+    - uses: actions/checkout@v4
+
+    - name: Setup .NET Core
       uses: actions/setup-dotnet@v4
       uses: actions/setup-dotnet@v4
       with:
       with:
         dotnet-version: 8.x
         dotnet-version: 8.x
@@ -34,19 +39,19 @@ jobs:
         mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
         mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
 
 
     # Note: this step is currently not writing to the gist for some reason
     # Note: this step is currently not writing to the gist for some reason
-    - name: Create Test Coverage Badge
-      uses: simon-k/[email protected]
-      id: create_coverage_badge
-      with:
-        label: Unit Test Coverage
-        color: brightgreen
-        path: UnitTests/TestResults/coverage.opencover.xml
-        gist-filename: code-coverage.json
-        # https://gist.github.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27
-        gist-id: 90ef67a684cb71db1817921a970f8d27
-        gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
-
-    - name: Print Code Coverage
-      run: |
-        echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
-        echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"
+    # - name: Create Test Coverage Badge
+    #   uses: simon-k/[email protected]
+    #   id: create_coverage_badge
+    #   with:
+    #     label: Unit Test Coverage
+    #     color: brightgreen
+    #     path: UnitTests/TestResults/coverage.opencover.xml
+    #     gist-filename: code-coverage.json
+    #     # https://gist.github.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27
+    #     gist-id: 90ef67a684cb71db1817921a970f8d27
+    #     gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
+
+    # - name: Print Code Coverage
+    #   run: |
+    #     echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
+    #     echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"

+ 1 - 1
.github/workflows/publish.yml

@@ -25,7 +25,7 @@ jobs:
           includePrerelease: true
           includePrerelease: true
 
 
     - name: Determine Version
     - name: Determine Version
-      uses: gittools/actions/gitversion/execute@v0
+      uses: gittools/actions/gitversion/execute@v1
       with:
       with:
         useConfigFile: true
         useConfigFile: true
         #additionalArguments: /b develop
         #additionalArguments: /b develop

+ 59 - 1
Terminal.Gui/Application/Application.cs

@@ -975,7 +975,7 @@ public static partial class Application
 
 
         if (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded || OverlappedChildNeedsDisplay ())
         if (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded || OverlappedChildNeedsDisplay ())
         {
         {
-            state.Toplevel.SetNeedsDisplay();
+            state.Toplevel.SetNeedsDisplay ();
             state.Toplevel.Draw ();
             state.Toplevel.Draw ();
             Driver.UpdateScreen ();
             Driver.UpdateScreen ();
 
 
@@ -1439,4 +1439,62 @@ public static partial class Application
     }
     }
 
 
     #endregion Toplevel handling
     #endregion Toplevel handling
+
+    /// <summary>
+    ///     Gets a string representation of the Application as rendered by <see cref="Driver"/>.
+    /// </summary>
+    /// <returns>A string representation of the Application </returns>
+    public new static string ToString ()
+    {
+        ConsoleDriver driver = Driver;
+
+        if (driver is null)
+        {
+            return string.Empty;
+        }
+
+        return ToString (driver);
+    }
+
+    /// <summary>
+    ///     Gets a string representation of the Application rendered by the provided <see cref="ConsoleDriver"/>.
+    /// </summary>
+    /// <param name="driver">The driver to use to render the contents.</param>
+    /// <returns>A string representation of the Application </returns>
+    public static string ToString (ConsoleDriver driver)
+    {
+        var sb = new StringBuilder ();
+
+        Cell [,] contents = driver.Contents;
+
+        for (var r = 0; r < driver.Rows; r++)
+        {
+            for (var c = 0; c < driver.Cols; c++)
+            {
+                Rune rune = contents [r, c].Rune;
+
+                if (rune.DecodeSurrogatePair (out char [] sp))
+                {
+                    sb.Append (sp);
+                }
+                else
+                {
+                    sb.Append ((char)rune.Value);
+                }
+
+                if (rune.GetColumns () > 1)
+                {
+                    c++;
+                }
+
+                // See Issue #2616
+                //foreach (var combMark in contents [r, c].CombiningMarks) {
+                //	sb.Append ((char)combMark.Value);
+                //}
+            }
+
+            sb.AppendLine ();
+        }
+        return sb.ToString ();
+    }
 }
 }

+ 71 - 95
Terminal.Gui/Drawing/Thickness.cs

@@ -1,4 +1,5 @@
-using System.Text.Json.Serialization;
+using System.Numerics;
+using System.Text.Json.Serialization;
 
 
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
@@ -13,28 +14,18 @@ namespace Terminal.Gui;
 ///         frame,
 ///         frame,
 ///         with the thickness widths subtracted.
 ///         with the thickness widths subtracted.
 ///     </para>
 ///     </para>
-///     <para>Use the helper API (<see cref="Draw(Rectangle, string)"/> to draw the frame with the specified thickness.</para>
+///     <para>
+///         Use the helper API (<see cref="Draw(Rectangle, string)"/> to draw the frame with the specified thickness.
+///     </para>
+///     <para>
+///         Thickness uses <see langword="float"/> intenrally. As a result, there is a potential precision loss for very
+///         large numbers. This is typically not an issue for UI dimensions but could be relevant in other contexts.
+///     </para>
 /// </remarks>
 /// </remarks>
-public class Thickness : IEquatable<Thickness>
+public record struct Thickness
 {
 {
-    /// <summary>Gets or sets the width of the lower side of the rectangle.</summary>
-    [JsonInclude]
-    public int Bottom;
-
-    /// <summary>Gets or sets the width of the left side of the rectangle.</summary>
-    [JsonInclude]
-    public int Left;
-
-    /// <summary>Gets or sets the width of the right side of the rectangle.</summary>
-    [JsonInclude]
-    public int Right;
-
-    /// <summary>Gets or sets the width of the upper side of the rectangle.</summary>
-    [JsonInclude]
-    public int Top;
-
     /// <summary>Initializes a new instance of the <see cref="Thickness"/> class with all widths set to 0.</summary>
     /// <summary>Initializes a new instance of the <see cref="Thickness"/> class with all widths set to 0.</summary>
-    public Thickness () { }
+    public Thickness () { _sides = Vector4.Zero; }
 
 
     /// <summary>Initializes a new instance of the <see cref="Thickness"/> class with a uniform width to each side.</summary>
     /// <summary>Initializes a new instance of the <see cref="Thickness"/> class with a uniform width to each side.</summary>
     /// <param name="width"></param>
     /// <param name="width"></param>
@@ -56,36 +47,24 @@ public class Thickness : IEquatable<Thickness>
         Bottom = bottom;
         Bottom = bottom;
     }
     }
 
 
-    // TODO: add operator overloads
-    /// <summary>Gets an empty thickness.</summary>
-    public static Thickness Empty => new (0);
+    private Vector4 _sides;
 
 
     /// <summary>
     /// <summary>
-    ///     Gets the total width of the left and right sides of the rectangle. Sets the width of the left and rigth sides
-    ///     of the rectangle to half the specified value.
+    ///     Adds the thickness widths of another <see cref="Thickness"/> to the current <see cref="Thickness"/>, returning a
+    ///     new <see cref="Thickness"/>.
     /// </summary>
     /// </summary>
-    public int Horizontal
-    {
-        get => Left + Right;
-        set => Left = Right = value / 2;
-    }
+    /// <param name="other"></param>
+    /// <returns></returns>
+    public readonly Thickness Add (Thickness other) { return new (Left + other.Left, Top + other.Top, Right + other.Right, Bottom + other.Bottom); }
 
 
-    /// <summary>
-    ///     Gets the total height of the top and bottom sides of the rectangle. Sets the height of the top and bottom
-    ///     sides of the rectangle to half the specified value.
-    /// </summary>
-    public int Vertical
+    /// <summary>Gets or sets the width of the lower side of the rectangle.</summary>
+    [JsonInclude]
+    public int Bottom
     {
     {
-        get => Top + Bottom;
-        set => Top = Bottom = value / 2;
+        get => (int)_sides.W;
+        set => _sides.W = value;
     }
     }
 
 
-    // IEquitable
-    /// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
-    /// <param name="other"></param>
-    /// <returns>true if the current object is equal to the other parameter; otherwise, false.</returns>
-    public bool Equals (Thickness other) { return other is { } && Left == other.Left && Right == other.Right && Top == other.Top && Bottom == other.Bottom; }
-
     /// <summary>
     /// <summary>
     ///     Gets whether the specified coordinates lie within the thickness (inside the bounding rectangle but outside
     ///     Gets whether the specified coordinates lie within the thickness (inside the bounding rectangle but outside
     ///     the rectangle described by <see cref="GetInside(Rectangle)"/>.
     ///     the rectangle described by <see cref="GetInside(Rectangle)"/>.
@@ -100,22 +79,6 @@ public class Thickness : IEquatable<Thickness>
         return outside.Contains (location) && !inside.Contains (location);
         return outside.Contains (location) && !inside.Contains (location);
     }
     }
 
 
-    /// <summary>
-    ///     Adds the thickness widths of another <see cref="Thickness"/> to the current <see cref="Thickness"/>, returning a
-    ///     new <see cref="Thickness"/>.
-    /// </summary>
-    /// <param name="other"></param>
-    /// <returns></returns>
-    public Thickness Add (Thickness other) { return new (Left + other.Left, Top + other.Top, Right + other.Right, Bottom + other.Bottom); }
-
-    /// <summary>
-    ///     Adds the thickness widths of another <see cref="Thickness"/> to another <see cref="Thickness"/>.
-    /// </summary>
-    /// <param name="a"></param>
-    /// <param name="b"></param>
-    /// <returns></returns>
-    public static Thickness operator + (Thickness a, Thickness b) { return a.Add (b); }
-
     /// <summary>Draws the <see cref="Thickness"/> rectangle with an optional diagnostics label.</summary>
     /// <summary>Draws the <see cref="Thickness"/> rectangle with an optional diagnostics label.</summary>
     /// <remarks>
     /// <remarks>
     ///     If <see cref="ViewDiagnosticFlags"/> is set to
     ///     If <see cref="ViewDiagnosticFlags"/> is set to
@@ -240,31 +203,8 @@ public class Thickness : IEquatable<Thickness>
         return GetInside (rect);
         return GetInside (rect);
     }
     }
 
 
-    /// <summary>Determines whether the specified object is equal to the current object.</summary>
-    /// <param name="obj">The object to compare with the current object.</param>
-    /// <returns><c>true</c> if the specified object is equal to the current object; otherwise, <c>false</c>.</returns>
-    public override bool Equals (object obj)
-    {
-        //Check for null and compare run-time types.
-        if (obj is null || !GetType ().Equals (obj.GetType ()))
-        {
-            return false;
-        }
-
-        return Equals ((Thickness)obj);
-    }
-
-    /// <inheritdoc/>
-    public override int GetHashCode ()
-    {
-        var hashCode = 1380952125;
-        hashCode = hashCode * -1521134295 + Left.GetHashCode ();
-        hashCode = hashCode * -1521134295 + Right.GetHashCode ();
-        hashCode = hashCode * -1521134295 + Top.GetHashCode ();
-        hashCode = hashCode * -1521134295 + Bottom.GetHashCode ();
-
-        return hashCode;
-    }
+    /// <summary>Gets an empty thickness.</summary>
+    public static Thickness Empty => new (0);
 
 
     /// <summary>
     /// <summary>
     ///     Returns a rectangle describing the location and size of the inside area of <paramref name="rect"/> with the
     ///     Returns a rectangle describing the location and size of the inside area of <paramref name="rect"/> with the
@@ -289,23 +229,59 @@ public class Thickness : IEquatable<Thickness>
         return new (x, y, width, height);
         return new (x, y, width, height);
     }
     }
 
 
-    /// <inheritdoc/>
-    public static bool operator == (Thickness left, Thickness right) { return EqualityComparer<Thickness>.Default.Equals (left, right); }
+    /// <summary>
+    ///     Gets the total width of the left and right sides of the rectangle. Sets the width of the left and rigth sides
+    ///     of the rectangle to half the specified value.
+    /// </summary>
+    public int Horizontal
+    {
+        get => Left + Right;
+        set => Left = Right = value / 2;
+    }
 
 
-    /// <inheritdoc/>
-    public static bool operator != (Thickness left, Thickness right) { return !(left == right); }
+    /// <summary>Gets or sets the width of the left side of the rectangle.</summary>
+    [JsonInclude]
+    public int Left
+    {
+        get => (int)_sides.X;
+        set => _sides.X = value;
+    }
+
+    /// <summary>
+    ///     Adds the thickness widths of another <see cref="Thickness"/> to another <see cref="Thickness"/>.
+    /// </summary>
+    /// <param name="a"></param>
+    /// <param name="b"></param>
+    /// <returns></returns>
+    public static Thickness operator + (Thickness a, Thickness b) { return a.Add (b); }
+
+    /// <summary>Gets or sets the width of the right side of the rectangle.</summary>
+    [JsonInclude]
+    public int Right
+    {
+        get => (int)_sides.Z;
+        set => _sides.Z = value;
+    }
+
+    /// <summary>Gets or sets the width of the upper side of the rectangle.</summary>
+    [JsonInclude]
+    public int Top
+    {
+        get => (int)_sides.Y;
+        set => _sides.Y = value;
+    }
 
 
     /// <summary>Returns the thickness widths of the Thickness formatted as a string.</summary>
     /// <summary>Returns the thickness widths of the Thickness formatted as a string.</summary>
     /// <returns>The thickness widths as a string.</returns>
     /// <returns>The thickness widths as a string.</returns>
     public override string ToString () { return $"(Left={Left},Top={Top},Right={Right},Bottom={Bottom})"; }
     public override string ToString () { return $"(Left={Left},Top={Top},Right={Right},Bottom={Bottom})"; }
 
 
-    private int validate (int width)
+    /// <summary>
+    ///     Gets the total height of the top and bottom sides of the rectangle. Sets the height of the top and bottom
+    ///     sides of the rectangle to half the specified value.
+    /// </summary>
+    public int Vertical
     {
     {
-        if (width < 0)
-        {
-            throw new ArgumentException ("Thickness widths cannot be negative.");
-        }
-
-        return width;
+        get => Top + Bottom;
+        set => Top = Bottom = value / 2;
     }
     }
 }
 }

+ 99 - 263
UnitTests/TestHelpers.cs

@@ -1,32 +1,28 @@
-using System.Collections;
-using System.Diagnostics;
+using System.Diagnostics;
 using System.Globalization;
 using System.Globalization;
 using System.Reflection;
 using System.Reflection;
 using System.Text;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
-using UICatalog;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
 using Xunit.Sdk;
 using Xunit.Sdk;
 
 
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
-// This class enables test functions annotated with the [AutoInitShutdown] attribute to 
-// automatically call Application.Init at start of the test and Application.Shutdown after the
-// test exits. 
-// 
-// This is necessary because a) Application is a singleton and Init/Shutdown must be called
-// as a pair, and b) all unit test functions should be atomic..
+/// <summary>
+///     This class enables test functions annotated with the [AutoInitShutdown] attribute to
+///     automatically call Application.Init at start of the test and Application.Shutdown after the
+///     test exits.
+///     This is necessary because a) Application is a singleton and Init/Shutdown must be called
+///     as a pair, and b) all unit test functions should be atomic..
+/// </summary>
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
 public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
 public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
 {
 {
-    private readonly Type _driverType;
-
     /// <summary>
     /// <summary>
     ///     Initializes a [AutoInitShutdown] attribute, which determines if/how Application.Init and Application.Shutdown
     ///     Initializes a [AutoInitShutdown] attribute, which determines if/how Application.Init and Application.Shutdown
     ///     are automatically called Before/After a test runs.
     ///     are automatically called Before/After a test runs.
     /// </summary>
     /// </summary>
     /// <param name="autoInit">If true, Application.Init will be called Before the test runs.</param>
     /// <param name="autoInit">If true, Application.Init will be called Before the test runs.</param>
-    /// <param name="autoShutdown">If true, Application.Shutdown will be called After the test runs.</param>
     /// <param name="consoleDriverType">
     /// <param name="consoleDriverType">
     ///     Determines which ConsoleDriver (FakeDriver, WindowsDriver, CursesDriver, NetDriver)
     ///     Determines which ConsoleDriver (FakeDriver, WindowsDriver, CursesDriver, NetDriver)
     ///     will be used when Application.Init is called. If null FakeDriver will be used. Only valid if
     ///     will be used when Application.Init is called. If null FakeDriver will be used. Only valid if
@@ -65,7 +61,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
         ConfigurationManager.Locations = configLocation;
         ConfigurationManager.Locations = configLocation;
     }
     }
 
 
-    private bool AutoInit { get; }
+    private readonly Type _driverType;
 
 
     public override void After (MethodInfo methodUnderTest)
     public override void After (MethodInfo methodUnderTest)
     {
     {
@@ -102,6 +98,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
             ConfigurationManager.Reset ();
             ConfigurationManager.Reset ();
 
 
 #if DEBUG_IDISPOSABLE
 #if DEBUG_IDISPOSABLE
+
             // Clear out any lingering Responder instances from previous tests
             // Clear out any lingering Responder instances from previous tests
             if (Responder.Instances.Count == 0)
             if (Responder.Instances.Count == 0)
             {
             {
@@ -115,6 +112,8 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
             Application.Init ((ConsoleDriver)Activator.CreateInstance (_driverType));
             Application.Init ((ConsoleDriver)Activator.CreateInstance (_driverType));
         }
         }
     }
     }
+
+    private bool AutoInit { get; }
 }
 }
 
 
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
@@ -178,8 +177,8 @@ public class SetupFakeDriverAttribute : BeforeAfterTestAttribute
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
 [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
 public class TestDateAttribute : BeforeAfterTestAttribute
 public class TestDateAttribute : BeforeAfterTestAttribute
 {
 {
-    private readonly CultureInfo _currentCulture = CultureInfo.CurrentCulture;
     public TestDateAttribute () { CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; }
     public TestDateAttribute () { CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; }
+    private readonly CultureInfo _currentCulture = CultureInfo.CurrentCulture;
 
 
     public override void After (MethodInfo methodUnderTest)
     public override void After (MethodInfo methodUnderTest)
     {
     {
@@ -238,12 +237,12 @@ internal partial class TestHelpers
                 switch (match.Count)
                 switch (match.Count)
                 {
                 {
                     case 0:
                     case 0:
-                        throw new Exception (
-                                             $"{DriverContentsToString (driver)}\n"
-                                             + $"Expected Attribute {val} (PlatformColor = {val.Value.PlatformColor}) at Contents[{line},{c}] {contents [line, c]} ((PlatformColor = {contents [line, c].Attribute.Value.PlatformColor}) was not found.\n"
-                                             + $"  Expected: {string.Join (",", expectedAttributes.Select (c => c))}\n"
-                                             + $"  But Was: <not found>"
-                                            );
+                        throw new (
+                                   $"{Application.ToString (driver)}\n"
+                                   + $"Expected Attribute {val} (PlatformColor = {val.Value.PlatformColor}) at Contents[{line},{c}] {contents [line, c]} ((PlatformColor = {contents [line, c].Attribute.Value.PlatformColor}) was not found.\n"
+                                   + $"  Expected: {string.Join (",", expectedAttributes.Select (c => c))}\n"
+                                   + $"  But Was: <not found>"
+                                  );
                     case > 1:
                     case > 1:
                         throw new ArgumentException (
                         throw new ArgumentException (
                                                      $"Bad value for expectedColors, {match.Count} Attributes had the same Value"
                                                      $"Bad value for expectedColors, {match.Count} Attributes had the same Value"
@@ -255,12 +254,12 @@ internal partial class TestHelpers
 
 
                 if (colorUsed != userExpected)
                 if (colorUsed != userExpected)
                 {
                 {
-                    throw new Exception (
-                                         $"{DriverContentsToString (driver)}\n"
-                                         + $"Unexpected Attribute at Contents[{line},{c}] {contents [line, c]}.\n"
-                                         + $"  Expected: {userExpected} ({expectedAttributes [int.Parse (userExpected.ToString ())]})\n"
-                                         + $"  But Was:   {colorUsed} ({val})\n"
-                                        );
+                    throw new (
+                               $"{Application.ToString (driver)}\n"
+                               + $"Unexpected Attribute at Contents[{line},{c}] {contents [line, c]}.\n"
+                               + $"  Expected: {userExpected} ({expectedAttributes [int.Parse (userExpected.ToString ())]})\n"
+                               + $"  But Was:   {colorUsed} ({val})\n"
+                              );
                 }
                 }
             }
             }
 
 
@@ -282,7 +281,7 @@ internal partial class TestHelpers
     )
     )
     {
     {
 #pragma warning restore xUnit1013 // Public method should be marked as test
 #pragma warning restore xUnit1013 // Public method should be marked as test
-        string actualLook = DriverContentsToString (driver);
+        var actualLook = Application.ToString (driver ?? Application.Driver);
 
 
         if (string.Equals (expectedLook, actualLook))
         if (string.Equals (expectedLook, actualLook))
         {
         {
@@ -314,8 +313,7 @@ internal partial class TestHelpers
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Asserts that the driver contents are equal to the expected look, and that the cursor is at the expected
-    ///     position.
+    ///     Asserts that the driver contents are equal to the provided string.
     /// </summary>
     /// </summary>
     /// <param name="expectedLook"></param>
     /// <param name="expectedLook"></param>
     /// <param name="output"></param>
     /// <param name="output"></param>
@@ -337,7 +335,6 @@ internal partial class TestHelpers
 
 
         Cell [,] contents = driver.Contents;
         Cell [,] contents = driver.Contents;
 
 
-
         for (var rowIndex = 0; rowIndex < driver.Rows; rowIndex++)
         for (var rowIndex = 0; rowIndex < driver.Rows; rowIndex++)
         {
         {
             List<Rune> runes = [];
             List<Rune> runes = [];
@@ -353,7 +350,7 @@ internal partial class TestHelpers
                         x = colIndex;
                         x = colIndex;
                         y = rowIndex;
                         y = rowIndex;
 
 
-                        for (int i = 0; i < colIndex; i++)
+                        for (var i = 0; i < colIndex; i++)
                         {
                         {
                             runes.InsertRange (i, [SpaceRune]);
                             runes.InsertRange (i, [SpaceRune]);
                         }
                         }
@@ -433,7 +430,7 @@ internal partial class TestHelpers
 
 
         if (string.Equals (expectedLook, actualLook))
         if (string.Equals (expectedLook, actualLook))
         {
         {
-            return new Rectangle (x > -1 ? x : 0, y > -1 ? y : 0, w > -1 ? w : 0, h > -1 ? h : 0);
+            return new (x > -1 ? x : 0, y > -1 ? y : 0, w > -1 ? w : 0, h > -1 ? h : 0);
         }
         }
 
 
         // standardize line endings for the comparison
         // standardize line endings for the comparison
@@ -453,7 +450,7 @@ internal partial class TestHelpers
 
 
         Assert.Equal (expectedLook, actualLook);
         Assert.Equal (expectedLook, actualLook);
 
 
-        return new Rectangle (x > -1 ? x : 0, y > -1 ? y : 0, w > -1 ? w : 0, h > -1 ? h : 0);
+        return new (x > -1 ? x : 0, y > -1 ? y : 0, w > -1 ? w : 0, h > -1 ? h : 0);
     }
     }
 
 
 #pragma warning disable xUnit1013 // Public method should be marked as test
 #pragma warning disable xUnit1013 // Public method should be marked as test
@@ -483,95 +480,86 @@ internal partial class TestHelpers
     }
     }
 #pragma warning restore xUnit1013 // Public method should be marked as test
 #pragma warning restore xUnit1013 // Public method should be marked as test
 
 
-    public static string DriverContentsToString (ConsoleDriver driver = null)
+    public static View CreateViewFromType (Type type, ConstructorInfo ctor)
     {
     {
-        var sb = new StringBuilder ();
-        driver ??= Application.Driver;
-
-        Cell [,] contents = driver.Contents;
+        View viewType = null;
 
 
-        for (var r = 0; r < driver.Rows; r++)
+        if (type.IsGenericType && type.IsTypeDefinition)
         {
         {
-            for (var c = 0; c < driver.Cols; c++)
+            List<Type> gTypes = new ();
+
+            foreach (Type args in type.GetGenericArguments ())
             {
             {
-                Rune rune = contents [r, c].Rune;
+                gTypes.Add (typeof (object));
+            }
+
+            type = type.MakeGenericType (gTypes.ToArray ());
+
+            Assert.IsType (type, (View)Activator.CreateInstance (type));
+        }
+        else
+        {
+            ParameterInfo [] paramsInfo = ctor.GetParameters ();
+            Type paramType;
+            List<object> pTypes = new ();
 
 
-                if (rune.DecodeSurrogatePair (out char [] sp))
+            if (type.IsGenericType)
+            {
+                foreach (Type args in type.GetGenericArguments ())
                 {
                 {
-                    sb.Append (sp);
+                    paramType = args.GetType ();
+
+                    if (args.Name == "T")
+                    {
+                        pTypes.Add (typeof (object));
+                    }
+                    else
+                    {
+                        AddArguments (paramType, pTypes);
+                    }
                 }
                 }
-                else
+            }
+
+            foreach (ParameterInfo p in paramsInfo)
+            {
+                paramType = p.ParameterType;
+
+                if (p.HasDefaultValue)
                 {
                 {
-                    sb.Append ((char)rune.Value);
+                    pTypes.Add (p.DefaultValue);
                 }
                 }
-
-                if (rune.GetColumns () > 1)
+                else
                 {
                 {
-                    c++;
+                    AddArguments (paramType, pTypes);
                 }
                 }
-
-                // See Issue #2616
-                //foreach (var combMark in contents [r, c].CombiningMarks) {
-                //	sb.Append ((char)combMark.Value);
-                //}
             }
             }
 
 
-            sb.AppendLine ();
+            if (type.IsGenericType && !type.IsTypeDefinition)
+            {
+                viewType = (View)Activator.CreateInstance (type);
+                Assert.IsType (type, viewType);
+            }
+            else
+            {
+                viewType = (View)ctor.Invoke (pTypes.ToArray ());
+                Assert.IsType (type, viewType);
+            }
         }
         }
 
 
-        return sb.ToString ();
+        return viewType;
     }
     }
 
 
-    //// TODO: Update all tests that use GetALlViews to use GetAllViewsTheoryData instead
-    ///// <summary>Gets a list of instances of all classes derived from View.</summary>
-    ///// <returns>List of View objects</returns>
-    //public static List<View> GetAllViews ()
-    //{
-    //    return typeof (View).Assembly.GetTypes ()
-    //                        .Where (
-    //                                type => type.IsClass
-    //                                        && !type.IsAbstract
-    //                                        && type.IsPublic
-    //                                        && type.IsSubclassOf (typeof (View))
-    //                               )
-    //                        .Select (type => CreateView (type, type.GetConstructor (Array.Empty<Type> ())))
-    //                        .ToList ();
-    //}
-
-    //public class AllViewsData : IEnumerable<object []>
-    //{
-    //    private Lazy<List<object []>> data;
-
-    //    public AllViewsData ()
-    //    {
-    //        data = new Lazy<List<object []>> (GetTestData);
-    //    }
-
-    //    public IEnumerator<object []> GetEnumerator ()
-    //    {
-    //        return data.Value.GetEnumerator ();
-    //    }
-
-    //    IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
-
-    //    private List<object []> GetTestData ()
-    //    {
-    //        var viewTypes = typeof (View).Assembly
-    //                                     .GetTypes ()
-    //                                     .Where (type => type.IsClass && !type.IsAbstract && type.IsPublic && type.IsSubclassOf (typeof (View)));
-
-    //        var testData = new List<object []> ();
-
-    //        foreach (var type in viewTypes)
-    //        {
-    //            var view = CreateView (type, type.GetConstructor (Array.Empty<Type> ()));
-    //            testData.Add (new object [] { view, type.Name });
-    //        }
-
-    //        return testData;
-    //    }
-    //}
-
+    public static List<Type> GetAllViewClasses ()
+    {
+        return typeof (View).Assembly.GetTypes ()
+                            .Where (
+                                    myType => myType.IsClass
+                                              && !myType.IsAbstract
+                                              && myType.IsPublic
+                                              && myType.IsSubclassOf (typeof (View))
+                                   )
+                            .ToList ();
+    }
 
 
     /// <summary>
     /// <summary>
     ///     Verifies the console used all the <paramref name="expectedColors"/> when rendering. If one or more of the
     ///     Verifies the console used all the <paramref name="expectedColors"/> when rendering. If one or more of the
@@ -620,7 +608,7 @@ internal partial class TestHelpers
         sb.AppendLine ("The following colors were not used:" + string.Join ("; ", toFind.Select (a => a.ToString ())));
         sb.AppendLine ("The following colors were not used:" + string.Join ("; ", toFind.Select (a => a.ToString ())));
         sb.AppendLine ("Colors used were:" + string.Join ("; ", colorsUsed.Select (a => a.ToString ())));
         sb.AppendLine ("Colors used were:" + string.Join ("; ", colorsUsed.Select (a => a.ToString ())));
 
 
-        throw new Exception (sb.ToString ());
+        throw new (sb.ToString ());
     }
     }
 
 
     private static void AddArguments (Type paramType, List<object> pTypes)
     private static void AddArguments (Type paramType, List<object> pTypes)
@@ -674,156 +662,6 @@ internal partial class TestHelpers
         }
         }
     }
     }
 
 
-    public static View CreateView (Type type, ConstructorInfo ctor)
-    {
-        View view = null;
-
-        if (type.IsGenericType && type.IsTypeDefinition)
-        {
-            List<Type> gTypes = new ();
-
-            foreach (Type args in type.GetGenericArguments ())
-            {
-                gTypes.Add (typeof (object));
-            }
-
-            type = type.MakeGenericType (gTypes.ToArray ());
-
-            Assert.IsType (type, (View)Activator.CreateInstance (type));
-        }
-        else
-        {
-            ParameterInfo [] paramsInfo = ctor.GetParameters ();
-            Type paramType;
-            List<object> pTypes = new ();
-
-            if (type.IsGenericType)
-            {
-                foreach (Type args in type.GetGenericArguments ())
-                {
-                    paramType = args.GetType ();
-
-                    if (args.Name == "T")
-                    {
-                        pTypes.Add (typeof (object));
-                    }
-                    else
-                    {
-                        AddArguments (paramType, pTypes);
-                    }
-                }
-            }
-
-            foreach (ParameterInfo p in paramsInfo)
-            {
-                paramType = p.ParameterType;
-
-                if (p.HasDefaultValue)
-                {
-                    pTypes.Add (p.DefaultValue);
-                }
-                else
-                {
-                    AddArguments (paramType, pTypes);
-                }
-            }
-
-            if (type.IsGenericType && !type.IsTypeDefinition)
-            {
-                view = (View)Activator.CreateInstance (type);
-                Assert.IsType (type, view);
-            }
-            else
-            {
-                view = (View)ctor.Invoke (pTypes.ToArray ());
-                Assert.IsType (type, view);
-            }
-        }
-
-        return view;
-    }
-
-    public static List<Type> GetAllViewClasses ()
-    {
-        return typeof (View).Assembly.GetTypes ()
-                            .Where (
-                                    myType => myType.IsClass
-                                              && !myType.IsAbstract
-                                              && myType.IsPublic
-                                              && myType.IsSubclassOf (typeof (View))
-                                   )
-                            .ToList ();
-    }
-
-    public static View CreateViewFromType (Type type, ConstructorInfo ctor)
-    {
-        View viewType = null;
-
-        if (type.IsGenericType && type.IsTypeDefinition)
-        {
-            List<Type> gTypes = new ();
-
-            foreach (Type args in type.GetGenericArguments ())
-            {
-                gTypes.Add (typeof (object));
-            }
-
-            type = type.MakeGenericType (gTypes.ToArray ());
-
-            Assert.IsType (type, (View)Activator.CreateInstance (type));
-        }
-        else
-        {
-            ParameterInfo [] paramsInfo = ctor.GetParameters ();
-            Type paramType;
-            List<object> pTypes = new ();
-
-            if (type.IsGenericType)
-            {
-                foreach (Type args in type.GetGenericArguments ())
-                {
-                    paramType = args.GetType ();
-
-                    if (args.Name == "T")
-                    {
-                        pTypes.Add (typeof (object));
-                    }
-                    else
-                    {
-                        AddArguments (paramType, pTypes);
-                    }
-                }
-            }
-
-            foreach (ParameterInfo p in paramsInfo)
-            {
-                paramType = p.ParameterType;
-
-                if (p.HasDefaultValue)
-                {
-                    pTypes.Add (p.DefaultValue);
-                }
-                else
-                {
-                    AddArguments (paramType, pTypes);
-                }
-            }
-
-            if (type.IsGenericType && !type.IsTypeDefinition)
-            {
-                viewType = (View)Activator.CreateInstance (type);
-                Assert.IsType (type, viewType);
-            }
-            else
-            {
-                viewType = (View)ctor.Invoke (pTypes.ToArray ());
-                Assert.IsType (type, viewType);
-            }
-        }
-
-        return viewType;
-    }
-
     [GeneratedRegex ("^\\s+", RegexOptions.Multiline)]
     [GeneratedRegex ("^\\s+", RegexOptions.Multiline)]
     private static partial Regex LeadingWhitespaceRegEx ();
     private static partial Regex LeadingWhitespaceRegEx ();
 
 
@@ -832,11 +670,11 @@ internal partial class TestHelpers
         string replaced = toReplace;
         string replaced = toReplace;
 
 
         replaced = Environment.NewLine.Length switch
         replaced = Environment.NewLine.Length switch
-        {
-            2 when !replaced.Contains ("\r\n") => replaced.Replace ("\n", Environment.NewLine),
-            1 => replaced.Replace ("\r\n", Environment.NewLine),
-            var _ => replaced
-        };
+                   {
+                       2 when !replaced.Contains ("\r\n") => replaced.Replace ("\n", Environment.NewLine),
+                       1 => replaced.Replace ("\r\n", Environment.NewLine),
+                       var _ => replaced
+                   };
 
 
         return replaced;
         return replaced;
     }
     }
@@ -863,6 +701,4 @@ public class TestsAllViews
 
 
         return Activator.CreateInstance (type) as View;
         return Activator.CreateInstance (type) as View;
     }
     }
-
 }
 }
-

+ 5 - 5
UnitTests/View/Adornment/BorderTests.cs

@@ -18,7 +18,7 @@ public class BorderTests (ITestOutputHelper output)
         view.Border.Thickness = new (0, 1, 0, 0);
         view.Border.Thickness = new (0, 1, 0, 0);
         view.Border.LineStyle = LineStyle.Single;
         view.Border.LineStyle = LineStyle.Single;
 
 
-        view.ColorScheme = new()
+        view.ColorScheme = new ()
         {
         {
             Normal = new (Color.Red, Color.Green),
             Normal = new (Color.Red, Color.Green),
             Focus = new (Color.Green, Color.Red)
             Focus = new (Color.Green, Color.Red)
@@ -53,7 +53,7 @@ public class BorderTests (ITestOutputHelper output)
         view.Border.Thickness = new (0, 1, 0, 0);
         view.Border.Thickness = new (0, 1, 0, 0);
         view.Border.LineStyle = LineStyle.Single;
         view.Border.LineStyle = LineStyle.Single;
 
 
-        view.ColorScheme = new()
+        view.ColorScheme = new ()
         {
         {
             Normal = new (Color.Red, Color.Green), Focus = new (Color.Green, Color.Red)
             Normal = new (Color.Red, Color.Green), Focus = new (Color.Green, Color.Red)
         };
         };
@@ -90,7 +90,7 @@ public class BorderTests (ITestOutputHelper output)
         {
         {
             Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double
             Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double
         };
         };
-        win.Border.Thickness.Top = 4;
+        win.Border.Thickness = win.Border.Thickness with { Top = 4 };
 
 
         RunState rs = Application.Begin (win);
         RunState rs = Application.Begin (win);
         var firstIteration = false;
         var firstIteration = false;
@@ -224,7 +224,7 @@ public class BorderTests (ITestOutputHelper output)
         {
         {
             Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double
             Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double
         };
         };
-        win.Border.Thickness.Top = 3;
+        win.Border.Thickness = win.Border.Thickness with { Top = 3 };
 
 
         RunState rs = Application.Begin (win);
         RunState rs = Application.Begin (win);
         var firstIteration = false;
         var firstIteration = false;
@@ -358,7 +358,7 @@ public class BorderTests (ITestOutputHelper output)
         {
         {
             Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double
             Title = "1234", Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Double
         };
         };
-        win.Border.Thickness.Top = 2;
+        win.Border.Thickness = win.Border.Thickness with { Top = 2 };
 
 
         RunState rs = Application.Begin (win);
         RunState rs = Application.Begin (win);
         var firstIteration = false;
         var firstIteration = false;