acdream/tests/AcDream.App.Tests/UI/Layout/RetailPanelUiControllerTests.cs
Erik a96767ba6d feat(ui): share indicator detail panels
Port the authored Link Status, Vitae, and Mini Game detail roots and register every indicator page with retail's one-active gmPanelUI owner. Helpful/Harmful and the new pages now replace Inventory, Character, or Magic at one canonical window position while preserving the DAT restore-previous flag.

Correct the retail ping wire to its payload-free request/response, publish measured RTT, and port Vitae recovery XP from the live modifier and player properties. Keep transport packet-loss averaging and mini-game gameplay explicitly tracked under AP-110.

Release build and all 5,814 tests pass with five intentional skips. Connected visual gate pending.

Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-17 10:27:41 +02:00

184 lines
6.5 KiB
C#

using AcDream.App.UI;
using AcDream.App.UI.Layout;
namespace AcDream.App.Tests.UI.Layout;
public sealed class RetailPanelUiControllerTests
{
[Fact]
public void ShowingPanel_HidesCurrent_AndClosingLeavesHostEmpty()
{
var visible = new Dictionary<string, bool>(StringComparer.Ordinal)
{
["inventory"] = false,
["helpful"] = false,
};
var controller = Create(visible);
controller.Register(7u, "inventory");
controller.Register(4u, "helpful");
Assert.True(controller.SetPanelVisibility(7u, true));
Assert.True(visible["inventory"]);
Assert.Equal(7u, controller.ActivePanelId);
Assert.True(controller.SetPanelVisibility(4u, true));
Assert.False(visible["inventory"]);
Assert.True(visible["helpful"]);
Assert.Equal(4u, controller.ActivePanelId);
Assert.False(controller.TogglePanel(4u));
Assert.False(visible["helpful"]);
Assert.Null(controller.ActivePanelId);
}
[Fact]
public void RestorePreviousProperty_ReopensOnlyNonRestoringPreviousPanel()
{
var visible = new Dictionary<string, bool>(StringComparer.Ordinal)
{
["ordinary"] = false,
["transient"] = false,
};
var controller = Create(visible);
controller.Register(1u, "ordinary", restorePrevious: false);
controller.Register(2u, "transient", restorePrevious: true);
controller.SetPanelVisibility(1u, true);
controller.SetPanelVisibility(2u, true);
Assert.False(visible["ordinary"]);
Assert.True(visible["transient"]);
controller.SetPanelVisibility(2u, false);
Assert.True(visible["ordinary"]);
Assert.False(visible["transient"]);
Assert.Equal(1u, controller.ActivePanelId);
}
[Fact]
public void ObservedPersistenceShow_UsesSameExclusiveLifecycle()
{
var visible = new Dictionary<string, bool>(StringComparer.Ordinal)
{
["first"] = false,
["second"] = false,
};
var controller = Create(visible);
controller.Register(1u, "first");
controller.Register(2u, "second");
controller.SetPanelVisibility(1u, true);
visible["second"] = true;
controller.ObserveWindowVisibility("second", visible: true);
Assert.False(visible["first"]);
Assert.True(visible["second"]);
Assert.Equal(2u, controller.ActivePanelId);
}
[Fact]
public void MainPanels_ShareOneCanonicalPlacementAcrossMoveCloseAndSwitch()
{
var root = new UiRoot { Width = 1280f, Height = 720f };
RetailWindowHandle inventory = Mount(root, WindowNames.Inventory, 40f, 60f);
RetailWindowHandle character = Mount(root, WindowNames.Character, 540f, 18f);
RetailWindowHandle spellbook = Mount(root, WindowNames.Spellbook, 18f, 18f);
using var controller = Create(root);
controller.RegisterMainPanel(7u, WindowNames.Inventory, inventory);
controller.RegisterMainPanel(11u, WindowNames.Character, character);
controller.RegisterMainPanel(13u, WindowNames.Spellbook, spellbook);
int characterMoves = 0;
int spellbookMoves = 0;
character.Moved += _ => characterMoves++;
spellbook.Moved += _ => spellbookMoves++;
controller.SetPanelVisibility(7u, visible: true);
inventory.MoveTo(312f, 147f);
Assert.Equal((312f, 147f), (character.Left, character.Top));
Assert.Equal((312f, 147f), (spellbook.Left, spellbook.Top));
Assert.True(characterMoves > 0);
Assert.True(spellbookMoves > 0);
controller.SetPanelVisibility(11u, visible: true);
Assert.False(inventory.IsVisible);
Assert.True(character.IsVisible);
Assert.Equal((312f, 147f), (character.Left, character.Top));
controller.SetPanelVisibility(11u, visible: false);
controller.SetPanelVisibility(13u, visible: true);
Assert.False(character.IsVisible);
Assert.True(spellbook.IsVisible);
Assert.Equal((312f, 147f), (spellbook.Left, spellbook.Top));
}
[Fact]
public void IndicatorDetailPanel_SharesPlacementAndRestoresPreviousPanel()
{
var root = new UiRoot { Width = 1280f, Height = 720f };
RetailWindowHandle inventory = Mount(root, WindowNames.Inventory, 40f, 60f);
RetailWindowHandle character = Mount(root, WindowNames.Character, 540f, 18f);
RetailWindowHandle effect = Mount(root, WindowNames.PositiveEffects, 900f, 30f);
using var controller = Create(root);
controller.RegisterMainPanel(7u, WindowNames.Inventory, inventory);
controller.RegisterMainPanel(11u, WindowNames.Character, character);
controller.RegisterMainPanel(
4u,
WindowNames.PositiveEffects,
effect,
restorePrevious: true);
controller.SetPanelVisibility(7u, visible: true);
inventory.MoveTo(280f, 120f);
controller.SetPanelVisibility(4u, visible: true);
Assert.Equal((280f, 120f), (effect.Left, effect.Top));
Assert.False(inventory.IsVisible);
Assert.True(effect.IsVisible);
controller.SetPanelVisibility(4u, visible: false);
Assert.True(inventory.IsVisible);
Assert.Equal((280f, 120f), (inventory.Left, inventory.Top));
controller.SetPanelVisibility(11u, visible: true);
Assert.Equal((280f, 120f), (character.Left, character.Top));
}
private static RetailPanelUiController Create(Dictionary<string, bool> visible)
=> new(
name => visible[name],
name =>
{
visible[name] = true;
return true;
},
name =>
{
visible[name] = false;
return true;
});
private static RetailPanelUiController Create(UiRoot root)
=> new(root.IsWindowVisible, root.ShowWindow, root.HideWindow);
private static RetailWindowHandle Mount(
UiRoot root,
string name,
float left,
float top)
{
var content = new UiPanel { Width = 300f, Height = 500f };
return RetailWindowFrame.Mount(
root,
content,
_ => (0u, 0, 0),
new RetailWindowFrame.Options
{
WindowName = name,
Left = left,
Top = top,
Visible = false,
ConstrainDragToParent = true,
});
}
}