rumdl_lib/rules/md036_no_emphasis_only_first/
md036_config.rs1use crate::rule_config_serde::RuleConfig;
2use crate::types::HeadingLevel;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7#[serde(rename_all = "snake_case")]
8pub enum HeadingStyle {
9 #[default]
11 Atx,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "kebab-case")]
17pub struct MD036Config {
18 #[serde(default = "default_punctuation")]
23 pub punctuation: String,
24
25 #[serde(default)]
29 pub fix: bool,
30
31 #[serde(default, rename = "heading-style", alias = "heading_style")]
34 pub heading_style: HeadingStyle,
35
36 #[serde(default = "default_heading_level", rename = "heading-level", alias = "heading_level")]
40 pub heading_level: HeadingLevel,
41}
42
43fn default_punctuation() -> String {
44 ".,;:!?".to_string()
45}
46
47fn default_heading_level() -> HeadingLevel {
48 HeadingLevel::new(2).unwrap()
50}
51
52impl Default for MD036Config {
53 fn default() -> Self {
54 Self {
55 punctuation: default_punctuation(),
56 fix: false,
57 heading_style: HeadingStyle::default(),
58 heading_level: default_heading_level(),
59 }
60 }
61}
62
63impl RuleConfig for MD036Config {
64 const RULE_NAME: &'static str = "MD036";
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_default_values() {
73 let config = MD036Config::default();
74 assert_eq!(config.punctuation, ".,;:!?");
75 assert!(!config.fix);
76 assert_eq!(config.heading_style, HeadingStyle::Atx);
77 assert_eq!(config.heading_level.get(), 2);
78 }
79
80 #[test]
81 fn test_kebab_case_config() {
82 let toml_str = r#"
83 punctuation = ".,;:"
84 fix = true
85 heading-style = "atx"
86 heading-level = 3
87 "#;
88 let config: MD036Config = toml::from_str(toml_str).unwrap();
89 assert_eq!(config.punctuation, ".,;:");
90 assert!(config.fix);
91 assert_eq!(config.heading_style, HeadingStyle::Atx);
92 assert_eq!(config.heading_level.get(), 3);
93 }
94
95 #[test]
96 fn test_snake_case_backwards_compatibility() {
97 let toml_str = r#"
98 punctuation = "."
99 fix = true
100 heading_style = "atx"
101 heading_level = 4
102 "#;
103 let config: MD036Config = toml::from_str(toml_str).unwrap();
104 assert_eq!(config.punctuation, ".");
105 assert!(config.fix);
106 assert_eq!(config.heading_style, HeadingStyle::Atx);
107 assert_eq!(config.heading_level.get(), 4);
108 }
109
110 #[test]
111 fn test_invalid_heading_level_rejected() {
112 let toml_str = r#"
114 heading-level = 0
115 "#;
116 let result: Result<MD036Config, _> = toml::from_str(toml_str);
117 assert!(result.is_err());
118 let err = result.unwrap_err().to_string();
119 assert!(err.contains("must be between 1 and 6"));
120
121 let toml_str = r#"
123 heading-level = 7
124 "#;
125 let result: Result<MD036Config, _> = toml::from_str(toml_str);
126 assert!(result.is_err());
127 let err = result.unwrap_err().to_string();
128 assert!(err.contains("must be between 1 and 6"));
129 }
130
131 #[test]
132 fn test_all_valid_heading_levels() {
133 for level in 1..=6 {
134 let toml_str = format!("heading-level = {level}");
135 let config: MD036Config = toml::from_str(&toml_str).unwrap();
136 assert_eq!(config.heading_level.get(), level);
137 }
138 }
139}