.ai import: tests for Pattern brushes' number counts and an older Art brush's first number

A Pattern brush reads its scale from 3 or more numbers (the older form's
8 too) and isn't read with fewer; an 8-number Art brush is the older form
whatever its first number. The module notes say the count tells the form.
This commit is contained in:
Don Omondi
2026-11-08 03:51:30 -05:00
parent 6abe10583a
commit ba1abb73b0
2 changed files with 31 additions and 5 deletions
+7 -5
View File
@@ -28,10 +28,11 @@
//! [`vectorcraft_brush::ArtBrush`]'s `overlap: false`).
//! - A Scatter, Art or Pattern brush's parameters are fields split by `/`: a number, the art's
//! section names (one for Scatter, five for Art and Pattern, empty where there is none, each
//! after a space for Art and Pattern), more fields, and last 15 numbers. Brushes whose first
//! number is 1, as older files write them, have one field fewer before the numbers and 8 numbers;
//! an Art brush in that form is read from its art's name alone (its numbers aren't known, so it
//! keeps the defaults and its paths their drawn look).
//! after a space for Art and Pattern), more fields, and last 15 numbers. Older files write
//! brushes with first number 1, one field fewer before the numbers and 8 numbers; an Art brush
//! with 8 numbers, whatever its first number, is read from its art's name alone (its numbers
//! aren't known, so it keeps the defaults and its paths their drawn look). A Pattern brush needs
//! only its first 3 numbers (its scale is the third).
//! - Scatter: the size (2, 3), spacing (5, 6) and scatter (8, 9) as (low, high) factors of the
//! art, the rotation in degrees (11, 12), how each varies (4, 7, 10, 13) and whether the
//! rotation follows the path (14), and 1 Tints (1).
@@ -339,7 +340,8 @@ pub(super) fn parse_tool_object(kind: Tool, name: &str, params: &str) -> Result<
}
Tool::Art => {
// The older form's 8 numbers aren't known: its brush keeps the defaults and its
// paths their drawn look. Any other count isn't a form this reads.
// paths their drawn look. The count tells the form, not the first number.
// Any other count isn't a form this reads.
let (colorization, plain) = if let Ok(n15) = <&[f64; 15]>::try_from(n.as_slice()) {
(if n15[1] == 1.0 { Colorization::Tints } else { Colorization::None }, art_is_plain(n15))
} else if n.len() == 8 {
+24
View File
@@ -8225,6 +8225,10 @@ fn an_older_art_brush_comes_in_with_its_art() {
assert_eq!(brush::parse_tool_object(brush::Tool::Art, "Ribbon", bad), Err(brush::BrushError::Values), "{bad}");
}
assert_eq!(brush::parse_tool_object(brush::Tool::Scatter, "Spray", "1 /Dot art/ 0 1 / 1 0 1 0 1 0 0 0"), Err(brush::BrushError::Values));
// 8 numbers are the older form whatever the first number says: read with the defaults.
let d = brush::parse_tool_object(brush::Tool::Art, "Ribbon", "0 / Ribbon art/ / / / / 0 1 / 1 0 1 0 1 0 0 0").unwrap();
let brush::DraftKind::Art { ref brush, ref art, plain } = d.kind else { panic!("art") };
assert_eq!((art.as_str(), plain, brush.colorization), ("Ribbon art", false, vectorcraft_brush::ArtBrush::default().colorization));
let objects = [plugin_object(ART_BRUSH, "Ribbon", OLD_RIBBON), plugin_object(ART_BRUSH, "Bare", "1 / / / / / / 0 1 / 1 0 1 0 1 0 0 0")].concat();
let r = read_ok(&format!("{}{objects}{}", brush_art("Ribbon art", 4.0), layer("")));
let lib = vectorcraft_brush::library(&r.doc);
@@ -8234,6 +8238,26 @@ fn an_older_art_brush_comes_in_with_its_art() {
assert!(r.warnings.iter().any(|w| w.ends_with("Brushes panel (1)")), "{:?}", r.warnings);
}
/// A Pattern brush needs only its first 3 numbers, its scale the third (as a percentage), so the
/// older form's 8 numbers read too; fewer than 3 aren't read.
#[test]
fn a_pattern_brush_reads_its_scale_from_three_or_more_numbers() {
const SLOTS: &str = "1 / Tile one/ Tile two/ / / Tile five/ 0 1 / ";
for numbers in ["1 0 0.5", "1 0 0.5 0 1 0 0 0"] {
let d = brush::parse_tool_object(brush::Tool::Pattern, "Fence", &format!("{SLOTS}{numbers}")).unwrap();
let brush::DraftKind::Pattern { tiles, scale } = d.kind else { panic!("{d:?}") };
assert_eq!(tiles[1].as_deref(), Some("Tile two"), "{numbers}");
assert!((scale - 50.0).abs() < 1e-9, "{numbers}: {scale}");
}
for numbers in ["", "1", "1 0"] {
assert_eq!(
brush::parse_tool_object(brush::Tool::Pattern, "Fence", &format!("{SLOTS}{numbers}")),
Err(brush::BrushError::Values),
"{numbers:?}"
);
}
}
/// A brush's art filled with a pattern the file defines before it is read, with that pattern.
#[test]
fn a_brushs_art_takes_the_patterns_defined_before_it() {