oxedyne/fe2o3/fe2o3_text/tests/markdown.rs
3.9 KiB, 1 run
created by r1870400018:22716, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | use oxedyne_fe2o3_text::doc::{ |
| 2 | Block, |
| 3 | Doc, |
| 4 | Inline, |
| 5 | markdown, |
| 6 | }; |
| 7 | |
| 8 | use oxedyne_fe2o3_core::{ |
| 9 | prelude::*, |
| 10 | test::test_it, |
| 11 | }; |
| 12 | |
| 13 | /// Prose using every construct the tree has a node for. |
| 14 | const SOURCE: &str = "\ |
| 15 | # A title |
| 16 | |
| 17 | A paragraph with **strong**, *emphasis*, `code`, a [link](https://example.com) and an |
| 18 | . |
| 19 | |
| 20 | ## Second |
| 21 | |
| 22 | - One |
| 23 | - Two |
| 24 | - Nested |
| 25 | - Also nested |
| 26 | - Three |
| 27 | |
| 28 | 1. First |
| 29 | 2. Second |
| 30 | |
| 31 | > Quoted, and it goes on. |
| 32 | |
| 33 | | Name | Count | |
| 34 | | :-- | --: | |
| 35 | | Widget | 12 | |
| 36 | |
| 37 | ```rust |
| 38 | fn main() {} |
| 39 | ``` |
| 40 | |
| 41 | --- |
| 42 | |
| 43 | The end. |
| 44 | "; |
| 45 | |
| 46 | pub fn test_markdown(filter: &'static str) -> Outcome<()> { |
| 47 | |
| 48 | res!(test_it(filter, &["A tree written and read back is the same tree 000", "all", "markdown"], || { |
| 49 | // The writer's oracle is the reader, which is tested on its own terms elsewhere. This says the |
| 50 | // two AGREE; it says nothing about either matching CommonMark, and is not offered as if it did. |
| 51 | // What it does catch, and catches nothing else in this crate does, is an escape that changes |
| 52 | // the meaning of a character and an indent that changes what a list is nested inside. |
| 53 | let once = res!(markdown::parse(SOURCE)); |
| 54 | let out = markdown::write::render(&once); |
| 55 | let twice = res!(markdown::parse(&out)); |
| 56 | assert_eq!(once, twice, "written as:\n{}", out); |
| 57 | // And it is stable: writing the tree again gives the same text. |
| 58 | assert_eq!(markdown::write::render(&twice), out); |
| 59 | Ok(()) |
| 60 | })); |
| 61 | |
| 62 | res!(test_it(filter, &["A nested list nests under its parent's text 001", "all", "markdown"], || { |
| 63 | let doc = res!(markdown::parse(SOURCE)); |
| 64 | let out = markdown::write::render(&doc); |
| 65 | assert!(out.contains("- Two\n - Nested\n"), "got:\n{}", out); |
| 66 | // Which is to say the indent is the width of the marker above it, and not a fixed depth that |
| 67 | // doubles at every level. |
| 68 | assert!(!out.contains(" - Nested"), "the indent compounded:\n{}", out); |
| 69 | Ok(()) |
| 70 | })); |
| 71 | |
| 72 | res!(test_it(filter, &["An escape goes where it changes the meaning 002", "all", "markdown"], || { |
| 73 | // A hyphen opening a line opens a list; one in the middle of a sentence is a hyphen. A writer |
| 74 | // that escaped both would fill the document with backslashes, and one that escaped neither |
| 75 | // would turn a sentence into a bullet the next time it was read. |
| 76 | let doc = Doc { |
| 77 | blocks: vec![ |
| 78 | Block::Para(vec![Inline::Text("- not a list".to_string())]), |
| 79 | Block::Para(vec![Inline::Text("a - b - c".to_string())]), |
| 80 | Block::Para(vec![Inline::Text("1. not a list".to_string())]), |
| 81 | Block::Table { |
| 82 | head: None, |
| 83 | rows: vec![oxedyne_fe2o3_text::doc::Row(vec![ |
| 84 | oxedyne_fe2o3_text::doc::Cell(vec![Inline::Text("3.40".to_string())]), |
| 85 | oxedyne_fe2o3_text::doc::Cell(vec![Inline::Text("a | b".to_string())]), |
| 86 | ])], |
| 87 | cols: vec![], |
| 88 | }, |
| 89 | ], |
| 90 | }; |
| 91 | let out = markdown::write::render(&doc); |
| 92 | assert!(out.contains("\\- not a list"), "got:\n{}", out); |
| 93 | assert!(out.contains("a - b - c"), "a hyphen mid-sentence is left alone:\n{}", out); |
| 94 | assert!(out.contains("1\\. not a list"), "got:\n{}", out); |
| 95 | // A price in a cell is not the start of a line, whatever it looks like. |
| 96 | assert!(out.contains("| 3.40 |"), "a cell got a spurious escape:\n{}", out); |
| 97 | assert!(out.contains("a \\| b"), "a pipe in a cell would end it:\n{}", out); |
| 98 | // And all of it reads back as what it said. |
| 99 | let back = res!(markdown::parse(&out)); |
| 100 | assert_eq!(back.blocks[0], doc.blocks[0]); |
| 101 | assert_eq!(back.blocks[1], doc.blocks[1]); |
| 102 | assert_eq!(back.blocks[2], doc.blocks[2]); |
| 103 | Ok(()) |
| 104 | })); |
| 105 | |
| 106 | res!(test_it(filter, &["A fence is longer than anything inside it 003", "all", "markdown"], || { |
| 107 | // A listing about Markdown holds a fence, and a writer that always used three backticks would |
| 108 | // close its own block at the first one. |
| 109 | let doc = Doc { |
| 110 | blocks: vec![Block::Code { |
| 111 | lang: None, |
| 112 | text: "```\nnot the end\n```\n".to_string(), |
| 113 | }], |
| 114 | }; |
| 115 | let out = markdown::write::render(&doc); |
| 116 | assert!(out.starts_with("````\n"), "got:\n{}", out); |
| 117 | let back = res!(markdown::parse(&out)); |
| 118 | assert_eq!(back.blocks, doc.blocks); |
| 119 | Ok(()) |
| 120 | })); |
| 121 | |
| 122 | Ok(()) |
| 123 | } |