Files
benilla-octo/crates/benilla-ui/src/loader/template_name_tests.rs
T
Sam SungandClaude Opus 5.5 87706792cb A frame or region takes no name or id from its template (#839)
An instance with no `name=` took its template's name: `framexml::merge` laid the instance's attributes over the template's, so `name` and `id` carried through. Stock `UIOptionsFrame.xml`'s unnamed `<Button inherits="UIPanelCloseButton">` became the global `UIPanelCloseButton`, with `GetName()` answering it, and any unnamed addon frame did the same to its template's name.

In 1.12.1, `PreLoadXML` (`0x769770`) reads `name` and `id` from the instance node before `LoadXML` walks the templates (`0x76985c`). The texture and font string factories also read `name` once, outside that walk (`0x6f2751`, `0x6f27e1`). So neither is ever inherited.

The merge now drops the template's `name` and `id`. Tests cover an unnamed frame, a named frame (no template id), an unnamed texture and `CreateFrame` with a nil name. All four fail without the fix.

Fixes #394

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:18:42 +07:00

88 lines
2.9 KiB
Rust

//! `name=` and `id=` belong to the node they are written on: `PreLoadXML 0x769770` reads them from
//! the instance before `LoadXML` walks its templates (`0x76985c`), and the region factories read
//! `name` once, outside that walk (`0x6f2751`, `0x6f27e1`).
use crate::framexml;
use crate::loader::load;
use crate::script::UiScript;
const DOC: &str = r#"<Ui>
<Button name="TmpCloseTemplate" id="3" virtual="true">
<Size><AbsDimension x="32" y="32"/></Size>
</Button>
<Texture name="TmpTexTemplate" virtual="true">
<Color r="1" g="0" b="0" a="1"/>
</Texture>
<Frame name="Holder">
<Size><AbsDimension x="64" y="64"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture inherits="TmpTexTemplate"/>
</Layer>
</Layers>
<Frames>
<Button inherits="TmpCloseTemplate"/>
<Button name="$parentClose" inherits="TmpCloseTemplate"/>
</Frames>
</Frame>
</Ui>"#;
fn loaded() -> UiScript {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
let report = load(&s, &framexml::parse(DOC).unwrap(), &|_| None);
assert!(report.errors.is_empty(), "{:?}", report.errors);
s
}
/// Stock `UIOptionsFrame.xml:1477`'s unnamed `<Button inherits="UIPanelCloseButton">` is the
/// shape: in 1.12.1 the template's name is no global and the button answers no name.
#[test]
fn an_unnamed_instance_takes_neither_its_templates_name_nor_its_id() {
let s = loaded();
assert!(
s.eval::<bool>("return TmpCloseTemplate == nil").unwrap(),
"the unnamed instance published the template's name as a global"
);
assert!(s
.eval::<bool>("return ({Holder:GetChildren()})[1]:GetName() == nil")
.unwrap());
assert_eq!(
s.eval::<i64>("return ({Holder:GetChildren()})[1]:GetID()")
.unwrap(),
0
);
}
#[test]
fn a_named_instance_keeps_its_own_name_and_takes_no_template_id() {
let s = loaded();
assert_eq!(
s.eval::<String>("return HolderClose:GetName()").unwrap(),
"HolderClose"
);
assert_eq!(s.eval::<i64>("return HolderClose:GetID()").unwrap(), 0);
}
#[test]
fn an_unnamed_region_takes_no_name_from_its_template() {
let s = loaded();
assert!(s.eval::<bool>("return TmpTexTemplate == nil").unwrap());
assert!(s
.eval::<bool>("return ({Holder:GetRegions()})[1]:GetName() == nil")
.unwrap());
}
/// `CreateFrame` builds its node with the `name` it was given (`0x70622d`), nil included.
#[test]
fn create_frame_with_no_name_stays_unnamed_under_a_named_template() {
let s = loaded();
assert!(s
.eval::<bool>(
"local b = CreateFrame('Button', nil, Holder, 'TmpCloseTemplate') \
return b:GetName() == nil and TmpCloseTemplate == nil"
)
.unwrap());
}