1 use super::{find_testable_code, plain_text_summary, short_markdown_summary};
2 use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownItemInfo};
3 use rustc_span::edition::{Edition, DEFAULT_EDITION};
40 let mut map = IdMap::new();
41 let actual: Vec<String> = input.iter().map(|s| map.derive(s.to_string())).collect();
42 assert_eq!(&actual[..], expected);
46 fn test_lang_string_parse() {
47 fn t(lg: LangString) {
49 assert_eq!(LangString::parse(s, ErrorCodes::Yes, true, None), lg)
52 t(Default::default());
53 t(LangString { original: "rust".into(), ..Default::default() });
54 t(LangString { original: ".rust".into(), ..Default::default() });
55 t(LangString { original: "{rust}".into(), ..Default::default() });
56 t(LangString { original: "{.rust}".into(), ..Default::default() });
57 t(LangString { original: "sh".into(), rust: false, ..Default::default() });
58 t(LangString { original: "ignore".into(), ignore: Ignore::All, ..Default::default() });
60 original: "ignore-foo".into(),
61 ignore: Ignore::Some(vec!["foo".to_string()]),
64 t(LangString { original: "should_panic".into(), should_panic: true, ..Default::default() });
65 t(LangString { original: "no_run".into(), no_run: true, ..Default::default() });
66 t(LangString { original: "test_harness".into(), test_harness: true, ..Default::default() });
68 original: "compile_fail".into(),
73 t(LangString { original: "no_run,example".into(), no_run: true, ..Default::default() });
75 original: "sh,should_panic".into(),
80 t(LangString { original: "example,rust".into(), ..Default::default() });
82 original: "test_harness,.rust".into(),
87 original: "text, no_run".into(),
93 original: "text,no_run".into(),
99 original: "text,no_run, ".into(),
105 original: "text,no_run,".into(),
111 original: "edition2015".into(),
112 edition: Some(Edition::Edition2015),
116 original: "edition2018".into(),
117 edition: Some(Edition::Edition2018),
123 fn test_lang_string_tokenizer() {
124 fn case(lang_string: &str, want: &[&str]) {
125 let have = LangString::tokens(lang_string).collect::<Vec<&str>>();
126 assert_eq!(have, want, "Unexpected lang string split for `{}`", lang_string);
130 case("foo", &["foo"]);
131 case("foo,bar", &["foo", "bar"]);
132 case(".foo,.bar", &["foo", "bar"]);
133 case("{.foo,.bar}", &["foo", "bar"]);
134 case(" {.foo,.bar} ", &["foo", "bar"]);
135 case("foo bar", &["foo", "bar"]);
136 case("foo\tbar", &["foo", "bar"]);
137 case("foo\t, bar", &["foo", "bar"]);
138 case(" foo , bar ", &["foo", "bar"]);
139 case(",,foo,,bar,,", &["foo", "bar"]);
140 case("foo=bar", &["foo=bar"]);
141 case("a-b-c", &["a-b-c"]);
142 case("a_b_c", &["a_b_c"]);
147 fn t(input: &str, expect: &str) {
148 let mut map = IdMap::new();
149 let output = Markdown {
153 error_codes: ErrorCodes::Yes,
154 edition: DEFAULT_EDITION,
156 heading_offset: HeadingOffset::H2,
159 assert_eq!(output, expect, "original: {}", input);
162 t("# Foo bar", "<h2 id=\"foo-bar\"><a href=\"#foo-bar\">Foo bar</a></h2>");
164 "## Foo-bar_baz qux",
165 "<h3 id=\"foo-bar_baz-qux\">\
166 <a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h3>",
169 "### **Foo** *bar* baz!?!& -_qux_-%",
170 "<h4 id=\"foo-bar-baz--qux-\">\
171 <a href=\"#foo-bar-baz--qux-\"><strong>Foo</strong> \
172 <em>bar</em> baz!?!& -<em>qux</em>-%</a>\
176 "#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux",
177 "<h5 id=\"foo--bar--baz--qux\">\
178 <a href=\"#foo--bar--baz--qux\"><strong>Foo?</strong> & *bar?!* \
179 <em><code>baz</code></em> ❤ #qux</a>\
185 fn test_header_ids_multiple_blocks() {
186 let mut map = IdMap::new();
187 fn t(map: &mut IdMap, input: &str, expect: &str) {
188 let output = Markdown {
192 error_codes: ErrorCodes::Yes,
193 edition: DEFAULT_EDITION,
195 heading_offset: HeadingOffset::H2,
198 assert_eq!(output, expect, "original: {}", input);
201 t(&mut map, "# Example", "<h2 id=\"example\"><a href=\"#example\">Example</a></h2>");
202 t(&mut map, "# Panics", "<h2 id=\"panics\"><a href=\"#panics\">Panics</a></h2>");
203 t(&mut map, "# Example", "<h2 id=\"example-1\"><a href=\"#example-1\">Example</a></h2>");
204 t(&mut map, "# Search", "<h2 id=\"search-1\"><a href=\"#search-1\">Search</a></h2>");
205 t(&mut map, "# Example", "<h2 id=\"example-2\"><a href=\"#example-2\">Example</a></h2>");
206 t(&mut map, "# Panics", "<h2 id=\"panics-1\"><a href=\"#panics-1\">Panics</a></h2>");
210 fn test_short_markdown_summary() {
211 fn t(input: &str, expect: &str) {
212 let output = short_markdown_summary(input, &[][..]);
213 assert_eq!(output, expect, "original: {}", input);
217 t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
218 t("*italic*", "<em>italic</em>");
219 t("**bold**", "<strong>bold</strong>");
220 t("Multi-line\nsummary", "Multi-line summary");
221 t("Hard-break \nsummary", "Hard-break summary");
222 t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
223 t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
224 t("dud [link]", "dud [link]");
225 t("code `let x = i32;` ...", "code <code>let x = i32;</code> …");
226 t("type `Type<'static>` ...", "type <code>Type<'static></code> …");
227 // Test to ensure escaping and length-limiting work well together.
228 // The output should be limited based on the input length,
229 // rather than the output, because escaped versions of characters
230 // are usually longer than how the character is actually displayed.
232 "& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &",
233 "& & & & & & & & & & & & \
234 & & & & & & & & & & & & \
235 & & & & & …",
237 t("# top header", "top header");
238 t("# top header\n\nfollowed by a paragraph", "top header");
239 t("## header", "header");
240 t("first paragraph\n\nsecond paragraph", "first paragraph");
241 t("```\nfn main() {}\n```", "");
242 t("<div>hello</div>", "");
244 "a *very*, **very** long first paragraph. it has lots of `inline code: Vec<T>`. and it has a [link](https://www.rust-lang.org).\nthat was a soft line break! \nthat was a hard one\n\nsecond paragraph.",
245 "a <em>very</em>, <strong>very</strong> long first paragraph. it has lots of …",
250 fn test_plain_text_summary() {
251 fn t(input: &str, expect: &str) {
252 let output = plain_text_summary(input);
253 assert_eq!(output, expect, "original: {}", input);
257 t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
258 t("**bold**", "bold");
259 t("Multi-line\nsummary", "Multi-line summary");
260 t("Hard-break \nsummary", "Hard-break summary");
261 t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)");
262 t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
263 t("dud [link]", "dud [link]");
264 t("code `let x = i32;` ...", "code `let x = i32;` …");
265 t("type `Type<'static>` ...", "type `Type<'static>` …");
266 t("# top header", "top header");
267 t("# top header\n\nfollowed by some text", "top header");
268 t("## header", "header");
269 t("first paragraph\n\nsecond paragraph", "first paragraph");
270 t("```\nfn main() {}\n```", "");
271 t("<div>hello</div>", "");
273 "a *very*, **very** long first paragraph. it has lots of `inline code: Vec<T>`. and it has a [link](https://www.rust-lang.org).\nthat was a soft line break! \nthat was a hard one\n\nsecond paragraph.",
274 "a very, very long first paragraph. it has lots of `inline code: Vec<T>`. and it has a link. that was a soft line break! that was a hard one",
279 fn test_markdown_html_escape() {
280 fn t(input: &str, expect: &str) {
281 let mut idmap = IdMap::new();
282 let output = MarkdownItemInfo(input, &mut idmap).into_string();
283 assert_eq!(output, expect, "original: {}", input);
286 t("`Struct<'a, T>`", "<code>Struct<'a, T></code>");
287 t("Struct<'a, T>", "Struct<’a, T>");
288 t("Struct<br>", "Struct<br>");
292 fn test_find_testable_code_line() {
293 fn t(input: &str, expect: &[usize]) {
294 impl crate::doctest::Tester for Vec<usize> {
295 fn add_test(&mut self, _test: String, _config: LangString, line: usize) {
299 let mut lines = Vec::<usize>::new();
300 find_testable_code(input, &mut lines, ErrorCodes::No, false, None);
301 assert_eq!(lines, expect);
305 t("```rust\n```", &[1]);
306 t(" ```rust\n```", &[1]);
307 t("\n```rust\n```", &[2]);
308 t("\n ```rust\n```", &[2]);
309 t("```rust\n```\n```rust\n```", &[1, 3]);
310 t("```rust\n```\n ```rust\n```", &[1, 3]);
314 fn test_ascii_with_prepending_hashtag() {
315 fn t(input: &str, expect: &str) {
316 let mut map = IdMap::new();
317 let output = Markdown {
321 error_codes: ErrorCodes::Yes,
322 edition: DEFAULT_EDITION,
324 heading_offset: HeadingOffset::H2,
327 assert_eq!(output, expect, "original: {}", input);
332 #..#.####.#....#.....##..
333 #..#.#....#....#....#..#.
334 ####.###..#....#....#..#.
335 #..#.#....#....#....#..#.
336 #..#.#....#....#....#..#.
337 #..#.####.####.####..##..
339 "<div class=\"example-wrap\"><pre class=\"language-ascii\"><code>\
340 #..#.####.#....#.....##..
341 #..#.#....#....#....#..#.
342 ####.###..#....#....#..#.
343 #..#.#....#....#....#..#.
344 #..#.#....#....#....#..#.
345 #..#.####.####.####..##..
346 </code></pre></div>",