use rumdl_lib::lint_context::LintContext;
use rumdl_lib::rule::Rule;
use rumdl_lib::rules::{MD011NoReversedLinks, MD037NoSpaceInEmphasis, MD052ReferenceLinkImages};
#[test]
fn test_md037_skips_html_comments() {
let rule = MD037NoSpaceInEmphasis;
let content = r#"# Test MD037 with HTML Comments
Regular text with * spaces * that should be flagged.
<!-- This has * spaces * inside a comment and should NOT be flagged -->
More text with * another issue * here.
<!--
Multi-line comment with
* spaced emphasis *
should also be ignored
-->
Final * test * outside comments."#;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 3, "Expected 3 warnings for emphasis outside comments");
let lines_with_issues: Vec<usize> = result.iter().map(|w| w.line).collect();
assert!(lines_with_issues.contains(&3), "Should flag line 3");
assert!(lines_with_issues.contains(&7), "Should flag line 7");
assert!(lines_with_issues.contains(&15), "Should flag line 15");
}
#[test]
fn test_md037_skips_math_contexts() {
let rule = MD037NoSpaceInEmphasis;
let content = r#"# Test MD037 with Math Contexts
Regular text with * spaces * that should be flagged.
$$
This is a math block with * asterisks * that should NOT be flagged.
They might represent multiplication: a * b * c
$$
Inline math $a * b * c$ should also not be flagged.
Double dollar inline math $$x * y * z$$ should not be flagged.
But this * spaced emphasis * outside math should be flagged."#;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Expected 2 warnings for emphasis outside math");
let lines_with_issues: Vec<usize> = result.iter().map(|w| w.line).collect();
assert!(lines_with_issues.contains(&3), "Should flag line 3");
assert!(lines_with_issues.contains(&14), "Should flag line 14");
}
#[test]
fn test_md052_skips_html_comments() {
let rule = MD052ReferenceLinkImages::new();
let content = r#"# Test MD052 with HTML Comments
Regular [undefined][ref1] reference that should be flagged.
<!-- This [hidden][ref2] reference should NOT be flagged -->
Another [missing][ref3] reference outside comments.
<!--
Multi-line comment with
[ignored][ref4] reference
and [another][ref5] one
-->
<!-- Complex patterns like [1:] from issue #20 should not be flagged -->"#;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Expected 2 warnings for references outside comments");
let messages: Vec<String> = result.iter().map(|w| w.message.clone()).collect();
assert!(messages.iter().any(|m| m.contains("ref1")), "Should flag ref1");
assert!(messages.iter().any(|m| m.contains("ref3")), "Should flag ref3");
assert!(
!messages.iter().any(|m| m.contains("ref2")),
"Should not flag ref2 in comment"
);
assert!(
!messages.iter().any(|m| m.contains("ref4")),
"Should not flag ref4 in comment"
);
assert!(
!messages.iter().any(|m| m.contains("ref5")),
"Should not flag ref5 in comment"
);
}
#[test]
fn test_md052_skips_math_contexts() {
let rule = MD052ReferenceLinkImages::new();
let content = r#"# Test MD052 with Math
Regular [text][undefined_ref] reference that should be flagged.
$$
This is a math block with array notation [0] and [1] that should NOT be flagged.
Matrix element M[i][j] should also be ignored.
$$
Inline math with array $a[0]$ and matrix $M[i][j]$ should not be flagged.
Double dollar inline $$f[x]$$ should not be flagged.
But this [link][missing_ref] reference outside math should be flagged."#;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Expected 2 warnings for references outside math");
let messages: Vec<String> = result.iter().map(|w| w.message.clone()).collect();
assert!(
messages.iter().any(|m| m.contains("undefined_ref")),
"Should flag 'undefined_ref'"
);
assert!(
messages.iter().any(|m| m.contains("missing_ref")),
"Should flag 'missing_ref'"
);
}
#[test]
fn test_md052_skips_tables() {
let rule = MD052ReferenceLinkImages::new();
let content = r#"# Test MD052 with Tables
Regular [link][undefined_ref] reference that should be flagged.
| Header | Column |
|--------|--------|
| Cell with [ref1][x] | Another [ref2][y] |
| More [ref3][z] data | Final [ref4][w] cell |
This [link2][missing_ref] reference outside the table should be flagged.
Another table:
| Col 1 | Col 2 | Col 3 |
|-------|-------|-------|
| [a][x1] | [b][x2] | [c][x3] |
Final [link3][broken_ref] reference should be flagged."#;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 3, "Expected 3 warnings for references outside tables");
let messages: Vec<String> = result.iter().map(|w| w.message.clone()).collect();
assert!(
messages.iter().any(|m| m.contains("undefined_ref")),
"Should flag 'undefined_ref'"
);
assert!(
messages.iter().any(|m| m.contains("missing_ref")),
"Should flag 'missing_ref'"
);
assert!(
messages.iter().any(|m| m.contains("broken_ref")),
"Should flag 'broken_ref'"
);
}
#[test]
fn test_md011_skips_html_comments() {
let rule = MD011NoReversedLinks;
let content = r#"# Test MD011 with HTML Comments
Regular (https://example.com)[reversed link] that should be flagged.
<!-- This (https://hidden.com)[in comment] should NOT be flagged -->
Another (https://test.com)[reversed] link outside comments.
<!--
Multi-line comment with
(https://ignored.com)[reversed syntax]
should also be ignored
-->"#;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(
result.len(),
2,
"Expected 2 warnings for reversed links outside comments"
);
let lines_with_issues: Vec<usize> = result.iter().map(|w| w.line).collect();
assert!(lines_with_issues.contains(&3), "Should flag line 3");
assert!(lines_with_issues.contains(&7), "Should flag line 7");
}
#[test]
fn test_md011_skips_math_contexts() {
let rule = MD011NoReversedLinks;
let content = r#"# Test MD011 with Math
Regular (https://example.com)[reversed link] that should be flagged.
$$
Function notation f(x)[0] should NOT be flagged.
Array access pattern (arr)[index] should be ignored.
$$
Inline math $f(x)[i]$ should not be flagged.
Double dollar inline $$g(y)[j]$$ should not be flagged.
But this (https://test.com)[reversed] outside math should be flagged."#;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Expected 2 warnings for reversed links outside math");
let lines_with_issues: Vec<usize> = result.iter().map(|w| w.line).collect();
assert!(lines_with_issues.contains(&3), "Should flag line 3");
assert!(lines_with_issues.contains(&14), "Should flag line 14");
}
#[test]
fn test_md011_skips_front_matter() {
let rule = MD011NoReversedLinks;
let content = r#"---
title: "My Post"
tags: ["test", "example"]
description: "Pattern (like)[this] in frontmatter"
---
# Content
Regular (https://example.com)[reversed link] that should be flagged.
+++
title = "TOML frontmatter"
tags = ["more", "tags"]
pattern = "(toml)[pattern]"
+++
# More Content
Another (https://test.com)[reversed] link should be flagged."#;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(
result.len(),
3,
"Expected 3 warnings for reversed links outside front matter"
);
let lines_with_issues: Vec<usize> = result.iter().map(|w| w.line).collect();
assert!(lines_with_issues.contains(&9), "Should flag line 9");
assert!(
lines_with_issues.contains(&14),
"Should flag line 14 (TOML block is not front matter)"
);
assert!(lines_with_issues.contains(&19), "Should flag line 19");
}
#[test]
fn test_combined_skip_contexts() {
let content = r#"---
frontmatter: "with (pattern)[like] this"
---
# Test Document
Regular * emphasis with spaces * should be flagged.
<!-- HTML comment with * spaces * and [link][undefined] reference -->
$$
Math block with * asterisks * and [array][notation]
$$
Inline math $f(x) * g(x)$ and $a[i]$ should be skipped.
| Table | Header |
|-------|--------|
| * spaces * | [ref][x] |
Outside contexts: * spaced * emphasis and [link][missing_ref] reference and (https://example.com)[reversed] link."#;
let md037 = MD037NoSpaceInEmphasis;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md037.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "MD037: Expected 2 warnings outside skip contexts");
let md052 = MD052ReferenceLinkImages::new();
let result = md052.check(&ctx).unwrap();
assert_eq!(result.len(), 1, "MD052: Expected 1 warning for 'missing_ref' reference");
let md011 = MD011NoReversedLinks;
let result = md011.check(&ctx).unwrap();
assert_eq!(result.len(), 1, "MD011: Expected 1 warning for reversed link");
}
#[test]
fn test_nested_contexts() {
let content = r#"# Nested Contexts Test
<!-- Comment with `inline code containing * spaces *` should be skipped entirely -->
Math with inline code: $$`array[0]` is inline code in math$$
Regular * spaces * outside all contexts should be flagged."#;
let md037 = MD037NoSpaceInEmphasis;
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md037.check(&ctx).unwrap();
assert_eq!(
result.len(),
1,
"Expected only 1 warning for emphasis outside all contexts"
);
assert_eq!(result[0].line, 7, "Should flag line 7");
}