From a3b606fe6ea4aea0a3f17e62d3500135ee5e7bf5 Mon Sep 17 00:00:00 2001 From: Tig Date: Mon, 15 Jul 2024 16:36:05 -0600 Subject: [PATCH] New unit tests. Lots of fixes --- Terminal.Gui/Application/Application.cs | 12 +- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 2 +- Terminal.Gui/Text/TextFormatter.cs | 54 +-- Terminal.Gui/View/Layout/DimAuto.cs | 17 +- Terminal.Gui/View/Layout/PosCenter.cs | 3 +- Terminal.Gui/View/Layout/ViewLayout.cs | 4 +- Terminal.Gui/View/ViewText.cs | 14 +- Terminal.Gui/Views/Menu/ContextMenu.cs | 2 +- Terminal.Gui/Views/Menu/MenuBar.cs | 2 +- Terminal.Gui/Views/MessageBox.cs | 9 +- UICatalog/Scenarios/MessageBoxes.cs | 1 - UnitTests/View/DrawTests.cs | 10 +- UnitTests/View/Layout/Dim.AutoTests.cs | 336 ++++++++++++++----- UnitTests/View/Layout/Pos.CenterTests.cs | 27 +- UnitTests/View/Layout/Pos.PercentTests.cs | 14 + UnitTests/View/TextTests.cs | 51 +-- UnitTests/View/ViewTests.cs | 4 +- UnitTests/Views/LabelTests.cs | 2 +- UnitTests/Views/TextViewTests.cs | 2 +- 19 files changed, 367 insertions(+), 199 deletions(-) diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index 477553263..9833d19cd 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/Terminal.Gui/Application/Application.cs @@ -68,6 +68,14 @@ public static partial class Application .ToList (); } + /// + /// Gets the size of the screen. This is the size of the screen as reported by the . + /// + /// + /// If the has not been initialized, this will return a default size of 2048x2048; useful for unit tests. + /// + public static Rectangle Screen => Driver?.Screen ?? new (0, 0, 2048, 2048); + // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`. // This variable is set in `End` in this case so that `Begin` correctly sets `Top`. private static Toplevel _cachedRunStateToplevel; @@ -538,7 +546,7 @@ public static partial class Application MoveCurrent (Current); } - toplevel.SetRelativeLayout (Driver.Screen.Size); + toplevel.SetRelativeLayout (Screen.Size); toplevel.LayoutSubviews (); toplevel.PositionToplevels (); @@ -607,7 +615,7 @@ public static partial class Application // If the view is not visible within it's superview, don't position the cursor Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty }); - Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver.Screen; + Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Application.Screen; if (!superViewViewport.IntersectsWith (mostFocusedViewport)) { diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index 2d1a99db3..05cbb6217 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -20,7 +20,7 @@ public abstract class ConsoleDriver // QUESTION: When non-full screen apps are supported, will this represent the app size, or will that be in Application? /// Gets the location and size of the terminal screen. - public Rectangle Screen => new (0, 0, Cols, Rows); + internal Rectangle Screen => new (0, 0, Cols, Rows); private Rectangle _clip; diff --git a/Terminal.Gui/Text/TextFormatter.cs b/Terminal.Gui/Text/TextFormatter.cs index bee37de67..d54451139 100644 --- a/Terminal.Gui/Text/TextFormatter.cs +++ b/Terminal.Gui/Text/TextFormatter.cs @@ -54,12 +54,12 @@ public class TextFormatter internal Size GetAutoSize () { Size size = CalcRect (0, 0, Text, Direction, TabWidth).Size; + return size with { Width = size.Width - GetHotKeySpecifierLength (), Height = size.Height - GetHotKeySpecifierLength (false) }; - } /// /// Gets the width or height of the characters @@ -112,7 +112,7 @@ public class TextFormatter } } } - + /// /// Determines if the viewport width will be used or only the text width will be used, /// If all the viewport area will be filled with whitespaces and the same background color @@ -191,7 +191,7 @@ public class TextFormatter { if (AutoSize) { - _size = EnableNeedsFormat (GetAutoSize()); + _size = EnableNeedsFormat (GetAutoSize ()); } else { @@ -451,9 +451,9 @@ public class TextFormatter } else { - Debug.WriteLine ($"Unsupported Alignment: {nameof (VerticalAlignment)}"); + Debug.WriteLine ($"Unsupported Alignment: {nameof (VerticalAlignment)}"); - return; + return; } int colOffset = screen.X < 0 ? Math.Abs (screen.X) : 0; @@ -655,8 +655,20 @@ public class TextFormatter return Size.Empty; } - int width = GetLines ().Max (static line => line.GetColumns ()); - int height = GetLines ().Count; + List lines = GetLines (); + + if (lines.Count == 0) + { + return Size.Empty; + } + + int width = lines.Max (static line => line.GetColumns ()); + int height = lines.Count; + + if (IsVerticalDirection (Direction)) + { + return new (height, width); + } return new (width, height); } @@ -1666,13 +1678,13 @@ public class TextFormatter private static string PerformCorrectFormatDirection (TextDirection textDirection, string line) { return textDirection switch - { - TextDirection.RightLeft_BottomTop - or TextDirection.RightLeft_TopBottom - or TextDirection.BottomTop_LeftRight - or TextDirection.BottomTop_RightLeft => StringExtensions.ToString (line.EnumerateRunes ().Reverse ()), - _ => line - }; + { + TextDirection.RightLeft_BottomTop + or TextDirection.RightLeft_TopBottom + or TextDirection.BottomTop_LeftRight + or TextDirection.BottomTop_RightLeft => StringExtensions.ToString (line.EnumerateRunes ().Reverse ()), + _ => line + }; } private static List PerformCorrectFormatDirection (TextDirection textDirection, List runes) @@ -1683,13 +1695,13 @@ public class TextFormatter private static List PerformCorrectFormatDirection (TextDirection textDirection, List lines) { return textDirection switch - { - TextDirection.TopBottom_RightLeft - or TextDirection.LeftRight_BottomTop - or TextDirection.RightLeft_BottomTop - or TextDirection.BottomTop_RightLeft => lines.ToArray ().Reverse ().ToList (), - _ => lines - }; + { + TextDirection.TopBottom_RightLeft + or TextDirection.LeftRight_BottomTop + or TextDirection.RightLeft_BottomTop + or TextDirection.BottomTop_RightLeft => lines.ToArray ().Reverse ().ToList (), + _ => lines + }; } /// Returns the number of lines needed to render the specified text given the width. diff --git a/Terminal.Gui/View/Layout/DimAuto.cs b/Terminal.Gui/View/Layout/DimAuto.cs index 00952abb4..c8e236d04 100644 --- a/Terminal.Gui/View/Layout/DimAuto.cs +++ b/Terminal.Gui/View/Layout/DimAuto.cs @@ -63,19 +63,25 @@ public class DimAuto () : Dim var maxCalculatedSize = 0; int autoMin = MinimumContentDim?.GetAnchor (superviewContentSize) ?? 0; - int autoMax = MaximumContentDim?.GetAnchor (superviewContentSize) ?? (dimension == Dimension.Width ? Application.Driver.Screen.Width : Application.Driver.Screen.Height); + int screen = dimension == Dimension.Width ? Application.Screen.Width * 4 : Application.Screen.Height * 4; + int autoMax = MaximumContentDim?.GetAnchor (superviewContentSize) ?? screen; if (Style.FastHasFlags (DimAutoStyle.Text)) { if (dimension == Dimension.Width) { - //us.TextFormatter.Size = us.GetContentSize (); + us.TextFormatter.Size = new (autoMax, 2048); textSize = int.Max (autoMin, us.TextFormatter.FormatAndGetSize ().Width); + us.TextFormatter.Size = new Size (textSize, 2048); } else { - us.TextFormatter.Size = us.GetContentSize () with { Height = Application.Driver.Screen.Height }; + if (us.TextFormatter.Size.Width == 0) + { + us.TextFormatter.Size = us.TextFormatter.GetAutoSize (); + } textSize = int.Max (autoMin, us.TextFormatter.FormatAndGetSize ().Height); + us.TextFormatter.Size = us.TextFormatter.Size with { Height = textSize }; } } @@ -629,15 +635,16 @@ public class DimAuto () : Dim // ************** We now definitively know `us.ContentSize` *************** + int oppositeScreen = dimension == Dimension.Width ? Application.Screen.Height * 4 : Application.Screen.Width * 4 ; foreach (var v in us.Subviews) { if (dimension == Dimension.Width) { - v.SetRelativeLayout (new Size (max, Application.Driver.Screen.Width)); + v.SetRelativeLayout (new Size (max, oppositeScreen)); } else { - v.SetRelativeLayout (new Size (Application.Driver.Screen.Height, max)); + v.SetRelativeLayout (new Size (oppositeScreen, max)); } } diff --git a/Terminal.Gui/View/Layout/PosCenter.cs b/Terminal.Gui/View/Layout/PosCenter.cs index 04c7958bb..b8f7d895f 100644 --- a/Terminal.Gui/View/Layout/PosCenter.cs +++ b/Terminal.Gui/View/Layout/PosCenter.cs @@ -13,8 +13,9 @@ public class PosCenter : Pos internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension) { + // Protect against negative dimensions int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0); - return GetAnchor (superviewDimension - newDimension); + return superviewDimension / 2 - newDimension / 2; } } \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs index edb64a230..38463cbba 100644 --- a/Terminal.Gui/View/Layout/ViewLayout.cs +++ b/Terminal.Gui/View/Layout/ViewLayout.cs @@ -737,10 +737,10 @@ public partial class View // Determine our container's ContentSize - // First try SuperView.Viewport, then Application.Top, then Driver.Viewport. - // Finally, if none of those are valid, use int.MaxValue (for Unit tests). + // Finally, if none of those are valid, use 2048 (for Unit tests). Size superViewContentSize = SuperView is { IsInitialized: true } ? SuperView.GetContentSize () : Application.Top is { } && Application.Top != this && Application.Top.IsInitialized ? Application.Top.GetContentSize () : - Application.Driver?.Screen.Size ?? new (int.MaxValue, int.MaxValue); + Application.Screen.Size; SetTextFormatterSize (); diff --git a/Terminal.Gui/View/ViewText.cs b/Terminal.Gui/View/ViewText.cs index 6b9e0cf94..a995bc752 100644 --- a/Terminal.Gui/View/ViewText.cs +++ b/Terminal.Gui/View/ViewText.cs @@ -1,5 +1,7 @@ #nullable enable +using static Unix.Terminal.Curses; + namespace Terminal.Gui; public partial class View @@ -159,17 +161,6 @@ public partial class View } } - /// - /// Gets the dimensions required for ignoring a . - /// - /// - internal Size GetSizeNeededForTextWithoutHotKey () - { - return new Size ( - TextFormatter.Size.Width - TextFormatter.GetHotKeySpecifierLength (), - TextFormatter.Size.Height - TextFormatter.GetHotKeySpecifierLength (false)); - } - /// /// Internal API. Sets .Size to the current size, adjusted for /// . @@ -196,6 +187,7 @@ public partial class View if ((widthAuto is { } && widthAuto.Style.FastHasFlags (DimAutoStyle.Text)) || (heightAuto is { } && heightAuto.Style.FastHasFlags (DimAutoStyle.Text))) { + // BUGBUG: This ignores wordwrap and other formatting options. size = TextFormatter.GetAutoSize (); if (widthAuto is null || !widthAuto.Style.FastHasFlags (DimAutoStyle.Text)) diff --git a/Terminal.Gui/Views/Menu/ContextMenu.cs b/Terminal.Gui/Views/Menu/ContextMenu.cs index cc635de00..226af1f91 100644 --- a/Terminal.Gui/Views/Menu/ContextMenu.cs +++ b/Terminal.Gui/Views/Menu/ContextMenu.cs @@ -144,7 +144,7 @@ public sealed class ContextMenu : IDisposable _container = Application.Current; _container.Closing += Container_Closing; _container.Deactivate += Container_Deactivate; - Rectangle frame = Application.Driver.Screen; + Rectangle frame = Application.Screen; Point position = Position; if (Host is { }) diff --git a/Terminal.Gui/Views/Menu/MenuBar.cs b/Terminal.Gui/Views/Menu/MenuBar.cs index b08b263b5..00247a613 100644 --- a/Terminal.Gui/Views/Menu/MenuBar.cs +++ b/Terminal.Gui/Views/Menu/MenuBar.cs @@ -619,7 +619,7 @@ public class MenuBar : View, IDesignable return Point.Empty; } - Rectangle superViewFrame = SuperView is null ? Driver.Screen : SuperView.Frame; + Rectangle superViewFrame = SuperView is null ? Application.Screen : SuperView.Frame; View sv = SuperView is null ? Application.Current : SuperView; if (sv is null) diff --git a/Terminal.Gui/Views/MessageBox.cs b/Terminal.Gui/Views/MessageBox.cs index 68d78877a..f4150d5ab 100644 --- a/Terminal.Gui/Views/MessageBox.cs +++ b/Terminal.Gui/Views/MessageBox.cs @@ -391,16 +391,13 @@ public static class MessageBox { int buttonHeight = buttonList.Count > 0 ? buttonList [0].Frame.Height : 0; Debug.Assert (d.TextFormatter.WordWrap); - d.TextFormatter.Size = new Size (d.GetContentSize ().Width, Application.Driver.Screen.Height); + d.TextFormatter.Size = new Size (d.GetContentSize ().Width, Application.Screen.Height); Size textSize = d.TextFormatter.GetAutoSize (); textSize.Height += buttonHeight; if (textSize != d.TextFormatter.Size) { - //d.TextFormatter.Size = textSize; - //d.SetContentSize (textSize); d.SetNeedsLayout (); - //d.SetRelativeLayout (Application.Driver.Screen.Size); } } }; @@ -412,10 +409,6 @@ public static class MessageBox d.TextFormatter.WordWrap = wrapMessage; d.TextFormatter.MultiLine = !wrapMessage; - // Add two lines to push buttons down two rows - // BUGBUG: The " " are here due to a bug in TextFormater.Format that strips trailing newlines when .Wordwrap = true - // d.Text += Environment.NewLine + " " + Environment.NewLine + " "; - d.ColorScheme = new ColorScheme (d.ColorScheme) { Focus = d.ColorScheme.Normal diff --git a/UICatalog/Scenarios/MessageBoxes.cs b/UICatalog/Scenarios/MessageBoxes.cs index ad206de6d..1cbfc4fdd 100644 --- a/UICatalog/Scenarios/MessageBoxes.cs +++ b/UICatalog/Scenarios/MessageBoxes.cs @@ -47,7 +47,6 @@ public class MessageBoxes : Scenario { X = 0, Y = Pos.Bottom (label), - Width = Dim.Width (label), Height = 1, TextAlignment = Alignment.End, diff --git a/UnitTests/View/DrawTests.cs b/UnitTests/View/DrawTests.cs index 46c791ab4..272d78780 100644 --- a/UnitTests/View/DrawTests.cs +++ b/UnitTests/View/DrawTests.cs @@ -394,7 +394,7 @@ public class DrawTests (ITestOutputHelper _output) var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single }; view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Screen.Size); Assert.Equal (new (0, 0, 2, 2), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -419,7 +419,7 @@ public class DrawTests (ITestOutputHelper _output) view.Border.Thickness = new Thickness (1, 1, 1, 0); view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Screen.Size); Assert.Equal (new (0, 0, 2, 1), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -437,7 +437,7 @@ public class DrawTests (ITestOutputHelper _output) view.Border.Thickness = new Thickness (0, 1, 1, 1); view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Screen.Size); Assert.Equal (new (0, 0, 1, 2), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -462,7 +462,7 @@ public class DrawTests (ITestOutputHelper _output) view.Border.Thickness = new Thickness (1, 1, 0, 1); view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Screen.Size); Assert.Equal (new (0, 0, 1, 2), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); @@ -488,7 +488,7 @@ public class DrawTests (ITestOutputHelper _output) view.BeginInit (); view.EndInit (); - view.SetRelativeLayout (Application.Driver.Screen.Size); + view.SetRelativeLayout (Application.Screen.Size); Assert.Equal (new (0, 0, 2, 1), view.Frame); Assert.Equal (Rectangle.Empty, view.Viewport); diff --git a/UnitTests/View/Layout/Dim.AutoTests.cs b/UnitTests/View/Layout/Dim.AutoTests.cs index 6ad50ed16..e133b855c 100644 --- a/UnitTests/View/Layout/Dim.AutoTests.cs +++ b/UnitTests/View/Layout/Dim.AutoTests.cs @@ -976,8 +976,9 @@ public class DimAutoTests (ITestOutputHelper output) public void DimAutoStyle_Content_IgnoresSubviews_When_ContentSize_Is_Set () { var view = new View (); - var subview = new View () { - Frame = new Rectangle (50, 50, 1, 1) + var subview = new View () + { + Frame = new Rectangle (50, 50, 1, 1) }; view.SetContentSize (new (10, 5)); @@ -1045,27 +1046,34 @@ public class DimAutoTests (ITestOutputHelper output) [InlineData (1, 50, 51)] [InlineData (0, 25, 25)] [InlineData (-1, 50, 49)] - public void With_Subview_Using_DimFactor (int subViewOffset, int dimFactor, int expectedSize) + public void With_Subview_Using_DimPercent (int subViewOffset, int percent, int expectedSize) { - var view = new View () { Width = 100, Height = 100 }; + var view = new View () + { + Width = 100, Height = 100 + }; var subview = new View () { X = subViewOffset, Y = subViewOffset, - Width = Dim.Percent (dimFactor), - Height = Dim.Percent (dimFactor) + Width = Dim.Percent (percent), + Height = Dim.Percent (percent) }; view.Add (subview); - subview.SetRelativeLayout (new (100, 100)); + view.BeginInit (); + view.EndInit (); - var dim = Dim.Auto (DimAutoStyle.Content); + // Assuming the calculation is done after layout + int calculatedX = subview.X.Calculate (100, subview.Width, subview, Dimension.Width); + int calculatedY = subview.Y.Calculate (100, subview.Height, subview, Dimension.Height); + int calculatedWidth = subview.Width.Calculate (0, 100, view, Dimension.Width); + int calculatedHeight = subview.Height.Calculate (0, 100, view, Dimension.Height); - int calculatedWidth = dim.Calculate (0, 100, view, Dimension.Width); - int calculatedHeight = dim.Calculate (0, 100, view, Dimension.Height); - - Assert.Equal (expectedSize, calculatedWidth); - Assert.Equal (expectedSize, calculatedHeight); + Assert.Equal (20, calculatedWidth); // subview's width + Assert.Equal (10, calculatedHeight); // subview's height + Assert.Equal (50, calculatedX); // 50% of 100 (Width) + Assert.Equal (50, calculatedY); // 50% of 100 (Height) } [Theory] @@ -1090,7 +1098,7 @@ public class DimAutoTests (ITestOutputHelper output) }; view.Add (subview); //view.LayoutSubviews (); - view.SetRelativeLayout(new (200,200)); + view.SetRelativeLayout (new (200, 200)); Assert.Equal (expectedSize, view.Frame.Width); } @@ -1136,72 +1144,226 @@ public class DimAutoTests (ITestOutputHelper output) // Testing all Pos combinations - [Fact] - public void With_Subview_At_PosAt () + [Theory] + [InlineData (0, 0, 0, 0, 0, 0)] + [InlineData (0, 19, 0, 9, 19, 9)] + [InlineData (0, 20, 0, 10, 20, 10)] + [InlineData (0, 21, 0, 11, 21, 11)] + [InlineData (1, 21, 1, 11, 21, 11)] + [InlineData (100, 21, 100, 11, 21, 11)] + public void With_Subview_Using_PosAbsolute (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight) { - var view = new View (); - var subview = new View () { X = Pos.Absolute (10), Y = Pos.Absolute (5), Width = 20, Height = 10 }; - view.Add (subview); - - var dimWidth = Dim.Auto (); - var dimHeight = Dim.Auto (); - - int calculatedWidth = dimWidth.Calculate (0, 100, view, Dimension.Width); - int calculatedHeight = dimHeight.Calculate (0, 100, view, Dimension.Height); - - // Expecting the size to include the subview's position and size - Assert.Equal (30, calculatedWidth); // 10 (X position) + 20 (Width) - Assert.Equal (15, calculatedHeight); // 5 (Y position) + 10 (Height) - } - - [Fact (Skip = "TextOnly")] - public void With_Subview_At_PosPercent () - { - var view = new View () { Width = 100, Height = 100 }; - var subview = new View () { X = Pos.Percent (50), Y = Pos.Percent (50), Width = 20, Height = 10 }; - view.Add (subview); - - var dimWidth = Dim.Auto (); - var dimHeight = Dim.Auto (); - - // Assuming the calculation is done after layout - int calculatedWidth = dimWidth.Calculate (0, 100, view, Dimension.Width); - int calculatedHeight = dimHeight.Calculate (0, 100, view, Dimension.Height); - - // Expecting the size to include the subview's position as a percentage of the parent view's size plus the subview's size - Assert.Equal (70, calculatedWidth); // 50% of 100 (Width) + 20 - Assert.Equal (60, calculatedHeight); // 50% of 100 (Height) + 10 - } - - [Fact (Skip = "TextOnly")] - public void With_Subview_At_PosCenter () - { - var view = new View () { Width = 100, Height = 100 }; - var subview = new View () { X = Pos.Center (), Y = Pos.Center (), Width = 20, Height = 10 }; - view.Add (subview); - - var dimWidth = Dim.Auto (); - var dimHeight = Dim.Auto (); - - // Assuming the calculation is done after layout - int calculatedWidth = dimWidth.Calculate (0, 100, view, Dimension.Width); - int calculatedHeight = dimHeight.Calculate (0, 100, view, Dimension.Height); - - // Expecting the size to include the subview's position at the center of the parent view plus the subview's size - Assert.Equal (70, calculatedWidth); // Centered in 100 (Width) + 20 - Assert.Equal (60, calculatedHeight); // Centered in 100 (Height) + 10 - } - - [Fact] - public void With_Subview_At_PosAnchorEnd () - { - var dimWidth = Dim.Auto (); - var dimHeight = Dim.Auto (); - var view = new View () { - Width = dimWidth, - Height = dimHeight + Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth), + Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight) + }; + var subview = new View () + { + X = Pos.Absolute (10), + Y = Pos.Absolute (5), + Width = 20, + Height = 10 + }; + view.Add (subview); + + // Assuming the calculation is done after layout + int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width); + int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height); + int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width); + int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height); + + Assert.Equal (expectedWidth, calculatedWidth); + Assert.Equal (expectedHeight, calculatedHeight); + + Assert.Equal (0, calculatedX); + Assert.Equal (0, calculatedY); + } + + [Theory] + [InlineData (0, 0, 0, 0, 0, 0)] + [InlineData (0, 19, 0, 9, 19, 9)] + [InlineData (0, 20, 0, 10, 20, 10)] + [InlineData (0, 21, 0, 11, 20, 10)] + [InlineData (1, 21, 1, 11, 20, 10)] + [InlineData (100, 21, 100, 11, 21, 11)] + public void With_Subview_Using_PosPercent (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight) + { + var view = new View () + { + Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth), + Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight) + }; + var subview = new View () + { + X = Pos.Percent (50), + Y = Pos.Percent (50), + Width = 20, + Height = 10 + }; + view.Add (subview); + + // Assuming the calculation is done after layout + int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width); + int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height); + int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width); + int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height); + + Assert.Equal (expectedWidth, calculatedWidth); + Assert.Equal (expectedHeight, calculatedHeight); + + Assert.Equal (0, calculatedX); + Assert.Equal (0, calculatedY); + + view.BeginInit (); + view.EndInit (); + // subview should be at 50% in the parent view + Assert.Equal ((int)(view.Viewport.Width * .50), subview.Frame.X); + Assert.Equal ((int)(view.Viewport.Height * .50), subview.Frame.Y); + } + + [Theory] + [InlineData (0, 0, 0, 0, 0, 0)] + [InlineData (0, 19, 0, 9, 19, 9)] + [InlineData (0, 20, 0, 10, 20, 10)] + [InlineData (0, 21, 0, 11, 21, 11)] + [InlineData (1, 21, 1, 11, 21, 11)] + [InlineData (100, 21, 100, 11, 21, 11)] + public void With_Subview_Using_PosPercent_Combine (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight) + { + var view = new View () + { + Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth), + Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight) + }; + var subview = new View () + { + X = Pos.Percent (50) + 1, + Y = 1 + Pos.Percent (50), + Width = 20, + Height = 10 + }; + view.Add (subview); + + // Assuming the calculation is done after layout + int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width); + int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height); + int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width); + int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height); + + Assert.Equal (expectedWidth, calculatedWidth); + Assert.Equal (expectedHeight, calculatedHeight); + + Assert.Equal (0, calculatedX); + Assert.Equal (0, calculatedY); + + view.BeginInit (); + view.EndInit (); + // subview should be at 50% in the parent view + Assert.Equal ((int)(view.Viewport.Width * .50) + 1, subview.Frame.X); + Assert.Equal ((int)(view.Viewport.Height * .50) + 1, subview.Frame.Y); + } + + [Theory] + [InlineData (0, 0, 0, 0, 0, 0)] + [InlineData (0, 19, 0, 9, 19, 9)] + [InlineData (0, 20, 0, 10, 20, 10)] + [InlineData (0, 21, 0, 11, 21, 11)] + [InlineData (1, 21, 1, 11, 21, 11)] + [InlineData (100, 21, 100, 11, 21, 11)] + public void With_Subview_Using_PosCenter (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight) + { + var view = new View () + { + Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth), + Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight) + }; + var subview = new View () + { + X = Pos.Center (), + Y = Pos.Center (), + Width = 20, + Height = 10 + }; + view.Add (subview); + + // Assuming the calculation is done after layout + int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width); + int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height); + int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width); + int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height); + + Assert.Equal (expectedWidth, calculatedWidth); + Assert.Equal (expectedHeight, calculatedHeight); + + Assert.Equal (0, calculatedX); + Assert.Equal (0, calculatedY); + + view.BeginInit (); + view.EndInit (); + // subview should be centered in the parent view + 1 + Assert.Equal (view.Viewport.Width / 2 - subview.Frame.Width / 2, subview.Frame.X); + Assert.Equal (view.Viewport.Height / 2 - subview.Frame.Height / 2, subview.Frame.Y); + } + + [Theory] + [InlineData (0, 0, 0, 0, 0, 0)] + [InlineData (0, 19, 0, 9, 19, 9)] + [InlineData (0, 18, 0, 8, 18, 8)] + [InlineData (0, 20, 0, 10, 20, 10)] + [InlineData (0, 21, 0, 11, 21, 11)] + [InlineData (1, 21, 1, 11, 21, 11)] + [InlineData (100, 21, 100, 11, 21, 11)] + public void With_Subview_Using_PosCenter_Combine (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight) + { + var view = new View () + { + Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth), + Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight) + }; + + var subview = new View () + { + X = Pos.Center () + 1, + Y = 1 + Pos.Center (), + Width = 20, + Height = 10 + }; + view.Add (subview); + + // Assuming the calculation is done after layout + int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width); + int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height); + int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width); + int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height); + + Assert.Equal (expectedWidth, calculatedWidth); + Assert.Equal (expectedHeight, calculatedHeight); + + Assert.Equal (0, calculatedX); + Assert.Equal (0, calculatedY); + + view.BeginInit (); + view.EndInit (); + // subview should be centered in the parent view + 1 + Assert.Equal (view.Viewport.Width / 2 - subview.Frame.Width / 2 + 1, subview.Frame.X); + Assert.Equal (view.Viewport.Height / 2 - subview.Frame.Height / 2 + 1, subview.Frame.Y); + } + + [Theory] + [InlineData (0, 0, 0, 0, 0, 0)] + [InlineData (0, 19, 0, 9, 19, 9)] + [InlineData (0, 18, 0, 8, 18, 8)] + [InlineData (0, 20, 0, 10, 20, 10)] + [InlineData (0, 21, 0, 11, 20, 10)] + [InlineData (1, 21, 1, 11, 20, 10)] + [InlineData (100, 21, 100, 11, 21, 11)] + public void With_Subview_Using_PosAnchorEnd (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight) + { + var view = new View () + { + Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth), + Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight) }; var subview = new View () @@ -1214,12 +1376,22 @@ public class DimAutoTests (ITestOutputHelper output) view.Add (subview); // Assuming the calculation is done after layout - int calculatedWidth = dimWidth.Calculate (0, 100, view, Dimension.Width); - int calculatedHeight = dimHeight.Calculate (0, 100, view, Dimension.Height); + int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width); + int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height); + int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width); + int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height); - // Expecting the size to include the subview's position at the end of the parent view minus the offset plus the subview's size - Assert.Equal (20, calculatedWidth); - Assert.Equal (10, calculatedHeight); + Assert.Equal (expectedWidth, calculatedWidth); + Assert.Equal (expectedHeight, calculatedHeight); + + Assert.Equal (0, calculatedX); + Assert.Equal (0, calculatedY); + + view.BeginInit (); + view.EndInit (); + // subview should be at the end of the view + Assert.Equal (view.Viewport.Width - subview.Frame.Width, subview.Frame.X); + Assert.Equal (view.Viewport.Height - subview.Frame.Height, subview.Frame.Y); } [Fact] diff --git a/UnitTests/View/Layout/Pos.CenterTests.cs b/UnitTests/View/Layout/Pos.CenterTests.cs index a17b1132a..d231df822 100644 --- a/UnitTests/View/Layout/Pos.CenterTests.cs +++ b/UnitTests/View/Layout/Pos.CenterTests.cs @@ -51,12 +51,31 @@ public class PosCenterTests (ITestOutputHelper output) Assert.IsType (pos); } - [Fact] - public void PosCenter_Calculate_ReturnsExpectedValue () + [Theory] + [InlineData (10, 2, 4)] + [InlineData (10, 10, 0)] + [InlineData (10, 11, 0)] + [InlineData (10, 12, -1)] + [InlineData (19, 20, -1)] + public void PosCenter_Calculate_ReturnsExpectedValue (int superviewDimension, int width, int expectedX) { var posCenter = new PosCenter (); - int result = posCenter.Calculate (10, new DimAbsolute (2), null, Dimension.None); - Assert.Equal (4, result); + int result = posCenter.Calculate (superviewDimension, new DimAbsolute (width), null!, Dimension.Width); + Assert.Equal (expectedX, result); + } + + + [Fact] + public void PosCenter_Bigger_Than_SuperView () + { + var superView = new View { Width = 10, Height = 10 }; + var view = new View { X = Center (), Y = Center (), Width = 20, Height = 20 }; + superView.Add (view); + superView.BeginInit(); + superView.EndInit(); + + Assert.Equal (-5, view.Frame.Left); + Assert.Equal (-5, view.Frame.Top); } [Theory] diff --git a/UnitTests/View/Layout/Pos.PercentTests.cs b/UnitTests/View/Layout/Pos.PercentTests.cs index 1614c46ce..d016c709c 100644 --- a/UnitTests/View/Layout/Pos.PercentTests.cs +++ b/UnitTests/View/Layout/Pos.PercentTests.cs @@ -7,6 +7,20 @@ public class PosPercentTests (ITestOutputHelper output) { private readonly ITestOutputHelper _output = output; + [Theory] + [InlineData (50, 10, 2, 5)] + [InlineData (50, 10, 10, 5)] + [InlineData (50, 10, 11, 5)] + [InlineData (50, 10, 12, 5)] + [InlineData (50, 19, 20, 9)] + public void PosPercent_Calculate_ReturnsExpectedValue (int percent, int superviewDimension, int width, int expectedX) + { + var posPercent = new PosPercent (percent); + int result = posPercent.Calculate (superviewDimension, new DimAbsolute (width), null!, Dimension.Width); + Assert.Equal (expectedX, result); + } + + // TODO: This actually a SetRelativeLayout/LayoutSubViews test and should be moved // TODO: A new test that calls SetRelativeLayout directly is needed. [Theory] diff --git a/UnitTests/View/TextTests.cs b/UnitTests/View/TextTests.cs index 3bd6cfb23..278ca3ed0 100644 --- a/UnitTests/View/TextTests.cs +++ b/UnitTests/View/TextTests.cs @@ -778,56 +778,7 @@ Y Application.End (rs); top.Dispose (); } - - [Fact] - [AutoInitShutdown] - public void GetTextFormatterBoundsSize_GetSizeNeededForText_HotKeySpecifier () - { - var text = "Say Hello 你"; - - // Frame: 0, 0, 12, 1 - var horizontalView = new View - { - Width = Dim.Auto (), Height = Dim.Auto () - }; - horizontalView.TextFormatter.HotKeySpecifier = (Rune)'_'; - horizontalView.Text = text; - - // Frame: 0, 0, 1, 12 - var verticalView = new View - { - Width = Dim.Auto (), Height = Dim.Auto (), TextDirection = TextDirection.TopBottom_LeftRight - }; - verticalView.Text = text; - verticalView.TextFormatter.HotKeySpecifier = (Rune)'_'; - - var top = new Toplevel (); - top.Add (horizontalView, verticalView); - Application.Begin (top); - ((FakeDriver)Application.Driver).SetBufferSize (50, 50); - - Assert.Equal (new (0, 0, 12, 1), horizontalView.Frame); - Assert.Equal (new (12, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ()); - Assert.Equal (horizontalView.Frame.Size, horizontalView.GetSizeNeededForTextWithoutHotKey ()); - - Assert.Equal (new (0, 0, 2, 11), verticalView.Frame); - Assert.Equal (new (2, 11), verticalView.GetSizeNeededForTextWithoutHotKey ()); - Assert.Equal (verticalView.Frame.Size, verticalView.GetSizeNeededForTextWithoutHotKey ()); - - text = "012345678你"; - horizontalView.Text = text; - verticalView.Text = text; - - Assert.Equal (new (0, 0, 11, 1), horizontalView.Frame); - Assert.Equal (new (11, 1), horizontalView.GetSizeNeededForTextWithoutHotKey ()); - Assert.Equal (horizontalView.Frame.Size, horizontalView.GetSizeNeededForTextWithoutHotKey ()); - - Assert.Equal (new (0, 0, 2, 10), verticalView.Frame); - Assert.Equal (new (2, 10), verticalView.GetSizeNeededForTextWithoutHotKey ()); - Assert.Equal (verticalView.Frame.Size, verticalView.GetSizeNeededForTextWithoutHotKey ()); - top.Dispose (); - } - + [Theory] [AutoInitShutdown] [InlineData (true)] diff --git a/UnitTests/View/ViewTests.cs b/UnitTests/View/ViewTests.cs index 4044507f1..cc030733e 100644 --- a/UnitTests/View/ViewTests.cs +++ b/UnitTests/View/ViewTests.cs @@ -833,10 +833,10 @@ At 0,0 TextDirection = TextDirection.TopBottom_LeftRight, Width = Dim.Auto (), Height = Dim.Auto () - }; // BUGBUG: AutoSize or Height need be set + }; + r.TextFormatter.WordWrap = false; Assert.NotNull (r); - // BUGBUG: IsInitialized must be true to process calculation r.BeginInit (); r.EndInit (); Assert.False (r.CanFocus); diff --git a/UnitTests/Views/LabelTests.cs b/UnitTests/Views/LabelTests.cs index 24a19c77d..baeab4aa9 100644 --- a/UnitTests/Views/LabelTests.cs +++ b/UnitTests/Views/LabelTests.cs @@ -473,7 +473,7 @@ e var label = new Label { BorderStyle = LineStyle.Single, Text = "Test" }; label.BeginInit (); label.EndInit (); - label.SetRelativeLayout (Application.Driver.Screen.Size); + label.SetRelativeLayout (Application.Screen.Size); Assert.Equal (new (0, 0, 4, 1), label.Viewport); Assert.Equal (new (0, 0, 6, 3), label.Frame); diff --git a/UnitTests/Views/TextViewTests.cs b/UnitTests/Views/TextViewTests.cs index f260dd162..da7720eba 100644 --- a/UnitTests/Views/TextViewTests.cs +++ b/UnitTests/Views/TextViewTests.cs @@ -6900,7 +6900,7 @@ This is the second line. ); ((FakeDriver)Application.Driver).SetBufferSize (6, 25); - tv.SetRelativeLayout (Application.Driver.Screen.Size); + tv.SetRelativeLayout (Application.Screen.Size); tv.Draw (); Assert.Equal (new Point (4, 2), tv.CursorPosition); Assert.Equal (new Point (12, 0), cp);