Partial on #2975 - Replaces Menu v1 in many places with v2 (#4040)

* touching publish.yml

* Fixed UICatalog bugs. Added fluent tests.

* marked v1 menu stuff as obsolte

* Tweaks.
Added View.GetSubMenus<type>().

* fixed unit tests

* general messing around

* general messing around

* Playing with Fluent

* ColorScheme tweaks

* WIP: ColorScheme tweaks

* Playing with Fluent

* Merged from laptop2

* Hacky-ish fixes to:
- #4016
- #4014

* Fixed Region bug preventing menus without borders from working

* Tweaks

* Fixed a bunch of CM issues

* Fixed OoptionSelector

* ip

* FixedCM issues

* Fixed CM issues2

* Revert "FixedCM issues"

This reverts commit dd6c6a70a3.

* Reverted stuff

* Found and fixed bug in AllViews_Center_Properly

* Fixed CM issues2

* removed menuv2 onapplied.
Changed how UICatalog Applys CM

* changed test time out to see if it helkps with ubuntu fails

* reset app on fail?

* back to 1500ms

* Made StatusBar nullable.

* Code Cleanup.

* HexEditor Code Cleanup.

* HexEditor Code Cleanup.

* Back to 3000ms. Sigh.

* Trying different logic

* Trying different logic2

* Fixed potential crash in runlop

* Fixed potential crash in runlop2

* Tweaked Spinner stuff

* Removed TabView from TextEffects scenario. Not needed and possible culprit.

* back to 2000ms

* WIP: Revamping menu scenarios

* Menu Scenario refinements.
Fixed a few bugs.
Code cleanup.

* fixed unit test

* Fixed warnings

* Fixed warnings2

* Fixed File.Exit

* WIP: Dealing with QuitKey struggles

* WIP: Dealing with QuitKey struggles 2

* WIP: Dealing with QuitKey struggles 3

* Fixed ListView collection nav bug

* Fixed a bunch of menu stuff.
Fixed Appv2 stuff.

* Lots of refactoring and fixing

* Lots of unit test issues

* Fixed DebugIDisposable issues

* Fixed release build issue

* Fixed release build issue 2

* DebugIDisposable -> EnableDebugIDisposableAsserts and more

* DebugIDisposable -> EnableDebugIDisposableAsserts and more 2

* Fixed Menus scenario - context menu

* Added @bdisp suggested assert. Commented it out as it breaks tests.

* Code cleanup

* Fixed disposed but

* Fixed UICatalog exit

* Fixed Unit test I broke.
Added 'Minimal' Theme that turns off all borders etc...
This commit is contained in:
Tig
2025-04-24 05:17:58 -06:00
committed by GitHub
parent 8d3d039fb3
commit 47bcf1bf57
136 changed files with 5109 additions and 2214 deletions

View File

@@ -8,13 +8,47 @@ public class BasicFluentAssertionTests
{
private readonly TextWriter _out;
public BasicFluentAssertionTests (ITestOutputHelper outputHelper) { _out = new TestOutputWriter (outputHelper); }
public BasicFluentAssertionTests (ITestOutputHelper outputHelper)
{
_out = new TestOutputWriter (outputHelper);
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void GuiTestContext_NewInstance_Runs (V2TestDriver d)
{
using GuiTestContext context = With.A<Window> (40, 10, d);
Assert.True (Application.Top!.Running);
context.WriteOutLogs (_out);
context.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void GuiTestContext_QuitKey_Stops (V2TestDriver d)
{
using GuiTestContext context = With.A<Window> (40, 10, d);
Assert.True (Application.Top!.Running);
Toplevel top = Application.Top;
context.RaiseKeyDownEvent (Application.QuitKey);
Assert.False (top!.Running);
Application.Top?.Dispose ();
Application.Shutdown();
context.WriteOutLogs (_out);
context.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void GuiTestContext_StartsAndStopsWithoutError (V2TestDriver d)
{
using GuiTestContext context = With.A<Window> (40, 10,d);
using GuiTestContext context = With.A<Window> (40, 10, d);
// No actual assertions are needed — if no exceptions are thrown, it's working
context.Stop ();
@@ -51,10 +85,10 @@ public class BasicFluentAssertionTests
{
var clicked = false;
MenuItemv2 [] menuItems = [new ("_New File", string.Empty, () => { clicked = true; })];
MenuItemv2 [] menuItems = [new ("_New File", string.Empty, () => { clicked = true; })];
using GuiTestContext c = With.A<Window> (40, 10, d)
.WithContextMenu (new PopoverMenu(menuItems))
.WithContextMenu (new PopoverMenu (menuItems))
.ScreenShot ("Before open menu", _out)
// Click in main area inside border
@@ -90,7 +124,7 @@ public class BasicFluentAssertionTests
new ("Six", "", null)
];
using GuiTestContext c = With.A<Window> (40, 10,d)
using GuiTestContext c = With.A<Window> (40, 10, d)
.WithContextMenu (new PopoverMenu (menuItems))
.ScreenShot ("Before open menu", _out)
@@ -100,7 +134,7 @@ public class BasicFluentAssertionTests
.Down ()
.Down ()
.Down ()
.Right()
.Right ()
.ScreenShot ("After open submenu", _out)
.Down ()
.Enter ()

View File

@@ -11,7 +11,10 @@ public class FileDialogFluentTests
{
private readonly TextWriter _out;
public FileDialogFluentTests (ITestOutputHelper outputHelper) { _out = new TestOutputWriter (outputHelper); }
public FileDialogFluentTests (ITestOutputHelper outputHelper)
{
_out = new TestOutputWriter (outputHelper);
}
private MockFileSystem CreateExampleFileSystem ()
{
@@ -41,27 +44,25 @@ public class FileDialogFluentTests
[ClassData (typeof (V2TestDrivers))]
public void CancelFileDialog_UsingEscape (V2TestDriver d)
{
var sd = new SaveDialog ( CreateExampleFileSystem ());
var sd = new SaveDialog (CreateExampleFileSystem ());
using var c = With.A (sd, 100, 20, d)
.ScreenShot ("Save dialog",_out)
.Escape()
.ScreenShot ("Save dialog", _out)
.Escape ()
.Then (() => Assert.True (sd.Canceled))
.Stop ();
Assert.True (sd.Canceled);
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void CancelFileDialog_UsingCancelButton_TabThenEnter (V2TestDriver d)
{
var sd = new SaveDialog (CreateExampleFileSystem ());
var sd = new SaveDialog (CreateExampleFileSystem ()) { Modal = false };
using var c = With.A (sd, 100, 20, d)
.ScreenShot ("Save dialog", _out)
.Focus <Button>(b=> b.Text == "_Cancel")
.Focus<Button> (b => b.Text == "_Cancel")
.Then (() => Assert.True (sd.Canceled))
.Enter ()
.Stop ();
Assert.True (sd.Canceled);
}
[Theory]
@@ -69,13 +70,13 @@ public class FileDialogFluentTests
public void CancelFileDialog_UsingCancelButton_LeftClickButton (V2TestDriver d)
{
var sd = new SaveDialog (CreateExampleFileSystem ());
using var c = With.A (sd, 100, 20, d)
.ScreenShot ("Save dialog", _out)
.LeftClick <Button> (b => b.Text == "_Cancel")
.Stop ()
.WriteOutLogs (_out);
Assert.True (sd.Canceled);
.LeftClick<Button> (b => b.Text == "_Cancel")
.WriteOutLogs (_out)
.Then (() => Assert.True (sd.Canceled))
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
@@ -86,9 +87,8 @@ public class FileDialogFluentTests
.ScreenShot ("Save dialog", _out)
.Send (Key.C.WithAlt)
.WriteOutLogs (_out)
.Then (() => Assert.True (sd.Canceled))
.Stop ();
Assert.True (sd.Canceled);
}
[Theory]
@@ -101,10 +101,9 @@ public class FileDialogFluentTests
.ScreenShot ("Save dialog", _out)
.LeftClick<Button> (b => b.Text == "_Save")
.WriteOutLogs (_out)
.Then (() => Assert.False (sd.Canceled))
.Then (() => AssertIsFileSystemRoot (fs, sd))
.Stop ();
Assert.False (sd.Canceled);
AssertIsFileSystemRoot (fs, sd);
}
[Theory]
@@ -117,10 +116,10 @@ public class FileDialogFluentTests
.ScreenShot ("Save dialog", _out)
.Send (Key.S.WithAlt)
.WriteOutLogs (_out)
.Then (() => Assert.False (sd.Canceled))
.Then (() => AssertIsFileSystemRoot (fs, sd))
.Stop ();
Assert.False (sd.Canceled);
AssertIsFileSystemRoot (fs, sd);
}
[Theory]
@@ -128,16 +127,15 @@ public class FileDialogFluentTests
public void SaveFileDialog_UsingOkButton_TabEnter (V2TestDriver d)
{
var fs = CreateExampleFileSystem ();
var sd = new SaveDialog (fs);
var sd = new SaveDialog (fs) { Modal = false };
using var c = With.A (sd, 100, 20, d)
.ScreenShot ("Save dialog", _out)
.Focus <Button> (b => b.Text == "_Save")
.Focus<Button> (b => b.Text == "_Save")
.Enter ()
.WriteOutLogs (_out)
.Then (() => Assert.False (sd.Canceled))
.Then (() => AssertIsFileSystemRoot (fs, sd))
.Stop ();
Assert.False (sd.Canceled);
AssertIsFileSystemRoot (fs,sd);
}
private void AssertIsFileSystemRoot (IFileSystem fs, SaveDialog sd)
@@ -155,43 +153,40 @@ public class FileDialogFluentTests
[ClassData (typeof (V2TestDrivers))]
public void SaveFileDialog_PressingPopTree_ShouldNotChangeCancel (V2TestDriver d)
{
var sd = new SaveDialog (CreateExampleFileSystem ()) { Modal = true };
var sd = new SaveDialog (CreateExampleFileSystem ()) { Modal = false };
using var c = With.A (sd, 100, 20, d)
.ScreenShot ("Save dialog", _out)
.AssertTrue (sd.Canceled)
.Then (() => Assert.True (sd.Canceled))
.Focus<Button> (b => b.Text == "►►")
.Enter ()
.ScreenShot ("After pop tree", _out)
.AssertTrue (sd.Canceled)
.WriteOutLogs (_out)
.Then (() => Assert.True (sd.Canceled))
.Stop ();
Assert.True(sd.Canceled);
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void SaveFileDialog_PopTree_AndNavigate (V2TestDriver d)
{
var sd = new SaveDialog (CreateExampleFileSystem ()) { Modal = true };
var sd = new SaveDialog (CreateExampleFileSystem ()) { Modal = false };
using var c = With.A (sd, 100, 20, d)
.ScreenShot ("Save dialog", _out)
.AssertTrue (sd.Canceled)
.LeftClick <Button> (b => b.Text == "►►")
.Then (() => Assert.True (sd.Canceled))
.LeftClick<Button> (b => b.Text == "►►")
.ScreenShot ("After pop tree", _out)
.Focus <TreeView<IFileSystemInfo>> (_ => true)
.Focus<TreeView<IFileSystemInfo>> (_ => true)
.Right ()
.ScreenShot ("After expand tree", _out)
.Down ()
.ScreenShot ("After navigate down in tree", _out)
.Enter ()
.WaitIteration ()
.AssertFalse (sd.Canceled)
.Then (() => Assert.False (sd.Canceled))
.AssertContains ("empty-dir", sd.FileName)
.WriteOutLogs (_out)
.Stop ();
Assert.False (sd.Canceled);
}
}

View File

@@ -0,0 +1,509 @@
using System.Reflection;
using Terminal.Gui;
using TerminalGuiFluentTesting;
using Xunit.Abstractions;
namespace IntegrationTests.FluentTests;
/// <summary>
/// Tests for the MenuBarv2 class
/// </summary>
public class MenuBarv2Tests
{
private readonly TextWriter _out;
public MenuBarv2Tests (ITestOutputHelper outputHelper)
{
_out = new TestOutputWriter (outputHelper);
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void Initializes_WithNoItems (V2TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d)
.Then (
() =>
{
// Create a menu bar with no items
var menuBar = new MenuBarv2 ();
Assert.Empty (menuBar.SubViews);
Assert.False (menuBar.CanFocus);
Assert.Equal (Orientation.Horizontal, menuBar.Orientation);
Assert.Equal (Key.F9, MenuBarv2.DefaultKey);
})
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void Initializes_WithItems (V2TestDriver d)
{
MenuBarItemv2 [] menuItems = [];
using GuiTestContext c = With.A<Window> (80, 25, d)
.Then (
() =>
{
// Create items for the menu bar
menuItems =
[
new (
"_File",
[
new MenuItemv2 ("_Open", "Opens a file", () => { })
]),
new (
"_Edit",
[
new MenuItemv2 ("_Copy", "Copies selection", () => { })
])
];
var menuBar = new MenuBarv2 (menuItems);
Assert.Equal (2, menuBar.SubViews.Count);
// First item should be the File menu
var fileMenu = menuBar.SubViews.ElementAt (0) as MenuBarItemv2;
Assert.NotNull (fileMenu);
Assert.Equal ("_File", fileMenu.Title);
// Second item should be the Edit menu
var editMenu = menuBar.SubViews.ElementAt (1) as MenuBarItemv2;
Assert.NotNull (editMenu);
Assert.Equal ("_Edit", editMenu.Title);
})
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void AddsItems_WithMenusProperty (V2TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d)
.Then (
() =>
{
var menuBar = new MenuBarv2 ();
// Set items through Menus property
menuBar.Menus =
[
new ("_File"),
new ("_Edit"),
new ("_View")
];
Assert.Equal (3, menuBar.SubViews.Count);
})
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void ChangesKey_RaisesEvent (V2TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d)
.Then (
() =>
{
var menuBar = new MenuBarv2 ();
var oldKeyValue = Key.Empty;
var newKeyValue = Key.Empty;
var eventRaised = false;
menuBar.KeyChanged += (_, args) =>
{
eventRaised = true;
oldKeyValue = args.OldKey;
newKeyValue = args.NewKey;
};
// Default key should be F9
Assert.Equal (Key.F9, menuBar.Key);
// Change key to F1
menuBar.Key = Key.F1;
// Verify event was raised
Assert.True (eventRaised);
Assert.Equal (Key.F9, oldKeyValue);
Assert.Equal (Key.F1, newKeyValue);
// Verify key was changed
Assert.Equal (Key.F1, menuBar.Key);
})
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void DefaultKey_Activates (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
menuBar = new MenuBarv2 ();
Toplevel top = Application.Top!;
top.Add (
new View ()
{
CanFocus = true,
Id = "focusableView",
});
menuBar.EnableForDesign (ref top);
Application.Top!.Add (menuBar);
})
.WaitIteration ()
.Then (() => Assert.IsNotType<MenuItemv2> (Application.Navigation!.GetFocused ()))
.ScreenShot ("MenuBar initial state", _out)
.RaiseKeyDownEvent (MenuBarv2.DefaultKey)
.WaitIteration ()
.ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
.WriteOutLogs (_out)
.Then (() => Assert.Equal ("_New file", Application.Navigation!.GetFocused ()!.Title))
.Then (() => Assert.True (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.True (menuBar?.IsOpen ()))
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void DefaultKey_DeActivates (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
menuBar = new MenuBarv2 ();
Toplevel top = Application.Top!;
top.Add (
new View ()
{
CanFocus = true,
Id = "focusableView",
});
menuBar.EnableForDesign (ref top);
Application.Top!.Add (menuBar);
})
.WaitIteration ()
.Then (() => Assert.IsNotType<MenuItemv2>(Application.Navigation!.GetFocused()))
.ScreenShot ("MenuBar initial state", _out)
.RaiseKeyDownEvent (MenuBarv2.DefaultKey)
.ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
.Then (() => Assert.Equal ("_New file", Application.Navigation!.GetFocused ()!.Title))
.RaiseKeyDownEvent (MenuBarv2.DefaultKey)
.ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
.Then (() => Assert.IsNotType<MenuItemv2>(Application.Navigation!.GetFocused()))
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void ShowHidePopovers (V2TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d)
.Then (
() =>
{
// Create a menu bar with items that have submenus
var fileMenuItem = new MenuBarItemv2 (
"_File",
[
new MenuItemv2 ("_Open", string.Empty, null),
new MenuItemv2 ("_Save", string.Empty, null)
]);
var menuBar = new MenuBarv2 ([fileMenuItem]);
// Initially, no menu should be open
Assert.False (menuBar.IsOpen ());
Assert.False (menuBar.Active);
// Initialize the menu bar
menuBar.BeginInit ();
menuBar.EndInit ();
// Simulate showing a popover menu by manipulating the first menu item
MethodInfo? showPopoverMethod = typeof (MenuBarv2).GetMethod (
"ShowPopover",
BindingFlags.NonPublic | BindingFlags.Instance);
// Set menu bar to active state using reflection
FieldInfo? activeField = typeof (MenuBarv2).GetField (
"_active",
BindingFlags.NonPublic | BindingFlags.Instance);
activeField?.SetValue (menuBar, true);
menuBar.CanFocus = true;
// Show the popover menu
showPopoverMethod?.Invoke (menuBar, new object? [] { fileMenuItem });
// Should be active now
Assert.True (menuBar.Active);
// Test if we can hide the popover menu
fileMenuItem.PopoverMenu!.Visible = true;
Assert.True (menuBar.HideActiveItem ());
// Menu should no longer be open or active
Assert.False (menuBar.Active);
Assert.False (menuBar.IsOpen ());
Assert.False (menuBar.CanFocus);
})
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void EnableForDesign_CreatesMenuItems (V2TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d)
.Then (
() =>
{
var menuBar = new MenuBarv2 ();
Application.Top!.Add (menuBar);
// Call EnableForDesign
Toplevel top = Application.Top!;
bool result = menuBar.EnableForDesign (ref top);
// Should return true
Assert.True (result);
// Should have created menu items
Assert.True (menuBar.SubViews.Count > 0);
// Should have File, Edit and Help menus
View? fileMenu = menuBar.SubViews.FirstOrDefault (v => (v as MenuBarItemv2)?.Title == "_File");
View? editMenu = menuBar.SubViews.FirstOrDefault (v => (v as MenuBarItemv2)?.Title == "_Edit");
View? helpMenu = menuBar.SubViews.FirstOrDefault (v => (v as MenuBarItemv2)?.Title == "_Help");
Assert.NotNull (fileMenu);
Assert.NotNull (editMenu);
Assert.NotNull (helpMenu);
})
.ScreenShot ("MenuBarv2 EnableForDesign", _out)
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void Navigation_Left_Right_Wraps (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
menuBar = new MenuBarv2 ();
Toplevel top = Application.Top!;
menuBar.EnableForDesign (ref top);
Application.Top!.Add (menuBar);
})
.WaitIteration ()
.ScreenShot ("MenuBar initial state", _out)
.RaiseKeyDownEvent (MenuBarv2.DefaultKey)
.Then (() => Assert.True (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.True (menuBar?.IsOpen ()))
.Then (() => Assert.Equal ("_New file", Application.Navigation?.GetFocused ()!.Title))
.ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
.Right ()
.Then (() => Assert.True (Application.Popover?.GetActivePopover () is PopoverMenu))
.ScreenShot ("After right arrow", _out)
.Then (() => Assert.Equal ("Cu_t", Application.Navigation?.GetFocused ()!.Title))
.Right ()
.ScreenShot ("After second right arrow", _out)
.Then (() => Assert.Equal ("_Online Help...", Application.Navigation?.GetFocused ()!.Title))
.ScreenShot ("After third right arrow", _out)
.Right ()
.ScreenShot ("After fourth right arrow", _out)
.Then (() => Assert.Equal ("_New file", Application.Navigation?.GetFocused ()!.Title))
.Left ()
.ScreenShot ("After left arrow", _out)
.Then (() => Assert.Equal ("_Online Help...", Application.Navigation?.GetFocused ()!.Title))
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void MenuBarItem_With_QuitKey_Open_QuitKey_Restores_Focus_Correctly (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
menuBar = new MenuBarv2 ();
Toplevel top = Application.Top!;
top.Add (
new View ()
{
CanFocus = true,
Id = "focusableView",
});
menuBar.EnableForDesign (ref top);
Application.Top!.Add (menuBar);
})
.WaitIteration ()
.Then (() => Assert.IsNotType<MenuItemv2>(Application.Navigation!.GetFocused()))
.ScreenShot ("MenuBar initial state", _out)
.RaiseKeyDownEvent (MenuBarv2.DefaultKey)
.Then (() => Assert.Equal ("_New file", Application.Navigation!.GetFocused ()!.Title))
.Then (() => Assert.True (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.True (menuBar?.IsOpen ()))
.Then (() => Assert.Equal ("_New file", Application.Navigation?.GetFocused ()!.Title))
.ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
.RaiseKeyDownEvent (Application.QuitKey)
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.IsNotType<MenuItemv2> (Application.Navigation!.GetFocused ()))
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void MenuBarItem_Without_QuitKey_Open_QuitKey_Restores_Focus_Correctly (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
menuBar = new MenuBarv2 ();
Toplevel top = Application.Top!;
top.Add (
new View ()
{
CanFocus = true,
Id = "focusableView",
});
menuBar.EnableForDesign (ref top);
Application.Top!.Add (menuBar);
})
.WaitIteration ()
.Then (() => Assert.IsNotType<MenuItemv2> (Application.Navigation!.GetFocused ()))
.ScreenShot ("MenuBar initial state", _out)
.RaiseKeyDownEvent (MenuBarv2.DefaultKey)
.RaiseKeyDownEvent (Key.CursorRight)
.Then (() => Assert.Equal ("Cu_t", Application.Navigation!.GetFocused ()!.Title))
.Then (() => Assert.True (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.True (menuBar?.IsOpen ()))
.Then (() => Assert.Equal ("Cu_t", Application.Navigation?.GetFocused ()!.Title))
.ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
.RaiseKeyDownEvent (Application.QuitKey)
.WriteOutLogs (_out)
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.IsNotType<MenuItemv2> (Application.Navigation!.GetFocused ()))
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void MenuBarItem_With_QuitKey_Open_QuitKey_Does_Not_Quit_App (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
menuBar = new MenuBarv2 ();
Toplevel top = Application.Top!;
top.Add (
new View ()
{
CanFocus = true,
Id = "focusableView",
});
menuBar.EnableForDesign (ref top);
Application.Top!.Add (menuBar);
})
.WaitIteration ()
.Then (() => Assert.IsNotType<MenuItemv2> (Application.Navigation!.GetFocused ()))
.ScreenShot ("MenuBar initial state", _out)
.RaiseKeyDownEvent (MenuBarv2.DefaultKey)
.Then (() => Assert.Equal ("_New file", Application.Navigation!.GetFocused ()!.Title))
.Then (() => Assert.True (Application.Top!.Running))
.ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
.RaiseKeyDownEvent (Application.QuitKey)
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.True (Application.Top!.Running))
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void MenuBarItem_Without_QuitKey_Open_QuitKey_Does_Not_Quit_MenuBar_SuperView (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
menuBar = new MenuBarv2 ();
Toplevel top = Application.Top!;
top.Add (
new View ()
{
CanFocus = true,
Id = "focusableView",
});
menuBar.EnableForDesign (ref top);
IEnumerable<MenuItemv2> items = menuBar.GetMenuItemsWithTitle ("_Quit");
foreach (MenuItemv2 item in items)
{
item.Key = Key.Empty;
}
Application.Top!.Add (menuBar);
})
.WaitIteration ()
.Then (() => Assert.IsNotType<MenuItemv2> (Application.Navigation!.GetFocused ()))
.ScreenShot ("MenuBar initial state", _out)
.RaiseKeyDownEvent (MenuBarv2.DefaultKey)
.Then (() => Assert.Equal ("_New file", Application.Navigation!.GetFocused ()!.Title))
.ScreenShot ($"After {MenuBarv2.DefaultKey}", _out)
.RaiseKeyDownEvent (Application.QuitKey)
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.True (Application.Top!.Running))
.WriteOutLogs (_out)
.Stop ();
}
}

View File

@@ -0,0 +1,243 @@
using System.Reflection;
using Terminal.Gui;
using TerminalGuiFluentTesting;
using Xunit.Abstractions;
namespace IntegrationTests.FluentTests;
/// <summary>
/// Tests for the PopoverMenu class
/// </summary>
public class PopoverMenuTests (ITestOutputHelper outputHelper)
{
private readonly TextWriter _out = new TestOutputWriter (outputHelper);
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void EnableForDesign_CreatesMenuItems (V2TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d)
.Then (
() =>
{
var popoverMenu = new PopoverMenu ();
Application.Top!.Add (popoverMenu);
// Call EnableForDesign
Toplevel top = Application.Top;
bool result = popoverMenu.EnableForDesign (ref top);
// Should return true
Assert.True (result);
// Should have created menu items
Assert.NotNull (popoverMenu.Root);
Assert.Equal (7, popoverMenu.Root.SubViews.Count);
// Should have Cut menu item
View? cutMenuItem = popoverMenu.GetMenuItemsOfAllSubMenus ().FirstOrDefault (v => v?.Title == "Cu_t");
Assert.NotNull (cutMenuItem);
})
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void Activate_Sets_Application_Navigation_Correctly (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
var popoverMenu = new PopoverMenu ();
// Call EnableForDesign
Toplevel top = Application.Top!;
popoverMenu.EnableForDesign (ref top);
View? view = new View ()
{
CanFocus = true,
Height = Dim.Auto (),
Width = Dim.Auto (),
Id = "focusableView",
Text = "View",
};
Application.Top!.Add (view);
// EnableForDesign sets to true; undo that
popoverMenu.Visible = false;
Application.Popover!.Register (popoverMenu);
view.SetFocus ();
})
.WaitIteration ()
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.IsNotType<MenuItemv2> (Application.Navigation!.GetFocused ()))
.ScreenShot ("PopoverMenu initial state", _out)
.Then (() => Application.Popover!.Show (Application.Popover.Popovers.First ()))
.WaitIteration ()
.ScreenShot ($"After Show", _out)
.Then (() => Assert.True (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.Equal ("Cu_t", Application.Navigation!.GetFocused ()!.Title))
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void QuitKey_Hides (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
var popoverMenu = new PopoverMenu ();
// Call EnableForDesign
Toplevel top = Application.Top!;
bool result = popoverMenu.EnableForDesign (ref top);
View? view = new View ()
{
CanFocus = true,
Height = Dim.Auto (),
Width = Dim.Auto (),
Id = "focusableView",
Text = "View",
};
Application.Top!.Add (view);
// EnableForDesign sets to true; undo that
popoverMenu.Visible = false;
Application.Popover!.Register (popoverMenu);
view.SetFocus ();
})
.WaitIteration ()
.ScreenShot ("PopoverMenu initial state", _out)
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Application.Popover!.Show (Application.Popover.Popovers.First ()))
.WaitIteration ()
.ScreenShot ($"After Show", _out)
.Then (() => Assert.True (Application.Popover?.GetActivePopover () is PopoverMenu))
.RaiseKeyDownEvent (Application.QuitKey)
.Then (() => Application.LayoutAndDraw (true))
.WaitIteration ()
.WriteOutLogs (_out)
.ScreenShot ($"After {Application.QuitKey}", _out)
.Then (() => Assert.False (Application.Popover!.Popovers.Cast<PopoverMenu> ().FirstOrDefault()!.Visible))
.Then (() => Assert.Null (Application.Popover!.GetActivePopover()))
.Then (() => Assert.True (Application.Top!.Running))
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void QuitKey_Restores_Focus_Correctly (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
var popoverMenu = new PopoverMenu ();
// Call EnableForDesign
Toplevel top = Application.Top!;
bool result = popoverMenu.EnableForDesign (ref top);
View? view = new View ()
{
CanFocus = true,
Height = Dim.Auto (),
Width = Dim.Auto (),
Id = "focusableView",
Text = "View",
};
Application.Top!.Add (view);
// EnableForDesign sets to true; undo that
popoverMenu.Visible = false;
Application.Popover!.Register (popoverMenu);
view.SetFocus ();
})
.WaitIteration ()
.ScreenShot ("PopoverMenu initial state", _out)
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.IsNotType<MenuItemv2>(Application.Navigation!.GetFocused()))
.Then (() => Application.Popover!.Show (Application.Popover.Popovers.First ()))
.WaitIteration ()
.ScreenShot ($"After Show", _out)
.Then (() => Assert.True (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.IsType<MenuItemv2>(Application.Navigation!.GetFocused()))
.RaiseKeyDownEvent (Application.QuitKey)
.ScreenShot ($"After {Application.QuitKey}", _out)
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.IsNotType<MenuItemv2>(Application.Navigation!.GetFocused()))
.WriteOutLogs (_out)
.Stop ();
}
[Theory]
[ClassData (typeof (V2TestDrivers))]
public void MenuBarItem_With_QuitKey_Open_QuitKey_Does_Not_Quit_App (V2TestDriver d)
{
MenuBarv2? menuBar = null;
using GuiTestContext c = With.A<Window> (50, 20, d)
.Then (
() =>
{
var popoverMenu = new PopoverMenu ();
// Call EnableForDesign
Toplevel top = Application.Top!;
bool result = popoverMenu.EnableForDesign (ref top);
View? view = new View ()
{
CanFocus = true,
Height = Dim.Auto (),
Width = Dim.Auto (),
Id = "focusableView",
Text = "View",
};
Application.Top!.Add (view);
// EnableForDesign sets to true; undo that
popoverMenu.Visible = false;
Application.Popover!.Register (popoverMenu);
view.SetFocus ();
})
.WaitIteration ()
.Then (() => Assert.IsNotType<MenuItemv2>(Application.Navigation!.GetFocused()))
.ScreenShot ("PopoverMenu initial state", _out)
.Then (() => Application.Popover!.Show (Application.Popover.Popovers.First ()))
.WaitIteration ()
.ScreenShot ("PopoverMenu after Show", _out)
.Then (() => Assert.Equal ("Cu_t", Application.Navigation!.GetFocused ()!.Title))
.Then (() => Assert.True (Application.Top!.Running))
.RaiseKeyDownEvent (Application.QuitKey)
.Then (() => Application.LayoutAndDraw ())
.ScreenShot ($"After {Application.QuitKey}", _out)
.Then (() => Assert.False (Application.Popover?.GetActivePopover () is PopoverMenu))
.Then (() => Assert.True (Application.Top!.Running))
.WriteOutLogs (_out)
.Stop ();
}
}

View File

@@ -13,7 +13,7 @@ public class ScenarioTests : TestsAllViews
public ScenarioTests (ITestOutputHelper output)
{
#if DEBUG_IDISPOSABLE
View.DebugIDisposable = true;
View.EnableDebugIDisposableAsserts = true;
View.Instances.Clear ();
#endif
_output = output;
@@ -44,11 +44,12 @@ public class ScenarioTests : TestsAllViews
_output.WriteLine ($"Running Scenario '{scenarioType}'");
var scenario = Activator.CreateInstance (scenarioType) as Scenario;
uint abortTime = 1500;
uint abortTime = 2000;
object? timeout = null;
var initialized = false;
var shutdown = false;
var shutdownGracefully = false;
var iterationCount = 0;
Key quitKey = Application.QuitKey;
Application.InitializedChanged += OnApplicationOnInitializedChanged;
@@ -69,7 +70,9 @@ public class ScenarioTests : TestsAllViews
}
Assert.True (initialized);
Assert.True (shutdown);
Assert.True (shutdownGracefully, $"Scenario Failed to Quit with {quitKey} after {abortTime}ms and {iterationCount} iterations. Force quit.");
#if DEBUG_IDISPOSABLE
Assert.Empty (View.Instances);
@@ -101,13 +104,13 @@ public class ScenarioTests : TestsAllViews
else
{
Application.Iteration -= OnApplicationOnIteration;
shutdown = true;
shutdownGracefully = true;
}
_output.WriteLine ($"Initialized == {a.CurrentValue}");
_output.WriteLine ($"Initialized == {a.CurrentValue}; shutdownGracefully == {shutdownGracefully}.");
}
// If the scenario doesn't close within 500ms, this will force it to quit
// If the scenario doesn't close within abortTime ms, this will force it to quit
bool ForceCloseCallback ()
{
lock (_timeoutLock)
@@ -118,9 +121,6 @@ public class ScenarioTests : TestsAllViews
}
}
Assert.Fail (
$"Scenario Failed to Quit with {Application.QuitKey} after {abortTime}ms and {iterationCount} iterations. Force quit.");
// Restore the configuration locations
ConfigurationManager.Locations = savedConfigLocations;
ConfigurationManager.Reset ();
@@ -137,8 +137,9 @@ public class ScenarioTests : TestsAllViews
if (Application.Initialized)
{
// Press QuitKey
_output.WriteLine ($"Attempting to quit with {Application.QuitKey}");
Application.RaiseKeyDownEvent (Application.QuitKey);
quitKey = Application.QuitKey;
_output.WriteLine ($"Attempting to quit with {quitKey} after {iterationCount} iterations.");
Application.RaiseKeyDownEvent (quitKey);
}
}
}
@@ -171,7 +172,7 @@ public class ScenarioTests : TestsAllViews
var top = new Toplevel ();
Dictionary<string, Type> viewClasses = GetAllViewClasses().ToDictionary (t => t.Name);
Dictionary<string, Type> viewClasses = GetAllViewClasses ().ToDictionary (t => t.Name);
Window leftPane = new ()
{
@@ -277,7 +278,7 @@ public class ScenarioTests : TestsAllViews
classListView.SelectedItemChanged += (s, args) =>
{
// Remove existing class, if any
if (curView is {})
if (curView is { })
{
curView.SubViewsLaidOut -= LayoutCompleteHandler;
hostPane.Remove (curView);
@@ -357,10 +358,13 @@ public class ScenarioTests : TestsAllViews
{
classListView.MoveDown ();
Assert.Equal (
curView!.GetType ().Name,
viewClasses.Values.ToArray () [classListView.SelectedItem].Name
);
if (curView is { })
{
Assert.Equal (
curView.GetType ().Name,
viewClasses.Values.ToArray () [classListView.SelectedItem].Name
);
}
}
else
{
@@ -507,12 +511,26 @@ public class ScenarioTests : TestsAllViews
// For each of the <T> arguments
List<Type> typeArguments = new ();
// use <object>
// use <object> or the original type if applicable
foreach (Type arg in type.GetGenericArguments ())
{
typeArguments.Add (typeof (object));
if (arg.IsValueType && Nullable.GetUnderlyingType (arg) == null)
{
typeArguments.Add (arg);
}
else
{
typeArguments.Add (typeof (object));
}
}
// Ensure the type does not contain any generic parameters
if (type.ContainsGenericParameters)
{
Logging.Warning ($"Cannot create an instance of {type} because it contains generic parameters.");
//throw new ArgumentException ($"Cannot create an instance of {type} because it contains generic parameters.");
return null;
}
// And change what type we are instantiating from MyClass<T> to MyClass<object>
type = type.MakeGenericType (typeArguments.ToArray ());
}