给节点 offset 补上有限数值校验
src-tauri/src/ui_editor/persistence.rs 的 validate_node 现在校验 node.offset.min/max 必须是有限数值,与相邻的 Transform/custom_minimum_size 校验一致;此前只有 Transform 的 anchor/offset 被校验,NaN 或 Infinity 的树级偏移可以存盘,预览按 offset.min 定位时整棵树的渲染会一起失效 同文件新增 rejects_non_finite_node_offset,覆盖「offset 全有限可保存、min 变成 Infinity 后校验失败」
This commit is contained in:
@@ -710,6 +710,11 @@ fn validate_node(
|
|||||||
{
|
{
|
||||||
return Err("UI 节点 Transform 必须是有限数值".to_string());
|
return Err("UI 节点 Transform 必须是有限数值".to_string());
|
||||||
}
|
}
|
||||||
|
if !node.offset.min.iter().all(|value| value.is_finite())
|
||||||
|
|| !node.offset.max.iter().all(|value| value.is_finite())
|
||||||
|
{
|
||||||
|
return Err("UI 节点 offset 必须是有限数值".to_string());
|
||||||
|
}
|
||||||
if node
|
if node
|
||||||
.layout
|
.layout
|
||||||
.transform
|
.transform
|
||||||
@@ -1321,6 +1326,62 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_non_finite_node_offset() {
|
||||||
|
let state: State = serde_json::from_value(serde_json::json!({
|
||||||
|
"ui_trees": [{
|
||||||
|
"src_ui_design": "page",
|
||||||
|
"root": {
|
||||||
|
"id": "root",
|
||||||
|
"layout": {
|
||||||
|
"transform": {
|
||||||
|
"anchor_min": [0.0, 0.0],
|
||||||
|
"anchor_max": [1.0, 1.0],
|
||||||
|
"offset_min": [0.0, 0.0],
|
||||||
|
"offset_max": [0.0, 0.0]
|
||||||
|
},
|
||||||
|
"custom_minimum_size": [0.0, 0.0],
|
||||||
|
"size_flags_horizontal": 1,
|
||||||
|
"size_flags_vertical": 1,
|
||||||
|
"size_flags_stretch_ratio": 1.0,
|
||||||
|
"container": "None"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "根节点",
|
||||||
|
"description": "",
|
||||||
|
"layout_status": "NoProblem",
|
||||||
|
"component_status": "NoProblem",
|
||||||
|
"allow_llm_edit_layout": true,
|
||||||
|
"allow_llm_edit_component": true,
|
||||||
|
"source": "System"
|
||||||
|
},
|
||||||
|
"component": null,
|
||||||
|
"children_display_mode": "Stack",
|
||||||
|
"children": [],
|
||||||
|
"offset": { "min": [0.0, 0.0], "max": [1280.0, 720.0] }
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"ui_design_images": {
|
||||||
|
"page": {
|
||||||
|
"path": "missing.png",
|
||||||
|
"pixel_size": [1280.0, 720.0],
|
||||||
|
"pixels_per_unit": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sprite_assets": {},
|
||||||
|
"font_assets": {}
|
||||||
|
}))
|
||||||
|
.expect("deserialize state with ordered offset");
|
||||||
|
assert_eq!(validate_state(&state), Ok(()));
|
||||||
|
|
||||||
|
let mut invalid = state;
|
||||||
|
invalid.ui_trees[0].root.offset.min[1] = f32::INFINITY;
|
||||||
|
assert_eq!(
|
||||||
|
validate_state(&invalid),
|
||||||
|
Err("UI 节点 offset 必须是有限数值".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recovers_last_valid_state_when_primary_is_corrupt() {
|
fn recovers_last_valid_state_when_primary_is_corrupt() {
|
||||||
let (directory, asset_id) = fixture();
|
let (directory, asset_id) = fixture();
|
||||||
|
|||||||
Reference in New Issue
Block a user