use assemblage_db::data::{BlockStyle, Layout, Node, SpanStyle, Styles}; use assemblage_view::{ markup::{block_to_markup, markup_to_block, markup_to_node}, model::{Block, Span}, styles, }; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); #[cfg(target_arch = "wasm32")] #[wasm_bindgen_test] fn markup_as_json_string_with_visible_markup() { use assemblage_view::markup::markup_to_json; assert_eq!( markup_to_json("*some markup*").unwrap(), "{\"type\":\"Text\",\"spans\":[{\"type\":\"Text\",\"styles\":[\"Bold\"],\"text\":\"some markup\"}]}", ); } #[cfg(target_arch = "wasm32")] #[wasm_bindgen_test] fn markup_json_roundtrip() { use assemblage_view::markup::{json_to_markup, markup_to_json}; let markup = "># A quoted heading, with some _italic and *bold*_ text!"; let json = markup_to_json(markup).unwrap(); assert_eq!(json_to_markup(&json).unwrap(), markup); } fn assert_roundtrip(before: &str, after: &str, block: Block) { let markup = format!("{}{}", before, after); assert_eq!(markup_to_block(&markup).unwrap(), block); assert_eq!(block_to_markup(&block).unwrap(), markup); } fn assert_completed_roundtrip(before: &str, after: &str, complete: &str, block: Block) { let markup = format!("{}{}", before, after); assert_eq!(markup_to_block(&markup).unwrap(), block); assert_eq!(block_to_markup(&block).unwrap(), complete); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_markup_to_node() { let markup = "just text"; let node = markup_to_node(markup).unwrap(); assert_eq!( node, Node::list(Layout::Page, vec![Node::text("just text")]) ); let markup = "# A Heading"; let node = markup_to_node(markup).unwrap(); assert_eq!( node, Node::styled( Styles::Block(styles!(BlockStyle::Heading)), Node::text("A Heading") ) ); let markup = "# A *Bold* Heading"; let node = markup_to_node(markup).unwrap(); assert_eq!( node, Node::styled( Styles::Block(styles!(BlockStyle::Heading)), Node::list( Layout::Chain, vec![ Node::text("A "), Node::styled(Styles::Span(styles!(SpanStyle::Bold)), Node::text("Bold")), Node::text(" Heading") ] ) ) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_block_without_markup() { let markup = "some block without special markup"; let block = Block::text(vec![Span::text(markup)]); assert_roundtrip(markup, "", block); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_block_with_block_markup() { let markup = "># A Heading & Quote"; let block = Block::Text { styles: styles![BlockStyle::Heading, BlockStyle::Quote], spans: vec![Span::text("A Heading & Quote")], }; assert_roundtrip(markup, "", block); let block = Block::Text { styles: styles![BlockStyle::Heading, BlockStyle::Quote], spans: vec![Span::text("A Heading & Quote")], }; assert_eq!( markup_to_block("##>#>>#>> A Heading & Quote").unwrap(), block ); assert_eq!(block_to_markup(&block).unwrap(), markup); let markup = ",>-# All block styles"; let block = Block::Text { styles: styles![ BlockStyle::Aside, BlockStyle::List, BlockStyle::Heading, BlockStyle::Quote ], spans: vec![Span::text("All block styles")], }; assert_roundtrip(markup, "", block); let markup = ",>-#no styles because the space after the prefix is missing"; let block = Block::text(vec![Span::text(markup)]); assert_roundtrip(markup, "", block); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_block_with_span_markup() { let markup = "A *very bold* statement!"; let block = Block::text(vec![ Span::text("A "), Span::Text { styles: styles![SpanStyle::Bold], text: "very bold".to_string(), }, Span::text(" statement!"), ]); assert_roundtrip(markup, "", block); let markup = "~_*struck bold italic*_~ _*bold italic*_"; let block = Block::text(vec![ Span::Text { styles: styles![SpanStyle::Struck, SpanStyle::Bold, SpanStyle::Italic], text: "struck bold italic".to_string(), }, Span::text(" "), Span::Text { styles: styles![SpanStyle::Bold, SpanStyle::Italic], text: "bold italic".to_string(), }, ]); assert_roundtrip(markup, "", block); let markup = "*bold*_italic_~struck~`mono`|marked|"; let block = Block::text(vec![ Span::Text { styles: styles![SpanStyle::Bold], text: "bold".to_string(), }, Span::Text { styles: styles![SpanStyle::Italic], text: "italic".to_string(), }, Span::Text { styles: styles![SpanStyle::Struck], text: "struck".to_string(), }, Span::Text { styles: styles![SpanStyle::Mono], text: "mono".to_string(), }, Span::Text { styles: styles![SpanStyle::Marked], text: "marked".to_string(), }, ]); assert_roundtrip(markup, "", block); let markup = "*bold and_italic ~text~_ markup*!"; let block = Block::text(vec![ Span::Text { styles: styles![SpanStyle::Bold], text: "bold and".to_string(), }, Span::Text { styles: styles![SpanStyle::Bold, SpanStyle::Italic], text: "italic ".to_string(), }, Span::Text { styles: styles![SpanStyle::Bold, SpanStyle::Italic, SpanStyle::Struck], text: "text".to_string(), }, Span::Text { styles: styles![SpanStyle::Bold], text: " markup".to_string(), }, Span::text("!"), ]); assert_roundtrip(markup, "", block); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_block_with_incomplete_span_markup() { let incomplete_markup = "italic starts _here but never ends..."; let complete_markup = "italic starts _here but never ends..._"; let block = Block::text(vec![ Span::text("italic starts "), Span::Text { styles: styles![SpanStyle::Italic], text: "here but never ends...".to_string(), }, ]); assert_completed_roundtrip(incomplete_markup, "", complete_markup, block); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_block_with_escaped_span_markup() { let incomplete_markup = "\\_not \\italic, _italic \\_ until here_"; let complete_markup = "\\_not \\\\italic, _italic \\_ until here_"; let block = Block::text(vec![ Span::text("_not \\italic, "), Span::Text { styles: styles![SpanStyle::Italic], text: "italic _ until here".to_string(), }, ]); assert_completed_roundtrip(incomplete_markup, "", complete_markup, block); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_block_with_escaped_block_markup() { let markup = "\\#> neither a heading nor a quote"; let block = Block::text(vec![Span::text("#> neither a heading nor a quote")]); assert_roundtrip(markup, "", block); let incomplete_markup = "\\#>neither a heading nor a quote"; let complete_markup = "\\\\#>neither a heading nor a quote"; let block = Block::text(vec![Span::text(incomplete_markup)]); assert_completed_roundtrip(incomplete_markup, "", complete_markup, block); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_block_with_overlapping_span_markup() { let markup = "bold *and _italic* and ~struck overlap_ here~"; let block = Block::text(vec![ Span::text("bold "), Span::Text { styles: styles![SpanStyle::Bold], text: "and ".to_string(), }, Span::Text { styles: styles![SpanStyle::Bold, SpanStyle::Italic], text: "italic".to_string(), }, Span::Text { styles: styles![SpanStyle::Italic], text: " and ".to_string(), }, Span::Text { styles: styles![SpanStyle::Italic, SpanStyle::Struck], text: "struck overlap".to_string(), }, Span::Text { styles: styles![SpanStyle::Struck], text: " here".to_string(), }, ]); assert_roundtrip(markup, "", block); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn parse_block_with_empty_inline_markup() { let incomplete_markup = "a text that contains empty ** bold markup"; let complete_markup = "a text that contains empty bold markup"; let block = Block::text(vec![ Span::text("a text that contains empty "), Span::text(" bold markup"), ]); assert_completed_roundtrip(incomplete_markup, "", complete_markup, block); let incomplete_markup = "a text that contains empty markup_*"; let complete_markup = "a text that contains empty markup"; let block = Block::text(vec![Span::text("a text that contains empty markup")]); assert_completed_roundtrip(incomplete_markup, "", complete_markup, block); }