every dialog is the reference's own, and the trainer loads on demand
- every dialog is the reference's own: `StaticPopup.xml` + `StaticPopup.lua` load off the player's chain, and 0308's engine with its 37 dialogs leaves `UiPanels.xml`; all 76 of the reference's dialogs are the stock table's, 28 of which no file of ours had ever registered (the resurrect family among them); the nine hidden listener frames that existed only because benilla once had no `UIParent_OnEvent` come home to it verbatim from UIParent.lua, and the seven files that were nothing but a dialog and its driver are deleted; what the swap surfaced: the reference capitalises the countdown's unit word ("5 Minutes until release") where ours had lowercased it, and ESC in the typed delete confirm's box is swallowed — the entry names no escape handler; arms for events this engine never fires (PLAYER_SKINNED, TRADE_REQUEST) wait on their feeds rather than being armed blind (1960)
- the social window and the unit menus are the reference's own files: `FriendsFrame.xml` loads off the chain and our transcription is deleted — its twelve dialogs re-homed, `FRIENDLIST_SHOW` fired as the answer to an explicit `ShowFriends()`, and `Get`/`SetLookingForGroup` a client-side flag until their bodies are carved; `UnitPopup.xml` loads off the chain, our row catalogue and its driver frame go, and nine verbs are built for it — `HasFullControl` off the player-control flag the reference reads at `0x51a158`, `UnitPlayerOrPetInParty`/`InRaid` over a new unit owner, and the six pet one-shots, each pressing the bar's own reaction or command slot word through the same latch and `CMSG_PET_ACTION`, confirmed by wow-re's carve; the Guild Leave/Promote confirms 1958 believed nothing registered were our social file's all along, and the duplicate went with it (1958, 1959)
- the trainer loads on demand: our `TrainerFrame.xml` is deleted and no row replaces it — `Blizzard_TrainerUI` loads off the player's own chain through the reference's `ClassTrainerFrame_LoadUI`, and the LoadOnDemand `Blizzard_*` addons are registry rows read off the chain; the timing IS the mechanism: the list builder writes the state-filter mask to 3 on every `SMSG_TRAINER_LIST` (`0x4d75d9`) and the stock addon pushes its saved filters exactly once, on its own ADDON_LOADED — which fires on the session's first trainer, after that packet, so the saved filters win that open and an eager load would never have applied them; the loader holds an anchor to a sibling not built yet and applies it once the subtree exists; and `UNIT_FLAGS` fires only on a change between two snapshots — wow-re's trio found the per-field watch bridge runs no notify pass on the create leg, correcting 1953 (1957)
- the additive window, built and withdrawn the same hour: under `BLEND_ADD` every additive particle draw commutes with every other, so same-key additive draws can be regrouped exactly — built in the effect lane's merge walk and measured on the crowd rig (Stormwind, forty partybots): the adjacency merge already folds about half the effect items and the regroup found two more folds in a frame of ninety-three, so the pre-regroup walk is what runs; what stays: an `fx=` items/merged census on the FPS probe line, a `DRESS_PART` line per drawn part of the self body on the dress census, and the regression the A/B uncovered: 1948's stock chat migration dropped the drain's plain-line sender, so every `WOW_PROBE_CHAT` rig — the crowd rig's forty `.partybot add`s among them — had gone silent on the server; a probe's slash-less line reaches the wire as SAY again (1955)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -207,6 +207,10 @@ fn load_action_bar(s: &UiScript) {
|
||||
// reference declares them in UIOptionsFrame_Init (1938) — and the manifest loads it before
|
||||
// the bars.
|
||||
super::test_ui::load_ui(s, "UiPanels.xml");
|
||||
// The dialog engine — the keybindings page registers its two confirms into its table (1960).
|
||||
super::test_ui::load_ui(s, r"Interface\FrameXML\BasicControls.xml"); // `TEXT`
|
||||
super::test_ui::load_ui(s, r"Interface\FrameXML\LocaleProperties.lua"); // `GetText`
|
||||
super::test_ui::load_ui(s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
super::test_ui::load_ui(s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
super::test_ui::load_ui(s, "ScrollTemplates.xml");
|
||||
super::test_ui::load_ui(s, "KeyBindingsPage.xml");
|
||||
@@ -1371,6 +1375,9 @@ fn the_main_bar_pages_and_a_bonus_page_still_outranks_it() {
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
"OptionsFrame.xml",
|
||||
"Interface\\FrameXML\\MultiActionBars.xml",
|
||||
|
||||
@@ -370,7 +370,56 @@ fn root_from(home: Option<PathBuf>) -> Option<PathBuf> {
|
||||
/// runs on one machine load the same interface. Real ordering constraints between addons are
|
||||
/// expressed by `## Dependencies:` and honoured by [`load_third_party`]'s recursion, which is the
|
||||
/// mechanism the reference actually uses.
|
||||
/// The reference's own LoadOnDemand addons, as its `Interface\\AddOns\\` folder names them — the
|
||||
/// twelve `Blizzard_*` folders on a 1.12 install, each a `.pub` decoy on disk with the real files
|
||||
/// inside the archive (the InspectUI header in the manifest). Probed against the chain, so a
|
||||
/// chain without one simply has no such addon.
|
||||
const BLIZZARD_ADDONS: [&str; 12] = [
|
||||
"Blizzard_AuctionUI",
|
||||
"Blizzard_BattlefieldMinimap",
|
||||
"Blizzard_BindingUI",
|
||||
"Blizzard_CombatText",
|
||||
"Blizzard_CraftUI",
|
||||
"Blizzard_GMSurveyUI",
|
||||
"Blizzard_InspectUI",
|
||||
"Blizzard_MacroUI",
|
||||
"Blizzard_RaidUI",
|
||||
"Blizzard_TalentUI",
|
||||
"Blizzard_TradeSkillUI",
|
||||
"Blizzard_TrainerUI",
|
||||
];
|
||||
|
||||
/// The Blizzard addons the chain carries as LoadOnDemand registry rows — the ones the reference
|
||||
/// reaches through `LoadAddOn` from `UIParentLoadAddOn` (1957). Two exclusions, both by shape:
|
||||
/// an addon `benilla.toc` lists with everything else (the eager trio the InspectUI header
|
||||
/// describes) already loaded and is not a row here; an addon whose toc is not LoadOnDemand
|
||||
/// would need the startup walk to read the chain, which it does not yet — that one stays with
|
||||
/// its own file until its window migrates.
|
||||
fn chain_addons() -> Vec<Addon> {
|
||||
let eager = super::manifest::chain_addons(&Addon::builtin().toc.files);
|
||||
BLIZZARD_ADDONS
|
||||
.iter()
|
||||
.filter(|name| !eager.iter().any(|e| e.eq_ignore_ascii_case(name)))
|
||||
.filter_map(|name| {
|
||||
let bytes = super::reference_ui::read(&format!("Interface/AddOns/{name}/{name}.toc"))?;
|
||||
let toc = Toc::parse(&benilla_ui::source::decode(&bytes));
|
||||
toc.load_on_demand().then(|| Addon {
|
||||
name: (*name).to_string(),
|
||||
toc,
|
||||
source: Source::Chain,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn discover() -> Vec<Addon> {
|
||||
let mut found = discover_folder();
|
||||
found.extend(chain_addons());
|
||||
found
|
||||
}
|
||||
|
||||
/// The player's own addons — every folder under the AddOns root with a `<Name>.toc`.
|
||||
fn discover_folder() -> Vec<Addon> {
|
||||
let Some(root) = root() else {
|
||||
return Vec::new();
|
||||
};
|
||||
@@ -424,7 +473,9 @@ fn manifest_in(dir: &Path, name: &str) -> Option<String> {
|
||||
/// Build the AddOn API's registry row for one discovered addon — every `.toc` directive the
|
||||
/// eleven verbs can be asked about, read once here rather than re-parsed per call.
|
||||
fn info_for(addon: &Addon) -> benilla_ui::script::AddOnInfo {
|
||||
info_from_toc(&addon.name, &addon.toc)
|
||||
let mut info = info_from_toc(&addon.name, &addon.toc);
|
||||
info.chain = matches!(addon.source, Source::Chain);
|
||||
info
|
||||
}
|
||||
|
||||
/// [`info_for`]'s body, over the two things it actually reads.
|
||||
@@ -462,6 +513,7 @@ pub(crate) fn info_from_toc(name: &str, toc: &Toc) -> benilla_ui::script::AddOnI
|
||||
// The version gate's dword (decision 1292) — the client's own parse: leading integer,
|
||||
// 0 when the manifest is silent (and 0 is out of date, not "unknown").
|
||||
interface: toc.interface_version(),
|
||||
chain: false, // `info_for` stamps the chain rows; the harness's rows are folder addons
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,7 +605,9 @@ impl InstalledAddOn {
|
||||
/// everything as enabled.
|
||||
pub(crate) fn installed(identity: Option<&(String, String)>) -> Vec<InstalledAddOn> {
|
||||
let disabled = disabled_set(identity);
|
||||
discover()
|
||||
// The player's own folder only: the glue's list is what a player can toggle, and the
|
||||
// reference's Blizzard addons are not in it.
|
||||
discover_folder()
|
||||
.into_iter()
|
||||
.map(|addon| InstalledAddOn {
|
||||
enabled: !disabled.contains(&addon.name.to_ascii_lowercase()),
|
||||
@@ -697,6 +751,8 @@ pub(super) fn load_third_party(
|
||||
// rather than answer whatever a previous session left, and an addon that asks before any
|
||||
// exist is asking a real question.
|
||||
let mut infos: Vec<_> = addons.iter().map(info_for).collect();
|
||||
// The chain-sourced rows read through the reference's own store (1957).
|
||||
script.set_addon_chain_reader(Box::new(super::reference_ui::read));
|
||||
if let Some(text) = enable_state_path(identity).and_then(|p| std::fs::read_to_string(p).ok()) {
|
||||
for (name, enabled) in parse_enable_state(&text) {
|
||||
if let Some(i) = infos
|
||||
@@ -925,6 +981,44 @@ impl Walk {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
/// The chain's Blizzard LoadOnDemand addons are registry rows (1957): every row is
|
||||
/// LoadOnDemand and read off the chain, `Blizzard_TrainerUI` is among them, and an addon
|
||||
/// the manifest lists eagerly is not a row twice.
|
||||
#[test]
|
||||
fn the_chain_carries_blizzards_load_on_demand_addons_as_registry_rows() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let rows = chain_addons();
|
||||
assert!(
|
||||
rows.iter().any(|a| a.name == "Blizzard_TrainerUI"),
|
||||
"the trainer addon is a row: {:?}",
|
||||
rows.iter().map(|a| &a.name).collect::<Vec<_>>()
|
||||
);
|
||||
for a in &rows {
|
||||
assert!(a.toc.load_on_demand(), "{} is LoadOnDemand", a.name);
|
||||
assert!(
|
||||
matches!(a.source, Source::Chain),
|
||||
"{} comes off the chain",
|
||||
a.name
|
||||
);
|
||||
assert!(
|
||||
info_for(a).chain,
|
||||
"{}'s registry row is marked chain-sourced",
|
||||
a.name
|
||||
);
|
||||
}
|
||||
let eager = super::super::manifest::chain_addons(&Addon::builtin().toc.files);
|
||||
for e in &eager {
|
||||
assert!(
|
||||
!rows.iter().any(|a| a.name.eq_ignore_ascii_case(e)),
|
||||
"{e} is listed in benilla.toc and must not also be a row"
|
||||
);
|
||||
}
|
||||
// The glue's list is the player's folder alone.
|
||||
assert!(installed(None)
|
||||
.iter()
|
||||
.all(|a| !a.name.starts_with("Blizzard_")));
|
||||
}
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Build an addon over a temp AddOns root, so the walk can be tested without an install.
|
||||
@@ -1607,7 +1701,12 @@ mod tests {
|
||||
assert!(failures.is_empty(), "load errors: {failures:?}");
|
||||
|
||||
// Discovery saw it at all — the `.toc` decoded rather than read as absent.
|
||||
assert_eq!(script.eval::<i64>("return GetNumAddOns()").ok(), Some(1));
|
||||
// The one in the folder, plus the chain's Blizzard LoadOnDemand rows on a machine that
|
||||
// has a chain (1957) — the registry is one list, as the reference's is.
|
||||
assert_eq!(
|
||||
script.eval::<i64>("return GetNumAddOns()").ok(),
|
||||
Some(1 + chain_addons().len() as i64)
|
||||
);
|
||||
assert_eq!(
|
||||
script
|
||||
.eval::<String>("return GetAddOnMetadata('Umlaut', 'Title')")
|
||||
@@ -1705,7 +1804,12 @@ mod tests {
|
||||
let mut script = UiScript::new().unwrap();
|
||||
let _ = load_third_party(&mut script, None, true);
|
||||
|
||||
assert_eq!(script.eval::<i64>("return GetNumAddOns()").ok(), Some(1));
|
||||
// The one in the folder, plus the chain's Blizzard LoadOnDemand rows on a machine that
|
||||
// has a chain (1957) — the registry is one list, as the reference's is.
|
||||
assert_eq!(
|
||||
script.eval::<i64>("return GetNumAddOns()").ok(),
|
||||
Some(1 + chain_addons().len() as i64)
|
||||
);
|
||||
assert_eq!(
|
||||
script
|
||||
.eval::<Vec<String>>(
|
||||
@@ -1861,7 +1965,12 @@ mod tests {
|
||||
let _ = load_third_party(&mut script, None, true);
|
||||
|
||||
// Discovered and described, but NOT run.
|
||||
assert_eq!(script.eval::<i64>("return GetNumAddOns()").ok(), Some(1));
|
||||
// The one in the folder, plus the chain's Blizzard LoadOnDemand rows on a machine that
|
||||
// has a chain (1957) — the registry is one list, as the reference's is.
|
||||
assert_eq!(
|
||||
script.eval::<i64>("return GetNumAddOns()").ok(),
|
||||
Some(1 + chain_addons().len() as i64)
|
||||
);
|
||||
assert_eq!(
|
||||
script
|
||||
.eval::<bool>("return IsAddOnLoadOnDemand(1) == 1")
|
||||
@@ -1986,8 +2095,14 @@ mod tests {
|
||||
save_enable_state(&script, Some(&id));
|
||||
|
||||
let written = std::fs::read_to_string(home.join("addons/Realm-Char.txt")).unwrap();
|
||||
// The folder's two in registry order, then the chain's Blizzard rows (1957) — every
|
||||
// registry row has a line, the reference's own one-line-per-addon format.
|
||||
let mut expected = String::from("Drop: disabled\nKeep: enabled\n");
|
||||
for a in chain_addons() {
|
||||
expected.push_str(&format!("{}: enabled\n", a.name));
|
||||
}
|
||||
assert_eq!(
|
||||
written, "Drop: disabled\nKeep: enabled\n",
|
||||
written, expected,
|
||||
"the reference's own one-line-per-addon format"
|
||||
);
|
||||
|
||||
|
||||
@@ -16,7 +16,11 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "BinderConfirm.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s.set_binder_pending(true);
|
||||
s
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ fn harness() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Cooldown.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
|
||||
|
||||
@@ -398,6 +398,8 @@ fn managed_positions_track_the_bottom_bar_stack() {
|
||||
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.xml");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\FloatingChatFrame.xml");
|
||||
|
||||
// The loader's post-load bootstrap, replayed with no bars in existence: the bare bases.
|
||||
|
||||
@@ -1209,6 +1209,10 @@ fn an_addons_tab_click_selects_through_the_generic_entry_point() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
|
||||
// A conforming row: tabs named `<frame>Tab1..N` (what `PanelTemplates_UpdateTabs` getglobals)
|
||||
|
||||
@@ -48,6 +48,10 @@ fn chat_with_menu() -> UiScript {
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\ColorPickerFrame.xml",
|
||||
"Interface\\FrameXML\\UIMenu.xml", // the kit ChatMenu/EmoteMenu/VoiceMacroMenu build from
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
|
||||
@@ -26,6 +26,10 @@ fn chat_ui() -> UiScript {
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\ColorPickerFrame.xml",
|
||||
"Interface\\FrameXML\\UIMenu.xml", // the kit ChatMenu/EmoteMenu/VoiceMacroMenu build from
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
|
||||
@@ -29,6 +29,8 @@ fn chat_frame() -> UiScript {
|
||||
// bar and the chat files; `FCF_OnUpdate` — the dock's hover, fade and drag driver — runs
|
||||
// from UIParent's OnUpdate, as in the reference.
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
// `FCF_ValidateChatFramePosition` (a tab-drag stop) reads `MainMenuBar:GetHeight()`; the bar's
|
||||
// own load-time chain precedes it, as in the action-bar harness.
|
||||
@@ -994,6 +996,10 @@ fn the_chat_menu_builds_its_rows_on_the_references_kit() {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml",
|
||||
r"Interface\FrameXML\UIMenu.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
|
||||
@@ -28,6 +28,10 @@ fn ui_with_the_cinematic_frame() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\CinematicFrame.xml");
|
||||
s.resolve();
|
||||
s
|
||||
|
||||
@@ -26,6 +26,10 @@ fn picker() -> UiScript {
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\ColorPickerFrame.xml",
|
||||
] {
|
||||
load_xml(&s, file);
|
||||
|
||||
@@ -23,11 +23,15 @@ fn load_combo_frame() -> UiScript {
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
load_xml(&s, "UnitPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UnitPopup.xml");
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.lua");
|
||||
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BuffFrame.xml");
|
||||
|
||||
@@ -15,7 +15,11 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "DeathFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s
|
||||
}
|
||||
|
||||
@@ -38,7 +42,7 @@ fn death_popup_counts_down_and_release_queues_repop() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"5 minutes until release",
|
||||
"5 Minutes until release",
|
||||
"the countdown renders through the engine's DEATH per-tick text"
|
||||
);
|
||||
// ESC must NOT close it (no hideOnEscape on DEATH — the ref's law).
|
||||
@@ -249,7 +253,7 @@ fn resurrect_request_picks_variant_and_answers() {
|
||||
fn xp_loss_two_step_confirm_then_range_hide() {
|
||||
let mut s = setup();
|
||||
s.set_death(DeathUiState {
|
||||
sickness_duration: Some("8 minutes".into()),
|
||||
sickness_duration: Some("8 Minutes".into()),
|
||||
spirit_healer_in_range: true,
|
||||
..Default::default()
|
||||
});
|
||||
@@ -262,7 +266,7 @@ fn xp_loss_two_step_confirm_then_range_hide() {
|
||||
.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap();
|
||||
assert!(
|
||||
text.contains("afflicted by 8 minutes of Resurrection Sickness"),
|
||||
text.contains("afflicted by 8 Minutes of Resurrection Sickness"),
|
||||
"the sickness duration formats into CONFIRM_XP_LOSS: {text}"
|
||||
);
|
||||
// First Accept: the AGAIN text swaps in, the dialog stays, nothing queues. XP_LOSS's verbatim
|
||||
@@ -318,7 +322,7 @@ fn xp_loss_two_step_confirm_then_range_hide() {
|
||||
fn xp_loss_cancel_then_reconfirm_reshows_with_the_alert_dress() {
|
||||
let mut s = setup();
|
||||
s.set_death(DeathUiState {
|
||||
sickness_duration: Some("8 minutes".into()),
|
||||
sickness_duration: Some("8 Minutes".into()),
|
||||
spirit_healer_in_range: true,
|
||||
..Default::default()
|
||||
});
|
||||
@@ -414,7 +418,7 @@ fn corpse_range_events_drive_recover_corpse() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"2 seconds until resurrection"
|
||||
"2 Seconds until resurrection"
|
||||
);
|
||||
s.tick(1.6);
|
||||
assert_eq!(
|
||||
|
||||
@@ -61,6 +61,17 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
// The stock DELETE_GOOD_ITEM's OnHide hands focus back to `ChatFrameEditBox` (1960).
|
||||
load_xml(&s, r"Interface\FrameXML\UIMenu.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\ChatFrame.xml");
|
||||
load_xml(&s, "GameTooltip.xml"); // TOOLTIP_DEFAULT_COLOR, read by the dropdown backdrop
|
||||
load_xml(&s, r"Interface\FrameXML\UIDropDownMenu.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\FloatingChatFrame.xml"); // declares ChatFrameEditBox
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s.set_money(0);
|
||||
s
|
||||
}
|
||||
@@ -437,13 +448,14 @@ fn no_on_the_typed_confirm_clears_and_leaves_the_box_empty_for_next_time() {
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
/// ESC out of the focused box: 1743's named divergence. The reference's `DELETE_GOOD_ITEM` names
|
||||
/// no `EditBoxOnEscapePressed`, so in 1.12 the focused box swallows the key and the destroy
|
||||
/// confirm cannot be dismissed with ESC at all. benilla's engine falls back to the ordinary
|
||||
/// hideOnEscape leg — the entry's `OnCancel` (`ClearCursor()`), then hide — so the item is
|
||||
/// released rather than left held under a dialog that will not close.
|
||||
/// ESC inside the typed confirm's focused box is SWALLOWED, the reference's own behaviour (1960):
|
||||
/// the stock `DELETE_GOOD_ITEM` entry defines no `EditBoxOnEscapePressed`, so the box's
|
||||
/// `StaticPopup_EditBoxOnEscapePressed` finds nothing to call and the dialog stays up with the
|
||||
/// item still on the cursor — the player answers with No. (ADD_FRIEND and its kin hide on ESC
|
||||
/// because their entries say so; this one does not.) Our engine used to fall through to a
|
||||
/// cancel here, which the earlier form of this test pinned.
|
||||
#[test]
|
||||
fn escape_out_of_the_typed_confirm_cancels_the_way_every_other_popup_does() {
|
||||
fn escape_in_the_typed_confirms_box_is_swallowed_as_the_reference_leaves_it() {
|
||||
let mut s = setup();
|
||||
drop_in_world(&mut s, 871, "Flurry Axe", 4);
|
||||
assert!(s
|
||||
@@ -452,10 +464,15 @@ fn escape_out_of_the_typed_confirm_cancels_the_way_every_other_popup_does() {
|
||||
|
||||
assert!(s.key_input("ESCAPE"), "the focused box consumes ESCAPE");
|
||||
assert!(
|
||||
!s.eval::<bool>("return StaticPopup1:IsVisible()").unwrap(),
|
||||
"ESC closes it"
|
||||
s.eval::<bool>("return StaticPopup1:IsVisible()").unwrap(),
|
||||
"the dialog stays: the entry names no escape handler"
|
||||
);
|
||||
assert!(s.cursor_item().is_none(), "and runs OnCancel's ClearCursor");
|
||||
assert!(
|
||||
s.eval::<bool>("return StaticPopup1EditBox:HasFocus()")
|
||||
.unwrap(),
|
||||
"and the box keeps focus"
|
||||
);
|
||||
assert!(s.cursor_item().is_some(), "the item is still on the cursor");
|
||||
assert!(s.take_container_destroys().is_empty(), "ESC never destroys");
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ const JERKY_LINK: &str = "|cffffffff|Hitem:117|h[Tough Jerky]|h|r";
|
||||
/// with these, in manifest order.
|
||||
const ROOM_UI: &[&str] = &[
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\ItemRef.xml",
|
||||
"Interface\\FrameXML\\MerchantFrame.xml",
|
||||
"Interface\\FrameXML\\StackSplitFrame.xml",
|
||||
@@ -46,6 +48,8 @@ const ROOM_UI: &[&str] = &[
|
||||
"Interface\\FrameXML\\UIPanelTemplates.lua",
|
||||
"Interface\\FrameXML\\UIPanelTemplates.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\FloatingChatFrame.xml",
|
||||
];
|
||||
|
||||
@@ -60,6 +64,10 @@ fn load_room(s: &UiScript) {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"UIParent.xml",
|
||||
"GameTooltip.xml",
|
||||
"Cooldown.xml",
|
||||
@@ -115,6 +123,8 @@ fn shown_paper_doll() -> UiScript {
|
||||
"Interface\\FrameXML\\UIPanelTemplates.lua",
|
||||
"Interface\\FrameXML\\UIPanelTemplates.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\FloatingChatFrame.xml",
|
||||
] {
|
||||
super::test_ui::load_ui_strict(&s, file);
|
||||
|
||||
@@ -15,7 +15,11 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "DuelFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s
|
||||
}
|
||||
|
||||
@@ -77,7 +81,7 @@ fn out_of_bounds_counts_down_and_inbounds_dismisses_it() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"Exiting duel area, you will forfeit in 10 seconds.",
|
||||
"Exiting duel area, you will forfeit in 10 Seconds.",
|
||||
"the engine's countdown branch fills %d %s"
|
||||
);
|
||||
s.fire_event("DUEL_INBOUNDS", vec![]);
|
||||
|
||||
@@ -20,6 +20,10 @@ fn harness() -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"UIParent.xml",
|
||||
"GameTooltip.xml",
|
||||
"MinimapCluster.xml",
|
||||
@@ -393,6 +397,9 @@ fn the_quest_tracker_stacks_below_the_durability_guy() {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"UIParent.xml",
|
||||
"GameTooltip.xml",
|
||||
"MinimapCluster.xml",
|
||||
|
||||
@@ -20,7 +20,11 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "EnchantConfirm.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,9 @@ fn an_error_toast_draws_over_an_open_panel_window() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml");
|
||||
load_xml(&s, "Cooldown.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); // BenillaMoney_* — QuestLogDetail's reward money row
|
||||
|
||||
@@ -155,6 +155,8 @@ fn escape_is_consumed_by_a_focused_editbox_and_leaves_windows_open() {
|
||||
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.xml");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\FloatingChatFrame.xml");
|
||||
s.set_money(0);
|
||||
s.set_container(0, Some(one_item_backpack()));
|
||||
@@ -191,6 +193,10 @@ fn escape_closes_the_options_window_before_opening_the_menu() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the Keybindings page's faux-scroll kit (1008)
|
||||
@@ -251,6 +257,8 @@ fn escape_closes_an_open_stack_split_frame() {
|
||||
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.xml");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\FloatingChatFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\StackSplitFrame.xml");
|
||||
s.set_money(0);
|
||||
@@ -499,6 +507,10 @@ fn an_addon_frame_registered_in_uispecialframes_closes_on_escape() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "GameMenuFrame.xml");
|
||||
|
||||
// The addon's three lines, verbatim in shape.
|
||||
|
||||
@@ -20,6 +20,10 @@ fn an_idle_fade_driver_parks_itself_off_the_tick() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
s.resolve();
|
||||
s.run(
|
||||
"BENILLA_TEST_FADE_TICKS = 0\n\
|
||||
@@ -59,6 +63,10 @@ fn a_started_fade_still_ramps_and_the_driver_reparks_after() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
s.resolve();
|
||||
s.run(r#"CreateFrame("Frame", "BenillaFadeProbe")"#)
|
||||
.unwrap();
|
||||
@@ -120,6 +128,10 @@ fn a_flash_alternates_then_stops_and_the_driver_reparks() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
s.resolve();
|
||||
|
||||
// Parked until something asks — the whole point of the driver over UIParent's own OnUpdate.
|
||||
|
||||
@@ -192,12 +192,6 @@ const KNOWN: &[Known] = &[
|
||||
"the enchant slot: ours inherits BenillaTradeEnchantItemTemplate, the reference's the \
|
||||
ordinary PlayerTradeItemTemplate. A structural difference in our own trade window.",
|
||||
},
|
||||
Known {
|
||||
frame: "WhoFrameDropDown",
|
||||
flag: Flag::Mouse,
|
||||
why: "the reference's /who sort dropdown carries its own handlers over the shared \
|
||||
UIDropDownMenuTemplate; ours takes the template alone.",
|
||||
},
|
||||
Known {
|
||||
frame: "WorldStateAlwaysUpFrame",
|
||||
flag: Flag::Mouse,
|
||||
@@ -603,11 +597,11 @@ fn the_shipped_frames_carry_the_references_flags() {
|
||||
}
|
||||
|
||||
assert!(
|
||||
// 1948 retired our ChatFrame.xml, 1952 our SpellBookFrame.xml, 1953 our PetActionBar.xml
|
||||
// and 1956 our SkillFrame.xml (their frames are the reference's own now), which took the
|
||||
// paired count from the low 400s to the high 310s; the floor guards the pairing, not the
|
||||
// census.
|
||||
compared > 300,
|
||||
// 1948 retired our ChatFrame.xml, 1952 our SpellBookFrame.xml, 1953 our PetActionBar.xml,
|
||||
// 1956 our SkillFrame.xml, 1958 our UnitPopup.xml and 1959 our FriendsFrame.xml (their
|
||||
// frames are the reference's own now), which took the paired count from the low 400s to
|
||||
// the high 150s; the floor guards the pairing, not the census.
|
||||
compared > 120,
|
||||
"only {compared} frames compared — the pairing broke, and the sweep guards nothing"
|
||||
);
|
||||
assert!(
|
||||
|
||||
@@ -15,50 +15,9 @@ use super::test_ui::load_ui_strict as load_xml;
|
||||
fn setup() -> UiScript {
|
||||
let mut s = UiScript::new().unwrap();
|
||||
s.set_screen_size(1024.0, 768.0);
|
||||
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
// The row right-click menu is the shared UnitPopup "FRIEND" menu, so the window's slice of
|
||||
// the manifest includes it (it loads well before FriendsFrame.xml in the real order).
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "UnitPopup.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
// The guild pane's frames inherit the reference's shared UIPanelButtonTemplate /
|
||||
// UIPanelCloseButton / UIPanelScrollFrameTemplate rather than a private copy (decision 1257),
|
||||
// so this file's slice needs the shared kit — and the strict `load_xml` above is what would
|
||||
// otherwise let those frames load art-less and silent.
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "FriendsFrame.xml");
|
||||
// The social window's fourth tab lives in its own file, and it is part of THIS window's
|
||||
// manifest slice now: `BENILLA_FRIENDS_SUBFRAMES` names "RaidFrame", and both
|
||||
// `FriendsFrame_ShowSubFrame` and `FriendsFrame_OnHide` resolve every name in that list
|
||||
// through `getglobal` and call `:Hide()` on it. The reference's list names it too and never
|
||||
// guards, because there RaidFrame.xml is FrameXML and always loaded — so the guard belongs in
|
||||
// the harness's load order, not in shipped Lua defending against a state the client cannot be
|
||||
// in (decision 1549).
|
||||
// Stock `RaidFrame_OnLoad` reconciles the party frames the moment it loads
|
||||
// (`RaidOptionsFrame_UpdatePartyFrames` -> `HidePartyFrame`/`ShowPartyFrame`), so this pane
|
||||
// drags in the whole unit-frame cluster — and it must be the REAL frames: loading only
|
||||
// `PartyFrame.lua` for the two names gets "attempt to index a nil value" the first time one
|
||||
// iterates. The manifest already seats these far above RaidFrame (1874).
|
||||
// The reference's own `BasicControls.xml`, which is manifest entry 3 — far above the pane
|
||||
// (1874). It is here for the error/message pair and `TEXT`. NOTE: unlike `raid_tests`, this
|
||||
// harness does not load `UIParent.xml`, so `UIParentLoadAddOn` — which 1881 moved there out
|
||||
// of BasicControls — is absent. Nothing this file exercises reaches it; if a future
|
||||
// assertion drives `RaidFrame_LoadUI`, that is the line to add.
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\TextStatusBar.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\TextStatusBar.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BuffFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UnitFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\CombatFeedback.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\PartyFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\RaidFrame.xml");
|
||||
load_xml(&s, r"Interface\AddOns\Blizzard_RaidUI\Blizzard_RaidUI.xml");
|
||||
for f in super::test_ui::SOCIAL_UI {
|
||||
load_xml(&s, f);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
@@ -171,17 +130,17 @@ fn friend_rows_render_the_online_and_offline_templates() {
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
s.eval::<String>("return FriendsFrameFriendButton1NameLocation:GetText()")
|
||||
s.eval::<String>("return FriendsFrameFriendButton1ButtonTextNameLocation:GetText()")
|
||||
.unwrap(),
|
||||
"Onerogue |cffffffff- Elwynn Forest|r <AFK>"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return FriendsFrameFriendButton1Info:GetText()")
|
||||
s.eval::<String>("return FriendsFrameFriendButton1ButtonTextInfo:GetText()")
|
||||
.unwrap(),
|
||||
"Level 60 Rogue"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return FriendsFrameFriendButton2NameLocation:GetText()")
|
||||
s.eval::<String>("return FriendsFrameFriendButton2ButtonTextNameLocation:GetText()")
|
||||
.unwrap(),
|
||||
"|cff999999Twomage - Offline|r"
|
||||
);
|
||||
@@ -270,8 +229,19 @@ fn the_friend_buttons_queue_their_verbs() {
|
||||
benilla_ui::script::PartyRequest::InviteName(n) if n == "Twomage"
|
||||
)));
|
||||
|
||||
// Send Message is the reference's `ChatFrame_OpenChat("/w Twomage ")`: the box shows with
|
||||
// the text PENDING (`editBox.setText = 1`), applied by its next OnUpdate, whose OnTextSet
|
||||
// runs the parse that turns the line into a whisper to the friend (1959).
|
||||
s.run("FriendsFrame_SendMessage()").unwrap();
|
||||
assert_eq!(s.take_tell_requests(), vec!["Twomage".to_string()]);
|
||||
s.tick(0.05);
|
||||
assert!(s
|
||||
.eval::<bool>("return ChatFrameEditBox:IsVisible()")
|
||||
.unwrap());
|
||||
assert_eq!(
|
||||
s.eval::<(String, String)>("return ChatFrameEditBox.chatType, ChatFrameEditBox.tellTarget")
|
||||
.unwrap(),
|
||||
("WHISPER".to_string(), "Twomage".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
/// The Ignore toggle-tab swaps tab 1's list without leaving the tab, and the ignore rows render
|
||||
@@ -304,12 +274,12 @@ fn the_ignore_list_is_the_other_half_of_tab_one() {
|
||||
"Ignore List"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return FriendsFrameIgnoreButton1Name:GetText()")
|
||||
s.eval::<String>("return FriendsFrameIgnoreButton1ButtonTextName:GetText()")
|
||||
.unwrap(),
|
||||
"Spammer"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return FriendsFrameIgnoreButton2Name:GetText()")
|
||||
s.eval::<String>("return FriendsFrameIgnoreButton2ButtonTextName:GetText()")
|
||||
.unwrap(),
|
||||
"Ninja"
|
||||
);
|
||||
@@ -328,9 +298,12 @@ fn the_ignore_list_is_the_other_half_of_tab_one() {
|
||||
assert!(s
|
||||
.eval::<bool>("return FriendsListFrame:IsVisible()")
|
||||
.unwrap());
|
||||
// The reference's `ShowIgnorePanel` shows the WINDOW (its tab switch is commented out in the
|
||||
// stock file), so the list that was up stays up — the friends list here (1959).
|
||||
s.run("ShowIgnorePanel()").unwrap();
|
||||
assert!(s.eval::<bool>("return FriendsFrame:IsVisible()").unwrap());
|
||||
assert!(s
|
||||
.eval::<bool>("return IgnoreListFrame:IsVisible()")
|
||||
.eval::<bool>("return FriendsListFrame:IsVisible()")
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
@@ -483,10 +456,13 @@ fn the_who_buttons_need_a_selected_row() {
|
||||
},
|
||||
"WHO_LIST_UPDATE",
|
||||
);
|
||||
// The reference keeps the selection across answers: `WhoList_Update` enables the buttons
|
||||
// whenever `WhoFrame.selectedWho` is set, and its WHO_LIST_UPDATE arm clears nothing. (Our
|
||||
// transcription dropped it; 1959.)
|
||||
assert!(
|
||||
!s.eval::<bool>("return WhoFrameAddFriendButton:IsEnabled() ~= 0")
|
||||
s.eval::<bool>("return WhoFrameAddFriendButton:IsEnabled() ~= 0")
|
||||
.unwrap(),
|
||||
"a fresh answer drops the old selection"
|
||||
"a fresh answer keeps the selection"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -527,57 +503,6 @@ fn the_who_edit_box_sends_its_filter() {
|
||||
);
|
||||
}
|
||||
|
||||
/// The slash bodies are the reference's: a NAMED `/friends` befriends, a bare one refreshes; a
|
||||
/// bare `/who` opens the panel and fills the edit box with the default filter.
|
||||
#[test]
|
||||
fn the_slash_bodies_match_the_reference() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let mut s = setup();
|
||||
// The WhoFrame's OnLoad routes results to chat until it is shown; drain that so each
|
||||
// assertion below sees only what its own call queued.
|
||||
let _ = s.take_social_requests();
|
||||
|
||||
s.run("BenillaSlashFriends(\"Onerogue\")").unwrap();
|
||||
assert_eq!(
|
||||
s.take_social_requests(),
|
||||
vec![SocialRequest::AddFriend("Onerogue".to_string())]
|
||||
);
|
||||
s.run("BenillaSlashFriends(\"\")").unwrap();
|
||||
assert_eq!(
|
||||
s.take_social_requests(),
|
||||
vec![SocialRequest::RefreshFriends]
|
||||
);
|
||||
|
||||
// `/ignore <name>` toggles rather than adds — the ref's AddOrDelIgnore.
|
||||
s.run("BenillaSlashIgnore(\"Spammer\")").unwrap();
|
||||
assert_eq!(
|
||||
s.take_social_requests(),
|
||||
vec![SocialRequest::ToggleIgnore("Spammer".to_string())]
|
||||
);
|
||||
|
||||
// A bare `/who` opens the Who panel and sends the default filter, which it also shows.
|
||||
s.run("BenillaSlashWho(\"\")").unwrap();
|
||||
assert!(s.eval::<bool>("return WhoFrame:IsVisible()").unwrap());
|
||||
let requests = s.take_social_requests();
|
||||
let sent = requests
|
||||
.iter()
|
||||
.find_map(|r| match r {
|
||||
SocialRequest::Who(filter) => Some(filter.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.expect("a bare /who still sends a query");
|
||||
assert!(
|
||||
sent.starts_with("z-\""),
|
||||
"the default filter is zone-scoped: {sent}"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return WhoFrameEditBox:GetText()")
|
||||
.unwrap(),
|
||||
sent,
|
||||
"and the edit box shows what was sent"
|
||||
);
|
||||
}
|
||||
|
||||
/// The Add Friend button with no friendly target opens the name-entry dialog — the first
|
||||
/// customer of the popup engine's `hasEditBox` capability. Accepting sends what was typed.
|
||||
#[test]
|
||||
@@ -604,7 +529,9 @@ fn add_friend_without_a_target_opens_the_name_dialog() {
|
||||
|
||||
let _ = s.take_social_requests();
|
||||
s.run("StaticPopup1EditBox:SetText(\"Onerogue\")").unwrap();
|
||||
s.run("StaticPopup_OnClick(StaticPopup1, 1)").unwrap();
|
||||
// Through the button: the stock dialog's OnAccept reads `this:GetParent()`, which only a
|
||||
// real click seats.
|
||||
s.run("StaticPopup1Button1:Click()").unwrap();
|
||||
assert_eq!(
|
||||
s.take_social_requests(),
|
||||
vec![SocialRequest::AddFriend("Onerogue".to_string())]
|
||||
@@ -684,7 +611,14 @@ fn right_clicking_a_who_row_opens_the_friend_menu() {
|
||||
Some(1),
|
||||
"the menu has a Whisper row"
|
||||
);
|
||||
assert_eq!(s.take_tell_requests(), vec!["Tigole".to_string()]);
|
||||
// The stock WHISPER row is `ChatFrame_SendTell(name)`: the chat box opens on the tell, its
|
||||
// pending text applied by the box's next OnUpdate (1959).
|
||||
s.tick(0.05);
|
||||
assert_eq!(
|
||||
s.eval::<(String, String)>("return ChatFrameEditBox.chatType, ChatFrameEditBox.tellTarget")
|
||||
.unwrap(),
|
||||
("WHISPER".to_string(), "Tigole".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
/// An OFFLINE friend's right-click opens nothing — there is no verb to offer them, which is the
|
||||
@@ -742,104 +676,3 @@ fn selecting_a_row_reads_back_in_the_same_tick() {
|
||||
.take_social_requests()
|
||||
.contains(&SocialRequest::SelectFriend(2)));
|
||||
}
|
||||
|
||||
/// **The window's geometry, diffed against the reference FrameXML itself.**
|
||||
///
|
||||
/// Every number in `FriendsFrame.xml` is a transcription of one in the reference's own file, and a
|
||||
/// wrong one is invisible to every other test here: the frame loads, the clicks work, only the
|
||||
/// *look* is wrong — so it surfaces as a screenshot from the director, one tab at a time. Two
|
||||
/// rounds of that is what this replaces. Four of the five it caught on its first run were the
|
||||
/// FriendsListFrame's values that had leaked into the IgnoreListFrame subtree, which is exactly
|
||||
/// the failure mode of building a sibling pane by copy-adapting instead of transcribing.
|
||||
///
|
||||
/// It scrapes both files for `<AbsDimension>` pairs per named element and compares the elements
|
||||
/// that exist in both (ours carry a `Benilla` prefix). Deliberately narrow — it does not try to
|
||||
/// understand the XML, only to notice that a number moved. Known-benign differences are listed
|
||||
/// explicitly rather than filtered by a pattern, so a NEW difference can never hide inside an
|
||||
/// exemption. Skips without the extracted reference.
|
||||
#[test]
|
||||
fn the_window_geometry_matches_the_reference_framexml() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let Some(reference) = super::framexml_diff::reference("FriendsFrame.xml") else {
|
||||
eprintln!("skipping: no extracted FrameXML");
|
||||
return;
|
||||
};
|
||||
|
||||
// Differences that are ours on purpose. Each is a *deliberate* deviation with a reason, not a
|
||||
// tolerance: the list is short and every entry names why.
|
||||
const EXPECTED: &[&str] = &[
|
||||
// The ref omits an all-zero <Offset>; we write none at all. Same anchor, fewer bytes.
|
||||
"FriendsFrameFriendButton2",
|
||||
"FriendsFrameFriendButton3",
|
||||
"FriendsFrameFriendButton4",
|
||||
"FriendsFrameFriendButton5",
|
||||
"FriendsFrameFriendButton6",
|
||||
"FriendsFrameFriendButton7",
|
||||
"FriendsFrameFriendButton8",
|
||||
"FriendsFrameFriendButton9",
|
||||
"FriendsFrameFriendButton10",
|
||||
"FriendsFrameIgnoreButton2",
|
||||
"FriendsFrameIgnoreButton3",
|
||||
"FriendsFrameIgnoreButton4",
|
||||
"FriendsFrameIgnoreButton5",
|
||||
"FriendsFrameIgnoreButton6",
|
||||
"FriendsFrameIgnoreButton7",
|
||||
"FriendsFrameIgnoreButton8",
|
||||
"FriendsFrameIgnoreButton9",
|
||||
"FriendsFrameIgnoreButton10",
|
||||
"FriendsFrameIgnoreButton11",
|
||||
"FriendsFrameIgnoreButton12",
|
||||
"FriendsFrameIgnoreButton13",
|
||||
"FriendsFrameIgnoreButton14",
|
||||
"FriendsFrameIgnoreButton15",
|
||||
"FriendsFrameIgnoreButton16",
|
||||
"FriendsFrameIgnoreButton17",
|
||||
"FriendsFrameIgnoreButton18",
|
||||
"FriendsFrameIgnoreButton19",
|
||||
"FriendsFrameIgnoreButton20",
|
||||
"WhoFrameButton2",
|
||||
"WhoFrameButton3",
|
||||
"WhoFrameButton4",
|
||||
"WhoFrameButton5",
|
||||
"WhoFrameButton6",
|
||||
"WhoFrameButton7",
|
||||
"WhoFrameButton8",
|
||||
"WhoFrameButton9",
|
||||
"WhoFrameButton10",
|
||||
"WhoFrameButton11",
|
||||
"WhoFrameButton12",
|
||||
"WhoFrameButton13",
|
||||
"WhoFrameButton14",
|
||||
"WhoFrameButton15",
|
||||
"WhoFrameButton16",
|
||||
"WhoFrameButton17",
|
||||
"FriendsFrameToggleTab2",
|
||||
"IgnoreFrameToggleTab2",
|
||||
"FriendsFrameTopLeft",
|
||||
"FriendsFrameTopRight",
|
||||
"FriendsFrameBottomLeft",
|
||||
"FriendsFrameBottomRight",
|
||||
"WhoFrameAddFriendButton",
|
||||
"WhoFrameWhoButton",
|
||||
// The ref writes an all-zero <Offset> on these two row columns; we write none.
|
||||
"FriendsFrameButtonTemplate/Info",
|
||||
"FriendsFrameWhoButtonTemplate/Variable",
|
||||
// Our column header carries the highlight's two anchors inline (the ref's sit in a
|
||||
// separate <HighlightTexture> block the scrape attributes to the same element).
|
||||
"WhoFrameColumnHeaderTemplate/Right",
|
||||
// The three faux-scroll frames: the ref decorates each with two UI-Character-ScrollBar
|
||||
// trough textures. benilla's FauxScrollFrameTemplate draws its own complete bar
|
||||
// (decisions 0247/0250/0251), so the ref's loose art would double it.
|
||||
"FriendsFrameFriendsScrollFrame",
|
||||
"FriendsFrameIgnoreScrollFrame",
|
||||
"WhoListScrollFrame",
|
||||
// …and the guild pane's, the fourth of the same kind (decision 1257).
|
||||
"GuildListScrollFrame",
|
||||
// The window's own close button predates UIPanelTemplates.xml shipping the reference's
|
||||
// `UIPanelCloseButton`, so it states inline the 32x32 that template confers. The guild
|
||||
// pane's two close buttons inherit it and therefore need no entry here.
|
||||
"FriendsFrameCloseButton",
|
||||
];
|
||||
|
||||
super::framexml_diff::assert_geometry_matches("FriendsFrame.xml", &reference, EXPECTED, 210);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,10 @@ fn harness_with(extra: &[&str]) -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
]
|
||||
.into_iter()
|
||||
.chain(extra.iter().copied())
|
||||
@@ -270,7 +274,9 @@ fn the_open_menu_takes_the_screen_and_refuses_every_other_panel() {
|
||||
// The loot window is the reference's own since 1751 — `test_ui::LOOT_UI` carries
|
||||
// what it needs and why, and PartyFrame's `MAX_PARTY_MEMBERS` is needed at LOAD.
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\UnitFrame.xml",
|
||||
@@ -394,7 +400,7 @@ fn player_camping_opens_a_counting_dialog_whose_early_close_cancels() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"20 seconds until logout",
|
||||
"20 Seconds until logout",
|
||||
"the countdown text is the engine's, from the server's 20 s clock"
|
||||
);
|
||||
// Cancel is the only button (the ref's CAMP_NOW is commented out in 1.12).
|
||||
@@ -457,7 +463,7 @@ fn player_quiting_offers_exit_now_and_logout_cancel_closes_it() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"20 seconds until exit"
|
||||
"20 Seconds until exit"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Button1:GetText()")
|
||||
@@ -618,7 +624,9 @@ fn nothing_opens_behind_the_world_map_and_escape_closes_it_first() {
|
||||
"Interface\\FrameXML\\MerchantFrame.xml",
|
||||
// The loot window is the reference's own since 1751 — see `test_ui::LOOT_UI` for what
|
||||
// each of these buys; `PartyFrame`'s MAX_PARTY_MEMBERS is needed at LOAD time.
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\UnitFrame.xml",
|
||||
|
||||
@@ -78,6 +78,9 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "GameTooltip.xml"); // PASS/NEED/GREED + item hovers
|
||||
load_xml(&s, "Cooldown.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
|
||||
@@ -552,6 +555,10 @@ fn managed_positions_engage_for_the_bare_frame_name() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
// `TOOLTIP_DEFAULT_COLOR`, which the chain's dropdown backdrops read in their OnLoad — the
|
||||
// dropdown kit rides in with the loot window now (1838), so this bespoke setup needs it too.
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
@@ -618,6 +625,8 @@ fn ctrl_and_shift_on_the_roll_icon_preview_and_post_its_link() {
|
||||
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.xml");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\FloatingChatFrame.xml");
|
||||
s.set_loot_rolls(rolls());
|
||||
|
||||
|
||||
@@ -203,39 +203,9 @@ fn setup() -> UiScript {
|
||||
..UnitState::default()
|
||||
}),
|
||||
);
|
||||
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "UnitPopup.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "FriendsFrame.xml");
|
||||
// The social window's fourth tab lives in its own file, and it is part of THIS window's
|
||||
// manifest slice now: `BENILLA_FRIENDS_SUBFRAMES` names "RaidFrame", and both
|
||||
// `FriendsFrame_ShowSubFrame` and `FriendsFrame_OnHide` resolve every name in that list
|
||||
// through `getglobal` and call `:Hide()` on it. The reference's list names it too and never
|
||||
// guards, because there RaidFrame.xml is FrameXML and always loaded — so the guard belongs in
|
||||
// the harness's load order, not in shipped Lua defending against a state the client cannot be
|
||||
// in (decision 1549).
|
||||
// Stock `RaidFrame_OnLoad` reconciles the party frames the moment it loads
|
||||
// (`RaidOptionsFrame_UpdatePartyFrames` -> `HidePartyFrame`/`ShowPartyFrame`), so this pane
|
||||
// drags in the whole unit-frame cluster — and it must be the REAL frames: loading only
|
||||
// `PartyFrame.lua` for the two names gets "attempt to index a nil value" the first time one
|
||||
// iterates. The manifest already seats these far above RaidFrame (1874).
|
||||
load_xml(&s, r"Interface\FrameXML\TextStatusBar.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\TextStatusBar.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BuffFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UnitFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\CombatFeedback.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\PartyFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\RaidFrame.xml");
|
||||
load_xml(&s, r"Interface\AddOns\Blizzard_RaidUI\Blizzard_RaidUI.xml");
|
||||
for f in super::test_ui::SOCIAL_UI {
|
||||
load_xml(&s, f);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
@@ -1436,11 +1406,13 @@ fn every_list_in_the_window_takes_the_mouse_wheel() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let s = setup();
|
||||
open(&s);
|
||||
// The reference's wheel lives on each list's FauxScrollFrameTemplate scroll frame, not on
|
||||
// the pane (1959).
|
||||
for frame in [
|
||||
"FriendsListFrame",
|
||||
"IgnoreListFrame",
|
||||
"WhoFrame",
|
||||
"GuildFrame",
|
||||
"FriendsFrameFriendsScrollFrame",
|
||||
"FriendsFrameIgnoreScrollFrame",
|
||||
"WhoListScrollFrame",
|
||||
"GuildListScrollFrame",
|
||||
] {
|
||||
assert!(
|
||||
s.eval::<bool>(&format!(
|
||||
|
||||
@@ -32,6 +32,8 @@ fn setup() -> UiScript {
|
||||
"MoneyFrame.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
// The stock file's `HelpFrame_OnShow` calls `UpdateMicroButtons()` before
|
||||
// `GetGMStatus()`, so without the micro row the OnShow raises and the status ask never
|
||||
// happens. Ours never called it. MicroMenu needs the bar's button kit under it.
|
||||
|
||||
@@ -373,6 +373,9 @@ fn shown_inspect_honor_page() -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
// `InspectUnit`'s home since 1832.
|
||||
"UIParent.xml",
|
||||
"GameTooltip.xml",
|
||||
|
||||
@@ -121,6 +121,8 @@ fn armed() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
// `InspectUnit` lives here now — the reference's own home for that name, and no longer in the
|
||||
// window's own file (decision 1832). The manifest's order, and 49 other harnesses'.
|
||||
load_xml(&s, "UIParent.xml");
|
||||
@@ -168,6 +170,8 @@ fn shipped_inspect_frame_loads_clean() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
// `InspectUnit` lives here now — the reference's own home for that name, and no longer in the
|
||||
// window's own file (decision 1832). The manifest's order, and 49 other harnesses'.
|
||||
load_xml(&s, "UIParent.xml");
|
||||
|
||||
@@ -93,9 +93,13 @@ fn the_self_menu_row_gates_on_the_binding_and_confirms_before_sending() {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua", // `TEXT`, which StaticPopup.lua and UnitPopup.lua read at file scope
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\BuffFrame.xml",
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
//! Keybindings redirect head; and the action bar's abbreviation law (`GetBindingText`
|
||||
//! transcribed in UIParent.xml) reads `s-2`, the ref's own Lua.
|
||||
//!
|
||||
//! Labels here are the RAW tokens (`BINDING_HEADER_MOVEMENT`, `BUTTON3`): the harness loads no
|
||||
//! GlobalStrings, exercising the page's `getglobal(...) or raw` fallback — the app's VM
|
||||
//! executes the real 1.12 GlobalStrings.lua at boot, which turns them into "Movement Keys" /
|
||||
//! "Middle Mouse". One test seeds a handful of the real strings to pin that path too.
|
||||
//! Labels are read the way the page reads them — `KeyBindings_String(token, raw)`, the
|
||||
//! GlobalStrings global with the raw token as fallback ([`label`]). The harness carries the
|
||||
//! real 1.12 GlobalStrings.lua since the dialog engine became the reference's file (1960; the
|
||||
//! stock StaticPopup.lua reads the strings at load), so a label here is the app's own
|
||||
//! "Movement Keys" / "Jump", never the raw token the strings-less harness used to show.
|
||||
|
||||
use benilla_ui::script::keybind::{KeybindCommand, KeybindRequest};
|
||||
use benilla_ui::script::{QuadContent, UiScript};
|
||||
@@ -48,6 +49,10 @@ pub(crate) fn harness() -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"ScrollTemplates.xml",
|
||||
@@ -74,6 +79,12 @@ pub(crate) fn harness() -> UiScript {
|
||||
s
|
||||
}
|
||||
|
||||
/// A label as the page resolves it: the GlobalStrings global named `token`, else `raw`.
|
||||
pub(crate) fn label(s: &UiScript, token: &str, raw: &str) -> String {
|
||||
s.eval::<String>(&format!(r#"return KeyBindings_String("{token}", "{raw}")"#))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Open the options window on the Keybindings page.
|
||||
pub(crate) fn on_page(s: &mut UiScript) {
|
||||
s.run(r#"ShowUIPanel(OptionsFrame); OptionsFrame_SelectCategory("Keybindings")"#)
|
||||
@@ -115,7 +126,7 @@ fn the_page_is_an_options_category_with_the_collapsed_honest_tree() {
|
||||
let text = s
|
||||
.eval::<String>(&format!("return {ROW}{}HeaderText:GetText()", i + 1))
|
||||
.unwrap();
|
||||
assert_eq!(&text, token, "section {} (raw-token fallback)", i + 1);
|
||||
assert_eq!(text, label(&s, token, token), "section {}", i + 1);
|
||||
}
|
||||
assert!(
|
||||
!s.eval::<bool>(&format!("return {ROW}{}:IsVisible()", expected.len() + 1))
|
||||
@@ -129,14 +140,14 @@ fn the_page_is_an_options_category_with_the_collapsed_honest_tree() {
|
||||
assert_eq!(
|
||||
s.eval::<String>(&format!("return {ROW}2Description:GetText()"))
|
||||
.unwrap(),
|
||||
"MOVEANDSTEER"
|
||||
label(&s, "BINDING_NAME_MOVEANDSTEER", "MOVEANDSTEER")
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>(&format!("return {ROW}2Key1ButtonText:GetText()"))
|
||||
.unwrap(),
|
||||
"BUTTON3"
|
||||
label(&s, "KEY_BUTTON3", "BUTTON3")
|
||||
);
|
||||
// With the real strings present (the app's GlobalStrings), the same rows read 1.12 text.
|
||||
// The same rows with the strings pinned by hand, so the expectation is literal 1.12 text.
|
||||
s.run(
|
||||
r#"BINDING_HEADER_MOVEMENT = "Movement Keys"
|
||||
BINDING_NAME_MOVEANDSTEER = "Move and Steer"
|
||||
@@ -164,7 +175,7 @@ fn the_page_is_an_options_category_with_the_collapsed_honest_tree() {
|
||||
assert_eq!(
|
||||
s.eval::<String>(&format!("return {ROW}2HeaderText:GetText()"))
|
||||
.unwrap(),
|
||||
"BINDING_HEADER_CHAT"
|
||||
label(&s, "BINDING_HEADER_CHAT", "BINDING_HEADER_CHAT")
|
||||
);
|
||||
// Leaving the page hides its body and the Unbind button.
|
||||
s.run(r#"OptionsFrame_SelectCategory("Controls")"#).unwrap();
|
||||
@@ -228,10 +239,11 @@ fn the_capture_flow_binds_steals_and_refuses_like_112() {
|
||||
s.eval::<String>(r#"return GetBindingAction("T")"#).unwrap(),
|
||||
"MOVEFORWARD"
|
||||
);
|
||||
let victim = label(&s, "BINDING_NAME_ATTACKTARGET", "ATTACKTARGET");
|
||||
assert!(
|
||||
s.eval::<String>("return OptionsFrameContainerBodyKeybindingsOutput:GetText()")
|
||||
.unwrap()
|
||||
.contains("ATTACKTARGET"),
|
||||
.contains(&victim),
|
||||
"the newly-bare victim is named"
|
||||
);
|
||||
// **The wheel binds like any other key** (B265, decision 1295) — including onto MOVEFORWARD,
|
||||
@@ -250,7 +262,10 @@ fn the_capture_flow_binds_steals_and_refuses_like_112() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return OptionsFrameContainerBodyKeybindingsOutput:GetText()")
|
||||
.unwrap(),
|
||||
"|cffff0000CAMERAZOOMIN Function is Now Unbound!|r"
|
||||
format!(
|
||||
"|cffff0000{} Function is Now Unbound!|r",
|
||||
label(&s, "BINDING_NAME_CAMERAZOOMIN", "CAMERAZOOMIN")
|
||||
)
|
||||
);
|
||||
// The refusal that IS there is the key-string validator, and this is the page arm that
|
||||
// reports it: a chord the engine will not take restores the slot's old key and says why
|
||||
@@ -293,7 +308,7 @@ fn unbind_reset_and_the_live_commit_replace_okay_cancel() {
|
||||
assert_eq!(
|
||||
s.eval::<String>(&format!("return {ROW}9Description:GetText()"))
|
||||
.unwrap(),
|
||||
"JUMP"
|
||||
label(&s, "BINDING_NAME_JUMP", "JUMP")
|
||||
);
|
||||
s.run(&format!("{ROW}9Key1Button:Click()")).unwrap();
|
||||
s.run("OptionsFrameContainerUnbind:Click()").unwrap();
|
||||
@@ -593,11 +608,12 @@ fn the_wheel_bubbles_from_the_rows_and_the_bar_rides_the_gutter() {
|
||||
s.resolve();
|
||||
|
||||
// A spin over a row NAME — the dead zone when the handler lived on the sibling.
|
||||
let steer = label(&s, "BINDING_NAME_MOVEANDSTEER", "MOVEANDSTEER");
|
||||
let quads = s.extract();
|
||||
let (wx, wy) = quads
|
||||
.iter()
|
||||
.find_map(|q| match &q.content {
|
||||
QuadContent::Text { text: Some(t), .. } if t == "MOVEANDSTEER" => q
|
||||
QuadContent::Text { text: Some(t), .. } if *t == steer => q
|
||||
.rect
|
||||
.map(|r| ((r.left + r.right) * 0.5, (r.bottom + r.top) * 0.5)),
|
||||
_ => None,
|
||||
@@ -706,7 +722,10 @@ fn the_pet_lane_is_registered_under_the_action_bar_header() {
|
||||
);
|
||||
|
||||
// Page side: search finds it and paints a live row with the capsule filled.
|
||||
s.run(r#"OptionsFrameSearchBox:SetText("bonusactionbutton1")"#)
|
||||
// The search tags are the DISPLAY names uppercased (era AddSearchTags), so the query is the
|
||||
// label the app's strings give the row, not its token.
|
||||
let query = label(&s, "BINDING_NAME_BONUSACTIONBUTTON1", "BONUSACTIONBUTTON1").to_lowercase();
|
||||
s.run(&format!(r#"OptionsFrameSearchBox:SetText("{query}")"#))
|
||||
.unwrap();
|
||||
s.tick(0.0); // the deferred OnTextChanged drains here (decision 1831)
|
||||
assert!(s
|
||||
@@ -715,8 +734,8 @@ fn the_pet_lane_is_registered_under_the_action_bar_header() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return OptionsFrameContainerBodyKeybindSearch1Description:GetText()")
|
||||
.unwrap(),
|
||||
"BONUSACTIONBUTTON1",
|
||||
"the raw-token fallback — the app's GlobalStrings read 'Secondary Action Button 1'"
|
||||
label(&s, "BINDING_NAME_BONUSACTIONBUTTON1", "BONUSACTIONBUTTON1"),
|
||||
"the row wears the app's own string"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return OptionsFrameContainerBodyKeybindSearch1Key1ButtonText:GetText()")
|
||||
|
||||
@@ -620,6 +620,8 @@ fn ctrl_and_shift_on_a_loot_row_preview_and_post_without_looting() {
|
||||
"Interface\\FrameXML\\UIPanelTemplates.lua",
|
||||
"Interface\\FrameXML\\UIPanelTemplates.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\FloatingChatFrame.xml",
|
||||
] {
|
||||
load_xml(&s, file);
|
||||
|
||||
@@ -93,6 +93,8 @@ fn harness_with(player: &str) -> UiScript {
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`
|
||||
"MoneyFrame.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
// The chain's `PanelTemplates_SelectTab` reaches for `GameTooltip` unguarded.
|
||||
"GameTooltip.xml",
|
||||
"UIParent.xml", // `ShowMacroFrame` lives here now
|
||||
|
||||
@@ -183,6 +183,26 @@ pub(crate) fn load_default_ui(script: &UiScript) -> Vec<String> {
|
||||
/// chain document means `Interface\FrameXML\ContainerFrame.xml`'s `<Script
|
||||
/// file="ContainerFrame.lua"/>` reaches `Interface\FrameXML\ContainerFrame.lua` without anything
|
||||
/// here knowing about it.
|
||||
/// The Blizzard addons the manifest lists off the chain (`Interface\AddOns\<Name>\…` rows), by
|
||||
/// name, in first-appearance order — the eager trio the InspectUI header describes, which the
|
||||
/// registry must not also carry as LoadOnDemand rows (`addons::chain_addons`, 1957).
|
||||
pub(crate) fn chain_addons(files: &[String]) -> Vec<String> {
|
||||
let mut out: Vec<String> = Vec::new();
|
||||
for file in files {
|
||||
let norm = file.replace('/', "\\");
|
||||
let Some(rest) = norm.strip_prefix("Interface\\AddOns\\") else {
|
||||
continue;
|
||||
};
|
||||
let Some((name, _)) = rest.split_once('\\') else {
|
||||
continue;
|
||||
};
|
||||
if !out.iter().any(|n| n == name) {
|
||||
out.push(name.to_string());
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn load_manifest(script: &UiScript, files: &[String]) -> Vec<String> {
|
||||
let builtin = Addon::builtin();
|
||||
let reference = reference_ui::addon(
|
||||
|
||||
@@ -1147,6 +1147,8 @@ fn ctrl_and_shift_on_a_vendor_row_preview_and_post_without_buying() {
|
||||
"Interface\\FrameXML\\UIPanelTemplates.lua",
|
||||
"Interface\\FrameXML\\UIPanelTemplates.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\FloatingChatFrame.xml",
|
||||
] {
|
||||
load_xml(&s, file);
|
||||
|
||||
@@ -27,6 +27,10 @@ fn harness() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MirrorTimer.xml");
|
||||
s
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ fn load_action_bar(s: &UiScript) {
|
||||
// MultiActionBars.xml l.39), and the manifest's since 1938.
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UiPanels.xml", // StaticPopupDialogs, which the options window's pages register into
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"ScrollTemplates.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
"OptionsFrame.xml",
|
||||
@@ -284,6 +287,10 @@ fn shipped_stance_bar_drives_end_to_end() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -483,6 +490,9 @@ fn multibar_hover_renders_the_buttons_own_action() {
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
"OptionsFrame.xml",
|
||||
"Interface\\FrameXML\\MultiActionBars.xml",
|
||||
@@ -584,6 +594,10 @@ fn the_vertical_multibars_exist_hidden_on_the_reference_pages() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -646,6 +660,10 @@ fn every_extra_bar_stays_down_until_its_own_toggle_is_set() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -733,6 +751,10 @@ fn raising_a_bottom_bar_moves_the_managed_bottom_stack() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -797,6 +819,10 @@ fn viewable_action_bar_pages_follow_the_bar_toggles() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -863,6 +889,10 @@ fn the_grid_option_holds_the_extra_bars_empty_wells_open() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -966,6 +996,10 @@ fn a_held_payload_ghosts_the_empty_wells_it_opens() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -1109,6 +1143,10 @@ fn a_bar_toggle_sends_the_byte_its_globals_pack_to() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -1196,6 +1234,10 @@ fn the_shipped_setter_passes_exactly_four_arguments() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -1248,6 +1290,10 @@ fn the_stance_bar_sits_where_the_pass_puts_it() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -1320,6 +1366,10 @@ fn the_stance_shelf_follows_the_bottom_left_bar() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -1441,6 +1491,10 @@ fn the_stance_shelf_is_as_long_as_the_form_count() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
@@ -1558,6 +1612,10 @@ fn an_extra_bars_empty_well_keeps_its_bound_hotkey_label() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "KeyBindingsPage.xml");
|
||||
load_xml(&s, "OptionsFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MultiActionBars.xml");
|
||||
|
||||
@@ -45,6 +45,10 @@ fn harness_on(mut s: UiScript) -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"ScrollTemplates.xml", // the Keybindings page's faux-scroll kit
|
||||
@@ -722,6 +726,9 @@ fn interface_harness() -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"UIParent.xml",
|
||||
// The target-of-target pair's definer (1576) and the three files ahead of it, all in
|
||||
// their manifest seats. The chain is a real load-ORDER requirement rather than
|
||||
@@ -732,7 +739,8 @@ fn interface_harness() -> UiScript {
|
||||
// loader takes it.
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\BuffFrame.xml",
|
||||
@@ -792,6 +800,10 @@ fn chat_harness() -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"UIParent.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
@@ -844,6 +856,9 @@ fn actionbars_harness() -> UiScript {
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
"OptionsFrame.xml",
|
||||
"Interface\\FrameXML\\MultiActionBars.xml",
|
||||
|
||||
@@ -51,6 +51,10 @@ fn harness() -> UiScript {
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
r"Interface\FrameXML\OptionsFrameTemplates.xml",
|
||||
"OptionsFrameTemplates.xml",
|
||||
] {
|
||||
|
||||
@@ -56,6 +56,11 @@ fn shipped_gossip_frame_drives_end_to_end() {
|
||||
// list passes load_xml and then loses the scrollbar silently.
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
// The window + its scroll frame (bar + child) + the 32-row shared pool (quest rows and option
|
||||
// rows both draw from it, decision 0088 §3 — the reference's own NUMGOSSIPBUTTONS) + the close
|
||||
// button + the GOODBYE button. The greeting and the NPC-name banner are FontString layers (the
|
||||
@@ -256,6 +261,11 @@ fn shipped_gossip_frame_renders_quest_rows_above_options() {
|
||||
// list passes load_xml and then loses the scrollbar silently.
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
|
||||
|
||||
s.set_gossip(Some(GossipMenu {
|
||||
@@ -414,6 +424,11 @@ fn shipped_gossip_rows_grow_to_their_wrapped_labels() {
|
||||
// list passes load_xml and then loses the scrollbar silently.
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
|
||||
|
||||
// Three long options — the shape of a real judgement/roleplay menu, every one of them wrapping
|
||||
@@ -527,6 +542,11 @@ fn gossip_show_hide_plays_open_and_close_kits() {
|
||||
// list passes load_xml and then loses the scrollbar silently.
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
|
||||
|
||||
// Hidden at load: no open sound (never transitions on startup).
|
||||
@@ -570,6 +590,11 @@ fn shipped_panel_slot_replaces_gossip_with_merchant() {
|
||||
// list passes load_xml and then loses the scrollbar silently.
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
|
||||
load_xml(&s, "GameTooltip.xml"); // app load order: tooltip before merchant
|
||||
// The vendor window is the reference's own since 1751, and its `MerchantFrame_UpdateMerchantInfo`
|
||||
@@ -664,6 +689,11 @@ fn displacing_an_npc_window_ends_the_displaced_session() {
|
||||
// list passes load_xml and then loses the scrollbar silently.
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
|
||||
load_xml(&s, "GameTooltip.xml"); // app load order: tooltip before merchant
|
||||
// The vendor window is the reference's own since 1751, and its `MerchantFrame_UpdateMerchantInfo`
|
||||
@@ -718,6 +748,11 @@ fn shipped_panel_slot_pushable_promotes_to_center() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "GameTooltip.xml"); // app load order: tooltip before merchant
|
||||
// The vendor window is the reference's own since 1751, and its `MerchantFrame_UpdateMerchantInfo`
|
||||
// calls `TEXT()` while building every row — see `test_ui::MERCHANT_UI` for the rest.
|
||||
@@ -821,6 +856,11 @@ fn gossip_bank_option_hands_the_left_slot_to_the_bank() {
|
||||
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); // the reference bank's slot buttons inherit it
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Cooldown.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
@@ -907,6 +947,11 @@ fn an_overflowing_gossip_menu_scrolls_instead_of_spilling() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml"); // UIPanelScrollFrameTemplate — see the note above
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
|
||||
|
||||
// Eight wrapping options: ~4 lines each, far past the 334 px scroll frame.
|
||||
@@ -1063,6 +1108,11 @@ fn an_addons_own_frame_registered_in_uipanelwindows_takes_the_left_slot() {
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml"); // UIPanelScrollFrameTemplate — see the note above
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
|
||||
|
||||
// The addon's three lines, in the order an addon writes them.
|
||||
@@ -1138,6 +1188,11 @@ fn the_1507_registry_rows_match_the_reference_bytes() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
for probe in [
|
||||
// ItemTextFrame — UIParent.lua l.20 (the B288 row).
|
||||
"UIPanelWindows['ItemTextFrame'].area == 'left'",
|
||||
@@ -1177,6 +1232,11 @@ fn a_dead_player_opens_only_whiledead_windows() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s.set_unit(
|
||||
"player",
|
||||
Some(benilla_ui::script::UnitState {
|
||||
@@ -1245,6 +1305,11 @@ fn a_frame_arriving_at_center_puts_the_child_windows_away() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
|
||||
// The letter is open; two shipped-row stand-ins take the seats: MerchantFrame (pushable 0)
|
||||
// holds left, TradeFrame (pushable 1) then ARRIVES at center (UIParent.lua l.734-741's
|
||||
|
||||
@@ -35,6 +35,8 @@ pub(super) fn load_pet_bar(s: &UiScript) {
|
||||
r"Interface\FrameXML\OptionsFrameTemplates.xml",
|
||||
r"Interface\FrameXML\ReputationFrame.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"ScrollTemplates.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
|
||||
@@ -31,7 +31,8 @@ fn load_pet_frame() -> UiScript {
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
load_xml(&s, "UnitPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UnitPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.lua");
|
||||
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BuffFrame.xml");
|
||||
|
||||
@@ -96,6 +96,8 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
// `QuestTitleButtonTemplate`, which the reference's registrar inherits for its two service
|
||||
// rows — 1.12 declares it in QuestFrameTemplates.xml, an `<Include>` of QuestFrame.xml, and
|
||||
// ours declares it in QuestFrame.xml directly. An unknown template is a loader WARNING, so
|
||||
|
||||
@@ -18,7 +18,11 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "QuestShareFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ fn questgiver_show_hide_plays_open_and_close_kits() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
// The BenillaMoney_* purse helpers the quest reward/progress panels repaint through live in
|
||||
// MerchantFrame.xml (the same documented cross-window dep the bag tests load).
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
@@ -91,6 +94,9 @@ fn panel_events_show_exactly_one_child_panel_and_hide_the_others() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -186,6 +192,9 @@ fn detail_panel_reward_grid_follows_the_refs_two_per_row_layout() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -285,6 +294,9 @@ fn reward_panel_choice_click_selects_and_completes_with_zero_based_index() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -361,6 +373,9 @@ fn greeting_goodbye_button_closes_the_window() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -415,6 +430,9 @@ fn detail_panel_action_buttons_resolve_to_real_onscreen_rects() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -540,6 +558,9 @@ fn write_on_still_fades_when_instant_text_is_off() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -614,6 +635,9 @@ fn npc_name_reaches_the_title_bar_on_open_and_on_refresh() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -694,6 +718,9 @@ fn greeting_panel_title_rows_grow_to_their_wrapped_titles() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -791,6 +818,9 @@ fn reward_rows_preview_and_post_without_selecting_the_choice() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
|
||||
@@ -36,6 +36,9 @@ fn harness() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
|
||||
|
||||
@@ -91,6 +91,9 @@ fn shipped_questlog_frame_loads_clean() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -121,6 +124,9 @@ fn shipped_questlog_frame_drives_end_to_end() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -327,6 +333,9 @@ fn shift_click_toggles_the_watch_checkbox_and_the_tracker_hud() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -471,6 +480,9 @@ fn watch_guards_no_op_without_erroring() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml"); // the guards' red-line surface
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
@@ -584,6 +596,9 @@ fn progress_auto_watches_for_five_minutes() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -665,6 +680,9 @@ fn the_auto_watch_flag_is_the_references_uvar_and_gates_the_watch() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
// The flag is declared by the options window's init since 1944, as the reference declares it
|
||||
// in UIOptionsFrame_Init — so the window that owns it loads first, as in the manifest.
|
||||
load_xml(&s, "UIParent.xml");
|
||||
@@ -727,6 +745,9 @@ fn the_row_tag_is_its_own_right_flush_string_and_the_state_word_wins() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -802,6 +823,9 @@ fn empty_quest_log_hides_rows_and_disables_abandon() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -863,6 +887,9 @@ fn reward_rows_follow_the_refs_two_per_row_layout() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -1048,6 +1075,9 @@ fn overflowing_detail_content_clips_to_the_scrollframe_rect() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -1119,6 +1149,9 @@ fn wheel_over_the_detail_pane_changes_vertical_scroll() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -1180,6 +1213,9 @@ fn selection_change_resets_detail_scroll_but_a_quest_log_update_refresh_does_not
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -1253,6 +1289,9 @@ fn reward_row_hover_serves_the_shared_item_tooltip() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
// This used to load LootFrame.xml for `BENILLA_LOOT_QUALITY_COLORS`, an alias our own copy of
|
||||
// that window set to `ITEM_QUALITY_COLORS`. 1751 retired the window and the alias with it, so
|
||||
// Fonts.xml alone is the source now. Formerly: it
|
||||
@@ -1351,6 +1390,10 @@ fn popup_children_inherit_the_dialog_stratum() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
s.run(
|
||||
"StaticPopupDialogs[\"TEST_STRATUM\"] = { text = \"Abandon?\", button1 = \"Yes\", \
|
||||
button2 = \"No\", timeout = 0 }\n\
|
||||
@@ -1404,6 +1447,9 @@ fn reward_rows_preview_and_post_and_a_plain_click_stays_inert() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -1499,6 +1545,9 @@ fn shift_click_on_a_title_posts_the_quest_name_with_chat_open_and_watches_with_i
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -1605,6 +1654,9 @@ fn share_quest_needs_both_a_sharable_selection_and_a_party() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -1688,6 +1740,9 @@ fn share_quest_is_dark_on_an_empty_log_even_in_a_party() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
@@ -1725,6 +1780,9 @@ fn share_quest_click_queues_the_selected_quests_id() {
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
|
||||
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
|
||||
|
||||
@@ -24,37 +24,9 @@ use super::test_ui::load_ui_strict as load_xml;
|
||||
fn setup() -> UiScript {
|
||||
let mut s = UiScript::new().unwrap();
|
||||
s.set_screen_size(1024.0, 768.0);
|
||||
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
load_xml(&s, "UnitPopup.xml");
|
||||
load_xml(&s, "ScrollTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "FriendsFrame.xml");
|
||||
// Stock `RaidFrame_OnLoad` reconciles the party frames the moment it loads
|
||||
// (`RaidOptionsFrame_UpdatePartyFrames` -> `HidePartyFrame`/`ShowPartyFrame`), so this pane
|
||||
// drags in the whole unit-frame cluster — and it must be the REAL frames: loading only
|
||||
// `PartyFrame.lua` for the two names gets "attempt to index a nil value" the first time one
|
||||
// iterates. The manifest already seats these far above RaidFrame (1874).
|
||||
// The reference's own `BasicControls.xml`, which is manifest entry 3 — far above the pane
|
||||
// (1874). `UIParentLoadAddOn` used to be what this line was here for; 1881 moved that
|
||||
// function to `UIParent.xml`, its home in the reference, and this harness already loads
|
||||
// `UIParent.xml` above, so the `RaidFrame_LoadUI` arm on `RAID_ROSTER_UPDATE` still
|
||||
// resolves. What is left here is the error/message pair and `TEXT`.
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\TextStatusBar.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\TextStatusBar.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BuffFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UnitFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\CombatFeedback.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\PartyFrame.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\RaidFrame.xml");
|
||||
load_xml(&s, r"Interface\AddOns\Blizzard_RaidUI\Blizzard_RaidUI.xml");
|
||||
for f in super::test_ui::SOCIAL_UI {
|
||||
load_xml(&s, f);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
|
||||
@@ -1471,6 +1471,16 @@ mod tests {
|
||||
// reads clean. Each belongs to whichever window's migration left it, and each is one
|
||||
// binding or one sourced file away.
|
||||
const KNOWN: &[(&str, &str, &str)] = &[
|
||||
(
|
||||
"ClassTrainerFrameTemplates.xml",
|
||||
"ClassTrainerSkillButton_OnClick",
|
||||
"defined by `Blizzard_TrainerUI`, which is a LoadOnDemand addon here as it is in \
|
||||
the reference (1957): it loads on the first trainer, through UIParent's \
|
||||
TRAINER_SHOW arm, and the skill-button template that carries this handler is \
|
||||
instantiated only by that addon, so no click can reach the name before its \
|
||||
definer exists. The reference is in exactly this state until its addon loads. \
|
||||
Permanent by design, not a gap to close.",
|
||||
),
|
||||
(
|
||||
"ContainerFrame.xml",
|
||||
"KeyRingButtonIDToInvSlotID",
|
||||
@@ -1506,16 +1516,6 @@ mod tests {
|
||||
step/rank cost is non-zero — which no 1.12 server sends. Unreachable until the \
|
||||
skill-point wire exists; not built (1956).",
|
||||
),
|
||||
(
|
||||
"ClassTrainerFrameTemplates.xml",
|
||||
"ClassTrainerSkillButton_OnClick",
|
||||
"defined by `Blizzard_TrainerUI`, a LoadOnDemand addon we do not load yet. The \
|
||||
file is on the manifest for ONE of its templates — the icon chooser's \
|
||||
`ClassTrainerListScrollFrameTemplate` (1862) — and the skill-button template that \
|
||||
carries this handler is never instantiated, so no click can reach it. The \
|
||||
reference is in the same state until its trainer addon loads on demand. It \
|
||||
resolves when that window migrates.",
|
||||
),
|
||||
(
|
||||
"DurabilityFrame.xml",
|
||||
"UpdateInventoryAlertStatus",
|
||||
@@ -1524,11 +1524,70 @@ mod tests {
|
||||
instead, so the recompute exists and only the Lua verb that forces one does not.",
|
||||
),
|
||||
(
|
||||
"ChatFrame.xml",
|
||||
"value",
|
||||
"not a global: `for index, value in SlashCmdList do … value(msg)` \
|
||||
(ChatFrame.lua l.2168-2171) calls the addon's handler through the table's loop \
|
||||
variable. The scan has no scopes, so the name reads as a call.",
|
||||
"StaticPopup.xml",
|
||||
"AcceptAreaSpiritHeal",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by AREA_SPIRIT_HEAL's Accept, an event this engine does not fire yet.",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"CancelAreaSpiritHeal",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by AREA_SPIRIT_HEAL's Cancel, an event this engine does not fire yet.",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"GetAreaSpiritHealerTime",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by AREA_SPIRIT_HEAL's OnShow, an event this engine does not fire yet.",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"AcceptBattlefieldPort",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by CONFIRM_BATTLEFIELD_ENTRY / CONFIRM_LEAVE_QUEUE, raised only by BattlefieldFrame.lua, which is not on the chain yet.",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"BeginTrade",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by the TRADE dialog, which 1.12.1 can never show (wow-re `incoming-trade-request-law.md`: TRADE_REQUEST is signalled by nothing).",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"CancelTrade",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by the TRADE dialog, which 1.12.1 can never show (wow-re `incoming-trade-request-law.md`: TRADE_REQUEST is signalled by nothing).",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"ReplaceTradeEnchant",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by TRADE_REPLACE_ENCHANT's Accept, an event this engine does not fire yet.",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"CancelMeetingStoneRequest",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by CONFIRM_LEAVE_QUEUE's meeting-stone arm, raised only by BattlefieldFrame.lua / the meeting-stone gossip, neither on the chain yet.",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"CheckPetUntrainerDist",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by CONFIRM_PET_UNLEARN's OnUpdate, an event this engine does not fire yet.",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"ConfirmPetUnlearn",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by CONFIRM_PET_UNLEARN's Accept, an event this engine does not fire yet.",
|
||||
),
|
||||
(
|
||||
"StaticPopup.xml",
|
||||
"GetInstanceBootTimeRemaining",
|
||||
"a registered 1.12 binding whose body is uncarved (wow-re `bindings.md`, structural row only); a \
|
||||
wow-re orchestrator is out on it and it is built when the carve lands (1960). Reached by INSTANCE_BOOT's OnShow, an event this engine does not fire yet.",
|
||||
),
|
||||
];
|
||||
|
||||
@@ -1571,6 +1630,37 @@ mod tests {
|
||||
// are not are the ones a stat tooltip is built out of: `strupper`, `strsub`, `abs`,
|
||||
// `max`, `floor`, `format`, `getglobal`. `reference/1.12-globals.tsv` is the filter
|
||||
// that actually belongs here, and it does not care about case.
|
||||
// Names the file binds LOCALLY — `local X`, `local function X`, a `for` loop's
|
||||
// variables — are not globals however they are called: the stock StaticPopup.lua
|
||||
// reads a dialog's handlers into locals (`local OnAccept = …; OnAccept(…)`) and
|
||||
// ChatFrame.lua walks `SlashCmdList` with `for index, value in …; value(msg)`.
|
||||
let mut locals: std::collections::HashSet<String> = std::collections::HashSet::new();
|
||||
for line in text.lines() {
|
||||
let l = line.trim_start();
|
||||
let rest = if let Some(r) = l.strip_prefix("local function ") {
|
||||
Some(r)
|
||||
} else if let Some(r) = l.strip_prefix("local ") {
|
||||
Some(r)
|
||||
} else {
|
||||
l.strip_prefix("for ")
|
||||
};
|
||||
if let Some(rest) = rest {
|
||||
for name in rest
|
||||
.split(['=', ' ', '\t'])
|
||||
.take_while(|w| *w != "in" && *w != "=" && !w.starts_with('('))
|
||||
.flat_map(|w| w.split(','))
|
||||
.map(|w| w.trim())
|
||||
.filter(|w| !w.is_empty())
|
||||
{
|
||||
let name: String =
|
||||
name.chars().take_while(|c| super::is_word(*c)).collect();
|
||||
if !name.is_empty() {
|
||||
locals.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let b: Vec<char> = text.chars().collect();
|
||||
let mut called: std::collections::HashSet<String> = std::collections::HashSet::new();
|
||||
let mut i = 0;
|
||||
@@ -1599,6 +1689,7 @@ mod tests {
|
||||
let mut gaps: Vec<&String> = called
|
||||
.iter()
|
||||
.filter(|n| !defines.contains(*n))
|
||||
.filter(|n| !locals.contains(*n))
|
||||
.filter(|n| reference.contains(n.as_str()))
|
||||
.filter(|n| !have.contains(*n))
|
||||
.collect();
|
||||
|
||||
@@ -19,6 +19,10 @@ fn harness() -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"UIParent.xml",
|
||||
"ScreenshotStatus.xml",
|
||||
] {
|
||||
|
||||
@@ -106,6 +106,8 @@ pub(super) fn spellbook_ui(w: f32, h: f32) -> UiScript {
|
||||
r"Interface\FrameXML\OptionsFrameTemplates.xml",
|
||||
r"Interface\FrameXML\ReputationFrame.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"ScrollTemplates.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
@@ -131,6 +133,10 @@ fn shipped_spellbook_loads_clean() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
// The reference's own file, off the chain, with the one adapter it needs from this engine.
|
||||
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
|
||||
@@ -679,6 +685,8 @@ fn the_macro_editor_takes_a_shift_click_and_only_a_shift_click() {
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`
|
||||
"MoneyFrame.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
// `ShowMacroFrame` lives here since 1848.
|
||||
"UIParent.xml",
|
||||
"GameTooltip.xml",
|
||||
|
||||
@@ -15,6 +15,10 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
s
|
||||
}
|
||||
|
||||
@@ -78,7 +82,7 @@ fn start_delay_gates_button1_then_swaps_the_text_in() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"2 seconds until resurrection",
|
||||
"2 Seconds until resurrection",
|
||||
"the delayText countdown renders (ceil of 1.5s)"
|
||||
);
|
||||
s.tick(1.6);
|
||||
@@ -181,14 +185,14 @@ fn the_death_countdown_text_rerenders_each_tick() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"2 minutes until release",
|
||||
"2 Minutes until release",
|
||||
"above 60s renders ceil-minutes"
|
||||
);
|
||||
s.tick(31.0);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"59 seconds until release",
|
||||
"59 Seconds until release",
|
||||
"below 60s renders seconds"
|
||||
);
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
|
||||
@@ -31,7 +31,11 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "ConfirmSummon.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s.set_summon_confirm(SummonConfirmUiState {
|
||||
summoner: "Twomage".into(),
|
||||
area: "Stormwind City".into(),
|
||||
@@ -66,7 +70,7 @@ fn the_confirm_names_the_summoner_and_accept_queues_the_response() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"Twomage wants to summon you to Stormwind City. The spell will be cancelled in 2 minutes.",
|
||||
"Twomage wants to summon you to Stormwind City. The spell will be cancelled in 2 Minutes.",
|
||||
"the tick composes summoner + area + the count and its unit word"
|
||||
);
|
||||
|
||||
@@ -93,7 +97,7 @@ fn the_countdown_line_switches_to_seconds_and_singularises() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"Twomage wants to summon you to Elwynn Forest. The spell will be cancelled in 45 seconds."
|
||||
"Twomage wants to summon you to Elwynn Forest. The spell will be cancelled in 45 Seconds."
|
||||
);
|
||||
|
||||
// OnShow seeded 45 and the first tick spent 0.1 of it, so 44.9 stands; spending 44.2 more
|
||||
@@ -103,7 +107,7 @@ fn the_countdown_line_switches_to_seconds_and_singularises() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"Twomage wants to summon you to Elwynn Forest. The spell will be cancelled in 1 second."
|
||||
"Twomage wants to summon you to Elwynn Forest. The spell will be cancelled in 1 Second."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -124,7 +128,7 @@ fn a_summoner_whose_name_is_still_resolving_fills_in_on_a_later_tick() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
" wants to summon you to Stormwind City. The spell will be cancelled in 30 seconds.",
|
||||
" wants to summon you to Stormwind City. The spell will be cancelled in 30 Seconds.",
|
||||
"no name yet: a blank, not a raise and not a withheld dialog"
|
||||
);
|
||||
|
||||
@@ -137,7 +141,7 @@ fn a_summoner_whose_name_is_still_resolving_fills_in_on_a_later_tick() {
|
||||
assert_eq!(
|
||||
s.eval::<String>("return StaticPopup1Text:GetText()")
|
||||
.unwrap(),
|
||||
"Twomage wants to summon you to Stormwind City. The spell will be cancelled in 30 seconds.",
|
||||
"Twomage wants to summon you to Stormwind City. The spell will be cancelled in 30 Seconds.",
|
||||
"the name query landed; the same open dialog picks it up"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@ fn setup() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "TalentWipeConfirm.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
s.set_talent_master_pending(true);
|
||||
s
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ fn harness() -> UiScript {
|
||||
load_xml(&s, "Interface\\FrameXML\\BonusActionBarFrame.xml"); // BENILLA_FALLBACK_ICON
|
||||
// Before UnitPopup: that file reads ITEM_QUALITY_COLORS at FILE SCOPE, and its
|
||||
// declarer is UIParent (ref UIParent.lua:65) since 1888.
|
||||
load_xml(&s, "UnitPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UnitPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.lua");
|
||||
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BuffFrame.xml");
|
||||
|
||||
@@ -18,6 +18,9 @@ fn taxi_script() -> UiScript {
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "GameTooltip.xml"); // TaxiNodeOnButtonEnter's tooltip + SetTooltipMoney
|
||||
load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml"); // BenillaErrorsFrame_AddMessage — DrawOneHopLines' refusal
|
||||
// Three the reference's own TaxiFrame leans on that our transcription did not:
|
||||
|
||||
@@ -149,6 +149,8 @@ pub(super) const MERCHANT_UI: &[&str] = &[
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml", // app load order: tooltip before merchant
|
||||
];
|
||||
|
||||
@@ -160,6 +162,9 @@ pub(super) const LOOT_UI: &[&str] = &[
|
||||
"UiPanels.xml", // StaticPopup, and the LOOT_BIND / CONFIRM_LOOT_DISTRIBUTION dialogs
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml", // TOOLTIP_DEFAULT_COLOR, read by the dropdown backdrop
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml", // GroupLootDropDown's OnLoad calls UIDropDownMenu_Initialize
|
||||
// `UnitPopup.xml` reads ITEM_QUALITY_COLORS at FILE SCOPE for its three loot-threshold rows,
|
||||
@@ -167,7 +172,8 @@ pub(super) const LOOT_UI: &[&str] = &[
|
||||
// That declarer is UIParent (ref UIParent.lua:65); 1888 moved the table there when Fonts.xml
|
||||
// went on the chain, because the reference's Fonts.xml does not declare it.
|
||||
"UIParent.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
// …and what its rows' OnLoad calls: every `PartyMemberFrame<N>` and its pet frame runs
|
||||
// `UnitFrame_Initialize`, which lives in UnitFrame.lua and itself calls
|
||||
// `SetTextStatusBarText` out of TextStatusBar.lua. Naming PartyFrame without these loads
|
||||
@@ -238,12 +244,13 @@ pub(super) const CHARACTER_UI: &[&str] = &[
|
||||
"Cooldown.xml", // CooldownFrameTemplate + CooldownFrame_SetTimer, per equipment slot
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
// The unit frames' four right-click dropdowns call `UIDropDownMenu_Initialize` at LOAD, so the
|
||||
// kit and the menu table it initialises from both precede them — the manifest's own order
|
||||
// (175 → 189 → 193 → 263).
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"Interface\\FrameXML\\UIMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
// `UnitFrame_Initialize` and `CombatFeedback_Initialize`, which the two windows below call in
|
||||
@@ -288,6 +295,52 @@ pub(super) const CHARACTER_UI: &[&str] = &[
|
||||
"Interface\\FrameXML\\HonorFrame.xml",
|
||||
];
|
||||
|
||||
/// The social window's slice of the manifest (1959): everything the reference's
|
||||
/// `FriendsFrame.xml` + `RaidFrame.xml` reach at load or on show — `TEXT` and `GetText`, the
|
||||
/// bar chain under `UpdateMicroButtons`, the chat window whose edit box `FriendsFrame_SendMessage`
|
||||
/// opens, the unit menu, the party frames `RaidFrame_OnLoad` reconciles, and the raid tab's
|
||||
/// LoadOnDemand addon — in the manifest's own order. Shared by the friends, guild and raid
|
||||
/// harnesses.
|
||||
pub(super) const SOCIAL_UI: &[&str] = &[
|
||||
"Interface\\FrameXML\\Fonts.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"UIParent.xml",
|
||||
"Cooldown.xml",
|
||||
"Interface\\FrameXML\\ActionButtonTemplate.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\MainMenuBar.xml",
|
||||
"MoneyFrame.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\ActionBarFrame.xml",
|
||||
"Interface\\FrameXML\\BonusActionBarFrame.xml",
|
||||
"ScrollTemplates.xml",
|
||||
"Interface\\FrameXML\\UIPanelTemplates.lua",
|
||||
"Interface\\FrameXML\\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\OptionsFrameTemplates.xml",
|
||||
"Interface\\FrameXML\\ReputationFrame.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
"OptionsFrame.xml",
|
||||
"Interface\\FrameXML\\MultiActionBars.xml",
|
||||
"MicroMenu.xml",
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\UIMenu.xml",
|
||||
"Interface\\FrameXML\\ChatFrame.xml",
|
||||
"Interface\\FrameXML\\FloatingChatFrame.xml",
|
||||
"Interface\\FrameXML\\BuffFrame.xml",
|
||||
"Interface\\FrameXML\\UnitFrame.xml",
|
||||
"Interface\\FrameXML\\CombatFeedback.xml",
|
||||
"Interface\\FrameXML\\PartyFrame.xml",
|
||||
"Interface\\FrameXML\\FriendsFrame.xml",
|
||||
"Interface\\FrameXML\\RaidFrame.xml",
|
||||
"Interface\\AddOns\\Blizzard_RaidUI\\Blizzard_RaidUI.xml",
|
||||
];
|
||||
|
||||
pub(super) const BAG_UI: &[&str] = &[
|
||||
// The reference's own localized strings — `BACKPACK_TOOLTIP`, `EQUIP_CONTAINER`, `KEYRING`,
|
||||
// the `*_FONT_COLOR_CODE` pair. The app loads this at VM setup, ahead of the manifest
|
||||
@@ -311,6 +364,7 @@ pub(super) const BAG_UI: &[&str] = &[
|
||||
"Interface\\FrameXML\\ItemButtonTemplate.xml",
|
||||
"MoneyFrame.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"GameTooltip.xml",
|
||||
"Cooldown.xml",
|
||||
// The bag BAR declares `parent="MainMenuBarArtFrame"`, resolved at LOAD — so without this the
|
||||
@@ -327,6 +381,8 @@ pub(super) const BAG_UI: &[&str] = &[
|
||||
"MicroMenu.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
// The dialog engine, after the UIPanelCloseButton it inherits (1960).
|
||||
r"Interface\FrameXML\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\ContainerFrame.xml",
|
||||
// `PaperDollItemSlotButtonTemplate` and the `PaperDollItemSlotButton_*` family behind it,
|
||||
// which every bag button inherits and runs — resolved at load, so this has to precede the bar
|
||||
|
||||
@@ -99,7 +99,8 @@ fn unit_frame_hover_takes_the_default_corner_and_drops_on_leave() {
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\BuffFrame.xml",
|
||||
"Interface\\FrameXML\\UnitFrame.xml",
|
||||
"Interface\\FrameXML\\CombatFeedback.xml",
|
||||
@@ -165,7 +166,8 @@ fn your_own_portrait_explains_the_menu_instead_of_showing_your_health() {
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\BuffFrame.xml",
|
||||
"Interface\\FrameXML\\UnitFrame.xml",
|
||||
"Interface\\FrameXML\\CombatFeedback.xml",
|
||||
@@ -290,6 +292,9 @@ fn ubertooltips_off_seats_action_bar_plates_beside_the_button() {
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
"OptionsFrame.xml",
|
||||
"Interface\\FrameXML\\MultiActionBars.xml",
|
||||
|
||||
@@ -65,7 +65,8 @@ fn load_tot() -> UiScript {
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
load_xml(&s, "UnitPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UnitPopup.xml");
|
||||
load_xml(&s, "Cooldown.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.lua");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//! `assets/ui/TrainerFrame.xml` — a client-sorted, collapsible **skill-line tree** with a **dropdown**
|
||||
//! state filter and a draggable **scroll bar** (decisions 0247/0251) — loaded behind its deps
|
||||
//! (`UiPanels.xml` + `UIDropDownMenu.xml` + `ScrollTemplates.xml` + `MerchantFrame.xml` for the
|
||||
//! `BenillaMoney_*` coin helpers) and fed a synthetic service list. Covers what only a runtime load
|
||||
//! the stock money frames) and fed a synthetic service list. Covers what only a runtime load
|
||||
//! exercises: the Lua parses and every referenced global resolves, the tree renders interleaved
|
||||
//! header/service rows, a header click folds its group, the dropdown filter hides a state, the wheel
|
||||
//! scrolls the list, the NPC name rides `arg1` into the title, the byte-exact GlobalStrings render, the
|
||||
@@ -22,27 +22,83 @@ use super::test_ui::load_ui as load_xml;
|
||||
/// pushes into the engine on every show — so a test that wants the full tree sets those, not the
|
||||
/// engine's own `SetTrainerServiceTypeFilter`, which the next `TRAINER_SHOW` would overwrite.
|
||||
fn trainer_script() -> UiScript {
|
||||
let mut s = trainer_script_base();
|
||||
// The reference's own LoadOnDemand addon's files, direct off the chain (what its `LoadAddOn`
|
||||
// runs), and the FrameXML templates file its list inherits from (1957).
|
||||
load_xml(
|
||||
&s,
|
||||
"Interface\\AddOns\\Blizzard_TrainerUI\\Blizzard_TrainerUI.xml",
|
||||
);
|
||||
finish_trainer_load(&mut s);
|
||||
s
|
||||
}
|
||||
|
||||
/// Everything the manifest loads before the trainer addon — the chain a LoadOnDemand load lands
|
||||
/// on. The stock row's label is a width-0 `<ButtonText>` (fit the text), so a measurer is seated
|
||||
/// the way the app's VM has one at world entry.
|
||||
fn trainer_script_base() -> UiScript {
|
||||
let mut s = UiScript::new().unwrap();
|
||||
s.set_screen_size(1024.0, 768.0);
|
||||
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
|
||||
load_xml(&s, "MoneyFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, "GameTooltip.xml"); // TOOLTIP_DEFAULT_* (the kit's MenuBackdrop), app order
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml"); // the filter dropdown's kit
|
||||
load_xml(&s, "ScrollTemplates.xml"); // the faux-scroll bar kit
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); // the merchant kit; the money frames are MoneyFrame.xml's (1937)
|
||||
load_xml(&s, "TrainerFrame.xml");
|
||||
s.run(
|
||||
"TRAINER_FILTER_AVAILABLE = 1 TRAINER_FILTER_UNAVAILABLE = 1 TRAINER_FILTER_USED = 1 \
|
||||
BenillaTrainerFrame_ApplyFilter()",
|
||||
)
|
||||
.unwrap();
|
||||
s.set_text_measurer(Box::new(super::FixedWidthFont(7.0)));
|
||||
// The reference's window calls `UpdateMicroButtons` on show and inherits the panel kit's
|
||||
// templates, so the harness carries what the manifest loads before it, in the manifest's
|
||||
// order (ScrollTemplates BEFORE UIPanelTemplates, 1846) — and the reference's own
|
||||
// LoadOnDemand addon last, with the FrameXML templates file its list inherits from (1957).
|
||||
for f in [
|
||||
"Interface\\FrameXML\\Fonts.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"UIParent.xml",
|
||||
"Cooldown.xml",
|
||||
"Interface\\FrameXML\\ActionButtonTemplate.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\MainMenuBar.xml",
|
||||
"MoneyFrame.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\ActionBarFrame.xml",
|
||||
"Interface\\FrameXML\\BonusActionBarFrame.xml",
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
r"Interface\FrameXML\OptionsFrameTemplates.xml",
|
||||
r"Interface\FrameXML\ReputationFrame.xml",
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"KeyBindingsPage.xml",
|
||||
"OptionsFrame.xml",
|
||||
"Interface\\FrameXML\\MultiActionBars.xml",
|
||||
"MicroMenu.xml",
|
||||
"Interface\\FrameXML\\MerchantFrame.xml",
|
||||
"Interface\\FrameXML\\ClassTrainerFrameTemplates.xml",
|
||||
] {
|
||||
load_xml(&s, f);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// What follows the addon's files in its LoadOnDemand load (1957): the saved chunk (none in a
|
||||
/// bare harness) and then its ADDON_LOADED, whose arm pushes the three filter globals into the
|
||||
/// engine. The harness wants "used" shown too. The stock title reads `UnitName("npc")`, so the
|
||||
/// trainer NPC is seated here as the app seats it on TRAINER_SHOW.
|
||||
fn finish_trainer_load(s: &mut UiScript) {
|
||||
s.set_unit(
|
||||
"npc",
|
||||
Some(benilla_ui::script::UnitState {
|
||||
exists: true,
|
||||
name: Some("Sana Winterhoof".into()),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
s.run("TRAINER_FILTER_USED = 1").unwrap();
|
||||
s.fire_event(
|
||||
"ADDON_LOADED",
|
||||
vec![ScriptValue::Str("Blizzard_TrainerUI".into())],
|
||||
);
|
||||
}
|
||||
|
||||
/// Whether any rendered text quad carries `color` (within a small tolerance) — used to spot the
|
||||
/// reddened cost coins, whose `(1.0, 0.1, 0.1)` is distinct from the unavailable row's `(0.9, 0, 0)`.
|
||||
fn has_text_color(quads: &[ExtractedQuad], color: [f32; 3]) -> bool {
|
||||
@@ -192,7 +248,7 @@ fn shipped_trainer_frame_drives_end_to_end() {
|
||||
|
||||
// Hidden by default.
|
||||
assert!(!s
|
||||
.eval::<bool>("return BenillaTrainerFrame:IsVisible()")
|
||||
.eval::<bool>("return ClassTrainerFrame:IsVisible()")
|
||||
.unwrap());
|
||||
|
||||
// The app's feed: 50 copper in the purse + the warrior menu, then the open event with the name.
|
||||
@@ -206,22 +262,22 @@ fn shipped_trainer_frame_drives_end_to_end() {
|
||||
|
||||
// Shown, title took the NPC name off arg1.
|
||||
assert!(s
|
||||
.eval::<bool>("return BenillaTrainerFrame:IsVisible()")
|
||||
.eval::<bool>("return ClassTrainerFrame:IsVisible()")
|
||||
.unwrap());
|
||||
assert_eq!(
|
||||
s.eval::<String>("return BenillaTrainerTitleText:GetText()")
|
||||
s.eval::<String>("return ClassTrainerNameText:GetText()")
|
||||
.unwrap(),
|
||||
"Sana Winterhoof"
|
||||
);
|
||||
|
||||
// Row 1 renders the "Arms" header (its name, no indent); row 2 the first service.
|
||||
assert_eq!(
|
||||
s.eval::<String>("return BenillaTrainerService1Text:GetText()")
|
||||
s.eval::<String>("return ClassTrainerSkill1Text:GetText()")
|
||||
.unwrap(),
|
||||
"Arms"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return BenillaTrainerService2Text:GetText()")
|
||||
s.eval::<String>("return ClassTrainerSkill2Text:GetText()")
|
||||
.unwrap(),
|
||||
" Heroic Strike"
|
||||
);
|
||||
@@ -233,12 +289,12 @@ fn shipped_trainer_frame_drives_end_to_end() {
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return BenillaTrainerCostLabel:GetText()")
|
||||
s.eval::<String>("return ClassTrainerCostLabel:GetText()")
|
||||
.unwrap(),
|
||||
"Cost:"
|
||||
);
|
||||
assert!(s
|
||||
.eval::<bool>("return BenillaTrainerTrainButton:IsEnabled() ~= 0")
|
||||
.eval::<bool>("return ClassTrainerTrainButton:IsEnabled() ~= 0")
|
||||
.unwrap());
|
||||
|
||||
// Train buys the selected service — the row's spell id reaches the app's drain.
|
||||
@@ -248,11 +304,11 @@ fn shipped_trainer_frame_drives_end_to_end() {
|
||||
assert!(s.take_trainer_buys().is_empty(), "drained");
|
||||
|
||||
// Select the available-but-unaffordable service (Thunder Clap, index 6, 500c > 50c): Train disables
|
||||
// and the cost coins redden (BenillaMoney_SetColor 1.0, 0.1, 0.1).
|
||||
s.run("SelectTrainerService(6); BenillaTrainerFrame_Update()")
|
||||
// and the cost coins redden (SetMoneyFrameColor 1.0, 0.1, 0.1).
|
||||
s.run("this = ClassTrainerSkill6; ClassTrainerSkillButton_OnClick('LeftButton')")
|
||||
.unwrap();
|
||||
assert!(!s
|
||||
.eval::<bool>("return BenillaTrainerTrainButton:IsEnabled() ~= 0")
|
||||
.eval::<bool>("return ClassTrainerTrainButton:IsEnabled() ~= 0")
|
||||
.unwrap());
|
||||
s.resolve();
|
||||
assert!(
|
||||
@@ -262,10 +318,10 @@ fn shipped_trainer_frame_drives_end_to_end() {
|
||||
|
||||
// Select the gated service (Cleave, index 3): the Requires: line is built from the level/skill/
|
||||
// ability gates (byte-exact REQUIRES_LABEL), and Train stays disabled (unavailable).
|
||||
s.run("SelectTrainerService(3); BenillaTrainerFrame_Update()")
|
||||
s.run("this = ClassTrainerSkill3; ClassTrainerSkillButton_OnClick('LeftButton')")
|
||||
.unwrap();
|
||||
let reqs = s
|
||||
.eval::<String>("return BenillaTrainerSkillRequirements:GetText()")
|
||||
.eval::<String>("return ClassTrainerSkillRequirements:GetText()")
|
||||
.unwrap();
|
||||
assert!(reqs.starts_with("Requires: "), "reqs: {reqs}");
|
||||
for term in ["Level", "Swords", "Charge"] {
|
||||
@@ -279,14 +335,14 @@ fn shipped_trainer_frame_drives_end_to_end() {
|
||||
"a known prerequisite shows white with its rank: {reqs}"
|
||||
);
|
||||
assert!(!s
|
||||
.eval::<bool>("return BenillaTrainerTrainButton:IsEnabled() ~= 0")
|
||||
.eval::<bool>("return ClassTrainerTrainButton:IsEnabled() ~= 0")
|
||||
.unwrap());
|
||||
|
||||
// The app's client-side close: clear the snapshot + fire TRAINER_CLOSED → the window hides.
|
||||
s.set_trainer(None);
|
||||
s.fire_event("TRAINER_CLOSED", vec![]);
|
||||
assert!(!s
|
||||
.eval::<bool>("return BenillaTrainerFrame:IsVisible()")
|
||||
.eval::<bool>("return ClassTrainerFrame:IsVisible()")
|
||||
.unwrap());
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
@@ -304,25 +360,25 @@ fn clicking_a_header_row_collapses_its_group() {
|
||||
// Full tree: 2 headers + 4 services = 6 rows; row 2 is Heroic Strike.
|
||||
assert_eq!(s.eval::<i64>("return GetNumTrainerServices()").unwrap(), 6);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return BenillaTrainerService2Text:GetText()")
|
||||
s.eval::<String>("return ClassTrainerSkill2Text:GetText()")
|
||||
.unwrap(),
|
||||
" Heroic Strike"
|
||||
);
|
||||
|
||||
// Click the Arms header (row 1): its two services fold → 4 rows (H:Arms, H:Fury, Rend, Thunder
|
||||
// Clap). Row 2 is now the Fury header.
|
||||
s.run("BenillaTrainerSkillButton_OnClick(BenillaTrainerService1, 'LeftButton')")
|
||||
s.run("this = ClassTrainerSkill1; ClassTrainerSkillButton_OnClick('LeftButton')")
|
||||
.unwrap();
|
||||
assert_eq!(s.eval::<i64>("return GetNumTrainerServices()").unwrap(), 4);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return BenillaTrainerService2Text:GetText()")
|
||||
s.eval::<String>("return ClassTrainerSkill2Text:GetText()")
|
||||
.unwrap(),
|
||||
"Fury",
|
||||
"Arms folded; its header (row 1) now abuts the Fury header (row 2)"
|
||||
);
|
||||
|
||||
// Click it again → expands back to 6 rows.
|
||||
s.run("BenillaTrainerSkillButton_OnClick(BenillaTrainerService1, 'LeftButton')")
|
||||
s.run("this = ClassTrainerSkill1; ClassTrainerSkillButton_OnClick('LeftButton')")
|
||||
.unwrap();
|
||||
assert_eq!(s.eval::<i64>("return GetNumTrainerServices()").unwrap(), 6);
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
@@ -342,7 +398,9 @@ fn filter_hides_a_state_keeping_headers() {
|
||||
// Drive the dropdown's own click handler for the "used" row: the row button rides as `this` with
|
||||
// its pre-click state (checked=on, value="used"), exactly as UIDropDownMenuButton_OnClick invokes
|
||||
// the row func. It flips the engine filter off and repaints. Rend drops (6 → 5); headers remain.
|
||||
s.run("this = { value = 'used', checked = 1 }; BenillaTrainerFilterDropDown_OnClick()")
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap();
|
||||
s.run("this = DropDownList1Button3; UIDropDownMenuButton_OnClick()")
|
||||
.unwrap();
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
assert_eq!(
|
||||
@@ -373,7 +431,7 @@ fn filter_rows_toggle_through_the_dropdown_kit() {
|
||||
|
||||
// Open the menu the way the capsule's arrow does. Row 2 is "Unavailable" (Initialize's order),
|
||||
// checked because trainer_script() turned every state on.
|
||||
s.run("ToggleDropDownMenu(1, nil, BenillaTrainerFilterDropDown)")
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap();
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
let row_checked = |s: &mut UiScript| {
|
||||
@@ -416,9 +474,9 @@ fn filter_rows_toggle_through_the_dropdown_kit() {
|
||||
// what the clicks left behind (the two states left on, "used" still on from trainer_script()).
|
||||
s.run("this = DropDownList1Button2; UIDropDownMenuButton_OnClick()")
|
||||
.unwrap();
|
||||
s.run("ToggleDropDownMenu(1, nil, BenillaTrainerFilterDropDown)")
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap(); // same owner → closes
|
||||
s.run("ToggleDropDownMenu(1, nil, BenillaTrainerFilterDropDown)")
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap(); // re-open → re-Initialize
|
||||
assert!(
|
||||
!row_checked(&mut s),
|
||||
@@ -461,11 +519,11 @@ fn wheel_over_a_row_scrolls_the_list() {
|
||||
s.fire_event("TRAINER_SHOW", vec![ScriptValue::Str("Sana".into())]);
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
|
||||
let row1 = "return BenillaTrainerService1Text:GetText()";
|
||||
let row1 = "return ClassTrainerSkill1Text:GetText()";
|
||||
// At the top: row 1 is the "Arms" header, row 2 the first service.
|
||||
assert_eq!(s.eval::<String>(row1).unwrap(), "Arms");
|
||||
assert_eq!(
|
||||
s.eval::<String>("return BenillaTrainerService2Text:GetText()")
|
||||
s.eval::<String>("return ClassTrainerSkill2Text:GetText()")
|
||||
.unwrap(),
|
||||
" Service 01"
|
||||
);
|
||||
@@ -486,7 +544,7 @@ fn wheel_over_a_row_scrolls_the_list() {
|
||||
// reference's and is asserted as "a page, not a row"; pinning the exact row count would pin a
|
||||
// pixel arithmetic whose inputs resolve a frame apart.
|
||||
let offset = s
|
||||
.eval::<i64>("return BenillaTrainerListScrollFrame.offset or -1")
|
||||
.eval::<i64>("return ClassTrainerListScrollFrame.offset or -1")
|
||||
.unwrap();
|
||||
assert!(
|
||||
offset > 1,
|
||||
@@ -503,7 +561,7 @@ fn wheel_over_a_row_scrolls_the_list() {
|
||||
// there is the clamp working, not the wheel failing.
|
||||
s.mouse_wheel(x, y, -1.0);
|
||||
assert_eq!(
|
||||
s.eval::<i64>("return BenillaTrainerListScrollFrame.offset or -1")
|
||||
s.eval::<i64>("return ClassTrainerListScrollFrame.offset or -1")
|
||||
.unwrap(),
|
||||
offset,
|
||||
"clamped at the bottom (numItems - numToDisplay), never past it"
|
||||
@@ -513,7 +571,7 @@ fn wheel_over_a_row_scrolls_the_list() {
|
||||
s.mouse_wheel(x, y, 1.0);
|
||||
s.mouse_wheel(x, y, 1.0);
|
||||
assert_eq!(
|
||||
s.eval::<i64>("return BenillaTrainerListScrollFrame.offset or -1")
|
||||
s.eval::<i64>("return ClassTrainerListScrollFrame.offset or -1")
|
||||
.unwrap(),
|
||||
0,
|
||||
"back at the top, clamped"
|
||||
@@ -545,13 +603,13 @@ fn a_selected_or_hovered_service_row_paints_its_name_white() {
|
||||
// The name really is the button's own label now — a child FontString would leave
|
||||
// GetFontString() nil and no per-state font could reach it.
|
||||
assert!(
|
||||
s.eval::<bool>("return BenillaTrainerService1:GetFontString() ~= nil")
|
||||
s.eval::<bool>("return ClassTrainerSkill1:GetFontString() ~= nil")
|
||||
.unwrap(),
|
||||
"the row name is the Button's ButtonText, the only region per-state fonts reach"
|
||||
);
|
||||
|
||||
// Cleave (index 3) is unavailable → red when not selected. Select it → its name goes white.
|
||||
s.run("SelectTrainerService(3); BenillaTrainerFrame_Update()")
|
||||
s.run("this = ClassTrainerSkill3; ClassTrainerSkillButton_OnClick('LeftButton')")
|
||||
.unwrap();
|
||||
s.resolve();
|
||||
assert!(
|
||||
@@ -560,7 +618,7 @@ fn a_selected_or_hovered_service_row_paints_its_name_white() {
|
||||
);
|
||||
|
||||
// Select Heroic Strike (index 2): Cleave is no longer selected → back to unavailable red.
|
||||
s.run("SelectTrainerService(2); BenillaTrainerFrame_Update()")
|
||||
s.run("this = ClassTrainerSkill2; ClassTrainerSkillButton_OnClick('LeftButton')")
|
||||
.unwrap();
|
||||
s.resolve();
|
||||
assert!(
|
||||
@@ -617,7 +675,7 @@ fn wheel_scroll_is_silent_but_the_arrows_click() {
|
||||
);
|
||||
|
||||
// The down arrow (enabled at the top), though — clicking it plays the ref's arrow click.
|
||||
s.run("BenillaTrainerListScrollFrameScrollBarScrollDownButton:Click()")
|
||||
s.run("ClassTrainerListScrollFrameScrollBarScrollDownButton:Click()")
|
||||
.unwrap();
|
||||
assert!(
|
||||
s.take_sounds().contains(&click),
|
||||
@@ -641,12 +699,12 @@ fn the_scrollbar_arrows_step_the_list_the_way_they_point() {
|
||||
s.set_trainer(Some(long_menu())); // 16 rows > 11 visible → the bar shows
|
||||
s.fire_event("TRAINER_SHOW", vec![ScriptValue::Str("Sana".into())]);
|
||||
let offset = |s: &mut UiScript| {
|
||||
s.eval::<i64>("return BenillaTrainerListScrollFrame.offset or -1")
|
||||
s.eval::<i64>("return ClassTrainerListScrollFrame.offset or -1")
|
||||
.unwrap()
|
||||
};
|
||||
let click = |s: &mut UiScript, which: &str| {
|
||||
s.run(&format!(
|
||||
"BenillaTrainerListScrollFrameScrollBarScroll{which}Button:Click()"
|
||||
"ClassTrainerListScrollFrameScrollBarScroll{which}Button:Click()"
|
||||
))
|
||||
.unwrap();
|
||||
};
|
||||
@@ -668,42 +726,70 @@ fn the_scrollbar_arrows_step_the_list_the_way_they_point() {
|
||||
}
|
||||
|
||||
/// **The filter is remembered across a restart** (decision 1128) — the whole persistence path, in
|
||||
/// one test: the shipped XML declares its three globals for saving at file scope, a dropdown toggle
|
||||
/// writes the *global* (not only the engine mask), the serialized file carries it, and a fresh VM
|
||||
/// that loads the same XML and then executes that file comes up with the toggled filter applied.
|
||||
///
|
||||
/// It also pins the two halves that are easy to "simplify" apart and silently break: writing only
|
||||
/// the engine mask in the click handler would lose the choice at the next list packet (the reference
|
||||
/// rebuilds that mask on every one), and applying the globals only in `<OnShow>` would leave the
|
||||
/// first painted frame under the reset.
|
||||
/// The reference's own restart, through its own mechanism (1957): the addon is a LoadOnDemand
|
||||
/// registry row read off the chain; `LoadAddOn` runs its files (file-scope defaults), then its
|
||||
/// per-addon saved file over them, then fires ADDON_LOADED — whose arm pushes the three filter
|
||||
/// globals into the engine. A dropdown toggle writes the GLOBAL; the addon's `## SavedVariables`
|
||||
/// carry it into the file; a fresh VM loading the addon comes up with the toggle applied.
|
||||
#[test]
|
||||
fn the_state_filter_survives_a_restart_through_the_saved_variables_file() {
|
||||
let mut s = trainer_script();
|
||||
s.set_money(50);
|
||||
s.set_trainer(Some(menu()));
|
||||
s.fire_event("TRAINER_SHOW", vec![ScriptValue::Str("Sana".into())]);
|
||||
assert_eq!(s.eval::<i64>("return GetNumTrainerServices()").unwrap(), 6);
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let toc =
|
||||
super::reference_ui::read("Interface/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.toc")
|
||||
.map(|b| benilla_ui::toc::Toc::parse(&benilla_ui::source::decode(&b)))
|
||||
.expect("the addon's toc off the chain");
|
||||
assert!(toc.load_on_demand(), "the reference ships it LoadOnDemand");
|
||||
let info = || {
|
||||
let mut i = super::addons::info_from_toc("Blizzard_TrainerUI", &toc);
|
||||
i.chain = true;
|
||||
i
|
||||
};
|
||||
let saved_dir =
|
||||
std::env::temp_dir().join(format!("benilla-trainer-saved-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&saved_dir);
|
||||
std::fs::create_dir_all(&saved_dir).unwrap();
|
||||
let boot = |s: &mut UiScript| {
|
||||
s.set_addon_chain_reader(Box::new(super::reference_ui::read));
|
||||
s.register_addons(vec![info()], None, Some(saved_dir.clone()), None);
|
||||
s.set_unit(
|
||||
"npc",
|
||||
Some(benilla_ui::script::UnitState {
|
||||
exists: true,
|
||||
name: Some("Sana Winterhoof".into()),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
s.set_money(50);
|
||||
s.set_trainer(Some(menu()));
|
||||
// The reference's arm: TRAINER_SHOW → ClassTrainerFrame_LoadUI → UIParentLoadAddOn.
|
||||
s.fire_event("TRAINER_SHOW", vec![ScriptValue::Str("Sana".into())]);
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
assert!(
|
||||
s.eval::<bool>("return IsAddOnLoaded('Blizzard_TrainerUI') == 1")
|
||||
.unwrap(),
|
||||
"loaded on demand, off the chain"
|
||||
);
|
||||
};
|
||||
|
||||
// This XML declared exactly the reference's three globals, in its order. Filtered to the
|
||||
// trainer's own prefix because the registry belongs to the whole UI: every file the harness
|
||||
// loads adds its own (GameTooltip.xml's SHOW_NEWBIE_TIPS since 1136), and what the OTHER files
|
||||
// register is not this test's business.
|
||||
let declared: Vec<String> = s
|
||||
.saved_variable_names()
|
||||
.into_iter()
|
||||
.filter(|n| n.starts_with("TRAINER_"))
|
||||
.collect();
|
||||
let mut s = trainer_script_base();
|
||||
boot(&mut s);
|
||||
// The reference's own file-scope default hides known spells (TRAINER_FILTER_USED = 0), so
|
||||
// the one used service is out on the very first paint: 2 headers + 3 of the 4 services.
|
||||
assert_eq!(s.eval::<i64>("return GetNumTrainerServices()").unwrap(), 5);
|
||||
assert_eq!(
|
||||
declared,
|
||||
info().saved_variables,
|
||||
vec![
|
||||
"TRAINER_FILTER_AVAILABLE",
|
||||
"TRAINER_FILTER_UNAVAILABLE",
|
||||
"TRAINER_FILTER_USED",
|
||||
]
|
||||
],
|
||||
"the toc's own three, in its order"
|
||||
);
|
||||
|
||||
// Toggle "Unavailable" off through the dropdown row's own handler (pre-click state on `this`).
|
||||
s.run("this = { value = 'unavailable', checked = 1 }; BenillaTrainerFilterDropDown_OnClick()")
|
||||
// Toggle "Unavailable" off through the dropdown row's own handler.
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap();
|
||||
s.run("this = DropDownList1Button2; UIDropDownMenuButton_OnClick()")
|
||||
.unwrap();
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
assert_eq!(
|
||||
@@ -711,19 +797,17 @@ fn the_state_filter_survives_a_restart_through_the_saved_variables_file() {
|
||||
0,
|
||||
"the click must write the SAVED global, not just the engine mask"
|
||||
);
|
||||
let text = s.saved_variables_text();
|
||||
let text = s.saved_variables_text_for(&info().saved_variables);
|
||||
assert!(
|
||||
text.contains("TRAINER_FILTER_UNAVAILABLE = 0"),
|
||||
"the file carries the toggle: {text}"
|
||||
);
|
||||
std::fs::write(saved_dir.join("Blizzard_TrainerUI.lua"), &text).unwrap();
|
||||
|
||||
// The restart: a fresh VM with the same XML (file-scope defaults stand), then the saved file
|
||||
// executed over them, then a trainer opens.
|
||||
let mut fresh = trainer_script();
|
||||
fresh.run(&text).unwrap();
|
||||
fresh.set_money(50);
|
||||
fresh.set_trainer(Some(menu()));
|
||||
fresh.fire_event("TRAINER_SHOW", vec![ScriptValue::Str("Sana".into())]);
|
||||
// The restart: a fresh VM loads the addon on demand — files, then the saved file, then
|
||||
// ADDON_LOADED — and the first paint is already filtered.
|
||||
let mut fresh = trainer_script_base();
|
||||
boot(&mut fresh);
|
||||
assert!(
|
||||
!fresh
|
||||
.eval::<bool>("return GetTrainerServiceTypeFilter('unavailable') == 1")
|
||||
@@ -732,14 +816,10 @@ fn the_state_filter_survives_a_restart_through_the_saved_variables_file() {
|
||||
);
|
||||
assert_eq!(
|
||||
fresh.eval::<i64>("return GetNumTrainerServices()").unwrap(),
|
||||
5,
|
||||
4,
|
||||
"Cleave (the unavailable service) is hidden on the very first paint after the restart"
|
||||
);
|
||||
assert!(
|
||||
fresh.errors().is_empty(),
|
||||
"script errors: {:?}",
|
||||
fresh.errors()
|
||||
);
|
||||
let _ = std::fs::remove_dir_all(&saved_dir);
|
||||
}
|
||||
|
||||
/// A **new list packet resets the engine's filter mask** to the builder's own default — mask 3 at a
|
||||
@@ -750,7 +830,10 @@ fn the_state_filter_survives_a_restart_through_the_saved_variables_file() {
|
||||
fn a_new_list_packet_resets_the_filter_mask_and_the_collapse_set() {
|
||||
let mut s = trainer_script();
|
||||
s.set_trainer(Some(menu()));
|
||||
s.run("BenillaTrainerFrame_ApplyFilter()").unwrap();
|
||||
s.fire_event(
|
||||
"ADDON_LOADED",
|
||||
vec![ScriptValue::Str("Blizzard_TrainerUI".into())],
|
||||
);
|
||||
// Collapse a group, and turn a state off directly (no global) — both are engine-side state.
|
||||
s.run("CollapseTrainerSkillLine(1) SetTrainerServiceTypeFilter('used', 1)")
|
||||
.unwrap();
|
||||
@@ -880,7 +963,7 @@ fn a_long_row_name_stays_on_one_line_and_carries_its_rank_along() {
|
||||
// Find each name's row by what it painted (the group comparator owns the order, not this test).
|
||||
let row_of = |s: &mut UiScript, needle: &str| -> i64 {
|
||||
s.eval::<i64>(&format!(
|
||||
"for i = 1, 11 do local b = getglobal('BenillaTrainerService' .. i) \
|
||||
"for i = 1, 11 do local b = getglobal('ClassTrainerSkill' .. i) \
|
||||
local t = b:GetText() if t and strfind(t, '{needle}', 1, 1) then return i end \
|
||||
end return 0"
|
||||
))
|
||||
@@ -892,9 +975,9 @@ fn a_long_row_name_stays_on_one_line_and_carries_its_rank_along() {
|
||||
|
||||
let geom = |s: &mut UiScript, row: i64| -> (f32, f32, f32, f32) {
|
||||
s.eval::<(f32, f32, f32, f32)>(&format!(
|
||||
"local b = getglobal('BenillaTrainerService{row}') \
|
||||
"local b = getglobal('ClassTrainerSkill{row}') \
|
||||
local n = b:GetFontString() \
|
||||
return n:GetHeight(), n:GetRight(), b.subtext:GetLeft(), b:GetHeight()"
|
||||
return n:GetHeight(), n:GetRight(), getglobal(b:GetName() .. 'SubText'):GetLeft(), b:GetHeight()"
|
||||
))
|
||||
.unwrap()
|
||||
};
|
||||
@@ -941,11 +1024,12 @@ fn learning_a_spell_keeps_the_filter_and_the_collapse_a_re_open_still_resets() {
|
||||
|
||||
let mut s = trainer_script();
|
||||
// The reference's own file-scope defaults (1128), then the player's choice below.
|
||||
s.run(
|
||||
"TRAINER_FILTER_AVAILABLE = 1 TRAINER_FILTER_UNAVAILABLE = 1 TRAINER_FILTER_USED = 0 \
|
||||
BenillaTrainerFrame_ApplyFilter()",
|
||||
)
|
||||
.unwrap();
|
||||
s.run("TRAINER_FILTER_AVAILABLE = 1 TRAINER_FILTER_UNAVAILABLE = 1 TRAINER_FILTER_USED = 0")
|
||||
.unwrap();
|
||||
s.fire_event(
|
||||
"ADDON_LOADED",
|
||||
vec![ScriptValue::Str("Blizzard_TrainerUI".into())],
|
||||
);
|
||||
s.set_money(5000);
|
||||
|
||||
// The trainer feed (`ui_trainer::feed_trainer`), reduced to the part this bug lives in.
|
||||
@@ -969,11 +1053,11 @@ fn learning_a_spell_keeps_the_filter_and_the_collapse_a_re_open_still_resets() {
|
||||
let mut open = TrainerOpen::default();
|
||||
open.open(DAZALAR, 0, vec![], "Hello, hunter!".into());
|
||||
feed(&mut s, &mut open, menu(), "TRAINER_SHOW");
|
||||
s.run("ToggleDropDownMenu(1, nil, BenillaTrainerFilterDropDown)")
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap();
|
||||
s.run("this = DropDownList1Button2; UIDropDownMenuButton_OnClick()")
|
||||
.unwrap();
|
||||
s.run("ToggleDropDownMenu(1, nil, BenillaTrainerFilterDropDown)")
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap();
|
||||
assert!(
|
||||
!filter_on(&mut s, "unavailable"),
|
||||
@@ -1006,37 +1090,39 @@ fn learning_a_spell_keeps_the_filter_and_the_collapse_a_re_open_still_resets() {
|
||||
"and the list is still his — the folded Arms group is empty of learnables now, so it goes \
|
||||
with its header, leaving Fury over Thunder Clap"
|
||||
);
|
||||
s.run("ToggleDropDownMenu(1, nil, BenillaTrainerFilterDropDown)")
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap();
|
||||
assert!(
|
||||
!s.eval::<bool>("return DropDownList1Button2Check:IsVisible() and true or false")
|
||||
.unwrap(),
|
||||
"the dropdown agrees with the list, instead of claiming a filter the list ignores"
|
||||
);
|
||||
s.run("ToggleDropDownMenu(1, nil, BenillaTrainerFilterDropDown)")
|
||||
s.run("ToggleDropDownMenu(1, nil, ClassTrainerFrameFilterDropDown)")
|
||||
.unwrap();
|
||||
|
||||
// He walks away and comes back: THIS packet opens a window, so the reference's reset lands —
|
||||
// and the window's own OnShow/TRAINER_SHOW puts the saved globals straight back over it. The
|
||||
// filter survives (it is saved), the collapse does not (it is engine-side, and the reset clears
|
||||
// it) — the reference's own split.
|
||||
// He walks away and comes back: THIS packet opens a window, so the reference's reset lands
|
||||
// (`0x4d75d9` writes the mask to 3 on every list) — and nothing puts the saved globals back
|
||||
// over it: the stock addon pushes them once, on ITS ADDON_LOADED, which a LoadOnDemand
|
||||
// addon fires on the session's first trainer. The collapse is engine-side and clears too
|
||||
// (1957; the transcription used to re-push on show, which the reference never does).
|
||||
open.clear();
|
||||
open.open(DAZALAR, 0, vec![], "Hello, hunter!".into());
|
||||
let mut learned = menu();
|
||||
learned.services[0].category = TrainerServiceCategory::Used;
|
||||
feed(&mut s, &mut open, learned, "TRAINER_SHOW");
|
||||
assert!(
|
||||
!filter_on(&mut s, "unavailable"),
|
||||
"the saved filter is pushed back over the packet reset"
|
||||
filter_on(&mut s, "unavailable"),
|
||||
"a fresh list is the reference's reset: unavailable shows again"
|
||||
);
|
||||
assert!(filter_on(&mut s, "available"));
|
||||
assert!(
|
||||
filter_on(&mut s, "available"),
|
||||
"and the states he never turned off are still on"
|
||||
!filter_on(&mut s, "used"),
|
||||
"and the reset's mask is 3 — used stays hidden"
|
||||
);
|
||||
assert_eq!(
|
||||
rows(&mut s),
|
||||
2,
|
||||
"nothing collapsed now — but still filtered"
|
||||
s.eval::<i64>("return TRAINER_FILTER_UNAVAILABLE").unwrap(),
|
||||
0,
|
||||
"his saved choice is still the global's, for the next session's first trainer"
|
||||
);
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ fn load_unit_frames(s: &UiScript) {
|
||||
load_xml(s, "MoneyFrame.xml");
|
||||
load_xml(s, "GameTooltip.xml");
|
||||
load_xml(s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
load_xml(s, "UnitPopup.xml");
|
||||
load_xml(s, "Interface\\FrameXML\\BasicControls.xml"); // `TEXT`, which UnitPopup.lua reads at file scope
|
||||
load_xml(s, "Interface\\FrameXML\\UnitPopup.xml");
|
||||
load_xml(s, "Interface\\FrameXML\\BuffFrame.xml");
|
||||
load_xml(s, "Interface\\FrameXML\\UnitFrame.xml");
|
||||
load_xml(s, "Interface\\FrameXML\\CombatFeedback.xml");
|
||||
@@ -650,6 +651,9 @@ fn shipped_target_frame_runs_the_level_law() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
@@ -1212,12 +1216,16 @@ fn the_party_art_paints_over_the_bars() {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "GameTooltip.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
|
||||
// Before UnitPopup: that file reads ITEM_QUALITY_COLORS at FILE SCOPE and its
|
||||
// declarer is UIParent (ref UIParent.lua:65) since 1888.
|
||||
load_xml(&s, "UIParent.xml");
|
||||
load_xml(&s, "UnitPopup.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
|
||||
load_xml(&s, "Interface\\FrameXML\\UnitPopup.xml");
|
||||
// The reference's own kit, in the manifest's order. `UIParent.xml` is not decoration here:
|
||||
// `RaiseFrameLevel`/`LowerFrameLevel` live in it (ref UIParent.lua l.1890-1896) and stock
|
||||
// `TargetofTargetTextureFrame`'s OnLoad calls one of them.
|
||||
|
||||
@@ -22,9 +22,17 @@ fn load_popup_frames(s: &UiScript) {
|
||||
// `StaticPopupDialogs` and the `PanelTemplates_*` family, both of which FriendsFrame.xml
|
||||
// reaches at LOAD (its tab row and its confirm dialogs).
|
||||
"UiPanels.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua", // `TEXT`, read at file scope below
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\UIMenu.xml",
|
||||
"Interface\\FrameXML\\ChatFrame.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\ItemRef.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
@@ -36,9 +44,9 @@ fn load_popup_frames(s: &UiScript) {
|
||||
"Interface\\FrameXML\\TargetFrame.xml",
|
||||
"Interface\\FrameXML\\PetFrame.xml",
|
||||
"ScrollTemplates.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"FriendsFrame.xml",
|
||||
"Interface\\FrameXML\\FriendsFrame.xml",
|
||||
// Declares ChatFrameEditBox, which the rename dialog's OnHide refocuses (1960).
|
||||
"Interface\\FrameXML\\FloatingChatFrame.xml",
|
||||
] {
|
||||
load_xml(s, file);
|
||||
}
|
||||
@@ -108,11 +116,13 @@ fn chat_name_right_click_opens_the_invite_menu() {
|
||||
s.eval::<bool>("return DropDownList1:IsVisible()").unwrap(),
|
||||
"the chat-name right-click opens the FRIEND dropdown"
|
||||
);
|
||||
// title (Bob) + Whisper + Invite + Cancel — the rest of FRIEND is DEFERRED/hidden.
|
||||
// title (Bob) + Whisper + Invite + Target + Cancel — the reference's FRIEND menu with its two
|
||||
// guild rows hidden by their own predicates (no guild, no guild frame). Our transcription
|
||||
// had deferred Target; the stock row is `TargetByName`, which exists (1958).
|
||||
assert_eq!(
|
||||
s.eval::<i64>("return DropDownList1.numButtons").unwrap(),
|
||||
4,
|
||||
"title + Whisper + Invite + Cancel"
|
||||
5,
|
||||
"title + Whisper + Invite + Target + Cancel"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return DropDownList1Button1:GetText()")
|
||||
@@ -138,14 +148,22 @@ fn chat_name_right_click_opens_the_invite_menu() {
|
||||
"Invite on a chat name queues an invite-by-name"
|
||||
);
|
||||
|
||||
// A plain LEFT-click on the name whispers instead (ref's else branch).
|
||||
// A plain LEFT-click on the name whispers instead (ref's else branch): the stock
|
||||
// `ChatFrame_SendTell` puts the box into WHISPER mode at the name and opens it (1960).
|
||||
s.run(r#"SetItemRef("player:Carol", "|Hplayer:Carol|h[Carol]|h", "LeftButton")"#)
|
||||
.unwrap();
|
||||
s.tick(0.05);
|
||||
assert_eq!(
|
||||
s.take_tell_requests(),
|
||||
vec!["Carol".to_string()],
|
||||
s.eval::<(String, String)>("return ChatFrameEditBox.chatType, ChatFrameEditBox.tellTarget")
|
||||
.unwrap(),
|
||||
("WHISPER".to_string(), "Carol".to_string()),
|
||||
"left-click a chat name opens a whisper"
|
||||
);
|
||||
assert!(
|
||||
s.eval::<bool>("return ChatFrameEditBox:IsVisible()")
|
||||
.unwrap(),
|
||||
"and the box is open"
|
||||
);
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
@@ -471,9 +489,14 @@ fn load_pet_menu_frames(s: &UiScript) {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua", // `TEXT`, read at file scope below
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\UIMenu.xml",
|
||||
"Interface\\FrameXML\\ChatFrame.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml",
|
||||
"UnitPopup.xml",
|
||||
"Interface\\FrameXML\\UnitPopup.xml",
|
||||
"Interface\\FrameXML\\TextStatusBar.lua",
|
||||
"Interface\\FrameXML\\TextStatusBar.xml",
|
||||
"Interface\\FrameXML\\BuffFrame.xml",
|
||||
@@ -488,6 +511,8 @@ fn load_pet_menu_frames(s: &UiScript) {
|
||||
"Interface\\FrameXML\\MainMenuBar.xml",
|
||||
"Interface\\FrameXML\\ActionBarFrame.xml",
|
||||
"Interface\\FrameXML\\BonusActionBarFrame.xml",
|
||||
// Declares ChatFrameEditBox, which the rename dialog's OnHide refocuses (1960).
|
||||
"Interface\\FrameXML\\FloatingChatFrame.xml",
|
||||
] {
|
||||
load_xml(s, file);
|
||||
}
|
||||
@@ -795,150 +820,6 @@ fn the_pet_details_row_opens_the_pet_paper_doll() {
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
// ── The enable-pass driver (BenillaUnitPopupDriver) ─────────────────────────────────────────────
|
||||
|
||||
/// **The idle popup driver parks itself** (decision 1396's class, the audit's driver-hide item):
|
||||
/// with no unit menu of ours open, `UnitPopup_OnUpdate`'s early-out hides the driver's own frame —
|
||||
/// and the engine dispatches OnUpdate only to visible frames (`tick.rs`), so the per-frame scan
|
||||
/// stops entirely. `UnitPopup_ShowMenu` — the one opener every unit menu goes through (grep:
|
||||
/// UnitFrames/PartyFrame/FriendsFrame/ItemRef all call it) — wakes it again.
|
||||
///
|
||||
/// The probe wraps `UnitPopup_OnUpdate` in a counter: after the first tick parks the shipped-shown
|
||||
/// driver, ten idle ticks never run the pass. The control: an open target menu still runs the
|
||||
/// per-frame enable pass — a disconnected target's Whisper row greys, and greys back live when the
|
||||
/// unit reconnects mid-open — and closing the menu re-parks the driver.
|
||||
#[test]
|
||||
fn an_idle_unit_popup_driver_parks_itself_off_the_tick() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let mut s = UiScript::new().unwrap();
|
||||
s.set_screen_size(1024.0, 768.0);
|
||||
bake_strings(&s);
|
||||
load_popup_frames(&s);
|
||||
|
||||
s.set_unit(
|
||||
"player",
|
||||
Some(UnitState {
|
||||
exists: true,
|
||||
name: Some("Me".into()),
|
||||
is_player: true,
|
||||
player_controlled: true,
|
||||
..UnitState::default()
|
||||
}),
|
||||
);
|
||||
// A friendly player target, DISCONNECTED (is_connected defaults to false): the Whisper row's
|
||||
// grey predicate is live from the first enable pass.
|
||||
s.set_unit(
|
||||
"target",
|
||||
Some(UnitState {
|
||||
exists: true,
|
||||
name: Some("Ally".into()),
|
||||
health: 40,
|
||||
max_health: 40,
|
||||
is_player: true,
|
||||
player_controlled: true,
|
||||
reaction: 5,
|
||||
..UnitState::default()
|
||||
}),
|
||||
);
|
||||
s.fire_event("PLAYER_TARGET_CHANGED", vec![]);
|
||||
s.resolve();
|
||||
assert!(s.errors().is_empty(), "load errors: {:?}", s.errors());
|
||||
|
||||
s.run(
|
||||
"BENILLA_TEST_POPUP_TICKS = 0\n\
|
||||
local real = UnitPopup_OnUpdate\n\
|
||||
function UnitPopup_OnUpdate(elapsed)\n\
|
||||
BENILLA_TEST_POPUP_TICKS = BENILLA_TEST_POPUP_TICKS + 1\n\
|
||||
real(elapsed)\n\
|
||||
end",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// The driver ships shown; the first tick's early-out parks it, and then nothing runs.
|
||||
s.tick(0.016);
|
||||
s.resolve();
|
||||
assert!(
|
||||
!s.eval::<bool>("return BenillaUnitPopupDriver:IsShown()")
|
||||
.unwrap(),
|
||||
"no menu open: the first tick parks the driver"
|
||||
);
|
||||
s.run("BENILLA_TEST_POPUP_TICKS = 0").unwrap();
|
||||
for _ in 0..10 {
|
||||
s.tick(0.016);
|
||||
s.resolve();
|
||||
}
|
||||
assert_eq!(
|
||||
s.eval::<i64>("return BENILLA_TEST_POPUP_TICKS").unwrap(),
|
||||
0,
|
||||
"a parked driver never runs the enable pass"
|
||||
);
|
||||
|
||||
// Open the PLAYER menu through the real hit path: the driver wakes...
|
||||
let (cx, cy) = s
|
||||
.eval::<(f64, f64)>("return TargetFrame:GetCenter()")
|
||||
.unwrap();
|
||||
s.mouse_button(cx as f32, cy as f32, "RightButton", true);
|
||||
s.mouse_button(cx as f32, cy as f32, "RightButton", false);
|
||||
s.resolve();
|
||||
assert!(
|
||||
s.eval::<bool>("return DropDownList1:IsVisible()").unwrap(),
|
||||
"the menu opened"
|
||||
);
|
||||
assert!(
|
||||
s.eval::<bool>("return BenillaUnitPopupDriver:IsShown()")
|
||||
.unwrap(),
|
||||
"UnitPopup_ShowMenu wakes the driver"
|
||||
);
|
||||
|
||||
// ...and the pass runs per frame: the disconnected target's Whisper row greys...
|
||||
s.tick(0.016);
|
||||
s.resolve();
|
||||
assert!(
|
||||
s.eval::<i64>("return BENILLA_TEST_POPUP_TICKS").unwrap() > 0,
|
||||
"an open menu ticks the enable pass"
|
||||
);
|
||||
assert!(
|
||||
!s.eval::<bool>("return DropDownList1Button2:IsEnabled() ~= 0")
|
||||
.unwrap(),
|
||||
"Whisper greys against a disconnected target"
|
||||
);
|
||||
|
||||
// ...and un-greys LIVE when the unit reconnects while the menu is up — the whole reason the
|
||||
// pass is per-frame rather than baked at open.
|
||||
s.set_unit(
|
||||
"target",
|
||||
Some(UnitState {
|
||||
exists: true,
|
||||
name: Some("Ally".into()),
|
||||
health: 40,
|
||||
max_health: 40,
|
||||
is_player: true,
|
||||
player_controlled: true,
|
||||
reaction: 5,
|
||||
is_connected: true,
|
||||
..UnitState::default()
|
||||
}),
|
||||
);
|
||||
s.tick(0.016);
|
||||
s.resolve();
|
||||
assert!(
|
||||
s.eval::<bool>("return DropDownList1Button2:IsEnabled() ~= 0")
|
||||
.unwrap(),
|
||||
"Whisper enables the frame the target reconnects"
|
||||
);
|
||||
|
||||
// Closing the menu re-parks the driver on its next tick.
|
||||
s.run("CloseDropDownMenus()").unwrap();
|
||||
s.tick(0.016);
|
||||
s.resolve();
|
||||
assert!(
|
||||
!s.eval::<bool>("return BenillaUnitPopupDriver:IsShown()")
|
||||
.unwrap(),
|
||||
"a closed menu parks the driver again"
|
||||
);
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
/// Click an open dropdown row through the real hit path.
|
||||
fn click_row(s: &mut UiScript, row: u32) {
|
||||
click_frame(s, &format!("DropDownList1Button{row}"));
|
||||
|
||||
@@ -18,6 +18,10 @@ fn harness() -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"GameTooltip.xml",
|
||||
"Interface\\FrameXML\\UIDropDownMenu.xml", // the map's continent/zone pickers initialize into it at OnLoad
|
||||
"ScrollTemplates.xml",
|
||||
|
||||
@@ -20,6 +20,10 @@ pub(crate) fn harness() -> UiScript {
|
||||
"UiPanels.xml",
|
||||
r"Interface\FrameXML\UIPanelTemplates.lua",
|
||||
r"Interface\FrameXML\UIPanelTemplates.xml",
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\BasicControls.xml",
|
||||
"Interface\\FrameXML\\LocaleProperties.lua",
|
||||
"Interface\\FrameXML\\StaticPopup.xml",
|
||||
"UIParent.xml",
|
||||
"GameTooltip.xml",
|
||||
"WorldStateFrame.xml",
|
||||
|
||||
@@ -47,6 +47,8 @@ fn harness() -> UiScript {
|
||||
load_xml(&s, "UiPanels.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
|
||||
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
|
||||
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
|
||||
load_xml(&s, "UIParent.xml");
|
||||
// The fading kit, its own manifest entry since window 8 — as it is in the reference's TOC.
|
||||
load_xml(&s, "Interface\\FrameXML\\FadingFrame.xml");
|
||||
|
||||
Reference in New Issue
Block a user