clawspec_core/client/oauth2/
error.rs

1//! OAuth2-specific error types.
2
3use std::fmt;
4
5/// Errors that can occur during OAuth2 authentication.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum OAuth2Error {
8    /// Token endpoint URL is invalid.
9    InvalidTokenEndpoint {
10        /// The invalid URL that was provided.
11        url: String,
12        /// Description of why the URL is invalid.
13        reason: String,
14    },
15
16    /// Token acquisition failed.
17    TokenAcquisitionFailed {
18        /// Description of the failure.
19        reason: String,
20    },
21
22    /// Token has expired and no refresh token is available.
23    TokenExpired,
24
25    /// Token refresh failed.
26    TokenRefreshFailed {
27        /// Description of the failure.
28        reason: String,
29    },
30
31    /// Invalid OAuth2 response from the token endpoint.
32    InvalidTokenResponse {
33        /// Description of what was invalid.
34        reason: String,
35    },
36
37    /// Network error during token request.
38    NetworkError {
39        /// Description of the network error.
40        reason: String,
41    },
42
43    /// Configuration error.
44    ConfigurationError {
45        /// Description of the configuration issue.
46        reason: String,
47    },
48}
49
50impl std::error::Error for OAuth2Error {}
51
52impl fmt::Display for OAuth2Error {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self {
55            Self::InvalidTokenEndpoint { url, reason } => {
56                write!(f, "Invalid token endpoint URL '{url}': {reason}")
57            }
58            Self::TokenAcquisitionFailed { reason } => {
59                write!(f, "Token acquisition failed: {reason}")
60            }
61            Self::TokenExpired => {
62                write!(
63                    f,
64                    "OAuth2 token has expired and no refresh token is available"
65                )
66            }
67            Self::TokenRefreshFailed { reason } => {
68                write!(f, "Token refresh failed: {reason}")
69            }
70            Self::InvalidTokenResponse { reason } => {
71                write!(f, "Invalid OAuth2 token response: {reason}")
72            }
73            Self::NetworkError { reason } => {
74                write!(f, "Network error during OAuth2 request: {reason}")
75            }
76            Self::ConfigurationError { reason } => {
77                write!(f, "OAuth2 configuration error: {reason}")
78            }
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn should_display_invalid_token_endpoint() {
89        let error = OAuth2Error::InvalidTokenEndpoint {
90            url: "not-a-url".to_string(),
91            reason: "missing scheme".to_string(),
92        };
93        assert_eq!(
94            error.to_string(),
95            "Invalid token endpoint URL 'not-a-url': missing scheme"
96        );
97    }
98
99    #[test]
100    fn should_display_token_acquisition_failed() {
101        let error = OAuth2Error::TokenAcquisitionFailed {
102            reason: "invalid_client".to_string(),
103        };
104        assert_eq!(
105            error.to_string(),
106            "Token acquisition failed: invalid_client"
107        );
108    }
109
110    #[test]
111    fn should_display_token_expired() {
112        let error = OAuth2Error::TokenExpired;
113        assert_eq!(
114            error.to_string(),
115            "OAuth2 token has expired and no refresh token is available"
116        );
117    }
118
119    #[test]
120    fn should_display_configuration_error() {
121        let error = OAuth2Error::ConfigurationError {
122            reason: "missing client_secret".to_string(),
123        };
124        assert_eq!(
125            error.to_string(),
126            "OAuth2 configuration error: missing client_secret"
127        );
128    }
129}