1use thiserror::Error;
2
3#[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 pub fn auth(msg: impl Into<String>) -> Self {
51 Self::Authentication(msg.into())
52 }
53
54 pub fn config(msg: impl Into<String>) -> Self {
56 Self::Config(msg.into())
57 }
58
59 pub fn invalid_response(msg: impl Into<String>) -> Self {
61 Self::InvalidResponse(msg.into())
62 }
63
64 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}