use leptos::either::EitherOf7;
use leptos::prelude::*;
#[derive(Debug, Clone)]
pub enum SvgElement {
Path { d: String },
Circle { cx: String, cy: String, r: String },
Rect { x: String, y: String, width: String, height: String, rx: Option<String>, ry: Option<String> },
Ellipse { cx: String, cy: String, rx: String, ry: String },
Line { x1: String, y1: String, x2: String, y2: String },
Polyline { points: String },
Polygon { points: String },
}
impl SvgElement {
pub fn to_leptos_view(&self) -> impl IntoView + use<> {
match self {
SvgElement::Path { d } => EitherOf7::A(view! { <path d=d /> }),
SvgElement::Circle { cx, cy, r } => EitherOf7::B(view! { <circle cx=cx cy=cy r=r /> }),
SvgElement::Rect { x, y, width, height, rx, ry } => EitherOf7::C(match (rx, ry) {
(Some(rx), Some(ry)) => view! { <rect x=x y=y width=width height=height rx=rx ry=ry /> },
(Some(rx), None) => view! { <rect x=x y=y width=width height=height rx=rx /> },
(None, Some(ry)) => view! { <rect x=x y=y width=width height=height ry=ry /> },
(None, None) => view! { <rect x=x y=y width=width height=height /> },
}),
SvgElement::Ellipse { cx, cy, rx, ry } => EitherOf7::D(view! { <ellipse cx=cx cy=cy rx=rx ry=ry /> }),
SvgElement::Line { x1, y1, x2, y2 } => EitherOf7::E(view! { <line x1=x1 y1=y1 x2=x2 y2=y2 /> }),
SvgElement::Polyline { points } => EitherOf7::F(view! { <polyline points=points /> }),
SvgElement::Polygon { points } => EitherOf7::G(view! { <polygon points=points /> }),
}
}
}
pub fn parse_svg_elements(svg_content: &str) -> Vec<SvgElement> {
svg_content
.lines()
.filter_map(|line| {
let line = line.trim();
if line.is_empty() {
return None;
}
if line.starts_with("<path ") {
parse_path_element(line)
} else if line.starts_with("<circle ") {
parse_circle_element(line)
} else if line.starts_with("<rect ") {
parse_rect_element(line)
} else if line.starts_with("<ellipse ") {
parse_ellipse_element(line)
} else if line.starts_with("<line ") {
parse_line_element(line)
} else if line.starts_with("<polyline ") {
parse_polyline_element(line)
} else if line.starts_with("<polygon ") {
parse_polygon_element(line)
} else {
None
}
})
.collect()
}
fn extract_attribute(line: &str, attr: &str) -> Option<String> {
if let Some(start) = line.find(&format!("{}=\"", attr)) {
let start = start + attr.len() + 2; if let Some(end) = line[start..].find('"') {
return Some(line[start..start + end].to_string());
}
}
None
}
fn parse_path_element(line: &str) -> Option<SvgElement> {
extract_attribute(line, "d").map(|d| SvgElement::Path { d })
}
fn parse_circle_element(line: &str) -> Option<SvgElement> {
let cx = extract_attribute(line, "cx")?;
let cy = extract_attribute(line, "cy")?;
let r = extract_attribute(line, "r")?;
Some(SvgElement::Circle { cx, cy, r })
}
fn parse_rect_element(line: &str) -> Option<SvgElement> {
let x = extract_attribute(line, "x")?;
let y = extract_attribute(line, "y")?;
let width = extract_attribute(line, "width")?;
let height = extract_attribute(line, "height")?;
let rx = extract_attribute(line, "rx");
let ry = extract_attribute(line, "ry");
Some(SvgElement::Rect { x, y, width, height, rx, ry })
}
fn parse_ellipse_element(line: &str) -> Option<SvgElement> {
let cx = extract_attribute(line, "cx")?;
let cy = extract_attribute(line, "cy")?;
let rx = extract_attribute(line, "rx")?;
let ry = extract_attribute(line, "ry")?;
Some(SvgElement::Ellipse { cx, cy, rx, ry })
}
fn parse_line_element(line: &str) -> Option<SvgElement> {
let x1 = extract_attribute(line, "x1")?;
let y1 = extract_attribute(line, "y1")?;
let x2 = extract_attribute(line, "x2")?;
let y2 = extract_attribute(line, "y2")?;
Some(SvgElement::Line { x1, y1, x2, y2 })
}
fn parse_polyline_element(line: &str) -> Option<SvgElement> {
let points = extract_attribute(line, "points")?;
Some(SvgElement::Polyline { points })
}
fn parse_polygon_element(line: &str) -> Option<SvgElement> {
let points = extract_attribute(line, "points")?;
Some(SvgElement::Polygon { points })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_svg_element_path_creation() {
let path = SvgElement::Path { d: "M10 10 L20 20".to_string() };
match path {
SvgElement::Path { d } => assert_eq!(d, "M10 10 L20 20"),
_ => panic!("Expected Path variant"),
}
}
#[test]
fn test_svg_element_circle_creation() {
let circle = SvgElement::Circle { cx: "10".to_string(), cy: "20".to_string(), r: "5".to_string() };
match circle {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "10");
assert_eq!(cy, "20");
assert_eq!(r, "5");
}
_ => panic!("Expected Circle variant"),
}
}
#[test]
fn test_extract_attribute_success() {
let line = r#"<path d="M10 10 L20 20" fill="red" />"#;
assert_eq!(extract_attribute(line, "d"), Some("M10 10 L20 20".to_string()));
assert_eq!(extract_attribute(line, "fill"), Some("red".to_string()));
}
#[test]
fn test_extract_attribute_not_found() {
let line = r#"<path d="M10 10 L20 20" />"#;
assert_eq!(extract_attribute(line, "fill"), None);
assert_eq!(extract_attribute(line, "stroke"), None);
}
#[test]
fn test_extract_attribute_empty_value() {
let line = r#"<path d="" />"#;
assert_eq!(extract_attribute(line, "d"), Some("".to_string()));
}
#[test]
fn test_parse_path_element_success() {
let line = r#"<path d="M10 10 L20 20" />"#;
let result = parse_path_element(line);
match result {
Some(SvgElement::Path { d }) => assert_eq!(d, "M10 10 L20 20"),
_ => panic!("Expected Some(Path)"),
}
}
#[test]
fn test_parse_path_element_missing_d() {
let line = r#"<path fill="red" />"#;
let result = parse_path_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_circle_element_success() {
let line = r#"<circle cx="10" cy="20" r="5" />"#;
let result = parse_circle_element(line);
match result {
Some(SvgElement::Circle { cx, cy, r }) => {
assert_eq!(cx, "10");
assert_eq!(cy, "20");
assert_eq!(r, "5");
}
_ => panic!("Expected Some(Circle)"),
}
}
#[test]
fn test_parse_circle_element_missing_attributes() {
let line = r#"<circle cx="10" />"#;
let result = parse_circle_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_svg_elements_mixed_content() {
let svg_content = r#"
<svg>
<path d="M10 10 L20 20" />
<circle cx="15" cy="25" r="3" />
<rect x="0" y="0" width="10" height="10" />
<path d="M0 0 L10 10" />
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 4);
match &elements[0] {
SvgElement::Path { d } => assert_eq!(d, "M10 10 L20 20"),
_ => panic!("Expected first element to be Path"),
}
match &elements[1] {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "15");
assert_eq!(cy, "25");
assert_eq!(r, "3");
}
_ => panic!("Expected second element to be Circle"),
}
match &elements[2] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "10");
assert_eq!(height, "10");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected third element to be Rect"),
}
match &elements[3] {
SvgElement::Path { d } => assert_eq!(d, "M0 0 L10 10"),
_ => panic!("Expected fourth element to be Path"),
}
}
#[test]
fn test_parse_svg_elements_empty_content() {
let svg_content = "";
let elements = parse_svg_elements(svg_content);
assert!(elements.is_empty());
}
#[test]
fn test_parse_svg_elements_whitespace_only() {
let svg_content = " \n \t \n ";
let elements = parse_svg_elements(svg_content);
assert!(elements.is_empty());
}
#[test]
fn test_parse_svg_elements_no_matching_elements() {
let svg_content = r#"
<svg>
<g fill="red">
<text x="10" y="20">Hello</text>
<image href="image.png" />
</g>
<defs>
<pattern id="pattern1" />
</defs>
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert!(elements.is_empty());
}
#[test]
fn test_parse_svg_elements_complex_path() {
let svg_content = r#"<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 1);
match &elements[0] {
SvgElement::Path { d } => {
assert_eq!(
d,
"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
);
}
_ => panic!("Expected Path element"),
}
}
#[test]
fn test_parse_svg_elements_multiple_paths_and_circles() {
let svg_content = r#"
<path d="M1 1 L2 2" />
<circle cx="1" cy="1" r="1" />
<path d="M3 3 L4 4" />
<circle cx="2" cy="2" r="2" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 4);
match &elements[0] {
SvgElement::Path { d } => assert_eq!(d, "M1 1 L2 2"),
_ => panic!("Expected first element to be Path"),
}
match &elements[1] {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "1");
assert_eq!(cy, "1");
assert_eq!(r, "1");
}
_ => panic!("Expected second element to be Circle"),
}
match &elements[2] {
SvgElement::Path { d } => assert_eq!(d, "M3 3 L4 4"),
_ => panic!("Expected third element to be Path"),
}
match &elements[3] {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "2");
assert_eq!(cy, "2");
assert_eq!(r, "2");
}
_ => panic!("Expected fourth element to be Circle"),
}
}
#[test]
fn test_svg_element_rect_creation() {
let rect = SvgElement::Rect {
x: "10".to_string(),
y: "20".to_string(),
width: "100".to_string(),
height: "50".to_string(),
rx: None,
ry: None,
};
match rect {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "10");
assert_eq!(y, "20");
assert_eq!(width, "100");
assert_eq!(height, "50");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected Rect variant"),
}
}
#[test]
fn test_svg_element_rect_with_rounded_corners() {
let rect = SvgElement::Rect {
x: "0".to_string(),
y: "0".to_string(),
width: "50".to_string(),
height: "50".to_string(),
rx: Some("5".to_string()),
ry: Some("10".to_string()),
};
match rect {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "50");
assert_eq!(height, "50");
assert_eq!(rx.as_ref(), Some(&"5".to_string()));
assert_eq!(ry.as_ref(), Some(&"10".to_string()));
}
_ => panic!("Expected Rect variant"),
}
}
#[test]
fn test_parse_rect_element_basic() {
let line = r#"<rect x="10" y="20" width="100" height="50" />"#;
let result = parse_rect_element(line);
match result {
Some(SvgElement::Rect { x, y, width, height, rx, ry }) => {
assert_eq!(x, "10");
assert_eq!(y, "20");
assert_eq!(width, "100");
assert_eq!(height, "50");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected Some(Rect)"),
}
}
#[test]
fn test_parse_rect_element_with_rx_ry() {
let line = r#"<rect x="0" y="0" width="50" height="30" rx="5" ry="10" />"#;
let result = parse_rect_element(line);
match result {
Some(SvgElement::Rect { x, y, width, height, rx, ry }) => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "50");
assert_eq!(height, "30");
assert_eq!(rx.as_ref(), Some(&"5".to_string()));
assert_eq!(ry.as_ref(), Some(&"10".to_string()));
}
_ => panic!("Expected Some(Rect)"),
}
}
#[test]
fn test_parse_rect_element_with_only_rx() {
let line = r#"<rect x="0" y="0" width="50" height="30" rx="5" />"#;
let result = parse_rect_element(line);
match result {
Some(SvgElement::Rect { x, y, width, height, rx, ry }) => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "50");
assert_eq!(height, "30");
assert_eq!(rx.as_ref(), Some(&"5".to_string()));
assert!(ry.is_none());
}
_ => panic!("Expected Some(Rect)"),
}
}
#[test]
fn test_parse_rect_element_missing_required_attributes() {
let line = r#"<rect x="10" y="20" />"#;
let result = parse_rect_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_rect_element_missing_width() {
let line = r#"<rect x="10" y="20" height="50" />"#;
let result = parse_rect_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_svg_elements_with_rect() {
let svg_content = r#"
<svg>
<path d="M10 10 L20 20" />
<rect x="0" y="0" width="50" height="30" />
<circle cx="15" cy="25" r="3" />
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Path { d } => assert_eq!(d, "M10 10 L20 20"),
_ => panic!("Expected first element to be Path"),
}
match &elements[1] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "50");
assert_eq!(height, "30");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected second element to be Rect"),
}
match &elements[2] {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "15");
assert_eq!(cy, "25");
assert_eq!(r, "3");
}
_ => panic!("Expected third element to be Circle"),
}
}
#[test]
fn test_parse_svg_elements_mixed_with_rounded_rect() {
let svg_content = r#"
<rect x="10" y="10" width="80" height="60" rx="15" ry="20" />
<path d="M1 1 L2 2" />
<rect x="0" y="0" width="10" height="10" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "10");
assert_eq!(y, "10");
assert_eq!(width, "80");
assert_eq!(height, "60");
assert_eq!(rx.as_ref(), Some(&"15".to_string()));
assert_eq!(ry.as_ref(), Some(&"20".to_string()));
}
_ => panic!("Expected first element to be Rect"),
}
match &elements[1] {
SvgElement::Path { d } => assert_eq!(d, "M1 1 L2 2"),
_ => panic!("Expected second element to be Path"),
}
match &elements[2] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "10");
assert_eq!(height, "10");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected third element to be Rect"),
}
}
#[test]
fn test_svg_element_ellipse_creation() {
let ellipse = SvgElement::Ellipse {
cx: "50".to_string(),
cy: "100".to_string(),
rx: "20".to_string(),
ry: "30".to_string(),
};
match ellipse {
SvgElement::Ellipse { cx, cy, rx, ry } => {
assert_eq!(cx, "50");
assert_eq!(cy, "100");
assert_eq!(rx, "20");
assert_eq!(ry, "30");
}
_ => panic!("Expected Ellipse variant"),
}
}
#[test]
fn test_parse_ellipse_element_success() {
let line = r#"<ellipse cx="50" cy="100" rx="20" ry="30" />"#;
let result = parse_ellipse_element(line);
match result {
Some(SvgElement::Ellipse { cx, cy, rx, ry }) => {
assert_eq!(cx, "50");
assert_eq!(cy, "100");
assert_eq!(rx, "20");
assert_eq!(ry, "30");
}
_ => panic!("Expected Some(Ellipse)"),
}
}
#[test]
fn test_parse_ellipse_element_missing_cx() {
let line = r#"<ellipse cy="100" rx="20" ry="30" />"#;
let result = parse_ellipse_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_ellipse_element_missing_cy() {
let line = r#"<ellipse cx="50" rx="20" ry="30" />"#;
let result = parse_ellipse_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_ellipse_element_missing_rx() {
let line = r#"<ellipse cx="50" cy="100" ry="30" />"#;
let result = parse_ellipse_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_ellipse_element_missing_ry() {
let line = r#"<ellipse cx="50" cy="100" rx="20" />"#;
let result = parse_ellipse_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_svg_elements_with_ellipse() {
let svg_content = r#"
<svg>
<path d="M10 10 L20 20" />
<ellipse cx="50" cy="100" rx="20" ry="30" />
<circle cx="15" cy="25" r="3" />
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Path { d } => assert_eq!(d, "M10 10 L20 20"),
_ => panic!("Expected first element to be Path"),
}
match &elements[1] {
SvgElement::Ellipse { cx, cy, rx, ry } => {
assert_eq!(cx, "50");
assert_eq!(cy, "100");
assert_eq!(rx, "20");
assert_eq!(ry, "30");
}
_ => panic!("Expected second element to be Ellipse"),
}
match &elements[2] {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "15");
assert_eq!(cy, "25");
assert_eq!(r, "3");
}
_ => panic!("Expected third element to be Circle"),
}
}
#[test]
fn test_parse_svg_elements_mixed_with_ellipse_and_rect() {
let svg_content = r#"
<ellipse cx="10" cy="20" rx="15" ry="25" />
<rect x="0" y="0" width="50" height="30" />
<path d="M1 1 L2 2" />
<ellipse cx="100" cy="200" rx="5" ry="10" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 4);
match &elements[0] {
SvgElement::Ellipse { cx, cy, rx, ry } => {
assert_eq!(cx, "10");
assert_eq!(cy, "20");
assert_eq!(rx, "15");
assert_eq!(ry, "25");
}
_ => panic!("Expected first element to be Ellipse"),
}
match &elements[1] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "50");
assert_eq!(height, "30");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected second element to be Rect"),
}
match &elements[2] {
SvgElement::Path { d } => assert_eq!(d, "M1 1 L2 2"),
_ => panic!("Expected third element to be Path"),
}
match &elements[3] {
SvgElement::Ellipse { cx, cy, rx, ry } => {
assert_eq!(cx, "100");
assert_eq!(cy, "200");
assert_eq!(rx, "5");
assert_eq!(ry, "10");
}
_ => panic!("Expected fourth element to be Ellipse"),
}
}
#[test]
fn test_parse_svg_elements_ellipse_only() {
let svg_content = r#"
<ellipse cx="25" cy="75" rx="10" ry="20" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 1);
match &elements[0] {
SvgElement::Ellipse { cx, cy, rx, ry } => {
assert_eq!(cx, "25");
assert_eq!(cy, "75");
assert_eq!(rx, "10");
assert_eq!(ry, "20");
}
_ => panic!("Expected element to be Ellipse"),
}
}
#[test]
fn test_svg_element_line_creation() {
let line = SvgElement::Line {
x1: "10".to_string(),
y1: "20".to_string(),
x2: "100".to_string(),
y2: "200".to_string(),
};
match line {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "10");
assert_eq!(y1, "20");
assert_eq!(x2, "100");
assert_eq!(y2, "200");
}
_ => panic!("Expected Line variant"),
}
}
#[test]
fn test_parse_line_element_success() {
let line = r#"<line x1="10" y1="20" x2="100" y2="200" />"#;
let result = parse_line_element(line);
match result {
Some(SvgElement::Line { x1, y1, x2, y2 }) => {
assert_eq!(x1, "10");
assert_eq!(y1, "20");
assert_eq!(x2, "100");
assert_eq!(y2, "200");
}
_ => panic!("Expected Some(Line)"),
}
}
#[test]
fn test_parse_line_element_missing_x1() {
let line = r#"<line y1="20" x2="100" y2="200" />"#;
let result = parse_line_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_line_element_missing_y1() {
let line = r#"<line x1="10" x2="100" y2="200" />"#;
let result = parse_line_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_line_element_missing_x2() {
let line = r#"<line x1="10" y1="20" y2="200" />"#;
let result = parse_line_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_line_element_missing_y2() {
let line = r#"<line x1="10" y1="20" x2="100" />"#;
let result = parse_line_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_svg_elements_with_line() {
let svg_content = r#"
<svg>
<path d="M10 10 L20 20" />
<line x1="0" y1="0" x2="50" y2="50" />
<circle cx="15" cy="25" r="3" />
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Path { d } => assert_eq!(d, "M10 10 L20 20"),
_ => panic!("Expected first element to be Path"),
}
match &elements[1] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "0");
assert_eq!(y1, "0");
assert_eq!(x2, "50");
assert_eq!(y2, "50");
}
_ => panic!("Expected second element to be Line"),
}
match &elements[2] {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "15");
assert_eq!(cy, "25");
assert_eq!(r, "3");
}
_ => panic!("Expected third element to be Circle"),
}
}
#[test]
fn test_parse_svg_elements_mixed_with_line() {
let svg_content = r#"
<line x1="5" y1="5" x2="15" y2="15" />
<rect x="0" y="0" width="50" height="30" />
<path d="M1 1 L2 2" />
<line x1="100" y1="200" x2="300" y2="400" />
<ellipse cx="25" cy="50" rx="10" ry="20" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 5);
match &elements[0] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "5");
assert_eq!(y1, "5");
assert_eq!(x2, "15");
assert_eq!(y2, "15");
}
_ => panic!("Expected first element to be Line"),
}
match &elements[1] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "50");
assert_eq!(height, "30");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected second element to be Rect"),
}
match &elements[2] {
SvgElement::Path { d } => assert_eq!(d, "M1 1 L2 2"),
_ => panic!("Expected third element to be Path"),
}
match &elements[3] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "100");
assert_eq!(y1, "200");
assert_eq!(x2, "300");
assert_eq!(y2, "400");
}
_ => panic!("Expected fourth element to be Line"),
}
match &elements[4] {
SvgElement::Ellipse { cx, cy, rx, ry } => {
assert_eq!(cx, "25");
assert_eq!(cy, "50");
assert_eq!(rx, "10");
assert_eq!(ry, "20");
}
_ => panic!("Expected fifth element to be Ellipse"),
}
}
#[test]
fn test_parse_svg_elements_line_only() {
let svg_content = r#"
<line x1="0" y1="0" x2="100" y2="100" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 1);
match &elements[0] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "0");
assert_eq!(y1, "0");
assert_eq!(x2, "100");
assert_eq!(y2, "100");
}
_ => panic!("Expected element to be Line"),
}
}
#[test]
fn test_parse_svg_elements_multiple_lines() {
let svg_content = r#"
<line x1="0" y1="0" x2="10" y2="10" />
<line x1="20" y1="20" x2="30" y2="30" />
<line x1="40" y1="40" x2="50" y2="50" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "0");
assert_eq!(y1, "0");
assert_eq!(x2, "10");
assert_eq!(y2, "10");
}
_ => panic!("Expected first element to be Line"),
}
match &elements[1] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "20");
assert_eq!(y1, "20");
assert_eq!(x2, "30");
assert_eq!(y2, "30");
}
_ => panic!("Expected second element to be Line"),
}
match &elements[2] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "40");
assert_eq!(y1, "40");
assert_eq!(x2, "50");
assert_eq!(y2, "50");
}
_ => panic!("Expected third element to be Line"),
}
}
#[test]
fn test_parse_line_element_with_decimal_coordinates() {
let line = r#"<line x1="10.5" y1="20.25" x2="100.75" y2="200.125" />"#;
let result = parse_line_element(line);
match result {
Some(SvgElement::Line { x1, y1, x2, y2 }) => {
assert_eq!(x1, "10.5");
assert_eq!(y1, "20.25");
assert_eq!(x2, "100.75");
assert_eq!(y2, "200.125");
}
_ => panic!("Expected Some(Line)"),
}
}
#[test]
fn test_svg_element_polyline_creation() {
let polyline = SvgElement::Polyline { points: "10,20 30,40 50,60".to_string() };
match polyline {
SvgElement::Polyline { points } => {
assert_eq!(points, "10,20 30,40 50,60");
}
_ => panic!("Expected Polyline variant"),
}
}
#[test]
fn test_parse_polyline_element_success() {
let line = r#"<polyline points="10,20 30,40 50,60" />"#;
let result = parse_polyline_element(line);
match result {
Some(SvgElement::Polyline { points }) => {
assert_eq!(points, "10,20 30,40 50,60");
}
_ => panic!("Expected Some(Polyline)"),
}
}
#[test]
fn test_parse_polyline_element_missing_points() {
let line = r#"<polyline stroke="red" />"#;
let result = parse_polyline_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_polyline_element_empty_points() {
let line = r#"<polyline points="" />"#;
let result = parse_polyline_element(line);
match result {
Some(SvgElement::Polyline { points }) => {
assert_eq!(points, "");
}
_ => panic!("Expected Some(Polyline) with empty points"),
}
}
#[test]
fn test_parse_svg_elements_with_polyline() {
let svg_content = r#"
<svg>
<path d="M10 10 L20 20" />
<polyline points="0,0 10,10 20,0" />
<circle cx="15" cy="25" r="3" />
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Path { d } => assert_eq!(d, "M10 10 L20 20"),
_ => panic!("Expected first element to be Path"),
}
match &elements[1] {
SvgElement::Polyline { points } => {
assert_eq!(points, "0,0 10,10 20,0");
}
_ => panic!("Expected second element to be Polyline"),
}
match &elements[2] {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "15");
assert_eq!(cy, "25");
assert_eq!(r, "3");
}
_ => panic!("Expected third element to be Circle"),
}
}
#[test]
fn test_parse_svg_elements_mixed_with_polyline() {
let svg_content = r#"
<polyline points="0,0 5,5 10,0 15,5" />
<rect x="0" y="0" width="50" height="30" />
<path d="M1 1 L2 2" />
<line x1="100" y1="200" x2="300" y2="400" />
<polyline points="20,20 25,25 30,20" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 5);
match &elements[0] {
SvgElement::Polyline { points } => {
assert_eq!(points, "0,0 5,5 10,0 15,5");
}
_ => panic!("Expected first element to be Polyline"),
}
match &elements[1] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "50");
assert_eq!(height, "30");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected second element to be Rect"),
}
match &elements[2] {
SvgElement::Path { d } => assert_eq!(d, "M1 1 L2 2"),
_ => panic!("Expected third element to be Path"),
}
match &elements[3] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "100");
assert_eq!(y1, "200");
assert_eq!(x2, "300");
assert_eq!(y2, "400");
}
_ => panic!("Expected fourth element to be Line"),
}
match &elements[4] {
SvgElement::Polyline { points } => {
assert_eq!(points, "20,20 25,25 30,20");
}
_ => panic!("Expected fifth element to be Polyline"),
}
}
#[test]
fn test_parse_svg_elements_polyline_only() {
let svg_content = r#"
<polyline points="10,15 20,25 30,35 40,45" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 1);
match &elements[0] {
SvgElement::Polyline { points } => {
assert_eq!(points, "10,15 20,25 30,35 40,45");
}
_ => panic!("Expected element to be Polyline"),
}
}
#[test]
fn test_parse_svg_elements_multiple_polylines() {
let svg_content = r#"
<polyline points="0,0 10,10" />
<polyline points="20,20 30,30 40,40" />
<polyline points="50,50 60,60 70,70 80,80" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Polyline { points } => {
assert_eq!(points, "0,0 10,10");
}
_ => panic!("Expected first element to be Polyline"),
}
match &elements[1] {
SvgElement::Polyline { points } => {
assert_eq!(points, "20,20 30,30 40,40");
}
_ => panic!("Expected second element to be Polyline"),
}
match &elements[2] {
SvgElement::Polyline { points } => {
assert_eq!(points, "50,50 60,60 70,70 80,80");
}
_ => panic!("Expected third element to be Polyline"),
}
}
#[test]
fn test_parse_polyline_element_with_decimal_coordinates() {
let line = r#"<polyline points="10.5,20.25 30.75,40.125 50.5,60.25" />"#;
let result = parse_polyline_element(line);
match result {
Some(SvgElement::Polyline { points }) => {
assert_eq!(points, "10.5,20.25 30.75,40.125 50.5,60.25");
}
_ => panic!("Expected Some(Polyline)"),
}
}
#[test]
fn test_parse_polyline_element_complex_points() {
let line = r#"<polyline points="11 3 11 11 14 8 17 11 17 3" />"#;
let result = parse_polyline_element(line);
match result {
Some(SvgElement::Polyline { points }) => {
assert_eq!(points, "11 3 11 11 14 8 17 11 17 3");
}
_ => panic!("Expected Some(Polyline)"),
}
}
#[test]
fn test_parse_svg_elements_with_album_structure() {
let svg_content = r#"
<svg>
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
<polyline points="11 3 11 11 14 8 17 11 17 3" />
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 2);
match &elements[0] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "3");
assert_eq!(y, "3");
assert_eq!(width, "18");
assert_eq!(height, "18");
assert_eq!(rx.as_ref(), Some(&"2".to_string()));
assert_eq!(ry.as_ref(), Some(&"2".to_string()));
}
_ => panic!("Expected first element to be Rect"),
}
match &elements[1] {
SvgElement::Polyline { points } => {
assert_eq!(points, "11 3 11 11 14 8 17 11 17 3");
}
_ => panic!("Expected second element to be Polyline"),
}
}
#[test]
fn test_svg_element_polygon_creation() {
let polygon = SvgElement::Polygon { points: "10,20 30,40 50,60".to_string() };
match polygon {
SvgElement::Polygon { points } => {
assert_eq!(points, "10,20 30,40 50,60");
}
_ => panic!("Expected Polygon variant"),
}
}
#[test]
fn test_parse_polygon_element_success() {
let line = r#"<polygon points="10,20 30,40 50,60" />"#;
let result = parse_polygon_element(line);
match result {
Some(SvgElement::Polygon { points }) => {
assert_eq!(points, "10,20 30,40 50,60");
}
_ => panic!("Expected Some(Polygon)"),
}
}
#[test]
fn test_parse_polygon_element_missing_points() {
let line = r#"<polygon fill="blue" />"#;
let result = parse_polygon_element(line);
assert!(result.is_none());
}
#[test]
fn test_parse_polygon_element_empty_points() {
let line = r#"<polygon points="" />"#;
let result = parse_polygon_element(line);
match result {
Some(SvgElement::Polygon { points }) => {
assert_eq!(points, "");
}
_ => panic!("Expected Some(Polygon) with empty points"),
}
}
#[test]
fn test_parse_svg_elements_with_polygon() {
let svg_content = r#"
<svg>
<path d="M10 10 L20 20" />
<polygon points="0,0 10,10 20,0" />
<circle cx="15" cy="25" r="3" />
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Path { d } => assert_eq!(d, "M10 10 L20 20"),
_ => panic!("Expected first element to be Path"),
}
match &elements[1] {
SvgElement::Polygon { points } => {
assert_eq!(points, "0,0 10,10 20,0");
}
_ => panic!("Expected second element to be Polygon"),
}
match &elements[2] {
SvgElement::Circle { cx, cy, r } => {
assert_eq!(cx, "15");
assert_eq!(cy, "25");
assert_eq!(r, "3");
}
_ => panic!("Expected third element to be Circle"),
}
}
#[test]
fn test_parse_svg_elements_mixed_with_polygon() {
let svg_content = r#"
<polygon points="0,0 5,5 10,0" />
<rect x="0" y="0" width="50" height="30" />
<path d="M1 1 L2 2" />
<line x1="100" y1="200" x2="300" y2="400" />
<polyline points="20,20 25,25 30,20" />
<polygon points="40,40 45,45 50,40 45,35" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 6);
match &elements[0] {
SvgElement::Polygon { points } => {
assert_eq!(points, "0,0 5,5 10,0");
}
_ => panic!("Expected first element to be Polygon"),
}
match &elements[1] {
SvgElement::Rect { x, y, width, height, rx, ry } => {
assert_eq!(x, "0");
assert_eq!(y, "0");
assert_eq!(width, "50");
assert_eq!(height, "30");
assert!(rx.is_none());
assert!(ry.is_none());
}
_ => panic!("Expected second element to be Rect"),
}
match &elements[2] {
SvgElement::Path { d } => assert_eq!(d, "M1 1 L2 2"),
_ => panic!("Expected third element to be Path"),
}
match &elements[3] {
SvgElement::Line { x1, y1, x2, y2 } => {
assert_eq!(x1, "100");
assert_eq!(y1, "200");
assert_eq!(x2, "300");
assert_eq!(y2, "400");
}
_ => panic!("Expected fourth element to be Line"),
}
match &elements[4] {
SvgElement::Polyline { points } => {
assert_eq!(points, "20,20 25,25 30,20");
}
_ => panic!("Expected fifth element to be Polyline"),
}
match &elements[5] {
SvgElement::Polygon { points } => {
assert_eq!(points, "40,40 45,45 50,40 45,35");
}
_ => panic!("Expected sixth element to be Polygon"),
}
}
#[test]
fn test_parse_svg_elements_polygon_only() {
let svg_content = r#"
<polygon points="10,15 20,25 30,35 25,45 15,45 5,35" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 1);
match &elements[0] {
SvgElement::Polygon { points } => {
assert_eq!(points, "10,15 20,25 30,35 25,45 15,45 5,35");
}
_ => panic!("Expected element to be Polygon"),
}
}
#[test]
fn test_parse_svg_elements_multiple_polygons() {
let svg_content = r#"
<polygon points="0,0 10,10 0,20" />
<polygon points="20,20 30,30 40,40 30,50" />
<polygon points="50,50 60,60 70,70 80,80 70,90 60,80" />
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 3);
match &elements[0] {
SvgElement::Polygon { points } => {
assert_eq!(points, "0,0 10,10 0,20");
}
_ => panic!("Expected first element to be Polygon"),
}
match &elements[1] {
SvgElement::Polygon { points } => {
assert_eq!(points, "20,20 30,30 40,40 30,50");
}
_ => panic!("Expected second element to be Polygon"),
}
match &elements[2] {
SvgElement::Polygon { points } => {
assert_eq!(points, "50,50 60,60 70,70 80,80 70,90 60,80");
}
_ => panic!("Expected third element to be Polygon"),
}
}
#[test]
fn test_parse_polygon_element_with_decimal_coordinates() {
let line = r#"<polygon points="10.5,20.25 30.75,40.125 50.5,60.25" />"#;
let result = parse_polygon_element(line);
match result {
Some(SvgElement::Polygon { points }) => {
assert_eq!(points, "10.5,20.25 30.75,40.125 50.5,60.25");
}
_ => panic!("Expected Some(Polygon)"),
}
}
#[test]
fn test_parse_polygon_element_triangle() {
let line = r#"<polygon points="100,50 150,100 50,100" />"#;
let result = parse_polygon_element(line);
match result {
Some(SvgElement::Polygon { points }) => {
assert_eq!(points, "100,50 150,100 50,100");
}
_ => panic!("Expected Some(Polygon)"),
}
}
#[test]
fn test_parse_polygon_element_star() {
let line = r#"<polygon points="50,0 61,35 98,35 68,57 79,91 50,70 21,91 32,57 2,35 39,35" />"#;
let result = parse_polygon_element(line);
match result {
Some(SvgElement::Polygon { points }) => {
assert_eq!(points, "50,0 61,35 98,35 68,57 79,91 50,70 21,91 32,57 2,35 39,35");
}
_ => panic!("Expected Some(Polygon)"),
}
}
#[test]
fn test_parse_svg_elements_polygon_vs_polyline() {
let svg_content = r#"
<svg>
<polyline points="0,0 10,10 20,0" />
<polygon points="30,30 40,40 50,30" />
</svg>
"#;
let elements = parse_svg_elements(svg_content);
assert_eq!(elements.len(), 2);
match &elements[0] {
SvgElement::Polyline { points } => {
assert_eq!(points, "0,0 10,10 20,0");
}
_ => panic!("Expected first element to be Polyline"),
}
match &elements[1] {
SvgElement::Polygon { points } => {
assert_eq!(points, "30,30 40,40 50,30");
}
_ => panic!("Expected second element to be Polygon"),
}
}
#[test]
fn test_parse_polygon_element_space_separated_coordinates() {
let line = r#"<polygon points="0 0 10 0 5 10" />"#;
let result = parse_polygon_element(line);
match result {
Some(SvgElement::Polygon { points }) => {
assert_eq!(points, "0 0 10 0 5 10");
}
_ => panic!("Expected Some(Polygon)"),
}
}
}