Skip to main content

slack_rs/profile/
token_type.rs

1//! Token type definitions and resolution logic
2//!
3//! This module provides:
4//! - TokenType enum for bot/user token distinction
5//! - Token type resolution logic with priority: CLI flag > profile default > fallback
6
7use serde::{Deserialize, Serialize};
8use std::fmt;
9use std::str::FromStr;
10use thiserror::Error;
11
12/// Token type for Slack API authentication
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "lowercase")]
15pub enum TokenType {
16    /// Bot token (xoxb-*)
17    Bot,
18    /// User token (xoxp-*)
19    User,
20}
21
22impl TokenType {
23    /// Returns "bot" or "user" as a string
24    pub fn as_str(&self) -> &'static str {
25        match self {
26            TokenType::Bot => "bot",
27            TokenType::User => "user",
28        }
29    }
30
31    /// Resolve token type with priority: CLI flag > profile default > fallback
32    ///
33    /// # Arguments
34    /// * `cli_flag` - Token type specified via --token-type CLI flag
35    /// * `profile_default` - Default token type stored in profile
36    /// * `fallback` - Fallback token type (typically Bot)
37    ///
38    /// # Examples
39    /// ```
40    /// use slack_rs::profile::TokenType;
41    ///
42    /// // CLI flag takes priority
43    /// let resolved = TokenType::resolve(Some(TokenType::User), Some(TokenType::Bot), TokenType::Bot);
44    /// assert_eq!(resolved, TokenType::User);
45    ///
46    /// // Profile default is used when no CLI flag
47    /// let resolved = TokenType::resolve(None, Some(TokenType::User), TokenType::Bot);
48    /// assert_eq!(resolved, TokenType::User);
49    ///
50    /// // Fallback is used when neither CLI flag nor profile default
51    /// let resolved = TokenType::resolve(None, None, TokenType::Bot);
52    /// assert_eq!(resolved, TokenType::Bot);
53    /// ```
54    pub fn resolve(
55        cli_flag: Option<TokenType>,
56        profile_default: Option<TokenType>,
57        fallback: TokenType,
58    ) -> TokenType {
59        cli_flag.or(profile_default).unwrap_or(fallback)
60    }
61}
62
63impl fmt::Display for TokenType {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(f, "{}", self.as_str())
66    }
67}
68
69impl FromStr for TokenType {
70    type Err = TokenTypeError;
71
72    fn from_str(s: &str) -> Result<Self, Self::Err> {
73        match s.to_lowercase().as_str() {
74            "bot" => Ok(TokenType::Bot),
75            "user" => Ok(TokenType::User),
76            _ => Err(TokenTypeError::InvalidValue(s.to_string())),
77        }
78    }
79}
80
81#[derive(Debug, Error)]
82pub enum TokenTypeError {
83    #[error("Invalid token type: {0}. Valid values: bot, user")]
84    InvalidValue(String),
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_token_type_as_str() {
93        assert_eq!(TokenType::Bot.as_str(), "bot");
94        assert_eq!(TokenType::User.as_str(), "user");
95    }
96
97    #[test]
98    fn test_token_type_display() {
99        assert_eq!(TokenType::Bot.to_string(), "bot");
100        assert_eq!(TokenType::User.to_string(), "user");
101    }
102
103    #[test]
104    fn test_token_type_from_str() {
105        assert_eq!("bot".parse::<TokenType>().unwrap(), TokenType::Bot);
106        assert_eq!("Bot".parse::<TokenType>().unwrap(), TokenType::Bot);
107        assert_eq!("BOT".parse::<TokenType>().unwrap(), TokenType::Bot);
108        assert_eq!("user".parse::<TokenType>().unwrap(), TokenType::User);
109        assert_eq!("User".parse::<TokenType>().unwrap(), TokenType::User);
110        assert_eq!("USER".parse::<TokenType>().unwrap(), TokenType::User);
111
112        assert!("invalid".parse::<TokenType>().is_err());
113        assert!("admin".parse::<TokenType>().is_err());
114    }
115
116    #[test]
117    fn test_token_type_serialization() {
118        let bot = TokenType::Bot;
119        let user = TokenType::User;
120
121        let bot_json = serde_json::to_string(&bot).unwrap();
122        let user_json = serde_json::to_string(&user).unwrap();
123
124        assert_eq!(bot_json, "\"bot\"");
125        assert_eq!(user_json, "\"user\"");
126
127        let bot_deserialized: TokenType = serde_json::from_str(&bot_json).unwrap();
128        let user_deserialized: TokenType = serde_json::from_str(&user_json).unwrap();
129
130        assert_eq!(bot_deserialized, TokenType::Bot);
131        assert_eq!(user_deserialized, TokenType::User);
132    }
133
134    #[test]
135    fn test_token_type_resolve_cli_flag_priority() {
136        // CLI flag takes highest priority
137        let resolved =
138            TokenType::resolve(Some(TokenType::User), Some(TokenType::Bot), TokenType::Bot);
139        assert_eq!(resolved, TokenType::User);
140
141        let resolved =
142            TokenType::resolve(Some(TokenType::Bot), Some(TokenType::User), TokenType::User);
143        assert_eq!(resolved, TokenType::Bot);
144    }
145
146    #[test]
147    fn test_token_type_resolve_profile_default() {
148        // Profile default is used when no CLI flag
149        let resolved = TokenType::resolve(None, Some(TokenType::User), TokenType::Bot);
150        assert_eq!(resolved, TokenType::User);
151
152        let resolved = TokenType::resolve(None, Some(TokenType::Bot), TokenType::User);
153        assert_eq!(resolved, TokenType::Bot);
154    }
155
156    #[test]
157    fn test_token_type_resolve_fallback() {
158        // Fallback is used when neither CLI flag nor profile default
159        let resolved = TokenType::resolve(None, None, TokenType::Bot);
160        assert_eq!(resolved, TokenType::Bot);
161
162        let resolved = TokenType::resolve(None, None, TokenType::User);
163        assert_eq!(resolved, TokenType::User);
164    }
165
166    #[test]
167    fn test_token_type_resolve_all_combinations() {
168        // Test all possible combinations
169        assert_eq!(
170            TokenType::resolve(Some(TokenType::Bot), Some(TokenType::Bot), TokenType::Bot),
171            TokenType::Bot
172        );
173        assert_eq!(
174            TokenType::resolve(Some(TokenType::Bot), Some(TokenType::Bot), TokenType::User),
175            TokenType::Bot
176        );
177        assert_eq!(
178            TokenType::resolve(Some(TokenType::Bot), Some(TokenType::User), TokenType::Bot),
179            TokenType::Bot
180        );
181        assert_eq!(
182            TokenType::resolve(Some(TokenType::Bot), Some(TokenType::User), TokenType::User),
183            TokenType::Bot
184        );
185        assert_eq!(
186            TokenType::resolve(Some(TokenType::Bot), None, TokenType::Bot),
187            TokenType::Bot
188        );
189        assert_eq!(
190            TokenType::resolve(Some(TokenType::Bot), None, TokenType::User),
191            TokenType::Bot
192        );
193
194        assert_eq!(
195            TokenType::resolve(Some(TokenType::User), Some(TokenType::Bot), TokenType::Bot),
196            TokenType::User
197        );
198        assert_eq!(
199            TokenType::resolve(Some(TokenType::User), Some(TokenType::Bot), TokenType::User),
200            TokenType::User
201        );
202        assert_eq!(
203            TokenType::resolve(Some(TokenType::User), Some(TokenType::User), TokenType::Bot),
204            TokenType::User
205        );
206        assert_eq!(
207            TokenType::resolve(
208                Some(TokenType::User),
209                Some(TokenType::User),
210                TokenType::User
211            ),
212            TokenType::User
213        );
214        assert_eq!(
215            TokenType::resolve(Some(TokenType::User), None, TokenType::Bot),
216            TokenType::User
217        );
218        assert_eq!(
219            TokenType::resolve(Some(TokenType::User), None, TokenType::User),
220            TokenType::User
221        );
222
223        assert_eq!(
224            TokenType::resolve(None, Some(TokenType::Bot), TokenType::Bot),
225            TokenType::Bot
226        );
227        assert_eq!(
228            TokenType::resolve(None, Some(TokenType::Bot), TokenType::User),
229            TokenType::Bot
230        );
231        assert_eq!(
232            TokenType::resolve(None, Some(TokenType::User), TokenType::Bot),
233            TokenType::User
234        );
235        assert_eq!(
236            TokenType::resolve(None, Some(TokenType::User), TokenType::User),
237            TokenType::User
238        );
239
240        assert_eq!(
241            TokenType::resolve(None, None, TokenType::Bot),
242            TokenType::Bot
243        );
244        assert_eq!(
245            TokenType::resolve(None, None, TokenType::User),
246            TokenType::User
247        );
248    }
249}