vectorcraft/crates/engine/src/tests_strokegeom.rs

77 lines
3.5 KiB
Rust

//! Stroke geometry from the Stroke panel's commands (`cmd/stroke.rs`): arrowhead alignment and
//! the width-profile presets.
use serde_json::json;
use vectorcraft_doc::{ArrowAlign, StrokeLayer, WidthProfile};
use super::*;
fn session_with_line() -> (Session, NodeId) {
let mut s = Session::new();
s.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
let r = s.execute("shape.line", &json!({"x1": 10, "y1": 100, "x2": 150, "y2": 100})).unwrap();
(s, NodeId(r["id"].as_u64().unwrap()))
}
fn stroke(s: &Session, id: NodeId) -> StrokeLayer {
s.doc().unwrap().doc.node(id).unwrap().appearance.stroke().unwrap().clone()
}
#[test]
fn arrow_align_is_set_per_stroke_and_validated() {
let (mut s, id) = session_with_line();
assert_eq!(stroke(&s, id).arrow_align, ArrowAlign::Extend);
s.execute("stroke.set", &json!({"endArrow": "TriangleOpen", "arrowAlign": "tip"})).unwrap();
let st = stroke(&s, id);
assert_eq!((st.end_arrow, st.arrow_align), (Some(vectorcraft_doc::Arrowhead::TriangleOpen), ArrowAlign::Tip));
s.execute("stroke.set", &json!({"arrowAlign": "extend", "ids": [id.0]})).unwrap();
assert_eq!(stroke(&s, id).arrow_align, ArrowAlign::Extend);
assert!(s.execute("stroke.set", &json!({"arrowAlign": "middle"})).is_err());
s.execute("edit.undo", &json!({})).unwrap();
assert_eq!(stroke(&s, id).arrow_align, ArrowAlign::Tip);
}
#[test]
fn profiles_come_from_the_preset_catalogue() {
let (mut s, id) = session_with_line();
for p in WidthProfile::PRESETS {
s.execute("stroke.set", &json!({"profile": p.id})).unwrap();
let st = stroke(&s, id);
assert_eq!(WidthProfile::id_of(st.profile.as_ref()), p.id);
}
assert!(stroke(&s, id).profile.is_some());
s.execute("stroke.set", &json!({"profile": "uniform"})).unwrap();
assert!(stroke(&s, id).profile.is_none(), "uniform is the plain stroke");
assert!(s.execute("stroke.set", &json!({"profile": "zigzag"})).is_err());
// The params doc (what agents read) lists every preset and the arrow alignment.
let spec = command_specs().iter().find(|c| c.id == "stroke.set").unwrap();
for p in WidthProfile::PRESETS {
assert!(spec.params.contains(&format!("\"{}\"", p.id)), "{}", p.id);
}
assert!(spec.params.contains("arrowAlign"));
// …and every arrowhead name `startArrow`/`endArrow` accept.
for a in vectorcraft_doc::Arrowhead::ALL {
let name = serde_json::to_value(a).unwrap();
assert!(spec.params.contains(name.as_str().unwrap()), "{name}");
s.execute("stroke.set", &json!({"endArrow": name})).unwrap();
assert_eq!(stroke(&s, id).end_arrow, Some(a));
}
}
#[test]
fn arrow_align_and_profiles_survive_the_native_format() {
let (mut s, id) = session_with_line();
s.execute(
"stroke.set",
&json!({"startArrow": "CircleOpen", "endArrow": "Arrow", "arrowAlign": "tip", "profile": "lens", "dash": [0, 6], "cap": "round"}),
)
.unwrap();
let doc = &s.doc().unwrap().doc;
let back = vectorcraft_format::load(&vectorcraft_format::save(doc, false)).unwrap();
assert_eq!(back.node(id).unwrap().appearance.stroke().unwrap(), &stroke(&s, id));
// A stroke with the default alignment writes nothing new, so older builds read it unchanged.
s.execute("stroke.set", &json!({"arrowAlign": "extend"})).unwrap();
let text = String::from_utf8(vectorcraft_format::save(&s.doc().unwrap().doc, true)).unwrap();
assert!(!text.contains("arrow_align"));
}