146 lines
6.7 KiB
Rust
146 lines
6.7 KiB
Rust
//! Clear deletes its exact targets, including compound members (#786).
|
|
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
|
|
|
|
use serde_json::json;
|
|
use vectorcraft_doc::NodeId;
|
|
use vectorcraft_engine::{EngineError, Session};
|
|
|
|
fn compound() -> (Session, NodeId, NodeId, NodeId) {
|
|
let mut s = Session::new();
|
|
s.execute("file.new", &json!({})).unwrap();
|
|
let mut rectangle =
|
|
|x| NodeId(s.execute("shape.rectangle", &json!({"x": x, "y": 10, "width": 30, "height": 30})).unwrap()["id"].as_u64().unwrap());
|
|
let a = rectangle(10);
|
|
let b = rectangle(50);
|
|
s.execute("select.set", &json!({"ids": [a.0, b.0]})).unwrap();
|
|
let c = NodeId(s.execute("object.compoundPath.make", &json!({})).unwrap()["id"].as_u64().unwrap());
|
|
(s, a, b, c)
|
|
}
|
|
|
|
#[test]
|
|
fn clear_selected_compound_member_preserves_its_sibling_and_is_undoable() {
|
|
let (mut s, a, b, c) = compound();
|
|
s.execute("select.set", &json!({"ids": [a.0]})).unwrap();
|
|
s.execute("edit.clear", &json!({})).unwrap();
|
|
assert!(s.active().unwrap().doc.node(a).is_none());
|
|
assert_eq!(s.active().unwrap().doc.parent_of(b), Some(c));
|
|
assert!(s.active().unwrap().selection.is_empty());
|
|
assert_eq!(s.execute("edit.undo", &json!({})).unwrap()["undone"], "Clear");
|
|
assert_eq!(s.active().unwrap().doc.parent_of(a), Some(c));
|
|
assert_eq!(s.active().unwrap().selection.objects, vec![a]);
|
|
s.execute("edit.redo", &json!({})).unwrap();
|
|
assert!(s.active().unwrap().doc.node(a).is_none());
|
|
assert_eq!(s.active().unwrap().doc.parent_of(b), Some(c));
|
|
}
|
|
|
|
#[test]
|
|
fn clear_explicit_ids_works_without_a_selection_and_overrides_selected_anchors() {
|
|
let (mut s, a, b, c) = compound();
|
|
s.execute("select.none", &json!({})).unwrap();
|
|
let info = s.commands().into_iter().find(|info| info.id == "edit.clear").unwrap();
|
|
assert!(!info.enabled, "the menu stays disabled with no selection");
|
|
s.execute("edit.clear", &json!({"ids": [a.0]})).unwrap();
|
|
assert!(s.active().unwrap().doc.node(a).is_none());
|
|
assert_eq!(s.active().unwrap().doc.parent_of(b), Some(c));
|
|
s.execute("edit.undo", &json!({})).unwrap();
|
|
s.execute("select.anchors", &json!({"id": b.0, "anchors": [[0, 0]]})).unwrap();
|
|
let sibling = s.active().unwrap().doc.node(b).unwrap().clone();
|
|
s.execute("edit.clear", &json!({"ids": [a.0]})).unwrap();
|
|
assert!(s.active().unwrap().doc.node(a).is_none());
|
|
assert_eq!(s.active().unwrap().doc.node(b).unwrap(), &sibling);
|
|
}
|
|
|
|
#[test]
|
|
fn clear_explicit_targets_are_validated_atomically() {
|
|
let (mut s, a, _, _) = compound();
|
|
s.execute("select.none", &json!({})).unwrap();
|
|
for ids in [json!([a.0, 999]), json!([a.0, -1]), json!([a.0, "bad"]), json!([a.0, 2.5]), json!(null), json!(a.0)] {
|
|
let doc = s.active().unwrap().doc.clone();
|
|
let journal = s.journal.clone();
|
|
assert!(matches!(s.execute("edit.clear", &json!({"ids": ids})), Err(EngineError::BadParams { .. })), "{ids}");
|
|
assert_eq!(s.active().unwrap().doc, doc);
|
|
assert_eq!(s.journal, journal);
|
|
}
|
|
assert!(s.execute("edit.clear", &json!({})).is_err());
|
|
assert!(Session::new().execute("edit.clear", &json!({"ids": [a.0]})).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn clear_compound_and_member_together_deletes_the_compound() {
|
|
for explicit in [false, true] {
|
|
let (mut s, a, b, c) = compound();
|
|
s.execute("select.set", &json!({"ids": [a.0, c.0]})).unwrap();
|
|
s.execute("edit.clear", &if explicit { json!({"ids": [a.0, c.0, c.0]}) } else { json!({}) }).unwrap();
|
|
for id in [a, b, c] {
|
|
assert!(s.active().unwrap().doc.node(id).is_none());
|
|
}
|
|
s.execute("edit.undo", &json!({})).unwrap();
|
|
assert_eq!(s.active().unwrap().doc.parent_of(a), Some(c));
|
|
assert_eq!(s.active().unwrap().doc.parent_of(b), Some(c));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn cut_compound_member_keeps_copy_and_delete_targets_consistent() {
|
|
let (mut s, a, b, c) = compound();
|
|
s.execute("select.set", &json!({"ids": [a.0]})).unwrap();
|
|
s.execute("edit.cut", &json!({})).unwrap();
|
|
assert_eq!(s.clipboard.nodes.len(), 1);
|
|
assert_eq!(s.clipboard.nodes[0].id, c);
|
|
assert!(s.active().unwrap().doc.node(c).is_none());
|
|
s.execute("edit.pasteInPlace", &json!({})).unwrap();
|
|
let pasted = s.active().unwrap().selection.objects[0];
|
|
assert_eq!(s.active().unwrap().doc.node(pasted).unwrap().children().unwrap().len(), 2);
|
|
s.execute("edit.undo", &json!({})).unwrap();
|
|
s.execute("edit.undo", &json!({})).unwrap();
|
|
assert_eq!(s.active().unwrap().doc.parent_of(a), Some(c));
|
|
assert_eq!(s.active().unwrap().doc.parent_of(b), Some(c));
|
|
}
|
|
|
|
#[test]
|
|
fn clear_direct_selected_anchors_keeps_the_rest_of_the_path() {
|
|
let (mut s, a, b, c) = compound();
|
|
s.execute("select.anchors", &json!({"id": a.0, "anchors": [[0, 0]]})).unwrap();
|
|
s.execute("edit.clear", &json!({})).unwrap();
|
|
assert_eq!(s.active().unwrap().doc.node(a).unwrap().path_data().unwrap().anchor_count(), 3);
|
|
assert_eq!(s.active().unwrap().doc.parent_of(b), Some(c));
|
|
}
|
|
|
|
#[test]
|
|
fn clear_guides_and_empty_explicit_targets_keep_their_separate_behavior() {
|
|
let (mut s, a, _, _) = compound();
|
|
s.execute("guide.add", &json!({"vertical": true, "pos": 10})).unwrap();
|
|
s.execute("guide.select", &json!({"indexes": [0]})).unwrap();
|
|
let history = s.active().unwrap().history.undo.len();
|
|
let selection = s.active().unwrap().selection.clone();
|
|
s.execute("edit.clear", &json!({"ids": []})).unwrap();
|
|
assert_eq!(s.active().unwrap().history.undo.len(), history);
|
|
assert_eq!(s.active().unwrap().selection, selection);
|
|
assert_eq!(s.active().unwrap().doc.guides.len(), 1);
|
|
s.execute("edit.clear", &json!({})).unwrap();
|
|
assert!(s.active().unwrap().doc.guides.is_empty());
|
|
assert!(s.active().unwrap().doc.node(a).is_some());
|
|
s.execute("edit.undo", &json!({})).unwrap();
|
|
assert_eq!(s.active().unwrap().doc.guides.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn clear_keeps_layers_but_deletes_an_explicitly_targeted_child() {
|
|
let (mut s, a, b, c) = compound();
|
|
let layer = s.active().unwrap().doc.layers[0].id;
|
|
s.execute("select.none", &json!({})).unwrap();
|
|
s.execute("edit.clear", &json!({"ids": [layer.0, a.0]})).unwrap();
|
|
assert!(s.active().unwrap().doc.node(layer).is_some());
|
|
assert!(s.active().unwrap().doc.node(a).is_none());
|
|
assert_eq!(s.active().unwrap().doc.parent_of(b), Some(c));
|
|
}
|
|
|
|
#[test]
|
|
fn cut_direct_selected_anchors_retains_anchor_deletion() {
|
|
let (mut s, a, b, c) = compound();
|
|
s.execute("select.anchors", &json!({"id": a.0, "anchors": [[0, 0]]})).unwrap();
|
|
s.execute("edit.cut", &json!({})).unwrap();
|
|
assert_eq!(s.active().unwrap().doc.node(a).unwrap().path_data().unwrap().anchor_count(), 3);
|
|
assert_eq!(s.active().unwrap().doc.parent_of(b), Some(c));
|
|
}
|