using System.Linq; using AcDream.App.UI; using AcDream.App.UI.Layout; using AcDream.Core.Net.Messages; using AcDream.Core.World; namespace AcDream.App.Tests.UI.Layout; /// /// Controller-level tests for against /// the committed map_house_2100006E_1000018C.json fixture (Batch C, /// overnight hover/UI round) — the SAME LayoutImporter.ImportInfos(dats, /// 0x2100006Eu, 0x1000018Cu) catalog import /// performs against real /// DATs. No DAT access, no live runtime — dat-free per the established /// pattern. /// public sealed class MapHousePanelControllerTests { /// Serves BOTH the town-hotspot template (any (layoutId, /// elementId) pair not the player/house icon ids) and the two icons /// re-resolves standalone /// (m_pMap's own button-swallowed children) — a real /// would set DatElementId the /// same way does, so tests that need /// to find these icons back by id after the fact need it too. private static UiElement? FakeHotspotTemplate(uint layoutId, uint elementId) => new UiText { Width = 10f, Height = 10f, DatElementId = elementId }; private static MapHousePanelController.Callbacks MakeCallbacks( List? calls = null, Func? currentCalendar = null, Func? playerCellId = null, Func? housePosition = null, Func>? houseLines = null) { calls ??= new List(); return new MapHousePanelController.Callbacks( Toggle: () => calls.Add("toggle"), Map: new MapPageController.Bindings( CurrentCalendar: currentCalendar ?? (static () => default), PlayerCellId: playerCellId ?? (static () => 0u), HousePosition: housePosition ?? (static () => null), TemplateResolver: FakeHotspotTemplate), House: new HousePageController.Bindings( Lines: houseLines ?? (static () => Array.Empty()), OnShown: () => calls.Add("house-shown"))); } [Fact] public void Bind_RootBuildsAsUiTabPanel() { ElementInfo rootInfo = FixtureLoader.LoadMapHouseHostInfos(); ImportedLayout layout = FixtureLoader.LoadMapHouseHost(); MapHousePanelController? controller = MapHousePanelController.Bind(rootInfo, layout, MakeCallbacks()); Assert.NotNull(controller); Assert.IsType(controller!.Root); } /// Pins the authored tab table exactly as read from the live /// DATs (MapHousePanelSlotProbeTests): two entries, Map is the /// sole default. [Fact] public void TabTable_MatchesLiveDatPairing_MapIsDefault() { ImportedLayout layout = FixtureLoader.LoadMapHouseHost(); var tabs = Assert.IsType(layout.Root); Assert.Equal(2, tabs.Tabs.Count); Assert.Contains(tabs.Tabs, e => e.ButtonElementId == 0x100001F3u && e.PageElementId == 0x100001F6u && e.IsDefault); Assert.Contains(tabs.Tabs, e => e.ButtonElementId == 0x100001F4u && e.PageElementId == 0x100001F7u && !e.IsDefault); Assert.Single(tabs.Tabs, e => e.IsDefault); } [Fact] public void Bind_Succeeds_AndActivateTabs_SelectsMapByDefault() { ElementInfo rootInfo = FixtureLoader.LoadMapHouseHostInfos(); ImportedLayout layout = FixtureLoader.LoadMapHouseHost(); MapHousePanelController? controller = MapHousePanelController.Bind(rootInfo, layout, MakeCallbacks()); Assert.NotNull(controller); controller!.ActivateTabs(); Assert.Empty(controller.TabPanel.UnresolvedEntries); Assert.False(controller.IsShowingHouse); } [Fact] public void SwitchToHouse_FiresOnShown_OnlyWhenPanelIsVisible() { ElementInfo rootInfo = FixtureLoader.LoadMapHouseHostInfos(); ImportedLayout layout = FixtureLoader.LoadMapHouseHost(); var calls = new List(); MapHousePanelController? controller = MapHousePanelController.Bind(rootInfo, layout, MakeCallbacks(calls)); Assert.NotNull(controller); controller!.ActivateTabs(); // Not visible yet: switching tabs must not fire OnShown. controller.TabPanel.SwitchTo(0x100001F7u); Assert.DoesNotContain("house-shown", calls); controller.OnShown(); Assert.Contains("house-shown", calls); } [Fact] public void CloseButton_InvokesToggle() { ElementInfo rootInfo = FixtureLoader.LoadMapHouseHostInfos(); ImportedLayout layout = FixtureLoader.LoadMapHouseHost(); var calls = new List(); MapHousePanelController? controller = MapHousePanelController.Bind(rootInfo, layout, MakeCallbacks(calls)); Assert.NotNull(controller); UiElement? close = layout.FindElement(0x100001F5u); Assert.IsType(close); ((UiButton)close!).OnClick?.Invoke(); Assert.Contains("toggle", calls); } [Fact] public void Bind_BuildsAll53TownHotspots_UnderTheMapWidget() { ElementInfo rootInfo = FixtureLoader.LoadMapHouseHostInfos(); ImportedLayout layout = FixtureLoader.LoadMapHouseHost(); MapHousePanelController? controller = MapHousePanelController.Bind(rootInfo, layout, MakeCallbacks()); Assert.NotNull(controller); UiElement? map = UiElement.FindDescendant(controller!.Root, MapPageController.MapWidgetId); Assert.NotNull(map); // m_pMap's own children are the player/house icons (re-resolved // standalone — see MapPageController.Bind's doc on why m_pMap being // a Button swallows its authored nested children) PLUS the 53 town // hotspots. var townMarkers = map!.Children .Where(c => c.DatElementId != MapPageController.PlayerIconId && c.DatElementId != MapPageController.HouseIconId) .ToList(); Assert.Equal(55, map.Children.Count); Assert.Equal(53, townMarkers.Count); Assert.All(townMarkers, c => Assert.Contains( MapLocations.All, loc => loc.Width == c.Width && loc.Height == c.Height)); Assert.All(townMarkers, c => Assert.True(c.AuthoredTooltipEnabled)); Assert.Contains(townMarkers, c => c.AuthoredTooltipText == "Holtburg"); } [Fact] public void Bind_HouseListBoxStartsEmpty_MatchingRetailPostInit() { ElementInfo rootInfo = FixtureLoader.LoadMapHouseHostInfos(); ImportedLayout layout = FixtureLoader.LoadMapHouseHost(); MapHousePanelController? controller = MapHousePanelController.Bind(rootInfo, layout, MakeCallbacks()); Assert.NotNull(controller); UiElement? box = UiElement.FindDescendant(controller!.Root, HousePageController.TextBoxId); var listBox = Assert.IsType(box); Assert.Equal(0, listBox.ContentHeight); } }