perl_lsp_feature_profile_cli/
lib.rs1#![warn(missing_docs)]
2use std::fmt;
8
9pub use perl_lsp_feature_policy::FeatureProfile;
10use perl_lsp_feature_profile::parse_profile_token;
11
12pub fn parse_feature_profile_arg(
17 raw_profile: &str,
18) -> Result<FeatureProfile, UnsupportedFeatureProfileError> {
19 match parse_profile_token(raw_profile) {
20 Some(kind) => Ok(FeatureProfile::from_kind(kind)),
21 None => Err(UnsupportedFeatureProfileError { raw_profile: raw_profile.to_string() }),
22 }
23}
24
25pub fn parse_feature_profile_arg_or_current(raw_profile: &str) -> FeatureProfile {
27 parse_feature_profile_arg(raw_profile).unwrap_or_else(|_| FeatureProfile::current())
28}
29
30pub const fn feature_profile_label(profile: FeatureProfile) -> &'static str {
32 profile.as_str()
33}
34
35pub const fn feature_profile_supported_tokens() -> &'static [&'static str] {
37 FeatureProfile::supported_cli_profiles()
38}
39
40#[derive(Debug)]
42pub struct UnsupportedFeatureProfileError {
43 pub raw_profile: String,
45}
46
47impl UnsupportedFeatureProfileError {
48 pub fn message(&self) -> String {
50 let supported = feature_profile_supported_tokens().join(", ");
51 format!("Invalid feature profile: {}. Supported: {}", self.raw_profile, supported)
52 }
53}
54
55impl fmt::Display for UnsupportedFeatureProfileError {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 f.write_str(&self.message())
58 }
59}
60
61impl std::error::Error for UnsupportedFeatureProfileError {}
62
63#[cfg(test)]
64mod tests {
65 use super::{
66 FeatureProfile, UnsupportedFeatureProfileError, feature_profile_label,
67 feature_profile_supported_tokens, parse_feature_profile_arg,
68 parse_feature_profile_arg_or_current,
69 };
70 use perl_tdd_support::{must, must_err};
71
72 #[test]
73 fn parse_feature_profile_accepts_known_aliases() {
74 let profile = must(parse_feature_profile_arg("ga_lock"));
75 assert_eq!(profile.as_str(), "ga-lock");
76
77 let profile = must(parse_feature_profile_arg("Prod"));
78 assert_eq!(profile.as_str(), "production");
79
80 let profile = must(parse_feature_profile_arg(" ALL "));
81 assert_eq!(profile.as_str(), "all");
82 }
83
84 #[test]
85 fn parse_unknown_profile_falls_back_to_current() {
86 let profile = parse_feature_profile_arg_or_current("unknown-profile");
87 assert_eq!(profile, FeatureProfile::current());
88 }
89
90 #[test]
91 fn supported_tokens_contain_expected() {
92 let supported = feature_profile_supported_tokens();
93 assert!(supported.contains(&"auto"));
94 assert!(supported.contains(&"ga"));
95 assert!(supported.contains(&"prod"));
96 assert!(supported.contains(&"all"));
97 }
98
99 #[test]
102 fn parse_feature_profile_arg_returns_error_for_unknown() {
103 let err = must_err(parse_feature_profile_arg("bogus"));
104 assert!(err.raw_profile == "bogus", "error should capture the raw profile token");
105 }
106
107 #[test]
108 fn unsupported_error_message_contains_raw_token() {
109 let err = UnsupportedFeatureProfileError { raw_profile: "xyzzy".to_string() };
110 let msg = err.message();
111 assert!(msg.contains("xyzzy"), "error message should contain the raw token");
112 }
113
114 #[test]
115 fn unsupported_error_message_lists_supported_tokens() {
116 let err = UnsupportedFeatureProfileError { raw_profile: "bad".to_string() };
117 let msg = err.message();
118 assert!(msg.contains("auto"), "error message should list 'auto'");
119 assert!(msg.contains("prod"), "error message should list 'prod'");
120 assert!(msg.contains("all"), "error message should list 'all'");
121 }
122
123 #[test]
124 fn unsupported_error_display_matches_message() {
125 let err = UnsupportedFeatureProfileError { raw_profile: "nope".to_string() };
126 let display = format!("{err}");
127 assert_eq!(display, err.message());
128 }
129
130 #[test]
131 fn unsupported_error_is_std_error() {
132 let err: Box<dyn std::error::Error> =
133 Box::new(UnsupportedFeatureProfileError { raw_profile: "test".to_string() });
134 let msg = format!("{err}");
135 assert!(msg.contains("test"));
136 }
137
138 #[test]
141 fn feature_profile_label_returns_canonical_name() {
142 assert_eq!(feature_profile_label(FeatureProfile::GaLock), "ga-lock");
143 assert_eq!(feature_profile_label(FeatureProfile::Production), "production");
144 assert_eq!(feature_profile_label(FeatureProfile::All), "all");
145 }
146
147 #[test]
150 fn parse_feature_profile_arg_or_current_accepts_valid() {
151 let profile = parse_feature_profile_arg_or_current("all");
152 assert_eq!(profile, FeatureProfile::All);
153 }
154
155 #[test]
156 fn parse_feature_profile_arg_or_current_with_whitespace() {
157 let profile = parse_feature_profile_arg_or_current(" ga ");
158 assert_eq!(profile, FeatureProfile::GaLock);
159 }
160}