diff --git a/src/MenuTracker.cs b/src/MenuTracker.cs index ffe7d670..109c3b07 100644 --- a/src/MenuTracker.cs +++ b/src/MenuTracker.cs @@ -47,6 +47,22 @@ public void Register(MenuBar mb) this.bars.Add(mb); } + /// + /// Unregisters listeners for . + /// + /// to stop tracking. + public void UnregisterMenuBar( MenuBar? mb ) + { + if ( !bars.TryTake( out mb ) ) + { + return; + } + + mb.MenuAllClosed -= MenuAllClosed; + mb.MenuOpened -= MenuOpened; + mb.MenuClosing -= MenuClosing; + } + /// /// /// Searches child items of all MenuBars tracked by this class @@ -63,7 +79,7 @@ public void Register(MenuBar mb) /// The immediate parent of . /// Result may be a top level menu (e.g. File, View) /// or a sub-menu parent (e.g. View=>Windows). - public MenuBarItem? GetParent( MenuItem item, out MenuBar? hostBar ) + private MenuBarItem? GetParent( MenuItem item, out MenuBar? hostBar ) { foreach (var bar in this.bars) { @@ -83,7 +99,23 @@ public void Register(MenuBar mb) return null; } - public bool TryGetParent(MenuItem item, [NotNullWhen(true)]out MenuBar? hostBar, [NotNullWhen(true)] out MenuBarItem? parentItem) + /// + /// Searches child items of all MenuBars tracked by this class to try and find the parent of the item passed. + /// + /// The item whose parent you want to find. + /// + /// When this method returns true, the that owns .
Otherwise, if + /// not found or parent not registered (see ). + /// + /// + /// When this method returns , the immediate parent of .
Otherwise, + /// + /// + /// + /// Search is recursive and dips into sub-menus.
For sub-menus it is the immediate parent that is returned. + ///
+ /// A indicating if the search was successful or not. + public bool TryGetParent( MenuItem item, [NotNullWhen( true )] out MenuBar? hostBar, [NotNullWhen( true )] out MenuBarItem? parentItem ) { var parentCandidate = GetParent( item, out hostBar ); if ( parentCandidate is null ) @@ -106,22 +138,21 @@ public bool TryGetParent(MenuItem item, [NotNullWhen(true)]out MenuBar? hostBar, /// the substitution object (). See /// /// for more information. - public Dictionary ConvertEmptyMenus() + public Dictionary ConvertEmptyMenus( ) { - var toReturn = new Dictionary(); - + Dictionary dictionary = []; foreach (var b in this.bars) { foreach (var bi in b.Menus) { - foreach (var converted in this.ConvertEmptyMenus(b, bi)) + foreach ( ( MenuBarItem? convertedMenuBarItem, MenuItem? convertedMenuItem ) in this.ConvertEmptyMenus( dictionary, b, bi ) ) { - toReturn.Add(converted.Key, converted.Value); + dictionary.TryAdd( convertedMenuBarItem, convertedMenuItem ); } } } - return toReturn; + return dictionary; } /// @@ -137,12 +168,12 @@ public Dictionary ConvertEmptyMenus() /// The result of the conversion (same text, same index etc but /// instead of ). /// if conversion was possible (menu was empty and belonged to tracked menu). - internal static bool ConvertMenuBarItemToRegularItemIfEmpty(MenuBarItem bar, out MenuItem? added) + internal static bool ConvertMenuBarItemToRegularItemIfEmpty( MenuBarItem bar, [NotNullWhen( true )] out MenuItem? added ) { added = null; // bar still has more children so don't convert - if (bar.Children.Any()) + if ( bar.Children.Length != 0 ) { return false; } @@ -152,8 +183,7 @@ internal static bool ConvertMenuBarItemToRegularItemIfEmpty(MenuBarItem bar, out return false; } - var children = parent.Children.ToList(); - var idx = children.IndexOf(bar); + int idx = Array.IndexOf( parent.Children, bar ); if (idx < 0) { @@ -161,39 +191,32 @@ internal static bool ConvertMenuBarItemToRegularItemIfEmpty(MenuBarItem bar, out } // bar has no children so convert to MenuItem - added = new MenuItem { Title = bar.Title }; - added.Data = bar.Data; - added.Shortcut = bar.Shortcut; - - children.RemoveAt(idx); - children.Insert(idx, added); - - parent.Children = children.ToArray(); + parent.Children[ idx ] = added = new( ) + { + Title = bar.Title, + Data = bar.Data, + Shortcut = bar.Shortcut + }; return true; } /// - private Dictionary ConvertEmptyMenus(MenuBar bar, MenuBarItem mbi) + private Dictionary ConvertEmptyMenus(Dictionary dictionary, MenuBar bar, MenuBarItem mbi) { - var toReturn = new Dictionary(); - foreach (var c in mbi.Children.OfType()) { - this.ConvertEmptyMenus(bar, c); - if ( ConvertMenuBarItemToRegularItemIfEmpty( c, out var added)) + this.ConvertEmptyMenus(dictionary,bar, c); + if ( ConvertMenuBarItemToRegularItemIfEmpty( c, out MenuItem? added)) { - if (added != null) - { - toReturn.Add(c, added); - } + dictionary.TryAdd( c, added ); bar.CloseMenu(); bar.OpenMenu(); } } - return toReturn; + return dictionary; } private void MenuClosing(object? sender, MenuClosingEventArgs obj) @@ -204,7 +227,7 @@ private void MenuClosing(object? sender, MenuClosingEventArgs obj) private void MenuOpened(object? sender, MenuOpenedEventArgs obj) { this.CurrentlyOpenMenuItem = obj.MenuItem; - this.ConvertEmptyMenus(); + this.ConvertEmptyMenus( ); } private void MenuAllClosed(object? sender, EventArgs e) diff --git a/src/Operations/MenuOperations/RemoveMenuItemOperation.cs b/src/Operations/MenuOperations/RemoveMenuItemOperation.cs index 9bc1304c..35d696b2 100644 --- a/src/Operations/MenuOperations/RemoveMenuItemOperation.cs +++ b/src/Operations/MenuOperations/RemoveMenuItemOperation.cs @@ -64,10 +64,12 @@ public override void Undo() return; } - var children = this.Parent.Children.ToList(); - - children.Insert(this.removedAtIdx, this.OperateOn); - this.Parent.Children = children.ToArray(); + this.Parent.Children = + [ + .. Parent.Children[ .. removedAtIdx ], + this.OperateOn, + .. Parent.Children[ removedAtIdx .. ] + ]; this.Bar?.SetNeedsDisplay(); // if any MenuBarItem were converted to vanilla MenuItem @@ -123,12 +125,12 @@ protected override bool DoImpl() return false; } - var children = this.Parent.Children.ToList(); - - this.removedAtIdx = Math.Max(0, children.IndexOf(this.OperateOn)); - - children.Remove(this.OperateOn); - this.Parent.Children = children.ToArray(); + this.removedAtIdx = Math.Max( 0, Array.IndexOf( Parent.Children, OperateOn ) ); + this.Parent.Children = + [ + .. Parent.Children[ ..removedAtIdx ], + .. Parent.Children[ ( removedAtIdx + 1 ).. ] + ]; this.Bar?.SetNeedsDisplay(); if (this.Bar != null) @@ -137,27 +139,24 @@ protected override bool DoImpl() } // if a top level menu now has no children - if (this.Bar != null) + var empty = this.Bar?.Menus.Where(bi => bi.Children.Length == 0).ToArray(); + if (empty?.Any() == true) { - var empty = this.Bar.Menus.Where(bi => bi.Children.Length == 0).ToArray(); - if (empty.Any()) - { - // remember where they were - this.prunedEmptyTopLevelMenus = empty.ToDictionary(e => Array.IndexOf(this.Bar.Menus, e), v => v); + // remember where they were + this.prunedEmptyTopLevelMenus = empty.ToDictionary(e => Array.IndexOf(this.Bar.Menus, e), v => v); - // and remove them - this.Bar.Menus = this.Bar.Menus.Except(this.prunedEmptyTopLevelMenus.Values).ToArray(); - } + // and remove them + this.Bar.Menus = this.Bar.Menus.Except(this.prunedEmptyTopLevelMenus.Values).ToArray(); + } - // if we just removed the last menu header - // leaving a completely blank menu bar - if (this.Bar.Menus.Length == 0 && this.Bar.SuperView != null) - { - // remove the bar completely - this.Bar.CloseMenu(); - this.barRemovedFrom = this.Bar.SuperView; - this.barRemovedFrom.Remove(this.Bar); - } + // if we just removed the last menu header + // leaving a completely blank menu bar + if (this.Bar?.Menus.Length == 0 && this.Bar.SuperView != null) + { + // remove the bar completely + this.Bar.CloseMenu(); + this.barRemovedFrom = this.Bar.SuperView; + this.barRemovedFrom.Remove(this.Bar); } return true; diff --git a/src/TerminalGuiDesigner.csproj b/src/TerminalGuiDesigner.csproj index dc993dbb..09c80a37 100644 --- a/src/TerminalGuiDesigner.csproj +++ b/src/TerminalGuiDesigner.csproj @@ -1,4 +1,4 @@ - + True @@ -145,8 +145,8 @@ - + diff --git a/src/TerminalGuiDesigner.sln.DotSettings b/src/TerminalGuiDesigner.sln.DotSettings new file mode 100644 index 00000000..98557a3a --- /dev/null +++ b/src/TerminalGuiDesigner.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/src/ViewFactory.cs b/src/ViewFactory.cs index 2ed8d221..3d1898c2 100644 --- a/src/ViewFactory.cs +++ b/src/ViewFactory.cs @@ -28,7 +28,7 @@ public static class ViewFactory internal const string DefaultMenuItemText = "Edit Me"; internal static readonly Type[] KnownUnsupportedTypes = - { + [ typeof( Toplevel ), typeof( Dialog ), typeof( FileDialog ), @@ -41,7 +41,7 @@ public static class ViewFactory // BUG These seem to cause stack overflows in CreateSubControlDesigns (see TestAddView_RoundTrip) typeof( Wizard ), typeof( WizardStep ) - }; + ]; /// /// Gets a new instance of a default [], to include as the default initial @@ -56,12 +56,11 @@ internal static MenuBarItem[] DefaultMenuBarItems { get { - return new[] - { - new MenuBarItem( - "_File (F9)", - new[] { new MenuItem( DefaultMenuItemText, string.Empty, ( ) => { } ) } ) - }; + return + [ + new( "_File (F9)", + [ new MenuItem( DefaultMenuItemText, string.Empty, static ( ) => { } ) ] ) + ]; } } diff --git a/tests/ListViewTests.cs b/tests/ListViewTests.cs index 961450f8..4d42721a 100644 --- a/tests/ListViewTests.cs +++ b/tests/ListViewTests.cs @@ -78,7 +78,7 @@ public void TestIListSourceProperty_Rhs( ) Assert.That( lv.Source, Has.Count.EqualTo( 2 ) ); - var code = PropertyTests.ExpressionToCode( prop.GetRhs( ) ); + var code = Helpers.ExpressionToCode( prop.GetRhs( ) ); Assert.That( code, Is.EqualTo( "new Terminal.Gui.ListWrapper(new string[] {\n \"hi there\",\n \"my friend\"})".Replace( "\n", Environment.NewLine ) ) ); diff --git a/tests/MenuBarTests.cs b/tests/MenuBarTests.cs index a2a2e467..6eea6ee3 100644 --- a/tests/MenuBarTests.cs +++ b/tests/MenuBarTests.cs @@ -3,10 +3,394 @@ namespace UnitTests; [TestFixture] -[TestOf(typeof(OperationManager))] -[Category("UI")] +[TestOf( typeof( OperationManager ) )] +[Category( "UI" )] internal class MenuBarTests : Tests { + [Test] + [TestOf( typeof( RemoveMenuItemOperation ) )] + public void DeletingLastMenuItem_ShouldRemoveWholeBar( ) + { + using MenuBar bar = GetMenuBar( out Design root ); + + MenuItem mi = bar.Menus[ 0 ].Children[ 0 ]; + + RemoveMenuItemOperation? removeMenuItemOperation = null; + Assert.That( ( ) => removeMenuItemOperation = new( mi ), Throws.Nothing ); + Assert.That( removeMenuItemOperation, Is.Not.Null.And.InstanceOf( ) ); + + bool removeMenuItemOperationSucceeded = false; + Assert.That( ( ) => removeMenuItemOperationSucceeded = OperationManager.Instance.Do( removeMenuItemOperation! ), Throws.Nothing ); + Assert.That( removeMenuItemOperationSucceeded ); + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.UndoStackSize, Is.EqualTo( 1 ) ); + Assert.That( OperationManager.Instance.RedoStackSize, Is.Zero ); + } ); + + Assert.Multiple( ( ) => + { + Assert.That( bar.Menus, Is.Empty ); + Assert.That( root.View.Subviews, Has.None.InstanceOf( ) ); + } ); + + Assert.That( OperationManager.Instance.Undo, Throws.Nothing ); + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.UndoStackSize, Is.Zero ); + Assert.That( OperationManager.Instance.RedoStackSize, Is.EqualTo( 1 ) ); + // TODO: This needs to clean up after itself in a safe fashion + } ); + + // Same conditions as at the start + // The MenuBar should be back in the root view... + Assert.That( root.View.Subviews, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( root.View.Subviews[ 0 ], Is.Not.Null.And.SameAs( bar ) ); + + // ...And the original MenuBar should be back as it was at the start. + Assert.That( bar.Menus, Is.Not.Null ); + Assert.That( bar.Menus, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( bar.Menus[ 0 ], Is.Not.Null.And.InstanceOf( ) ); + Assert.That( bar.Menus[ 0 ].Children, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( bar.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.InstanceOf( ) ); + } + + [Test] + [TestOf( typeof( RemoveMenuItemOperation ) )] + public void DeletingMenuItemFromSubmenu_AllSubmenuChild( ) + { + using MenuBarWithSubmenuItems m = GetMenuBarWithSubmenuItems( ); + + MenuItem? bottomChild = m.Head2.Children[ 1 ]; + + Assume.That( m.Bar.Menus[ 0 ].Children, Has.Exactly( 3 ).InstanceOf( ) ); + Assume.That( m.Bar.Menus[ 0 ].Children[ 1 ], Is.Not.Null.And.InstanceOf( ) ); + Assume.That( m.Head2.Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assume.That( m.Head2.Children[ 0 ], Is.SameAs( m.TopChild ) ); + + RemoveMenuItemOperation cmd1 = new( m.TopChild ); + Assert.That( cmd1.Do, Throws.Nothing ); + + RemoveMenuItemOperation cmd2 = new( bottomChild ); + Assert.That( cmd2.Do, Throws.Nothing ); + + // Deleting both children should convert us from + // a dropdown submenu to just a regular MenuItem + Assert.That( m.Bar.Menus[ 0 ].Children, Has.Exactly( 3 ).InstanceOf( ) ); + Assert.That( m.Bar.Menus[ 0 ].Children[ 1 ], Is.Not.Null.And.InstanceOf( ) ); + + Assert.That( cmd2.Undo, Throws.Nothing ); + + // should bring the bottom one back + Assert.That( m.Bar.Menus[ 0 ].Children, Has.Exactly( 3 ).InstanceOf( ) ); + Assert.That( m.Bar.Menus[ 0 ].Children[ 1 ], Is.Not.Null.And.InstanceOf( ) ); + Assert.That( ( (MenuBarItem)m.Bar.Menus[ 0 ].Children[ 1 ] ).Children[ 0 ], Is.SameAs( bottomChild ) ); + + Assert.That( cmd1.Undo, Throws.Nothing ); + + // Both submenu items should now be back + Assert.That( m.Bar.Menus[ 0 ].Children, Has.Exactly( 3 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( m.Bar.Menus[ 0 ].Children[ 1 ], Is.Not.Null.And.InstanceOf( ) ); + Assert.That( m.Head2.Children, Has.Exactly( 2 ).InstanceOf( ) ); + } ); + Assert.Multiple( ( ) => + { + Assert.That( m.Head2.Children[ 0 ], Is.SameAs( m.TopChild ) ); + Assert.That( ( (MenuBarItem)m.Bar.Menus[ 0 ].Children[ 1 ] ).Children[ 0 ], Is.SameAs( m.TopChild ) ); + Assert.That( ( (MenuBarItem)m.Bar.Menus[ 0 ].Children[ 1 ] ).Children[ 1 ], Is.SameAs( bottomChild ) ); + } ); + } + + [Test] + [TestOf( typeof( RemoveMenuItemOperation ) )] + public void DeletingMenuItemFromSubmenu_TopChild( ) + { + using MenuBarWithSubmenuItems m = GetMenuBarWithSubmenuItems( ); + + RemoveMenuItemOperation cmd = new ( m.TopChild ); + bool cmdSucceeded = false; + Assert.That( ( ) => cmdSucceeded = cmd.Do( ), Throws.Nothing ); + Assert.That( cmdSucceeded ); + + // Delete the top child should leave only 1 in submenu + Assert.Multiple( ( ) => + { + Assert.That( m.Bar.Menus[ 0 ].Children, Has.Exactly( 3 ).InstanceOf( ) ); + Assert.That( m.Head2.Children, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( m.Head2.Children[ 0 ], Is.Not.SameAs( m.TopChild ) ); + } ); + + Assert.That( cmd.Undo, Throws.Nothing ); + + Assert.Multiple( ( ) => + { + // should come back now + Assert.That( m.Bar.Menus[ 0 ].Children, Has.Exactly( 3 ).InstanceOf( ) ); + Assert.That( m.Head2.Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.That( m.Head2.Children[ 0 ], Is.SameAs( m.TopChild ) ); + } ); + } + + [Test] + [TestOf( typeof( MenuBarTests ) )] + [Category( "Change Control" )] + [Order( 1 )] + [Repeat( 10 )] + [Description( "Ensures that the GetMenuBar helper method returns the expected objects and doesn't fail even if used multiple times." )] + public void GetMenuBar_BehavesAsExpected( ) + { + using MenuBar bar = GetMenuBar( out Design root ); + Assert.Multiple( ( ) => + { + Assert.That( bar, Is.Not.Null.And.InstanceOf( ) ); + Assert.That( root, Is.Not.Null.And.InstanceOf( ) ); + } ); + Assert.That( root.View.Subviews, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( root.View.Subviews[ 0 ], Is.Not.Null.And.SameAs( bar ) ); + Assert.That( bar.Menus, Is.Not.Null ); + } ); + Assert.That( bar.Menus, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( bar.Menus[ 0 ], Is.Not.Null.And.InstanceOf( ) ); + Assert.That( bar.Menus[ 0 ].Children, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( bar.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.InstanceOf( ) ); + Assert.That( OperationManager.Instance.UndoStackSize, Is.Zero ); + Assert.That( OperationManager.Instance.RedoStackSize, Is.Zero ); + } ); + } + + [Test] + [TestOf( typeof( MenuBarWithSubmenuItems ) )] + [Category( "Change Control" )] + [Order( 2 )] + [Repeat( 10 )] + [Description( "Ensures that the GetMenuBarWithSubmenuItems helper method returns the expected objects and doesn't fail even if used multiple times." )] + public void GetMenuBarWithSubmenuItems_BehavesAsExpected( ) + { + using MenuBarWithSubmenuItems m = GetMenuBarWithSubmenuItems( ); + + Assert.That( m.Bar.Menus, Has.Exactly( 1 ).InstanceOf( ) ); + + MenuBarItem menu0 = m.Bar.Menus[ 0 ]; + Assert.That( menu0.Children, Has.Exactly( 3 ).InstanceOf( ) ); + + // First item + MenuItem menu0Child0 = menu0.Children[ 0 ]; + Assert.That( menu0Child0.Title, Is.EqualTo( "Head1" ) ); + + // Second item and its children + Assert.That( menu0.Children[ 1 ], Is.Not.Null.And.InstanceOf( ) ); + MenuBarItem menu0Child1 = (MenuBarItem)menu0.Children[ 1 ]; + Assert.Multiple( ( ) => + { + Assert.That( menu0Child1.Title, Is.EqualTo( "Head2" ) ); + Assert.That( menu0Child1.Children, Has.Exactly( 2 ).InstanceOf( ) ); + } ); + MenuItem menu0Child1Leaf0 = menu0Child1.Children[ 0 ]; + MenuItem menu0Child1Leaf1 = menu0Child1.Children[ 1 ]; + Assert.Multiple( ( ) => + { + Assert.That( menu0Child1Leaf0.Title, Is.EqualTo( "Child1" ) ); + Assert.That( menu0Child1Leaf0.Shortcut, Is.EqualTo( Key.J.WithCtrl.KeyCode ) ); + Assert.That( menu0Child1Leaf1.Title, Is.EqualTo( "Child2" ) ); + Assert.That( menu0Child1Leaf1.Shortcut, Is.EqualTo( Key.F.WithCtrl.KeyCode ) ); + } ); + + // Third item + Assert.That( menu0.Children[ 2 ], Is.Not.Null.And.InstanceOf( ) ); + MenuItem menu0Child2 = menu0.Children[ 2 ]; + Assert.That( menu0Child2.Title, Is.EqualTo( "Head3" ) ); + + //Now just make sure the record properties were set to the right references + Assert.Multiple( ( ) => + { + Assert.That( m.Head2, Is.SameAs( menu0Child1 ) ); + Assert.That( m.TopChild, Is.SameAs( menu0Child1Leaf0 ) ); + } ); + } + + [Test] + [TestOf( typeof( MoveMenuItemLeftOperation ) )] + public void MoveMenuItemLeft_CannotMoveRootItems( ) + { + using MenuBar bar = GetMenuBar( ); + + // cannot move a root item + MoveMenuItemLeftOperation moveMenuItemLeftOperation = new( bar.Menus[ 0 ].Children[ 0 ] ); + Assert.That( moveMenuItemLeftOperation.IsImpossible ); + bool moveMenuItemLeftOperationSucceeded = false; + Assert.That( ( ) => moveMenuItemLeftOperationSucceeded = moveMenuItemLeftOperation.Do( ), Throws.Nothing ); + Assert.That( moveMenuItemLeftOperationSucceeded, Is.False ); + } + + [Test] + public void MoveMenuItemLeft_MoveTopChild( ) + { + using MenuBarWithSubmenuItems m = GetMenuBarWithSubmenuItems( ); + + MoveMenuItemLeftOperation moveMenuItemLeftOperation = new ( m.TopChild ); + Assert.That( moveMenuItemLeftOperation.IsImpossible, Is.False ); + bool moveMenuItemLeftOperationSucceeded = false; + Assert.That( ( ) => moveMenuItemLeftOperationSucceeded = moveMenuItemLeftOperation.Do( ), Throws.Nothing ); + Assert.That( moveMenuItemLeftOperationSucceeded ); + + // move the top child left should pull + // it out of the submenu and onto the root + Assert.That( m.Bar.Menus[ 0 ].Children, Has.Exactly( 4 ).InstanceOf( ) ); + Assert.That( m.Head2.Children, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( m.Head2.Children[ 0 ], Is.Not.SameAs( m.TopChild ) ); + + // it should be pulled out underneath its parent + Assert.That( m.Bar.Menus[ 0 ].Children[ 2 ], Is.SameAs( m.TopChild ) ); + + // undoing command should return us to previous state + Assert.That( moveMenuItemLeftOperation.Undo, Throws.Nothing ); + + Assert.That( m.Bar.Menus[ 0 ].Children, Has.Exactly( 3 ).InstanceOf( ) ); + Assert.That( m.Head2.Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.That( m.Head2.Children[ 0 ], Is.SameAs( m.TopChild ) ); + } + + [Test] + [TestOf( typeof( AddMenuItemOperation ) )] + public void MoveMenuItemRight_CannotMoveElementZero( ) + { + using MenuBar bar = GetMenuBar( ); + + MenuItem? mi = bar.Menus[ 0 ].Children[ 0 ]; + mi.Data = "yarg"; + mi.Shortcut = Key.Y.WithCtrl.KeyCode; + + AddMenuItemOperation addAnother = new( mi ); + Assert.That( addAnother.IsImpossible, Is.False ); + bool addAnotherSucceeded = false; + Assert.That( ( ) => addAnotherSucceeded = addAnother.Do( ), Throws.Nothing ); + Assert.That( addAnotherSucceeded ); + + // should have added below us + Assert.That( bar.Menus[ 0 ].Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( bar.Menus[ 0 ].Children[ 0 ], Is.SameAs( mi ) ); + Assert.That( bar.Menus[ 0 ].Children[ 1 ], Is.Not.SameAs( mi ) ); + } ); + + // cannot move element 0 + MoveMenuItemRightOperation impossibleMoveRightOp = new( bar.Menus[ 0 ].Children[ 0 ] ); + Assert.That( impossibleMoveRightOp.IsImpossible ); + bool impossibleMoveRightOpSucceeded = false; + Assert.That( ( ) => impossibleMoveRightOpSucceeded = impossibleMoveRightOp.Do( ), Throws.Nothing ); + Assert.That( impossibleMoveRightOpSucceeded, Is.False ); + + // can move element 1 + // This is a destructive action, so references will change. + MoveMenuItemRightOperation validMoveRightOp = new( bar.Menus[ 0 ].Children[ 1 ] ); + Assert.That( validMoveRightOp.IsImpossible, Is.False ); + bool validMoveRightOpSucceeded = false; + Assert.That( ( ) => validMoveRightOpSucceeded = validMoveRightOp.Do( ), Throws.Nothing ); + Assert.That( validMoveRightOpSucceeded ); + + // We will have changed from a MenuItem to a MenuBarItem + // so element 0 will not be us. In Terminal.Gui there is + // a different class for a menu item and one with submenus. + Assert.That( bar.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.InstanceOf( ) ); + MenuBarItem miConvertedToMenuBarItem = (MenuBarItem)bar.Menus[ 0 ].Children[ 0 ]; + + // Check that the references are unequal but values are equal + Assert.Multiple( ( ) => + { + Assert.That( miConvertedToMenuBarItem, Is.Not.SameAs( mi ) ); + Assert.That( miConvertedToMenuBarItem.Title, Is.EqualTo( mi.Title ) ); + Assert.That( miConvertedToMenuBarItem.Data, Is.EqualTo( mi.Data ) ); + Assert.That( miConvertedToMenuBarItem.Children, Has.Exactly( 1 ).InstanceOf( ) ); + } ); + + // Now undo it. + // This is destructive as well. + Assert.That( validMoveRightOp.Undo, Throws.Nothing ); + + Assert.That( bar.Menus[ 0 ].Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( bar.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.InstanceOf( ) ); + Assert.That( bar.Menus[ 0 ].Children[ 1 ], Is.Not.Null.And.InstanceOf( ) ); + } ); + MenuItem firstChildAfterUndo = bar.Menus[ 0 ].Children[ 0 ]; + MenuItem secondChildAfterUndo = bar.Menus[ 0 ].Children[ 1 ]; + + Assert.Multiple( ( ) => + { + // All the previous references are gone forever through this process. + // So, neither element should be mi. + Assert.That( firstChildAfterUndo, Is.Not.SameAs( mi ) ); + Assert.That( secondChildAfterUndo, Is.Not.SameAs( mi ) ); + + // Neither element should be miConvertedToMenuBarItem either + Assert.That( firstChildAfterUndo, Is.Not.SameAs( miConvertedToMenuBarItem ) ); + Assert.That( secondChildAfterUndo, Is.Not.SameAs( miConvertedToMenuBarItem ) ); + + // And mi still should not be miConvertedToMenuBarItem + Assert.That( mi, Is.Not.SameAs( miConvertedToMenuBarItem ) ); + + // But the values need to be preserved + Assert.That( firstChildAfterUndo.Title, Is.EqualTo( mi.Title ) ); + Assert.That( firstChildAfterUndo.Data, Is.EqualTo( mi.Data ) ); + Assert.That( firstChildAfterUndo.Shortcut, Is.EqualTo( mi.Shortcut ) ); + } ); + } + + /// + /// Tests that when there is only one menu item + /// that it cannot be moved into a submenu + /// + [Test] + [TestOf( typeof( MoveMenuItemRightOperation ) )] + public void MoveMenuItemRight_CannotMoveLast( ) + { + MenuBar bar = GetMenuBar( ); + + MenuItem? mi = bar.Menus[ 0 ].Children[ 0 ]; + MoveMenuItemRightOperation cmd = new( mi ); + Assert.That( cmd.IsImpossible ); + Assert.That( cmd.Do, Is.False ); + } + + /// + /// Tests removing the last menu item (i.e. 'Do Something') + /// under the only remaining menu header (e.g. 'File F9') + /// should result in a completely empty menu bar and be undoable + /// + [Test] + [TestOf( typeof( RemoveMenuItemOperation ) )] + public void RemoveFinalMenuItemOnBar( ) + { + using MenuBar bar = GetMenuBar( ); + + MenuBarItem? fileMenu = bar.Menus[ 0 ]; + MenuItem? placeholderMenuItem = fileMenu.Children[ 0 ]; + + RemoveMenuItemOperation removeOp = new( placeholderMenuItem ); + + // we are able to remove the last one + Assert.That( removeOp.IsImpossible, Is.False ); + bool removeOpSucceeded = false; + Assert.That( ( ) => removeOpSucceeded = removeOp.Do( ), Throws.Nothing ); + Assert.That( removeOpSucceeded ); + Assert.That( bar.Menus, Is.Empty ); + + Assert.That( removeOp.Undo, Throws.Nothing ); + + // should be back to where we started + Assert.That( bar.Menus, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( bar.Menus[ 0 ].Children, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( bar.Menus[ 0 ].Children[ 0 ], Is.SameAs( placeholderMenuItem ) ); + } + [Test] public void RoundTrip_PreserveMenuItems() { @@ -31,7 +415,7 @@ public void RoundTrip_PreserveMenuItems() Assume.That( addViewOperation, Is.Not.Null.And.InstanceOf( ) ); bool addViewOperationSucceeded = false; - Assert.That( ( ) => addViewOperationSucceeded = OperationManager.Instance.Do( addViewOperation ), Throws.Nothing ); + Assert.That( ( ) => addViewOperationSucceeded = OperationManager.Instance.Do( addViewOperation! ), Throws.Nothing ); Assert.That( addViewOperationSucceeded ); Assume.That( ( ) => viewToCode.GenerateDesignerCs( designOut, typeof( Dialog ) ), Throws.Nothing ); @@ -41,19 +425,19 @@ public void RoundTrip_PreserveMenuItems() Assert.That( codeToView, Is.Not.Null.And.InstanceOf( ) ); Design? designBackIn = null; - Assert.That( ( ) => designBackIn = codeToView.CreateInstance( ), Throws.Nothing ); + Assert.That( ( ) => designBackIn = codeToView!.CreateInstance( ), Throws.Nothing ); Assert.That( designBackIn, Is.Not.Null.And.InstanceOf( ) ); // 1 visible root menu (e.g. File) MenuBar? mbIn = null; - Assert.That( designBackIn.View, Is.Not.Null.And.InstanceOf( ) ); + Assert.That( designBackIn!.View, Is.Not.Null.And.InstanceOf( ) ); IList actualSubviews = designBackIn.View.GetActualSubviews(); Assert.That( actualSubviews, Has.Exactly( 1 ).InstanceOf( ) ); Assert.That( ( ) => mbIn = actualSubviews.OfType( ).Single( ), Throws.Nothing ); Assert.That( mbIn, Is.Not.Null.And.InstanceOf( ) ); // 1 child menu item (e.g. Open) - Assert.That( mbIn.Menus, Is.Not.Null.And.Not.Empty ); + Assert.That( mbIn!.Menus, Is.Not.Null.And.Not.Empty ); Assert.That( mbIn.Menus, Has.Exactly( 1 ).InstanceOf( ) ); Assert.That( mbIn.Menus[ 0 ].Children, Has.Exactly( 1 ).InstanceOf( ) ); Assert.That( mbIn.Menus[ 0 ].Children[ 0 ].Title, Is.EqualTo( mbOut.Menus[ 0 ].Children[ 0 ].Title ) ); @@ -91,11 +475,11 @@ public void RoundTrip_PreserveMenuItems_WithSubmenus( ) bool addChildMenuOperation1Succeeded = false; bool addChildMenuOperation2Succeeded = false; bool addChildMenuOperation3Succeeded = false; - Assert.That( ( ) => addChildMenuOperation1Succeeded = addChildMenuOperation1.Do( ), Throws.Nothing ); + Assert.That( ( ) => addChildMenuOperation1Succeeded = addChildMenuOperation1!.Do( ), Throws.Nothing ); Assert.That( addChildMenuOperation1Succeeded ); - Assert.That( ( ) => addChildMenuOperation2Succeeded = addChildMenuOperation2.Do( ), Throws.Nothing ); + Assert.That( ( ) => addChildMenuOperation2Succeeded = addChildMenuOperation2!.Do( ), Throws.Nothing ); Assert.That( addChildMenuOperation2Succeeded ); - Assert.That( ( ) => addChildMenuOperation3Succeeded = addChildMenuOperation3.Do( ), Throws.Nothing ); + Assert.That( ( ) => addChildMenuOperation3Succeeded = addChildMenuOperation3!.Do( ), Throws.Nothing ); Assert.That( addChildMenuOperation3Succeeded ); } ); @@ -122,7 +506,7 @@ public void RoundTrip_PreserveMenuItems_WithSubmenus( ) Design? designBackIn = null; - Assume.That( ( ) => designBackIn = codeToView.CreateInstance( ), Throws.Nothing ); + Assume.That( ( ) => designBackIn = codeToView!.CreateInstance( ), Throws.Nothing ); Assume.That( designBackIn, Is.Not.Null.And.InstanceOf( ) ); MenuBar? mbIn = null; @@ -134,7 +518,7 @@ public void RoundTrip_PreserveMenuItems_WithSubmenus( ) Assert.That( mbIn, Is.Not.Null.And.InstanceOf( ) ); // 1 visible root menu (e.g. File) - Assert.That( mbIn.Menus, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( mbIn!.Menus, Has.Exactly( 1 ).InstanceOf( ) ); // 3 child menu item (original one + 3 we added -1 because we moved it to submenu) Assert.That( mbIn.Menus[ 0 ].Children, Has.Exactly( 3 ).InstanceOf( ) ); Assert.That( mbIn.Menus[ 0 ].Children, Has.All.Not.Null ); @@ -147,18 +531,21 @@ public void RoundTrip_PreserveMenuItems_WithSubmenus( ) } [Test] - [TestOf(typeof(MenuTracker))] - public void TestMenuOperations() + [TestOf( typeof( MenuTracker ) )] + // TODO: Break this one up into smaller units at some point. + public void TestMenuOperations( ) { - ViewToCode viewToCode = new (); + ViewToCode viewToCode = new( ); - FileInfo file = new ($"{nameof(TestMenuOperations)}.cs"); + FileInfo file = new( $"{nameof( TestMenuOperations )}.cs" ); Design designOut = viewToCode.GenerateNewView( file, "YourNamespace", typeof( Dialog ) ); Assume.That( designOut, Is.Not.Null.And.InstanceOf( ) ); Assume.That( designOut.View, Is.Not.Null.And.InstanceOf( ) ); - MenuBar mbOut = ViewFactory.Create( ); + using MenuBar mbOut = ViewFactory.Create( ); Assume.That( mbOut, Is.Not.Null.And.InstanceOf( ) ); + Assume.That( OperationManager.Instance.UndoStackSize, Is.Zero ); + Assume.That( OperationManager.Instance.RedoStackSize, Is.Zero ); Assert.Warn( "MenuTracker.Instance.CurrentlyOpenMenuItem cannot be guaranteed null at this time. See https://github.com/gui-cs/TerminalGuiDesigner/issues/270" ); // TODO: Enable this pre-condition once MenuTracker changes are implemented. @@ -168,192 +555,196 @@ public void TestMenuOperations() MenuTracker.Instance.Register( mbOut ); // 1 visible root menu (e.g. File) - ClassicAssert.AreEqual(1, mbOut.Menus.Length); + Assert.That( mbOut.Menus, Has.Exactly( 1 ).InstanceOf( ) ); // 1 child menu item (e.g. Open) - ClassicAssert.AreEqual(1, mbOut.Menus[0].Children.Length); + Assert.That( mbOut.Menus[ 0 ].Children, Has.Exactly( 1 ).InstanceOf( ) ); - MenuItem? orig = mbOut.Menus[0].Children[0]; + MenuItem? orig = mbOut.Menus[ 0 ].Children[ 0 ]; + Assert.That( orig, Is.Not.Null.And.InstanceOf( ) ); - OperationManager.Instance.Do( - new AddMenuItemOperation(mbOut.Menus[0].Children[0])); + AddMenuItemOperation? addMenuItemOperation = null; + Assert.That( ( ) => addMenuItemOperation = new( mbOut.Menus[ 0 ].Children[ 0 ] ), Throws.Nothing ); + Assert.That( addMenuItemOperation, Is.Not.Null.And.InstanceOf( ) ); + + bool addMenuItemOperationSucceeded = false; + Assert.That( ( ) => addMenuItemOperationSucceeded = OperationManager.Instance.Do( addMenuItemOperation! ), Throws.Nothing ); + Assert.That( addMenuItemOperationSucceeded ); // Now 2 child menu item - ClassicAssert.AreEqual(2, mbOut.Menus[0].Children.Length); - ClassicAssert.AreSame(orig, mbOut.Menus[0].Children[0]); // original is still at top + Assert.That( mbOut.Menus[ 0 ].Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.SameAs( orig ) ); // original is still at top + Assert.That( mbOut.Menus[ 0 ].Children[ 1 ], Is.Not.Null.And.Not.SameAs( orig ) ); + } ); + + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.UndoStackSize, Is.EqualTo( 1 ) ); + Assert.That( OperationManager.Instance.RedoStackSize, Is.Zero ); + } ); OperationManager.Instance.Undo(); + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.UndoStackSize, Is.Zero ); + Assert.That( OperationManager.Instance.RedoStackSize, Is.EqualTo( 1 ) ); + } ); + // Now only 1 child menu item - ClassicAssert.AreEqual(1, mbOut.Menus[0].Children.Length); - ClassicAssert.AreSame(orig, mbOut.Menus[0].Children[0]); // original is still at top + Assert.That( mbOut.Menus[ 0 ].Children, Has.Exactly( 1 ).InstanceOf( ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.SameAs( orig ) ); // original is still at top OperationManager.Instance.Redo(); - // Now 2 child menu item - ClassicAssert.AreEqual(2, mbOut.Menus[0].Children.Length); - ClassicAssert.AreSame(orig, mbOut.Menus[0].Children[0]); // original is still at top + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.UndoStackSize, Is.EqualTo( 1 ) ); + Assert.That( OperationManager.Instance.RedoStackSize, Is.Zero ); + } ); + + // Now 2 child menu items again + Assert.That( mbOut.Menus[ 0 ].Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.SameAs( orig ) ); // original is still at top + Assert.That( mbOut.Menus[ 0 ].Children[ 1 ], Is.Not.Null.And.Not.SameAs( orig ) ); // original is still at top + } ); // Now test moving an item around - MenuItem? toMove = mbOut.Menus[0].Children[1]; + MenuItem? toMove = mbOut.Menus[ 0 ].Children[ 1 ]; + Assume.That( toMove, Is.Not.Null.And.InstanceOf( ) ); // Move second menu item up - MoveMenuItemOperation up = new MoveMenuItemOperation(toMove, true); - ClassicAssert.IsFalse(up.IsImpossible); - OperationManager.Instance.Do(up); + MoveMenuItemOperation? up = null; + Assert.That( ( ) => up = new( toMove, true ), Throws.Nothing ); + Assert.That( up, Is.Not.Null.And.InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( up!.Bar, Is.SameAs( mbOut ) ); + Assert.That( up.IsImpossible, Is.False ); + } ); + + bool moveUpSucceeded = false; + Assert.That( ( ) => moveUpSucceeded = OperationManager.Instance.Do( up! ), Throws.Nothing ); + Assert.That( moveUpSucceeded ); + + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.UndoStackSize, Is.EqualTo( 2 ) ); + Assert.That( OperationManager.Instance.RedoStackSize, Is.Zero ); + } ); // Original one should now be bottom - ClassicAssert.AreSame(orig, mbOut.Menus[0].Children[1]); + Assume.That( orig, Is.Not.SameAs( toMove ) ); + Assert.That( mbOut.Menus[ 0 ].Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.Not.SameAs( orig ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.Not.Null.And.SameAs( toMove ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 1 ], Is.SameAs( orig ) ); + } ); // can't move top one up - ClassicAssert.IsTrue(new MoveMenuItemOperation(toMove, true).IsImpossible); + MoveMenuItemOperation? impossibleMoveUpOperation = null; + Assert.That( ( ) => impossibleMoveUpOperation = new( toMove, true ), Throws.Nothing ); + Assert.That( impossibleMoveUpOperation, Is.Not.Null.And.InstanceOf( ) ); + Assert.That( impossibleMoveUpOperation!.IsImpossible ); + // cant move bottom one down - ClassicAssert.IsTrue(new MoveMenuItemOperation(mbOut.Menus[0].Children[1], false).IsImpossible); + MoveMenuItemOperation? impossibleMoveDownOperation = null; + Assert.That( ( ) => impossibleMoveDownOperation = new( mbOut.Menus[ 0 ].Children[ 1 ], false ), Throws.Nothing ); + Assert.That( impossibleMoveDownOperation, Is.Not.Null.And.InstanceOf( ) ); + Assert.That( impossibleMoveDownOperation!.IsImpossible ); - OperationManager.Instance.Undo(); + Assert.That( static ( ) => OperationManager.Instance.Undo( ), Throws.Nothing ); // Original one should be back on top - ClassicAssert.AreSame(orig, mbOut.Menus[0].Children[0]); + Assert.That( mbOut.Menus[ 0 ].Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.SameAs( orig ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.Not.SameAs( toMove ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 1 ], Is.SameAs( toMove ) ); + } ); // test moving the top one down - MenuItem? toMove2 = mbOut.Menus[0].Children[1]; + MenuItem? toMove2 = mbOut.Menus[ 0 ].Children[ 1 ]; // Move first menu item down - MoveMenuItemOperation down = new MoveMenuItemOperation(toMove2, true); - ClassicAssert.IsFalse(down.IsImpossible); - OperationManager.Instance.Do(down); - - // Original one should now be bottom - ClassicAssert.AreSame(orig, mbOut.Menus[0].Children[1]); - ClassicAssert.AreNotSame(orig, mbOut.Menus[0].Children[0]); - - OperationManager.Instance.Undo(); - - // should be back to how we started now - ClassicAssert.AreSame(orig, mbOut.Menus[0].Children[0]); - ClassicAssert.AreNotSame(orig, mbOut.Menus[0].Children[1]); - } - - private MenuBar GetMenuBar() - { - return this.GetMenuBar(out _); - } - - private MenuBar GetMenuBar(out Design root) - { - root = Get10By10View(); - - var bar = ViewFactory.Create( ); - var addBarCmd = new AddViewOperation(bar, root, "mb"); - ClassicAssert.IsTrue(addBarCmd.Do()); + MoveMenuItemOperation? down = null; + Assert.That( ( ) => down = new( toMove2, true ), Throws.Nothing ); + Assert.That( down, Is.Not.Null.And.InstanceOf( ) ); + Assert.That( down!.IsImpossible, Is.False ); - // Expect ViewFactory to have created a single - // placeholder menu item - ClassicAssert.AreEqual(1, bar.Menus.Length); - ClassicAssert.AreEqual(1, bar.Menus[0].Children.Length); - - return bar; - } - - /// - /// Tests removing the last menu item (i.e. 'Do Something') - /// under the only remaining menu header (e.g. 'File F9') - /// should result in a completely empty menu bar and be undoable - /// - [Test] - public void TestRemoveFinalMenuItemOnBar() - { - var bar = this.GetMenuBar(); + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.RedoStackSize, Is.EqualTo( 1 ) ); + Assert.That( OperationManager.Instance.UndoStackSize, Is.EqualTo( 1 ) ); + } ); - var fileMenu = bar.Menus[0]; - var placeholderMenuItem = fileMenu.Children[0]; + bool moveDownSucceeded = false; + Assert.That( ( ) => moveDownSucceeded = OperationManager.Instance.Do( down ), Throws.Nothing ); + Assert.That( moveDownSucceeded ); + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.RedoStackSize, Is.Zero ); + Assert.That( OperationManager.Instance.UndoStackSize, Is.EqualTo( 2 ) ); + } ); - var remove = new RemoveMenuItemOperation(placeholderMenuItem); + // Original one should now be bottom + Assert.That( mbOut.Menus[ 0 ].Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.SameAs( toMove2 ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.Not.SameAs( orig ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 1 ], Is.SameAs( orig ) ); + } ); - // we are able to remove the last one - ClassicAssert.IsTrue(remove.Do()); - ClassicAssert.IsEmpty(bar.Menus, "menu bar should now be completely empty"); + Assert.That( static ( ) => OperationManager.Instance.Undo( ), Throws.Nothing ); - remove.Undo(); + Assert.Multiple( static ( ) => + { + Assert.That( OperationManager.Instance.RedoStackSize, Is.EqualTo( 1 ) ); + Assert.That( OperationManager.Instance.UndoStackSize, Is.EqualTo( 1 ) ); + } ); - // should be back to where we started - ClassicAssert.AreEqual(1, bar.Menus.Length); - ClassicAssert.AreEqual(1, bar.Menus[0].Children.Length); - ClassicAssert.AreSame(placeholderMenuItem, bar.Menus[0].Children[0]); - } - /// - /// Tests that when there is only one menu item - /// that it cannot be moved into a submenu - /// - [Test] - public void TestMoveMenuItemRight_CannotMoveLast() - { - var bar = this.GetMenuBar(); + // should be back to how we started now + Assert.That( mbOut.Menus[ 0 ].Children, Has.Exactly( 2 ).InstanceOf( ) ); + Assert.Multiple( ( ) => + { + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.SameAs( orig ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 0 ], Is.Not.SameAs( toMove2 ) ); + Assert.That( mbOut.Menus[ 0 ].Children[ 1 ], Is.SameAs( toMove2 ) ); + } ); - var mi = bar.Menus[0].Children[0]; - var cmd = new MoveMenuItemRightOperation(mi); - ClassicAssert.IsFalse(cmd.Do()); + MenuTracker.Instance.UnregisterMenuBar( mbOut ); } - [Test] - public void TestMoveMenuItemRight_CannotMoveElementZero() + private static MenuBar GetMenuBar( ) { - var bar = this.GetMenuBar(); - - var mi = bar.Menus[0].Children[0]; - mi.Data = "yarg"; - mi.Shortcut = Key.Y.WithCtrl.KeyCode; - var addAnother = new AddMenuItemOperation(mi); - ClassicAssert.True(addAnother.Do()); - - // should have added below us - ClassicAssert.AreSame(mi, bar.Menus[0].Children[0]); - ClassicAssert.AreNotSame(mi, bar.Menus[0].Children[1]); - ClassicAssert.AreEqual(2, bar.Menus[0].Children.Length); - - // cannot move element 0 - ClassicAssert.IsFalse(new MoveMenuItemRightOperation( - bar.Menus[0].Children[0]) - .Do()); - - var cmd = new MoveMenuItemRightOperation( - bar.Menus[0].Children[1]); - - // can move element 1 - ClassicAssert.IsTrue(cmd.Do()); - - // We will have changed from a MenuItem to a MenuBarItem - // so element 0 will not be us. In Terminal.Gui there is - // a different class for a menu item and one with submenus - ClassicAssert.AreNotSame(mi, bar.Menus[0].Children[0]); - ClassicAssert.AreEqual(mi.Title, bar.Menus[0].Children[0].Title); - ClassicAssert.AreEqual(mi.Data, bar.Menus[0].Children[0].Data); - ClassicAssert.AreEqual(1, bar.Menus[0].Children.Length); - - cmd.Undo(); - - ClassicAssert.AreEqual(mi.Title, bar.Menus[0].Children[0].Title); - ClassicAssert.AreEqual(mi.Data, bar.Menus[0].Children[0].Data); - ClassicAssert.AreEqual(mi.Shortcut, bar.Menus[0].Children[0].Shortcut); - ClassicAssert.AreNotSame(mi, bar.Menus[0].Children[1]); + return GetMenuBar( out _ ); } - [Test] - public void TestMoveMenuItemLeft_CannotMoveRootItems() + private static MenuBar GetMenuBar( out Design root ) { - var bar = this.GetMenuBar(); + root = Get10By10View( ); - var mi = bar.Menus[0].Children[0]; + var bar = ViewFactory.Create( ); + var addBarCmd = new AddViewOperation( bar, root, "mb" ); + addBarCmd.Do( ); - // cannot move a root item - ClassicAssert.IsFalse(new MoveMenuItemLeftOperation( - bar.Menus[0].Children[0]) - .Do()); + return bar; } - private MenuBar GetMenuBarWithSubmenuItems(out MenuBarItem head2, out MenuItem topChild) + private static MenuBarWithSubmenuItems GetMenuBarWithSubmenuItems( ) { - var bar = this.GetMenuBar(); + MenuBarWithSubmenuItems toReturn = new( GetMenuBar( ), null!, null! ) + { + Bar = GetMenuBar( ) + }; // Set up a menu like: /* @@ -363,156 +754,54 @@ private MenuBar GetMenuBarWithSubmenuItems(out MenuBarItem head2, out MenuItem t Head3 Child2 */ - var mi = bar.Menus[0].Children[0]; + var mi = toReturn.Bar.Menus[ 0 ].Children[ 0 ]; mi.Title = "Head1"; - bar.Menus[0].Children = new[] + toReturn.Bar.Menus[ 0 ].Children = + [ + toReturn.Bar.Menus[ 0 ].Children[ 0 ], + toReturn.Head2 = CreateHead2Item( ), + new( "Head3", null, static ( ) => { } ), + ]; + + return toReturn; + + MenuBarItem CreateHead2Item( ) { - bar.Menus[0].Children[0], - head2 = new MenuBarItem(new[] + return new( [toReturn.TopChild = CreateHead2Child1Item( ), CreateHead2Child2Item( )] ) { - topChild = new MenuItem("Child1", null, () => { }) + Title = "Head2", + }; + + static MenuItem CreateHead2Child1Item( ) + { + return new( "Child1", null, static ( ) => { } ) { Data = "Child1", Shortcut = Key.J.WithCtrl.KeyCode, - }, - new MenuItem("Child2", null, () => { }) + }; + } + + static MenuItem CreateHead2Child2Item( ) + { + return new( "Child2", null, static ( ) => { } ) { Data = "Child2", Shortcut = Key.F.WithCtrl.KeyCode, - }, - }) - { - Title = "Head2", - }, - new MenuItem("Head3", null, () => { }), - }; - - return bar; + }; + } + } } - [Test] - public void TestMoveMenuItemLeft_MoveTopChild() + private sealed record MenuBarWithSubmenuItems( MenuBar Bar, MenuBarItem Head2, MenuItem TopChild ) : IDisposable { - var bar = this.GetMenuBarWithSubmenuItems(out var head2, out var topChild); - - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(2, head2.Children.Length); - ClassicAssert.AreSame(topChild, head2.Children[0]); - - var cmd = new MoveMenuItemLeftOperation(topChild); - ClassicAssert.IsTrue(cmd.Do()); + public MenuBarItem Head2 { get; set; } = Head2; + public MenuItem TopChild { get; set; } = TopChild; - // move the top child left should pull - // it out of the submenu and onto the root - ClassicAssert.AreEqual(4, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(1, head2.Children.Length); - - // it should be pulled out underneath its parent - // and preserve its (Name) and Shortcuts - ClassicAssert.AreEqual(topChild.Title, bar.Menus[0].Children[2].Title); - ClassicAssert.AreEqual(topChild.Data, bar.Menus[0].Children[2].Data); - ClassicAssert.AreEqual(topChild.Shortcut, bar.Menus[0].Children[2].Shortcut); - ClassicAssert.AreSame(topChild, bar.Menus[0].Children[2]); - - // undoing command should return us to - // previous state - cmd.Undo(); - - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(2, head2.Children.Length); - - ClassicAssert.AreEqual(topChild.Title, head2.Children[0].Title); - ClassicAssert.AreEqual(topChild.Data, head2.Children[0].Data); - ClassicAssert.AreEqual(topChild.Shortcut, head2.Children[0].Shortcut); - ClassicAssert.AreSame(topChild, head2.Children[0]); - } - - [Test] - public void TestDeletingMenuItemFromSubmenu_TopChild() - { - var bar = this.GetMenuBarWithSubmenuItems(out var head2, out var topChild); - - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(2, head2.Children.Length); - ClassicAssert.AreSame(topChild, head2.Children[0]); - - var cmd = new RemoveMenuItemOperation(topChild); - ClassicAssert.IsTrue(cmd.Do()); - - // Delete the top child should leave only 1 in submenu - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(1, head2.Children.Length); - ClassicAssert.AreNotSame(topChild, head2.Children[0]); - - cmd.Undo(); - - // should come back now - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(2, head2.Children.Length); - ClassicAssert.AreSame(topChild, head2.Children[0]); - } - - [Test] - public void TestDeletingMenuItemFromSubmenu_AllSubmenuChild() - { - var bar = this.GetMenuBarWithSubmenuItems(out var head2, out var topChild); - var bottomChild = head2.Children[1]; - - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(typeof(MenuBarItem), bar.Menus[0].Children[1].GetType()); - ClassicAssert.AreEqual(2, head2.Children.Length); - ClassicAssert.AreSame(topChild, head2.Children[0]); - - var cmd1 = new RemoveMenuItemOperation(topChild); - ClassicAssert.IsTrue(cmd1.Do()); - - var cmd2 = new RemoveMenuItemOperation(bottomChild); - ClassicAssert.IsTrue(cmd2.Do()); - - // Deleting both children should convert us from - // a dropdown submenu to just a regular MenuItem - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(typeof(MenuItem), bar.Menus[0].Children[1].GetType()); - - cmd2.Undo(); - - // should bring the bottom one back - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(typeof(MenuBarItem), bar.Menus[0].Children[1].GetType()); - ClassicAssert.AreSame(bottomChild, ((MenuBarItem)bar.Menus[0].Children[1]).Children[0]); - - cmd1.Undo(); - - // Both submenu items should now be back - ClassicAssert.AreEqual(3, bar.Menus[0].Children.Length); - ClassicAssert.AreEqual(typeof(MenuBarItem), bar.Menus[0].Children[1].GetType()); - ClassicAssert.AreSame(topChild, ((MenuBarItem)bar.Menus[0].Children[1]).Children[0]); - ClassicAssert.AreSame(bottomChild, ((MenuBarItem)bar.Menus[0].Children[1]).Children[1]); - } - - [Test] - public void TestDeletingLastMenuItem_ShouldRemoveWholeBar() - { - var bar = this.GetMenuBar(out Design root); - - var mi = bar.Menus[0].Children[0]; - - ClassicAssert.Contains(bar, root.View.Subviews.ToArray(), - "The MenuBar should be on the main view being edited"); - - var cmd = new RemoveMenuItemOperation(mi); - ClassicAssert.IsTrue(cmd.Do()); - - ClassicAssert.IsEmpty(bar.Menus, "Expected menu bar header (File) to be removed along with it's last (only) child"); - - ClassicAssert.IsFalse( - root.View.Subviews.Contains(bar), - "Now that the MenuBar is completely empty it should be automatically removed"); - - cmd.Undo(); - - ClassicAssert.Contains(bar, root.View.Subviews.ToArray(), - "Undo should put the MenuBar back on the view again"); + /// + public void Dispose( ) + { + Bar.Dispose( ); + } } } \ No newline at end of file diff --git a/tests/MouseManagerTests.cs b/tests/MouseManagerTests.cs deleted file mode 100644 index e9303386..00000000 --- a/tests/MouseManagerTests.cs +++ /dev/null @@ -1,370 +0,0 @@ -using System; -using System.Linq; -using Terminal.Gui; -using TerminalGuiDesigner; -using TerminalGuiDesigner.Operations; -using TerminalGuiDesigner.UI; - -namespace UnitTests; - -internal class MouseManagerTests : Tests -{ - [Test] - public void TestDragLabel() - { - var d = Get10By10View(); - - var lbl = new Label(0, 0, "Hi there buddy"); - var lblDesign = new Design(d.SourceCode, "mylabel", lbl); - lbl.Data = lblDesign; - d.View.Add(lbl); - - var mgr = new MouseManager(); - - // we haven't done anything yet - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - ClassicAssert.AreEqual(0, lbl.Bounds.Y); - - // user presses down over the control - var e = new MouseEvent - { - X = 1, - Y = 0, - Flags = MouseFlags.Button1Pressed, - }; - - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(0, lbl.Bounds.Y); - - // we still haven't committed to anything - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - - // user pulled view down but still has mouse down - e = new MouseEvent - { - X = 1, - Y = 1, - Flags = MouseFlags.Button1Pressed, - }; - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual((Pos)1, lbl.Y); - - // we still haven't committed to anything - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - - // user releases mouse (in place) - e = new MouseEvent - { - X = 1, - Y = 1, - }; - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual((Pos)1, lbl.Y); - - // we have now committed the drag so could undo - ClassicAssert.AreEqual(1, OperationManager.Instance.UndoStackSize); - } - - [TestCase(typeof(Button))] - [TestCase(typeof(TabView))] - [TestCase(typeof(TableView))] - [TestCase(typeof(View))] - public void TestDragResizeView(Type t) - { - var d = Get10By10View(); - - var view = ViewFactory.Create(t); - view.Width = 8; - view.Height = 1; - - var design = new Design(d.SourceCode, "myView", view); - view.Data = design; - d.View.Add(view); - - ClassicAssert.AreEqual(8, view.Bounds.Width); - var mgr = new MouseManager(); - - // we haven't done anything yet - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - ClassicAssert.AreEqual(0, view.Bounds.X); - ClassicAssert.AreEqual(0, view.Bounds.Y); - ClassicAssert.AreEqual(8, view.Bounds.Width); - ClassicAssert.AreEqual(1, view.Bounds.Height); - - // user presses down in the lower right of control - var e = new MouseEvent - { - X = 6, - Y = 0, - Flags = MouseFlags.Button1Pressed, - }; - - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(0, view.Bounds.Y); - - // we still haven't committed to anything - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - - // user pulled view size +1 width and +1 height - e = new MouseEvent - { - X = 9, - Y = 0, - Flags = MouseFlags.Button1Pressed, - }; - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(0, view.Bounds.X); - ClassicAssert.AreEqual(0, view.Bounds.Y); - ClassicAssert.AreEqual(10, view.Bounds.Width, "Expected resize to increase Width when dragging"); - ClassicAssert.AreEqual(1, view.Bounds.Height, "Expected resize of button to ignore Y component"); - - // we still haven't committed to anything - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - - // user releases mouse (in place) - e = new MouseEvent - { - X = 9, - Y = 0, - }; - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(0, view.Bounds.X); - ClassicAssert.AreEqual(0, view.Bounds.Y); - ClassicAssert.AreEqual(10, view.Bounds.Width, "Expected resize to increase Width when dragging"); - ClassicAssert.AreEqual(1, view.Bounds.Height); - - // we have now committed the drag so could undo - ClassicAssert.AreEqual(1, OperationManager.Instance.UndoStackSize); - } - - [TestCase(typeof(View))] - public void TestDragResizeView_CannotResize_DimFill(Type t) - { - var d = Get10By10View(); - - var view = ViewFactory.Create(t); - view.Width = Dim.Fill(); - view.Height = 1; - - var design = new Design(d.SourceCode, "myView", view); - view.Data = design; - d.View.Add(view); - - var mgr = new MouseManager(); - - // we haven't done anything yet - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - ClassicAssert.AreEqual(0, view.Bounds.X); - ClassicAssert.AreEqual(0, view.Bounds.Y); - ClassicAssert.AreEqual(10, view.Bounds.Width); - ClassicAssert.AreEqual(1, view.Bounds.Height); - - // user presses down in the lower right of control - var e = new MouseEvent - { - X = 9, - Y = 0, - Flags = MouseFlags.Button1Pressed, - }; - - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(0, view.Bounds.Y); - - // we still haven't committed to anything - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - - // user pulled view size down and left - e = new MouseEvent - { - X = 6, - Y = 3, - Flags = MouseFlags.Button1Pressed, - }; - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(0, view.Bounds.X); - ClassicAssert.AreEqual(0, view.Bounds.Y); - ClassicAssert.AreEqual(10, view.Bounds.Width, "Expected Width to remain constant because it is Dim.Fill()"); - ClassicAssert.AreEqual(4, view.Bounds.Height, "Expected resize to update Y component"); - ClassicAssert.AreEqual(Dim.Fill(),view.Width); - ClassicAssert.AreEqual(Dim.Sized(4), view.Height); - - // we still haven't committed to anything - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - - // user releases mouse (in place) - e = new MouseEvent - { - X = 6, - Y = 3, - }; - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(0, view.Bounds.X); - ClassicAssert.AreEqual(0, view.Bounds.Y); - ClassicAssert.AreEqual(10, view.Bounds.Width, "Expected Width to remain constant because it is Dim.Fill()"); - ClassicAssert.AreEqual(4, view.Bounds.Height, "Expected resize to update Y component"); - ClassicAssert.AreEqual(Dim.Fill(), view.Width); - ClassicAssert.AreEqual(Dim.Sized(4), view.Height); - - // we have now committed the drag so could undo - ClassicAssert.AreEqual(1, OperationManager.Instance.UndoStackSize); - - OperationManager.Instance.Undo(); - - // Should reset us to the initial state - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - ClassicAssert.AreEqual(0, view.Bounds.X); - ClassicAssert.AreEqual(0, view.Bounds.Y); - ClassicAssert.AreEqual(10, view.Bounds.Width); - ClassicAssert.AreEqual(1, view.Bounds.Height); - ClassicAssert.AreEqual(Dim.Fill(), view.Width); - ClassicAssert.AreEqual(Dim.Sized(1), view.Height); - - } - - [TestCase(0,0)] - [TestCase(3, 3)] - public void TestDragResizeView_CannotResize_1By1View(int locationOfViewX, int locationOfViewY) - { - var d = Get10By10View(); - - var view = ViewFactory.Create(typeof(View)); - view.Width = Dim.Fill(); - view.X = locationOfViewX; - view.Y = locationOfViewY; - view.Width = 1; - view.Height = 1; - - var design = new Design(d.SourceCode, "myView", view); - view.Data = design; - d.View.Add(view); - - d.View.LayoutSubviews(); - - var mgr = new MouseManager(); - - // we haven't done anything yet - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - ClassicAssert.AreEqual(locationOfViewX, view.Frame.X); - ClassicAssert.AreEqual(locationOfViewY, view.Frame.Y); - ClassicAssert.AreEqual(1, view.Bounds.Width); - ClassicAssert.AreEqual(1, view.Bounds.Height); - - // user presses down in the lower right of control - var e = new MouseEvent - { - X = locationOfViewX, - Y = locationOfViewY, - Flags = MouseFlags.Button1Pressed, - }; - - var hit = view.HitTest(e, out var isBorder, out var isLowerRight); - ClassicAssert.AreSame(view, hit); - ClassicAssert.IsTrue(isBorder); - ClassicAssert.IsFalse(isLowerRight,"Upper left should never be considered lower right even if view is 1x1"); - - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(locationOfViewY, view.Frame.Y); - - // we still haven't committed to anything - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - - // user pulled view size down and left - e = new MouseEvent - { - X = 6, - Y = 3, - Flags = MouseFlags.Button1Pressed, - }; - mgr.HandleMouse(e, d); - - ClassicAssert.AreEqual(1, view.Bounds.Width); - ClassicAssert.AreEqual(1, view.Bounds.Height); - } - - [TestCase(1, 1, 4, 6, new[] { 0, 2 })] // drag from 1,1 to 4,6 and expect labels 0 and 2 to be selected - [TestCase(1, 1, 10, 10, new[] { 0, 1, 2 })] // drag over all - public void TestDragSelectionBox(int xStart, int yStart, int xEnd, int yEnd, int[] expectSelected) - { - var d = Get10By10View(); - - /* - Hi - Hi - Hi - */ - - var lbl1 = new Label(2, 1, "Hi"); - var lbl2 = new Label(4, 2, "Hi"); - var lbl3 = new Label(2, 3, "Hi"); - - var lbl1Design = new Design(d.SourceCode, "lbl1", lbl1); - var lbl2Design = new Design(d.SourceCode, "lbl2", lbl2); - var lbl3Design = new Design(d.SourceCode, "lbl3", lbl3); - - lbl1.Data = lbl1Design; - lbl2.Data = lbl2Design; - lbl3.Data = lbl3Design; - - var labels = new[] { lbl1Design, lbl2Design, lbl3Design }; - - d.View.Add(lbl1); - d.View.Add(lbl2); - d.View.Add(lbl3); - - var selection = SelectionManager.Instance; - selection.Clear(); - var mgr = new MouseManager(); - - // user presses down - var e = new MouseEvent - { - X = xStart, - Y = yStart, - Flags = MouseFlags.Button1Pressed, - }; - - mgr.HandleMouse(e, d); - - // user pulled selection box to destination - e = new MouseEvent - { - X = xEnd, - Y = yEnd, - Flags = MouseFlags.Button1Pressed, - }; - mgr.HandleMouse(e, d); - - // user releases mouse (in place) - e = new MouseEvent - { - X = xEnd, - Y = yEnd, - }; - mgr.HandleMouse(e, d); - - // do not expect dragging selection box to change anything - // or be undoable - ClassicAssert.AreEqual(0, OperationManager.Instance.UndoStackSize); - - // for each selectable thing - for (int i = 0; i < labels.Length; i++) - { - // its selection status should match the expectation - // passed in the test case - ClassicAssert.AreEqual( - expectSelected.Contains(i), - selection.Selected.ToList().Contains(labels[i]), - $"Expectation wrong for label index {i} (indexes are 0 based)"); - } - } -} diff --git a/tests/PosTests.cs b/tests/PosTests.cs index 82094333..c1ae6461 100644 --- a/tests/PosTests.cs +++ b/tests/PosTests.cs @@ -1,9 +1,3 @@ -using System.IO; -using System.Linq; -using TerminalGuiDesigner.FromCode; -using TerminalGuiDesigner.Operations; -using TerminalGuiDesigner.ToCode; - namespace UnitTests; [TestFixture] @@ -196,7 +190,7 @@ private static IEnumerable IsAnchorEnd_Cases }; } } - + private static IEnumerable IsCenter_Cases { get @@ -336,14 +330,14 @@ private static IEnumerable IsRelative_WithOutParams_Cases [TestCaseSource( nameof( GetCode_Cases ) )] public void GetCode( Pos testPos, string expectedCodeString, Design d, View v ) { - Assert.That( testPos.ToCode( new( ) { d } ), Is.EqualTo( expectedCodeString ) ); + Assert.That( testPos.ToCode( [d] ), Is.EqualTo( expectedCodeString ) ); } [Test] [TestCaseSource( nameof( GetPosType_OutputsCorrectOffset_Cases ) )] public bool GetPosType_OutputsCorrectOffset( Pos testValue, int expectedOffset, Design? d ) { - List knownDesigns = new( ); + List knownDesigns = []; if ( d is not null ) { knownDesigns.Add( d ); @@ -358,7 +352,7 @@ public bool GetPosType_OutputsCorrectOffset( Pos testValue, int expectedOffset, [TestCaseSource( nameof( GetPosType_OutputsCorrectType_Cases ) )] public bool GetPosType_OutputsCorrectType( Pos testValue, PosType expectedPosType, Design? d ) { - List knownDesigns = new( ); + List knownDesigns = []; if ( d is not null ) { knownDesigns.Add( d ); @@ -373,7 +367,7 @@ public bool GetPosType_OutputsCorrectType( Pos testValue, PosType expectedPosTyp [TestCaseSource( nameof( GetPosType_OutputsCorrectValue_Cases ) )] public bool GetPosType_OutputsCorrectValue( Pos testValue, float expectedValue, Design? d ) { - List knownDesigns = new( ); + List knownDesigns = []; if ( d is not null ) { knownDesigns.Add( d ); @@ -411,6 +405,7 @@ public bool IsAnchorEnd( Pos? testValue ) { Assert.Ignore( "BUG: Null returns true for this, when it shouldn't" ); } + return testValue.IsAnchorEnd( ); } @@ -433,6 +428,7 @@ public bool IsCenter( Pos? testValue ) { Assert.Warn( "BUG: Null returns true for this, when it shouldn't" ); } + return testValue.IsCenter( ); } @@ -472,7 +468,7 @@ public bool IsRelative( Pos? testValue ) [NonParallelizable] public bool IsRelative_WithOutParams( Pos testValue, Design? expectedOutDesign, Side expectedOutSide ) { - List knownDesigns = new( ); + List knownDesigns = []; if ( expectedOutDesign is not null ) { knownDesigns.Add( expectedOutDesign ); @@ -499,7 +495,7 @@ public void CreatePosRelative( [Values] Side side, [Values( -10, -5, 0, 5, 10 )] Assert.Multiple( ( ) => { Assert.That( p.IsRelative ); - Assert.That( p.IsRelative( new List { d }, out Design outDesign, out Side outSide ) ); + 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 ) ); } ); @@ -524,121 +520,43 @@ public void NullPos( ) } [Test] - [Ignore( "Code generation is tested in other tests here" )] - public void TestRoundTrip_PosAnchorEnd( ) - { - var viewToCode = new ViewToCode( ); - - 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