1pub fn check_pascal_case(s: &str) -> Option<String> {
8 if s.len() <= 1 {
9 return None;
10 }
11 let expected = heck::AsPascalCase(s).to_string();
12 if s == expected { None } else { Some(expected) }
13}
14
15pub fn check_screaming_snake_case(s: &str) -> Option<String> {
17 if s.len() <= 1 {
18 return None;
19 }
20 let expected = preserve_underscores(s, heck::AsShoutySnakeCase(s).to_string());
21 if s == expected { None } else { Some(expected) }
22}
23
24pub fn check_mixed_case(s: &str) -> Option<String> {
27 if s.len() <= 1 {
28 return None;
29 }
30 let expected = preserve_underscores(s, heck::AsLowerCamelCase(s).to_string());
31 if s == expected { None } else { Some(expected) }
32}
33
34fn preserve_underscores(s: &str, body: String) -> String {
35 let prefix = if s.starts_with('_') { "_" } else { "" };
36 let suffix = if s.ends_with('_') { "_" } else { "" };
37 format!("{prefix}{body}{suffix}")
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn pascal_case_accepts_valid() {
46 assert_eq!(check_pascal_case("MyStruct"), None);
47 assert_eq!(check_pascal_case("Erc20"), None);
48 assert_eq!(check_pascal_case("A"), None);
49 }
50
51 #[test]
52 fn pascal_case_suggests_for_invalid() {
53 assert_eq!(check_pascal_case("my_struct").as_deref(), Some("MyStruct"));
54 assert_eq!(check_pascal_case("myStruct").as_deref(), Some("MyStruct"));
55 assert_eq!(check_pascal_case("MY_STRUCT").as_deref(), Some("MyStruct"));
56 }
57
58 #[test]
59 fn screaming_snake_case_accepts_valid() {
60 assert_eq!(check_screaming_snake_case("MAX_VALUE"), None);
61 assert_eq!(check_screaming_snake_case("_PRIVATE_CONST"), None);
62 assert_eq!(check_screaming_snake_case("VALUE_"), None);
63 }
64
65 #[test]
66 fn screaming_snake_case_suggests_for_invalid() {
67 assert_eq!(check_screaming_snake_case("maxValue").as_deref(), Some("MAX_VALUE"));
68 assert_eq!(check_screaming_snake_case("MaxValue").as_deref(), Some("MAX_VALUE"));
69 }
70
71 #[test]
72 fn screaming_snake_case_preserves_underscores() {
73 assert_eq!(check_screaming_snake_case("_maxValue").as_deref(), Some("_MAX_VALUE"));
74 assert_eq!(check_screaming_snake_case("maxValue_").as_deref(), Some("MAX_VALUE_"));
75 }
76
77 #[test]
78 fn mixed_case_accepts_valid() {
79 assert_eq!(check_mixed_case("counter"), None);
80 assert_eq!(check_mixed_case("totalSupply"), None);
81 assert_eq!(check_mixed_case("_internalVar"), None);
82 }
83
84 #[test]
85 fn mixed_case_suggests_for_invalid() {
86 assert_eq!(check_mixed_case("TotalSupply").as_deref(), Some("totalSupply"));
87 assert_eq!(check_mixed_case("total_supply").as_deref(), Some("totalSupply"));
88 assert_eq!(check_mixed_case("TOTAL_SUPPLY").as_deref(), Some("totalSupply"));
89 }
90
91 #[test]
92 fn mixed_case_preserves_underscores() {
93 assert_eq!(check_mixed_case("_TotalSupply").as_deref(), Some("_totalSupply"));
94 assert_eq!(check_mixed_case("totalSupply_"), None);
95 }
96}