From fb7176565d6a9d12718a5dd877662aca81ca1ed7 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Thu, 12 Nov 2026 22:16:56 -0800 Subject: [PATCH] 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. --- crates/engine/tests/import_fuzz.rs | 37 +++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/crates/engine/tests/import_fuzz.rs b/crates/engine/tests/import_fuzz.rs index 1a13af2868..d6a76a772b 100644 --- a/crates/engine/tests/import_fuzz.rs +++ b/crates/engine/tests/import_fuzz.rs @@ -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::(), ) { 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::>().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