1use toml::Value;
5
6#[macro_export]
19macro_rules! impl_default_config {
20 ($rule_name:expr, $($field:ident: $value:expr),* $(,)?) => {{
21 let mut map = toml::map::Map::new();
22 $(
23 map.insert(stringify!($field).to_string(), $value);
24 )*
25 Some(($rule_name.to_string(), toml::Value::Table(map)))
26 }};
27 ($rule_name:expr $(,)?) => {{
28 let map = toml::map::Map::new();
29 Some(($rule_name.to_string(), toml::Value::Table(map)))
30 }};
31}
32
33pub fn toml_bool(b: bool) -> Value {
35 Value::Boolean(b)
36}
37
38pub fn toml_int<T: Into<i64>>(i: T) -> Value {
39 Value::Integer(i.into())
40}
41
42pub fn toml_string<T: Into<String>>(s: T) -> Value {
43 Value::String(s.into())
44}
45
46pub fn toml_array<T: Into<String>>(items: Vec<T>) -> Value {
47 Value::Array(items.into_iter().map(|s| Value::String(s.into())).collect())
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn test_toml_bool() {
56 assert_eq!(toml_bool(true), Value::Boolean(true));
57 assert_eq!(toml_bool(false), Value::Boolean(false));
58 }
59
60 #[test]
61 fn test_toml_int() {
62 assert_eq!(toml_int(42), Value::Integer(42));
63 assert_eq!(toml_int(0), Value::Integer(0));
64 assert_eq!(toml_int(-10), Value::Integer(-10));
65
66 assert_eq!(toml_int(42u8), Value::Integer(42));
68 assert_eq!(toml_int(42u16), Value::Integer(42));
69 assert_eq!(toml_int(42u32), Value::Integer(42));
70 assert_eq!(toml_int(42i8), Value::Integer(42));
71 assert_eq!(toml_int(42i16), Value::Integer(42));
72 assert_eq!(toml_int(42i32), Value::Integer(42));
73 }
74
75 #[test]
76 fn test_toml_string() {
77 assert_eq!(toml_string("hello"), Value::String("hello".to_string()));
78 assert_eq!(toml_string(String::from("world")), Value::String("world".to_string()));
79 assert_eq!(toml_string(""), Value::String("".to_string()));
80
81 assert_eq!(toml_string("你好"), Value::String("你好".to_string()));
83 assert_eq!(toml_string("🦀"), Value::String("🦀".to_string()));
84 }
85
86 #[test]
87 fn test_toml_array() {
88 let arr1 = toml_array(vec!["one", "two", "three"]);
90 if let Value::Array(values) = arr1 {
91 assert_eq!(values.len(), 3);
92 assert_eq!(values[0], Value::String("one".to_string()));
93 assert_eq!(values[1], Value::String("two".to_string()));
94 assert_eq!(values[2], Value::String("three".to_string()));
95 } else {
96 panic!("Expected array");
97 }
98
99 let arr2 = toml_array(vec![String::from("alpha"), String::from("beta")]);
101 if let Value::Array(values) = arr2 {
102 assert_eq!(values.len(), 2);
103 assert_eq!(values[0], Value::String("alpha".to_string()));
104 assert_eq!(values[1], Value::String("beta".to_string()));
105 } else {
106 panic!("Expected array");
107 }
108
109 let arr3 = toml_array(Vec::<String>::new());
111 assert_eq!(arr3, Value::Array(vec![]));
112 }
113
114 #[test]
115 fn test_impl_default_config_macro() {
116 let config = impl_default_config!(
118 "MD001",
119 enabled: toml_bool(true),
120 indent: toml_int(4),
121 style: toml_string("consistent"),
122 );
123
124 assert!(config.is_some());
125 let (rule_name, value) = config.unwrap();
126 assert_eq!(rule_name, "MD001");
127
128 if let Value::Table(table) = value {
129 assert_eq!(table.get("enabled"), Some(&Value::Boolean(true)));
130 assert_eq!(table.get("indent"), Some(&Value::Integer(4)));
131 assert_eq!(table.get("style"), Some(&Value::String("consistent".to_string())));
132 } else {
133 panic!("Expected table");
134 }
135 }
136
137 #[test]
138 fn test_impl_default_config_macro_empty() {
139 let config = impl_default_config!("MD023");
141
142 assert!(config.is_some());
143 let (rule_name, value) = config.unwrap();
144 assert_eq!(rule_name, "MD023");
145
146 if let Value::Table(table) = value {
147 assert!(table.is_empty());
148 } else {
149 panic!("Expected table");
150 }
151 }
152
153 #[test]
154 fn test_impl_default_config_macro_complex() {
155 let my_array = vec!["item1", "item2"];
157 let my_bool = false;
158 let my_number = 42 + 58;
159
160 let config = impl_default_config!(
161 "MD003",
162 items: toml_array(my_array),
163 enabled: toml_bool(my_bool),
164 count: toml_int(my_number),
165 );
166
167 assert!(config.is_some());
168 let (rule_name, value) = config.unwrap();
169 assert_eq!(rule_name, "MD003");
170
171 if let Value::Table(table) = value {
172 assert!(table.contains_key("items"));
173 assert_eq!(table.get("enabled"), Some(&Value::Boolean(false)));
174 assert_eq!(table.get("count"), Some(&Value::Integer(100)));
175 } else {
176 panic!("Expected table");
177 }
178 }
179
180 #[test]
181 fn test_macro_field_name_preservation() {
182 let config = impl_default_config!(
184 "MD004",
185 snake_case_field: toml_string("value1"),
186 camelCaseField: toml_string("value2"),
187 UPPERCASE_FIELD: toml_string("value3"),
188 );
189
190 let (_, value) = config.unwrap();
191 if let Value::Table(table) = value {
192 assert!(table.contains_key("snake_case_field"));
193 assert!(table.contains_key("camelCaseField"));
194 assert!(table.contains_key("UPPERCASE_FIELD"));
195 } else {
196 panic!("Expected table");
197 }
198 }
199
200 #[test]
201 fn test_toml_value_types() {
202 assert!(matches!(toml_bool(true), Value::Boolean(_)));
204 assert!(matches!(toml_int(42), Value::Integer(_)));
205 assert!(matches!(toml_string("test"), Value::String(_)));
206 assert!(matches!(toml_array(vec!["a", "b"]), Value::Array(_)));
207 }
208
209 #[test]
210 fn test_edge_cases() {
211 assert_eq!(toml_int(i32::MAX), Value::Integer(i32::MAX as i64));
213 assert_eq!(toml_int(i32::MIN), Value::Integer(i32::MIN as i64));
214
215 assert_eq!(toml_string("with\nnewline"), Value::String("with\nnewline".to_string()));
217 assert_eq!(toml_string("with\ttab"), Value::String("with\ttab".to_string()));
218 assert_eq!(toml_string("with\"quote"), Value::String("with\"quote".to_string()));
219 }
220}