Merge pull request #2117 from Silvertree2010/fix/h11295-node-reparent-silently-turns-a-n

Reject negative or fractional index in node.reparent
This commit is contained in:
BFlat authored and GitHub committed 2026-11-12 09:20:42 +07:00
commit f2c593ff6e
2 files changed
+17 -1

No files matched your search

+1 -1
View File
@@ -245,7 +245,7 @@ pub(super) fn stroke_brush(s: &mut Session, p: &Value) -> Result<Value> {
pub(super) fn reparent(s: &mut Session, p: &Value) -> Result<Value> {
let ids = req_targets("node.reparent", s, p)?;
let parent = req_id("node.reparent", p, "parent")?;
let index = num(p, "index").map(|i| i.max(0.0) as usize);
let index = opt_index("node.reparent", p, "index")?;
let doc = s.doc_mut()?;
let ids = z_sorted(doc, &roots(doc, &ids));
// `index` is where the first moved layer ends up among the parent's children (bottom first),
@@ -200,6 +200,22 @@ fn reparent_index_is_the_final_position_in_auto_layout_and_across_parents() {
assert!(kids(&s, row).is_empty());
}
#[test]
fn reparent_rejects_a_negative_or_fractional_index() {
let mut s = Session::new();
let frame = id(&ex(&mut s, "node.create", json!({"type": "frame", "name": "F"})));
let rect = |s: &mut Session, n: &str, parent: NodeId| id(&ex(s, "node.create", json!({"type": "rectangle", "name": n, "parent": parent})));
let (a, b) = (rect(&mut s, "a", frame), rect(&mut s, "b", frame));
let free = id(&ex(&mut s, "node.create", json!({"type": "rectangle", "name": "free"})));
for bad in [json!(-1), json!(1.5), json!("x")] {
let r = s.execute("node.reparent", &json!({"ids": [free], "parent": frame, "index": bad}));
assert!(r.is_err(), "index {bad} accepted");
assert_eq!(kids(&s, frame), [a, b], "the tree is unchanged for index {bad}");
}
ex(&mut s, "node.reparent", json!({"ids": [free], "parent": frame, "index": 0}));
assert_eq!(kids(&s, frame), [free, a, b]);
}
#[test]
fn renaming_several_layers_by_the_documented_codes() {
// Three layers named `names`, bottom to top; (names, params, new names, derivation).