mirror of
https://github.com/lexmount/moli.git
synced 2026-09-23 00:01:25 +00:00
256 lines
7.6 KiB
Rust
256 lines
7.6 KiB
Rust
mod support;
|
|
|
|
use moli_html2md::{Converter, Options};
|
|
use support::{Tree, rendered_html};
|
|
|
|
fn markdown_with(html: &str, options: Options) -> String {
|
|
let dom = Tree::parse(html);
|
|
let before = dom.clone();
|
|
let result = Converter::new(options).convert(&dom, dom.root);
|
|
assert_eq!(dom, before);
|
|
result
|
|
}
|
|
|
|
fn markdown(html: &str) -> String {
|
|
markdown_with(html, Options::default())
|
|
}
|
|
|
|
#[test]
|
|
fn inline_code_breaks_separate_words_without_formatting_markers() {
|
|
for html in [
|
|
"<code>git<br>status</code>",
|
|
"<code><strong>git<br></strong><em>status</em></code>",
|
|
"<code><a href='/'>git</a><span><br></span><b>status</b></code>",
|
|
] {
|
|
for preformatted_code in [false, true] {
|
|
let result = markdown_with(
|
|
html,
|
|
Options {
|
|
preformatted_code,
|
|
..Options::default()
|
|
},
|
|
);
|
|
assert_eq!(result, "`git status`", "{html}");
|
|
assert_eq!(
|
|
rendered_html(&result),
|
|
"<p><code>git status</code></p>\n",
|
|
"{html}"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn inline_code_breaks_follow_the_selected_whitespace_mode() {
|
|
let html = "<code>git<br><br> status</code>";
|
|
assert_eq!(markdown(html), "`git status`");
|
|
let result = markdown_with(
|
|
html,
|
|
Options {
|
|
preformatted_code: true,
|
|
..Options::default()
|
|
},
|
|
);
|
|
assert_eq!(result, "`git status`");
|
|
assert_eq!(
|
|
rendered_html(&result),
|
|
"<p><code>git status</code></p>\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn inline_code_breaks_keep_separation_at_code_span_edges() {
|
|
for (html, expected) in [
|
|
(
|
|
"before<code>git<br></code><code>status</code>after",
|
|
"before`git` `status`after",
|
|
),
|
|
("before<code><br>git<br></code>after", "before `git` after"),
|
|
] {
|
|
assert_eq!(markdown(html), expected, "{html}");
|
|
}
|
|
let result = markdown_with(
|
|
"before<code>git<br></code><code>status</code>after",
|
|
Options {
|
|
preformatted_code: true,
|
|
..Options::default()
|
|
},
|
|
);
|
|
assert_eq!(
|
|
rendered_html(&result),
|
|
"<p>before<code>git </code><code>status</code>after</p>\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn inline_code_breaks_obey_the_depth_limit() {
|
|
let html = "<code>git<span><br></span>status</code>";
|
|
for (max_depth, expected) in [(3, "`gitstatus`"), (4, "`git status`")] {
|
|
assert_eq!(
|
|
markdown_with(
|
|
html,
|
|
Options {
|
|
max_depth,
|
|
..Options::default()
|
|
},
|
|
),
|
|
expected
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pre_keeps_raw_text_and_line_endings() {
|
|
let result = markdown("<pre><code><b>git</b>\n <em>status</em></code></pre>");
|
|
assert_eq!(result, "```\ngit\n status\n```");
|
|
assert_eq!(
|
|
rendered_html(&result),
|
|
"<pre><code>git\n status\n</code></pre>\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn preformatted_examples_keep_inline_values_and_separate_display_lines() {
|
|
for (source, expected) in [
|
|
(
|
|
"<pre>const answer = <output>42</output>;</pre>",
|
|
"const answer = 42;",
|
|
),
|
|
(
|
|
"<pre><h3>TypeScript</h3><code>function identity() {}</code></pre>",
|
|
"TypeScript\nfunction identity() {}",
|
|
),
|
|
(
|
|
"<pre><ol><li>first()</li><li>second()</li></ol></pre>",
|
|
"first()\nsecond()",
|
|
),
|
|
("<pre>first<br>second</pre>", "first\nsecond"),
|
|
] {
|
|
let result = markdown(source);
|
|
assert_eq!(
|
|
rendered_html(&result),
|
|
format!("<pre><code>{expected}\n</code></pre>\n"),
|
|
"{source}: {result}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn empty_wrappers_do_not_add_lines_to_preformatted_examples() {
|
|
for (source, expected) in [
|
|
("<pre><div><!-- note --></div>print(42)</pre>", "print(42)"),
|
|
(
|
|
"<pre><section><div></div></section>print(42)</pre>",
|
|
"print(42)",
|
|
),
|
|
(
|
|
"<pre>first<div>second</div>third</pre>",
|
|
"first\nsecond\nthird",
|
|
),
|
|
("<pre><span>\n</span>print(42)</pre>", "\nprint(42)"),
|
|
] {
|
|
let result = markdown(source);
|
|
assert_eq!(
|
|
rendered_html(&result),
|
|
format!("<pre><code>{expected}\n</code></pre>\n"),
|
|
"{source}: {result}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn nested_emphasis_closes_with_markdown_before_a_word() {
|
|
for (html, expected, expected_html) in [
|
|
(
|
|
"<em><strong>x</strong></em>y",
|
|
"***x***y",
|
|
"<p><em><strong>x</strong></em>y</p>\n",
|
|
),
|
|
(
|
|
"<strong><em>x</em></strong>y",
|
|
"***x***y",
|
|
"<p><em><strong>x</strong></em>y</p>\n",
|
|
),
|
|
(
|
|
"a<strong>b<em>c</em></strong>d",
|
|
"a**b*c***d",
|
|
"<p>a<strong>b<em>c</em></strong>d</p>\n",
|
|
),
|
|
(
|
|
"a<em>b<strong>c</strong></em>d",
|
|
"a*b**c***d",
|
|
"<p>a<em>b<strong>c</strong></em>d</p>\n",
|
|
),
|
|
(
|
|
"<strong><em>x</em>y</strong>z",
|
|
"***x*y**z",
|
|
"<p><strong><em>x</em>y</strong>z</p>\n",
|
|
),
|
|
(
|
|
"<em><strong>x</strong>y</em>z",
|
|
"***x**y*z",
|
|
"<p><em><strong>x</strong>y</em>z</p>\n",
|
|
),
|
|
] {
|
|
let result = markdown(html);
|
|
assert_eq!(result, expected, "{html}");
|
|
assert_eq!(rendered_html(&result), expected_html, "{html}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn nested_emphasis_still_uses_html_after_literal_punctuation() {
|
|
for text in ["word!", "word*", "word`", "word)", "日本語。"] {
|
|
for (outer, inner) in [("em", "strong"), ("strong", "em")] {
|
|
let html = format!("<{outer}><{inner}>{text}</{inner}></{outer}>after");
|
|
let result = markdown(&html);
|
|
assert!(result.contains(&format!("<{outer}>")), "{result}");
|
|
assert_eq!(rendered_html(&result), format!("<p>{html}</p>\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn closing_runs_stop_at_links_code_images_and_other_markers() {
|
|
for (html, expected_html) in [
|
|
(
|
|
"<em><strong><a href='/'>x</a></strong></em>y",
|
|
"<p><em><strong><a href=\"/\">x</a></strong></em>y</p>\n",
|
|
),
|
|
(
|
|
"<em><strong><code>x</code></strong></em>y",
|
|
"<p><em><strong><code>x</code></strong></em>y</p>\n",
|
|
),
|
|
(
|
|
"<em><strong><img src='/x' alt='x'></strong></em>y",
|
|
"<p><em><strong><img src=\"/x\" alt=\"x\" /></strong></em>y</p>\n",
|
|
),
|
|
("<em><del>x</del></em>y", "<p><em><del>x</del></em>y</p>\n"),
|
|
("<del><em>x</em></del>y", "<p><del><em>x</em></del>y</p>\n"),
|
|
] {
|
|
assert_eq!(rendered_html(&markdown(html)), expected_html, "{html}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn separate_nested_spans_keep_html_when_delimiters_are_ambiguous() {
|
|
let result = markdown("<em><strong>a</strong>b<strong>c</strong></em>d");
|
|
assert_eq!(result, "<em>**a**b**c**</em>d");
|
|
assert_eq!(
|
|
rendered_html(&result),
|
|
"<p><em><strong>a</strong>b<strong>c</strong></em>d</p>\n"
|
|
);
|
|
for text in ["x", "x!", "x*"] {
|
|
for (outer, inner) in [("em", "strong"), ("strong", "em")] {
|
|
let html = format!(
|
|
"before<{outer}><{inner}>{text}</{inner}>b<{inner}>c</{inner}></{outer}>after"
|
|
);
|
|
assert_eq!(
|
|
rendered_html(&markdown(&html)),
|
|
format!("<p>{html}</p>\n"),
|
|
"{html}"
|
|
);
|
|
}
|
|
}
|
|
}
|