use rumdl_lib::lint_context::LintContext;
use rumdl_lib::rule::Rule;
use rumdl_lib::rules::{
MD036NoEmphasisAsHeading, MD037NoSpaceInEmphasis, MD049EmphasisStyle, MD050StrongStyle,
emphasis_style::EmphasisStyle, strong_style::StrongStyle,
};
#[test]
fn test_md036_unicode_emphasis() {
let rule = MD036NoEmphasisAsHeading::new(String::new());
let content = "\
**Hello 👋 World**
*ä½ å¥½ä¸–ç•Œ*
__Ù…Ø±ØØ¨Ø§ بالعالم__
_Привет мир_";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 4, "Should detect all Unicode emphasis as headings");
let fixed = rule.fix(&ctx).unwrap();
assert_eq!(fixed, content, "Content should remain unchanged");
}
#[test]
fn test_md036_punctuation_edge_cases() {
let rule = MD036NoEmphasisAsHeading::new(".,;:!?。".to_string());
let content = "\
**Important!**
*Question?*
**Statement.**
*Chinese。*
**Multiple!!!**
*No punctuation*";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 1, "Should only detect emphasis without punctuation");
assert_eq!(result[0].line, 11);
}
#[test]
fn test_md036_toc_labels() {
let rule = MD036NoEmphasisAsHeading::new(String::new());
let content = "\
**Table of Contents**
**Contents**
**TOC**
**Index**
**table of contents**
**CONTENTS**
**Custom Heading**";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(!result.is_empty(), "Should detect at least one emphasis");
assert!(result.iter().any(|r| r.line == 13));
}
#[test]
fn test_md036_complex_contexts() {
let rule = MD036NoEmphasisAsHeading::new(String::new());
let content = "\
**Standalone heading**
- **In a list**
- *Nested list*
> **In blockquote**
> *Also in quote*
1. **Numbered list**
2. *Another item*
```
**In code block**
```
`**in inline code**`
# Real heading with **emphasis** inside
| **Table** | *Header* |
|-----------|----------|
| **Cell** | *Data* |";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 1, "Should only detect standalone emphasis");
assert_eq!(result[0].line, 1);
}
#[test]
fn test_md036_edge_patterns() {
let rule = MD036NoEmphasisAsHeading::new(String::new());
let content = "\
****
__
**
*
***Mixed***
**Partial emphasis** not alone
Not **standalone** emphasis
**Multiple** **emphasis** **markers**";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.len() <= 1, "Should handle edge patterns correctly");
}
#[test]
fn test_md037_unicode_spaces() {
let rule = MD037NoSpaceInEmphasis;
let content = "\
Here is * Hello 👋 * and also ** ä½ å¥½ ** and also _ Ù…Ø±ØØ¨Ø§ _ and also __ Привет __";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 4, "Should detect spaces in emphasis");
let fixed = rule.fix(&ctx).unwrap();
assert!(fixed.contains("*Hello 👋*"));
assert!(fixed.contains("**ä½ å¥½**"));
assert!(fixed.contains("_Ù…Ø±ØØ¨Ø§_"));
assert!(fixed.contains("__Привет__"));
}
#[test]
fn test_md037_complex_spacing() {
let rule = MD037NoSpaceInEmphasis;
let content = "\
Here is * spaces after * and also *spaces before * and also * spaces both * and also * multiple spaces * end";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 4, "Should detect various spacing issues");
}
#[test]
fn test_md037_multiple_emphasis_per_line() {
let rule = MD037NoSpaceInEmphasis;
let content = "\
This * has * spaces and * more * spaces and *even more *
Mix of * good* and *bad * emphasis * markers *
** Bold ** with _ italic _ and __more bold __";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.len() >= 8, "Should detect all spacing issues");
let fixed = rule.fix(&ctx).unwrap();
assert!(fixed.contains("*has*"));
assert!(fixed.contains("*more*"));
assert!(fixed.contains("*even more*"));
assert!(fixed.contains("**Bold**"));
assert!(fixed.contains("_italic_"));
}
#[test]
fn test_md037_edge_patterns() {
let rule = MD037NoSpaceInEmphasis;
let content = "\
Here is ** ** and also * * end
`* code *` should be ignored
```
* code block *
```";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert!(result.len() <= 2, "Should handle edge patterns gracefully");
}
#[test]
fn test_md049_unicode_content() {
let rule = MD049EmphasisStyle::new(EmphasisStyle::Underscore);
let content = "\
*Hello 世界*
_Bonjour monde_
*Ù…Ø±ØØ¨Ø§ العالم*
_Привет мир_
This is *inline ä½ å¥½* emphasis
Another _inline Ù…Ø±ØØ¨Ø§_ style";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 3, "Should detect asterisk emphasis");
let fixed = rule.fix(&ctx).unwrap();
assert!(fixed.contains("_Hello 世界_"));
assert!(fixed.contains("_Ù…Ø±ØØ¨Ø§ العالم_"));
assert!(fixed.contains("_inline ä½ å¥½_"));
}
#[test]
fn test_md049_consistent_mode() {
let rule = MD049EmphasisStyle::new(EmphasisStyle::Consistent);
let content = "\
*First style is asterisk*
More text with *asterisk* style
_This underscore should be flagged_
*Correct style*
_Another incorrect_";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should detect inconsistent underscore emphasis");
let content2 = "\
_First style is underscore_
*This should be flagged*
_Correct style_";
let ctx2 = LintContext::new(content2, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result2 = rule.check(&ctx2).unwrap();
assert_eq!(result2.len(), 1, "Should detect inconsistent asterisk emphasis");
}
#[test]
fn test_md049_url_preservation() {
let rule = MD049EmphasisStyle::new(EmphasisStyle::Asterisk);
let content = "\
_Regular emphasis_
Visit https://example.com/some_url_with_underscores
Check this_file_name_with_underscores.md
Email: user_name@company_domain.com
But _this emphasis_ should be fixed";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should only detect emphasis, not URLs");
let fixed = rule.fix(&ctx).unwrap();
assert!(fixed.contains("*Regular emphasis*"));
assert!(fixed.contains("some_url_with_underscores"));
assert!(fixed.contains("this_file_name_with_underscores.md"));
assert!(fixed.contains("user_name@company_domain.com"));
assert!(fixed.contains("*this emphasis*"));
}
#[test]
fn test_md049_complex_nesting() {
let rule = MD049EmphasisStyle::new(EmphasisStyle::Underscore);
let content = "\
This has *italic with **bold** inside* text
Another _italic with __bold__ inside_ example
Mixed *styles **with** nesting* here
Link with [*emphasis*](url) inside
Image with  emphasis";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(
result.len(),
2,
"Should detect 2 standalone asterisk emphasis (not in links)"
);
}
#[test]
fn test_md050_unicode_content() {
let rule = MD050StrongStyle::new(StrongStyle::Underscore);
let content = "\
**Bold 世界**
__Bold monde__
**عالم غامق**
__Жирный мир__
This is **inline ä½ å¥½** emphasis
Another __inline Ù…Ø±ØØ¨Ø§__ style";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 3, "Should detect double asterisk emphasis");
let fixed = rule.fix(&ctx).unwrap();
assert!(fixed.contains("__Bold 世界__"));
assert!(fixed.contains("__عالم غامق__"));
assert!(fixed.contains("__inline ä½ å¥½__"));
}
#[test]
fn test_md050_consistent_mode() {
let rule = MD050StrongStyle::new(StrongStyle::Consistent);
let content = "\
**First style is double asterisk**
More text with **asterisk** style
__This underscore should be flagged__
**Correct style**
__Another incorrect__";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should detect inconsistent strong emphasis");
}
#[test]
fn test_md050_escaped_emphasis() {
let rule = MD050StrongStyle::new(StrongStyle::Asterisk);
let content = "\
__Real strong emphasis__
\\__Not emphasis\\__
\\_\\_Also not emphasis\\_\\_
**\\__Mixed escape\\__**
__Should be \\*\\*fixed\\*\\* to asterisks__";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = rule.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should only detect unescaped emphasis");
}
#[test]
fn test_emphasis_rules_interaction() {
let md036 = MD036NoEmphasisAsHeading::new(String::new());
let md037 = MD037NoSpaceInEmphasis;
let md049 = MD049EmphasisStyle::new(EmphasisStyle::Underscore);
let md050 = MD050StrongStyle::new(StrongStyle::Underscore);
let content = "\
** Heading with spaces **
This has * spaces * and *wrong style*
**Bold heading**
More __bold __ with spaces";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result036 = md036.check(&ctx).unwrap();
let result037 = md037.check(&ctx).unwrap();
let result049 = md049.check(&ctx).unwrap();
let result050 = md050.check(&ctx).unwrap();
assert!(!result036.is_empty(), "MD036 should detect headings");
assert!(result037.len() >= 2, "MD037 should detect spaces");
assert!(!result049.is_empty(), "MD049 should detect wrong style");
assert!(!result050.is_empty(), "MD050 should detect wrong style");
}
#[test]
fn test_emphasis_in_special_constructs() {
let md037 = MD037NoSpaceInEmphasis;
let content = "\
[Link with * spaces *](url)

[Reference with * spaces *][ref]
[ref]: https://example.com
> Quote with * spaces *
- List with * spaces *
| Table | * Header * |
|-------|------------|
| Cell | * Data * |
<!-- HTML comment with * spaces * -->
<div>HTML with * spaces *</div>";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md037.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should detect spaces in blockquotes and lists");
}
#[test]
fn test_emphasis_performance_edge_cases() {
let md037 = MD037NoSpaceInEmphasis;
let long_text = "a".repeat(500);
let content = format!("Here is * {long_text} * and also ** {long_text} **");
let ctx = LintContext::new(&content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md037.check(&ctx).unwrap();
assert_eq!(result.len(), 2, "Should handle long lines");
let many_emphasis = format!("Here is {}", "* text * and ".repeat(50));
let ctx2 = LintContext::new(&many_emphasis, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result2 = md037.check(&ctx2).unwrap();
assert_eq!(result2.len(), 50, "Should handle many emphasis markers");
}
#[test]
fn test_emphasis_line_endings() {
let md037 = MD037NoSpaceInEmphasis;
let content_lf = "Here is * spaces * and\nAnother * more * line";
let content_crlf = "Here is * spaces * and\r\nAnother * more * line";
let content_no_ending = "Here is * spaces * text";
let ctx_lf = LintContext::new(content_lf, rumdl_lib::config::MarkdownFlavor::Standard, None);
let ctx_crlf = LintContext::new(content_crlf, rumdl_lib::config::MarkdownFlavor::Standard, None);
let ctx_no_ending = LintContext::new(content_no_ending, rumdl_lib::config::MarkdownFlavor::Standard, None);
assert_eq!(md037.check(&ctx_lf).unwrap().len(), 2);
assert_eq!(md037.check(&ctx_crlf).unwrap().len(), 2);
assert_eq!(md037.check(&ctx_no_ending).unwrap().len(), 1);
}
#[test]
fn test_emphasis_empty_and_minimal() {
let md036 = MD036NoEmphasisAsHeading::new(String::new());
let md037 = MD037NoSpaceInEmphasis;
let content = "\
**
__
*a*
_b_
* *
_ _";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result036 = md036.check(&ctx).unwrap();
let result037 = md037.check(&ctx).unwrap();
assert!(result036.len() >= 2, "Should detect single char emphasis");
assert!(result037.len() <= 2, "MD037 behavior for empty emphasis varies");
}
#[test]
fn test_emphasis_html_entities() {
let md037 = MD037NoSpaceInEmphasis;
let content = "\
Here is * * and also * & * and also * 👋 * and also *<tag>*";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md037.check(&ctx).unwrap();
assert_eq!(result.len(), 3, "Should detect spaces around HTML entities");
}
#[test]
fn test_emphasis_front_matter() {
let md036 = MD036NoEmphasisAsHeading::new(String::new());
let content = "\
---
title: **Not a heading**
emphasis: *also not*
---
**This is a heading**
Normal content";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result = md036.check(&ctx).unwrap();
assert_eq!(result.len(), 1, "Should ignore front matter");
assert_eq!(result[0].line, 6);
}
#[test]
fn test_emphasis_adjacent_markers() {
let md049 = MD049EmphasisStyle::new(EmphasisStyle::Consistent);
let md050 = MD050StrongStyle::new(StrongStyle::Consistent);
let content = "\
*italic***bold**
**bold***italic*
_italic___bold__
__bold___italic_
***both***
___both___";
let ctx = LintContext::new(content, rumdl_lib::config::MarkdownFlavor::Standard, None);
let result049 = md049.check(&ctx).unwrap();
let result050 = md050.check(&ctx).unwrap();
assert!(
!result049.is_empty() || !result050.is_empty(),
"Should detect some style issues"
);
}