From 149a1beb47417e840025cae3a9a6fb31dee3c35e Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 2 Sep 2026 16:58:29 +0700 Subject: [PATCH] the colour picker, guild charter, honour page and four more go stock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - the colour dialog is the reference's own `ColorPickerFrame.xml` — the window with the largest reach in the addon corpus (86 of 218 addons name it, 64 of those Dewdrop-2.0, so every Ace2 config menu's colour row opens it), and the guild charter, the guild registrar, the error toasts with the raid warning (which our copy had declared with NO scripts at all, so the big centre text and its sound had been inert scenery), the honour page, the quest timer and the stack-split spinner follow — each a toc line and a deletion - the swaps caught our own bugs on the way: the registrar's two service rows were hidden by a template modelled on the quest list's pooled rows, leaving a bare "Available Services" heading over blank parchment; the stack spinner CLAMPED a too-big digit where the reference ignores it (37 against a 5-stack leaves the 3 standing, `StackSplitFrame.lua:72-85`) — a divergence with a test defending it; and 1.12's Lua-5.0 `arg`/`arg.n` varargs turn out to work in this VM (mlua's vendored 5.1 has `LUA_COMPAT_VARARG`), which unblocks every stock file written in that idiom - 42 test modules carried five near-identical private copies of a disk-only XML loader that structurally cannot name a chain file; they are one shared reader now (733 lines out), with a strict variant that fails on an unknown-template WARNING — the case where a frame builds with none of its art — which is how the registrar bug was caught on the first window after Co-Authored-By: Claude Fable 5.1 --- .../assets/ui/ColorPickerFrame.xml | 390 ----------- crates/benilla-app/assets/ui/ErrorsFrame.xml | 103 --- .../assets/ui/GuildRegistrarFrame.xml | 355 ---------- crates/benilla-app/assets/ui/HonorFrame.xml | 652 ------------------ crates/benilla-app/assets/ui/InspectFrame.xml | 107 +++ .../benilla-app/assets/ui/PetitionFrame.xml | 389 ----------- crates/benilla-app/assets/ui/QuestFrame.xml | 31 +- .../benilla-app/assets/ui/QuestLogFrame.xml | 10 + .../benilla-app/assets/ui/QuestTimerFrame.xml | 259 ------- crates/benilla-app/assets/ui/StackSplit.xml | 314 --------- crates/benilla-app/assets/ui/UiPanels.xml | 39 ++ crates/benilla-app/assets/ui/benilla.toc | 91 ++- .../benilla-app/src/ui_action/feed_tests.rs | 14 +- .../src/ui_script/action_bar_tests.rs | 2 +- crates/benilla-app/src/ui_script/bag_tests.rs | 22 +- .../src/ui_script/basic_controls_tests.rs | 17 +- .../benilla-app/src/ui_script/buff_tests.rs | 17 +- .../benilla-app/src/ui_script/cast_tests.rs | 17 +- .../src/ui_script/character_tests.rs | 32 +- .../src/ui_script/chat_options_tests.rs | 27 +- .../src/ui_script/chat_resize_tests.rs | 31 +- .../benilla-app/src/ui_script/chat_tests.rs | 17 +- .../src/ui_script/cinematic_tests.rs | 12 +- .../src/ui_script/color_picker_tests.rs | 33 +- .../src/ui_script/combat_text_tests.rs | 18 +- .../src/ui_script/dressup_tests.rs | 2 +- .../src/ui_script/dropdown_tests.rs | 16 +- .../src/ui_script/enchant_confirm_tests.rs | 17 +- .../benilla-app/src/ui_script/errors_tests.rs | 22 +- .../benilla-app/src/ui_script/escape_tests.rs | 2 +- .../benilla-app/src/ui_script/fade_tests.rs | 19 +- .../src/ui_script/faux_scroll_tests.rs | 17 +- .../src/ui_script/frame_flag_gate.rs | 5 - .../src/ui_script/friends_tests.rs | 34 +- .../benilla-app/src/ui_script/guild_tests.rs | 35 +- .../src/ui_script/honor_frame_tests.rs | 35 +- .../src/ui_script/inspect_tests.rs | 27 +- .../src/ui_script/instance_tests.rs | 17 +- crates/benilla-app/src/ui_script/mod.rs | 7 + .../src/ui_script/money_frame_tests.rs | 17 +- .../src/ui_script/multibar_stance_tests.rs | 17 +- .../src/ui_script/panel_template_tests.rs | 12 +- .../src/ui_script/perf_bar_tests.rs | 17 +- .../src/ui_script/pet_bar_tests.rs | 17 +- .../src/ui_script/pet_frame_tests.rs | 18 +- .../src/ui_script/pet_paperdoll_tests.rs | 17 +- .../src/ui_script/petition_tests.rs | 64 +- .../benilla-app/src/ui_script/quest_tests.rs | 18 +- .../src/ui_script/quest_timer_tests.rs | 47 +- .../src/ui_script/questlog_tests.rs | 28 +- .../benilla-app/src/ui_script/raid_tests.rs | 30 +- .../src/ui_script/reputation_frame_tests.rs | 18 +- .../src/ui_script/screenshot_tests.rs | 16 +- .../src/ui_script/skills_frame_tests.rs | 18 +- .../src/ui_script/spellbook_tests.rs | 18 +- .../src/ui_script/target_aura_tests.rs | 16 +- .../benilla-app/src/ui_script/taxi_tests.rs | 20 +- crates/benilla-app/src/ui_script/test_ui.rs | 29 +- .../src/ui_script/tooltip_anchor_tests.rs | 18 +- .../src/ui_script/tooltip_template_tests.rs | 16 +- .../src/ui_script/tot_frame_tests.rs | 17 +- .../src/ui_script/unit_frame_tests.rs | 18 +- .../src/ui_script/world_state_tests.rs | 16 +- crates/benilla-ui/src/script/lua50.rs | 13 + 64 files changed, 485 insertions(+), 3304 deletions(-) delete mode 100644 crates/benilla-app/assets/ui/ColorPickerFrame.xml delete mode 100644 crates/benilla-app/assets/ui/ErrorsFrame.xml delete mode 100644 crates/benilla-app/assets/ui/GuildRegistrarFrame.xml delete mode 100644 crates/benilla-app/assets/ui/HonorFrame.xml delete mode 100644 crates/benilla-app/assets/ui/PetitionFrame.xml delete mode 100644 crates/benilla-app/assets/ui/QuestTimerFrame.xml delete mode 100644 crates/benilla-app/assets/ui/StackSplit.xml diff --git a/crates/benilla-app/assets/ui/ColorPickerFrame.xml b/crates/benilla-app/assets/ui/ColorPickerFrame.xml deleted file mode 100644 index d4d7992c..00000000 --- a/crates/benilla-app/assets/ui/ColorPickerFrame.xml +++ /dev/null @@ -1,390 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if ( OpacityFrame.opacityFunc ) then - OpacityFrame.opacityFunc(); - end - - - - - - - - - - - OpacityFrameCloseButton:Show(); - - - OpacityFrameCloseButton:Hide(); - - - - diff --git a/crates/benilla-app/assets/ui/ErrorsFrame.xml b/crates/benilla-app/assets/ui/ErrorsFrame.xml deleted file mode 100644 index b8a26a70..00000000 --- a/crates/benilla-app/assets/ui/ErrorsFrame.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - UIErrorsFrame_OnLoad() - UIErrorsFrame_OnEvent(event, arg1) - - - - - - - - - - - - - - - - diff --git a/crates/benilla-app/assets/ui/GuildRegistrarFrame.xml b/crates/benilla-app/assets/ui/GuildRegistrarFrame.xml deleted file mode 100644 index 42df2fbc..00000000 --- a/crates/benilla-app/assets/ui/GuildRegistrarFrame.xml +++ /dev/null @@ -1,355 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - this:SetFrameLevel(this:GetFrameLevel() + 2) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MoneyFrame_OnLoad() - MoneyFrame_SetType("STATIC") - - - - - - - - - - - - - - - - - - - - - - - - - - - GuildRegistrar_Purchase(this:GetText()) - GuildRegistrar_RefocusChat() - - - - - - - - - this:RegisterEvent("GUILD_REGISTRAR_SHOW") - this:RegisterEvent("GUILD_REGISTRAR_CLOSED") - - GuildRegistrar_OnEvent(event) - - GuildRegistrar_OnShow() - PlaySound("igQuestListOpen") - - - - PlaySound("igQuestListClose") - CloseGuildRegistrar() - - - - diff --git a/crates/benilla-app/assets/ui/HonorFrame.xml b/crates/benilla-app/assets/ui/HonorFrame.xml deleted file mode 100644 index 12a69a08..00000000 --- a/crates/benilla-app/assets/ui/HonorFrame.xml +++ /dev/null @@ -1,652 +0,0 @@ - - - - - - - - - BenillaHonorRow_OnEnter(self) - GameTooltip:Hide() - - - - - - - - - - - - - - - - - - - BenillaHonorRow_OnLoad(self, HONORABLE_KILLS, NEWBIE_TOOLTIP_HONORABLE_KILLS) - - - - - - - - - - - - - - - - - - - BenillaHonorRow_OnLoad(self, DISHONORABLE_KILLS, NEWBIE_TOOLTIP_DISHONORABLE_KILLS) - - - - - - - - - - - - - - - - - - - BenillaHonorRow_OnLoad(self, HONOR_CONTRIBUTION_POINTS, NEWBIE_TOOLTIP_HONOR_CONTRIBUTION_POINTS) - - - - - - - - - - - - - - - - - - - BenillaHonorRow_OnLoad(self, HONOR_STANDING, NEWBIE_TOOLTIP_HONOR_STANDING) - - - - - - - - - - - - - - - - - - - BenillaHonorRow_OnLoad(self, RANK, NEWBIE_TOOLTIP_RANK) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaTooltip_AddNewbieTipFor(self, RANK, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, NEWBIE_TOOLTIP_RANK) - GameTooltip:Hide() - - - - - - - - - - - self:SetFrameLevel(self:GetFrameLevel() - 1) - BenillaTooltip_AddNewbieTipFor(self, RANK_POSITION, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, NEWBIE_TOOLTIP_RANK_POSITION) - GameTooltip:Hide() - - - - - self:SetFrameLevel(self:GetFrameLevel() - 1) - - - - - - HonorFrame_OnLoad(self) - HonorFrame_OnEvent(event) - - - diff --git a/crates/benilla-app/assets/ui/InspectFrame.xml b/crates/benilla-app/assets/ui/InspectFrame.xml index 3c361078..c3e269d1 100644 --- a/crates/benilla-app/assets/ui/InspectFrame.xml +++ b/crates/benilla-app/assets/ui/InspectFrame.xml @@ -54,6 +54,113 @@ (CharacterFrame.xml hit the identical wall) — click-only, so no OnUpdate is wired. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - this:SetFrameLevel(this:GetFrameLevel() + 2) - - - - - - - - - - - - - - - this:RegisterEvent("PETITION_SHOW") - this:RegisterEvent("PETITION_CLOSED") - - PetitionFrame_OnEvent(event) - PlaySound("igQuestListOpen") - - - PlaySound("igQuestListClose") - ClosePetition() - - - return - - - diff --git a/crates/benilla-app/assets/ui/QuestFrame.xml b/crates/benilla-app/assets/ui/QuestFrame.xml index cab3d730..f927a9cb 100644 --- a/crates/benilla-app/assets/ui/QuestFrame.xml +++ b/crates/benilla-app/assets/ui/QuestFrame.xml @@ -845,10 +845,15 @@ QuestRewardItem_OnClick() - - - - - - - - - - - + + + + + + + + + diff --git a/crates/benilla-app/assets/ui/QuestLogFrame.xml b/crates/benilla-app/assets/ui/QuestLogFrame.xml index 2e64fc48..b903f217 100644 --- a/crates/benilla-app/assets/ui/QuestLogFrame.xml +++ b/crates/benilla-app/assets/ui/QuestLogFrame.xml @@ -69,6 +69,16 @@ to be the real widget method rather than a benilla global. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - QuestTimerFrame_OnLoad(self) - QuestTimerFrame_OnUpdate() - QuestTimerFrame_OnEvent() - - UIParent_ManageFramePositions() - UIParent_ManageFramePositions() - - - diff --git a/crates/benilla-app/assets/ui/StackSplit.xml b/crates/benilla-app/assets/ui/StackSplit.xml deleted file mode 100644 index 574caae1..00000000 --- a/crates/benilla-app/assets/ui/StackSplit.xml +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StackSplitFrame_OnHide() - StackSplitFrame_OnChar() - StackSplitFrame_OnKeyDown() - - - diff --git a/crates/benilla-app/assets/ui/UiPanels.xml b/crates/benilla-app/assets/ui/UiPanels.xml index 0b99154c..a4992194 100644 --- a/crates/benilla-app/assets/ui/UiPanels.xml +++ b/crates/benilla-app/assets/ui/UiPanels.xml @@ -1660,6 +1660,45 @@ hideOnEscape = 1, } + -- The guild-charter rename box, ref StaticPopup.lua l.133-160 — **in the reference's own + -- home, which is this file**. It lived in our PetitionFrame.xml on the reasoning that "a + -- popup belongs to the window that raises it"; that is a fine rule and it is not 1.12's, + -- which keeps every dialog in one registry. 1751's twelfth window made the charter the + -- reference's own file, whose Rename button calls `StaticPopup_Show("RENAME_GUILD")` and + -- registers nothing, so the entry had to come here. + -- + -- 24 letters is the server's MAX_CHARTER_NAME, so the box cannot compose a name that will + -- be refused for length. Accept and Enter run the same two lines; the reference spells + -- them out twice (l.139-147), and its Enter arm hides the dialog while its Accept arm does + -- not — the popup engine hides on a plain Accept anyway. + StaticPopupDialogs["RENAME_GUILD"] = { + text = RENAME_GUILD_LABEL, + button1 = ACCEPT, + button2 = CANCEL, + hasEditBox = 1, + maxLetters = 24, + OnAccept = function() + RenamePetition(getglobal(this:GetParent():GetName() .. "EditBox"):GetText()) + end, + EditBoxOnEnterPressed = function() + RenamePetition(getglobal(this:GetParent():GetName() .. "EditBox"):GetText()) + this:GetParent():Hide() + end, + OnShow = function() + getglobal(this:GetName() .. "EditBox"):SetFocus() + end, + OnHide = function() + if ChatFrameEditBox and ChatFrameEditBox:IsVisible() then + ChatFrameEditBox:SetFocus() + end + getglobal(this:GetName() .. "EditBox"):SetText("") + end, + timeout = 0, + exclusive = 1, + whileDead = 1, + hideOnEscape = 1, + } + -- ref UIParent.lua l.324-343 + l.356-360, the four arms on one driver. Each equip arm -- hides the OTHER dialog first — the two questions are mutually exclusive by construction -- (one item, one destination), and the hide is what cancels the record the new question diff --git a/crates/benilla-app/assets/ui/benilla.toc b/crates/benilla-app/assets/ui/benilla.toc index 1ad9d32e..ebfad01e 100644 --- a/crates/benilla-app/assets/ui/benilla.toc +++ b/crates/benilla-app/assets/ui/benilla.toc @@ -317,21 +317,27 @@ UIPanelTemplates.xml # UICheckButtonTemplate and UIPanelButtonTemplate. Not benilla's own options window # (OptionsFrame.xml, far below): these are the shared names addons build panels out of. OptionsFrameTemplates.xml -# The shared colour dialog + its opacity slider (`ColorPickerFrame`, `OpacitySliderFrame`, -# `ColorPickerOkayButton`, `ColorPickerCancelButton`). Last of the "shared FrameXML surface with no -# benilla consumer yet" cluster that runs from UIPanelTemplates.xml down — the same posture as -# MoneyFrame.xml above, and for the same reason: 86 of the 218 corpus addons reach this window (64 -# of those files are `Dewdrop-2.0.lua`, which drives THIS one rather than rolling its own), and -# nothing we ship opens it. The seat is a REQUIREMENT, not tidiness: its Okay/Cancel buttons -# `inherits="GameMenuButtonTemplate"`, which is resolved at LOAD, and that template lives in +# ══ THE COLOUR DIALOG — the reference's own, off the player's chain (1751, window 11) ══ +# `ColorPickerFrame` (a ``), `OpacitySliderFrame`, `ColorPickerOkayButton`, +# `ColorPickerCancelButton`, and the separate `OpacityFrame` beside them. The file ships no `.lua` +# — its whole script is inline, and the one function that drives it +# (`UIDropDownMenuButton_OpenColorPicker`) lives in UIDropDownMenu.lua. +# +# Last of the "shared FrameXML surface with no benilla consumer yet" cluster that runs from +# UIPanelTemplates.xml down, and the swap is exactly why that posture was worth holding: **86 of +# the 218 corpus addons reach this window** (64 of those files are `Dewdrop-2.0.lua`, which drives +# THIS one rather than rolling its own), and nothing we ship opens it — so every one of them is now +# talking to the reference's own frames rather than to our re-expression of them. +# +# THE SEAT IS A REQUIREMENT, not tidiness: the Okay/Cancel buttons +# `inherits="GameMenuButtonTemplate"`, resolved at LOAD, and that template lives in # UIPanelTemplates.xml six lines up (it moved there from GameMenuFrame.xml — the reference's own -# file for it — precisely because GameMenuFrame.xml is deliberately LAST). Everything else it needs -# is far above (Fonts' GameFontNormal/…Small trio; UiPanels' ShowUIPanel/HideUIPanel, its -# UISpecialFrames entry and the ESC rung that cancel-clicks it). UIDropDownMenu.xml, which owns the -# colour-swatch row that OPENS this window, sits above too — but that direction is call-time only -# (`UIDropDownMenuButton_OpenColorPicker` reaches `ColorPickerFrame` by name when the swatch is -# clicked), so the two could sit either way round. -ColorPickerFrame.xml +# file for it — precisely because GameMenuFrame.xml is deliberately LAST, which is also why this +# entry does not follow the reference's own position below it). Everything else it needs is far +# above: Fonts' GameFontNormal trio, and UiPanels' ShowUIPanel/HideUIPanel plus its UISpecialFrames +# entry and the ESC rung that cancel-clicks it. UIDropDownMenu.xml sits above too, but that +# direction is call-time only, so the two could sit either way round. +Interface\FrameXML\ColorPickerFrame.xml # The fullscreen world map (decision 0203 phase 2), over the worldmap host API # (`crate::ui_world_map` feeds it); the 'M' binding (ui_script/input.rs) calls its # ToggleWorldMap(). @@ -397,7 +403,28 @@ BuffFrame.xml # bind. It is reachable only from the dead `enchantTimer` branch above, so it is left absent rather # than stubbed (1203) — the honest state is "nothing calls it", not "we answer it with a lie". Interface\FrameXML\DurabilityFrame.xml -ErrorsFrame.xml +# ══ THE ERROR TOASTS AND THE RAID WARNING — the reference's own (1751, window 14) ══ +# `UIErrorsFrame` (the red/yellow toast strip) and `UIErrorsFrame_OnLoad`/`_OnEvent`, then +# `RaidWarningFrame` and `RaidBossEmoteFrame` with `RaidWarningFrame_OnLoad`/`_OnEvent`. Two files, +# in the reference's own split and its own order: the warning frame anchors `relativeTo= +# "UIErrorsFrame"`, resolved at LOAD, so it cannot precede it. +# +# Our single `ErrorsFrame.xml` held both and is deleted. It declared `RaidWarningFrame` with **no +# `` at all**, and the reason it gave was wrong: *"we already deliver that chat type +# through `ui_chat::feed`, so wiring a second consumer would print every raid warning TWICE"*. +# Checked rather than inherited — `ui_chat` fires `CHAT_MSG_RAID_WARNING` as an ordinary chat event +# and nothing of ours consumes it for a display. So the reference's handler adds the big centre +# text and its `PlaySound("RaidWarning")` **beside** the chat line, which is exactly what 1.12 +# does: the chat window and the warning frame are two consumers of one event there too. +# +# It also brings `RaidBossEmoteFrame`, which our copy withheld on the "no corpus caller, and a +# shadowed name with no caller is building against a guess" rule (1222). That rule is about names +# WE would invent; this one is the reference's own declaration, so there is nothing left to guess. +# +# `ChatTypeInfo["RAID_WARNING"]` comes from ChatFrame.xml far below — read at call time, so the +# order does not bind. +Interface\FrameXML\UIErrorsFrame.xml +Interface\FrameXML\RaidWarning.xml # ══ THE BAG WINDOWS — the reference's own, off the player's chain (decision 1751, window 1) ══ # `ContainerFrame1..12`, `ContainerFrameTemplate`, `ContainerFrameItemButtonTemplate` and the whole # `ToggleBag`/`ToggleBackpack`/`OpenAllBags`/`IsBagOpen`/`ToggleKeyRing` verb family — the real @@ -453,7 +480,7 @@ Interface\FrameXML\MainMenuBarBagButtons.xml # click handler (the reference's `ContainerFrameItemButton_OnClick`) calls `OpenStackSplitFrame`. # Order between the two doesn't matter for correctness (Lua globals resolve at call time, and # neither file's XML `inherits=` reaches into the other's templates) — adjacent for legibility. -StackSplit.xml +Interface\FrameXML\StackSplitFrame.xml # Our ADAPTERS over the reference's own container files — one wrapper, for the keyring tooltip # detour benilla answers differently (0765). Must load AFTER them, since it captures at load the # body it wraps; its own header says what it stopped needing to do when the XML became sourceable. @@ -505,7 +532,7 @@ SkillFrame.xml # declared here, and `inherits=` resolves at LOAD. The reference has the identical edge — its # `HonorFrameTemplates.xml` is ``d by `HonorFrame.xml` and inherited by the LoadOnDemand # `Blizzard_InspectUI`, which loads later still. -HonorFrame.xml +Interface\FrameXML\HonorFrame.xml # The inspect window (decision 0631): another player's paper doll. Beside the character # window it mirrors — it needs the same three (Fonts/UiPanels/GameTooltip) plus # `CharacterFrameTabButtonTemplate` from UiPanels.xml, and nothing from CharacterFrame.xml @@ -651,15 +678,27 @@ GroupLootFrame.xml # art conventions); its title/panel-button labels use the auto-centred ButtonText slot. QuestFrame.xml # The two guild-charter windows (decision 1672): the guild registrar — the window the "How do I -# form a guild?" gossip row opens — and the charter itself, the sheet nine people sign. Loaded -# here, right after QuestFrame, because both wear the QuestGreeting parchment and its QuestFont / +# form a guild?" gossip row opens — and the charter itself, the sheet nine people sign. **Both are +# the reference's own files off the player's chain now** (1751, windows 12 and 13). Loaded here, +# right after QuestFrame, because both wear the QuestGreeting parchment and its QuestFont / # QuestTitleFont objects and read as that family; they need UiPanels (the panel manager seats both, -# and PetitionFrame registers its RENAME_GUILD dialog on the shared popup engine), MoneyFrame (the -# registrar's price rides MoneyFrameTemplate, resolved at LOAD — decision 1580's ordering rule) and -# UIPanelTemplates (the close/action buttons), all far above. The registrar must come first: no -# load-order dependency links them, but the flow does, and the pair reads in the order it is used. -GuildRegistrarFrame.xml -PetitionFrame.xml +# and the RENAME_GUILD dialog the charter raises is registered there, where 1.12 keeps every +# dialog), MoneyFrame (the registrar's price rides MoneyFrameTemplate, resolved at LOAD — decision +# 1580's ordering rule) and UIPanelTemplates (the close/action buttons), all far above. The +# registrar must come first: no load-order dependency links them, but the flow does, and the pair +# reads in the order it is used. +Interface\FrameXML\GuildRegistrarFrame.xml +# ══ THE GUILD CHARTER — the reference's own, off the player's chain (1751, window 12) ══ +# `PetitionFrame` and its nine signature rows, `PetitionFrame_Update`, `MAX_PETITION_SIGNATURES`, +# and the leader/signer button pair that share one anchor. Ours was the same window under the same +# names (decision 1672) with a different expression of the same painter; the reference's file is +# what that expression was written from. +# +# The seat is unchanged and every dependency it names is above: UiPanels (the panel manager seats +# it, and its RENAME_GUILD dialog rides the shared popup engine), MoneyFrame, UIPanelTemplates (the +# close/action buttons `inherits=` at LOAD), and the QuestGreeting parchment family it shares with +# GuildRegistrarFrame directly above. +Interface\FrameXML\PetitionFrame.xml # The quest log window (decision 0088 arc, the quest-log slice): durable player state, not an # NPC session — loaded after MerchantFrame (the BenillaMoney coin helpers it reuses) and # alongside QuestFrame (same arc); the 'L' binding (ui_script/input.rs) calls its @@ -669,7 +708,7 @@ QuestLogFrame.xml # file split. After MinimapCluster (its anchor), UIParent (the manage pass that re-seats it, # and SecondsToTime), GameTooltip (its row hover), and QuestLogFrame — whose window a row # click opens, and whose MAX_QUESTS it shares. -QuestTimerFrame.xml +Interface\FrameXML\QuestTimerFrame.xml ChatFrame.xml # The macro window (decision 0983): the editor + its name/icon popup, driven over the # engine's OWN macro table (`benilla_ui::script::macros` — 1.12 macros have no server diff --git a/crates/benilla-app/src/ui_action/feed_tests.rs b/crates/benilla-app/src/ui_action/feed_tests.rs index c61799b4..de618a34 100644 --- a/crates/benilla-app/src/ui_action/feed_tests.rs +++ b/crates/benilla-app/src/ui_action/feed_tests.rs @@ -415,16 +415,10 @@ fn pre_resolved_lines_land_on_the_errors_frame_in_the_arms_colour() { { let mut script = app.world_mut().non_send_resource_mut::(); script.set_screen_size(1024.0, 768.0); - for file in ["Fonts.xml", "ErrorsFrame.xml"] { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(&script, &doc, &|_| None); - assert!(report.errors.is_empty(), "{file}: {:?}", report.errors); + // The errors frame is the reference's own file since 1751 window 14, so this reads both + // stores through the one loader that speaks them. + for file in ["Fonts.xml", "Interface\\FrameXML\\UIErrorsFrame.xml"] { + crate::ui_script::load_ui_for_test(&script, file); } } diff --git a/crates/benilla-app/src/ui_script/action_bar_tests.rs b/crates/benilla-app/src/ui_script/action_bar_tests.rs index 30044d65..4adcb718 100644 --- a/crates/benilla-app/src/ui_script/action_bar_tests.rs +++ b/crates/benilla-app/src/ui_script/action_bar_tests.rs @@ -784,7 +784,7 @@ fn shipped_bag_frame_drives_end_to_end() { bar_frames = frames; } } - load_ui(&s, "StackSplit.xml"); + load_ui(&s, "Interface\\FrameXML\\StackSplitFrame.xml"); load_ui(&s, "MerchantFrame.xml"); assert_eq!( diff --git a/crates/benilla-app/src/ui_script/bag_tests.rs b/crates/benilla-app/src/ui_script/bag_tests.rs index 213e424f..b8fa1d8b 100644 --- a/crates/benilla-app/src/ui_script/bag_tests.rs +++ b/crates/benilla-app/src/ui_script/bag_tests.rs @@ -1006,7 +1006,7 @@ fn open_backpack_with_a_five_stack(s: &mut UiScript) -> (f32, f32) { load_xml(s, file); } load_xml(s, "MerchantFrame.xml"); - load_xml(s, "StackSplit.xml"); + load_xml(s, "Interface\\FrameXML\\StackSplitFrame.xml"); s.set_money(0); let mut slots = std::collections::HashMap::new(); @@ -1233,14 +1233,18 @@ fn typing_a_number_into_the_split_spinner_sets_the_count() { "and the label follows" ); - // A second digit appends, then clamps to the 5-stack rather than being thrown away. + // A second digit that would overflow the stack is **IGNORED**, not clamped — the reference's + // `StackSplitFrame_OnChar` writes `this.split` only inside `if split <= this.maxStack` + // (StackSplitFrame.lua l.72-85), so 37 against a 5-stack leaves 3 standing. Our own copy + // clamped to 5 instead, and this assertion was written against that; the window is the + // reference's since 1751 window 17, so the ignore is the behaviour. assert!(s.char_input("7")); assert_eq!( s.eval::("return StackSplitFrame.split").unwrap(), - 5, - "37 against a 5-stack clamps to 5" + 3, + "37 against a 5-stack keeps the 3 — the ref ignores the digit, it does not clamp" ); - // BACKSPACE drops a digit off the clamped value. + // BACKSPACE drops a digit off it. assert!(s.frame_key_input("BACKSPACE"), "the dialog took BACKSPACE"); assert_eq!(s.eval::("return StackSplitFrame.split").unwrap(), 1); @@ -1273,10 +1277,10 @@ fn split_okay_then_a_placement_queues_the_split_move() { assert!(s.eval::("return StackSplitFrame:IsShown()").unwrap()); // Bump the spinner from 1 to 3, then Okay — the carry lands on the cursor. - s.run("BenillaStackSplitRight_Click()").unwrap(); - s.run("BenillaStackSplitRight_Click()").unwrap(); + click(&mut s, "StackSplitRightButton", "LeftButton"); + click(&mut s, "StackSplitRightButton", "LeftButton"); assert_eq!(s.eval::("return StackSplitFrame.split").unwrap(), 3); - s.run("BenillaStackSplitOkay_Click()").unwrap(); + click(&mut s, "StackSplitOkayButton", "LeftButton"); assert!( !s.eval::("return StackSplitFrame:IsShown()").unwrap(), "Okay hides the spinner" @@ -1548,7 +1552,7 @@ fn keyring_surface(s: &UiScript) { load_xml(s, file); } load_xml(s, "MerchantFrame.xml"); - load_xml(s, "ErrorsFrame.xml"); + load_xml(s, "Interface\\FrameXML\\UIErrorsFrame.xml"); } /// **The gate** (decision 0765): no key ⇒ no keyring anywhere on the bar — the button is hidden and diff --git a/crates/benilla-app/src/ui_script/basic_controls_tests.rs b/crates/benilla-app/src/ui_script/basic_controls_tests.rs index f52e5907..525f909d 100644 --- a/crates/benilla-app/src/ui_script/basic_controls_tests.rs +++ b/crates/benilla-app/src/ui_script/basic_controls_tests.rs @@ -7,22 +7,7 @@ use benilla_ui::script::UiScript; -/// One shipped file into `s`, asserting it loaded clean. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// Fonts then BasicControls — the manifest's own order, and the whole dependency this file has. fn basic_controls() -> UiScript { diff --git a/crates/benilla-app/src/ui_script/buff_tests.rs b/crates/benilla-app/src/ui_script/buff_tests.rs index b9e594c2..51d0f5e4 100644 --- a/crates/benilla-app/src/ui_script/buff_tests.rs +++ b/crates/benilla-app/src/ui_script/buff_tests.rs @@ -17,22 +17,7 @@ use benilla_ui::script::{AuraState, ExtractedQuad, QuadContent, UiScript}; -/// Load one shipped `assets/ui/`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; fn harness() -> UiScript { let mut s = UiScript::new().unwrap(); diff --git a/crates/benilla-app/src/ui_script/cast_tests.rs b/crates/benilla-app/src/ui_script/cast_tests.rs index dce0d853..153814ec 100644 --- a/crates/benilla-app/src/ui_script/cast_tests.rs +++ b/crates/benilla-app/src/ui_script/cast_tests.rs @@ -10,22 +10,7 @@ use benilla_ui::script::{ExtractedQuad, QuadContent, ScriptValue, UiScript}; -/// Load one shipped `assets/ui/`, panicking on any loader error (the bag/panel tests' loader). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; fn harness() -> UiScript { let mut s = UiScript::new().unwrap(); diff --git a/crates/benilla-app/src/ui_script/character_tests.rs b/crates/benilla-app/src/ui_script/character_tests.rs index 97b59cce..8e82d9b3 100644 --- a/crates/benilla-app/src/ui_script/character_tests.rs +++ b/crates/benilla-app/src/ui_script/character_tests.rs @@ -18,23 +18,7 @@ use benilla_ui::script::{ UnitCombatStats, UnitState, }; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the questlog/panel -/// tests' loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// A Night Elf Warrior, level 12 — the fixture every test below shares for the level/name line. fn player_unit() -> UnitState { @@ -138,6 +122,7 @@ fn backpack_with_fitting_helm() -> benilla_ui::script::ContainerState { /// attack/damage/ranged rows + 5 resistance frames + the model pane + its 2 rotate buttons + chrome). #[test] fn shipped_character_frame_loads_clean() { + let _data = benilla_formats::wow_data_or_skip!(); let s = UiScript::new().unwrap(); load_xml(&s, "Fonts.xml"); load_xml(&s, "MoneyFrame.xml"); @@ -154,6 +139,7 @@ fn shipped_character_frame_loads_clean() { /// and a second toggle closes it again — each transition its own sound. #[test] fn shipped_character_frame_drives_end_to_end() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -369,6 +355,7 @@ fn shipped_character_frame_drives_end_to_end() { /// page's own quads. Checked on the real extracted draw order, not merely the level integer. #[test] fn close_button_draws_above_the_paper_doll_page() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -414,6 +401,7 @@ fn close_button_draws_above_the_paper_doll_page() { /// comment) keep `format()` from erroring outright, rather than the window failing to open at all. #[test] fn level_line_survives_no_player_snapshot_yet() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -447,6 +435,7 @@ fn level_line_survives_no_player_snapshot_yet() { /// the SAME slot cancels: the cursor empties and the dim clears. #[test] fn clicking_an_occupied_doll_slot_picks_it_up_and_locks_it() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -501,6 +490,7 @@ fn clicking_an_occupied_doll_slot_picks_it_up_and_locks_it() { /// this file's own header comment on the emulation). #[test] fn cursor_update_highlights_fitting_doll_slots_while_holding_a_bag_item() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -544,6 +534,7 @@ fn cursor_update_highlights_fitting_doll_slots_while_holding_a_bag_item() { /// `(bag, slot)` source, cursor cleared. #[test] fn model_pane_click_auto_equips_a_held_bag_item() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -581,6 +572,7 @@ fn model_pane_click_auto_equips_a_held_bag_item() { /// armor guy). Repairing it restores both to white. #[test] fn broken_equipped_item_tints_its_doll_slot_red() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -657,6 +649,7 @@ fn broken_equipped_item_tints_its_doll_slot_red() { /// HERE, not on the director's screen. Zero collected handler errors allowed anywhere. #[test] fn tab_round_trip_with_a_selected_skill_by_point() { + let _data = benilla_formats::wow_data_or_skip!(); use benilla_ui::script::{SkillEntry, SkillsState}; let mut s = UiScript::new().unwrap(); @@ -857,6 +850,7 @@ fn tab_round_trip_with_a_selected_skill_by_point() { /// click-LEFT subtracts); that quirk is quoted, so it is asserted here rather than "corrected". #[test] fn rotate_arrows_tap_twice_and_spin_while_held() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -950,6 +944,7 @@ fn rotate_arrows_tap_twice_and_spin_while_held() { /// to miss. #[test] fn a_keybind_page_switch_moves_the_tab_row_with_it() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); @@ -964,7 +959,7 @@ fn a_keybind_page_switch_moves_the_tab_row_with_it() { load_xml(&s, "PetPaperDollFrame.xml"); load_xml(&s, "ReputationFrame.xml"); load_xml(&s, "SkillFrame.xml"); - load_xml(&s, "HonorFrame.xml"); + load_xml(&s, "Interface\\FrameXML\\HonorFrame.xml"); s.set_unit("player", Some(player_unit())); // THE INVARIANT the fix rests on: a page's `id=` is its slot in this window's own tab row, and @@ -1060,6 +1055,7 @@ fn a_keybind_page_switch_moves_the_tab_row_with_it() { /// when it passes `this:GetParent()`. #[test] fn an_addons_tab_click_selects_through_the_generic_entry_point() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); diff --git a/crates/benilla-app/src/ui_script/chat_options_tests.rs b/crates/benilla-app/src/ui_script/chat_options_tests.rs index 3bf17ebd..4cc68c27 100644 --- a/crates/benilla-app/src/ui_script/chat_options_tests.rs +++ b/crates/benilla-app/src/ui_script/chat_options_tests.rs @@ -13,22 +13,7 @@ use benilla_ui::script::UiScript; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The GlobalStrings the menu labels itself with. The app runs the real /// `Interface\FrameXML\GlobalStrings.lua` off the player's own patch chain at boot @@ -62,7 +47,7 @@ fn chat_with_menu() -> UiScript { "UIDropDownMenu.xml", "ScrollTemplates.xml", "UIPanelTemplates.xml", - "ColorPickerFrame.xml", + "Interface\\FrameXML\\ColorPickerFrame.xml", "ChatFrame.xml", ] { load_xml(&s, file); @@ -125,6 +110,7 @@ fn left_click(s: &mut UiScript, frame: &str) { /// options at all" rather than "the menu is missing a row". #[test] fn right_clicking_a_chat_tab_opens_its_options_menu() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_with_menu(); assert!( s.eval::("return not DropDownList1:IsVisible()") @@ -173,6 +159,7 @@ fn right_clicking_a_chat_tab_opens_its_options_menu() { /// change. (The reference's own fork: the right-button arm returns before the select.) #[test] fn a_left_click_still_selects_the_tab_and_opens_no_menu() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_with_menu(); left_click(&mut s, "ChatFrame2Tab"); assert_eq!( @@ -206,6 +193,7 @@ fn a_left_click_still_selects_the_tab_and_opens_no_menu() { /// `204/255`, not as 0.8. #[test] fn the_background_row_opens_the_picker_and_its_opacity_slider_drives_the_window() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_with_menu(); right_click(&mut s, "ChatFrame1Tab"); @@ -274,6 +262,7 @@ fn the_background_row_opens_the_picker_and_its_opacity_slider_drives_the_window( /// hover ramp, which is the look the director signed off in 0288. #[test] fn the_shipped_window_still_fades_zero_to_a_quarter() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_with_menu(); s.mouse_move(1500.0, 850.0); for _ in 0..4 { @@ -301,6 +290,7 @@ fn the_shipped_window_still_fades_zero_to_a_quarter() { /// pick moves both the live font and the stored `SIZE`. #[test] fn the_font_size_submenu_resizes_the_window_and_stores_the_pick() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_with_menu(); right_click(&mut s, "ChatFrame1Tab"); @@ -343,6 +333,7 @@ fn the_font_size_submenu_resizes_the_window_and_stores_the_pick() { /// parent, so a single shared capsule would have written window 1 whichever tab was clicked. #[test] fn each_tabs_menu_writes_its_own_window() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_with_menu(); right_click(&mut s, "ChatFrame2Tab"); assert_eq!( @@ -370,6 +361,7 @@ fn each_tabs_menu_writes_its_own_window() { /// `previousValues` contract, which the reference reaches through the same `cancelFunc` field. #[test] fn cancelling_the_picker_puts_the_window_back() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_with_menu(); // Start from a non-default look so "restored" is distinguishable from "reset". s.run("FCF_SetWindowAlpha(ChatFrame1, 0.4) FCF_SetWindowColor(ChatFrame1, 0.2, 0.4, 0.6)") @@ -405,6 +397,7 @@ fn cancelling_the_picker_puts_the_window_back() { /// the fade latch. #[test] fn the_restore_event_repaints_the_window_from_the_store() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_with_menu(); s.set_chat_window_looks([( 0, diff --git a/crates/benilla-app/src/ui_script/chat_resize_tests.rs b/crates/benilla-app/src/ui_script/chat_resize_tests.rs index 7d841db3..cf49c057 100644 --- a/crates/benilla-app/src/ui_script/chat_resize_tests.rs +++ b/crates/benilla-app/src/ui_script/chat_resize_tests.rs @@ -11,22 +11,7 @@ use benilla_ui::script::UiScript; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The chat dock with everything its tab menu and its grips reach under it. fn chat_ui() -> UiScript { @@ -40,7 +25,7 @@ fn chat_ui() -> UiScript { "UIDropDownMenu.xml", "ScrollTemplates.xml", "UIPanelTemplates.xml", - "ColorPickerFrame.xml", + "Interface\\FrameXML\\ColorPickerFrame.xml", "ChatFrame.xml", ] { load_xml(&s, file); @@ -102,6 +87,7 @@ fn grab_grip(s: &mut UiScript, grip: &str) -> (f32, f32) { /// `GetChatWindowInfo` answers, because it is the chat-cache's own `LOCKED 1`. #[test] fn both_dock_windows_ship_locked() { + let _data = benilla_formats::wow_data_or_skip!(); let s = chat_ui(); for i in 1..=2 { assert_eq!( @@ -133,6 +119,7 @@ fn both_dock_windows_ship_locked() { /// locked, `LOCK_WINDOW` when it is not, `notCheckable`. #[test] fn the_tab_menus_lock_row_toggles_the_window_and_flips_its_label() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); right_click(&mut s, "ChatFrame1Tab"); // Shipped locked, so the row offers the way OUT of it. @@ -183,6 +170,7 @@ fn the_tab_menus_lock_row_toggles_the_window_and_flips_its_label() { /// it — see the template's note), and `FCF_Resize` must refuse even if something did reach it. #[test] fn a_locked_window_refuses_a_grip_drag() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); let before = width(&mut s); assert_eq!(before, 430.0, "the authored width"); @@ -229,6 +217,7 @@ fn a_locked_window_refuses_a_grip_drag() { /// so a window held past its minimum stops shrinking and starts *walking*. #[test] fn an_unlocked_bottom_right_grip_resizes_and_clamps_at_the_bounds() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); s.run("FCF_SetLocked(ChatFrame1, nil)").unwrap(); assert!( @@ -277,6 +266,7 @@ fn an_unlocked_bottom_right_grip_resizes_and_clamps_at_the_bounds() { /// the session. #[test] fn the_release_ends_the_resize_from_anywhere_on_screen() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); s.run("FCF_SetLocked(ChatFrame1, nil)").unwrap(); let (x, y) = grab_grip(&mut s, "ChatFrame1ResizeBottomRight"); @@ -308,6 +298,7 @@ fn the_release_ends_the_resize_from_anywhere_on_screen() { /// held-spell dismissal working on the same button. #[test] fn the_body_drag_moves_an_unlocked_window_and_a_locked_one_stays_put() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); let (cx, cy) = centre(&mut s, "ChatFrame1"); let start = left(&mut s); @@ -348,6 +339,7 @@ fn the_body_drag_moves_an_unlocked_window_and_a_locked_one_stays_put() { /// back on the bottom-stack seat. #[test] fn a_moved_window_is_user_placed_and_the_managed_pass_skips_it() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); // The managed pass owns the seat to begin with — the control for the assertion below. s.run("UIParent_ManageFramePositions()").unwrap(); @@ -388,6 +380,7 @@ fn a_moved_window_is_user_placed_and_the_managed_pass_skips_it() { /// seat it into a *fresh* VM whose windows are all on their authored anchors. #[test] fn the_geometry_round_trips_through_the_save_file() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); s.run("FCF_SetLocked(ChatFrame1, nil)").unwrap(); @@ -455,6 +448,7 @@ fn the_geometry_round_trips_through_the_save_file() { /// so the handles appear with the box and are invisible without it. #[test] fn the_grip_art_follows_the_windows_reveal_and_tint() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); // Off-hover, at the shipped alpha-0 base: everything in the set is invisible. s.run("BenillaFCF.hover = false FCF_OnUpdate(1.0)").unwrap(); @@ -497,6 +491,7 @@ fn the_grip_art_follows_the_windows_reveal_and_tint() { /// clause the box would fade out from under the hand holding it. #[test] fn a_drag_in_flight_holds_the_chrome_visible() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); s.run("FCF_SetLocked(ChatFrame1, nil)").unwrap(); grab_grip(&mut s, "ChatFrame1ResizeBottomRight"); @@ -524,6 +519,7 @@ fn a_drag_in_flight_holds_the_chrome_visible() { /// `FCF_Get_ChatLocked()` gate, which is the first line of both verbs. #[test] fn the_chat_locked_global_overrides_the_per_window_lock() { + let _data = benilla_formats::wow_data_or_skip!(); let s = chat_ui(); s.run("FCF_SetLocked(ChatFrame1, nil)").unwrap(); assert!(s @@ -556,6 +552,7 @@ fn the_chat_locked_global_overrides_the_per_window_lock() { /// reference's third gate — `isDocked and chatFrame ~= DEFAULT_CHAT_FRAME`. #[test] fn the_docked_combat_log_cannot_be_moved_or_resized_on_its_own() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = chat_ui(); s.run("FCF_SetLocked(ChatFrame2, nil)").unwrap(); assert!( diff --git a/crates/benilla-app/src/ui_script/chat_tests.rs b/crates/benilla-app/src/ui_script/chat_tests.rs index b05e7294..3d5cc85f 100644 --- a/crates/benilla-app/src/ui_script/chat_tests.rs +++ b/crates/benilla-app/src/ui_script/chat_tests.rs @@ -7,22 +7,7 @@ use benilla_ui::script::{ExtractedQuad, QuadContent, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The full ChatFrame stack (fonts first, so the FontString's `inherits="ChatFontNormal"` resolves). fn chat_frame() -> UiScript { diff --git a/crates/benilla-app/src/ui_script/cinematic_tests.rs b/crates/benilla-app/src/ui_script/cinematic_tests.rs index 93c47e5f..e39b2eeb 100644 --- a/crates/benilla-app/src/ui_script/cinematic_tests.rs +++ b/crates/benilla-app/src/ui_script/cinematic_tests.rs @@ -15,17 +15,7 @@ use benilla_ui::script::UiScript; -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!(report.errors.is_empty(), "{file}: {:?}", report.errors); -} +use super::test_ui::load_ui as load_xml; /// The frame tree a cinematic actually runs against: `UIParent` (whose `ShowUIPanel` the frame's /// `CINEMATIC_START` arm calls) and the cinematic frame itself. diff --git a/crates/benilla-app/src/ui_script/color_picker_tests.rs b/crates/benilla-app/src/ui_script/color_picker_tests.rs index c9d32be3..dfbbaf98 100644 --- a/crates/benilla-app/src/ui_script/color_picker_tests.rs +++ b/crates/benilla-app/src/ui_script/color_picker_tests.rs @@ -9,22 +9,7 @@ use benilla_ui::script::{QuadContent, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The manifest prefix the picker needs: fonts, the panel manager (`ShowUIPanel`/`HideUIPanel`, /// `UISpecialFrames`, the ESC chain), the shared widget kit (`GameMenuButtonTemplate`), then the @@ -40,7 +25,7 @@ fn picker() -> UiScript { "UIDropDownMenu.xml", "ScrollTemplates.xml", "UIPanelTemplates.xml", - "ColorPickerFrame.xml", + "Interface\\FrameXML\\ColorPickerFrame.xml", ] { load_xml(&s, file); } @@ -73,6 +58,7 @@ fn after_round_trip(r: f64, g: f64, b: f64) -> (f64, f64, f64) { /// `ColorPickerOkayButton` is nil. #[test] fn the_named_pieces_exist_and_their_scripts_are_fetchable() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); assert!(s .eval::("return ColorPickerFrame ~= nil and ColorPickerFrame.SetColorRGB ~= nil") @@ -110,6 +96,7 @@ fn the_named_pieces_exist_and_their_scripts_are_fetchable() { /// this test while the swatch drew nothing. What the renderer receives is the only honest witness. #[test] fn set_color_rgb_paints_the_swatch_and_reads_back_the_widgets_colour() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = picker(); s.run("ShowUIPanel(ColorPickerFrame)").unwrap(); s.run("ColorPickerFrame:SetColorRGB(0.2, 0.4, 0.8)") @@ -139,6 +126,7 @@ fn set_color_rgb_paints_the_swatch_and_reads_back_the_widgets_colour() { /// WIDTH with it. Both arms of the reference's `OnShow` (l.161-170). #[test] fn has_opacity_shows_the_slider_and_widens_the_window() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = picker(); // Without it: no slider, the narrow window. (`GetWidth` reports the *resolved* rect, so the @@ -179,6 +167,7 @@ fn has_opacity_shows_the_slider_and_widens_the_window() { /// and the reference's own `` (l.146-152). #[test] fn the_opacity_slider_drives_opacity_func_on_every_change() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); s.run( r#" @@ -247,6 +236,7 @@ fn dewdrop_open(s: &UiScript, r: f64, g: f64, b: f64, opacity: f64) { /// quantized colour and the slider-derived alpha, and the window closes. #[test] fn the_dewdrop_sequence_commits_on_okay() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); dewdrop_open(&s, 0.1, 0.5, 0.9, 0.25); assert!(s.errors().is_empty(), "{:?}", s.errors()); @@ -296,6 +286,7 @@ fn the_dewdrop_sequence_commits_on_okay() { /// in with, and it does it by *calling `cancelFunc`* — the window has no memory of its own. #[test] fn cancel_restores_the_previous_colour_through_cancel_func() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); dewdrop_open(&s, 0.1, 0.5, 0.9, 0.25); @@ -331,6 +322,7 @@ fn cancel_restores_the_previous_colour_through_cancel_func() { /// open behind it. #[test] fn escape_cancels_rather_than_merely_hiding() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); dewdrop_open(&s, 0.1, 0.5, 0.9, 0.25); s.run("ColorPickerFrame:SetColorRGB(1, 0, 0)").unwrap(); @@ -356,6 +348,7 @@ fn escape_cancels_rather_than_merely_hiding() { /// this library. #[test] fn ace_console_can_chain_the_okay_buttons_onclick() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); s.run( r#" @@ -392,6 +385,7 @@ fn ace_console_can_chain_the_okay_buttons_onclick() { /// world's windows. #[test] fn the_picker_is_a_uispecialframe_and_close_windows_puts_it_away() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); let listed: bool = s .eval( @@ -426,6 +420,7 @@ fn the_picker_is_a_uispecialframe_and_close_windows_puts_it_away() { /// exact one FloatingChatFrame's colour rows use. #[test] fn a_dropdown_row_with_has_color_swatch_opens_the_picker_and_cancel_restores() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); s.run( r#" @@ -506,6 +501,7 @@ fn a_dropdown_row_with_has_color_swatch_opens_the_picker_and_cancel_restores() { /// menu row from sprouting a colour button. #[test] fn a_row_without_the_flag_has_no_swatch() { + let _data = benilla_formats::wow_data_or_skip!(); let s = picker(); s.run( r#" @@ -536,6 +532,7 @@ fn a_row_without_the_flag_has_no_swatch() { /// the picker addresses it by name. #[test] fn the_shipped_window_carries_the_wheel_at_the_references_geometry() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = picker(); s.run("ShowUIPanel(ColorPickerFrame)").unwrap(); s.resolve(); @@ -593,6 +590,7 @@ fn the_shipped_window_carries_the_wheel_at_the_references_geometry() { /// The click is at the wheel's right rim, which the pick law makes 180° — cyan. #[test] fn a_click_on_the_wheel_reaches_the_callers_func() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = picker(); // Dewdrop-2.0.lua l.425-465's block, as transcribed in this file's other tests. s.run( @@ -641,6 +639,7 @@ fn a_click_on_the_wheel_reaches_the_callers_func() { /// if the content is (decision 1592 §4). #[test] fn the_generated_art_reaches_the_renderer_carrying_only_what_moves_a_pixel() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = picker(); s.run("ColorPickerFrame:SetColorRGB(0.15, 0.55, 0.75); ShowUIPanel(ColorPickerFrame)") .unwrap(); diff --git a/crates/benilla-app/src/ui_script/combat_text_tests.rs b/crates/benilla-app/src/ui_script/combat_text_tests.rs index a6e5ca98..024d4383 100644 --- a/crates/benilla-app/src/ui_script/combat_text_tests.rs +++ b/crates/benilla-app/src/ui_script/combat_text_tests.rs @@ -4,23 +4,7 @@ use benilla_ui::script::{ScriptValue, UiScript, UnitState}; -/// Load one shipped `assets/ui/` (the panel tests' loader, duplicated to stay -/// self-contained), panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; fn load_combat_text() -> UiScript { let mut s = UiScript::new().unwrap(); diff --git a/crates/benilla-app/src/ui_script/dressup_tests.rs b/crates/benilla-app/src/ui_script/dressup_tests.rs index fe8407c3..9f07a1df 100644 --- a/crates/benilla-app/src/ui_script/dressup_tests.rs +++ b/crates/benilla-app/src/ui_script/dressup_tests.rs @@ -32,7 +32,7 @@ const ROOM_UI: &[&str] = &[ "UnitPopup.xml", "Interface\\FrameXML\\ItemRef.xml", "MerchantFrame.xml", - "StackSplit.xml", + "Interface\\FrameXML\\StackSplitFrame.xml", "DressUpFrame.xml", "ChatFrame.xml", ]; diff --git a/crates/benilla-app/src/ui_script/dropdown_tests.rs b/crates/benilla-app/src/ui_script/dropdown_tests.rs index 6f9500f5..e79836ff 100644 --- a/crates/benilla-app/src/ui_script/dropdown_tests.rs +++ b/crates/benilla-app/src/ui_script/dropdown_tests.rs @@ -12,21 +12,7 @@ use benilla_ui::script::UiScript; -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The production prefix the lists need (ui_script/mod.rs order): the fonts (this OnLoad reads a /// real font height off Button1's NormalText), UIParent (the lists declare `parent="UIParent"`), diff --git a/crates/benilla-app/src/ui_script/enchant_confirm_tests.rs b/crates/benilla-app/src/ui_script/enchant_confirm_tests.rs index 55ee5ace..ada479d3 100644 --- a/crates/benilla-app/src/ui_script/enchant_confirm_tests.rs +++ b/crates/benilla-app/src/ui_script/enchant_confirm_tests.rs @@ -10,22 +10,7 @@ use benilla_ui::script::{EnchantConfirm, ScriptValue, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; fn setup() -> UiScript { let mut s = UiScript::new().unwrap(); diff --git a/crates/benilla-app/src/ui_script/errors_tests.rs b/crates/benilla-app/src/ui_script/errors_tests.rs index d19b5ff7..a5295d07 100644 --- a/crates/benilla-app/src/ui_script/errors_tests.rs +++ b/crates/benilla-app/src/ui_script/errors_tests.rs @@ -10,23 +10,7 @@ use benilla_ui::script::{ExtractedQuad, QuadContent, ScriptValue, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the panel/quest -/// tests' loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The toast lines as drawn, **top row first**, each with its colour+alpha and its band bottom. fn toast_lines(s: &mut UiScript) -> Vec<(String, [f32; 4], f32)> { @@ -55,7 +39,7 @@ fn info_and_error_messages_stack_hold_and_expire() { let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_xml(&s, "Fonts.xml"); - load_xml(&s, "ErrorsFrame.xml"); + load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml"); // Empty at load. The frame itself is shown — a MessageFrame with nothing to say simply draws // nothing, where the hand-rolled version had to `Hide()` itself. @@ -126,7 +110,7 @@ fn an_error_toast_draws_over_an_open_panel_window() { load_xml(&s, "Fonts.xml"); load_xml(&s, "MoneyFrame.xml"); load_xml(&s, "UiPanels.xml"); - load_xml(&s, "ErrorsFrame.xml"); + load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml"); load_xml(&s, "GameTooltip.xml"); load_xml(&s, "Cooldown.xml"); load_xml(&s, "MerchantFrame.xml"); // BenillaMoney_* — QuestLogDetail's reward money row diff --git a/crates/benilla-app/src/ui_script/escape_tests.rs b/crates/benilla-app/src/ui_script/escape_tests.rs index dd5cd340..cf52ebe2 100644 --- a/crates/benilla-app/src/ui_script/escape_tests.rs +++ b/crates/benilla-app/src/ui_script/escape_tests.rs @@ -231,7 +231,7 @@ fn escape_closes_an_open_stack_split_frame() { } load_xml(&s, "MerchantFrame.xml"); // ContainerFrameItemButton_OnClick reads MerchantFrame load_xml(&s, "ChatFrame.xml"); // …and ChatFrameEditBox, the shift fork's first test - load_xml(&s, "StackSplit.xml"); + load_xml(&s, "Interface\\FrameXML\\StackSplitFrame.xml"); s.set_money(0); let mut slots = std::collections::HashMap::new(); diff --git a/crates/benilla-app/src/ui_script/fade_tests.rs b/crates/benilla-app/src/ui_script/fade_tests.rs index 99282d9f..70e2c4f0 100644 --- a/crates/benilla-app/src/ui_script/fade_tests.rs +++ b/crates/benilla-app/src/ui_script/fade_tests.rs @@ -5,24 +5,7 @@ use benilla_ui::script::UiScript; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error — the same -/// per-file loader every `ui_script` test file carries (these tests only ever need -/// `UiPanels.xml`, where the fade kit lives). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// **The idle fade driver parks itself** (decision 1396's class, the audit's driver-hide item): /// with `FADEFRAMES` empty there is nothing to walk, so the driver's OnUpdate hides its own frame diff --git a/crates/benilla-app/src/ui_script/faux_scroll_tests.rs b/crates/benilla-app/src/ui_script/faux_scroll_tests.rs index f4452656..7b8eae64 100644 --- a/crates/benilla-app/src/ui_script/faux_scroll_tests.rs +++ b/crates/benilla-app/src/ui_script/faux_scroll_tests.rs @@ -17,22 +17,7 @@ use benilla_ui::script::UiScript; -/// One shipped file into `s`, asserting it loaded clean. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// A document written here in the test, loaded against the templates already registered — the /// cross-file template registry is on the `Model`, so an inline doc reaches `ScrollTemplates.xml`'s diff --git a/crates/benilla-app/src/ui_script/frame_flag_gate.rs b/crates/benilla-app/src/ui_script/frame_flag_gate.rs index 42da56b0..7b355f0c 100644 --- a/crates/benilla-app/src/ui_script/frame_flag_gate.rs +++ b/crates/benilla-app/src/ui_script/frame_flag_gate.rs @@ -287,11 +287,6 @@ const KNOWN: &[Known] = &[ flag: Flag::Mouse, why: "inherits BenillaMerchantItemTemplate", }, - Known { - frame: "HonorFrameProgressBar", - flag: Flag::Mouse, - why: "our honour bar carries its own hover tooltip; the reference's page has none", - }, Known { frame: "WorldMapFrame", flag: Flag::Mouse, diff --git a/crates/benilla-app/src/ui_script/friends_tests.rs b/crates/benilla-app/src/ui_script/friends_tests.rs index 0aa4b332..17ec34fe 100644 --- a/crates/benilla-app/src/ui_script/friends_tests.rs +++ b/crates/benilla-app/src/ui_script/friends_tests.rs @@ -9,39 +9,7 @@ use benilla_ui::script::{FriendInfo, SocialRequest, SocialState, UiScript, WhoInfo}; -/// Load one shipped `assets/ui/`, panicking on any loader error — **and on any -/// unknown-template warning**. -/// -/// That second check is not decoration. `inherits=` a template this house doesn't ship is a -/// *warning*, not an error: the frame is still created, just with none of the template's art or -/// size. Every test below stayed green while all eight action buttons and the close button were -/// invisible, because a bare Button still clicks. Only a live run showed it. The guard is here so -/// the next window cannot repeat it. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); - let missing: Vec<&String> = report - .warnings - .iter() - .filter(|w| w.contains("unknown template")) - .collect(); - assert!( - missing.is_empty(), - "{file}: inherits a template this house does not ship (the frame loads, its ART does \ - not): {missing:?}" - ); -} +use super::test_ui::load_ui_strict as load_xml; /// The window's own manifest slice, in `load_default_ui` order. fn setup() -> UiScript { diff --git a/crates/benilla-app/src/ui_script/guild_tests.rs b/crates/benilla-app/src/ui_script/guild_tests.rs index 05573471..5a3befac 100644 --- a/crates/benilla-app/src/ui_script/guild_tests.rs +++ b/crates/benilla-app/src/ui_script/guild_tests.rs @@ -22,40 +22,7 @@ use benilla_ui::script::{GuildState, ScriptValue, UiScript, UnitState}; -/// Load one shipped `assets/ui/`, panicking on any loader error — **and on any -/// unknown-template warning**. -/// -/// Copied from `friends_tests` on purpose, and the reason is its own: `inherits=` a template this -/// house doesn't ship is a *warning*, not an error — the frame is still created, just with none of -/// the template's art or size. Every social-window test stayed green while all eight action buttons -/// and the close button were invisible, because a bare Button still clicks (decision 0672). The -/// guild pane inherits four shared templates from `UIPanelTemplates.xml` and four local ones; this -/// is what makes a typo in any of the eight loud. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); - let missing: Vec<&String> = report - .warnings - .iter() - .filter(|w| w.contains("unknown template")) - .collect(); - assert!( - missing.is_empty(), - "{file}: inherits a template this house does not ship (the frame loads, its ART does \ - not): {missing:?}" - ); -} +use super::test_ui::load_ui_strict as load_xml; /// The guild engine API, stood in for in Lua (see the module header). /// diff --git a/crates/benilla-app/src/ui_script/honor_frame_tests.rs b/crates/benilla-app/src/ui_script/honor_frame_tests.rs index 9bd8524b..6977993f 100644 --- a/crates/benilla-app/src/ui_script/honor_frame_tests.rs +++ b/crates/benilla-app/src/ui_script/honor_frame_tests.rs @@ -19,23 +19,7 @@ use benilla_ui::script::{HonorState, UiScript, UnitState}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the -/// character/reputation tests' loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The fixture snapshot — a rank-12 Alliance character with a figure in every bucket, all thirteen /// distinct so a swapped pair of rows cannot pass. Deliberately the same numbers as the protocol @@ -92,7 +76,7 @@ fn load_page(s: &UiScript) { "UIPanelTemplates.xml", "OptionsFrameTemplates.xml", "CharacterFrame.xml", - "HonorFrame.xml", + "Interface\\FrameXML\\HonorFrame.xml", ] { load_xml(s, file); } @@ -138,6 +122,7 @@ fn text(s: &mut UiScript, frame: &str) -> String { /// standing against a kill count — fails here and only here. #[test] fn every_figure_lands_in_its_own_row() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = shown_honor_page(); for (frame, want) in [ ("HonorFrameCurrentHKValue", "17"), @@ -164,6 +149,7 @@ fn every_figure_lands_in_its_own_row() { /// makes it impossible to ship. #[test] fn the_title_is_the_internal_rank_and_the_badge_is_the_visual_one() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = shown_honor_page(); assert_eq!(text(&mut s, "HonorFrameCurrentPVPTitle"), "Knight-Captain"); // Internal 12 → visual 8. The line reads "(Rank 8)", never "(Rank 12)". @@ -186,6 +172,7 @@ fn the_title_is_the_internal_rank_and_the_badge_is_the_visual_one() { /// badge. The nil is the mechanism, so this is the case that proves the pane never invents a title. #[test] fn an_unranked_character_reads_none_and_shows_no_badge() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = shown_honor_page(); s.set_honor(Some(HonorState { rank: 0, @@ -217,6 +204,7 @@ fn an_unranked_character_reads_none_and_shows_no_badge() { /// resolved — a bar with no colour at all would read as a broken pane. #[test] fn the_bar_takes_the_fraction_and_the_faction_colour() { + let _data = benilla_formats::wow_data_or_skip!(); let s = shown_honor_page(); // Against the binding's own arithmetic, not against `191/255`. The client MULTIPLIES by the // f32 nearest 1/255 (`0x3B808081`, wow-re `honor-panel-law.md` `0x51aace`) rather than @@ -255,6 +243,7 @@ fn the_bar_takes_the_fraction_and_the_faction_colour() { /// the flag's *derivation from the event name* is the half that can be got wrong. #[test] fn a_kill_repaints_the_session_but_not_the_week() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = shown_honor_page(); // Everything moves in the snapshot — including a weekly figure, which is the bait. s.set_honor(Some(HonorState { @@ -262,8 +251,7 @@ fn a_kill_repaints_the_session_but_not_the_week() { this_week_hk: 124, ..state() })); - s.run(r#"HonorFrame_OnEvent("PLAYER_PVP_KILLS_CHANGED")"#) - .unwrap(); + s.fire_event("PLAYER_PVP_KILLS_CHANGED", vec![]); s.resolve(); assert_eq!( text(&mut s, "HonorFrameCurrentHKValue"), @@ -277,8 +265,7 @@ fn a_kill_repaints_the_session_but_not_the_week() { ); // World entry is the flag that says "repaint those too". - s.run(r#"HonorFrame_OnEvent("PLAYER_ENTERING_WORLD")"#) - .unwrap(); + s.fire_event("PLAYER_ENTERING_WORLD", vec![]); s.resolve(); assert_eq!(text(&mut s, "HonorFrameThisWeekHKValue"), "124"); assert!(s.errors().is_empty(), "script errors: {:?}", s.errors()); @@ -378,7 +365,7 @@ fn shown_inspect_honor_page() -> UiScript { "GameTooltip.xml", // Before InspectFrame.xml — the honor page inherits this file's row templates and calls // its two shared painters, and `inherits=` resolves at load (the manifest's own order). - "HonorFrame.xml", + "Interface\\FrameXML\\HonorFrame.xml", "InspectFrame.xml", ] { load_xml(&s, file); @@ -406,6 +393,7 @@ fn shown_inspect_honor_page() -> UiScript { /// not the player. Everything the character page's row test pins, on the other feed. #[test] fn the_inspect_page_paints_the_reply_it_holds() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = shown_inspect_honor_page(); for (frame, want) in [ ("BenillaInspectHonorFrameCurrentHKValue", "17"), @@ -454,6 +442,7 @@ fn the_inspect_page_paints_the_reply_it_holds() { /// happens to be held looks identical either way. #[test] fn the_page_asks_only_when_it_holds_nothing() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = shown_inspect_honor_page(); // Held: the open above consumed no request. assert_eq!( diff --git a/crates/benilla-app/src/ui_script/inspect_tests.rs b/crates/benilla-app/src/ui_script/inspect_tests.rs index 29449029..eeaf2ec8 100644 --- a/crates/benilla-app/src/ui_script/inspect_tests.rs +++ b/crates/benilla-app/src/ui_script/inspect_tests.rs @@ -35,22 +35,7 @@ fn reach(dist_sq: f64) -> UnitReach { } } -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The inspected player: a Dwarf Paladin, level 34. fn target_unit() -> UnitState { @@ -132,7 +117,7 @@ fn armed() -> UiScript { // Before InspectFrame.xml, and required rather than tidy: this window's honor page inherits // HonorFrame.xml's five row templates and `inherits=` resolves at LOAD, so without it the // twelve honor rows materialize bare (decision 1512; the manifest states the same order). - load_xml(&s, "HonorFrame.xml"); + load_xml(&s, "Interface\\FrameXML\\HonorFrame.xml"); load_xml(&s, "InspectFrame.xml"); s.set_unit("target", Some(target_unit())); s.set_inspect(Some(inspect_view("target"))); @@ -144,6 +129,7 @@ fn armed() -> UiScript { /// The loader itself: the window and its 19 slots + model pane materialize with no errors. #[test] fn shipped_inspect_frame_loads_clean() { + let _data = benilla_formats::wow_data_or_skip!(); let s = UiScript::new().unwrap(); load_xml(&s, "Fonts.xml"); load_xml(&s, "MoneyFrame.xml"); @@ -152,7 +138,7 @@ fn shipped_inspect_frame_loads_clean() { // Before InspectFrame.xml, and required rather than tidy: this window's honor page inherits // HonorFrame.xml's five row templates and `inherits=` resolves at LOAD, so without it the // twelve honor rows materialize bare (decision 1512; the manifest states the same order). - load_xml(&s, "HonorFrame.xml"); + load_xml(&s, "Interface\\FrameXML\\HonorFrame.xml"); load_xml(&s, "InspectFrame.xml"); // All 19 slots exist and carry their GetInventorySlotInfo id (1..=19, no ammo slot). for (name, id) in [ @@ -174,6 +160,7 @@ fn shipped_inspect_frame_loads_clean() { /// call in range does both. A `CanInspect` stuck truthy passes every other test in this file. #[test] fn inspect_unit_refuses_out_of_range() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = armed(); // 11 yards (d² = 121) — past the verified 100.0 threshold. s.set_unit_reach(HashMap::from([("target".to_string(), reach(121.0))])); @@ -212,6 +199,7 @@ fn inspect_unit_refuses_out_of_range() { /// silently normalizes — hence a test on the boundary itself. #[test] fn range_predicates_transcribe_the_verified_thresholds() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = armed(); for (d2, can_inspect, interact1) in [ (99.9_f64, true, true), @@ -301,6 +289,7 @@ fn range_predicates_transcribe_the_verified_thresholds() { /// slot; the inspected token must read the foreign one and `"player"` must still read ours. #[test] fn inventory_bindings_route_by_unit_token() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = armed(); s.set_inventory_slots(own_slots()); @@ -336,6 +325,7 @@ fn inventory_bindings_route_by_unit_token() { /// moving the booth yaw, and closing firing `ClearInspectPlayer`. #[test] fn shipped_inspect_frame_drives_end_to_end() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = armed(); // Hidden at load, and no sound queued (never transitions on startup). @@ -473,6 +463,7 @@ fn shipped_inspect_frame_drives_end_to_end() { /// second one non-obvious. #[test] fn the_active_tab_is_inert_and_toggle_inspect_closes() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = armed(); s.run(r#"InspectUnit("target")"#).unwrap(); let _ = s.take_sounds(); diff --git a/crates/benilla-app/src/ui_script/instance_tests.rs b/crates/benilla-app/src/ui_script/instance_tests.rs index 94032649..fc04bf96 100644 --- a/crates/benilla-app/src/ui_script/instance_tests.rs +++ b/crates/benilla-app/src/ui_script/instance_tests.rs @@ -8,22 +8,7 @@ use benilla_ui::script::UiScript; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The three bindings answer with the reference's own shapes — `IsInInstance` a PAIR, both /// readers `1`/`nil` rather than `true`/`false` (the reference pushes the double 1.0), and diff --git a/crates/benilla-app/src/ui_script/mod.rs b/crates/benilla-app/src/ui_script/mod.rs index fa05ed51..5af9e319 100644 --- a/crates/benilla-app/src/ui_script/mod.rs +++ b/crates/benilla-app/src/ui_script/mod.rs @@ -767,6 +767,13 @@ impl benilla_ui::script::TextMeasure for FixedWidthFont { #[cfg(test)] mod test_ui; +/// [`test_ui::load_ui`] for a test module OUTSIDE `ui_script` — `ui_action::feed_tests` drives the +/// real `UIErrorsFrame` end to end and needs the same both-stores reader everything else uses. +#[cfg(test)] +pub(crate) fn load_ui_for_test(script: &benilla_ui::script::UiScript, entry: &str) -> usize { + test_ui::load_ui(script, entry) +} + #[cfg(test)] mod cinematic_tests; diff --git a/crates/benilla-app/src/ui_script/money_frame_tests.rs b/crates/benilla-app/src/ui_script/money_frame_tests.rs index d173502a..bb0861a7 100644 --- a/crates/benilla-app/src/ui_script/money_frame_tests.rs +++ b/crates/benilla-app/src/ui_script/money_frame_tests.rs @@ -15,22 +15,7 @@ use benilla_ui::script::{QuadContent, UiScript}; -/// One shipped file into `s`, asserting it loaded clean. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The kit plus the two frames an addon would declare: one on each template. fn harness(money: u64) -> UiScript { diff --git a/crates/benilla-app/src/ui_script/multibar_stance_tests.rs b/crates/benilla-app/src/ui_script/multibar_stance_tests.rs index 40b7351c..37f8174b 100644 --- a/crates/benilla-app/src/ui_script/multibar_stance_tests.rs +++ b/crates/benilla-app/src/ui_script/multibar_stance_tests.rs @@ -7,22 +7,7 @@ use benilla_ui::script::{ActionSlot, QuadContent, ScriptValue, SpellTooltipView, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "loader errors in {file}: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// Load the shipped `UIParent.xml` (UIParent_ManageFramePositions — the stance bar's /// OnShow/OnHide calls it, decision 0272; the runtime loads it before every bar) + diff --git a/crates/benilla-app/src/ui_script/panel_template_tests.rs b/crates/benilla-app/src/ui_script/panel_template_tests.rs index d6e25e62..a368ce81 100644 --- a/crates/benilla-app/src/ui_script/panel_template_tests.rs +++ b/crates/benilla-app/src/ui_script/panel_template_tests.rs @@ -30,17 +30,7 @@ use benilla_ui::script::UiScript; -/// One shipped file into `s`, asserting it loaded clean. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string(ui_dir().join(file)).unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; fn ui_dir() -> std::path::PathBuf { std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("assets/ui") diff --git a/crates/benilla-app/src/ui_script/perf_bar_tests.rs b/crates/benilla-app/src/ui_script/perf_bar_tests.rs index 5e8ca494..f6e072ab 100644 --- a/crates/benilla-app/src/ui_script/perf_bar_tests.rs +++ b/crates/benilla-app/src/ui_script/perf_bar_tests.rs @@ -7,22 +7,7 @@ use benilla_ui::script::{QuadContent, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The bar on a 1024×768 screen. 1024 wide is deliberate: the 1024-wide bar then spans x 0..1024, /// so every ref offset below is also an absolute screen coordinate. diff --git a/crates/benilla-app/src/ui_script/pet_bar_tests.rs b/crates/benilla-app/src/ui_script/pet_bar_tests.rs index b840b4a9..5ea329d4 100644 --- a/crates/benilla-app/src/ui_script/pet_bar_tests.rs +++ b/crates/benilla-app/src/ui_script/pet_bar_tests.rs @@ -4,22 +4,7 @@ use benilla_ui::script::{PetActionView, QuadContent, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "loader errors in {file}: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The pet bar's own load prerequisites, in manifest order: UiPanels (`SetDesaturation`, the /// disabled-bar grey), UIParent (the managed bottom stack its OnShow/OnHide re-fires), Cooldown diff --git a/crates/benilla-app/src/ui_script/pet_frame_tests.rs b/crates/benilla-app/src/ui_script/pet_frame_tests.rs index 6d1c3ec9..3849e4ec 100644 --- a/crates/benilla-app/src/ui_script/pet_frame_tests.rs +++ b/crates/benilla-app/src/ui_script/pet_frame_tests.rs @@ -9,23 +9,7 @@ use benilla_ui::script::{ AuraState, QuadContent, ScriptValue, SelectionRequest, UiScript, UnitState, }; -/// Load one shipped `assets/ui/`, panicking on any loader error (the unit-frame tests' -/// loader). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The pet frame's production load prefix — it is parented to `PlayerFrame`, so the whole /// unit-frame file comes with it, and the tooltip/dropdown kit its hover and its neighbours need. diff --git a/crates/benilla-app/src/ui_script/pet_paperdoll_tests.rs b/crates/benilla-app/src/ui_script/pet_paperdoll_tests.rs index 4b04233f..fca956e1 100644 --- a/crates/benilla-app/src/ui_script/pet_paperdoll_tests.rs +++ b/crates/benilla-app/src/ui_script/pet_paperdoll_tests.rs @@ -11,22 +11,7 @@ use benilla_ui::script::{ PetStats, QuadContent, ScriptValue, UiScript, UnitCombatStats, UnitState, }; -/// Load one shipped `assets/ui/`, panicking on any loader error (the character tests' loader). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The page's production load prefix — it leans on `CharacterFrame.xml` for the shared setters, /// the row templates and the tab row itself, exactly as the manifest orders them. diff --git a/crates/benilla-app/src/ui_script/petition_tests.rs b/crates/benilla-app/src/ui_script/petition_tests.rs index 03b0c866..925566e7 100644 --- a/crates/benilla-app/src/ui_script/petition_tests.rs +++ b/crates/benilla-app/src/ui_script/petition_tests.rs @@ -19,36 +19,7 @@ use benilla_ui::script::UiScript; -/// Load one shipped `assets/ui/`, panicking on any loader error **and on any -/// unknown-template warning** — `guild_tests`' loader, and the decision-0672 reason is the same: -/// `inherits=` a template this house doesn't ship is a *warning*, the frame still loads, and a -/// bare Button still clicks. Both windows here inherit from `UIPanelTemplates.xml` and -/// `MoneyFrame.xml`, and the registrar defines one local template of its own. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); - let missing: Vec<&String> = report - .warnings - .iter() - .filter(|w| w.contains("unknown template")) - .collect(); - assert!( - missing.is_empty(), - "{file}: inherits a template this house does not ship (the frame loads, its ART does \ - not): {missing:?}" - ); -} +use super::test_ui::load_ui_strict as load_xml; /// The charter engine API, stood in for in Lua. /// @@ -114,13 +85,31 @@ fn setup() -> UiScript { let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); s.run(PETITION_FIXTURE).unwrap(); + // The player's own strings: the reference's `PetitionFrame_Update` formats + // GUILD_CHARTER_TEMPLATE and reads GUILD_PETITION_*_INSTRUCTIONS and NOT_YET_SIGNED straight + // out of GlobalStrings, with no fallback of its own — `format(nil, …)` raises, and the window + // never paints. + load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua"); load_xml(&s, "Fonts.xml"); load_xml(&s, "BasicControls.xml"); load_xml(&s, "MoneyFrame.xml"); load_xml(&s, "UiPanels.xml"); load_xml(&s, "UIPanelTemplates.xml"); - load_xml(&s, "GuildRegistrarFrame.xml"); - load_xml(&s, "PetitionFrame.xml"); + // `QuestTitleButtonTemplate`, which the reference's registrar inherits for its two service + // rows — 1.12 declares it in QuestFrameTemplates.xml, an `` of QuestFrame.xml, and + // ours declares it in QuestFrame.xml directly. An unknown template is a loader WARNING, so + // without this the rows build with no art at all and nothing goes red — which is exactly the + // failure `load_ui_strict` exists to turn into a red test. + load_xml(&s, "ScrollTemplates.xml"); + load_xml(&s, "QuestFrame.xml"); + // `ChatFrameEditBox`, which the reference's own purchase button indexes on every click to + // decide where focus goes after the name box closes — a nil there raises before the charter is + // bought. Ours guarded it; the reference does not. + load_xml(&s, "GameTooltip.xml"); // TOOLTIP_DEFAULT_COLOR, read by the dropdown backdrops + load_xml(&s, "UIDropDownMenu.xml"); // ChatFrame's seven dropdowns inherit its template + load_xml(&s, "ChatFrame.xml"); + load_xml(&s, "Interface\\FrameXML\\GuildRegistrarFrame.xml"); + load_xml(&s, "Interface\\FrameXML\\PetitionFrame.xml"); s } @@ -161,6 +150,7 @@ fn show_registrar(s: &mut UiScript) { /// blank row 2 while every other assertion here still passed. #[test] fn a_signers_charter_shows_the_sign_face_and_nine_rows() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); show_petition(&mut s); @@ -223,6 +213,7 @@ fn a_signers_charter_shows_the_sign_face_and_nine_rows() { /// either view alone. #[test] fn the_owners_charter_swaps_sign_for_request_and_rename() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); s.run("BenillaPetitionFixture.isOriginator = 1").unwrap(); show_petition(&mut s); @@ -245,6 +236,7 @@ fn the_owners_charter_swaps_sign_for_request_and_rename() { /// still pass. #[test] fn request_signature_disables_at_the_wires_requirement_not_at_nine() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); s.run( r#" @@ -279,6 +271,7 @@ fn request_signature_disables_at_the_wires_requirement_not_at_nine() { /// a signer's view and still be unsignable (already signed, already guilded, full). #[test] fn the_sign_button_follows_can_sign_petition() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); show_petition(&mut s); assert!(s @@ -304,6 +297,7 @@ fn the_sign_button_follows_can_sign_petition() { /// window closes, and without it the engine keeps a charter session for a window nobody can see. #[test] fn the_charter_buttons_reach_their_verbs_and_the_close_clears_the_session() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); show_petition(&mut s); let _ = calls(&s); @@ -326,6 +320,7 @@ fn the_charter_buttons_reach_their_verbs_and_the_close_clears_the_session() { /// 24-character charter-name limit. #[test] fn rename_guild_sends_the_box_text_and_caps_at_twenty_four() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); s.run("BenillaPetitionFixture.isOriginator = 1").unwrap(); show_petition(&mut s); @@ -358,6 +353,7 @@ fn rename_guild_sends_the_box_text_and_caps_at_twenty_four() { /// before the player has typed a name. #[test] fn the_registrar_opens_on_services_and_purchase_is_a_local_panel_swap() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); show_registrar(&mut s); @@ -409,6 +405,7 @@ fn the_registrar_opens_on_services_and_purchase_is_a_local_panel_swap() { /// window will be told. #[test] fn purchase_sends_the_typed_name_and_register_turns_the_charter_in() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); show_registrar(&mut s); s.run("GuildRegistrarButton1:Click()").unwrap(); @@ -444,6 +441,7 @@ fn purchase_sends_the_typed_name_and_register_turns_the_charter_in() { /// charter list, and the greeting panel never displays one. #[test] fn the_charter_price_is_read_when_the_purchase_panel_opens() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); show_registrar(&mut s); s.run("GuildRegistrarButton1:Click()").unwrap(); @@ -456,6 +454,7 @@ fn the_charter_price_is_read_when_the_purchase_panel_opens() { /// panel left over from last time. #[test] fn reopening_the_registrar_returns_to_the_services_list() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); show_registrar(&mut s); s.run("GuildRegistrarButton1:Click()").unwrap(); @@ -472,6 +471,7 @@ fn reopening_the_registrar_returns_to_the_services_list() { /// in no slot and two left-slot windows paint over each other (B288's shape, decision 1507). #[test] fn both_charter_windows_are_registered_left_slot_panels() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = setup(); for frame in ["GuildRegistrarFrame", "PetitionFrame"] { assert_eq!( diff --git a/crates/benilla-app/src/ui_script/quest_tests.rs b/crates/benilla-app/src/ui_script/quest_tests.rs index f71ed81b..5068eaa0 100644 --- a/crates/benilla-app/src/ui_script/quest_tests.rs +++ b/crates/benilla-app/src/ui_script/quest_tests.rs @@ -5,23 +5,7 @@ use benilla_ui::script::{QuestPanel, QuestState, ScriptValue, SoundRequest, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the panel tests' -/// loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The questgiver window's open/close kits — the window-sound convention (decision 0090). The real /// QuestFrame.lua plays igQuestListOpen in QuestFrame_OnShow (l.285) and igQuestListClose in diff --git a/crates/benilla-app/src/ui_script/quest_timer_tests.rs b/crates/benilla-app/src/ui_script/quest_timer_tests.rs index e22356f2..1c14cec5 100644 --- a/crates/benilla-app/src/ui_script/quest_timer_tests.rs +++ b/crates/benilla-app/src/ui_script/quest_timer_tests.rs @@ -13,22 +13,7 @@ use benilla_ui::script::{ QuestLogEntryView, QuestLogObjectiveView, QuestLogState, ScriptValue, UiScript, }; -/// Load one shipped `assets/ui/`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// Fonts + UIParent (SecondsToTime lives there) + the window itself. Deliberately NOT the whole /// manifest: the window must stand up on its own dependencies, and a harness that loads everything @@ -36,9 +21,22 @@ fn load_xml(s: &UiScript, file: &str) { fn harness() -> UiScript { let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); + // The window's title is `text="QUEST_TIMERS"`, resolved against the global at load — without + // the player's own strings it draws the KEY, which is exactly what a `text=` attribute does + // with an unknown name. + load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua"); load_xml(&s, "Fonts.xml"); + // `SecondsToTime`, which the reference's `QuestTimerFrame_Update` formats every row with, and + // `UIParent_ManageFramePositions`, which its OnShow/OnHide call. load_xml(&s, "UIParent.xml"); - load_xml(&s, "QuestTimerFrame.xml"); + // `MAX_QUESTS`, the loop bound the reference's repaint hides its spare rows with. 1.12 + // declares it on QuestLogFrame.lua:2 and so do we (1751 window 16) — a nil there is + // `'for' limit must be a number` on the first repaint, not a missing row. + load_xml(&s, "MoneyFrame.xml"); + load_xml(&s, "UiPanels.xml"); + load_xml(&s, "ScrollTemplates.xml"); + load_xml(&s, "QuestLogFrame.xml"); + load_xml(&s, "Interface\\FrameXML\\QuestTimerFrame.xml"); s } @@ -83,6 +81,7 @@ fn row_text(s: &UiScript, i: u32) -> String { /// `45 + 16·n`; and back to hidden when the last timer goes. #[test] fn the_window_follows_the_timed_quests() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = harness(); // An untimed log: QUEST_LOG_UPDATE fires, the frame stays down. @@ -132,6 +131,7 @@ fn the_window_follows_the_timed_quests() { /// and `mirror_timer_tests` were both written for. #[test] fn the_countdown_reaches_the_draw_list() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = harness(); s.set_quest_log(log(vec![quest(1, "Deliver the Message", 1_000_860)])); s.set_server_unix_time(1_000_000.0); @@ -162,6 +162,7 @@ fn the_countdown_reaches_the_draw_list() { /// change again. #[test] fn a_world_entry_paints_a_quest_already_running() { + let _data = benilla_formats::wow_data_or_skip!(); let mut s = harness(); s.set_quest_log(log(vec![quest(1, "Deliver the Message", 1_000_090)])); s.set_server_unix_time(1_000_000.0); @@ -181,12 +182,20 @@ fn a_world_entry_paints_a_quest_already_running() { /// `QuestTimer1: ours [(140.0, 16.0), (0.0, -29.0)] != ref [(140.0, 16.0), (0.0, -30.0)]`. #[test] fn the_window_geometry_matches_the_reference_framexml() { - let Some(reference) = super::framexml_diff::reference("QuestTimerFrame.xml") else { + let _data = benilla_formats::wow_data_or_skip!(); + let Some(reference) = + super::framexml_diff::reference("Interface\\FrameXML\\QuestTimerFrame.xml") + else { eprintln!("skipping: no extracted FrameXML"); return; }; // No exemptions: this window's frames keep the reference's bare names (decision 0591 §3 — the // manage pass and the ref's own row lookup both resolve by literal name), and every number in // it is the reference's. If an entry ever needs to go here, it names its reason. - super::framexml_diff::assert_geometry_matches("QuestTimerFrame.xml", &reference, &[], 22); + super::framexml_diff::assert_geometry_matches( + "Interface\\FrameXML\\QuestTimerFrame.xml", + &reference, + &[], + 22, + ); } diff --git a/crates/benilla-app/src/ui_script/questlog_tests.rs b/crates/benilla-app/src/ui_script/questlog_tests.rs index 66c1ccd1..95869563 100644 --- a/crates/benilla-app/src/ui_script/questlog_tests.rs +++ b/crates/benilla-app/src/ui_script/questlog_tests.rs @@ -8,23 +8,7 @@ use benilla_ui::script::{ QuestLogEntryView, QuestLogObjectiveView, QuestLogState, SoundRequest, UiScript, }; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the panel/quest -/// tests' loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// Find a bare frame's own rect via its `QuadContent::Frame` entry (`panel_tests.rs`'s helper, /// duplicated) — used to locate the window so the wheel test's coordinates land inside it. @@ -427,11 +411,11 @@ fn watch_guards_no_op_without_erroring() { load_xml(&s, "MoneyFrame.xml"); load_xml(&s, "UiPanels.xml"); load_xml(&s, "MerchantFrame.xml"); - load_xml(&s, "ErrorsFrame.xml"); // the guards' red-line surface - // ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits - // UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error — - // an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar - // silently. + load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml"); // the guards' red-line surface + // ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits + // UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error — + // an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar + // silently. load_xml(&s, "ScrollTemplates.xml"); load_xml(&s, "UIPanelTemplates.xml"); load_xml(&s, "QuestLogFrame.xml"); diff --git a/crates/benilla-app/src/ui_script/raid_tests.rs b/crates/benilla-app/src/ui_script/raid_tests.rs index 98cb1632..f7474695 100644 --- a/crates/benilla-app/src/ui_script/raid_tests.rs +++ b/crates/benilla-app/src/ui_script/raid_tests.rs @@ -16,35 +16,7 @@ use benilla_ui::script::{ UiScript, }; -/// Load one shipped `assets/ui/`, panicking on any loader error **or unknown-template -/// warning** — `friends_tests::load_xml`'s reason verbatim: `inherits=` a template this house does -/// not ship is a warning, the frame still loads, and every behavioural test stays green while the -/// art is missing. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); - let missing: Vec<&String> = report - .warnings - .iter() - .filter(|w| w.contains("unknown template")) - .collect(); - assert!( - missing.is_empty(), - "{file}: inherits a template this house does not ship (the frame loads, its ART does \ - not): {missing:?}" - ); -} +use super::test_ui::load_ui_strict as load_xml; /// The window's slice of the manifest, in `load_default_ui` order. `UIParent.xml` is in it for /// two functions the pane really calls — `MouseIsOver` (the drag's hover sweep) and diff --git a/crates/benilla-app/src/ui_script/reputation_frame_tests.rs b/crates/benilla-app/src/ui_script/reputation_frame_tests.rs index 5156c872..b4085586 100644 --- a/crates/benilla-app/src/ui_script/reputation_frame_tests.rs +++ b/crates/benilla-app/src/ui_script/reputation_frame_tests.rs @@ -15,23 +15,7 @@ use benilla_ui::script::{FactionEntry, ReputationState, UiScript, UnitState}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the -/// skills/character tests' loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// An ordinary bar row: visible, not a header, `standing_id` 5 ("Friendly") sitting 1000 into a /// 6000-wide rank window. The same numbers `benilla-ui`'s own fixture uses. diff --git a/crates/benilla-app/src/ui_script/screenshot_tests.rs b/crates/benilla-app/src/ui_script/screenshot_tests.rs index 2174c3b2..c2182023 100644 --- a/crates/benilla-app/src/ui_script/screenshot_tests.rs +++ b/crates/benilla-app/src/ui_script/screenshot_tests.rs @@ -8,21 +8,7 @@ use benilla_ui::script::UiScript; -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; fn harness() -> UiScript { let mut s = UiScript::new().unwrap(); diff --git a/crates/benilla-app/src/ui_script/skills_frame_tests.rs b/crates/benilla-app/src/ui_script/skills_frame_tests.rs index 2d27b3a0..9e84b890 100644 --- a/crates/benilla-app/src/ui_script/skills_frame_tests.rs +++ b/crates/benilla-app/src/ui_script/skills_frame_tests.rs @@ -14,23 +14,7 @@ use benilla_ui::script::{QuadContent, SkillEntry, SkillsState, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the -/// character/spellbook tests' loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; fn skill( skill_id: u32, diff --git a/crates/benilla-app/src/ui_script/spellbook_tests.rs b/crates/benilla-app/src/ui_script/spellbook_tests.rs index 490c5e8f..cb3e422a 100644 --- a/crates/benilla-app/src/ui_script/spellbook_tests.rs +++ b/crates/benilla-app/src/ui_script/spellbook_tests.rs @@ -5,23 +5,7 @@ use benilla_ui::script::{SpellBookState, SpellSlotView, SpellTabView, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the -/// character/questlog tests' loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// Two tabs' worth of a small book: "Fire" (Fireball, Fire Blast — slots 0-1) and "Frost" (Frost /// Armor — slot 2), the flat `slots` in tab order. `offset` is each tab's 0-based start index into diff --git a/crates/benilla-app/src/ui_script/target_aura_tests.rs b/crates/benilla-app/src/ui_script/target_aura_tests.rs index 024f0f65..9c03bb95 100644 --- a/crates/benilla-app/src/ui_script/target_aura_tests.rs +++ b/crates/benilla-app/src/ui_script/target_aura_tests.rs @@ -11,21 +11,7 @@ use benilla_ui::script::{AuraState, QuadContent, ScriptValue, UiScript, UnitState}; -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; fn harness() -> UiScript { let mut s = UiScript::new().unwrap(); diff --git a/crates/benilla-app/src/ui_script/taxi_tests.rs b/crates/benilla-app/src/ui_script/taxi_tests.rs index 6a38d972..0e50f667 100644 --- a/crates/benilla-app/src/ui_script/taxi_tests.rs +++ b/crates/benilla-app/src/ui_script/taxi_tests.rs @@ -8,23 +8,7 @@ use benilla_ui::script::{ScriptValue, TaxiNodeType, TaxiUiNode, TaxiUiState, UiScript}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) -> usize { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); - report.frames -} +use super::test_ui::load_ui as load_xml; /// Load the taxi window + its deps into a fresh script, screen sized. fn taxi_script() -> UiScript { @@ -34,7 +18,7 @@ fn taxi_script() -> UiScript { load_xml(&s, "MoneyFrame.xml"); load_xml(&s, "UiPanels.xml"); load_xml(&s, "GameTooltip.xml"); // TaxiNodeOnButtonEnter's tooltip + SetTooltipMoney - load_xml(&s, "ErrorsFrame.xml"); // BenillaErrorsFrame_AddMessage — DrawOneHopLines' refusal + load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml"); // BenillaErrorsFrame_AddMessage — DrawOneHopLines' refusal load_xml(&s, "TaxiFrame.xml"); s } diff --git a/crates/benilla-app/src/ui_script/test_ui.rs b/crates/benilla-app/src/ui_script/test_ui.rs index 8b712792..f8fc34f9 100644 --- a/crates/benilla-app/src/ui_script/test_ui.rs +++ b/crates/benilla-app/src/ui_script/test_ui.rs @@ -28,6 +28,21 @@ use benilla_ui::script::UiScript; /// **A chain entry needs client data**, so a test that names one has to open with /// `benilla_formats::wow_data_or_skip!()`; [`BAG_UI`] is a list that always does. pub(super) fn load_ui(s: &UiScript, entry: &str) -> usize { + load_entry(s, entry, false) +} + +/// [`load_ui`], and **a missing template is a failure too**. +/// +/// A frame that inherits a template nothing declares is a loader *warning*, not an error: the frame +/// is built and simply has none of the template's art. So an under-loaded dependency list passes +/// [`load_ui`] and then loses a window's whole skin silently — which is why four of the social +/// windows' test modules grew this check by hand. It is one function now rather than four copies, +/// and any test may ask for it. +pub(super) fn load_ui_strict(s: &UiScript, entry: &str) -> usize { + load_entry(s, entry, true) +} + +fn load_entry(s: &UiScript, entry: &str, strict_templates: bool) -> usize { let path = entry.replace('\\', "/"); let bytes = read(&path).unwrap_or_else(|| panic!("{entry}: not found")); if path.to_ascii_lowercase().ends_with(".lua") { @@ -44,6 +59,18 @@ pub(super) fn load_ui(s: &UiScript, entry: &str) -> usize { "{entry}: loader errors: {:?}", report.errors ); + if strict_templates { + let missing: Vec<&String> = report + .warnings + .iter() + .filter(|w| w.contains("unknown template")) + .collect(); + assert!( + missing.is_empty(), + "{entry}: inherits a template this house does not ship (the frame loads, its ART does \ + not): {missing:?}" + ); + } report.frames } @@ -112,7 +139,7 @@ pub(super) const BAG_UI: &[&str] = &[ // `StackSplitFrame` is not optional either: the reference's own // `ContainerFrameItemButton_OnClick` calls `StackSplitFrame:Hide()` on EVERY plain click // (ContainerFrame.lua l.581) before the pickup, and opens it on the shift fork. - "StackSplit.xml", + "Interface\\FrameXML\\StackSplitFrame.xml", // …nor is the chat edit box. The reference's SHIFT arm opens with // `if ( ChatFrameEditBox:IsShown() )` (ContainerFrame.lua l.569) to decide between posting the // item's link and splitting the stack, so a VM without it raises before either. diff --git a/crates/benilla-app/src/ui_script/tooltip_anchor_tests.rs b/crates/benilla-app/src/ui_script/tooltip_anchor_tests.rs index cbd16e27..2bebf415 100644 --- a/crates/benilla-app/src/ui_script/tooltip_anchor_tests.rs +++ b/crates/benilla-app/src/ui_script/tooltip_anchor_tests.rs @@ -11,23 +11,7 @@ use benilla_ui::script::{AuraState, UiScript, UnitState}; -/// Load one shipped `assets/ui/` into `s`, panicking on any loader error (the bag/panel -/// tests' loader, duplicated so this file is self-contained). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// A 1024×768 screen with the anchor law's three fixed files (fonts, the real UIParent, the /// real GameTooltip) plus `extra`. `CONTAINER_OFFSET_X/Y` hold their UIParent.xml load values diff --git a/crates/benilla-app/src/ui_script/tooltip_template_tests.rs b/crates/benilla-app/src/ui_script/tooltip_template_tests.rs index 95ac3fcb..22626fd7 100644 --- a/crates/benilla-app/src/ui_script/tooltip_template_tests.rs +++ b/crates/benilla-app/src/ui_script/tooltip_template_tests.rs @@ -27,21 +27,7 @@ use benilla_ui::script::UiScript; -fn ui_dir() -> std::path::PathBuf { - std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("assets/ui") -} - -/// One shipped `assets/ui/` into `s`, asserting it loaded clean. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string(ui_dir().join(file)).unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// An **addon's** document text, loaded after the shipped files exactly as `LoadAddOn` would — /// the template registry is persistent, so `inherits=` reaches what `GameTooltip.xml` registered. diff --git a/crates/benilla-app/src/ui_script/tot_frame_tests.rs b/crates/benilla-app/src/ui_script/tot_frame_tests.rs index 93875098..1be4f4ac 100644 --- a/crates/benilla-app/src/ui_script/tot_frame_tests.rs +++ b/crates/benilla-app/src/ui_script/tot_frame_tests.rs @@ -18,22 +18,7 @@ use benilla_ui::script::{ SelectionRequest, UiScript, UnitState, }; -/// Load one shipped `assets/ui/`, panicking on any loader error (the unit-frame tests'). -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// A unit snapshot with a guid — the identity `UnitIsUnit` compares, which the "your target is /// you" gate reads. diff --git a/crates/benilla-app/src/ui_script/unit_frame_tests.rs b/crates/benilla-app/src/ui_script/unit_frame_tests.rs index ad7f5ffd..5e807e4f 100644 --- a/crates/benilla-app/src/ui_script/unit_frame_tests.rs +++ b/crates/benilla-app/src/ui_script/unit_frame_tests.rs @@ -2,23 +2,7 @@ use benilla_ui::script::{ QuadContent, ScriptValue, SelectionRequest, SoundRequest, UiScript, UnitState, }; -/// Load one shipped `assets/ui/` (the panel tests' loader, duplicated to stay -/// self-contained), panicking on any loader error. -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; /// The unit frames' production load prefix (ui_script/mod.rs order): fonts + UIParent + /// tooltip, then the dropdown kit + unit popups the frames' DropDown children initialize into. diff --git a/crates/benilla-app/src/ui_script/world_state_tests.rs b/crates/benilla-app/src/ui_script/world_state_tests.rs index 4f49b3d9..e5607ffc 100644 --- a/crates/benilla-app/src/ui_script/world_state_tests.rs +++ b/crates/benilla-app/src/ui_script/world_state_tests.rs @@ -9,21 +9,7 @@ use benilla_ui::script::{QuadContent, ScriptValue, UiScript, WorldStateUiView}; -fn load_xml(s: &UiScript, file: &str) { - let text = std::fs::read_to_string( - std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("assets/ui") - .join(file), - ) - .unwrap(); - let doc = benilla_ui::framexml::parse(&text).unwrap(); - let report = benilla_ui::loader::load(s, &doc, &|_| None); - assert!( - report.errors.is_empty(), - "{file}: loader errors: {:?}", - report.errors - ); -} +use super::test_ui::load_ui as load_xml; pub(crate) fn harness() -> UiScript { let mut s = UiScript::new().unwrap(); diff --git a/crates/benilla-ui/src/script/lua50.rs b/crates/benilla-ui/src/script/lua50.rs index 5f8f9d6b..90a23bc2 100644 --- a/crates/benilla-ui/src/script/lua50.rs +++ b/crates/benilla-ui/src/script/lua50.rs @@ -45,6 +45,19 @@ //! `foreachi`. `reference/1.12-globals.tsv` lists all three; we had the other seventeen of that //! family and not these. //! +//! ## What this module does NOT have to do: the vararg `arg` table +//! +//! Lua 5.0 gives every vararg function an implicit `arg` table with an `n` field, and 1.12's +//! FrameXML uses it directly — `QuestTimerFrame_Update(...)` walks `for i=1, arg.n`, and so do +//! `FCFDropDown_LoadChannels`, `TradeSkill_OnEvent` and the GM-ticket and CVar families. Three of +//! our own transcriptions carry a note saying they rewrote it "the 5.1-native way" with +//! `select("#", ...)`, which reads as though the dialect demanded it. +//! +//! **It does not.** mlua's vendored 5.1 is built with `LUA_COMPAT_VARARG`, so `arg` and `arg.n` +//! are already there — measured, not assumed: `local function f(...) return arg.n end; f('a','b')` +//! answers 2 in this VM. That matters for 1751: a stock file using 5.0 varargs needs nothing from +//! this module, and the rewrite was a precaution against a problem we did not have. +//! //! ## The one known divergence, stated rather than hidden //! //! `table.insert`/`table.remove` stay on 5.1's `#t` border rather than consulting `getn`. **This