using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using PolyTrader.Core.Modularity; using Xunit; namespace PolyTrader.Tests { /// Sicherheitsnetz für das gemeinsame „Fenster"-Menü (Slice 1): Inhalt + Verhalten. public class WindowMenuTests { private sealed class FakeUiHost : IModuleUiHost { public List ViewList { get; } = new(); public HashSet OpenIds { get; } = new(); public List Opened { get; } = new(); public bool MainActivated { get; private set; } public bool ShutdownRequested { get; private set; } public IReadOnlyList Views => ViewList; public bool IsOpen(string viewId) => OpenIds.Contains(viewId); public void OpenView(string viewId) => Opened.Add(viewId); public void ActivateMain() => MainActivated = true; public void RequestShutdown() => ShutdownRequested = true; public void RegisterView(ModuleView view) => ViewList.Add(view); public event Action? OpenStateChanged { add { } remove { } } } private static FakeUiHost Host() { var h = new FakeUiHost(); h.RegisterView(new ModuleView { Id = "core.dashboard", Title = "Dashboard", Order = 1 }); h.RegisterView(new ModuleView { Id = "core.terminal", Title = "Terminal / Logs", Order = 2 }); h.OpenIds.Add("core.terminal"); // Terminal ist offen return h; } [Fact] public void Populate_lists_launcher_views_and_exit_side_by_side() { var host = Host(); var menu = new MenuStrip(); // currentViewId == null => Launcher (Hauptprozess): rechte Aktion ist „Beenden". WindowMenu.Populate(menu, host, currentViewId: null); var texts = menu.Items.OfType().Select(i => i.Text).ToList(); Assert.Equal("Launcher", texts[0]); // Launcher als erster Top-Level-Eintrag Assert.Contains("Dashboard", texts); Assert.Contains("Terminal / Logs", texts); Assert.Contains("Beenden", texts); } [Fact] public void Non_launcher_window_offers_close_window_not_exit() { var host = Host(); var menu = new MenuStrip(); // currentViewId != null => Modul-/Core-Fenster: KEIN „Beenden", nur „Fenster schließen". WindowMenu.Populate(menu, host, currentViewId: "core.dashboard"); var texts = menu.Items.OfType().Select(i => i.Text).ToList(); Assert.Contains("Fenster schließen", texts); Assert.DoesNotContain("Beenden", texts); // Klick auf „Fenster schließen" fordert NICHT das App-Shutdown an. menu.Items.OfType().First(i => i.Text == "Fenster schließen").PerformClick(); Assert.False(host.ShutdownRequested); } [Fact] public void Views_carry_their_icon_in_the_menu() { var host = new FakeUiHost(); using var icon = new System.Drawing.Bitmap(16, 16); host.RegisterView(new ModuleView { Id = "core.dashboard", Title = "Dashboard", Order = 1, Icon = icon }); var menu = new MenuStrip(); WindowMenu.Populate(menu, host, currentViewId: null); var dashboard = menu.Items.OfType().First(i => i.Text == "Dashboard"); Assert.Same(icon, dashboard.Image); Assert.Equal(ToolStripItemDisplayStyle.ImageAndText, dashboard.DisplayStyle); } [Fact] public void Current_view_is_bold_and_checked_open_view_is_checked() { var host = Host(); var menu = new MenuStrip(); WindowMenu.Populate(menu, host, currentViewId: "core.dashboard"); var dashboard = menu.Items.OfType().First(i => i.Text == "Dashboard"); var terminal = menu.Items.OfType().First(i => i.Text == "Terminal / Logs"); Assert.True(dashboard.Checked); // aktuelles Fenster Assert.True(dashboard.Font.Bold); Assert.True(terminal.Checked); // offenes Fenster Assert.False(terminal.Font.Bold); } [Fact] public void Clicking_items_navigates() { var host = Host(); var menu = new MenuStrip(); WindowMenu.Populate(menu, host, currentViewId: null); var items = menu.Items.OfType().ToList(); items.First(i => i.Text == "Launcher").PerformClick(); items.First(i => i.Text == "Terminal / Logs").PerformClick(); Assert.True(host.MainActivated); Assert.Contains("core.terminal", host.Opened); } [Fact] public void Clicking_exit_requests_shutdown_not_immediate_exit() { var host = Host(); var menu = new MenuStrip(); WindowMenu.Populate(menu, host, currentViewId: null); menu.Items.OfType().First(i => i.Text == "Beenden").PerformClick(); Assert.True(host.ShutdownRequested); } } }