mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-28 21:06:56 -06:00
* Build: line tables only in dev, no debug info for dependencies * Tests: one integration-test binary per crate Each crate's tests/*.rs becomes a module of tests/it/main.rs. Files that install process-wide state (the file io hooks, user aliases, SAVETIME and SAVEFILEPATH, user linetype and pattern files, registered fonts) stay their own test binaries. * xtask ci: nextest, tests without examples, one wasm check call
121 lines
5.0 KiB
Rust
121 lines
5.0 KiB
Rust
//! Other applications' xdata is part of its object, as in AutoCAD: COPY, MIRROR, ARRAY and paste
|
|
//! give the copies the same xdata, so it is saved on them too; the pieces of an exploded object
|
|
//! don't keep it.
|
|
|
|
use cadcraft_engine::Session;
|
|
use cadcraft_engine::doc::{Drawing, EntityKind, Handle, RawTag};
|
|
use serde_json::json;
|
|
|
|
/// A LINE with a hyperlink (`PE_URL`) and another application's data, and an LWPOLYLINE with
|
|
/// the same, read from DXF.
|
|
const DXF: &str = "0\nSECTION\n2\nENTITIES\n\
|
|
0\nLINE\n5\n2A\n8\n0\n10\n0\n20\n0\n30\n0\n11\n10\n21\n0\n31\n0\n\
|
|
1001\nPE_URL\n1000\nhttps://example.com/door-7\n1002\n{\n1000\nDoor 7\n1002\n}\n\
|
|
1001\nACME_TAGS\n1000\nD-07\n1070\n3\n1040\n2.5\n\
|
|
0\nLWPOLYLINE\n5\n2B\n8\n0\n90\n3\n70\n0\n10\n0\n20\n5\n10\n5\n20\n5\n10\n5\n20\n10\n\
|
|
1001\nACME_TAGS\n1000\nP-01\n\
|
|
0\nENDSEC\n0\nEOF\n";
|
|
|
|
fn tags(xdata: &[RawTag]) -> Vec<(i32, String)> {
|
|
xdata.iter().map(|t| (t.code, t.value.trim().to_string())).collect()
|
|
}
|
|
|
|
fn session() -> (Session, Handle, Handle) {
|
|
let d = cadcraft_io::read_dxf(DXF.as_bytes()).unwrap();
|
|
let mut s = Session::empty();
|
|
s.open_drawing(d, "xdata", None);
|
|
let doc = s.doc().unwrap();
|
|
let find = |line: bool| doc.model.iter().find(|e| matches!(e.kind, EntityKind::Line(_)) == line).map(|e| e.handle).unwrap();
|
|
let (l, p) = (find(true), find(false));
|
|
(s, l, p)
|
|
}
|
|
|
|
fn xdata_of(d: &Drawing, h: Handle) -> Vec<(i32, String)> {
|
|
tags(&d.entity(h).unwrap().common.xdata)
|
|
}
|
|
|
|
fn new_handles(s: &Session, before: &[Handle]) -> Vec<Handle> {
|
|
s.doc().unwrap().model.iter().map(|e| e.handle).filter(|h| !before.contains(h)).collect()
|
|
}
|
|
|
|
fn model_handles(s: &Session) -> Vec<Handle> {
|
|
s.doc().unwrap().model.iter().map(|e| e.handle).collect()
|
|
}
|
|
|
|
#[test]
|
|
fn reading_puts_xdata_on_the_entity() {
|
|
let (s, l, p) = session();
|
|
let d = s.doc().unwrap();
|
|
let x = xdata_of(d, l);
|
|
assert_eq!(x.first(), Some(&(1001, "PE_URL".to_string())));
|
|
assert!(x.contains(&(1001, "ACME_TAGS".to_string())) && x.contains(&(1000, "D-07".to_string())));
|
|
assert_eq!(xdata_of(d, p), vec![(1001, "ACME_TAGS".to_string()), (1000, "P-01".to_string())]);
|
|
assert!(d.foreign.entities.values().all(|x| x.xdata.is_empty()), "entity xdata is not kept twice");
|
|
}
|
|
|
|
#[test]
|
|
fn copies_keep_the_xdata() {
|
|
let (mut s, l, _) = session();
|
|
let want = xdata_of(s.doc().unwrap(), l);
|
|
|
|
let before = model_handles(&s);
|
|
s.execute("copy", &json!({ "handles": [l.hex()], "delta": [0, 20] })).unwrap();
|
|
let copied = new_handles(&s, &before);
|
|
assert_eq!(copied.len(), 1);
|
|
assert_eq!(xdata_of(s.doc().unwrap(), copied[0]), want, "COPY");
|
|
|
|
let before = model_handles(&s);
|
|
s.execute("mirror", &json!({ "handles": [l.hex()], "p1": [0, -1], "p2": [10, -1] })).unwrap();
|
|
let mirrored = new_handles(&s, &before);
|
|
assert_eq!(mirrored.len(), 1);
|
|
assert_eq!(xdata_of(s.doc().unwrap(), mirrored[0]), want, "MIRROR");
|
|
|
|
let before = model_handles(&s);
|
|
s.execute("arrayrect", &json!({ "handles": [l.hex()], "rows": 1, "cols": 3, "colSpacing": 20, "associative": false })).unwrap();
|
|
let arrayed = new_handles(&s, &before);
|
|
assert_eq!(arrayed.len(), 2);
|
|
for h in arrayed {
|
|
assert_eq!(xdata_of(s.doc().unwrap(), h), want, "ARRAYRECT");
|
|
}
|
|
|
|
s.execute("copyclip", &json!({ "handles": [l.hex()] })).unwrap();
|
|
let before = model_handles(&s);
|
|
s.execute("pasteclip", &json!({ "at": [100, 100] })).unwrap();
|
|
let pasted = new_handles(&s, &before);
|
|
assert_eq!(pasted.len(), 1);
|
|
assert_eq!(xdata_of(s.doc().unwrap(), pasted[0]), want, "PASTECLIP");
|
|
|
|
// Undo takes the copy away; the original keeps its xdata.
|
|
s.execute("u", &json!({})).unwrap();
|
|
assert!(s.doc().unwrap().entity(pasted[0]).is_none());
|
|
assert_eq!(xdata_of(s.doc().unwrap(), l), want);
|
|
}
|
|
|
|
#[test]
|
|
fn a_copy_saves_its_xdata() {
|
|
let (mut s, l, _) = session();
|
|
s.execute("copy", &json!({ "handles": [l.hex()], "delta": [0, 20] })).unwrap();
|
|
let text = cadcraft_io::write_dxf(s.doc().unwrap());
|
|
let groups: Vec<&str> = text.lines().map(str::trim).collect();
|
|
let count = |code: &str, value: &str| groups.chunks(2).filter(|g| *g == [code, value]).count();
|
|
assert_eq!(count("1001", "PE_URL"), 2, "on the line and on its copy");
|
|
assert_eq!(count("1000", "https://example.com/door-7"), 2);
|
|
assert_eq!((count("2", "PE_URL"), count("2", "ACME_TAGS")), (1, 1), "the applications stay registered");
|
|
let back = cadcraft_io::read_dxf(text.as_bytes()).unwrap();
|
|
let lines: Vec<_> = back.model.iter().filter(|e| matches!(e.kind, EntityKind::Line(_))).collect();
|
|
assert_eq!(lines.len(), 2);
|
|
assert_eq!(tags(&lines[0].common.xdata), tags(&lines[1].common.xdata));
|
|
}
|
|
|
|
#[test]
|
|
fn exploded_pieces_do_not_keep_the_xdata() {
|
|
let (mut s, _, p) = session();
|
|
let before = model_handles(&s);
|
|
s.execute("explode", &json!({ "handles": [p.hex()] })).unwrap();
|
|
let pieces = new_handles(&s, &before);
|
|
assert_eq!(pieces.len(), 2);
|
|
for h in pieces {
|
|
assert!(s.doc().unwrap().entity(h).unwrap().common.xdata.is_empty());
|
|
}
|
|
}
|