at main 231 lines 6.2 kB view raw
1//! Snapshot tests for EditorWriter output. 2//! 3//! These tests exercise edge cases in paragraph rendering, cursor positioning, 4//! and offset mapping. 5 6use markdown_weaver::Parser; 7 8use crate::text::EditorRope; 9use crate::weaver_renderer; 10 11use super::EditorWriter; 12 13/// Helper to render markdown and return HTML segments + paragraph ranges. 14fn render_markdown(source: &str) -> RenderOutput { 15 let rope = EditorRope::from(source); 16 let parser = Parser::new_ext(source, weaver_renderer::default_md_options()).into_offset_iter(); 17 18 let writer: EditorWriter<'_, _, _, (), (), ()> = 19 EditorWriter::new(source, &rope, parser).with_auto_incrementing_prefix(0); 20 21 let result = writer.run().expect("render failed"); 22 23 RenderOutput { 24 html_segments: result.html_segments, 25 paragraph_ranges: result 26 .paragraph_ranges 27 .into_iter() 28 .map(|(byte_range, char_range)| ParagraphRange { 29 byte_start: byte_range.start, 30 byte_end: byte_range.end, 31 char_start: char_range.start, 32 char_end: char_range.end, 33 }) 34 .collect(), 35 offset_maps: result 36 .offset_maps_by_paragraph 37 .into_iter() 38 .map(|maps| { 39 maps.into_iter() 40 .map(|m| OffsetMapEntry { 41 byte_range: format!("{}..{}", m.byte_range.start, m.byte_range.end), 42 char_range: format!("{}..{}", m.char_range.start, m.char_range.end), 43 node_id: m.node_id.to_string(), 44 char_offset_in_node: m.char_offset_in_node, 45 utf16_len: m.utf16_len, 46 }) 47 .collect() 48 }) 49 .collect(), 50 } 51} 52 53#[derive(Debug, serde::Serialize)] 54struct RenderOutput { 55 html_segments: Vec<String>, 56 paragraph_ranges: Vec<ParagraphRange>, 57 offset_maps: Vec<Vec<OffsetMapEntry>>, 58} 59 60#[derive(Debug, serde::Serialize)] 61struct ParagraphRange { 62 byte_start: usize, 63 byte_end: usize, 64 char_start: usize, 65 char_end: usize, 66} 67 68#[derive(Debug, serde::Serialize)] 69struct OffsetMapEntry { 70 byte_range: String, 71 char_range: String, 72 node_id: String, 73 char_offset_in_node: usize, 74 utf16_len: usize, 75} 76 77// === Trailing paragraph tests === 78 79#[test] 80fn test_single_paragraph_no_trailing() { 81 let output = render_markdown("hello world"); 82 insta::assert_yaml_snapshot!(output); 83} 84 85#[test] 86fn test_single_paragraph_single_newline() { 87 let output = render_markdown("hello world\n"); 88 insta::assert_yaml_snapshot!(output); 89} 90 91#[test] 92fn test_single_paragraph_double_newline() { 93 // This should create a synthetic trailing paragraph 94 let output = render_markdown("hello world\n\n"); 95 insta::assert_yaml_snapshot!(output); 96} 97 98#[test] 99fn test_single_paragraph_triple_newline() { 100 // Multiple trailing newlines 101 let output = render_markdown("hello world\n\n\n"); 102 insta::assert_yaml_snapshot!(output); 103} 104 105#[test] 106fn test_two_paragraphs() { 107 let output = render_markdown("first\n\nsecond"); 108 insta::assert_yaml_snapshot!(output); 109} 110 111#[test] 112fn test_two_paragraphs_trailing() { 113 // Two paragraphs plus trailing newlines 114 let output = render_markdown("first\n\nsecond\n\n"); 115 insta::assert_yaml_snapshot!(output); 116} 117 118// === Multiple blank lines tests === 119 120#[test] 121fn test_three_enters() { 122 // Simulates pressing enter 3 times from empty 123 let output = render_markdown("\n\n\n"); 124 insta::assert_yaml_snapshot!(output); 125} 126 127#[test] 128fn test_four_enters() { 129 // Bug report: 4th enter moves cursor backwards 130 let output = render_markdown("\n\n\n\n"); 131 insta::assert_yaml_snapshot!(output); 132} 133 134#[test] 135fn test_text_then_four_enters() { 136 let output = render_markdown("test\n\n\n\n"); 137 insta::assert_yaml_snapshot!(output); 138} 139 140#[test] 141fn test_many_blank_lines() { 142 // Bug report: arrow keys in many blank lines jumps to top 143 let output = render_markdown("start\n\n\n\n\n\nend"); 144 insta::assert_yaml_snapshot!(output); 145} 146 147// === Blockquote tests === 148 149#[test] 150fn test_blockquote_simple() { 151 let output = render_markdown("> quote"); 152 insta::assert_yaml_snapshot!(output); 153} 154 155#[test] 156fn test_blockquote_with_trailing() { 157 let output = render_markdown("> quote\n\n"); 158 insta::assert_yaml_snapshot!(output); 159} 160 161#[test] 162fn test_blockquote_multiline() { 163 let output = render_markdown("> line one\n> line two"); 164 insta::assert_yaml_snapshot!(output); 165} 166 167#[test] 168fn test_blockquote_then_text() { 169 // Bug report: can't type on right side of > 170 let output = render_markdown("> quote\n\ntext after"); 171 insta::assert_yaml_snapshot!(output); 172} 173 174// === Wikilink tests === 175 176#[test] 177fn test_wikilink_simple() { 178 let output = render_markdown("[[link]]"); 179 insta::assert_yaml_snapshot!(output); 180} 181 182#[test] 183fn test_wikilink_partial() { 184 // Partial wikilink 185 let output = render_markdown("[[word"); 186 insta::assert_yaml_snapshot!(output); 187} 188 189#[test] 190fn test_wikilink_nested_brackets() { 191 // Bug report: [[][]] structure causes trouble 192 let output = render_markdown("[[][]]"); 193 insta::assert_yaml_snapshot!(output); 194} 195 196#[test] 197fn test_wikilink_partial_inside_full() { 198 // Partial link inside full link 199 let output = render_markdown("[[outer[[inner]]outer]]"); 200 insta::assert_yaml_snapshot!(output); 201} 202 203#[test] 204fn test_many_opening_brackets() { 205 // From the screenshot - many [[ in sequence 206 let output = render_markdown("[[[[[[[[[[[[z]]\n]]]]"); 207 insta::assert_yaml_snapshot!(output); 208} 209 210// === Soft break / line continuation tests === 211 212#[test] 213fn test_soft_break() { 214 let output = render_markdown("line one\nline two"); 215 insta::assert_yaml_snapshot!(output); 216} 217 218#[test] 219fn test_hard_break() { 220 // Two trailing spaces = hard break 221 let output = render_markdown("line one \nline two"); 222 insta::assert_yaml_snapshot!(output); 223} 224 225#[test] 226fn test_blank_lines_in_paragraph() { 227 // Text with ZWSP, then blank lines, then more text 228 // This tests the exact case causing cursor jump issues 229 let output = render_markdown("test\n\u{200B}d\n\n\ntsdsd"); 230 insta::assert_yaml_snapshot!(output); 231}