M8: regression tests for one-sided strokes on rounded shapes and XML-forbidden characters in SVG (#1351, #1124) (#1719)

Both reports were checked by running them and are already fixed on main. Pins a rounded rectangle or frame stroking only the side asked for in every alignment, and SVG font families and ids leaving out characters XML forbids.
This commit is contained in:
BFlat
2026-10-31 07:41:40 +07:00
committed by GitHub
parent 3837b08a71
commit bdb6a05976
4 changed files with 58 additions and 2 deletions
+2 -1
View File
File diff suppressed because one or more lines are too long
+31
View File
@@ -321,6 +321,37 @@ fn side_strokes_follow_rounded_corners() {
}
}
/// #1351: a stroke on one side of a rectangle or frame with rounded corners stays on that side, for
/// every alignment, with no stroke on the other edges.
#[test]
fn a_rounded_shape_strokes_only_the_side_asked_for() {
// On each edge, top to left: a point of an outside stroke and one of an inside stroke, which a
// centred stroke covers too.
let edges = [[(70, 18), (70, 21)], [(131, 50), (128, 50)], [(70, 81), (70, 78)], [(8, 50), (11, 50)]];
for kind in [NodeKind::Rectangle, NodeKind::Frame] {
for align in [StrokeAlign::Inside, StrokeAlign::Center, StrokeAlign::Outside] {
for side in 0..4 {
let mut d = figcraft_doc::Document::new("t");
let p = d.first_page().unwrap();
let f = d.create(p, kind.clone(), "F", 10.0, 20.0, 120.0, 60.0).unwrap();
let n = d.get_mut(f).unwrap();
n.corners.radii = [16.0; 4];
n.fills = vec![Paint::solid(Color::WHITE)];
n.strokes = vec![Paint::solid(Color::BLACK)];
n.stroke.align = align;
n.stroke.sides = Some(std::array::from_fn(|i| if i == side { 4.0 } else { 0.0 }));
let pix = render_view(&d, p, &view(150, 100), &Options::default()).unwrap();
let black = |(x, y): (u32, u32)| px(&pix, x, y) == [0, 0, 0, 255];
let at = edges[side][usize::from(align != StrokeAlign::Outside)];
assert!(black(at), "{kind:?} {align:?} side {side} has its stroke at {at:?}");
for (i, edge) in edges.iter().enumerate().filter(|(i, _)| *i != side) {
assert!(!edge.iter().any(|at| black(*at)), "{kind:?} {align:?} side {side} leaves edge {i} alone");
}
}
}
}
}
#[test]
fn mask_clips_siblings() {
let mut d = figcraft_doc::Document::new("t");
+23
View File
@@ -210,6 +210,29 @@ fn live_text_export_drops_xml_forbidden_control_characters() {
}
}
/// #1124: a font family and a layer name (written as an id) with characters XML forbids leave them
/// out too, whatever text itself does, so the file parses.
#[test]
fn ids_and_font_families_drop_xml_forbidden_control_characters() {
use figcraft_doc::TextData;
figcraft_text::scan_system_fonts();
let forbidden = ['\u{0}', '\u{1}', '\u{8}', '\u{b}', '\u{c}', '\u{e}', '\u{1f}', '\u{fffe}', '\u{ffff}'];
let junk: String = forbidden.iter().flat_map(|c| ['x', *c]).collect();
let mut d = Document::new("t");
let page = d.first_page().unwrap();
let mut text = TextData::new(format!("a{junk}b"));
text.style.font_size = 24.0;
text.style.font_family = format!("Font{junk}<&\"");
let id = d.create(page, NodeKind::Text(text), &format!("Layer{junk}"), 0.0, 0.0, 600.0, 40.0).unwrap();
d.get_mut(id).unwrap().fills = vec![Paint::solid(Color::BLACK)];
let svg = export_svg(&d, &[id], &SvgOptions { outline_text: false, include_ids: true, ..SvgOptions::default() }).unwrap();
assert!(!svg.contains(forbidden), "{svg:?}");
assert!(svg.contains("font-family=\"Fontxxxxxxxxx&lt;&amp;&quot;\""), "{svg}");
let mut d2 = Document::new("t2");
let p2 = d2.first_page().unwrap();
assert!(import_svg(&mut d2, svg.as_bytes(), p2, 0.0, 0.0, "x").is_ok(), "{svg:?}");
}
#[test]
fn side_strokes_on_rounded_corners_export_as_their_area() {
// border-l-4 rounded-r-lg: the stroke path is the 4 px bar (60 px tall), drawn even-odd.
+2 -1
View File
File diff suppressed because one or more lines are too long