The panel registry, the map's own row, and a test that raced
`UIParent.lua`'s registry moved under three tests at once:
- `ItemTextFrame` is `pushable = 5`, so the reader shares the screen instead of replacing what is
there; `QuestLogFrame` is `area = "doublewide"` with `width = 690`, not a left-slot window, so a
`whileDead` open seats at the doublewide slot and leaves the left one empty; and
`UIChildWindows` has five rows, the realm having added `ReputationDetailFrame`.
- `SetUIPanel` runs `CloseChildWindows()` for **any** slot it seats (`UIParent.lua:792-796`), not
just the centre one, so a window merely pushed across also puts the open letter away. The test
that pinned the stock trigger now watches both halves go.
- `user_placed_layouts()` is not empty after a manifest load, and should not be: the realm's own
movable windows stamp themselves in their OnLoad — `PlayerFrame.xml:488-489` is
`SetMovable(1) SetUserPlaced(true)`, the same feature as the `MOVE`/`MOVE_RESET` rows in their
right-click menus — and `TargetFrame`, the Turtle shop, transmog and guild bank do likewise. The
map test now asserts about its own row rather than about the file being empty.
- The blip tooltip calls `UnitName("player")` (`WorldMapFrame.lua:660`), which reads the player
record; `load_default_ui` seats a placeholder one so the realm's files have a race and class at
load, so a test that wants a named player names the record, after the manifest.
And one real race, not a realm change: `a_binding_table_resolves_whatever_case_the_package_spelled_it_in`
moves `BENILLA_HOME` and `WOW_CAPTURE` without taking `ENV_LOCK`. It was the only env-moving test
in that module missing it, and the collision shows up as a *neighbour* reading the wrong roster —
which is how it surfaced here, two addons tests failing in the full run and passing alone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -1357,6 +1357,13 @@ mod tests {
|
||||
/// its hover-bind, its edit-mode escape and every bar page key.
|
||||
#[test]
|
||||
fn a_binding_table_resolves_whatever_case_the_package_spelled_it_in() {
|
||||
// This test moves `BENILLA_HOME` and `WOW_CAPTURE`, which are process-wide: without the
|
||||
// lock every other env-moving test in this module can see a home that is not its own.
|
||||
// It is the one such test here that was missing it, and the collision shows up as a
|
||||
// neighbour reading the wrong roster, not as a failure here.
|
||||
let _l = crate::local_state::test_env::ENV_LOCK
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
let tmp =
|
||||
std::env::temp_dir().join(format!("benilla-addon-lcbindings-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&tmp);
|
||||
|
||||
@@ -977,7 +977,9 @@ fn the_panel_registry_rows_match_the_reference_bytes() {
|
||||
for probe in [
|
||||
// UIParent.lua:20
|
||||
"UIPanelWindows['ItemTextFrame'].area == 'left'",
|
||||
"UIPanelWindows['ItemTextFrame'].pushable == 0",
|
||||
// 5, not 1.12's 0: the realm made the reader pushable, so it shares the screen with
|
||||
// another left-slot window instead of replacing it.
|
||||
"UIPanelWindows['ItemTextFrame'].pushable == 5",
|
||||
"UIPanelWindows['ItemTextFrame'].whileDead == nil",
|
||||
// UIParent.lua:19
|
||||
"UIPanelWindows['CharacterFrame'].pushable == 2",
|
||||
@@ -985,12 +987,15 @@ fn the_panel_registry_rows_match_the_reference_bytes() {
|
||||
// UIParent.lua:21 and :25
|
||||
"UIPanelWindows['SpellBookFrame'].whileDead == 1",
|
||||
"UIPanelWindows['QuestLogFrame'].whileDead == 1",
|
||||
// UIParent.lua:45-50; `TalentFrame`'s row loads with `Blizzard_TalentUI.lua:71`.
|
||||
"table.getn(UIChildWindows) == 4",
|
||||
// UIParent.lua:46-52; `TalentFrame`'s row loads with `Blizzard_TalentUI.lua:71`. Five
|
||||
// rows, not 1.12's four: the realm added `ReputationDetailFrame`, so a frame arriving at
|
||||
// centre now puts that one away too.
|
||||
"table.getn(UIChildWindows) == 5",
|
||||
"UIChildWindows[1] == 'OpenMailFrame'",
|
||||
"UIChildWindows[2] == 'GuildControlPopupFrame'",
|
||||
"UIChildWindows[3] == 'GuildMemberDetailFrame'",
|
||||
"UIChildWindows[4] == 'GuildInfoFrame'",
|
||||
"UIChildWindows[5] == 'ReputationDetailFrame'",
|
||||
] {
|
||||
assert!(
|
||||
s.eval::<bool>(&format!("return {probe}")).unwrap(),
|
||||
@@ -1054,10 +1059,17 @@ fn a_dead_player_opens_only_whiledead_windows() {
|
||||
s.eval::<bool>("return QuestLogFrame:IsShown()").unwrap(),
|
||||
"a whileDead = 1 row opens exactly as alive"
|
||||
);
|
||||
// …at the **doublewide** slot: the realm's row is
|
||||
// `{ area = "doublewide", pushable = 0, whileDead = 1, width = 690 }` (`UIParent.lua:22`),
|
||||
// where 1.12's quest log was a plain left-slot window.
|
||||
assert!(
|
||||
s.eval::<bool>("return GetLeftFrame():GetName() == 'QuestLogFrame'")
|
||||
s.eval::<bool>("return GetUIPanel('doublewide'):GetName() == 'QuestLogFrame'")
|
||||
.unwrap(),
|
||||
"and it seats normally at the left slot"
|
||||
"and it seats normally, at the slot its own row names"
|
||||
);
|
||||
assert!(
|
||||
s.eval::<bool>("return GetLeftFrame() == nil").unwrap(),
|
||||
"which is not the left one"
|
||||
);
|
||||
assert!(
|
||||
s.take_ui_errors().is_empty(),
|
||||
@@ -1065,10 +1077,12 @@ fn a_dead_player_opens_only_whiledead_windows() {
|
||||
);
|
||||
}
|
||||
|
||||
/// `SetCenterFrame` hides every `UIChildWindows` frame (`UIParent.lua:839-846`), but
|
||||
/// `MovePanelToCenter` seats by assignment (`:877-885`), so a frame pushed to center leaves them.
|
||||
/// `SetUIPanel` hides every `UIChildWindows` frame whenever it seats one, in **any** slot
|
||||
/// (`UIParent.lua:792-796`, `CloseChildWindows` at `:1289`). Stock 1.12 gated that on the centre
|
||||
/// seat, so a window merely pushed across left the open letter alone; the realm's version does
|
||||
/// not, which is why the second half of this test watches it go too.
|
||||
#[test]
|
||||
fn a_frame_arriving_at_center_puts_the_child_windows_away() {
|
||||
fn a_frame_arriving_at_any_slot_puts_the_child_windows_away() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let mut s = UiScript::new().unwrap();
|
||||
s.set_screen_size(1024.0, 768.0);
|
||||
@@ -1103,7 +1117,8 @@ fn a_frame_arriving_at_center_puts_the_child_windows_away() {
|
||||
"the arriving center frame hid the open letter (the UIChildWindows loop)"
|
||||
);
|
||||
|
||||
// LootFrame (pushable 7) holds left; a pushable-0 window slides it to center, the letter stays.
|
||||
// LootFrame (pushable 7) holds left; a pushable-0 window slides it to center — and the letter
|
||||
// goes with it, because the newcomer's own seat ran the loop.
|
||||
s.run(
|
||||
r#"HideUIPanel(TradeFrame) HideUIPanel(MerchantFrame)
|
||||
OpenMailFrame:Show()
|
||||
@@ -1119,7 +1134,7 @@ fn a_frame_arriving_at_center_puts_the_child_windows_away() {
|
||||
"loot slid to center (MovePanelToCenter), merchant took left"
|
||||
);
|
||||
assert!(
|
||||
s.eval::<bool>("return OpenMailFrame:IsShown()").unwrap(),
|
||||
"a PUSHED frame does not run the child-window loop — the ref's exact trigger"
|
||||
!s.eval::<bool>("return OpenMailFrame:IsShown()").unwrap(),
|
||||
"every seat runs the child-window loop here, not only the centre one"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -532,6 +532,16 @@ fn hovering_the_player_blip_on_a_scaled_map_names_the_player() {
|
||||
);
|
||||
let failures = super::load_default_ui(&s);
|
||||
assert!(failures.is_empty(), "manifest load errors: {failures:#?}");
|
||||
// After the manifest, not before: `load_default_ui` seats a placeholder player record so the
|
||||
// realm's own files have a race and a class to read at load, and `UnitName("player")` — which
|
||||
// is what the blip's tooltip calls (`WorldMapFrame.lua:660`) — reads that record, not the unit
|
||||
// snapshot. Naming it here is what makes the two agree.
|
||||
s.set_player_record(benilla_ui::script::PlayerRecord {
|
||||
name: "Probefour".into(),
|
||||
race: Some(("Human".into(), "Human".into())),
|
||||
class: Some(("Warrior".into(), "WARRIOR".into())),
|
||||
sex: 2,
|
||||
});
|
||||
s.resolve();
|
||||
s.run("ShowUIPanel(WorldMapFrame)").unwrap();
|
||||
s.resolve();
|
||||
@@ -897,9 +907,20 @@ fn a_stale_layout_row_cannot_seat_a_stock_frame() {
|
||||
.unwrap(),
|
||||
"and the apply's userPlaced stamp lives inside the position arm it never took"
|
||||
);
|
||||
// …so the row falls out of the file at this logout instead of being written again. Only this
|
||||
// row: the realm stamps its own movable windows userPlaced in their OnLoad — `PlayerFrame`
|
||||
// and `TargetFrame` both do `SetMovable(1) SetUserPlaced(true)` (`PlayerFrame.xml:488-489`),
|
||||
// which is the same feature as the `MOVE`/`MOVE_RESET` rows in their right-click menus, and
|
||||
// the Turtle shop/transmog/guild-bank windows do the same. Those five belong in the file.
|
||||
assert!(
|
||||
s.user_placed_layouts().is_empty(),
|
||||
"so the row falls out of the file at this logout instead of being written again"
|
||||
!s.user_placed_layouts()
|
||||
.iter()
|
||||
.any(|l| l.name == "WorldMapFrame"),
|
||||
"the map must not be written back: {:?}",
|
||||
s.user_placed_layouts()
|
||||
.iter()
|
||||
.map(|l| l.name.clone())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
// The control: with the addon's `SetMovable` and `SetResizable`, the same row seats.
|
||||
@@ -921,8 +942,11 @@ fn a_stale_layout_row_cannot_seat_a_stock_frame() {
|
||||
"and the position arm stamps the bit it was written under"
|
||||
);
|
||||
let saved = s.user_placed_layouts();
|
||||
assert_eq!(saved.len(), 1, "which is what puts the row back: {saved:?}");
|
||||
assert_eq!(saved[0], row(), "unchanged through the round trip");
|
||||
let map_row = saved
|
||||
.iter()
|
||||
.find(|l| l.name == "WorldMapFrame")
|
||||
.unwrap_or_else(|| panic!("which is what puts the row back: {saved:?}"));
|
||||
assert_eq!(*map_row, row(), "unchanged through the round trip");
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user