garmin_cli/
error.rs

1use thiserror::Error;
2
3/// Main error type for garmin-cli
4#[derive(Error, Debug)]
5pub enum GarminError {
6    #[error("Authentication error: {0}")]
7    Authentication(String),
8
9    #[error("Authentication required. Please run 'garmin auth login' first.")]
10    NotAuthenticated,
11
12    #[error("MFA required")]
13    MfaRequired,
14
15    #[error("Rate limited. Please wait before retrying.")]
16    RateLimited,
17
18    #[error("HTTP error: {0}")]
19    Http(#[from] reqwest::Error),
20
21    #[error("Invalid response: {0}")]
22    InvalidResponse(String),
23
24    #[error("JSON error: {0}")]
25    Json(#[from] serde_json::Error),
26
27    #[error("IO error: {0}")]
28    Io(#[from] std::io::Error),
29
30    #[error("Configuration error: {0}")]
31    Config(String),
32
33    #[error("Keyring error: {0}")]
34    Keyring(String),
35
36    #[error("Invalid date format: {0}. Expected YYYY-MM-DD")]
37    InvalidDateFormat(String),
38
39    #[error("Invalid parameter: {0}")]
40    InvalidParameter(String),
41
42    #[error("{0}")]
43    Other(String),
44}
45
46pub type Result<T> = std::result::Result<T, GarminError>;
47
48impl GarminError {
49    /// Create an authentication error from a message
50    pub fn auth(msg: impl Into<String>) -> Self {
51        Self::Authentication(msg.into())
52    }
53
54    /// Create a configuration error from a message
55    pub fn config(msg: impl Into<String>) -> Self {
56        Self::Config(msg.into())
57    }
58
59    /// Create an invalid response error from a message
60    pub fn invalid_response(msg: impl Into<String>) -> Self {
61        Self::InvalidResponse(msg.into())
62    }
63
64    /// Create an invalid parameter error from a message
65    pub fn invalid_param(msg: impl Into<String>) -> Self {
66        Self::InvalidParameter(msg.into())
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_error_display() {
76        let err = GarminError::Authentication("Invalid credentials".to_string());
77        assert_eq!(err.to_string(), "Authentication error: Invalid credentials");
78    }
79
80    #[test]
81    fn test_not_authenticated_error() {
82        let err = GarminError::NotAuthenticated;
83        assert!(err.to_string().contains("garmin auth login"));
84    }
85
86    #[test]
87    fn test_rate_limited_error() {
88        let err = GarminError::RateLimited;
89        assert!(err.to_string().contains("Rate limited"));
90    }
91
92    #[test]
93    fn test_invalid_date_format_error() {
94        let err = GarminError::InvalidDateFormat("not-a-date".to_string());
95        assert!(err.to_string().contains("not-a-date"));
96        assert!(err.to_string().contains("YYYY-MM-DD"));
97    }
98
99    #[test]
100    fn test_error_constructors() {
101        let auth_err = GarminError::auth("test auth");
102        assert!(matches!(auth_err, GarminError::Authentication(_)));
103
104        let config_err = GarminError::config("test config");
105        assert!(matches!(config_err, GarminError::Config(_)));
106
107        let response_err = GarminError::invalid_response("bad response");
108        assert!(matches!(response_err, GarminError::InvalidResponse(_)));
109
110        let param_err = GarminError::invalid_param("bad param");
111        assert!(matches!(param_err, GarminError::InvalidParameter(_)));
112    }
113}