Tests: the one-paint style fuzz case applies the styles it loads

The fuzz case also loads its .ai library with graphicStyle.loadLibrary,
applies every style to the rich document's objects and then applies a
red 2 pt stroke style read before the fuzzed one, and checks that the
stroke style reaches the objects whenever the fuzzed text is only paint
operators.
This commit is contained in:
dotCooCoo
2026-11-12 22:16:56 -08:00
parent ecb994540c
commit fb7176565d
+31 -6
View File
@@ -4218,9 +4218,11 @@ proptest! {
}
/// Graphic style libraries whose styles are one paint (`/SimpleStyle`): any paint operators in
/// any order, with any operands or none, `Xd` missing or repeated, and the paint left open.
/// any order, with any operands or none, `Xd` missing or repeated, and the paint left open. The
/// library is also loaded in the Graphic Style Libraries panel and its styles applied to artwork.
#[test]
fn ai_style_libraries_of_one_paint_styles_never_panic(
// Each operator, and whether it is a paint operator rather than any text.
ops in prop::collection::vec(prop_oneof![
prop::sample::select(vec![
"0 R", "0 O", "0 1 1 0 K", "1 0 0 0 k", "0 0 0 0 1 0 0 Xa", "0 0 0 0 1 0 0 XA", "0.5 G", "0 g", "K", "Xa",
@@ -4228,20 +4230,43 @@ proptest! {
"1 0 Xd", "0 1 Xd", "1 1 Xd", "0 0 Xd", "1 Xd", "Xd", "0 1 0 0 0 Xy", "1 0.5 1 1 0 Xy", "Xy",
"0 Bb", "2 (Sky) 0 0 0 100 1 0 0 1 0 0 Bg", "0 BB", "(Dots) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] p",
"(Dots) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] P", "0 XR",
]).prop_map(str::to_string),
"[ -~]{0,12}",
]).prop_map(|op| (op.to_string(), true)),
"[ -~]{0,12}".prop_map(|text| (text, false)),
], 0..12),
closed in any::<bool>(),
) {
use vectorcraft_testkit::ai;
let close = if closed { "/Paint ;\n/Def ;\n" } else { "" };
// C, a red 2 pt stroke, comes first, so that it reads whatever A holds.
let header = format!(
"%AI9_BeginArtStyles\n/KnownStyle :\n(A) /Name ,\n/SimpleStyle :\n{}\n{close}/KnownStyle :\n(B) /Name ,\n/SimpleStyle :\n1 0 Xd\n/Paint ;\n/Def ;\n\
%AI9_EndArtStyles\n%AI9_BeginArtStyleList\n(A)\n(B)\n%AI9_EndArtStyleList\n",
ops.join("\n")
"%AI9_BeginArtStyles\n/KnownStyle :\n(C) /Name ,\n/SimpleStyle :\n0 R\n0 1 1 0 K\n2 w\n1 0 Xd\n/Paint ;\n/Def ;\n\
/KnownStyle :\n(A) /Name ,\n/SimpleStyle :\n{}\n{close}/KnownStyle :\n(B) /Name ,\n/SimpleStyle :\n1 0 Xd\n/Paint ;\n/Def ;\n\
%AI9_EndArtStyles\n%AI9_BeginArtStyleList\n(A)\n(B)\n(C)\n%AI9_EndArtStyleList\n",
ops.iter().map(|(op, _)| op.as_str()).collect::<Vec<_>>().join("\n")
);
let library = ai::editing_data(200.0, 100.0, &header);
survive("one-paint style library", || Some(vectorcraft_eps::layered_ai(library.as_bytes(), Document::new(200.0, 100.0), vec![], false, false, 1.0).0))?;
let file = ai::ai(library.as_bytes(), ai::page_pdf());
// How many objects C's look reached, and what applying it answered.
let (mut styled, mut applied) = (0, Value::Null);
survive("one-paint styles applied", || {
let mut s = rich_session();
let p = json!({"dataBase64": vectorcraft_format::base64_encode(&file), "name": "fuzz.ai"});
let library = no_panic(s.execute("graphicStyle.loadLibrary", &p)).ok()?["library"].clone();
no_panic(s.execute("select.all", &json!({}))).ok()?;
// Every style is added and the first one, A when it reads, applied; then C is applied.
let _ = no_panic(s.execute("graphicStyle.addFromLibrary", &json!({"library": library, "apply": true})));
applied = no_panic(s.execute("graphicStyle.addFromLibrary", &json!({"library": library, "names": ["C"], "apply": true}))).ok()?;
let d = (*s.doc().ok()?.doc).clone();
if let Some(look) = applied["applied"].as_str().and_then(|name| d.graphic_style(name)).map(|g| &g.appearance) {
d.walk(|n| styled += usize::from(n.appearance == *look));
}
Some(d)
})?;
// Text that isn't a paint operator can leave a string or a comment open over the style list.
if ops.iter().all(|(_, paint)| *paint) {
prop_assert!(applied["applied"].is_string() && styled > 0, "the stroke style wasn't applied: {applied}");
}
}
/// Objects on Path records of any shape: ids in any order, repeated or missing, any number of