diff --git a/crates/benilla-app/src/ui_script/bag_tests.rs b/crates/benilla-app/src/ui_script/bag_tests.rs index f258c812..ef1af20b 100644 --- a/crates/benilla-app/src/ui_script/bag_tests.rs +++ b/crates/benilla-app/src/ui_script/bag_tests.rs @@ -502,6 +502,24 @@ fn hovered_bag_tooltip_fills_itself_when_the_stats_land() { ..Default::default() }, ); + // Not the next frame: the realm's `ContainerFrameItemButton_OnUpdate` **accumulates** and + // repaints only once `this.updateTooltip` passes `TOOLTIP_UPDATE_TIME` + // (`ContainerFrame.lua:694-704`), where stock 1.12 counted down from it and so repainted on + // the first update after a hover. A fifth of a second, which is what a player sees. + s.tick(0.016); + assert_eq!( + s.eval::("return GameTooltip:NumLines()").unwrap(), + 1, + "one frame in, the plate is still the fallback line" + ); + // The threshold is read **before** the accumulate, so the repaint lands on the frame after + // the one that crosses it. + s.tick(0.2); + assert_eq!( + s.eval::("return GameTooltip:NumLines()").unwrap(), + 1, + "the frame that crosses the threshold still reads the old total" + ); s.tick(0.016); assert!( s.eval::("return GameTooltip:NumLines()").unwrap() > 1, @@ -1639,7 +1657,8 @@ fn the_keyring_button_opens_a_keyring_window() { keyring_surface(&s); s.set_money(0); s.set_has_key(true); - // Level 44: 8 slots (the 40..49 rung). The level decides; the feed carries the same 8. + // The level decides nothing here (see `seat_player_at_level`): `GetKeyRingSize` scans for the + // highest filled slot and rounds up to a multiple of four (`ContainerFrame.lua:817-844`). seat_player_at_level(&mut s, 44); s.set_container(-2, Some(keyring(8, true))); s.fire_event("BAG_UPDATE", vec![benilla_ui::script::ScriptValue::Int(-2)]); @@ -1670,7 +1689,11 @@ fn the_keyring_button_opens_a_keyring_window() { if getglobal('{w}Item' .. i):IsShown() then n = n + 1 end end return n" )) .unwrap(); - assert_eq!(shown, 8, "only the level-unlocked keyring slots are drawn"); + assert_eq!( + shown, 4, + "one key in slot 1 rounds up to one row of four — not the fed `num_slots`, which stock \ + FrameXML never asks the keyring for" + ); assert_eq!( s.eval::("return BenillaGetContainerItemID(KEYRING_CONTAINER, 1)") .unwrap(), @@ -1731,24 +1754,46 @@ fn a_key_dropped_on_the_button_files_itself() { "filed into the FIRST FREE keyring slot (1 is taken), not the backpack" ); - // Full: each slot needs a texture, since `PutKeyInKeyRing` reads a slot as free from - // `GetContainerItemInfo`'s first return, the icon (`ContainerFrame.lua:744-746`). - let mut full = keyring(4, true); - for slot in 2..=4 { - full.slots.insert( - slot, - ContainerSlot { - item_id: 7146, - count: 1, - texture: Some("Interface\\Icons\\INV_Misc_Key_07".into()), - ..Default::default() - }, - ); - } - s.set_container(-2, Some(full)); + // A key in every slot of the row is not full: `GetKeyRingSize` only keeps the current size + // when `numItems < maxSlotNumberFilled`, so four keys in slots 1-4 round up to eight + // (`ContainerFrame.lua:835-839`) and `PutKeyInKeyRing` finds slot 5 free. Each slot needs a + // texture, since it reads a slot as free from `GetContainerItemInfo`'s first return, the icon. + let keyed = |slots: std::ops::RangeInclusive| { + let mut ring = keyring(4, true); + for slot in slots { + ring.slots.insert( + slot, + ContainerSlot { + item_id: 7146, + count: 1, + texture: Some("Interface\\Icons\\INV_Misc_Key_07".into()), + ..Default::default() + }, + ); + } + ring + }; + s.set_container(-2, Some(keyed(2..=4))); + s.run("PickupContainerItem(0, 3)").unwrap(); + s.run("KeyRingButton:Click()").unwrap(); + assert_eq!( + s.take_container_moves(), + vec![ContainerMove { + src_bag: 0, + src_slot: 3, + dst_bag: -2, + dst_slot: 5, + count: None, + }], + "a filled row grows by four rather than refusing" + ); + + // Truly full is all 32 — `GetKeyRingSize` clamps there (`:841`) — and the refusal now says so: + // stock `PutKeyInKeyRing` printed `NO_EMPTY_KEYRING_SLOTS`, a name 1.12 never defines, and the + // realm renamed it to `NO_EMPTY_KEYRING_SLOTS_ERROR` (`:797`) and defined it in + // `GlobalStrings.lua` as "Your keyring is full." So the 1.12 silent-refusal bug is fixed. + s.set_container(-2, Some(keyed(2..=32))); s.run("PickupContainerItem(0, 3)").unwrap(); - // Stock `PutKeyInKeyRing` reports through `NO_EMPTY_KEYRING_SLOTS`, which 1.12 never defines - // (`ContainerFrame.lua:753`), so nothing prints: a 1.12 bug, kept. s.run("KeyRingButton:Click()").unwrap(); assert!( s.take_container_moves().is_empty(), @@ -1756,15 +1801,12 @@ fn a_key_dropped_on_the_button_files_itself() { ); s.resolve(); assert!( - !s.extract().iter().any(|q| matches!( + s.extract().iter().any(|q| matches!( &q.content, QuadContent::Text { text: Some(t), .. } if t.contains("keyring is full") )), - "the reference's own dangling string name prints nothing — un-quirking it is a decision, \ - not a default" + "the refusal reaches UIErrorsFrame now that the string exists" ); - // Nor does it raise: `AddMessage` reads its text through `lua_isstring` (`0x6f3510`), whose - // failure edge jumps to the function's epilogue (`0x79562c`). assert!(s.errors().is_empty(), "script errors: {:?}", s.errors()); } diff --git a/crates/benilla-app/src/ui_script/quest_tests.rs b/crates/benilla-app/src/ui_script/quest_tests.rs index 1fcf725b..cf64c3c9 100644 --- a/crates/benilla-app/src/ui_script/quest_tests.rs +++ b/crates/benilla-app/src/ui_script/quest_tests.rs @@ -178,8 +178,11 @@ fn detail_panel_reward_grid_follows_the_refs_two_per_row_layout() { load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml"); + // A real item id per row, because `GetNumQuestChoices`/`GetNumQuestRewards` take-while on it: + // the reference's counters (`0x5016c0`, `0x5016a0`) `je` out of their loop on the first zero, + // so a row with no id hides itself and every row behind it. Only non-zero-ness matters. let choice = |name: &str, quality: u32| benilla_ui::script::QuestItemView { - item_id: 0, + item_id: 4_984, name: Some(name.into()), texture: None, count: 1, @@ -274,8 +277,9 @@ fn reward_panel_choice_click_selects_and_completes_with_zero_based_index() { load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml"); + // Non-zero, as the reference's take-while counters need (see the detail-grid test above). let choice = |name: &str| benilla_ui::script::QuestItemView { - item_id: 0, + item_id: 4_984, name: Some(name.into()), texture: None, count: 1, diff --git a/crates/benilla-app/src/ui_script/raid_tests.rs b/crates/benilla-app/src/ui_script/raid_tests.rs index b474b7f9..43b23dc5 100644 --- a/crates/benilla-app/src/ui_script/raid_tests.rs +++ b/crates/benilla-app/src/ui_script/raid_tests.rs @@ -240,14 +240,23 @@ fn the_grid_seats_each_row_in_its_own_subgroups_next_free_slot() { ); assert_eq!(text_of(&s, "RaidGroupButton1Name"), "Me"); + // The rank is art now, not a letter: the realm added a `$parentRankIcon` Texture + // (`Blizzard_RaidUI.xml:49`) and the row update sets it to `RAID_LEADER_ICON` or + // `RAID_ASSISTANT_ICON` (`Blizzard_RaidUI.lua:100`, `:155-161`). The `$parentRank` FontString + // 1.12 wrote "(L)"/"(A)" into is still declared and now never written. + let rank_icon = |s: &UiScript, button: &str| { + s.eval::(&format!("return {button}RankIcon:GetTexture() or ''")) + .unwrap() + }; assert_eq!( - text_of(&s, "RaidGroupButton1Rank"), - "(L)", + rank_icon(&s, "RaidGroupButton1"), + "Interface\\GroupFrame\\UI-Group-LeaderIcon", "the leader token" ); + assert_eq!(text_of(&s, "RaidGroupButton1Rank"), ""); assert_eq!( - text_of(&s, "RaidGroupButton2Rank"), - "(A)", + rank_icon(&s, "RaidGroupButton2"), + "Interface\\GroupFrame\\UI-Group-AssistantIcon", "the assistant token" ); assert_eq!( diff --git a/crates/benilla-app/src/ui_script/test_ui.rs b/crates/benilla-app/src/ui_script/test_ui.rs index a20e1741..d4a22266 100644 --- a/crates/benilla-app/src/ui_script/test_ui.rs +++ b/crates/benilla-app/src/ui_script/test_ui.rs @@ -743,6 +743,11 @@ pub(super) fn load_social_ui(s: &mut UiScript) { for f in SOCIAL_UI { load_ui_strict(s, f); } + // The `.lua` alone, for `GroupFrame_InitiateReadyCheck`: the realm moved the ready check out + // of `Blizzard_RaidUI` and into its own group UI (`Turtle_GroupUI.lua:259`, toc row 106-ish), + // and `RaidFrameReadyCheckButton`'s `` calls it by name + // (`Blizzard_RaidUI.xml:538-540`). Without it the button clicks into a nil. + load_ui(s, r"Interface\FrameXML\Turtle_GroupUI\Turtle_GroupUI.lua"); seat_chain_addon(s, "Blizzard_RaidUI"); s.run("RaidFrame_LoadUI()").unwrap(); }