cadcraft/crates/engine/tests/dynamic_block_data.rs

141 lines
6.6 KiB
Rust

//! `blocks.dynamic` and `blocks.list` report a dynamic block's parameters and actions as read
//! from another program's file (kept foreign data, built by hand here).
use std::sync::Arc;
use cadcraft_engine::Session;
use cadcraft_engine::doc::foreign::{Foreign, ForeignExtra, ForeignObject};
use cadcraft_engine::doc::{Handle, RawTag};
use serde_json::json;
fn obj(handle: u64, kind: &str, tags: &[(i32, &str)]) -> ForeignObject {
ForeignObject { handle: Handle(handle), kind: kind.into(), tags: tags.iter().map(|(c, v)| RawTag { code: *c, value: (*v).into() }).collect() }
}
/// A session whose block "Door" has a visibility parameter with two states.
fn session() -> Session {
let mut s = Session::new();
let l = s.execute("line", &json!({ "points": [[0, 0], [1, 0]] })).unwrap()["handles"][0].clone();
s.execute("block", &json!({ "name": "Door", "base": [0, 0], "handles": [l] })).unwrap();
let line = s.doc().unwrap().block("Door").unwrap().entities.handles()[0].hex();
let mut f = Foreign::default();
f.records.insert(("BLOCK_RECORD".into(), "DOOR".into()), ForeignExtra { xdict: Some(Handle(0xF00)), ..Default::default() });
f.objects.push(obj(0xF00, "DICTIONARY", &[(100, "AcDbDictionary"), (3, "ACAD_ENHANCEDBLOCK"), (360, "F01")]));
f.objects.push(obj(0xF01, "ACAD_EVALUATION_GRAPH", &[(100, "AcDbEvalGraph"), (91, "0"), (95, "1"), (360, "F02")]));
f.objects.push(obj(
0xF02,
"BLOCKVISIBILITYPARAMETER",
&[
(100, "AcDbEvalExpr"),
(90, "1"),
(100, "AcDbBlockElement"),
(300, "Visibility State"),
(100, "AcDbBlockParameter"),
(280, "1"),
(100, "AcDbBlock1PtParameter"),
(1010, "2"),
(1020, "3"),
(100, "AcDbBlockVisibilityParameter"),
(301, "Visibility1"),
(302, ""),
(93, "1"),
(331, &line),
(92, "2"),
(303, "Open"),
(94, "1"),
(332, &line),
(95, "0"),
(303, "Closed"),
(94, "0"),
(95, "0"),
],
));
let mut d = s.doc().unwrap().clone();
d.foreign = Arc::new(f);
s.open_drawing(d, "dynamic", None);
s
}
#[test]
fn dynamic_block_data_is_reported() {
let mut s = session();
let list = s.execute("blocks.list", &json!({})).unwrap();
let flags: Vec<_> = list["blocks"].as_array().unwrap().iter().map(|b| (b["name"].as_str().unwrap().to_string(), b["dynamic"].clone())).collect();
assert!(flags.contains(&("Door".into(), json!(true))), "{flags:?}");
let m = s.execute("blocks.dynamic", &json!({ "name": "DOOR" })).unwrap();
let p = &m["parameters"][0];
assert_eq!((p["node"].clone(), p["element"].clone(), p["showProperties"].clone()), (json!(1), json!("Visibility State"), json!(true)));
assert_eq!(p["kind"]["type"], "visibility");
assert_eq!(p["kind"]["label"], "Visibility1");
assert_eq!(p["kind"]["at"], json!({ "x": 2.0, "y": 3.0, "z": 0.0 }));
let states: Vec<_> =
p["kind"]["states"].as_array().unwrap().iter().map(|st| (st["name"].clone(), st["visible"].as_array().unwrap().len())).collect();
assert_eq!(states, [(json!("Open"), 1), (json!("Closed"), 0)]);
assert!(p["kind"]["controlled"][0].is_string(), "handles are hex strings");
assert_eq!(m["actions"], json!([]));
}
#[test]
fn blocks_without_dynamic_data_and_bad_names() {
let mut s = session();
let l = s.execute("line", &json!({ "points": [[0, 0], [1, 1]] })).unwrap()["handles"][0].clone();
s.execute("block", &json!({ "name": "Window", "base": [0, 0], "handles": [l] })).unwrap();
assert_eq!(s.execute("blocks.dynamic", &json!({ "name": "Window" })).unwrap(), json!(null));
assert_eq!(s.execute("blocks.dynamic", &json!({ "name": "*Model_Space" })).unwrap(), json!(null));
for p in [json!({}), json!({ "name": 3 }), json!({ "name": "Nope" }), json!(null)] {
assert!(s.execute("blocks.dynamic", &p).is_err(), "{p}");
}
}
#[test]
fn a_reference_to_a_dynamic_block_reports_its_custom_properties() {
let mut s = session();
// BLOCK made the line a reference to Door, which has Door's own values.
let insert = s.doc().unwrap().model.handles()[0].hex();
let r = s.execute("blocks.reference", &json!({ "handle": insert })).unwrap();
assert_eq!(r["definition"], "Door");
assert_eq!(r["values"], json!({}));
assert_eq!(r["properties"], json!([{ "name": "Visibility1", "value": "Open", "choices": ["Open", "Closed"], "editable": true }]));
// A plain block's reference, objects that aren't references and bad parameters.
let l = s.execute("line", &json!({ "points": [[0, 0], [1, 1]] })).unwrap()["handles"][0].clone();
let plain = s.execute("block", &json!({ "name": "Window", "base": [0, 0], "handles": [l.clone()] })).unwrap()["insert"].clone();
assert_eq!(s.execute("blocks.reference", &json!({ "handle": plain })).unwrap(), json!(null));
let l = s.execute("line", &json!({ "points": [[0, 0], [2, 2]] })).unwrap()["handles"][0].clone();
assert!(s.execute("blocks.reference", &json!({ "handle": l })).is_err());
for p in [json!({}), json!({ "handle": "zz" }), json!({ "handle": "FFFFFF" }), json!(null)] {
assert!(s.execute("blocks.reference", &p).is_err(), "{p}");
}
}
#[test]
fn a_visibility_state_is_changed_in_one_undo_step() {
let mut s = session();
let insert = s.doc().unwrap().model.handles()[0].hex();
let r = s.execute("blocks.reference.set", &json!({ "handle": insert, "name": "Visibility1", "value": "Closed" })).unwrap();
assert_eq!(r["properties"][0]["value"], "Closed");
let block = |s: &Session| match s.doc().unwrap().model.iter().next().map(|e| e.kind.clone()) {
Some(cadcraft_engine::doc::EntityKind::Insert(i)) => i.block,
other => panic!("{other:?}"),
};
assert!(block(&s).starts_with("*U"));
// Still a reference to Door, in its new state.
let r = s.execute("blocks.reference", &json!({ "handle": insert })).unwrap();
assert_eq!((r["definition"].clone(), r["properties"][0]["value"].clone()), (json!("Door"), json!("Closed")));
s.execute("undo", &json!({})).unwrap();
assert_eq!(block(&s), "Door");
let r = s.execute("blocks.reference", &json!({ "handle": insert })).unwrap();
assert_eq!(r["properties"][0]["value"], "Open");
for p in [
json!({ "handle": insert, "name": "Visibility1", "value": "Ajar" }),
json!({ "handle": insert, "name": "Visibility1" }),
json!({ "name": "Visibility1", "value": "Open" }),
json!({ "handle": insert, "value": "Open" }),
] {
assert!(s.execute("blocks.reference.set", &p).is_err(), "{p}");
}
}