Effects: hiding a 3D effect still checks the values given with it

effect.setParams with visible: false skipped every 3D parameter check,
so a hidden edit could store a Classic depth of 2001, an unknown
surface or bevel, an empty light list or a Revolve edge other than left
or right. The values given are now checked by validate_three_d_params
(the checks of validate_three_d that do not build the art); after a
change of 3D type the values the effect keeps are checked too. The
object still does not need to fit while the effect is hidden.
This commit is contained in:
dotCooCoo
2026-11-08 06:35:39 -08:00
parent f384d27bee
commit 517e0b7ae8
5 changed files with 86 additions and 9 deletions
+50
View File
@@ -46,6 +46,56 @@ fn revolve_commands_keep_profile_live_edit_options_expand_and_undo() {
assert_eq!(effects_for_test(&s, id), before);
}
/// `effect.setParams` checks the values it is given for a 3D effect when the same edit hides it:
/// a bad value is refused and the document is left as it was, and good values are stored.
#[test]
fn hiding_a_3d_effect_still_checks_its_new_values() {
let mut s = Session::new();
s.execute("file.new", &json!({"width": 400, "height": 400})).unwrap();
let rect = |s: &mut Session, x: u32| {
NodeId(s.execute("shape.rectangle", &json!({"x": x, "y": 100, "width": 60, "height": 60})).unwrap()["id"].as_u64().unwrap())
};
let classic = rect(&mut s, 20);
s.execute("effect.apply", &json!({"effect": effects::CLASSIC_EXTRUDE, "ids": [classic.0], "item": null})).unwrap();
let extrude = rect(&mut s, 120);
s.execute("effect.apply", &json!({"effect": effects::EXTRUDE, "ids": [extrude.0], "item": null})).unwrap();
let profile = NodeId(s.execute("path.create", &json!({"d": "M 300 40 L 330 60 L 330 140 L 300 160"})).unwrap()["id"].as_u64().unwrap());
s.execute("effect.apply", &json!({"effect": effects::REVOLVE, "ids": [profile.0], "item": null})).unwrap();
for (id, params, why) in [
(classic, json!({"depth": 2001}), "`depth` must be between 0 and 2000"),
(classic, json!({"surface": "glossy"}), "`surface` must be one of"),
(classic, json!({"bevel": "wavy"}), "bevel must be none or one of"),
(extrude, json!({"lights": []}), "lights must contain one to ten lights"),
(extrude, json!({"lightColor": "red"}), "lightColor must be an opaque RGB color"),
(profile, json!({"edge": "top"}), "Revolve edge must be left or right"),
] {
let before = s.doc().unwrap().doc.clone();
let undo = s.doc().unwrap().history.undo.len();
let p = json!({"ids": [id.0], "index": 0, "item": null, "params": params, "visible": false});
let e = s.execute("effect.setParams", &p).unwrap_err().to_string();
assert!(e.contains(why), "{params}: {e}");
assert_eq!(s.doc().unwrap().doc, before, "{params}");
assert_eq!(s.doc().unwrap().history.undo.len(), undo, "{params}");
}
// A hidden switch of 3D type checks the values given with it for the new type.
let before = s.doc().unwrap().doc.clone();
let p = json!({"ids": [extrude.0], "index": 0, "item": null, "threeDType": "inflate", "params": {"lights": []}, "visible": false});
let e = s.execute("effect.setParams", &p).unwrap_err().to_string();
assert!(e.contains("lights must contain one to ten lights"), "{e}");
assert_eq!(s.doc().unwrap().doc, before);
// Hiding alone checks nothing.
s.execute("effect.setParams", &json!({"ids": [extrude.0], "index": 0, "item": null, "visible": false})).unwrap();
assert!(!node(&s, extrude).appearance.effects[0].visible);
s.execute("effect.setParams", &json!({"ids": [classic.0], "index": 0, "item": null, "params": {"depth": 2000}, "visible": false})).unwrap();
let e = &node(&s, classic).appearance.effects[0];
assert_eq!((e.params["depth"].as_f64(), e.visible), (Some(2000.0), false));
// A value the effect already holds is not checked again: a key it does not take, as a file
// can carry, does not stop a hidden edit of another value.
std::sync::Arc::make_mut(&mut s.doc_mut().unwrap().doc).node_mut(classic).unwrap().appearance.effects[0].params["extra"] = json!(1);
s.execute("effect.setParams", &json!({"ids": [classic.0], "index": 0, "item": null, "params": {"depth": 10}, "visible": false})).unwrap();
assert_eq!(node(&s, classic).appearance.effects[0].params["depth"].as_f64(), Some(10.0));
}
/// Extrude & Bevel, Inflate and Rotate: applied by command, saved and reopened, edited,
/// exported, expanded and undone; one 3D effect per object.
#[test]