Files
benilla-octo/crates/benilla-app/src/ui_script/video_options_tests.rs
T
Sam SungandClaude Opus 5.5 459e0e90c1 The stock video window's boxes are registered and ffx, ffxGlow, ffxDeath and gxMaximize work; benilla's options gain Spell Detail; load failures go to FrameXML.log (#585)
**#549: the stock video window's CVars.** Its check boxes, `ffx` and `gxRefresh` are registered at the reference's defaults. `pixelShaders` and `specular` ship as `overridden` "1" (`hwDetect`, `0x639a60`), and `gxFixLag` ships "1".
- `ffx`, `ffxGlow` and `ffxDeath` gate the full-screen effect passes every frame, as the reference's gate does (`0x6cd890`; `CFFXGlow` reads `ffxGlow` at `0x6cc5a8`, `CFFXDeath` reads `ffxDeath` at `0x6cdf10`).
- `gxMaximize` is latched. At the `RestartGx` commit it makes a windowed client borderless over the monitor, as the reference's window rebuild does (`0x58cf10`).
- The rest are registered with no effect, and each row says why: `useWeatherShaders` (snow's fallback leg is a separate CPU draw), `lod`, `M2UseShaders`, `M2UsePixelShaders`, `movieSubtitle`, `gxTripleBuffer`, `gxCursor`, `gxRefresh`, `DesktopGamma`.
- `cvars.rs` is split into the runtime and the table.

**#329: Spell Detail.** benilla's options window gains 1.12's Spell Detail Level slider on the Graphics page, over `spellEffectLevel` on the stock 0-2 grid.

**#583: `FrameXML.log`.** Load failures now go to `benilla-config/Logs/FrameXML.log`, as the reference's go to `Logs\FrameXML.log`, and no longer to chat.
- The log uses the reference's lines ("Couldn't open", "Error loading", "Couldn't parse XML in") and its banners.
- A UI load that reports something rewrites the file, and a runtime `LoadAddOn` appends to it (`0x490187`, `0x46aac0`).

Verified:
- New tests for each switch, the maximize latch, every box's stored value with no unknown-CVar warning, the Spell Detail row and the log file's rewrite and append, each failing on main.
- A region dump of the options window shows the new row, and the rows below it moved 35 px, and nothing else.
- `scripts/gates.sh` and `scripts/smoke.sh` are green.
- A live run unticked Full Screen Glow in the stock window, which turned the glow pass off and saved `ffxGlow = "0"`, and a missing addon file produced its four log lines.

Built on macOS; no platform seam touched.

Fixes #549
Fixes #329
Fixes #583

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 10:09:02 +07:00

247 lines
9.0 KiB
Rust

//! The stock Video Options window (`OptionsFrame.xml`/`.lua`, off the player's chain) standing on
//! its own: open, every box and slider, Okay, Defaults and Cancel, with no Lua error and the
//! values each verb stores.
use benilla_ui::script::{ScreenResolution, UiScript, UnitState, VideoCaps};
/// A loaded default UI with the display facts the window's `OnLoad`s and `_Load` read.
fn video_ui() -> UiScript {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
s.set_screen_resolutions(
vec![
ScreenResolution {
width: 1280,
height: 720,
},
ScreenResolution {
width: 1920,
height: 1080,
},
],
Some(ScreenResolution {
width: 1600,
height: 900,
}),
);
s.set_video_caps(VideoCaps {
anisotropic: true,
pixel_shaders: true,
vertex_shaders: true,
trilinear: true,
triple_buffering: false,
max_anisotropy: 16,
hardware_cursor: true,
});
s.set_unit(
"player",
Some(UnitState {
exists: true,
name: Some("Probefour".into()),
level: 60,
class: Some("Warrior".into()),
class_file: Some("WARRIOR".into()),
..Default::default()
}),
);
let failures = super::load_default_ui(&s);
assert!(failures.is_empty(), "manifest load errors: {failures:#?}");
s
}
fn cvar(s: &UiScript, name: &str) -> Option<String> {
s.eval::<Option<String>>(&format!("return GetCVar({name:?})"))
.unwrap()
}
fn slider(s: &UiScript, i: usize) -> f64 {
s.eval::<f64>(&format!("return OptionsFrameSlider{i}:GetValue()"))
.unwrap()
}
fn assert_clean(s: &UiScript, step: &str) {
let errors = s.errors();
assert!(errors.is_empty(), "{step} raised: {errors:#?}");
let unknown: Vec<String> = s
.warnings()
.into_iter()
.filter(|w| w.contains("unknown CVar"))
.collect();
assert!(
unknown.is_empty(),
"{step} touched an unregistered CVar: {unknown:#?}"
);
}
/// Every box's `(cvar, stored value, checked)`, over the window's own table
/// (`OptionsFrameCheckButtons`, `OptionsFrame.lua:5-22`); the stored value is `"nil"` when absent.
fn boxes(s: &UiScript) -> Vec<(String, String, bool, bool)> {
s.eval::<Vec<String>>(
r#"local out = {}
for _, v in OptionsFrameCheckButtons do
local b = getglobal("OptionsFrameCheckButton"..v.index)
local bit = function(x) if x then return "1" else return "0" end end
table.insert(out, v.cvar.."|"..(GetCVar(v.cvar) or "nil").."|"..bit(b:GetChecked())
.."|"..bit(b:IsEnabled() == 1))
end
return out"#,
)
.unwrap()
.into_iter()
.map(|row| {
let f: Vec<&str> = row.split('|').collect();
(f[0].to_string(), f[1].to_string(), f[2] == "1", f[3] == "1")
})
.collect()
}
/// Open, walk every box and slider, Okay; reopen and Defaults; reopen, move the gamma and Cancel.
/// Each step runs the stock Lua to its end: an aborted `OptionsFrame_Load` leaves
/// `OptionsFrame.gamma` nil for `OnHide`'s `SetGamma` (`OptionsFrame.lua:260`).
#[test]
fn the_stock_video_window_opens_saves_restores_defaults_and_cancels_clean() {
let _data = benilla_formats::wow_data_or_skip!();
let s = video_ui();
// ── Open: `OptionsFrame_Load` reads every slider through its verb or its CVar. ──
s.run("ShowUIPanel(OptionsFrame)").unwrap();
assert_clean(&s, "opening the window");
assert!(s.eval::<bool>("return OptionsFrame:IsShown()").unwrap());
// Environment Detail: `GetWorldDetail`, stop 1 at the registered `SmallCull` 0.04.
assert_eq!(slider(&s, 3), 1.0);
// Terrain Mip: `GetTerrainMip` is `1 - shadowLevel` (`0x488fbd`), `shadowLevel` "1".
assert_eq!(slider(&s, 4), 0.0);
// Texture Detail: `GetBaseMip` is `1 - baseMip` (`0x48928d`), `baseMip` "0".
assert_eq!(slider(&s, 5), 1.0);
// Spell Detail: the CVar path, `spellEffectLevel` "2".
assert_eq!(slider(&s, 8), 2.0);
// `OptionsFrame_Load:153-154` recorded both for `OnHide`.
assert_eq!(s.eval::<f64>("return OptionsFrame.gamma").unwrap(), 0.0);
assert_eq!(
s.eval::<Option<String>>("return OptionsFrame.desktopGamma")
.unwrap()
.as_deref(),
Some("0"),
"`DesktopGamma` registers \"0\" (`0x402d4d`)"
);
// Every box shows its CVar's stored value: all eighteen are registered, and an enabled box is
// ticked exactly when its value is "1" (`OptionsFrame_Load`'s `EnableCheckBox(button, 1,
// GetCVar(...))`).
let at_open = boxes(&s);
assert_eq!(at_open.len(), 18);
for (cvar, value, checked, enabled) in &at_open {
assert!(value == "0" || value == "1", "{cvar} stores {value:?}");
if *enabled {
assert_eq!(*checked, value == "1", "{cvar}'s box shows its value");
}
}
// ── Every box, then every slider to a position off its default. ──
for i in 1..=18 {
s.run(&format!("OptionsFrameCheckButton{i}:Click()"))
.unwrap();
}
for (i, v) in [
(1, "1.0"),
(2, "777"),
(3, "2"),
(4, "1"),
(5, "0"),
(6, "0.5"),
(7, "5"),
(8, "0"),
(9, "0"),
] {
s.run(&format!("OptionsFrameSlider{i}:SetValue({v})"))
.unwrap();
}
assert_clean(&s, "walking the boxes and sliders");
// ── Okay: `OptionsFrame_Save`, then `OnHide`'s `OptionsFrame_Cancel`. ──
s.run("OptionsFrameOkay:Click()").unwrap();
assert_clean(&s, "Okay");
assert!(!s.eval::<bool>("return OptionsFrame:IsShown()").unwrap());
// `SetWorldDetail(2)`: `frillDensity` 48 and `smallCull` "%f" of 0.01 (`0x488e1e`, `0x488e56`).
assert_eq!(cvar(&s, "frillDensity").as_deref(), Some("48"));
assert_eq!(cvar(&s, "SmallCull").as_deref(), Some("0.010000"));
assert_eq!(s.eval::<f64>("return GetWorldDetail()").unwrap(), 2.0);
// `SetTerrainMip(1)` writes `1 - 1` as "%d" (`0x48901d`-`0x489025`).
assert_eq!(cvar(&s, "shadowLevel").as_deref(), Some("0"));
// `SetBaseMip(0)` writes `trunc(1 - 0)` as "%d" (`0x4892f5`-`0x489301`).
assert_eq!(cvar(&s, "baseMip").as_deref(), Some("1"));
assert_eq!(cvar(&s, "spellEffectLevel").as_deref(), Some("0"));
assert_eq!(cvar(&s, "farclip").as_deref(), Some("777"));
assert_eq!(cvar(&s, "gamma").as_deref(), Some("0.500000"));
// The Use Desktop Gamma box was ticked, `_Save` wrote "1" and the recorded value follows it.
assert_eq!(cvar(&s, "desktopGamma").as_deref(), Some("1"));
// `_Save` stored every box as it was left, and each moved box kept its click.
let saved = boxes(&s);
for (cvar, value, checked, _) in &saved {
assert_eq!(
value,
if *checked { "1" } else { "0" },
"{cvar} kept its box"
);
}
let moved: Vec<&str> = at_open
.iter()
.zip(&saved)
.filter(|(a, b)| a.1 != b.1)
.map(|(a, _)| a.0.as_str())
.collect();
for cvar in [
"ffxGlow",
"specular",
"movieSubtitle",
"lod",
"gxCursor",
"useWeatherShaders",
] {
assert!(
moved.contains(&cvar),
"{cvar} was clicked and saved: {moved:?}"
);
}
// Enable All Shaders is copied into `ffx` (`OptionsFrame.lua:202-204`).
assert_eq!(cvar(&s, "ffx"), cvar(&s, "pixelShaders"));
// ── Defaults: `OptionsFrame_SetDefaults` reads `GetCVarDefault` for `smallCull`,
// `shadowLevel` and `baseMip` (`:431-443`) and ends in `RestoreVideoDefaults`. ──
s.run("ShowUIPanel(OptionsFrame)").unwrap();
assert_clean(&s, "reopening for Defaults");
s.run("OptionsFrameDefaults:Click()").unwrap();
assert_clean(&s, "Defaults");
assert!(!s.eval::<bool>("return OptionsFrame:IsShown()").unwrap());
// `RestoreVideoDefaults` restores the graphics CVars benilla registers among `0x639a60`'s.
for (name, default) in [
("farclip", "350"),
("SmallCull", "0.04"),
("shadowLevel", "1"),
("baseMip", "0"),
("doodadAnim", "1"),
] {
assert_eq!(cvar(&s, name).as_deref(), Some(default), "{name} restored");
}
// ── Cancel: `OnHide` puts back the gamma and desktop gamma recorded at open. ──
s.run("ShowUIPanel(OptionsFrame)").unwrap();
let gamma_at_open = cvar(&s, "gamma");
let desktop_at_open = cvar(&s, "desktopGamma");
s.run("OptionsFrameCheckButton1:SetChecked(nil) OptionsFrameSlider6:SetValue(-0.5) SetGamma(-0.5)")
.unwrap();
s.run("OptionsFrameCancel:Click()").unwrap();
assert_clean(&s, "Cancel");
assert!(!s.eval::<bool>("return OptionsFrame:IsShown()").unwrap());
assert_eq!(
cvar(&s, "gamma"),
gamma_at_open,
"Cancel restores the gamma"
);
assert_eq!(
cvar(&s, "desktopGamma"),
desktop_at_open,
"…and the desktop gamma (`OptionsFrame.lua:261`)"
);
}