vectorcraft/crates/engine/src/tests_flatpresets.rs

137 lines
8.4 KiB
Rust

//! Transparency Flattener Presets (M3.93): built-in presets stay as they are, saved presets are
//! made, changed, renamed and deleted, travel through export/import and persist with the
//! preferences.
use serde_json::{Value, json};
use super::*;
use crate::cmd::{FlattenOptions, FlattenerPreset};
fn run(s: &mut Session, id: &str, p: Value) -> Value {
s.execute(id, &p).unwrap()
}
fn names(s: &mut Session) -> Vec<(String, bool)> {
let list = run(s, "flattener.presets.list", json!({}));
list["presets"].as_array().unwrap().iter().map(|p| (p["name"].as_str().unwrap().to_string(), p["builtIn"].as_bool().unwrap())).collect()
}
#[test]
fn built_in_presets_are_listed_and_protected() {
let mut s = Session::new();
let builtin = [("High Resolution", true), ("Medium Resolution", true), ("Low Resolution", true)].map(|(n, b)| (n.to_string(), b));
assert_eq!(names(&mut s), builtin);
for name in ["High Resolution", "medium", "LOW"] {
assert!(s.execute("flattener.presets.save", &json!({"name": name, "balance": 10})).is_err(), "{name} changed");
assert!(s.execute("flattener.presets.delete", &json!({ "name": name })).is_err(), "{name} deleted");
}
assert!(s.execute("flattener.presets.delete", &json!({"name": "Nope"})).is_err());
assert_eq!(FlattenOptions::preset("high"), FlattenOptions::find_preset("High Resolution", &[]));
assert_eq!(names(&mut s), builtin, "nothing changed");
// A saved preset can't take a built-in name either.
run(&mut s, "flattener.presets.save", json!({"name": "Mine"}));
assert!(s.execute("flattener.presets.save", &json!({"name": "Mine", "newName": "low resolution"})).is_err());
}
#[test]
fn saved_presets_are_made_changed_renamed_and_used() {
let mut s = Session::new();
let r = run(&mut s, "flattener.presets.save", json!({"name": "Press", "preset": "high", "balance": 40}));
assert_eq!((r["name"].as_str(), r["created"].as_bool()), (Some("Press"), Some(true)));
assert_eq!((r["options"]["balance"].as_f64(), r["options"]["lineArtPpi"].as_f64()), (Some(40.0), Some(1200.0)));
// A change starts from the preset's own options.
let r = run(&mut s, "flattener.presets.save", json!({"name": "press", "options": {"antiAlias": false}}));
assert_eq!(
(r["created"].as_bool(), r["options"]["balance"].as_f64(), r["options"]["antiAlias"].as_bool()),
(Some(false), Some(40.0), Some(false))
);
assert_eq!(r["name"], "Press", "the saved name keeps its case");
// Renaming, and names that are taken.
run(&mut s, "flattener.presets.save", json!({"name": "Press", "newName": "Print"}));
run(&mut s, "flattener.presets.save", json!({"name": "Other"}));
assert!(s.execute("flattener.presets.save", &json!({"name": "Print", "newName": "other"})).is_err());
assert!(s.execute("flattener.presets.save", &json!({"name": " "})).is_err());
assert!(s.execute("flattener.presets.save", &json!({"name": "Print", "balance": 101})).is_err(), "options are validated");
// Unnamed presets are numbered.
assert_eq!(run(&mut s, "flattener.presets.save", json!({}))["name"], "Flattener Preset 1");
assert_eq!(run(&mut s, "flattener.presets.save", json!({}))["name"], "Flattener Preset 2");
let saved: Vec<String> = names(&mut s).into_iter().filter(|n| !n.1).map(|n| n.0).collect();
assert_eq!(saved, ["Print", "Other", "Flattener Preset 1", "Flattener Preset 2"]);
// Anywhere options are taken, a saved preset works by name.
let o = s.flatten_options(&json!({"preset": "PRINT"})).unwrap();
assert_eq!((o.balance, o.line_art_ppi, o.anti_alias), (40.0, 1200.0, false));
assert!(s.flatten_options(&json!({"preset": "Gone"})).is_err());
s.execute("file.new", &json!({"width": 100, "height": 100})).unwrap();
let id = run(&mut s, "shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 50}))["id"].clone();
run(&mut s, "transparency.set", json!({"ids": [id], "opacity": 50}));
let r = run(&mut s, "object.flattenTransparency", json!({"ids": [id], "preset": "Print"}));
assert_eq!(r["options"]["balance"], 40.0);
assert_eq!(run(&mut s, "flattener.presets.delete", json!({"name": "print"}))["deleted"], "Print");
assert!(s.execute("object.flattenTransparency", &json!({"preset": "Print"})).is_err());
}
#[test]
fn presets_round_trip_through_export_and_import() {
let mut s = Session::new();
assert!(s.execute("flattener.presets.export", &json!({})).is_err(), "nothing saved to export");
run(&mut s, "flattener.presets.save", json!({"name": "A", "preset": "low", "clipComplexRegions": true}));
run(&mut s, "flattener.presets.save", json!({"name": "B", "balance": 0}));
let saved = s.prefs.flattener_presets.clone();
let out = run(&mut s, "flattener.presets.export", json!({}));
assert_eq!(out["count"], 2);
let data = out["data"].as_str().unwrap().to_string();
for n in ["A", "B"] {
run(&mut s, "flattener.presets.delete", json!({ "name": n }));
}
assert_eq!(run(&mut s, "flattener.presets.import", json!({ "data": data }))["imported"], json!(["A", "B"]));
assert_eq!(s.prefs.flattener_presets, saved, "the same presets come back");
// Names in use get a number, unless the import replaces them.
assert_eq!(run(&mut s, "flattener.presets.import", json!({ "data": data }))["imported"], json!(["A 2", "B 2"]));
run(&mut s, "flattener.presets.save", json!({"name": "A", "balance": 55}));
run(&mut s, "flattener.presets.import", json!({"data": data, "replace": true}));
assert_eq!(s.prefs.flattener_presets[0], saved[0]);
assert_eq!(s.prefs.flattener_presets.len(), 4);
// Built-in presets export by id or name, and import as saved copies.
let b64 = {
let out = run(&mut s, "flattener.presets.export", json!({"names": ["high", "Medium Resolution"]}));
assert_eq!(out["count"], 2);
vectorcraft_format::base64_encode(out["data"].as_str().unwrap().as_bytes())
};
let r = run(&mut s, "flattener.presets.import", json!({ "dataBase64": b64 }));
assert_eq!(r["imported"], json!(["High Resolution 2", "Medium Resolution 2"]));
assert_eq!(s.flatten_options(&json!({"preset": "High Resolution 2"})).unwrap(), FlattenOptions::preset("high").unwrap());
// Files on disk, and what isn't a presets file.
let path = std::env::temp_dir().join(format!("vc-flattener-{}.{}", std::process::id(), crate::cmd::flatten::PRESET_FORMAT));
let path = path.to_string_lossy().to_string();
assert_eq!(run(&mut s, "flattener.presets.export", json!({"names": ["A"], "path": path}))["count"], 1);
assert_eq!(run(&mut s, "flattener.presets.import", json!({ "path": path }))["imported"], json!(["A 3"]));
let _ = std::fs::remove_file(&path);
assert!(s.execute("flattener.presets.export", &json!({"names": ["Nope"]})).is_err());
for bad in [json!({"data": "{}"}), json!({"data": "not json"}), json!({"data": "{\"format\": \"other\", \"presets\": []}"}), json!({})] {
assert!(s.execute("flattener.presets.import", &bad).is_err(), "{bad}");
}
let wild = json!({"format": "vcflattener", "presets": [{"name": "Wild", "options": {"lineArtPpi": 99999}}]}).to_string();
assert!(s.execute("flattener.presets.import", &json!({ "data": wild })).is_err(), "out-of-range values are rejected");
}
#[test]
fn saved_presets_persist_with_the_preferences() {
let mut s = Session::new();
// Preferences saved before presets existed load without any.
let old = json!({"keyboardIncrement": 2.0});
assert!(serde_json::from_value::<Prefs>(old).unwrap().flattener_presets.is_empty());
assert!(Prefs::default().to_json().get("flattenerPresets").is_none(), "nothing saved while there are none");
run(&mut s, "flattener.presets.save", json!({"name": "Keep", "gradientPpi": 72}));
let saved = serde_json::to_string(&s.prefs).unwrap();
let back: Prefs = serde_json::from_str(&saved).unwrap();
assert_eq!(back.flattener_presets, [FlattenerPreset { name: "Keep".into(), options: s.flatten_options(&json!({"preset": "Keep"})).unwrap() }]);
let mut t = Session::new();
t.apply_prefs(back);
assert_eq!(t.flatten_options(&json!({"preset": "keep"})).unwrap().gradient_ppi, 72.0);
// They aren't a preference key, and resetting the preferences keeps them.
assert!(t.execute("prefs.set", &json!({"key": "flattenerPresets", "value": []})).is_err());
run(&mut t, "prefs.reset", json!({}));
assert_eq!(t.prefs.flattener_presets.len(), 1);
assert_eq!(run(&mut t, "prefs.get", json!({}))["prefs"]["flattenerPresets"][0]["name"], "Keep");
}