use flowmark::config::ListSpacing;
use flowmark::fill_markdown;
fn fmt(input: &str) -> String {
fill_markdown(input, true, 88, true, false, false, false, None, ListSpacing::Preserve)
}
fn fmt_loose(input: &str) -> String {
fill_markdown(input, true, 88, true, false, false, false, None, ListSpacing::Loose)
}
#[test]
fn test_escape_in_heading() {
let result = fmt("## 1\\. Test Heading\n");
assert!(
result.contains("## 1. Test Heading"),
"Escape should be removed in heading: got {result:?}"
);
let result = fmt("### Item 1\\. and 2\\. in title\n");
assert!(
result.contains("### Item 1. and 2. in title"),
"Escapes should be removed in heading: got {result:?}"
);
}
#[test]
fn test_escape_at_paragraph_start() {
let result = fmt("1\\. Not a list\n");
assert!(
result.contains("1\\."),
"Escape should be preserved at paragraph start: got {result:?}"
);
let result = fmt("10\\. Not a list either\n");
assert!(
result.contains("10\\."),
"Escape should be preserved at paragraph start: got {result:?}"
);
}
#[test]
fn test_escape_in_paragraph_middle() {
let result = fmt("Text with 1\\. in middle\n");
assert!(
result.contains("Text with 1. in middle"),
"Escape should be removed mid-paragraph: got {result:?}"
);
let result = fmt("End with number 1\\.\n");
assert!(
result.contains("End with number 1."),
"Escape should be removed at end: got {result:?}"
);
}
#[test]
fn test_actual_list_no_escape() {
let result = fmt_loose("1. First item\n2. Second item\n");
assert!(result.contains("1. First item"), "List items should be preserved");
assert!(result.contains("2. Second item"), "List items should be preserved");
}
#[test]
fn test_other_escaped_chars() {
let result = fmt("Test \\* not emphasis\n");
assert!(result.contains("\\*"), "Asterisk escape should be preserved: got {result:?}");
let result = fmt("Test \\# not heading\n");
assert!(result.contains("\\#"), "Hash escape should be preserved: got {result:?}");
let result = fmt("Text with \\- hyphen\n");
assert!(result.contains("\\-"), "Hyphen escape should be preserved: got {result:?}");
let result = fmt("Cost is \\$100\n");
assert!(result.contains("\\$"), "Dollar escape should be preserved: got {result:?}");
let result = fmt("Use \\_name\\_ for underscores\n");
assert!(result.contains("\\_"), "Underscore escape should be preserved: got {result:?}");
let result = fmt("Not a link: \\[text\\]\n");
assert!(result.contains("\\["), "Open bracket escape should be preserved: got {result:?}");
assert!(result.contains("\\]"), "Close bracket escape should be preserved: got {result:?}");
let result = fmt("Literal \\`backtick\\`\n");
assert!(result.contains("\\`"), "Backtick escape should be preserved: got {result:?}");
}
#[test]
fn test_escaped_chars_in_headings() {
let result = fmt("## Test \\* Heading\n");
assert!(
result.contains("\\*"),
"Asterisk escape should be preserved in heading: got {result:?}"
);
let result = fmt("## Test \\# Heading\n");
assert!(result.contains("\\#"), "Hash escape should be preserved in heading: got {result:?}");
}
#[test]
fn test_escaped_chars_at_line_start() {
let result = fmt("\\* Not a list\n");
assert!(result.contains("\\*"), "Asterisk escape at start should be preserved: got {result:?}");
let result = fmt("\\- Not a list\n");
assert!(result.contains("\\-"), "Hyphen escape at start should be preserved: got {result:?}");
}
#[test]
fn test_escape_in_list_item() {
let result = fmt("- List item 1\\. in middle\n");
assert!(
result.contains("1. in middle"),
"Escape should be removed in list item middle: got {result:?}"
);
}
#[test]
fn test_escape_in_list_item_start_preserved() {
let result = fmt("- 1\\. At start of item\n");
assert!(
result.contains("1\\."),
"Escape should be preserved at list item start: got {result:?}"
);
}
#[test]
fn test_escape_in_quote() {
let result = fmt("> Quote with 1\\. in middle\n");
assert!(
result.contains("1. in middle"),
"Escape should be removed in quote middle: got {result:?}"
);
let result = fmt("> 1\\. Quote start\n");
assert!(result.contains("1\\."), "Escape should be preserved at quote start: got {result:?}");
}
#[test]
fn test_escape_in_table() {
let input = "| Header | 1\\. Cell |\n| --- | --- |\n| 1\\. | Value 1\\. here |\n";
let result = fmt(input);
assert!(result.contains("1. Cell"), "Escape should be removed in table header: got {result:?}");
assert!(
result.contains("Value 1. here"),
"Escape should be removed in table cell: got {result:?}"
);
}
#[test]
fn test_mixed_escapes() {
let input = "## 1\\. Heading\n\nParagraph with 1\\. in middle.\n\n1\\. Start of paragraph\n\n- List 1\\. middle\n- 1\\. start\n\n> 1\\. quote start\n";
let expected = "## 1. Heading\n\nParagraph with 1. in middle.\n\n1\\. Start of paragraph\n\n- List 1. middle\n\n- 1\\. start\n\n> 1\\. quote start\n";
assert_eq!(fmt_loose(input), expected);
}
#[test]
fn test_mixed_escapes_comprehensive() {
let input = "## 1\\. Heading with \\* asterisk\n\nText with 1\\. period and \\* asterisk and \\# hash.\n\n1\\. Not a list (period escape kept)\n\\* Not a list (asterisk escape kept)\n\nCost: \\$100 (dollar escape kept)\n";
let expected = "## 1. Heading with \\* asterisk\n\nText with 1. period and \\* asterisk and \\# hash.\n\n1\\. Not a list (period escape kept) \\* Not a list (asterisk escape kept)\n\nCost: \\$100 (dollar escape kept)\n";
assert_eq!(fmt(input), expected);
}
#[test]
fn test_pua_chars_safe_range_preserved() {
let input = "Text with \u{E080} characters.\n";
let result = fmt(input);
assert!(
result.contains('\u{E080}'),
"PUA char U+E080 (outside placeholder range) should be preserved: {result:?}"
);
}
#[test]
fn test_pua_placeholder_no_collision() {
let input = "Text with \u{E05C} inside.\n";
let result = fmt(input);
assert!(
result.contains('\u{E05C}'),
"PUA char U+E05C should be preserved (no collision with 2-char placeholder): {result:?}"
);
}
#[test]
fn test_pua_adjacent_to_escape() {
let input = "\\*test\u{E080}\n";
let result = fmt(input);
assert!(result.contains('\u{E080}'), "PUA char should be preserved next to escape: {result:?}");
}