use aasvg::{render, render_with_options, RenderOptions};
const FIXTURES_DIR: &str = "tests/fixtures";
fn load_fixture(name: &str) -> String {
std::fs::read_to_string(format!("{}/{}", FIXTURES_DIR, name))
.expect("Failed to read fixture file")
}
#[test]
fn test_render_simple_box() {
let diagram = "+--+\n| |\n+--+";
let svg = render(diagram);
assert!(svg.starts_with("<svg"));
assert!(svg.ends_with("</svg>"));
assert!(svg.contains("<path")); assert!(svg.contains("var(--aasvg-stroke)")); }
#[test]
fn test_render_horizontal_arrow() {
let svg = render("--->");
assert!(svg.contains("<path")); assert!(svg.contains("<polygon")); assert!(svg.contains("var(--aasvg-fill)")); }
#[test]
fn test_render_vertical_arrow() {
let svg = render("|\n|\nv");
assert!(svg.contains("<path"));
assert!(svg.contains("<polygon"));
}
#[test]
fn test_render_text() {
let svg = render("Hello World");
assert!(svg.contains("<text"));
assert!(svg.contains("Hello"));
assert!(svg.contains("World"));
assert!(svg.contains("var(--aasvg-text)")); }
#[test]
fn test_render_mixed_diagram() {
let diagram = r#"
+--------+
| Hello! |---->
+--------+
"#;
let svg = render(diagram);
assert!(svg.contains("<path"));
assert!(svg.contains("<text"));
assert!(svg.contains("<polygon"));
}
#[test]
fn test_css_variables_present() {
let svg = render("-");
assert!(svg.contains("--aasvg-stroke"));
assert!(svg.contains("--aasvg-fill"));
assert!(svg.contains("--aasvg-bg"));
assert!(svg.contains("--aasvg-text"));
assert!(svg.contains("prefers-color-scheme: dark"));
}
#[test]
fn test_stroke_uses_variable() {
let svg = render("---");
assert!(svg.contains(r#"stroke="var(--aasvg-stroke)"#));
}
#[test]
fn test_fill_uses_variable() {
let svg = render("-->");
assert!(svg.contains(r#"fill="var(--aasvg-fill)"#));
}
#[test]
fn test_backdrop_uses_variable() {
let options = RenderOptions::new().with_backdrop(true);
let svg = render_with_options("-", &options);
assert!(svg.contains(r#"fill="var(--aasvg-bg)"#));
}
#[test]
fn test_backdrop_option() {
let with_backdrop = render_with_options("-", &RenderOptions::new().with_backdrop(true));
let _without_backdrop = render_with_options("-", &RenderOptions::new().with_backdrop(false));
assert!(with_backdrop.contains("<rect"));
}
#[test]
fn test_disable_text_option() {
let with_text = render("Hello");
let without_text =
render_with_options("Hello", &RenderOptions::new().with_disable_text(true));
assert!(with_text.contains("Hello"));
assert!(!without_text.contains("Hello"));
}
#[test]
fn test_fixture_boxes() {
let input = load_fixture("boxes.txt");
let svg = render(&input);
assert!(svg.starts_with("<svg"));
assert!(svg.ends_with("</svg>"));
assert!(svg.contains("<path"));
assert!(svg.contains("--aasvg-stroke"));
}
#[test]
fn test_fixture_arrows() {
let input = load_fixture("arrows.txt");
let svg = render(&input);
assert!(svg.contains("<polygon"));
assert!(svg.contains("<path"));
}
#[test]
fn test_fixture_curves() {
let input = load_fixture("curves.txt");
let svg = render(&input);
assert!(svg.starts_with("<svg"));
assert!(svg.ends_with("</svg>"));
}
#[test]
fn test_fixture_points() {
let input = load_fixture("points.txt");
let svg = render(&input);
assert!(svg.contains("<circle"));
}
#[test]
fn test_fixture_example() {
let input = load_fixture("example.txt");
let svg = render(&input);
assert!(svg.starts_with("<svg"));
assert!(svg.ends_with("</svg>"));
assert!(svg.contains("<path")); assert!(svg.contains("<polygon")); assert!(svg.contains("<text"));
assert!(svg.contains("--aasvg-stroke"));
assert!(svg.contains("prefers-color-scheme: dark"));
}
#[test]
fn test_empty_input() {
let svg = render("");
assert!(svg.starts_with("<svg"));
assert!(svg.ends_with("</svg>"));
}
#[test]
fn test_whitespace_only() {
let svg = render(" \n \n ");
assert!(svg.starts_with("<svg"));
assert!(svg.ends_with("</svg>"));
}
#[test]
fn test_single_character() {
let svg = render("X");
assert!(svg.contains("<text"));
assert!(svg.contains("X"));
}
#[test]
fn test_unicode_text() {
let svg = render("日本語");
assert!(svg.contains("<text"));
assert!(svg.contains("日本語"));
}
#[test]
fn test_special_characters() {
let svg = render("<>&\"");
assert!(svg.contains("<"));
assert!(svg.contains(">"));
assert!(svg.contains("&"));
}
#[test]
fn test_horizontal_line() {
let svg = render("-----");
assert!(svg.contains("<path"));
}
#[test]
fn test_vertical_line() {
let svg = render("|\n|\n|\n|");
assert!(svg.contains("<path"));
}
#[test]
fn test_diagonal_line() {
let svg = render("\\\n \\");
assert!(svg.contains("<path"));
}
#[test]
fn test_forward_diagonal() {
let svg = render(" /\n/");
assert!(svg.contains("<path"));
}
#[test]
fn test_double_line() {
let svg = render("=====");
assert!(svg.contains("<path"));
}
#[test]
fn test_squiggle_line() {
let svg = render("~~~~~");
assert!(svg.contains("<path"));
assert!(svg.contains(" Q "));
}
fn count_pattern(s: &str, pattern: &str) -> usize {
s.matches(pattern).count()
}
fn extract_text_content(svg: &str) -> Vec<String> {
let mut texts = Vec::new();
for line in svg.lines() {
if let Some(start) = line.find("<text") {
if let Some(end) = line.find("</text>") {
if let Some(content_start) = line[start..].find('>') {
let content = &line[start + content_start + 1..end];
if !content.is_empty() {
texts.push(content.to_string());
}
}
}
}
}
texts.sort();
texts
}
#[test]
fn test_example_matches_reference() {
let input = std::fs::read_to_string("example.txt").expect("Failed to read example.txt");
let reference =
std::fs::read_to_string("tests/example.reference.svg").expect("Failed to read reference");
let options = RenderOptions::new().with_backdrop(true);
let rendered = render_with_options(&input, &options);
std::fs::write("tests/example.actual.svg", &rendered).ok();
let ref_paths = count_pattern(&reference, "<path");
let act_paths = count_pattern(&rendered, "<path");
let ref_polygons = count_pattern(&reference, "<polygon");
let act_polygons = count_pattern(&rendered, "<polygon");
let ref_circles = count_pattern(&reference, "<circle");
let act_circles = count_pattern(&rendered, "<circle");
let ref_texts = count_pattern(&reference, "<text");
let act_texts = count_pattern(&rendered, "<text");
let _ref_text_content = extract_text_content(&reference);
let _act_text_content = extract_text_content(&rendered);
let mut failures = Vec::new();
let mut known_issues = Vec::new();
let path_diff = (ref_paths as i32 - act_paths as i32).abs();
if path_diff > 10 {
known_issues.push(format!(
"Path count differs: reference={}, actual={} (diff={})",
ref_paths, act_paths, path_diff
));
}
let polygon_diff = (ref_polygons as i32 - act_polygons as i32).abs();
if polygon_diff > 5 {
failures.push(format!(
"Polygon (arrow) count differs significantly: reference={}, actual={}",
ref_polygons, act_polygons
));
} else if polygon_diff > 0 {
known_issues.push(format!(
"Polygon (arrow) count differs slightly: reference={}, actual={}",
ref_polygons, act_polygons
));
}
let circle_diff = (ref_circles as i32 - act_circles as i32).abs();
if circle_diff > 1 {
failures.push(format!(
"Circle (point) count differs significantly: reference={}, actual={}",
ref_circles, act_circles
));
} else if circle_diff > 0 {
known_issues.push(format!(
"Circle (point) count differs slightly: reference={}, actual={}",
ref_circles, act_circles
));
}
let key_texts = [
"A Box",
"Round",
"Mixed Rounded",
"Diagonals",
"Search",
"Interior",
"Diag line",
"Curved line",
"Done?",
"Join",
"Curved",
"Vertical",
];
for key_text in key_texts {
if !rendered.contains(key_text) {
failures.push(format!("Missing key text: '{}'", key_text));
}
}
eprintln!("\n=== Reference Comparison ===");
eprintln!("Paths: reference={:3}, actual={:3}", ref_paths, act_paths);
eprintln!(
"Polygons: reference={:3}, actual={:3}",
ref_polygons, act_polygons
);
eprintln!(
"Circles: reference={:3}, actual={:3}",
ref_circles, act_circles
);
eprintln!("Texts: reference={:3}, actual={:3}", ref_texts, act_texts);
if !known_issues.is_empty() {
eprintln!("\n=== Known Issues (non-blocking) ===");
for issue in &known_issues {
eprintln!(" - {}", issue);
}
}
if !failures.is_empty() {
eprintln!("\n=== Failures ===");
for failure in &failures {
eprintln!(" - {}", failure);
}
eprintln!("\nSee tests/example.actual.svg for the actual output.");
panic!(
"Reference comparison failed with {} issues",
failures.len()
);
}
eprintln!("\nReference comparison passed (with {} known issues)", known_issues.len());
}