extern crate svgparser; use svgparser::{ xmlparser, }; use svgparser::path::{ Tokenizer, Token, }; use xmlparser::{ FromSpan, }; macro_rules! test { ($name:ident, $text:expr, $( $seg:expr ),*) => ( #[test] fn $name() { let mut s = Tokenizer::from_str($text); $( assert_eq!(s.next().unwrap(), $seg); )* assert_eq!(s.next().is_none(), true); } ) } test!(null, "", ); test!(not_a_path, "q", ); test!(not_a_move_to, "L 20 30", ); test!(stop_on_err_1, "M 10 20 L 30 40 L 50", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 30.0, y: 40.0 } ); test!(move_to_1, "M 10 20", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }); test!(move_to_2, "m 10 20", Token::MoveTo { abs: false, x: 10.0, y: 20.0 }); test!(move_to_3, "M 10 20 30 40 50 60", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 30.0, y: 40.0 }, Token::LineTo { abs: true, x: 50.0, y: 60.0 } ); test!(move_to_4, "M 10 20 30 40 50 60 M 70 80 90 100 110 120", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 30.0, y: 40.0 }, Token::LineTo { abs: true, x: 50.0, y: 60.0 }, Token::MoveTo { abs: true, x: 70.0, y: 80.0 }, Token::LineTo { abs: true, x: 90.0, y: 100.0 }, Token::LineTo { abs: true, x: 110.0, y: 120.0 } ); test!(arc_to_1, "M 10 20 A 5 5 30 1 1 20 20", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::EllipticalArc { abs: true, rx: 5.0, ry: 5.0, x_axis_rotation: 30.0, large_arc: true, sweep: true, x: 20.0, y: 20.0 } ); test!(arc_to_2, "M 10 20 a 5 5 30 0 0 20 20", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::EllipticalArc { abs: false, rx: 5.0, ry: 5.0, x_axis_rotation: 30.0, large_arc: false, sweep: false, x: 20.0, y: 20.0 } ); test!(arc_to_10, "M10-20A5.5.3-4 010-.1", Token::MoveTo { abs: true, x: 10.0, y: -20.0 }, Token::EllipticalArc { abs: true, rx: 5.5, ry: 0.3, x_axis_rotation: -4.0, large_arc: false, sweep: true, x: 0.0, y: -0.1 } ); test!(separator_1, "M 10 20 L 5 15 C 10 20 30 40 50 60", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 5.0, y: 15.0 }, Token::CurveTo { abs: true, x1: 10.0, y1: 20.0, x2: 30.0, y2: 40.0, x: 50.0, y: 60.0, } ); test!(separator_2, "M 10, 20 L 5, 15 C 10, 20 30, 40 50, 60", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 5.0, y: 15.0 }, Token::CurveTo { abs: true, x1: 10.0, y1: 20.0, x2: 30.0, y2: 40.0, x: 50.0, y: 60.0, } ); test!(separator_3, "M 10,20 L 5,15 C 10,20 30,40 50,60", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 5.0, y: 15.0 }, Token::CurveTo { abs: true, x1: 10.0, y1: 20.0, x2: 30.0, y2: 40.0, x: 50.0, y: 60.0, } ); test!(separator_4, "M10, 20 L5, 15 C10, 20 30 40 50 60", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 5.0, y: 15.0 }, Token::CurveTo { abs: true, x1: 10.0, y1: 20.0, x2: 30.0, y2: 40.0, x: 50.0, y: 60.0, } ); test!(separator_5, "M10 20V30H40V50H60Z", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::VerticalLineTo { abs: true, y: 30.0 }, Token::HorizontalLineTo { abs: true, x: 40.0 }, Token::VerticalLineTo { abs: true, y: 50.0 }, Token::HorizontalLineTo { abs: true, x: 60.0 }, Token::ClosePath { abs: true } ); test!(all_segments_1, "M 10 20 L 30 40 H 50 V 60 C 70 80 90 100 110 120 S 130 140 150 160 Q 170 180 190 200 T 210 220 A 50 50 30 1 1 230 240 Z", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 30.0, y: 40.0 }, Token::HorizontalLineTo { abs: true, x: 50.0 }, Token::VerticalLineTo { abs: true, y: 60.0 }, Token::CurveTo { abs: true, x1: 70.0, y1: 80.0, x2: 90.0, y2: 100.0, x: 110.0, y: 120.0, }, Token::SmoothCurveTo { abs: true, x2: 130.0, y2: 140.0, x: 150.0, y: 160.0, }, Token::Quadratic { abs: true, x1: 170.0, y1: 180.0, x: 190.0, y: 200.0, }, Token::SmoothQuadratic { abs: true, x: 210.0, y: 220.0 }, Token::EllipticalArc { abs: true, rx: 50.0, ry: 50.0, x_axis_rotation: 30.0, large_arc: true, sweep: true, x: 230.0, y: 240.0 }, Token::ClosePath { abs: true } ); test!(all_segments_2, "m 10 20 l 30 40 h 50 v 60 c 70 80 90 100 110 120 s 130 140 150 160 q 170 180 190 200 t 210 220 a 50 50 30 1 1 230 240 z", Token::MoveTo { abs: false, x: 10.0, y: 20.0 }, Token::LineTo { abs: false, x: 30.0, y: 40.0 }, Token::HorizontalLineTo { abs: false, x: 50.0 }, Token::VerticalLineTo { abs: false, y: 60.0 }, Token::CurveTo { abs: false, x1: 70.0, y1: 80.0, x2: 90.0, y2: 100.0, x: 110.0, y: 120.0, }, Token::SmoothCurveTo { abs: false, x2: 130.0, y2: 140.0, x: 150.0, y: 160.0, }, Token::Quadratic { abs: false, x1: 170.0, y1: 180.0, x: 190.0, y: 200.0, }, Token::SmoothQuadratic { abs: false, x: 210.0, y: 220.0 }, Token::EllipticalArc { abs: false, rx: 50.0, ry: 50.0, x_axis_rotation: 30.0, large_arc: true, sweep: true, x: 230.0, y: 240.0 }, Token::ClosePath { abs: false } ); test!(close_path_1, "M10 20 L 30 40 ZM 100 200 L 300 400", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 30.0, y: 40.0 }, Token::ClosePath { abs: true }, Token::MoveTo { abs: true, x: 100.0, y: 200.0 }, Token::LineTo { abs: true, x: 300.0, y: 400.0 } ); test!(close_path_2, "M10 20 L 30 40 zM 100 200 L 300 400", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 30.0, y: 40.0 }, Token::ClosePath { abs: false }, Token::MoveTo { abs: true, x: 100.0, y: 200.0 }, Token::LineTo { abs: true, x: 300.0, y: 400.0 } ); test!(close_path_3, "M10 20 L 30 40 Z Z Z", Token::MoveTo { abs: true, x: 10.0, y: 20.0 }, Token::LineTo { abs: true, x: 30.0, y: 40.0 }, Token::ClosePath { abs: true }, Token::ClosePath { abs: true }, Token::ClosePath { abs: true } ); // first token should be EndOfStream test!(invalid_1, "M\t.", ); // ClosePath can't be followed by a number test!(invalid_2, "M 0 0 Z 2", Token::MoveTo { abs: true, x: 0.0, y: 0.0 }, Token::ClosePath { abs: true } ); // ClosePath can be followed by any command test!(invalid_3, "M 0 0 Z H 10", Token::MoveTo { abs: true, x: 0.0, y: 0.0 }, Token::ClosePath { abs: true }, Token::HorizontalLineTo { abs: true, x: 10.0 } );