From 21ebe65d83fa371403f4711e32e523daf240f516 Mon Sep 17 00:00:00 2001 From: grom Date: Thu, 29 Oct 2026 11:37:58 -0600 Subject: [PATCH] Three more kits loaded their files out of toc order, and one real defect found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each of these was one cause behind a whole cluster, and none of them was our client being wrong — except the last, which is. The character sheet, six tests: the realm's PaperDollFrame_OnLoad builds a titles dropdown (UIDropDownMenu_Initialize at PaperDollFrame.lua:34, nothing stock 1.12 has), so without UIDropDownMenu.xml the OnLoad raises and the whole file fails to load. The trade-skill window, six tests: its two filter checkboxes index _G[this:GetName() .. "Text"] straight out of their OnLoad, and that FontString comes from OptionsCheckButtonTemplate, which the kit never loaded. The extra action bars, two of five: MultiActionBars.xml is toc row 48 and BonusActionBarFrame.xml is row 84, and the kit had them the other way round. The stance file's ShapeshiftBar_OnLoad runs the managed-positions pass, which seats bare stand-ins for MultiBarLeft/Right/BottomLeft; a publish to _G being non-overwriting, the real bars stayed shadowed by nameless empties — the bar frames answered, their buttons did not. Third kit in two sessions to trip on this exact thing. The three that remain are a genuine client defect, left red on purpose and written up where it fails. A MultiBar button's grid ring ignores its half-alpha tint because `_G["NormalTexture"]` is a **different object** from `button:GetNormalTexture()` — while the live region's own GetName() is that very name. The fork is the depth of template inheritance: one level (ActionButton1) is fine, two (MultiBar1ButtonTemplate -> ActionBarButtonTemplate -> ActionButtonTemplate) is not, and neither outer template declares a of its own, so the duplicate comes from the loader's expansion. That reaches every _G[name .. "NormalTexture"] write in FrameXML and in addons, pfUI included, so it wants its own change in loader::widgets with its own tests. Workspace failures 257 -> 227, clippy clean. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn --- .../src/ui_script/multibar_stance_tests.rs | 43 ++++++++++++++++--- crates/benilla-app/tests/character_stats.rs | 6 +++ crates/benilla-app/tests/tradeskill_frame.rs | 6 +++ 3 files changed, 50 insertions(+), 5 deletions(-) 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 2b9f8941..d98cf998 100644 --- a/crates/benilla-app/src/ui_script/multibar_stance_tests.rs +++ b/crates/benilla-app/src/ui_script/multibar_stance_tests.rs @@ -21,6 +21,14 @@ fn load_action_bar(s: &UiScript) { "Interface\\FrameXML\\GlobalStrings.lua", "Interface\\FrameXML\\MainMenuBar.xml", "Interface\\FrameXML\\ActionBarFrame.xml", + // **Toc row 48, and it must come before BonusActionBarFrame at row 84.** The stance + // file's `ShapeshiftBar_OnLoad` runs the managed-positions pass, and the kit seats bare + // stand-ins for every frame that pass indexes — `MultiBarLeft`, `MultiBarRight` and + // `MultiBarBottomLeft` among them. A publish to `_G` is non-overwriting (`0x701bd0`), so + // loading this afterwards left the real bars shadowed by nameless empties for the rest + // of the VM: the bar frames answered, their buttons did not. Five tests, and the same + // shape as the pet bar's nine and `ChatFrame1`'s hundred and thirty-seven. + "Interface\\FrameXML\\MultiActionBars.xml", "Interface\\FrameXML\\BonusActionBarFrame.xml", // `ExhaustionTick_Update` reads `ReputationWatchBar`, which ReputationFrame.xml declares. r"Interface\FrameXML\UIPanelTemplates.lua", @@ -67,11 +75,21 @@ fn shipped_multibars_drive_end_to_end() { let mut s = UiScript::new().unwrap(); s.set_screen_size(1024.0, 768.0); load_action_bar(&s); - let frames = super::test_ui::load_ui(&s, "Interface\\FrameXML\\MultiActionBars.xml"); - assert_eq!( - frames, 100, - "what stock MultiActionBars.xml declares: the four bar frames and their 48 buttons, \ - each with a $parentCooldown — the same 100 ours built for the same seats" + // `MultiActionBars.xml` comes with `load_action_bar` now, ahead of the stance file — see the + // note there. What it declared, asserted where it used to be a frame count: the four bar + // frames, their buttons and each button's `$parentCooldown`. + assert!( + s.eval::( + "local ok = MultiBarLeft and MultiBarRight and MultiBarBottomLeft \ + and MultiBarBottomRight \ + for i = 1, 12 do \ + ok = ok and getglobal('MultiBarBottomLeftButton' .. i) \ + and getglobal('MultiBarBottomLeftButton' .. i .. 'Cooldown') \ + end \ + return ok and true or false" + ) + .unwrap(), + "the four bar frames, their buttons and each button's cooldown" ); // Occupy main slot 1, BottomLeft slot 1 (action 61), BottomRight slot 1 (action 49). @@ -921,6 +939,21 @@ fn a_held_payload_ghosts_the_empty_wells_it_opens() { 23, "11 empty main wells swap art + MultiBarBottomLeft's 12 appear" ); + // **Known red, and precisely located.** The eleven main-bar rings carry the half alpha; the + // twelve MultiBar ones do not, and the Lua state is right — `GetVertexColor()` on + // `MultiBarBottomLeftButton1NormalTexture` answers 0.5. The global is a **different object** + // than `MultiBarBottomLeftButton1:GetNormalTexture()`, though the live region's own + // `GetName()` is that very name, so the tint lands on something nothing draws. + // + // The fork is the depth of template inheritance, not the widget: `ActionButton1` is one level + // (`ActionBarButtonTemplate`) and is fine; a MultiBar button is two + // (`MultiBar1ButtonTemplate` -> `ActionBarButtonTemplate` -> `ActionButtonTemplate`) and is + // not. Neither of the two outer templates declares a `` of its own, so the + // duplicate comes out of the loader's expansion, not the markup. + // + // Left failing deliberately rather than relaxed: it is a real defect with real reach — every + // `_G[name .. "NormalTexture"]` write in FrameXML and in an addon, and pfUI makes many — and + // the fix belongs in `loader::widgets`'s state-texture path with its own tests. assert!( ghosts.iter().all(|a| *a == 0.5), "every grid ring is the ref's half-alpha ghost, not an opaque plate: {ghosts:?}" diff --git a/crates/benilla-app/tests/character_stats.rs b/crates/benilla-app/tests/character_stats.rs index b2cc8852..924fcf57 100644 --- a/crates/benilla-app/tests/character_stats.rs +++ b/crates/benilla-app/tests/character_stats.rs @@ -27,6 +27,12 @@ const FILES: &[&str] = &[ "Interface\\FrameXML\\GameTooltip.xml", // Each slot button's OnLoad calls `CooldownFrame_SetTimer` (`PaperDollFrame.lua:692`). "Interface\\FrameXML\\Cooldown.xml", + // The realm's `PaperDollFrame_OnLoad` builds a titles dropdown — + // `UIDropDownMenu_Initialize(PaperDollFrameTitlesDropdown, …)` at `PaperDollFrame.lua:34`, + // which stock 1.12 has no trace of. Without this the OnLoad raises on a nil global and the + // whole file fails to load, which took all six of this binary's tests. Toc row 26, well ahead + // of PaperDollFrame.xml at 64. + "Interface\\FrameXML\\UIDropDownMenu.xml", "Interface\\FrameXML\\PaperDollFrame.xml", ]; diff --git a/crates/benilla-app/tests/tradeskill_frame.rs b/crates/benilla-app/tests/tradeskill_frame.rs index e941ddae..5be3fe34 100644 --- a/crates/benilla-app/tests/tradeskill_frame.rs +++ b/crates/benilla-app/tests/tradeskill_frame.rs @@ -23,6 +23,12 @@ const FILES: &[&str] = &[ "Interface\\FrameXML\\StaticPopup.xml", // the dialog engine "Interface\\FrameXML\\GameTooltip.xml", "Interface\\FrameXML\\UIDropDownMenu.xml", + // `OptionsCheckButtonTemplate` (`OptionsFrameTemplates.xml:364`), whose `$parentText` + // FontString the realm's two filter checkboxes index straight out of their OnLoad: + // `_G[this:GetName() .. "Text"]:SetText(HAVE_MATERIALS)` + // (`Blizzard_TradeSkillUI.xml:527`). Unknown template, no child, nil index, and the whole + // file fails to load — all six of this binary's tests. + r"Interface\FrameXML\OptionsFrameTemplates.xml", "ScrollTemplates.xml", // Both windows open from UIParent's TRADE_SKILL_SHOW / CRAFT_SHOW arms (`*_LoadUI`, then // `*_Show`). With no addon registry the addons load as chain files, and `*_LoadUI` reports