at main 228 lines 7.0 kB view raw
1//! Tests for the AT Protocol ClientWriter 2//! 3//! These tests verify that ClientWriter produces the same output as StaticPageWriter 4//! for core markdown rendering, particularly footnotes/sidenotes. 5 6use super::writer::ClientWriter; 7use markdown_weaver::Parser; 8use markdown_weaver_escape::FmtWriter; 9 10/// Helper: Render markdown to HTML using ClientWriter 11fn render_markdown(input: &str) -> String { 12 let options = crate::default_md_options(); 13 let parser = Parser::new_ext(input, options).into_offset_iter(); 14 let mut output = String::new(); 15 let writer: ClientWriter<'_, _, _, ()> = ClientWriter::new(parser, FmtWriter(&mut output), input); 16 writer.run().unwrap(); 17 output 18} 19 20// ============================================================================= 21// Basic Rendering Tests 22// ============================================================================= 23 24#[test] 25fn test_smoke() { 26 let output = render_markdown("Hello world"); 27 assert!(output.contains("Hello world")); 28} 29 30#[test] 31fn test_paragraph_rendering() { 32 let input = "This is a paragraph.\n\nThis is another paragraph."; 33 let output = render_markdown(input); 34 insta::assert_snapshot!(output); 35} 36 37#[test] 38fn test_heading_rendering() { 39 let input = "# Heading 1\n\n## Heading 2\n\n### Heading 3"; 40 let output = render_markdown(input); 41 insta::assert_snapshot!(output); 42} 43 44#[test] 45fn test_list_rendering() { 46 let input = "- Item 1\n- Item 2\n - Nested\n\n1. Ordered 1\n2. Ordered 2"; 47 let output = render_markdown(input); 48 insta::assert_snapshot!(output); 49} 50 51#[test] 52fn test_code_block_rendering() { 53 let input = "```rust\nfn main() {\n println!(\"Hello\");\n}\n```"; 54 let output = render_markdown(input); 55 insta::assert_snapshot!(output); 56} 57 58#[test] 59fn test_table_rendering() { 60 let input = "| Left | Center | Right |\n|:-----|:------:|------:|\n| A | B | C |"; 61 let output = render_markdown(input); 62 insta::assert_snapshot!(output); 63} 64 65#[test] 66fn test_blockquote_rendering() { 67 let input = "> This is a quote\n>\n> With multiple lines"; 68 let output = render_markdown(input); 69 insta::assert_snapshot!(output); 70} 71 72#[test] 73fn test_math_rendering() { 74 let input = "Inline $x^2$ and display:\n\n$$\ny = mx + b\n$$"; 75 let output = render_markdown(input); 76 insta::assert_snapshot!(output); 77} 78 79#[test] 80fn test_empty_input() { 81 let output = render_markdown(""); 82 assert_eq!(output, ""); 83} 84 85#[test] 86fn test_html_and_special_characters() { 87 // ClientWriter wraps inline HTML in spans to contain embeds etc 88 let input = 89 "Text with <special> & some text. Valid tags: <em>emphasis</em> and <strong>bold</strong>"; 90 let output = render_markdown(input); 91 assert!(output.contains("&amp;")); 92 // Inline HTML gets wrapped in html-embed spans 93 assert!(output.contains("html-embed-inline")); 94 assert!(output.contains("<special>")); 95} 96 97#[test] 98fn test_unicode_content() { 99 let input = "Unicode: 你好 🎉 café"; 100 let output = render_markdown(input); 101 assert!(output.contains("你好")); 102 assert!(output.contains("🎉")); 103 assert!(output.contains("café")); 104} 105 106// ============================================================================= 107// WeaverBlock Prefix Tests 108// ============================================================================= 109 110#[test] 111fn test_weaver_block_aside_class() { 112 let input = "\n\n{.aside}\nThis paragraph should be in an aside."; 113 let output = render_markdown(input); 114 insta::assert_snapshot!(output); 115} 116 117#[test] 118fn test_weaver_block_custom_class() { 119 let input = "\n\n{.highlight}\nThis paragraph has a custom class."; 120 let output = render_markdown(input); 121 insta::assert_snapshot!(output); 122} 123 124#[test] 125fn test_weaver_block_custom_attributes() { 126 let input = "\n\n{.foo, width: 300px, data-test: value}\nParagraph with class and attributes."; 127 let output = render_markdown(input); 128 insta::assert_snapshot!(output); 129} 130 131#[test] 132fn test_weaver_block_before_heading() { 133 let input = "\n\n{.aside}\n## Heading in aside\n\nParagraph also in aside."; 134 let output = render_markdown(input); 135 insta::assert_snapshot!(output); 136} 137 138#[test] 139fn test_weaver_block_before_blockquote() { 140 let input = "\n\n{.aside}\n\n> This blockquote is in an aside."; 141 let output = render_markdown(input); 142 insta::assert_snapshot!(output); 143} 144 145#[test] 146fn test_weaver_block_before_list() { 147 let input = "\n\n{.aside}\n\n- Item 1\n- Item 2"; 148 let output = render_markdown(input); 149 insta::assert_snapshot!(output); 150} 151 152#[test] 153fn test_weaver_block_before_code_block() { 154 let input = "\n\n{.aside}\n\n```rust\nfn main() {}\n```"; 155 let output = render_markdown(input); 156 insta::assert_snapshot!(output); 157} 158 159#[test] 160fn test_weaver_block_multiple_classes() { 161 let input = "\n\n{.aside, .highlight, .important}\nMultiple classes applied."; 162 let output = render_markdown(input); 163 insta::assert_snapshot!(output); 164} 165 166#[test] 167fn test_weaver_block_no_effect_on_following() { 168 let input = "\n\n{.aside}\nFirst paragraph in aside.\n\nSecond paragraph NOT in aside."; 169 let output = render_markdown(input); 170 insta::assert_snapshot!(output); 171} 172 173// ============================================================================= 174// Footnote / Sidenote Tests 175// ============================================================================= 176 177#[test] 178fn test_footnote_traditional() { 179 let input = "Here is some text[^1].\n[^1]: This is the footnote definition."; 180 let output = render_markdown(input); 181 insta::assert_snapshot!(output); 182} 183 184#[test] 185fn test_footnote_sidenote_inline() { 186 let input = "Here is text[^note]\n[^note]: Sidenote content."; 187 let output = render_markdown(input); 188 insta::assert_snapshot!(output); 189} 190 191#[test] 192fn test_footnote_multiple() { 193 let input = "First[^1] and second[^2] footnotes.\n[^1]: First note.\n[^2]: Second note."; 194 let output = render_markdown(input); 195 insta::assert_snapshot!(output); 196} 197 198#[test] 199fn test_footnote_with_inline_formatting() { 200 let input = "Text with footnote[^fmt].\n[^fmt]: Note with **bold** and *italic*."; 201 let output = render_markdown(input); 202 insta::assert_snapshot!(output); 203} 204 205#[test] 206fn test_footnote_named() { 207 let input = "Reference[^my-note].\n[^my-note]: Named footnote content."; 208 let output = render_markdown(input); 209 insta::assert_snapshot!(output); 210} 211 212#[test] 213fn test_footnote_in_blockquote() { 214 let input = "> Quote with footnote[^q].\n[^q]: Footnote for quote."; 215 let output = render_markdown(input); 216 insta::assert_snapshot!(output); 217} 218 219// ============================================================================= 220// Combined WeaverBlock + Footnote Tests 221// ============================================================================= 222 223#[test] 224fn test_weaver_block_with_footnote() { 225 let input = "{.aside}\nAside with a footnote[^aside].\n\n[^aside]: Footnote in aside context."; 226 let output = render_markdown(input); 227 insta::assert_snapshot!(output); 228}