Skip to main content

perl_lsp_feature_profile/
lib.rs

1#![warn(missing_docs)]
2//! Canonical feature profile definitions used by runtime profile selection, CLI parsing,
3//! and downstream reporting tools.
4//!
5//! This crate intentionally keeps profile naming and canonicalization rules in one
6//! place so all LSP components (and external tooling) can share the same behavior
7//! without duplicating alias logic.
8
9pub use perl_lsp_feature_contracts::{
10    FeatureProfileKind, FeatureProfileSpec, feature_profile_specs,
11};
12
13/// Return every supported CLI token for profile parsing/validation.
14pub const fn supported_cli_profiles() -> &'static [&'static str] {
15    FeatureProfileKind::supported_cli_profiles()
16}
17
18/// Parse a raw profile token into canonical form.
19pub fn from_str_name(s: &str) -> Option<FeatureProfileKind> {
20    FeatureProfileKind::from_str_name(s)
21}
22
23/// Parse and normalize user input with trimming and legacy delimiter compatibility.
24pub fn parse_profile_token(raw_profile: &str) -> Option<FeatureProfileKind> {
25    let normalized = raw_profile.trim().to_ascii_lowercase().replace('_', "-");
26
27    from_str_name(&normalized)
28}
29
30#[cfg(test)]
31mod tests {
32    use super::FeatureProfileKind;
33
34    #[test]
35    fn supported_profiles_contains_expected_values() {
36        let supported = super::supported_cli_profiles();
37        assert!(supported.contains(&"auto"));
38        assert!(supported.contains(&"ga"));
39        assert!(supported.contains(&"ga_lock"));
40        assert!(supported.contains(&"ga-lock"));
41        assert!(supported.contains(&"prod"));
42        assert!(supported.contains(&"production"));
43        assert!(supported.contains(&"all"));
44    }
45
46    #[test]
47    fn canonical_names_are_stable() {
48        assert_eq!(FeatureProfileKind::GaLock.as_str(), "ga-lock");
49        assert_eq!(FeatureProfileKind::Production.as_str(), "production");
50        assert_eq!(FeatureProfileKind::All.as_str(), "all");
51    }
52
53    #[test]
54    fn aliases_resolve_to_known_profiles() {
55        assert_eq!(FeatureProfileKind::from_str_name("auto"), Some(FeatureProfileKind::current()));
56        assert_eq!(FeatureProfileKind::from_str_name("ga-lock"), Some(FeatureProfileKind::GaLock));
57        assert_eq!(FeatureProfileKind::from_str_name("ga"), Some(FeatureProfileKind::GaLock));
58        assert_eq!(FeatureProfileKind::from_str_name("ga_lock"), Some(FeatureProfileKind::GaLock));
59        assert_eq!(FeatureProfileKind::from_str_name("prod"), Some(FeatureProfileKind::Production));
60        assert_eq!(FeatureProfileKind::from_str_name("all"), Some(FeatureProfileKind::All));
61        assert_eq!(FeatureProfileKind::from_str_name("unknown"), None);
62    }
63
64    #[test]
65    fn normalized_profiles_keep_legacy_underscores() {
66        assert_eq!(super::parse_profile_token("ga_lock"), Some(FeatureProfileKind::GaLock));
67    }
68
69    // ── parse_profile_token normalization ────────────────────────────
70
71    #[test]
72    fn parse_profile_token_trims_whitespace() {
73        assert_eq!(super::parse_profile_token("  all  "), Some(FeatureProfileKind::All));
74        assert_eq!(super::parse_profile_token("\tprod\n"), Some(FeatureProfileKind::Production));
75    }
76
77    #[test]
78    fn parse_profile_token_lowercases() {
79        assert_eq!(super::parse_profile_token("ALL"), Some(FeatureProfileKind::All));
80        assert_eq!(super::parse_profile_token("Prod"), Some(FeatureProfileKind::Production));
81        assert_eq!(super::parse_profile_token("GA-LOCK"), Some(FeatureProfileKind::GaLock));
82    }
83
84    #[test]
85    fn parse_profile_token_normalizes_underscore_to_hyphen() {
86        assert_eq!(super::parse_profile_token("GA_LOCK"), Some(FeatureProfileKind::GaLock));
87    }
88
89    #[test]
90    fn parse_profile_token_rejects_empty() {
91        assert!(super::parse_profile_token("").is_none());
92    }
93
94    #[test]
95    fn parse_profile_token_rejects_unknown() {
96        assert!(super::parse_profile_token("debug").is_none());
97        assert!(super::parse_profile_token("minimal").is_none());
98    }
99
100    #[test]
101    fn parse_profile_token_resolves_auto() {
102        assert_eq!(super::parse_profile_token("auto"), Some(FeatureProfileKind::current()));
103        assert_eq!(super::parse_profile_token("AUTO"), Some(FeatureProfileKind::current()));
104    }
105
106    // ── from_str_name delegates ─────────────────────────────────────
107
108    #[test]
109    fn from_str_name_delegates_to_profile_kind() {
110        assert_eq!(super::from_str_name("all"), FeatureProfileKind::from_str_name("all"));
111        assert_eq!(super::from_str_name("bogus"), None);
112    }
113}