diff --git a/crates/benilla-app/src/ui_script/chat_tests.rs b/crates/benilla-app/src/ui_script/chat_tests.rs index fefdabd7..ea1f2656 100644 --- a/crates/benilla-app/src/ui_script/chat_tests.rs +++ b/crates/benilla-app/src/ui_script/chat_tests.rs @@ -428,7 +428,15 @@ fn chat_type_info_has_the_references_shape() { let count: i64 = s .eval("local n = 0 for _ in pairs(ChatTypeInfo) do n = n + 1 end return n") .unwrap(); - assert_eq!(count, 105, "the reference declares 105 keys"); + assert_eq!( + count, 106, + "the reference declares 106 keys — 1.12's 105 plus the realm's own HARDCORE row" + ); + assert!( + s.eval::("return ChatTypeInfo.HARDCORE ~= nil") + .unwrap(), + "the extra key is HARDCORE, the realm's death-announce type, not a stray of ours" + ); let sticky: String = s .eval( @@ -436,7 +444,13 @@ fn chat_type_info_has_the_references_shape() { table.insert(t, k) end end table.sort(t) return table.concat(t, \" \")", ) .unwrap(); - assert_eq!(sticky, "BATTLEGROUND GUILD PARTY RAID SAY"); + // Ten, not 1.12's five: the realm marks `CHANNEL`, `OFFICER`, `RAID_WARNING`, `WHISPER` and + // its own `HARDCORE` sticky too (`ChatFrame.lua`'s `ChatTypeInfo` block). Sticky is what the + // edit box keeps between sends, so this list is the typing behaviour a player feels. + assert_eq!( + sticky, + "BATTLEGROUND CHANNEL GUILD HARDCORE OFFICER PARTY RAID RAID_WARNING SAY WHISPER" + ); // REPLY and COMBAT_ERROR are FrameXML's own, absent from the engine's 94-entry registry, so // both have id 0, but their colors differ: the `UPDATE_CHAT_COLOR` arm copies WHISPER's diff --git a/crates/benilla-app/src/ui_script/dropdown_tests.rs b/crates/benilla-app/src/ui_script/dropdown_tests.rs index c6db3fc5..bca9a6b7 100644 --- a/crates/benilla-app/src/ui_script/dropdown_tests.rs +++ b/crates/benilla-app/src/ui_script/dropdown_tests.rs @@ -58,19 +58,35 @@ fn hiding_a_list_clears_its_open_menu_registry_entry() { ) .unwrap(); + // The realm **wipes** the row rather than dropping it: both lists' OnHide run + // `wipe(OPEN_DROPDOWNMENUS[n])` (`UIDropDownMenu.xml:17`, `:28`), where stock 1.12 assigned + // nil. The table identity therefore outlives the menu, and what clears is its contents — + // which is what `UnitPopup_OnUpdate`'s walk reads, since it keys off `.which`. + let table_ids: (String, String) = s + .eval("return tostring(OPEN_DROPDOWNMENUS[1]), tostring(OPEN_DROPDOWNMENUS[2])") + .unwrap(); + s.run("DropDownList2:Hide();").unwrap(); assert!( - s.eval::("return OPEN_DROPDOWNMENUS[2] == nil") + s.eval::("return next(OPEN_DROPDOWNMENUS[2]) == nil") .unwrap(), "level 2's registry entry survived its list hiding" ); s.run("DropDownList1:Hide();").unwrap(); assert!( - s.eval::("return OPEN_DROPDOWNMENUS[1] == nil") + s.eval::("return next(OPEN_DROPDOWNMENUS[1]) == nil") .unwrap(), "level 1's registry entry survived its list hiding" ); + assert_eq!( + s.eval::<(String, String)>( + "return tostring(OPEN_DROPDOWNMENUS[1]), tostring(OPEN_DROPDOWNMENUS[2])" + ) + .unwrap(), + table_ids, + "wiped in place, not replaced — an addon holding a reference keeps seeing the live row" + ); } /// `UIDropDownMenu.lua:16` declares the height nil; list 1's OnLoad sets it from Button1's font diff --git a/crates/benilla-app/src/ui_script/friends_tests.rs b/crates/benilla-app/src/ui_script/friends_tests.rs index 8c39f41d..c0d1614a 100644 --- a/crates/benilla-app/src/ui_script/friends_tests.rs +++ b/crates/benilla-app/src/ui_script/friends_tests.rs @@ -152,15 +152,19 @@ fn friend_rows_render_the_online_and_offline_templates() { "FRIENDLIST_UPDATE", ); + // The realm colours an online row three ways (`FriendsFrame.lua:186-197`): the name and the + // class in `RAID_CLASS_COLORS[TW_CLASS_TOKEN[class]].hex` — rogue yellow `|cfffff569` — and + // the level in `GetDifficultyColor(level).hex`, which against this fixture's level-less + // player reads as the hostile red `|cffff1919`. Stock 1.12 wrote all three plain. assert_eq!( s.eval::("return FriendsFrameFriendButton1ButtonTextNameLocation:GetText()") .unwrap(), - "Onerogue |cffffffff- Elwynn Forest|r " + "|cfffff569Onerogue|r |cffffffff- Elwynn Forest|r " ); assert_eq!( s.eval::("return FriendsFrameFriendButton1ButtonTextInfo:GetText()") .unwrap(), - "Level 60 Rogue" + "Level |cffff191960|r |cfffff569Rogue|r" ); assert_eq!( s.eval::("return FriendsFrameFriendButton2ButtonTextNameLocation:GetText()") diff --git a/crates/benilla-app/src/ui_script/guild_tests.rs b/crates/benilla-app/src/ui_script/guild_tests.rs index 402075a9..c4e8639d 100644 --- a/crates/benilla-app/src/ui_script/guild_tests.rs +++ b/crates/benilla-app/src/ui_script/guild_tests.rs @@ -280,15 +280,34 @@ fn an_offline_member_keeps_its_columns_and_only_greys() { ); assert_eq!(text(&s, "GuildFrameButton3Class"), "Mage"); + // The realm greys an offline row with **alpha**, not with a grey ink + // (`FriendsFrame.lua:526`, `local alpha = online and 1 or 0.55`, applied to all four columns). + // Its colours are the class's and the level's difficulty, online or not — stock 1.12 wrote + // gold names and flat `(0.5, 0.5, 0.5)` for an offline one. assert_eq!( colour(&s, "GuildFrameButton3Name"), - (0.5, 0.5, 0.5), - "offline rows go flat grey" + (0.41, 0.8, 0.94), + "a mage keeps mage blue offline (`RAID_CLASS_COLORS.MAGE`)" ); + for column in ["Name", "Zone", "Level", "Class"] { + let faded = s + .eval::(&format!("return GuildFrameButton3{column}:GetAlpha()")) + .unwrap(); + assert!( + (faded - 0.55).abs() < 1e-6, + "{column} fades with the row, which is the whole of being offline here: {faded}" + ); + assert_eq!( + s.eval::(&format!("return GuildFrameButton1{column}:GetAlpha()")) + .unwrap(), + 1.0, + "{column} of an online row is opaque" + ); + } assert_eq!( colour(&s, "GuildFrameButton1Name"), - (1.0, 0.82, 0.0), - "an online name keeps the gold" + (0.78, 0.61, 0.43), + "and an online warrior is warrior tan, not 1.12's gold" ); } diff --git a/crates/benilla-app/src/ui_script/minimap_tests.rs b/crates/benilla-app/src/ui_script/minimap_tests.rs index fd97e77f..00378cf9 100644 --- a/crates/benilla-app/src/ui_script/minimap_tests.rs +++ b/crates/benilla-app/src/ui_script/minimap_tests.rs @@ -201,17 +201,28 @@ fn hovering_the_indicator_shows_and_live_updates_the_game_time_tooltip() { s.eval::("return GameTooltip:IsVisible()").unwrap(), "OnEnter owns the tooltip (the Scripts-walker auto-enable capturing at {x},{y})" ); - // The enGB `LocalizeFrames` sets `TwentyFourHourTime = 1` (`Localization.lua:20`): 21:07. - let text = |s: &UiScript| { - s.eval::("return GameTooltipTextLeft1:GetText()") + // The realm's clock plate is four lines, not stock 1.12's one bare time: + // `GAMETIME_TITLE` then a `Zone time:` / `Server time:` / `Local time:` triple of double + // lines (`GameTime.lua:50-56`). The enGB `LocalizeFrames` sets `TwentyFourHourTime = 1` + // (`Localization.lua:20`), so the zone row reads 21:07. + let text = |s: &UiScript, line: &str| { + s.eval::(&format!("return GameTooltipText{line}:GetText()")) .unwrap() }; - assert_eq!(text(&s), "21:07"); + assert_eq!(text(&s, "Left1"), "Clock"); + assert_eq!(text(&s, "Left2"), "Zone time:"); + assert_eq!(text(&s, "Right2"), "21:07"); + assert_eq!(text(&s, "Left3"), "Server time:"); + assert_eq!(text(&s, "Left4"), "Local time:"); - // While owned, `GameTimeFrame_Update` refreshes the tooltip (`GameTime.lua:20-22`). + // While owned, `GameTimeFrame_Update` refreshes the tooltip (`GameTime.lua:44-45`). s.run("__benilla_game_minute = 8").unwrap(); s.tick(0.016); - assert_eq!(text(&s), "21:08", "the owned tooltip follows the clock"); + assert_eq!( + text(&s, "Right2"), + "21:08", + "the owned tooltip follows the clock" + ); // Inside the raw 50x50 rect but in the left inset: not hoverable. s.mouse_move(l + 2.0, y); diff --git a/crates/benilla-app/src/ui_script/spellbook_tests.rs b/crates/benilla-app/src/ui_script/spellbook_tests.rs index b83a554b..bba92c65 100644 --- a/crates/benilla-app/src/ui_script/spellbook_tests.rs +++ b/crates/benilla-app/src/ui_script/spellbook_tests.rs @@ -397,13 +397,36 @@ fn the_pet_tab_switches_books_and_renders_the_pets_spells() { s.fire_event("PLAYER_ENTERING_WORLD", vec![]); s.set_spellbook(book()); - // ── No pet: no toggle row, and no pet book (`SpellBookFrame.lua:11-14`) ────────────────── + // ── No pet: the Spellbook tab alone, and no pet book ──────────────────────────────────── s.run("ToggleSpellBook(BOOKTYPE_SPELL)").unwrap(); assert!(s.errors().is_empty(), "open errors: {:?}", s.errors()); + // The realm sets up tab 1 on **both** arms of its `hasPetSpells` fork + // (`SpellBookFrame.lua:211-216`), and `SpellBookFrame_SetTabType` ends in `tabButton:Show()` + // (`:253`). Stock 1.12 built the row only when there was a pet book to switch to, so the + // whole row stayed hidden; here the Spellbook tab is always up, and disabled because it is + // the open book. assert!( - !s.eval::("return SpellBookFrameTabButton1:IsVisible()") + s.eval::("return SpellBookFrameTabButton1:IsVisible()") .unwrap(), - "with no pet spells the ref hides the whole toggle row" + "the Spellbook tab shows with no pet" + ); + assert_eq!( + s.eval::("return SpellBookFrameTabButton1:GetText()") + .unwrap(), + "Spellbook" + ); + // `IsEnabled()` answers the number 0, not false — 0 is truthy in Lua, which is why the stock + // UI compares it (`== 0`, `FriendsFrame.lua:404`) instead of testing it. + assert_eq!( + s.eval::("return SpellBookFrameTabButton1:IsEnabled()") + .unwrap(), + 0, + "the tab for the open book is disabled (`:249-250`)" + ); + assert!( + !s.eval::("return SpellBookFrameTabButton2:IsVisible()") + .unwrap(), + "…and there is no second tab without a pet book behind it" ); s.run("ToggleSpellBook(BOOKTYPE_PET)").unwrap(); assert!( @@ -548,26 +571,35 @@ fn the_pet_tab_switches_books_and_renders_the_pets_spells() { "a right-click on the pet page must not also cast" ); - // ── Two reference quirks, pinned ─────────────────────────────────────────────────────────── - // The pet page ignores its page number: `SpellBook_GetSpellID`'s pet arm is a bare `return id` - // (`SpellBookFrame.lua:460-461`). + // ── Two 1.12 quirks the realm fixed ─────────────────────────────────────────────────────── + // Stock `SpellBook_GetSpellID`'s pet arm was a bare `return id`, so the pet page number was + // never applied; the realm's is `id + SPELLS_PER_PAGE * (page - 1)` like the spell arm + // (`SpellBookFrame.lua:532-537`). Page 2 therefore starts at the thirteenth pet spell. assert_eq!(s.eval::("return SpellBook_GetSpellID(1)").unwrap(), 1); s.run(r#"SPELLBOOK_PAGENUMBERS["pet"] = 2"#).unwrap(); assert_eq!( s.eval::("return SpellBook_GetSpellID(1)").unwrap(), - 1, - "DO NOT FIX: the ref's pet arm has no page term" + 1 + s.eval::("return SPELLS_PER_PAGE").unwrap(), + "the realm's pet arm carries the page term" ); - // …and Next writes `SPELLBOOK_PAGENUMBERS[selectedSkillLine]` on both books - // (`SpellBookFrame.lua:423`), so the pet page stays put. + + // And Next writes the pet book's own page rather than the selected skill line's + // (`:490-500`), so paging works — which also means the arrows gate on the pet book's length: + // two pet spells is one page, so Next is disabled and a click cannot move it. s.run(r#"SPELLBOOK_PAGENUMBERS["pet"] = 1"#).unwrap(); + s.run("SpellBook_UpdatePageArrows()").unwrap(); + assert_eq!( + s.eval::("return SpellBookNextPageButton:IsEnabled()") + .unwrap(), + 0, + "one page of pet spells, so there is nowhere to turn to" + ); click(&mut s, "SpellBookNextPageButton", "LeftButton"); assert!(s.errors().is_empty(), "page errors: {:?}", s.errors()); assert_eq!( s.eval::(r#"return SPELLBOOK_PAGENUMBERS["pet"]"#) .unwrap(), - 1, - "DO NOT FIX: the ref writes SPELLBOOK_PAGENUMBERS[selectedSkillLine] on both books" + 1 ); assert_eq!( s.eval::("return SpellButton1SpellName:GetText()") diff --git a/crates/benilla-app/src/ui_script/static_popup_tests.rs b/crates/benilla-app/src/ui_script/static_popup_tests.rs index d221f8d2..4556a17c 100644 --- a/crates/benilla-app/src/ui_script/static_popup_tests.rs +++ b/crates/benilla-app/src/ui_script/static_popup_tests.rs @@ -255,6 +255,11 @@ fn the_verb_dialogs_open_from_their_events_and_call_their_verbs() { let mut s = setup(); load_xml(&s, r"Interface\FrameXML\UIParent.xml"); // the arms s.set_money(50_000); + // The realm gave this dialog an `OnUpdate` that hides it the moment `CheckPetUntrainerDist()` + // stops answering (`StaticPopup.lua:1290-1294`) — stock 1.12 had no such arm, so the dialog + // used to stand on its own. The verb has to answer before the first tick or the dialog is + // gone before anything can click it. + s.set_pet_untrainer_pending(true); s.fire_event("CONFIRM_PET_UNLEARN", vec![ScriptValue::Int(12_345)]); s.tick(0.0); assert_eq!( diff --git a/crates/benilla-app/src/ui_script/taxi_tests.rs b/crates/benilla-app/src/ui_script/taxi_tests.rs index 1a17a62f..ad18f14e 100644 --- a/crates/benilla-app/src/ui_script/taxi_tests.rs +++ b/crates/benilla-app/src/ui_script/taxi_tests.rs @@ -132,7 +132,10 @@ fn no_single_hop_destination_posts_the_error_and_closes() { let quads = s.extract(); let has_refusal = quads.iter().any(|q| match &q.content { benilla_ui::script::QuadContent::Text { text: Some(t), .. } => { - t.contains("don\u{2019}t know any flight locations") + // A straight ASCII apostrophe: the realm's `GlobalStrings.lua` writes + // `"You don't know any flight locations connected to this one."`, not the curly + // U+2019 some of its other strings use. + t.contains("don't know any flight locations") } _ => false, }); diff --git a/crates/benilla-app/src/ui_script/test_ui.rs b/crates/benilla-app/src/ui_script/test_ui.rs index cc971afa..72d61bc8 100644 --- a/crates/benilla-app/src/ui_script/test_ui.rs +++ b/crates/benilla-app/src/ui_script/test_ui.rs @@ -689,6 +689,11 @@ pub(super) const CHARACTER_UI: &[&str] = &[ pub(super) const SOCIAL_UI: &[&str] = &[ "Interface\\FrameXML\\Fonts.xml", "Interface\\FrameXML\\GlobalStrings.lua", + // The realm's own globals (toc row 2, right after `GlobalStrings.lua`). `TW_CLASS_TOKEN` is + // the localized-class-name → token map its `FriendsFrame.lua:187-192` and + // `GuildFrame.lua` colour rows through; without it those rows silently draw uncoloured, which + // is a different window than the one the client paints. + r"Interface\FrameXML\Globals.lua", "Interface\\FrameXML\\LocaleProperties.lua", "Interface\\FrameXML\\BasicControls.xml", r"Interface\FrameXML\UIParent.xml", diff --git a/crates/benilla-app/src/ui_script/ui_menu_tests.rs b/crates/benilla-app/src/ui_script/ui_menu_tests.rs index 0e17429c..98727df9 100644 --- a/crates/benilla-app/src/ui_script/ui_menu_tests.rs +++ b/crates/benilla-app/src/ui_script/ui_menu_tests.rs @@ -49,25 +49,27 @@ fn chat_menu_rows_left_align_their_label_and_right_align_their_shortcut() { assert!(s.errors().is_empty(), "opening it raises: {:?}", s.errors()); s.resolve(); - // Macro is the tenth row `ChatMenu_OnLoad` adds (`ChatFrame.lua:2301`). + // Macro is the **eleventh** row `ChatMenu_OnLoad` adds (`ChatFrame.lua:2378`): the realm + // inserted its own `HARDCORE_MESSAGE` row fourth (`:2371`), which pushed everything below it + // down one, so stock 1.12's tenth seat now holds Voice Emote. assert_eq!( - s.eval::("return ChatMenuButton10:GetText()") + s.eval::("return ChatMenuButton11:GetText()") .unwrap(), "Macro" ); assert_eq!( - s.eval::("return ChatMenuButton10ShortcutText:GetText()") + s.eval::("return ChatMenuButton11ShortcutText:GetText()") .unwrap(), "/macro" ); // `UIMenu_Initialize` fixes the row at 104 wide (`UIMenu.lua:16`). - let (row_l, row_r) = edges(&mut s, "ChatMenuButton10"); + let (row_l, row_r) = edges(&mut s, "ChatMenuButton11"); assert_eq!(row_r - row_l, 104.0, "UIMENU_BUTTON_WIDTH"); // The label's implicit anchor is LEFT to LEFT (0, 0), from ``. let (p, rp, x, y): (String, String, f32, f32) = s .eval( - "local p, _, rp, x, y = ChatMenuButton10:GetFontString():GetPoint(1) \ + "local p, _, rp, x, y = ChatMenuButton11:GetFontString():GetPoint(1) \ return p, rp, x, y", ) .unwrap(); @@ -76,10 +78,10 @@ fn chat_menu_rows_left_align_their_label_and_right_align_their_shortcut() { ("LEFT", "LEFT", 0.0, 0.0), "the label is anchored by the normal font's justify" ); - let (label_l, label_r) = edges(&mut s, "ChatMenuButton10:GetFontString()"); + let (label_l, label_r) = edges(&mut s, "ChatMenuButton11:GetFontString()"); assert_eq!(label_l, row_l, "the label starts at the row's left edge"); // The template anchors the shortcut string RIGHT. - let (short_l, short_r) = edges(&mut s, "ChatMenuButton10ShortcutText"); + let (short_l, short_r) = edges(&mut s, "ChatMenuButton11ShortcutText"); assert_eq!(short_r, row_r, "the shortcut ends at the row's right edge"); // With 8 px glyphs "Macro" spans 40 and "/macro" 48 of 104; a centred label (32..72) overlaps. assert!( diff --git a/crates/benilla-app/src/ui_script/uiparent_tests.rs b/crates/benilla-app/src/ui_script/uiparent_tests.rs index 4722f458..355e054d 100644 --- a/crates/benilla-app/src/ui_script/uiparent_tests.rs +++ b/crates/benilla-app/src/ui_script/uiparent_tests.rs @@ -157,15 +157,24 @@ fn raid_class_colors_is_the_references_own_nine() { "keyed by UnitClass's uppercase second return, which is how addons index it" ); - // SHAMAN has PALADIN's colour in the reference; not a typo to fix. + // Stock 1.12 gave SHAMAN a copy of PALADIN's pink (shamans being Horde-only, the table + // reused the row); the realm's own `Fonts.xml:50` gives it the later blue instead, so the two + // rows are distinct here. Transcribed from the player's file, not corrected by us either way. assert_eq!( - s.eval::<(f64, f64, f64)>( - "local p, h = RAID_CLASS_COLORS.PALADIN, RAID_CLASS_COLORS.SHAMAN \ - return p.r - h.r, p.g - h.g, p.b - h.b" - ) - .unwrap(), - (0.0, 0.0, 0.0), - "SHAMAN shares PALADIN's pink in 1.12 — transcribed, not corrected" + s.eval::<(f64, f64, f64)>("local c = RAID_CLASS_COLORS.SHAMAN return c.r, c.g, c.b") + .unwrap(), + (0.0, 0.44, 0.87) + ); + assert_eq!( + s.eval::("return RAID_CLASS_COLORS.SHAMAN.hex") + .unwrap(), + "|cff0070de", + "and the `hex` every addon concatenates matches the three floats" + ); + assert_eq!( + s.eval::<(f64, f64, f64)>("local c = RAID_CLASS_COLORS.PALADIN return c.r, c.g, c.b") + .unwrap(), + (0.96, 0.55, 0.73) ); assert_eq!( s.eval::<(f64, f64, f64)>("local c = RAID_CLASS_COLORS.HUNTER return c.r, c.g, c.b")