use rumdl_lib::config::MarkdownFlavor;
use rumdl_lib::lint_context::LintContext;
use rumdl_lib::rule::Rule;
use rumdl_lib::rules::{MD022BlanksAroundHeadings, MD031BlanksAroundFences, MD032BlanksAroundLists};
#[test]
fn test_mkdocs_admonitions_md031_blanks() {
let content = r#"# Document
Some text here.
!!! note "Important Note"
This is content inside the admonition.
More content here.
More text after.
!!! warning
Properly spaced admonition.
Good spacing."#;
let rule = MD031BlanksAroundFences::default();
let ctx_mkdocs = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx_mkdocs).unwrap();
assert!(warnings.len() >= 2, "Should flag missing blanks around admonitions");
assert!(
warnings
.iter()
.any(|w| w.message.contains("No blank line before admonition"))
);
assert!(
warnings
.iter()
.any(|w| w.message.contains("No blank line after admonition"))
);
}
#[test]
fn test_mkdocs_admonitions_nested() {
let content = r#"# Document
!!! note "Outer"
Content of outer.
!!! warning "Inner"
Content of inner.
More inner content.
Back to outer.
Outside content."#;
let rule = MD031BlanksAroundFences::default();
let ctx_mkdocs = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx_mkdocs).unwrap();
assert!(warnings.len() <= 2, "Nested admonitions may need blank lines");
}
#[test]
fn test_mkdocs_admonitions_with_lists() {
let content = r#"# Document
!!! tip "List Example"
Here's a list inside an admonition:
- Item 1
- Item 2
- Item 3
End of admonition content.
Regular text."#;
let rule = MD032BlanksAroundLists::default();
let ctx_mkdocs = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx_mkdocs).unwrap();
assert_eq!(
warnings.len(),
0,
"Lists inside admonitions should not need blank lines"
);
}
#[test]
fn test_mkdocs_admonitions_with_headings() {
let content = r#"# Document
!!! example "Complex Example"
## Heading Inside Admonition
Content here.
### Subheading
More content.
Regular text."#;
let rule = MD022BlanksAroundHeadings::default();
let ctx_mkdocs = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx_mkdocs).unwrap();
assert!(warnings.len() <= 4, "Headings inside admonitions may still be checked");
}
#[test]
fn test_mkdocs_collapsible_admonitions() {
let content = r#"# Document
??? note "Collapsed by default"
Hidden content.
More content.
???+ warning "Expanded by default"
Visible content.
More content.
Regular text."#;
let rule = MD031BlanksAroundFences::default();
let ctx_mkdocs = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx_mkdocs).unwrap();
assert!(warnings.len() <= 1, "Collapsible admonitions should be recognized");
}
#[test]
fn test_mkdocs_inline_admonitions() {
let content = r#"# Document
Some text !!! note inline
Inline note content.
More text on same line flow.
!!! tip inline end
Right-aligned tip.
Text continues."#;
let rule = MD031BlanksAroundFences::default();
let ctx_mkdocs = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx_mkdocs).unwrap();
assert!(warnings.len() <= 4, "Inline admonitions may trigger some warnings");
}
#[test]
fn test_standard_flavor_no_admonition_detection() {
let content = r#"# Document
!!! note "This is just text"
Not an admonition in standard flavor.
Just regular text.
More text."#;
let rule = MD031BlanksAroundFences::default();
let ctx_standard = LintContext::new(content, MarkdownFlavor::Standard, None);
let warnings = rule.check(&ctx_standard).unwrap();
assert_eq!(warnings.len(), 0, "Standard flavor should not detect admonitions");
}
#[test]
fn test_fenced_code_inside_admonition_not_flagged_issue_415() {
let content = r#"# Document
!!! note "Example"
Some text before code.
```python
def hello():
print("world")
```
Some text after code.
More text."#;
let rule = MD031BlanksAroundFences::default();
let ctx = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx).unwrap();
assert_eq!(
warnings.len(),
0,
"Fenced code inside admonition must not trigger MD031 warnings. Got: {warnings:?}"
);
}
#[test]
fn test_multiple_fenced_code_blocks_inside_admonition_issue_415() {
let content = r#"# Document
!!! example "Code Samples"
First example:
```python
x = 1
```
Second example:
```bash
echo "hello"
```
End of admonition.
More text."#;
let rule = MD031BlanksAroundFences::default();
let ctx = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx).unwrap();
assert_eq!(
warnings.len(),
0,
"Multiple fenced code blocks inside admonition must not trigger MD031 warnings. Got: {warnings:?}"
);
}
#[test]
fn test_tilde_fenced_code_inside_admonition_issue_415() {
let content = r#"# Document
!!! warning
Content here.
~~~yaml
key: value
nested:
- item
~~~
More content.
End."#;
let rule = MD031BlanksAroundFences::default();
let ctx = LintContext::new(content, MarkdownFlavor::MkDocs, None);
let warnings = rule.check(&ctx).unwrap();
assert_eq!(
warnings.len(),
0,
"Tilde-fenced code inside admonition must not trigger MD031 warnings. Got: {warnings:?}"
);
}