R1: Umbau auf Multi-Projekt-Struktur (Vorbild PolytraderSharp) Kurskorrektur: Vorbild ist PolytraderSharp (C#), nicht die veraltete Python-Version. Reiner Strukturumbau, Verhalten unveraendert. - src/IBKRTrader.Core (classlib): Core-Code + UI-Contract (ModuleFormBase, WindowManager) - src/IBKRTrader.Modules.CongressTrading (classlib, referenziert nur Core) - Root: IBKRTrader.App (WinExe) referenziert Core + Modul - tests/IBKRTrader.Tests: Referenzen auf Core + Modul - Neue .slnx; ungenutztes HtmlAgilityPack entfernt - docs/ARCHITECTURE.md: korrigierter Ziel-Stand + R-Phasenplan - Build + 38/38 Tests gruen; App startet Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
101 lines
2.7 KiB
C#
101 lines
2.7 KiB
C#
using FluentAssertions;
|
|
using IBKRTrader.UI;
|
|
|
|
namespace IBKRTrader.Tests.UI;
|
|
|
|
[Trait("cat", "unit")]
|
|
public class WindowManagerTests
|
|
{
|
|
/// <summary>
|
|
/// Testbare Variante: unterdrückt echte Show-/Focus-Aufrufe (kein Message-Loop),
|
|
/// zählt aber die Focus-Aufrufe.
|
|
/// </summary>
|
|
private sealed class TestWindowManager : WindowManager
|
|
{
|
|
public int FocusCount;
|
|
protected override void Present(Form form) { /* kein Show im Test */ }
|
|
protected override void Focus(Form form) => FocusCount++;
|
|
}
|
|
|
|
[Fact]
|
|
public void OpenOrFocus_NewKey_InvokesFactory_AndTracks()
|
|
{
|
|
var wm = new TestWindowManager();
|
|
var created = 0;
|
|
|
|
using var form = wm.OpenOrFocus("CT", () => { created++; return new Form(); });
|
|
|
|
created.Should().Be(1);
|
|
wm.IsOpen("CT").Should().BeTrue();
|
|
wm.OpenCount.Should().Be(1);
|
|
}
|
|
|
|
[Fact]
|
|
public void OpenOrFocus_SameKey_FocusesExisting_DoesNotRecreate()
|
|
{
|
|
var wm = new TestWindowManager();
|
|
var created = 0;
|
|
|
|
using var first = wm.OpenOrFocus("CT", () => { created++; return new Form(); });
|
|
var second = wm.OpenOrFocus("CT", () => { created++; return new Form(); });
|
|
|
|
created.Should().Be(1);
|
|
wm.FocusCount.Should().Be(1);
|
|
second.Should().BeSameAs(first);
|
|
wm.OpenCount.Should().Be(1);
|
|
}
|
|
|
|
[Fact]
|
|
public void OpenOrFocus_DifferentKeys_TracksSeparately()
|
|
{
|
|
var wm = new TestWindowManager();
|
|
|
|
using var a = wm.OpenOrFocus("A", () => new Form());
|
|
using var b = wm.OpenOrFocus("B", () => new Form());
|
|
|
|
wm.OpenCount.Should().Be(2);
|
|
wm.IsOpen("A").Should().BeTrue();
|
|
wm.IsOpen("B").Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void OpenOrFocus_AfterDisposed_RecreatesWindow()
|
|
{
|
|
var wm = new TestWindowManager();
|
|
var created = 0;
|
|
|
|
var first = wm.OpenOrFocus("CT", () => { created++; return new Form(); });
|
|
first.Dispose();
|
|
|
|
wm.IsOpen("CT").Should().BeFalse();
|
|
|
|
using var second = wm.OpenOrFocus("CT", () => { created++; return new Form(); });
|
|
|
|
created.Should().Be(2);
|
|
second.Should().NotBeSameAs(first);
|
|
}
|
|
|
|
[Fact]
|
|
public void CloseAll_RemovesAllWindows()
|
|
{
|
|
var wm = new TestWindowManager();
|
|
wm.OpenOrFocus("A", () => new Form());
|
|
wm.OpenOrFocus("B", () => new Form());
|
|
|
|
wm.CloseAll();
|
|
|
|
wm.OpenCount.Should().Be(0);
|
|
wm.IsOpen("A").Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void OpenOrFocus_BlankKey_Throws()
|
|
{
|
|
var wm = new TestWindowManager();
|
|
|
|
var act = () => wm.OpenOrFocus(" ", () => new Form());
|
|
|
|
act.Should().Throw<ArgumentException>();
|
|
}
|
|
}
|