Read the test that reports errors first: 20 more, from four causes
The guild and friends clusters — 26 tests between them — were one nil function.
`guild_tests::driving_the_guild_windows_raises_no_script_errors` exists to name
its errors, and all four of them were the same line: `attempt to call global
'GetDifficultyColor' (a nil value)` at `FriendsFrame.lua:523`, reached from four
entry points. `GetDifficultyColor` is FrameXML's, not a client global
(`reference/1.12-globals.tsv` types it so), and `QuestLogFrame.lua` defines it —
ten toc rows above `FriendsFrame.xml`. The raise took the rest of the roster
update with it, including the `GuildPlayerStatusFrame:Show()` that ends that
branch, which is how it read as "the guild tab opens and the player pane is not
visible": an assertion about visibility with no hint of a nil function behind it.
One prerequisite row took guild 17 → 1 and friends 9 → 1.
The reputation, honor and skills pages (20 more) shared a fixture gap: their
player `UnitState` had a level, a race and a class and **no name**. The realm's
`CharacterFrame_OnShow` formats `gsub(UnitPVPName("player"), "\n.+", "")`, and
`UnitPVPName` answers nil for a nameless unit, so every one of those pages raised
`bad argument #1 to 'gsub'` on the way up and never finished showing.
The inspect page's arena tab raised three more: its team buttons inherit
`ArenaTeamTemplate`, which is a FrameXML row of the realm's own
(`Turtle_ArenaUI\Turtle_ArenaUITemplates.xml`) and not in the addon's templates
file, so the inherits was skipped, `$parentText` was never built, and the OnLoad's
`_G[this:GetName().."Text"]:SetText("(2v2)")` had nothing to index. That fixture
already said "Before the inspect addon, as `inherits=` resolves at load" — it was
simply missing this one.
And five expected a rank title without its trailing space. The realm's
`GlobalStrings.lua` gives every rank one — `PVP_RANK_8_1 = "Master Sergeant "`,
where stock 1.12's copy has none — because its own callers concatenate a name
after the title. The titles are now read off `PVP_RANK_<rank>_<team>` through one
helper, so the realm owns its own strings; that also turned up a wrong index
hiding behind the stale spelling (Grand Marshal is rank 18, not 14).
136 → 116, nothing newly failing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -32,6 +32,19 @@ fn state() -> HonorState {
|
||||
|
||||
/// The character window, whose fifth tab this page is; [`super::test_ui::CHARACTER_UI`] carries
|
||||
/// `HonorFrame.xml`, as `PaperDollFrame.lua:103` writes into it on every show.
|
||||
/// The realm's own `PVP_RANK_<rank>_<team>` string.
|
||||
///
|
||||
/// Never a copy written here: the realm's `GlobalStrings.lua` gives every rank a **trailing
|
||||
/// space** (`PVP_RANK_8_1 = "Master Sergeant "`, where stock 1.12's `patch.MPQ` copy has none),
|
||||
/// because its own callers concatenate a name after the title. Pinning the stock spelling made
|
||||
/// five tests in this file assert against a string the realm does not ship.
|
||||
fn rank_title(s: &UiScript, rank: u32, team: u32) -> String {
|
||||
s.eval::<String>(&format!(
|
||||
"return PVP_RANK_{rank}_{team} or \"<no PVP_RANK_{rank}_{team}>\""
|
||||
))
|
||||
.expect("the realm's own rank string")
|
||||
}
|
||||
|
||||
fn load_page(s: &UiScript) {
|
||||
for file in super::test_ui::CHARACTER_UI {
|
||||
super::test_ui::load_ui_strict(s, file);
|
||||
@@ -43,6 +56,12 @@ fn load_page(s: &UiScript) {
|
||||
fn alliance_player() -> UnitState {
|
||||
UnitState {
|
||||
exists: true,
|
||||
// Named: the window this page lives in formats the player's name on every show —
|
||||
// `CharacterFrame_OnShow` does `gsub(UnitPVPName("player"), "\n.+", "")`
|
||||
// (`CharacterFrame.lua:85`) — and `UnitPVPName` answers nil for a unit with no name, so a
|
||||
// nameless fixture raises `bad argument #1 to 'gsub'` and takes the rest of that OnShow
|
||||
// with it.
|
||||
name: Some("Tester".into()),
|
||||
level: 60,
|
||||
sex: 2,
|
||||
faction_group: Some("Alliance".into()),
|
||||
@@ -93,7 +112,7 @@ fn every_figure_lands_in_its_own_row() {
|
||||
("HonorFrameLifeTimeHKValue", "3907"),
|
||||
("HonorFrameLifeTimeDKValue", "12"),
|
||||
// The highest rank's title (14), not the current one (12).
|
||||
("HonorFrameLifeTimeRankValue", "Lieutenant Commander"),
|
||||
("HonorFrameLifeTimeRankValue", &rank_title(&s, 14, 1)),
|
||||
] {
|
||||
assert_eq!(text(&mut s, frame), want, "{frame}");
|
||||
}
|
||||
@@ -105,7 +124,10 @@ fn every_figure_lands_in_its_own_row() {
|
||||
fn the_title_is_the_internal_rank_and_the_badge_is_the_visual_one() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let mut s = shown_honor_page();
|
||||
assert_eq!(text(&mut s, "HonorFrameCurrentPVPTitle"), "Knight-Captain");
|
||||
assert_eq!(
|
||||
text(&mut s, "HonorFrameCurrentPVPTitle"),
|
||||
rank_title(&s, 12, 1)
|
||||
);
|
||||
assert_eq!(text(&mut s, "HonorFrameCurrentPVPRank"), "(Rank 8)");
|
||||
assert!(
|
||||
s.eval::<bool>("return HonorFramePvPIcon:IsShown()")
|
||||
@@ -178,12 +200,12 @@ fn a_gm_flagged_player_keeps_his_rank_title_and_loses_only_the_faction_group() {
|
||||
s.resolve();
|
||||
assert_eq!(
|
||||
text(&mut s, "HonorFrameLifeTimeRankValue"),
|
||||
"Grand Marshal",
|
||||
rank_title(&s, 18, 1),
|
||||
"the Highest Rank row — the reported symptom"
|
||||
);
|
||||
assert_eq!(
|
||||
text(&mut s, "HonorFrameCurrentPVPTitle"),
|
||||
"Grand Marshal",
|
||||
rank_title(&s, 18, 1),
|
||||
"and the title under the badge, which reads the same key"
|
||||
);
|
||||
assert!(
|
||||
@@ -278,7 +300,22 @@ fn the_real_global_strings_name_the_rank() {
|
||||
load_page(&s);
|
||||
s.set_honor(Some(state()));
|
||||
|
||||
for (team, want) in [(1i8, "Knight-Captain"), (0, "Legionnaire")] {
|
||||
// The expected title comes off the realm's **own** `PVP_RANK_<rank>_<team>` string, not a copy
|
||||
// written here: the realm's `GlobalStrings.lua` gives every rank a **trailing space**
|
||||
// (`PVP_RANK_8_1 = "Master Sergeant "`, where stock 1.12's `patch.MPQ` copy has none), because
|
||||
// its own callers concatenate a name after the title. Pinning the stock spelling here made
|
||||
// five tests in this file assert against a string the realm does not ship.
|
||||
//
|
||||
// Rank 12 is the fixture's (`state`), and the team digit is what this is really testing: the
|
||||
// same rank reads as the Alliance title for team 1 and the Horde one for team 0.
|
||||
for team in [1i8, 0] {
|
||||
let want = s
|
||||
.eval::<String>(&format!(
|
||||
"return PVP_RANK_12_{} or \"<no PVP_RANK_12_{}>\"",
|
||||
if team == 1 { 1 } else { 0 },
|
||||
if team == 1 { 1 } else { 0 }
|
||||
))
|
||||
.expect("the realm's own rank string");
|
||||
s.set_unit(
|
||||
"player",
|
||||
Some(UnitState {
|
||||
@@ -361,6 +398,13 @@ fn shown_inspect_honor_page() -> UiScript {
|
||||
// `ItemButtonTemplate`, its honor rows `HonorFrame.xml`'s row templates.
|
||||
"Interface\\FrameXML\\ItemButtonTemplate.xml",
|
||||
"Interface\\FrameXML\\HonorFrame.xml",
|
||||
// …and its **arena** page's three team buttons inherit `ArenaTeamTemplate`, which is a
|
||||
// FrameXML row of the realm's (`Turtle_ArenaUI\Turtle_ArenaUITemplates.xml`, toc row 109)
|
||||
// rather than anything in the addon's own templates file. Without it the inherits is
|
||||
// skipped, so `$parentText` is never built, and the OnLoad's
|
||||
// `_G[this:GetName().."Text"]:SetText("(2v2)")` (`InspectArenaFrame.xml:71`) raises
|
||||
// `attempt to index field '?'` — three times, once per team.
|
||||
r"Interface\FrameXML\Turtle_ArenaUI\Turtle_ArenaUITemplates.xml",
|
||||
] {
|
||||
load_xml(&s, file);
|
||||
}
|
||||
@@ -398,14 +442,14 @@ fn the_inspect_page_paints_the_reply_it_holds() {
|
||||
("InspectHonorFrameLastWeekStandingValue", "57"),
|
||||
("InspectHonorFrameLifeTimeHKValue", "3907"),
|
||||
("InspectHonorFrameLifeTimeDKValue", "12"),
|
||||
("InspectHonorFrameLifeTimeRankValue", "Lieutenant Commander"),
|
||||
("InspectHonorFrameLifeTimeRankValue", &rank_title(&s, 14, 1)),
|
||||
] {
|
||||
assert_eq!(text(&mut s, frame), want, "{frame}");
|
||||
}
|
||||
// The target's current rank, 12, and the bar from the reply's own byte.
|
||||
assert_eq!(
|
||||
text(&mut s, "InspectHonorFrameCurrentPVPTitle"),
|
||||
"Knight-Captain"
|
||||
rank_title(&s, 12, 1)
|
||||
);
|
||||
assert_eq!(text(&mut s, "InspectHonorFrameCurrentPVPRank"), "(Rank 8)");
|
||||
let bar = s
|
||||
|
||||
@@ -63,6 +63,12 @@ fn load_page(s: &UiScript) {
|
||||
fn player(level: u32) -> UnitState {
|
||||
UnitState {
|
||||
exists: true,
|
||||
// Named, because the window this page lives in formats the player's name on **every**
|
||||
// show: `CharacterFrame_OnShow` does `gsub(UnitPVPName("player"), "\n.+", "")`
|
||||
// (`CharacterFrame.lua:85`), and `UnitPVPName` answers nil for a unit with no name — so a
|
||||
// nameless fixture raises `bad argument #1 to 'gsub'` and takes the rest of that OnShow
|
||||
// with it, including the sub-frame show this page needs.
|
||||
name: Some("Tester".into()),
|
||||
level,
|
||||
race: Some("Human".into()),
|
||||
race_file: Some("Human".into()),
|
||||
|
||||
@@ -53,6 +53,12 @@ fn shown_skills_page_with(measurer: Option<Box<dyn benilla_ui::script::TextMeasu
|
||||
"player",
|
||||
Some(UnitState {
|
||||
exists: true,
|
||||
// Named: the window this page lives in formats the player's name on every show —
|
||||
// `CharacterFrame_OnShow` does `gsub(UnitPVPName("player"), "\n.+", "")`
|
||||
// (`CharacterFrame.lua:85`) — and `UnitPVPName` answers nil for a unit with no name, so a
|
||||
// nameless fixture raises `bad argument #1 to 'gsub'` and takes the rest of that OnShow
|
||||
// with it.
|
||||
name: Some("Tester".into()),
|
||||
level: 60,
|
||||
race: Some("Tauren".into()),
|
||||
race_file: Some("Tauren".into()),
|
||||
@@ -457,6 +463,12 @@ fn the_list_reaches_its_last_row_at_the_bars_end() {
|
||||
"player",
|
||||
Some(UnitState {
|
||||
exists: true,
|
||||
// Named: the window this page lives in formats the player's name on every show —
|
||||
// `CharacterFrame_OnShow` does `gsub(UnitPVPName("player"), "\n.+", "")`
|
||||
// (`CharacterFrame.lua:85`) — and `UnitPVPName` answers nil for a unit with no name, so a
|
||||
// nameless fixture raises `bad argument #1 to 'gsub'` and takes the rest of that OnShow
|
||||
// with it.
|
||||
name: Some("Tester".into()),
|
||||
level: 60,
|
||||
race: Some("Human".into()),
|
||||
race_file: Some("Human".into()),
|
||||
|
||||
@@ -141,6 +141,21 @@ const PREREQS: &[(&str, &[&str])] = &[
|
||||
// window 0, and `FloatingChatFrame_Update` hands `FCF_SetWindowName` a frame it cannot name —
|
||||
// two loader errors, and **137 of this crate's tests** died on them, every one that seats any
|
||||
// part of the chat UI.
|
||||
// `GetDifficultyColor` is a **FrameXML** function (`reference/1.12-globals.tsv` types it
|
||||
// `framexml`, not a client global) and `QuestLogFrame.lua` is what defines it — ten toc rows
|
||||
// above this one. `FriendsFrame.lua:523` calls it for every roster row's level colour, from
|
||||
// four different entry points (`FriendsFrame_Update`, `FriendsFrame_OnEvent`,
|
||||
// `FriendsFrameGuildStatusButton_OnClick`, `GuildFrameGuildListToggleButton_OnClick`), and the
|
||||
// raise takes the rest of the pane's update with it — including the
|
||||
// `GuildPlayerStatusFrame:Show()` at the end of that branch (`:579`), which is how it reads as
|
||||
// "the guild tab opens and the player pane is not visible".
|
||||
//
|
||||
// The `.lua` alone, not `QuestLogFrame.xml`: the functions are what is missing, and the window
|
||||
// would drag its own prerequisites in for frames no guild test looks at.
|
||||
(
|
||||
"friendsframe.xml",
|
||||
&[r"Interface\FrameXML\QuestLogFrame.lua"],
|
||||
),
|
||||
(
|
||||
"floatingchatframe.xml",
|
||||
&[r"Interface\FrameXML\ChatFrame.xml"],
|
||||
|
||||
Reference in New Issue
Block a user