Files
vectorcraft/crates/ui-egui/src/tests_svg.rs
bflatasticandClaude Opus 5.5 515ce2ac94 M4.14: Save As format chooser, Save writes back its own format, Save a Copy
Save As offers VectorCraft, VectorCraft Template, PDF, SVG and SVGZ and asks
for the chosen format's options before writing: SVG Options for SVG/SVGZ, the
Save PDF dialog for PDF (its OK finishes the save); on the web a Save As
dialog first names the file and picks the format. A document opened from or
saved as SVG/PDF remembers its format and options in one place
(DocState.format, save_options: the SVG options, or every Save PDF setting),
so Save writes it again; the result's warnings name what the format loses,
then the encoder's notes. Save a Copy writes "<name> copy.<ext>" and leaves
the path, title and modified state alone. Save is off for a clean saved
document, and Save as PDF... is in the File menu.

Engine: document.save, file.saveAs and file.saveCopy take {path?, format?,
options?, svg?} (SVG options also flat) and write linked images beside an
SVG; file.formatOptions reads a format's options. save_plan/save_with are the
one save path of every frontend, on the shared SVG encoder (one SVGZ path).
The template format is writable. Save panels get per-format filters, a folder
and a suggested name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:07:15 +07:00

58 lines
2.4 KiB
Rust

//! SVGZ in the app: Place takes it, and a .svgz name (Export As SVG, Save As) writes it.
use std::cell::RefCell;
use std::rc::Rc;
use serde_json::{Value, json};
use vectorcraft_engine::Session;
use crate::{Services, VectorcraftApp, io};
pub(super) type Written = Rc<RefCell<Vec<(String, Vec<u8>)>>>;
/// An app with a rectangle whose save dialog answers `picked`; the writer records its files.
pub(super) fn app(picked: &str) -> (VectorcraftApp, Written) {
let written = Written::default();
let w = written.clone();
let picked = picked.to_string();
let services = Services {
write: Some(Box::new(move |p: &str, b: &[u8]| {
w.borrow_mut().push((p.to_string(), b.to_vec()));
Ok(())
})),
pick_save: Some(Box::new(move |_: &crate::FilePick| Some(picked.clone()))),
..Default::default()
};
let mut app = VectorcraftApp::new(Session::new(), services);
app.run("file.new", json!({"width": 100, "height": 80})).unwrap();
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 40, "height": 30})).unwrap();
(app, written)
}
#[test]
fn svgz_places_like_svg() {
let (mut app, _) = app("/tmp/unused.svg");
let svg = app.session.execute("document.serialize", &json!({"format": "svg"})).unwrap()["text"].as_str().unwrap().to_string();
app.run("file.new", json!({"width": 100, "height": 80})).unwrap();
io::place_bytes(&mut app, "art.svgz", &vectorcraft_svg::compress(&svg)).unwrap();
assert_eq!(app.session.doc().unwrap().selection.objects.len(), 1, "the rectangle was placed");
}
#[test]
fn a_svgz_name_writes_compressed_svg() {
let (mut app, written) = app("/tmp/art.svgz");
// Export As SVG, named .svgz in the save dialog.
app.run("file.export.svg", Value::Null).unwrap();
crate::dialogs::confirm(&mut app).unwrap();
let (path, bytes) = written.borrow()[0].clone();
assert_eq!(path, "/tmp/art.svgz");
assert!(vectorcraft_svg::text_of(&bytes).unwrap().contains("<style>"), "the SVG Options apply");
assert!(vectorcraft_svg::is_svgz(&bytes));
// Save As .svgz asks for SVG Options, then saves compressed and keeps the path.
let r = app.run("file.saveAs", Value::Null).unwrap();
assert_eq!(r["path"], "/tmp/art.svgz");
crate::dialogs::confirm(&mut app).unwrap();
assert!(vectorcraft_svg::is_svgz(&written.borrow()[1].1));
assert_eq!(app.session.active().unwrap().path.as_deref(), Some("/tmp/art.svgz"));
}