test(ui): cover resizable plugin windows through RetailWindowManager + persistence
Extends the resizable="true"/minw/minh markup grammar's coverage past MarkupDocument's own parse tests to the two host seams a resizable plugin panel actually flows through, proving no host-side wiring beyond what MarkupDocument.Build already sets on the panel was needed: - RetailWindowManagerTests: a resizable="true" markup panel accepts RetailWindowManager.ResizeTo within its minw/minh floor (and clamps to it below the floor); a plain (non-resizable) markup panel refuses — Width/Height unchanged and no Resized event, exactly today's fixed-size behavior. - RetailWindowLayoutPersistenceTests: a resizable panel's dragged size round-trips through save/restore into a fresh session, and a saved size below the panel's CURRENT minw/minh floor (a legacy save, or a plugin update that raised its floor) clamps UP to the floor on restore rather than restoring the too-small legacy value. Mutation proof: reverted MarkupDocument.cs to its pre-feature state and reran the new tests — the two RetailWindowManagerTests cases failed (the old UiNineSlicePanel ctor default of Resizable=true/MinWidth=40 let the "fixed" window resize and let the "resizable" window shrink below the new floor), and the persistence floor-clamp case failed (80x60 came back instead of clamping to 200x150). The plain save/restore round-trip case passed either way — the old ctor default was already resizable, so it exercises a real but coincidentally already-covered path; kept for its own documentation value. Restoring the implementation returns 256/257 (1 pre-existing unrelated skip) on the full Markup/PluginSidePanel/RetailWindow/Anchor-filtered App suite and 9/9 on the MossTank markup-filtered suite, both green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
3a3b40fab5
commit
cd06f89e59
2 changed files with 116 additions and 0 deletions
|
|
@ -424,6 +424,81 @@ public sealed class RetailWindowLayoutPersistenceTests : IDisposable
|
|||
Assert.Equal((77f, 88f), (saved.X, saved.Y));
|
||||
}
|
||||
|
||||
// ── 2026-09-07: a resizable plugin markup panel's resized geometry
|
||||
// persists and restores exactly like any other registered window — no
|
||||
// persistence-layer change was needed for this, since RetailWindowLayoutPersistence
|
||||
// already clamps against the frame's own MinWidth/MinHeight/MaxWidth/
|
||||
// MaxHeight (Apply's ClampDimension) for every registered handle. ────────
|
||||
|
||||
[Fact]
|
||||
public void ResizableMarkupPluginPanel_ResizedSize_RoundTripsThroughPersistence()
|
||||
{
|
||||
const string xml =
|
||||
"<panel x=\"0\" y=\"0\" w=\"300\" h=\"200\" resizable=\"true\" minw=\"200\" minh=\"150\"></panel>";
|
||||
var panel = MarkupDocument.Build(xml, new object(), _ => (1u, 32, 32));
|
||||
var store = new SettingsStore(PathName);
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
root.AddChild(panel);
|
||||
RetailWindowHandle handle = root.RegisterWindow("plugin-resizable-panel", panel);
|
||||
using var persistence = new RetailWindowLayoutPersistence(
|
||||
root.WindowManager, store, () => "Alice", () => (800, 600));
|
||||
|
||||
handle.MoveTo(60f, 70f);
|
||||
handle.ResizeTo(420f, 260f);
|
||||
|
||||
UiWindowLayout saved = Assert.IsType<UiWindowLayout>(
|
||||
store.LoadWindowLayout("Alice", "800x600", "plugin-resizable-panel", default));
|
||||
Assert.Equal((60f, 70f, 420f, 260f), (saved.X, saved.Y, saved.Width, saved.Height));
|
||||
|
||||
// Simulate a fresh session: rebuild the same markup (a fresh, un-resized
|
||||
// panel) and restore — the saved 420x260 must come back, not the
|
||||
// authored 300x200.
|
||||
var freshPanel = MarkupDocument.Build(xml, new object(), _ => (1u, 32, 32));
|
||||
var freshRoot = new UiRoot { Width = 800, Height = 600 };
|
||||
freshRoot.AddChild(freshPanel);
|
||||
RetailWindowHandle freshHandle = freshRoot.RegisterWindow(
|
||||
"plugin-resizable-panel", freshPanel);
|
||||
using var freshPersistence = new RetailWindowLayoutPersistence(
|
||||
freshRoot.WindowManager, store, () => "Alice", () => (800, 600));
|
||||
|
||||
freshPersistence.RestoreAll();
|
||||
|
||||
Assert.Equal((420f, 260f), (freshPanel.Width, freshPanel.Height));
|
||||
Assert.Equal((60f, 70f), (freshPanel.Left, freshPanel.Top));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResizableMarkupPluginPanel_RestoreClampsBelowFloorToAuthoredMin()
|
||||
{
|
||||
// A legacy save from before this feature's minw/minh existed (or one
|
||||
// from a plugin update that raised its floor) can carry a size below
|
||||
// the CURRENT authored minimum. Restore must clamp up to that floor —
|
||||
// this is what RetailWindowLayoutPersistence.Apply's ClampDimension
|
||||
// already does against frame.MinWidth/MinHeight for every registered
|
||||
// window; it only bites here because MarkupDocument now sets those
|
||||
// fields from minw/minh instead of leaving them at UiElement's
|
||||
// generic 40x40 default.
|
||||
const string xml =
|
||||
"<panel x=\"0\" y=\"0\" w=\"300\" h=\"200\" resizable=\"true\" minw=\"200\" minh=\"150\"></panel>";
|
||||
var store = new SettingsStore(PathName);
|
||||
store.SaveWindowLayout(
|
||||
"Alice",
|
||||
"800x600",
|
||||
"plugin-resizable-floor",
|
||||
new UiWindowLayout(60f, 70f, 80f, 60f, true, false, false));
|
||||
|
||||
var panel = MarkupDocument.Build(xml, new object(), _ => (1u, 32, 32));
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
root.AddChild(panel);
|
||||
root.RegisterWindow("plugin-resizable-floor", panel);
|
||||
using var persistence = new RetailWindowLayoutPersistence(
|
||||
root.WindowManager, store, () => "Alice", () => (800, 600));
|
||||
|
||||
persistence.RestoreAll();
|
||||
|
||||
Assert.Equal((200f, 150f), (panel.Width, panel.Height));
|
||||
}
|
||||
|
||||
private static RetailWindowHandle Mount(
|
||||
UiRoot root,
|
||||
string name,
|
||||
|
|
|
|||
|
|
@ -250,6 +250,47 @@ public sealed class RetailWindowManagerTests
|
|||
transitions);
|
||||
}
|
||||
|
||||
// ── 2026-09-07: plugin markup's resizable="true" panel through the real
|
||||
// window-manager ResizeTo path (no host wiring beyond what MarkupDocument
|
||||
// already sets on the panel — Resizable/ResizeX/ResizeY/MinWidth/MinHeight
|
||||
// are ordinary UiElement properties RetailWindowManager.ResizeTo already
|
||||
// respects for any registered window). ───────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public void ResizableMarkupPluginWindow_AcceptsResizeWithinMinAndParentConstraints()
|
||||
{
|
||||
const string xml =
|
||||
"<panel x=\"0\" y=\"0\" w=\"300\" h=\"200\" resizable=\"true\" minw=\"250\" minh=\"150\"></panel>";
|
||||
var panel = MarkupDocument.Build(xml, new object(), _ => (1u, 32, 32));
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
root.AddChild(panel);
|
||||
RetailWindowHandle handle = root.RegisterWindow("plugin-resizable", panel);
|
||||
|
||||
Assert.True(handle.ResizeTo(500f, 400f));
|
||||
Assert.Equal((500f, 400f), (panel.Width, panel.Height));
|
||||
|
||||
// Below the authored floor clamps to minw/minh rather than shrinking further.
|
||||
Assert.True(handle.ResizeTo(50f, 50f));
|
||||
Assert.Equal((250f, 150f), (panel.Width, panel.Height));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NonResizableMarkupPluginWindow_RefusesResize()
|
||||
{
|
||||
const string xml = "<panel x=\"0\" y=\"0\" w=\"300\" h=\"200\"></panel>";
|
||||
var panel = MarkupDocument.Build(xml, new object(), _ => (1u, 32, 32));
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
root.AddChild(panel);
|
||||
RetailWindowHandle handle = root.RegisterWindow("plugin-fixed", panel);
|
||||
int resized = 0;
|
||||
handle.Resized += _ => resized++;
|
||||
|
||||
handle.ResizeTo(500f, 400f);
|
||||
|
||||
Assert.Equal((300f, 200f), (panel.Width, panel.Height));
|
||||
Assert.Equal(0, resized);
|
||||
}
|
||||
|
||||
private sealed class RecordingController : IRetainedPanelController
|
||||
{
|
||||
public int ShownCount { get; private set; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue