Files
vectorcraft/crates/testkit/src/lib.rs
T
bflatasticandClaude Opus 5.5 e204341996 M4.45: PDF import and place options — pages, Crop To and password
Opening or placing a PDF or .ai with several pages or a password shows the
Import PDF / Place PDF dialog: a page preview with page navigation, Pages
(All or a range) when opening, Crop To (Bounding Box, Art, Crop, Trim, Bleed,
Media) and a password prompt for encrypted files.

- vectorcraft-pdf: ImportOptions.pages / crop / password, CropTo, info()
  (pages, sizes, rotation, boxes); NeedsPassword / WrongPassword / BadPage
  errors; images keyed by content so placed pages merge safely.
- document.open takes pages, page, cropTo (or crop) and password;
  document.pdfInfo (query) lists pages and boxes, reports needsPassword and
  renders a page thumbnail.
- file.place and file.place.info read only the page placed and take every
  PDF box as crop (art, trim, bleed, media besides crop and bounding) and a
  password; the UI's File > Place asks with the dialog when no page is given,
  keeping Link, Template and the other place params.
- testkit::pdf writes hand-made PDFs with page boxes and RC4 encryption.

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

61 lines
2.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! VectorCraft test helpers.
//!
//! - [`fixtures`]: sessions and documents in known states (empty, single/multi selection, a "rich"
//! document touching most node kinds), plus a [`fixtures::DocBuilder`] for building documents
//! directly (render tests).
//! - [`strategies`]: proptest strategies for geometry and for engine command sequences ([`strategies::Op`]), and
//! junk-parameter generators for fuzzing the command registry.
//! - [`invariants`]: structural checks for documents and sessions, and round-trip checks
//! (`.vectorcraft`, SVG, `document.inspect`).
//! - [`raster`]: rendering helpers and image comparison with a perceptual tolerance.
//! - [`geom`]: geometry assertions (approximate equality, curve sampling, Hausdorff distance).
//! - [`pdf`]: hand-written PDF files (page boxes, colour spaces, encryption) for import tests.
//!
//! This crate may only be used as a dev-dependency (enforced by `cargo xtask layers`).
// Test support only (a dev-dependency of every crate that uses it): a failed setup or assertion
// must panic, like `assert!`, so the shipped-code ban on panicking (AGENTS.md › Robustness) doesn't
// apply here.
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
#![forbid(unsafe_code)]
pub mod fixtures;
pub mod geom;
pub mod invariants;
pub mod pdf;
pub mod raster;
pub mod strategies;
pub use serde_json::{Value, json};
pub use vectorcraft_engine::{Session, doc::NodeId};
/// Re-exports so dependents without direct dependencies (e.g. app test crates) can use them.
pub use {vectorcraft_doc as doc, vectorcraft_format as format, vectorcraft_render as render, vectorcraft_svg as svg};
/// A per-process temporary directory for test output (created on first use).
pub fn temp_dir(tag: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!("vectorcraft-testkit-{tag}-{}", std::process::id()));
std::fs::create_dir_all(&dir).expect("create temp dir");
dir
}
thread_local! {
static QUIET: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
}
/// Run `f`, catching a panic without printing it (other threads' panics still print). Returns the
/// panic message on panic.
pub fn catch_quiet<T>(f: impl FnOnce() -> T) -> Result<T, String> {
static HOOK: std::sync::Once = std::sync::Once::new();
HOOK.call_once(|| {
let prev = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
if !QUIET.with(|q| q.get()) {
prev(info);
}
}));
});
QUIET.with(|q| q.set(true));
let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
QUIET.with(|q| q.set(false));
r.map_err(|p| p.downcast_ref::<String>().cloned().or_else(|| p.downcast_ref::<&str>().map(|s| s.to_string())).unwrap_or_else(|| "panic".into()))
}