Files
cadcraft/crates/engine/tests/it/options_profile.rs
aiongg 9cf115e808 CI: one test binary per crate, nextest, line tables only (#1989)
* 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
2026-10-23 13:34:26 -04:00

189 lines
8.4 KiB
Rust

//! OPTIONS: the JSON form reads and sets the user-profile variables without a dialog.
use cadcraft_engine::Session;
use cadcraft_engine::cmd::options::{PROFILE_VARS, profile, restore};
use serde_json::json;
#[test]
fn options_json_reports_sets_and_resets_the_profile() {
let mut s = Session::new();
let all = s.execute("options", &json!({})).unwrap();
for name in PROFILE_VARS {
assert!(all.get(*name).is_some(), "{name} is reported");
}
assert_eq!(all["PICKBOX"], json!(3.0));
// Names in any case; the reply is the whole profile.
let r = s.execute("options", &json!({"pickbox": 6, "GRIPSIZE": 9, "PICKFIRST": 0, "CursorSize": 25})).unwrap();
assert_eq!(
(r["PICKBOX"].clone(), r["GRIPSIZE"].clone(), r["PICKFIRST"].clone(), r["CURSORSIZE"].clone()),
(json!(6.0), json!(9.0), json!(0), json!(25.0))
);
assert_eq!(s.execute("getvar", &json!({"name": "PICKBOX"})).unwrap()["value"], json!(6.0));
// All or nothing: a bad name or value changes nothing.
assert!(s.execute("options", &json!({"PICKBOX": 2, "LUNITS": 4})).is_err(), "drawing variables are not profile settings");
assert!(s.execute("options", &json!({"APERTURE": 20, "SNAPUNIT": "wide"})).is_err());
assert!(s.execute("options", &json!({"reset": "yes"})).is_err());
assert!(s.execute("options", &json!([1, 2])).is_err());
let now = s.execute("options", &json!({})).unwrap();
assert_eq!((now["PICKBOX"].clone(), now["APERTURE"].clone()), (json!(6.0), json!(10.0)));
// Reset, then apply in the same call.
let r = s.execute("options", &json!({"reset": true, "APERTURE": 15})).unwrap();
assert_eq!((r["PICKBOX"].clone(), r["GRIPSIZE"].clone(), r["APERTURE"].clone()), (json!(3.0), json!(5.0), json!(15.0)));
}
#[test]
fn saved_profile_restores_and_hostile_entries_are_skipped() {
let mut a = Session::new();
a.execute("options", &json!({"OSMODE": 515, "ORTHOMODE": 1, "POLARANG": 15, "GRIDUNIT": [2, 2], "DYNMODE": 0, "QPMODE": 1})).unwrap();
let saved = profile(&a);
let mut b = Session::new();
restore(&mut b, &saved);
assert_eq!(profile(&b), saved);
// Unknown names, drawing variables, bad values and non-objects are ignored, never panic.
let mut c = Session::new();
restore(&mut c, &json!({"PICKBOX": "huge", "LUNITS": 4, "NOPE": 1, "POLARANG": -5, "SNAPUNIT": ["x"], "GRIPSIZE": 8}));
restore(&mut c, &json!("not an object"));
restore(&mut c, &json!(null));
let p = profile(&c);
assert_eq!((p["PICKBOX"].clone(), p["GRIPSIZE"].clone()), (json!(3.0), json!(8.0)));
assert_ne!(c.execute("getvar", &json!({"name": "LUNITS"})).ok().map(|v| v["value"].clone()), Some(json!(4)));
}
#[test]
fn typed_options_without_a_dialog_reports_how_to_change_settings() {
let mut s = Session::new();
s.cmdline("OP").unwrap();
assert!(s.log.iter().any(|l| l.contains("SETVAR")), "{:?}", s.log);
}
fn getvar(s: &mut Session, name: &str) -> serde_json::Value {
s.execute("getvar", &json!({"name": name})).unwrap()["value"].clone()
}
#[test]
fn selection_highlight_variables() {
let mut s = Session::new();
// AutoCAD's defaults: highlighted, the colour effect, preview with and without a command,
// the preview dashed and thicker.
for (name, v) in [("HIGHLIGHT", 1), ("SELECTIONEFFECT", 1), ("SELECTIONPREVIEW", 3), ("PREVIEWEFFECT", 2)] {
assert_eq!(getvar(&mut s, name), json!(v), "{name}");
}
s.execute("setvar", &json!({"name": "HIGHLIGHT", "value": 0})).unwrap();
s.execute("options", &json!({"SELECTIONEFFECT": 0, "SELECTIONPREVIEW": 2, "PREVIEWEFFECT": 1})).unwrap();
let saved = profile(&s);
assert_eq!(saved["SELECTIONEFFECT"], json!(0));
// HIGHLIGHT lasts the session only (AutoCAD doesn't save it either): not in the profile, and
// OPTIONS, which sets profile variables, refuses it.
assert!(saved.get("HIGHLIGHT").is_none());
assert!(s.execute("options", &json!({"HIGHLIGHT": 0})).is_err());
for (name, value) in [("SELECTIONEFFECT", json!(2)), ("SELECTIONPREVIEW", json!(4)), ("PREVIEWEFFECT", json!(-1)), ("PREVIEWEFFECT", json!("x"))]
{
assert!(s.execute("setvar", &json!({"name": name, "value": value})).is_err(), "{name} {value}");
}
assert_eq!(getvar(&mut s, "SELECTIONPREVIEW"), json!(2), "a refused value changes nothing");
// A new session restores the profile and starts highlighted, even from a profile saved
// with HIGHLIGHT 0 by a build that kept it.
let mut t = Session::new();
let mut old = saved.clone();
old["HIGHLIGHT"] = json!(0);
restore(&mut t, &old);
assert_eq!((getvar(&mut t, "HIGHLIGHT"), getvar(&mut t, "SELECTIONPREVIEW"), getvar(&mut t, "PREVIEWEFFECT")), (json!(1), json!(2), json!(1)));
}
#[test]
fn selection_preview_follows_its_bits() {
let mut s = Session::new();
s.settings.pickfirst = true;
s.settings.selectionpreview = 3;
assert!(s.previews_selection(), "no command, bit 1");
s.settings.selectionpreview = 2;
assert!(!s.previews_selection(), "bit 1 off");
s.start("erase").unwrap();
assert!(s.picking_objects());
assert!(s.previews_selection(), "ERASE asks for objects, bit 2");
s.settings.selectionpreview = 1;
assert!(!s.previews_selection(), "bit 2 off");
}
#[test]
fn selection_tab_variables_have_autocads_defaults_ranges_and_are_saved() {
let mut s = Session::new();
for (name, v) in [
("PREVIEWFILTER", json!(3)),
("GRIPS", json!(1)),
("GRIPOBJLIMIT", json!(100)),
("SELECTIONAREA", json!(1)),
("WINDOWAREACOLOR", json!(150)),
("CROSSINGAREACOLOR", json!(100)),
("SELECTIONAREAOPACITY", json!(25)),
] {
assert_eq!(getvar(&mut s, name), v, "{name}");
}
s.execute("options", &json!({"PREVIEWFILTER": 20, "GRIPS": 0, "GRIPOBJLIMIT": 0, "SELECTIONAREA": 0, "WINDOWAREACOLOR": 5, "CROSSINGAREACOLOR": 3, "SELECTIONAREAOPACITY": 80, "PICKSTYLE": 0})).unwrap();
for (name, value) in [
("PREVIEWFILTER", json!(64)),
("GRIPS", json!(3)),
("GRIPOBJLIMIT", json!(40_000)),
("WINDOWAREACOLOR", json!(0)),
("CROSSINGAREACOLOR", json!(256)),
("SELECTIONAREAOPACITY", json!(101)),
] {
assert!(s.execute("setvar", &json!({"name": name, "value": value})).is_err(), "{name} {value}");
}
let mut t = Session::new();
restore(&mut t, &profile(&s));
assert_eq!(
(
getvar(&mut t, "PREVIEWFILTER"),
getvar(&mut t, "GRIPS"),
getvar(&mut t, "SELECTIONAREA"),
getvar(&mut t, "WINDOWAREACOLOR"),
getvar(&mut t, "PICKSTYLE")
),
(json!(20), json!(0), json!(0), json!(5), json!(0)),
"saved with the profile"
);
}
#[test]
fn grips_show_up_to_the_object_limit() {
let mut s = Session::new();
assert!(s.shows_grips(100) && !s.shows_grips(101), "GRIPOBJLIMIT 100");
s.settings.gripobjlimit = 0;
assert!(s.shows_grips(100_000), "0: no limit");
s.settings.grips = 0;
assert!(!s.shows_grips(1), "GRIPS 0");
}
#[test]
fn preview_filter_excludes_each_kind_it_names() {
use cadcraft_engine::select::preview_filtered;
let mut s = Session::new();
s.execute("mtext", &json!({"at": [0, 0], "text": "NOTE", "height": 2})).unwrap();
s.execute("rectang", &json!({"p1": [10, 0], "p2": [20, 10]})).unwrap();
s.execute("hatch", &json!({"points": [[15, 5]], "pattern": "SOLID"})).unwrap();
s.execute("line", &json!({"points": [[30, 0], [40, 0]]})).unwrap();
let d = s.doc().unwrap();
let find = |k: &str| d.model.iter().find(|e| e.kind.type_name() == k).unwrap().clone();
let (mtext, hatch, line) = (find("MText"), find("Hatch"), find("Line"));
assert!(preview_filtered(d, &mtext, 8) && !preview_filtered(d, &mtext, 16));
assert!(preview_filtered(d, &hatch, 16) && !preview_filtered(d, &hatch, 8));
assert!(!preview_filtered(d, &line, 63), "a line on an unlocked layer, in no group");
// Locked layers (1) and groups (32).
let d = s.doc_mut().unwrap();
d.ensure_layer("LOCKED");
if let Some(l) = d.layers.iter_mut().find(|l| l.name == "LOCKED") {
l.locked = true;
}
d.model.modify(line.handle, |e| e.common.layer = "LOCKED".into());
d.groups.push(cadcraft_engine::doc::Group { name: "G".into(), description: String::new(), selectable: true, members: vec![mtext.handle] });
let d = s.doc().unwrap();
let line = d.entity(line.handle).unwrap();
assert!(preview_filtered(d, line, 1) && !preview_filtered(d, line, 62));
assert!(preview_filtered(d, &mtext, 32));
}