LCOV - code coverage report
Current view: top level - dashql-core-session/src/visualize/markdown - tests.rs Coverage Total Hit
Test: DashQL 915828b Lines: 100.0 % 96 96
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : use super::*;
       2              : 
       3              : /// A compact rendering of a document: `type[attrs](children)`
       4          105 : fn render(node: &MarkdownNode) -> String {
       5              :     // The names of the snapshots, `LIST_ITEM` is `listItem`
       6          105 :     let mut out = String::new();
       7          117 :     for (i, part) in node.node_type.variant_name().unwrap_or("?").split('_').enumerate() {
       8          117 :         let part = part.to_ascii_lowercase();
       9          117 :         if i == 0 {
      10          105 :             out += ∂
      11          105 :         } else {
      12           12 :             out += &part[..1].to_ascii_uppercase();
      13           12 :             out += &part[1..];
      14           12 :         }
      15              :     }
      16          105 :     let mut attrs = Vec::new();
      17          420 :     for (key, value) in [("value", &node.value), ("url", &node.url), ("title", &node.title), ("lang", &node.language)] {
      18          420 :         if !value.is_empty() {
      19           52 :             attrs.push(format!("{key}={value:?}"));
      20          368 :         }
      21              :     }
      22          105 :     if node.node_type == MarkdownNodeType::HEADING {
      23            2 :         attrs.push(format!("level={}", node.level));
      24          103 :     }
      25          105 :     if node.node_type == MarkdownNodeType::LIST {
      26            3 :         attrs.push(format!("ordered={} tight={} start={}", node.ordered, node.tight, node.start));
      27          102 :     }
      28          105 :     if !attrs.is_empty() {
      29           55 :         out += &format!("[{}]", attrs.join(" "));
      30           55 :     }
      31          105 :     if !node.children.is_empty() {
      32           60 :         out += &format!("({})", node.children.iter().map(render).collect::<Vec<_>>().join(", "));
      33           60 :     }
      34          105 :     out
      35          105 : }
      36              : 
      37           18 : fn compile(template: &str) -> String {
      38           18 :     render(&compile_markdown_template(template).document)
      39           18 : }
      40              : 
      41              : #[test]
      42            1 : fn tokenizes_fields() {
      43            1 :     let document = compile_markdown_template("{{ a }} {{b}} {{a}} {{}} {{ ");
      44            1 :     assert_eq!(document.fields, vec!["a", "b"]);
      45            1 :     assert_eq!(
      46            1 :         render(&document.document),
      47              :         "document(paragraph(field[value=\"a\"], text[value=\" \"], field[value=\"b\"], text[value=\" \"], \
      48              :          field[value=\"a\"], text[value=\" {{}} {{\"]))"
      49              :     );
      50              :     // The token prefix grows until it does not occur in the template
      51            1 :     let (markdown, _) = tokenize_fields("DASHQLMARKDOWNFIELD {{x}}");
      52            1 :     assert_eq!(markdown, "DASHQLMARKDOWNFIELD DASHQLMARKDOWNFIELDX0TOKEN");
      53              :     // Fields in code, and fields in raw HTML are dropped with it
      54            1 :     assert_eq!(
      55            1 :         compile("`{{a}}` <b title=\"{{b}}\">x</b>"),
      56              :         "document(paragraph(inlineCode(field[value=\"a\"]), text[value=\" x\"]))"
      57              :     );
      58            1 : }
      59              : 
      60              : #[test]
      61            1 : fn merges_text() {
      62            1 :     assert_eq!(compile("a\\*b &amp; c"), "document(paragraph(text[value=\"a*b & c\"]))");
      63            1 :     assert_eq!(compile("&bogus; &#x41; &#0;"), "document(paragraph(text[value=\"&bogus; A \u{fffd}\"]))");
      64            1 :     assert_eq!(compile("a\0b"), "document(paragraph(text[value=\"a\u{fffd}b\"]))");
      65            1 :     assert_eq!(compile("a\nb <!-- c --> {{x}}"), "document(paragraph(text[value=\"a\\nb  \"], field[value=\"x\"]))");
      66            1 : }
      67              : 
      68              : #[test]
      69            1 : fn builds_blocks() {
      70            1 :     assert_eq!(
      71            1 :         compile("# H1 #\n\nSetext\n---"),
      72              :         "document(heading[level=1](text[value=\"H1\"]), heading[level=2](text[value=\"Setext\"]))"
      73              :     );
      74            1 :     assert_eq!(
      75            1 :         compile("- a\n- b\n\n1) c"),
      76              :         "document(list[ordered=false tight=true start=0](listItem(text[value=\"a\"]), listItem(text[value=\"b\"])), \
      77              :          list[ordered=true tight=true start=1](listItem(text[value=\"c\"])))"
      78              :     );
      79            1 :     assert_eq!(
      80            1 :         compile("- a\n\n- b"),
      81              :         "document(list[ordered=false tight=false start=0](listItem(paragraph(text[value=\"a\"])), listItem(paragraph(text[value=\"b\"]))))"
      82              :     );
      83            1 :     assert_eq!(
      84            1 :         compile("```sql x\nselect\n1\n```\n\n    code"),
      85              :         "document(codeBlock[lang=\"sql\"](text[value=\"select\\n1\\n\"]), codeBlock(text[value=\"code\"]))"
      86              :     );
      87            1 :     assert_eq!(compile("<div>\nhtml\n</div>\n\n***"), "document(thematicBreak)");
      88            1 :     assert_eq!(compile("> q\n"), "document(blockquote(paragraph(text[value=\"q\"])))");
      89            1 : }
      90              : 
      91              : #[test]
      92            1 : fn resolves_links() {
      93            1 :     assert_eq!(
      94            1 :         compile("[a][ref] ![img](/x.png \"t\") <https://x.y> <me@x.y> [bad](javascript:x)\n\n[REF]: http://r 'T'"),
      95              :         "document(paragraph(link[url=\"http://r\" title=\"T\"](text[value=\"a\"]), text[value=\" \"], \
      96              :          image[url=\"/x.png\" title=\"t\"](text[value=\"img\"]), text[value=\" \"], link[url=\"https://x.y\"](text[value=\"https://x.y\"]), \
      97              :          text[value=\" \"], link[url=\"mailto:me@x.y\"](text[value=\"me@x.y\"]), text[value=\" \"], span[url=\"javascript:x\"](text[value=\"bad\"])))"
      98              :     );
      99            1 :     assert_eq!(
     100            1 :         compile("[x]({{f}} \"{{f}}\")"),
     101              :         "document(paragraph(span[url=\"DASHQLMARKDOWNFIELD0TOKEN\"](text[value=\"x\"])))"
     102              :     );
     103            1 :     assert_eq!(compile("[x](/a&amp;b\\) \"t {{f}}\")"), "document(paragraph(link[url=\"/a&b)\"](text[value=\"x\"])))");
     104            1 : }
     105              : 
     106              : #[test]
     107            1 : fn resolves_emphasis() {
     108            1 :     assert_eq!(compile("***a** b*"), "document(paragraph(emphasis(strong(text[value=\"a\"]), text[value=\" b\"])))");
     109            1 :     assert_eq!(compile("a_b_c *x*"), "document(paragraph(text[value=\"a_b_c \"], emphasis(text[value=\"x\"])))");
     110            1 :     assert_eq!(compile("`` a`b ``"), "document(paragraph(inlineCode(text[value=\"a`b\"])))");
     111            1 :     assert_eq!(
     112            1 :         compile("a  \nb\\\nc"),
     113              :         "document(paragraph(text[value=\"a\"], hardBreak, text[value=\"b\"], hardBreak, text[value=\"c\"]))"
     114              :     );
     115            1 : }
     116              : 
     117              : #[test]
     118            1 : fn checks_urls() {
     119            1 :     assert!(is_safe_url("https://x"));
     120            1 :     assert!(is_safe_url("/a:b"));
     121            1 :     assert!(is_safe_url("a?b:c"));
     122            1 :     assert!(is_safe_url(" MailTo:x"));
     123            1 :     assert!(!is_safe_url("java\nscript:alert(1)"));
     124            1 :     assert!(!is_safe_url("data:text"));
     125            1 : }
     126              : 
     127              : #[test]
     128            1 : fn packs_documents() {
     129            1 :     let document = compile_markdown_template("# {{a}}");
     130            1 :     let mut builder = FlatBufferBuilder::new();
     131            1 :     let spec = pack_markdown_spec(&mut builder, &document);
     132            1 :     builder.finish(spec, None);
     133            1 :     let spec = flatbuffers::root::<MarkdownSpec>(builder.finished_data()).unwrap();
     134            1 :     assert_eq!(spec.template(), Some("# {{a}}"));
     135            1 :     let root = spec.document().unwrap();
     136            1 :     assert_eq!(root.node_type(), MarkdownNodeType::DOCUMENT);
     137            1 :     assert_eq!(root.value(), None);
     138            1 :     let heading = root.children().unwrap().get(0);
     139            1 :     assert_eq!(heading.level(), 1);
     140            1 :     assert_eq!(heading.children().unwrap().get(0).value(), Some("a"));
     141            1 : }
        

Generated by: LCOV version 2.0-1