use rumdl_lib::lint_context::LintContext;
use rumdl_lib::rule::Rule;
use rumdl_lib::rules::{MD009TrailingSpaces, MD028NoBlanksBlockquote};
#[test]
fn test_issue_66_exact_scenario() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = "# Test blockquote\n\n> La\n> \n> lala";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 0, "MD028 should not flag lines with '> ' marker");
let md009_result = md009.check(&ctx).unwrap();
assert_eq!(md009_result.len(), 0, "MD009 should not flag empty blockquote lines");
let fixed_content = md028.fix(&ctx).unwrap();
assert_eq!(
fixed_content, content,
"Content should not change since there are no violations"
);
}
#[test]
fn test_issue_66_without_space() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = "# Test blockquote\n\n> La\n>\n> lala";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 0, "MD028 should not flag lines with '>' marker");
let md009_result = md009.check(&ctx).unwrap();
assert_eq!(md009_result.len(), 0, "MD009 should not flag");
let fixed_content = md028.fix(&ctx).unwrap();
assert_eq!(fixed_content, content, "Content should not change");
}
#[test]
fn test_issue_66_with_truly_blank_line() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = "# Test blockquote\n\n> La\n\n> lala";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 1, "MD028 should flag truly blank line");
assert_eq!(md028_result[0].line, 4);
let fixed_content = md028.fix(&ctx).unwrap();
assert_eq!(fixed_content, "# Test blockquote\n\n> La\n>\n> lala");
let fixed_ctx = LintContext::new(&fixed_content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md009_after_fix = md009.check(&fixed_ctx).unwrap();
assert_eq!(md009_after_fix.len(), 0, "MD009 should not flag after MD028 fix");
}
#[test]
fn test_md028_does_not_add_trailing_space() {
let md028 = MD028NoBlanksBlockquote;
let content = "> First line\n\n> Third line";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 1, "MD028 should flag truly blank line");
assert_eq!(md028_result[0].line, 2);
let fixed_content = md028.fix(&ctx).unwrap();
assert_eq!(
fixed_content, "> First line\n>\n> Third line",
"MD028 should NOT add space after >"
);
let lines: Vec<&str> = fixed_content.lines().collect();
assert_eq!(lines[1], ">", "Fixed line should be just '>' without trailing space");
}
#[test]
fn test_md009_accepts_empty_blockquote_without_space() {
let md009 = MD009TrailingSpaces::default();
let test_cases = vec![
(">\n", "Single level empty blockquote"),
(">>\n", "Double level empty blockquote"),
(">>>\n", "Triple level empty blockquote"),
(" >\n", "Indented empty blockquote"),
("> Text\n>\n> More", "Empty blockquote in middle"),
];
for (content, description) in test_cases {
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md009.check(&ctx).unwrap();
assert_eq!(result.len(), 0, "MD009 should not flag {description}: {content}");
}
}
#[test]
fn test_md009_flags_multiple_trailing_spaces_in_blockquote() {
let md009 = MD009TrailingSpaces::default();
let test_cases = vec![
("> \n", 0, "Two spaces after > (allowed as line break)"),
(">> \n", 1, "Three spaces after >> (exceeds br_spaces)"),
("> Text \n", 0, "Two spaces after text (allowed as line break)"),
("> Text \n", 1, "Three spaces after text (exceeds br_spaces)"),
];
for (content, expected_warnings, description) in test_cases {
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md009.check(&ctx).unwrap();
assert_eq!(
result.len(),
expected_warnings,
"MD009 failed for {description}: {content}"
);
}
}
#[test]
fn test_md028_md009_nested_blockquotes() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = "> Level 1\n\n>> Level 2\n\n> Level 1 again";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 1);
assert_eq!(md028_result[0].line, 2);
let fixed = md028.fix(&ctx).unwrap();
assert_eq!(fixed, "> Level 1\n>\n>> Level 2\n\n> Level 1 again");
let fixed_ctx = LintContext::new(&fixed, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md009_result = md009.check(&fixed_ctx).unwrap();
assert_eq!(md009_result.len(), 0, "MD009 should not flag fixed nested blockquote");
}
#[test]
fn test_md028_md009_indented_blockquotes() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = " > Indented\n\n > More";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 1);
assert_eq!(md028_result[0].line, 2);
let fixed = md028.fix(&ctx).unwrap();
assert_eq!(fixed, " > Indented\n >\n > More");
let fixed_ctx = LintContext::new(&fixed, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md009_result = md009.check(&fixed_ctx).unwrap();
assert_eq!(md009_result.len(), 0, "MD009 should not flag fixed indented blockquote");
}
#[test]
fn test_md028_flags_blockquote_with_only_space() {
let md028 = MD028NoBlanksBlockquote;
let content = "> First\n> \n> Third";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md028.check(&ctx).unwrap();
assert_eq!(result.len(), 0, "MD028 should not flag blockquote line with space");
}
#[test]
fn test_multiple_fixes_dont_conflict() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = "> Block 1\n\n> Still block 1 \n\n> Block 2\n\n>> Nested ";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 3, "Should find 3 blank lines");
let md009_result = md009.check(&ctx).unwrap();
assert!(!md009_result.is_empty(), "Should find at least 1 trailing space issue");
let fixed_md028 = md028.fix(&ctx).unwrap();
let ctx_after_md028 = LintContext::new(&fixed_md028, rumdl_lib::config::MarkdownFlavor::Standard, None);
let final_fixed = md009.fix(&ctx_after_md028).unwrap();
let final_ctx = LintContext::new(&final_fixed, rumdl_lib::config::MarkdownFlavor::Standard, None);
let final_md028_check = md028.check(&final_ctx).unwrap();
let final_md009_check = md009.check(&final_ctx).unwrap();
assert_eq!(final_md028_check.len(), 0, "No MD028 issues after both fixes");
assert_eq!(final_md009_check.len(), 0, "No MD009 issues after both fixes");
}
#[test]
fn test_edge_case_only_blockquote_markers() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = ">\n>>\n>>>\n>";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(
md028_result.len(),
0,
"Lines with blockquote markers should not be flagged"
);
let md009_result = md009.check(&ctx).unwrap();
assert_eq!(
md009_result.len(),
0,
"MD009 should not flag empty blockquotes without trailing space"
);
}
#[test]
fn test_blockquote_with_tabs() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = ">\t\n> \t \n> text\t";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md009_result = md009.check(&ctx).unwrap();
assert_eq!(
md009_result.len(),
0,
"MD009 should not flag empty blockquote lines even with tabs/spaces"
);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 0, "MD028 should not flag blockquotes with tabs");
}
#[test]
fn test_mixed_blockquote_and_list() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = "> * Item 1\n\n> * Item 2";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 1, "Should flag blank line");
let fixed = md028.fix(&ctx).unwrap();
assert_eq!(fixed, "> * Item 1\n>\n> * Item 2");
let fixed_ctx = LintContext::new(&fixed, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md009_result = md009.check(&fixed_ctx).unwrap();
assert_eq!(md009_result.len(), 0, "MD009 should not flag fixed content");
}
#[test]
fn test_blockquote_at_end_of_file() {
let md028 = MD028NoBlanksBlockquote;
let md009 = MD009TrailingSpaces::default();
let content = "> First\n>";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let md028_result = md028.check(&ctx).unwrap();
assert_eq!(md028_result.len(), 0);
let md009_result = md009.check(&ctx).unwrap();
assert_eq!(md009_result.len(), 0);
}