use rumdl_lib::MD048CodeFenceStyle;
use rumdl_lib::rule::Rule;
use rumdl_lib::rules::code_fence_utils::CodeFenceStyle;
#[test]
fn test_consistent_backticks() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Backtick);
let content = "# Code blocks\n\n```\ncode here\n```\n\n```rust\nmore code\n```";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_consistent_tildes() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Tilde);
let content = "# Code blocks\n\n~~~\ncode here\n~~~\n\n~~~rust\nmore code\n~~~";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_mixed_fences_prefer_backticks() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Backtick);
let content = "# Mixed blocks\n\n```\nbacktick block\n```\n\n~~~\ntilde block\n~~~";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2);
let fixed = rule.fix(&ctx).unwrap();
assert_eq!(
fixed,
"# Mixed blocks\n\n```\nbacktick block\n```\n\n```\ntilde block\n```"
);
}
#[test]
fn test_mixed_fences_prefer_tildes() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Tilde);
let content = "# Mixed blocks\n\n```\nbacktick block\n```\n\n~~~\ntilde block\n~~~";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2);
let fixed = rule.fix(&ctx).unwrap();
assert_eq!(
fixed,
"# Mixed blocks\n\n~~~\nbacktick block\n~~~\n\n~~~\ntilde block\n~~~"
);
}
#[test]
fn test_consistent_style_first_backtick() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Consistent);
let content = "# Mixed blocks\n\n```\nbacktick block\n```\n\n~~~\ntilde block\n~~~";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2);
let fixed = rule.fix(&ctx).unwrap();
assert_eq!(
fixed,
"# Mixed blocks\n\n```\nbacktick block\n```\n\n```\ntilde block\n```"
);
}
#[test]
fn test_consistent_style_first_tilde() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Consistent);
let content = "# Mixed blocks\n\n~~~\ntilde block\n~~~\n\n```\nbacktick block\n```";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2);
let fixed = rule.fix(&ctx).unwrap();
assert_eq!(
fixed,
"# Mixed blocks\n\n```\ntilde block\n```\n\n```\nbacktick block\n```"
);
}
#[test]
fn test_empty_content() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Consistent);
let content = "";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_no_code_blocks() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Consistent);
let content = "# Just a heading\n\nSome regular text\n\n> A blockquote";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.is_empty());
}
#[test]
fn test_nested_code_blocks() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Backtick);
let content = r#"# Documentation
Here's how to use code blocks in markdown:
````markdown
You can use backticks:
```javascript
console.log("Hello");
```
Or tildes:
~~~python
print("Hello")
~~~
````
The outer block uses backticks.
"#;
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 0, "Should not flag fences inside code blocks");
let rule_tilde = MD048CodeFenceStyle::new(CodeFenceStyle::Tilde);
let result_tilde = rule_tilde.check(&ctx).unwrap();
assert_eq!(result_tilde.len(), 2, "Should flag outer backtick fences");
let fixed = rule_tilde.fix(&ctx).unwrap();
assert!(fixed.contains("~~~~markdown"));
assert!(fixed.contains("~~~~\n\nThe outer"));
assert!(fixed.contains("```javascript"));
assert!(fixed.contains("~~~python"));
}
#[test]
fn test_fence_inside_indented_code_block() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Consistent);
let content = "First fence:\n\n```rust\ncode\n```\n\nIndented block with fence:\n\n ```python\n # This is shown as text\n ```";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.is_empty(), "Fences in indented blocks should be ignored");
}
#[test]
fn test_fence_with_language_and_attributes() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Consistent);
let content = "~~~typescript {.numberLines startFrom=\"100\"}\ncode\n~~~\n\n```rust\nmore code\n```";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should flag inconsistent style");
assert!(result[0].message.contains("use ``` instead of ~~~"));
}
#[test]
fn test_empty_fences() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Backtick);
let content = "```\n```\n\n~~~\n~~~";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should flag tilde fences");
let fixed = rule.fix(&ctx).unwrap();
assert_eq!(fixed, "```\n```\n\n```\n```");
}
#[test]
fn test_fence_in_blockquote() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Consistent);
let content = "> Quote with code:\n> \n> ```js\n> console.log('test');\n> ```\n\n~~~python\nprint('test')\n~~~";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.len() <= 2, "May or may not detect fences in blockquotes");
}
#[test]
fn test_long_fence_markers() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Tilde);
let content = "``````javascript\ncode\n``````\n\n~~~~~ruby\ncode\n~~~~~";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should handle long fence markers");
let fixed = rule.fix(&ctx).unwrap();
assert!(fixed.contains("~~~~~~javascript"), "Should preserve fence length");
}
#[test]
fn test_unclosed_fence_style_detection() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Consistent);
let content = "~~~python\nprint('unclosed')";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(
result.is_empty(),
"Single fence with consistent style should not be flagged"
);
}
#[test]
fn test_nested_different_fence_types() {
let rule = MD048CodeFenceStyle::new(CodeFenceStyle::Backtick);
let content = "```outer\n~~~inner\ncontent\n~~~\n```";
let ctx = rumdl_lib::lint_context::LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(
result.is_empty(),
"Inner different fence type should be treated as content"
);
}