engine: test ungrouping a top-level group with a group inside it

Ungrouping a top-level group and a group inside it in one call, in
either order, frees the shapes of both onto the slide in the top-level
group's place, drawn where they were, returns them once each and
selects them. The other ungroup tests leave the outermost group
unnamed, so none checked that the inner group is found at the slide's
top level after the same call frees the group around it.
This commit is contained in:
Simon Koch-Sultan
2026-11-08 15:36:50 -05:00
parent 17db75b74a
commit 70a0d7a2d8
+47
View File
@@ -986,6 +986,53 @@ fn ungrouping_nested_groups_in_any_order_returns_only_freed_shapes() {
assert_eq!(order, [sid(a), sid(b), sid(c), sid(d), sid(e)]);
}
/// Ungrouping a top-level group and a group inside it in one call frees the shapes of both onto
/// the slide, in the top-level group's place and drawn where they were, whichever is named first.
#[test]
fn ungrouping_a_top_level_group_with_a_group_inside_it_frees_both() {
fn rect(s: &mut Session, x: f64, y: f64) -> u64 {
s.execute("shape.insert", &json!({"preset": "rect", "rect": [x, y, 100, 100]})).unwrap()["id"].as_u64().unwrap()
}
fn group(s: &mut Session, ids: [u64; 2]) -> u64 {
s.execute("arrange.group", &json!({"ids": ids})).unwrap()["id"].as_u64().unwrap()
}
let sid = |id: u64| ShapeId(u32::try_from(id).unwrap());
let sites = |s: &Session, id: u64| {
let st = s.doc().unwrap();
connect::sites_of(&st.doc, &st.selection, st.shapes(), sid(id)).unwrap()
};
let roots = |s: &Session| -> Vec<ShapeId> { s.doc().unwrap().shapes().iter().map(|x| x.id).collect() };
for outer_first in [true, false] {
let mut s = session();
s.execute("slide.new", &json!({"layout": "blank"})).unwrap();
let [a, b, c, z] = [(100.0, 100.0), (300.0, 100.0), (100.0, 300.0), (500.0, 500.0)].map(|(x, y)| rect(&mut s, x, y));
let inner = group(&mut s, [a, b]);
let outer = group(&mut s, [inner, c]);
s.execute("shape.resize", &json!({"ids": [outer], "w": 600})).unwrap();
let before = [a, b, c].map(|id| sites(&s, id));
let freed = [sid(a), sid(b), sid(c)];
let mut expected = vec![];
for x in roots(&s) {
if x == sid(outer) {
expected.extend(freed);
} else {
expected.push(x);
}
}
assert!(expected.contains(&sid(z)));
let ids = if outer_first { [outer, inner] } else { [inner, outer] };
let r = s.execute("arrange.ungroup", &json!({"ids": ids})).unwrap();
assert_eq!(r["ids"], json!([a, b, c]), "{ids:?}");
assert_eq!(s.doc().unwrap().selection.shapes, freed, "{ids:?}");
assert_eq!(roots(&s), expected, "{ids:?}");
for (id, was) in [a, b, c].into_iter().zip(before) {
let now = sites(&s, id);
assert_eq!(was.len(), now.len(), "{ids:?}: shape {id}");
assert!(was.iter().zip(&now).all(|(p, q)| (*p - *q).hypot() < 1e-6), "{ids:?}: shape {id} moved from {was:?} to {now:?}");
}
}
}
/// Grouping a group again and again stops at `MAX_GROUP_DEPTH`: past about 39 levels a saved
/// .deckcraft file no longer opens, and past 64 commands such as format.languageAll miss the text.
#[test]