mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Fixed UICatalog bugs. Added fluent tests.
This commit is contained in:
@@ -327,7 +327,7 @@ public class MenuBarv2 : Menuv2, IDesignable
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool EnableForDesign<TContext> (ref readonly TContext context) where TContext : notnull
|
||||
public override bool EnableForDesign ()
|
||||
{
|
||||
Add (
|
||||
new MenuBarItemv2 (
|
||||
|
||||
297
Tests/IntegrationTests/FluentTests/MenuBarv2Tests.cs
Normal file
297
Tests/IntegrationTests/FluentTests/MenuBarv2Tests.cs
Normal file
@@ -0,0 +1,297 @@
|
||||
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 BasicFluentAssertionTests.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.Equal (0, menuBar.SubViews.Count);
|
||||
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 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.IsActive ());
|
||||
|
||||
// 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.IsActive ());
|
||||
|
||||
// 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.IsActive ());
|
||||
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
|
||||
bool result = menuBar.EnableForDesign ();
|
||||
|
||||
// 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_BetweenItems (V2TestDriver d)
|
||||
{
|
||||
var menuBarActivated = false;
|
||||
|
||||
using GuiTestContext c = With.A<Window> (80, 25, d)
|
||||
.Then (
|
||||
() =>
|
||||
{
|
||||
// Create menu items
|
||||
var fileMenu = new MenuBarItemv2 (
|
||||
"_File",
|
||||
[
|
||||
new MenuItemv2 ("_Open", string.Empty, null),
|
||||
new MenuItemv2 ("_Save", string.Empty, null)
|
||||
]);
|
||||
|
||||
var editMenu = new MenuBarItemv2 (
|
||||
"_Edit",
|
||||
[
|
||||
new MenuItemv2 ("_Cut", string.Empty, null),
|
||||
new MenuItemv2 ("_Copy", string.Empty, null)
|
||||
]);
|
||||
|
||||
// Create menu bar and add to window
|
||||
var menuBar = new MenuBarv2 ([fileMenu, editMenu]);
|
||||
Application.Top.Add (menuBar);
|
||||
|
||||
// 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;
|
||||
menuBarActivated = true;
|
||||
|
||||
// Give focus to the first menu item
|
||||
fileMenu.SetFocus ();
|
||||
Assert.True (fileMenu.HasFocus);
|
||||
|
||||
Application.LayoutAndDraw ();
|
||||
})
|
||||
.ScreenShot ("MenuBar initial state", _out)
|
||||
.Then (
|
||||
() =>
|
||||
{
|
||||
if (!menuBarActivated)
|
||||
{
|
||||
// Skip further tests if activation failed
|
||||
}
|
||||
|
||||
// Move right to select the edit menu
|
||||
// This simulates navigation between menu items
|
||||
})
|
||||
.Right ()
|
||||
.ScreenShot ("After right arrow", _out)
|
||||
.Right ()
|
||||
.ScreenShot ("After second right arrow (should wrap)", _out)
|
||||
.Left ()
|
||||
.ScreenShot ("After left arrow", _out)
|
||||
.WriteOutLogs (_out)
|
||||
.Stop ();
|
||||
}
|
||||
}
|
||||
@@ -462,7 +462,7 @@ public class MessageBoxTests
|
||||
{
|
||||
MessageBox.Query (
|
||||
"",
|
||||
UICatalog.UICatalogTopLevel.GetAboutBoxMessage (),
|
||||
UICatalog.UICatalogTop.GetAboutBoxMessage (),
|
||||
wrapMessage: false,
|
||||
buttons: "_Ok"
|
||||
);
|
||||
|
||||
@@ -4146,7 +4146,7 @@ Nice Work")]
|
||||
{
|
||||
TextFormatter tf = new ()
|
||||
{
|
||||
Text = UICatalog.UICatalogTopLevel.GetAboutBoxMessage (),
|
||||
Text = UICatalog.UICatalogTop.GetAboutBoxMessage (),
|
||||
Alignment = Alignment.Center,
|
||||
VerticalAlignment = Alignment.Start,
|
||||
WordWrap = false,
|
||||
|
||||
@@ -61,8 +61,8 @@ public class UICatalog
|
||||
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
|
||||
}
|
||||
|
||||
UICatalogTopLevel.CachedScenarios = Scenario.GetScenarios ();
|
||||
UICatalogTopLevel.CachedCategories = Scenario.GetAllCategories ();
|
||||
UICatalogTop.CachedScenarios = Scenario.GetScenarios ();
|
||||
UICatalogTop.CachedCategories = Scenario.GetAllCategories ();
|
||||
|
||||
// Process command line args
|
||||
|
||||
@@ -108,7 +108,7 @@ public class UICatalog
|
||||
"The name of the Scenario to run. If not provided, the UI Catalog UI will be shown.",
|
||||
getDefaultValue: () => "none"
|
||||
).FromAmong (
|
||||
UICatalogTopLevel.CachedScenarios.Select (s => s.GetName ())
|
||||
UICatalogTop.CachedScenarios.Select (s => s.GetName ())
|
||||
.Append ("none")
|
||||
.ToArray ()
|
||||
);
|
||||
@@ -217,20 +217,20 @@ public class UICatalog
|
||||
|
||||
Application.Init (driverName: _forceDriver);
|
||||
|
||||
if (string.IsNullOrWhiteSpace (UICatalogTopLevel.CachedTheme))
|
||||
if (string.IsNullOrWhiteSpace (UICatalogTop.CachedTheme))
|
||||
{
|
||||
UICatalogTopLevel.CachedTheme = Themes?.Theme;
|
||||
UICatalogTop.CachedTheme = Themes?.Theme;
|
||||
}
|
||||
else
|
||||
{
|
||||
Themes!.Theme = UICatalogTopLevel.CachedTheme;
|
||||
Themes!.Theme = UICatalogTop.CachedTheme;
|
||||
Apply ();
|
||||
}
|
||||
|
||||
Application.Run<UICatalogTopLevel> ().Dispose ();
|
||||
Application.Run<UICatalogTop> ().Dispose ();
|
||||
Application.Shutdown ();
|
||||
|
||||
return UICatalogTopLevel.CachedSelectedScenario!;
|
||||
return UICatalogTop.CachedSelectedScenario!;
|
||||
}
|
||||
|
||||
[SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
|
||||
@@ -323,15 +323,15 @@ public class UICatalog
|
||||
// run it and exit when done.
|
||||
if (options.Scenario != "none")
|
||||
{
|
||||
int item = UICatalogTopLevel.CachedScenarios!.IndexOf (
|
||||
UICatalogTopLevel.CachedScenarios!.FirstOrDefault (
|
||||
int item = UICatalogTop.CachedScenarios!.IndexOf (
|
||||
UICatalogTop.CachedScenarios!.FirstOrDefault (
|
||||
s =>
|
||||
s.GetName ()
|
||||
.Equals (options.Scenario, StringComparison.OrdinalIgnoreCase)
|
||||
)!);
|
||||
UICatalogTopLevel.CachedSelectedScenario = (Scenario)Activator.CreateInstance (UICatalogTopLevel.CachedScenarios [item].GetType ())!;
|
||||
UICatalogTop.CachedSelectedScenario = (Scenario)Activator.CreateInstance (UICatalogTop.CachedScenarios [item].GetType ())!;
|
||||
|
||||
BenchmarkResults? results = RunScenario (UICatalogTopLevel.CachedSelectedScenario, options.Benchmark);
|
||||
BenchmarkResults? results = RunScenario (UICatalogTop.CachedSelectedScenario, options.Benchmark);
|
||||
|
||||
if (results is { })
|
||||
{
|
||||
@@ -360,9 +360,9 @@ public class UICatalog
|
||||
while (RunUICatalogTopLevel () is { } scenario)
|
||||
{
|
||||
VerifyObjectsWereDisposed ();
|
||||
Themes!.Theme = UICatalogTopLevel.CachedTheme!;
|
||||
Themes!.Theme = UICatalogTop.CachedTheme!;
|
||||
Apply ();
|
||||
scenario.TopLevelColorScheme = UICatalogTopLevel.CachedTopLevelColorScheme!;
|
||||
scenario.TopLevelColorScheme = UICatalogTop.CachedTopLevelColorScheme!;
|
||||
|
||||
#if DEBUG_IDISPOSABLE
|
||||
View.DebugIDisposable = true;
|
||||
@@ -412,7 +412,7 @@ public class UICatalog
|
||||
}
|
||||
|
||||
Application.Init (driverName: _forceDriver);
|
||||
scenario.TopLevelColorScheme = UICatalogTopLevel.CachedTopLevelColorScheme!;
|
||||
scenario.TopLevelColorScheme = UICatalogTop.CachedTopLevelColorScheme!;
|
||||
|
||||
if (benchmark)
|
||||
{
|
||||
@@ -442,7 +442,7 @@ public class UICatalog
|
||||
|
||||
var maxScenarios = 5;
|
||||
|
||||
foreach (Scenario s in UICatalogTopLevel.CachedScenarios!)
|
||||
foreach (Scenario s in UICatalogTop.CachedScenarios!)
|
||||
{
|
||||
resultsList.Add (RunScenario (s, true)!);
|
||||
maxScenarios--;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace UICatalog;
|
||||
/// This is the main UI Catalog app view. It is run fresh when the app loads (if a Scenario has not been passed on
|
||||
/// the command line) and each time a Scenario ends.
|
||||
/// </summary>
|
||||
public class UICatalogTopLevel : Toplevel
|
||||
public class UICatalogTop : Toplevel
|
||||
{
|
||||
// When a scenario is run, the main app is killed. The static
|
||||
// members are cached so that when the scenario exits the
|
||||
@@ -32,7 +32,7 @@ public class UICatalogTopLevel : Toplevel
|
||||
// Diagnostics
|
||||
private static ViewDiagnosticFlags _diagnosticFlags;
|
||||
|
||||
public UICatalogTopLevel ()
|
||||
public UICatalogTop ()
|
||||
{
|
||||
_diagnosticFlags = Diagnostics;
|
||||
|
||||
@@ -563,6 +563,7 @@ public class UICatalogTopLevel : Toplevel
|
||||
[JsonPropertyName ("UICatalog.StatusBar")]
|
||||
public static bool ShowStatusBar { get; set; } = true;
|
||||
|
||||
private Shortcut? _shQuit;
|
||||
private Shortcut? _shVersion;
|
||||
private CheckBox? _force16ColorsShortcutCb;
|
||||
|
||||
@@ -582,6 +583,13 @@ public class UICatalogTopLevel : Toplevel
|
||||
maximumContentDim: Dim.Func (() => statusBar.Visible ? 1 : 0));
|
||||
// ReSharper restore All
|
||||
|
||||
_shQuit = new ()
|
||||
{
|
||||
CanFocus = false,
|
||||
Title = "Quit",
|
||||
Key = Application.QuitKey
|
||||
};
|
||||
|
||||
_shVersion = new ()
|
||||
{
|
||||
Title = "Version Info",
|
||||
@@ -616,12 +624,7 @@ public class UICatalogTopLevel : Toplevel
|
||||
};
|
||||
|
||||
statusBar.Add (
|
||||
new Shortcut
|
||||
{
|
||||
CanFocus = false,
|
||||
Title = "Quit",
|
||||
Key = Application.QuitKey
|
||||
},
|
||||
_shQuit,
|
||||
statusBarShortcut,
|
||||
new Shortcut
|
||||
{
|
||||
@@ -648,13 +651,20 @@ public class UICatalogTopLevel : Toplevel
|
||||
|
||||
ColorScheme = Colors.ColorSchemes [CachedTopLevelColorScheme!];
|
||||
|
||||
((Shortcut)_statusBar!.SubViews.ElementAt (0)).Key = Application.QuitKey;
|
||||
_statusBar.Visible = ShowStatusBar;
|
||||
if (_shQuit is { })
|
||||
{
|
||||
_shQuit.Key = Application.QuitKey;
|
||||
}
|
||||
|
||||
if (_statusBar is { })
|
||||
{
|
||||
_statusBar.Visible = ShowStatusBar;
|
||||
}
|
||||
|
||||
_disableMouseCb!.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked;
|
||||
_force16ColorsShortcutCb!.CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
|
||||
|
||||
Application.Top!.SetNeedsDraw ();
|
||||
Application.Top?.SetNeedsDraw ();
|
||||
}
|
||||
|
||||
private void ConfigAppliedHandler (object? sender, ConfigurationManagerEventArgs? a) { ConfigChanged (); }
|
||||
Reference in New Issue
Block a user