1use path::math::Point;
2use path::PathEvent;
3use path::{Path, PathSlice};
4
5pub type Polygons = Vec<Vec<Point>>;
6pub type PolygonsRef<'a> = &'a [Vec<Point>];
7
8pub fn path_to_polygons(path: PathSlice) -> Polygons {
9 let mut polygons = Vec::new();
10 let mut poly = Vec::new();
11 for evt in path {
12 match evt {
13 PathEvent::Begin { at } => {
14 if !poly.is_empty() {
15 polygons.push(poly);
16 }
17 poly = vec![at];
18 }
19 PathEvent::Line { to, .. } => {
20 poly.push(to);
21 }
22 PathEvent::End { .. } => {
23 if !poly.is_empty() {
24 polygons.push(poly);
25 }
26 poly = Vec::new();
27 }
28 _ => {
29 println!(
30 " -- path_to_polygons: warning! Unsupported event type {:?}",
31 evt
32 );
33 }
34 }
35 }
36 polygons
37}
38
39pub fn polygons_to_path(polygons: PolygonsRef) -> Path {
40 let mut builder: NoAttributes> = Path::builder().flattened(tolerance:0.05);
41 for poly: &Vec> in polygons.iter() {
42 let mut poly_iter: Iter<'_, Point2D> = poly.iter();
43 builder.begin(*poly_iter.next().unwrap());
44 for v: &Point2D in poly_iter {
45 builder.line_to(*v);
46 }
47 builder.close();
48 }
49 builder.build()
50}
51
52pub fn find_reduced_test_case<F: Fn(Path) -> bool + panic::UnwindSafe + panic::RefUnwindSafe>(
53 path: PathSlice,
54 cb: &F,
55) -> Path {
56 let mut polygons = path_to_polygons(path);
57
58 println!(" -- removing sub-paths...");
59
60 polygons = find_reduced_test_case_sp(polygons, cb);
61
62 println!(" -- removing vertices...");
63
64 for p in 0..polygons.len() {
65 let mut v = 0;
66 loop {
67 if v >= polygons[p].len() || polygons[p].len() <= 3 {
68 break;
69 }
70
71 let mut cloned = polygons.clone();
72 cloned[p].remove(v);
73
74 let path = polygons_to_path(&cloned);
75
76 let failed = panic::catch_unwind(|| cb(path)).unwrap_or(true);
77
78 if failed {
79 polygons = cloned;
80 continue;
81 }
82
83 v += 1;
84 }
85 }
86
87 let path = polygons_to_path(&polygons);
88 println!(" ----------- reduced test case: -----------\n\n");
89 println!("#[test]");
90 println!("fn reduced_test_case() {{");
91 println!(" let mut builder = Path::builder();\n");
92 for poly in &polygons {
93 let mut poly_iter = poly.iter();
94 let pos = *poly_iter.next().unwrap();
95 println!(" builder.begin(point({:.}, {:.}));", pos.x, pos.y);
96 for pos in poly_iter {
97 println!(" builder.line_to(point({:.}, {:.}));", pos.x, pos.y);
98 }
99 println!(" builder.close();\n");
100 }
101 println!(" test_path(builder.build().as_slice());\n");
102 println!(" // SVG path syntax:");
103 println!(" // \"{:?}\"", path);
104 println!("}}\n\n");
105
106 path
107}
108
109use std::panic;
110
111fn find_reduced_test_case_sp<F>(mut polygons: Polygons, cb: &F) -> Polygons
112where
113 F: Fn(Path) -> bool + panic::UnwindSafe + panic::RefUnwindSafe,
114{
115 let mut i: usize = 0;
116 loop {
117 if i >= polygons.len() {
118 return polygons;
119 }
120
121 let mut cloned: Vec>> = polygons.clone();
122 cloned.remove(index:i);
123 let path: Path = polygons_to_path(&cloned);
124
125 let failed: bool = panic::catch_unwind(|| cb(path)).unwrap_or(default:true);
126
127 if failed {
128 polygons = cloned;
129 continue;
130 }
131
132 i += 1;
133 }
134}
135