Skip to main content

ferro_whatsapp/
error.rs

1/// Errors that can occur in ferro-whatsapp operations.
2#[derive(Debug, thiserror::Error)]
3pub enum Error {
4    /// Configuration error (missing env var or invalid value).
5    #[error("configuration error: {0}")]
6    Config(String),
7
8    /// Webhook signature verification failed.
9    #[error("webhook verification failed: {0}")]
10    WebhookVerification(String),
11
12    /// Meta API rate limit exceeded (HTTP 429).
13    #[error("rate limit exceeded")]
14    RateLimit,
15
16    /// Recipient phone number is invalid or not registered on WhatsApp.
17    #[error("invalid phone number")]
18    InvalidNumber,
19
20    /// Authentication error — access token invalid or expired (HTTP 401).
21    #[error("authentication error")]
22    AuthError,
23
24    /// Network-level error contacting the Meta Cloud API.
25    #[error("network error: {0}")]
26    NetworkError(String),
27
28    /// Meta Cloud API returned a non-2xx response.
29    #[error("api error {status}: {message}")]
30    ApiError {
31        /// HTTP status code from Meta API.
32        status: u16,
33        /// Error message from Meta API response body.
34        message: String,
35    },
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn error_config_displays_message() {
44        let e = Error::Config("WHATSAPP_APP_SECRET not set".into());
45        assert_eq!(
46            e.to_string(),
47            "configuration error: WHATSAPP_APP_SECRET not set"
48        );
49    }
50
51    #[test]
52    fn error_webhook_verification_displays_message() {
53        let e = Error::WebhookVerification("Signature mismatch".into());
54        assert_eq!(
55            e.to_string(),
56            "webhook verification failed: Signature mismatch"
57        );
58    }
59
60    #[test]
61    fn error_rate_limit_displays_correctly() {
62        let e = Error::RateLimit;
63        assert_eq!(e.to_string(), "rate limit exceeded");
64    }
65
66    #[test]
67    fn error_invalid_number_displays_correctly() {
68        let e = Error::InvalidNumber;
69        assert_eq!(e.to_string(), "invalid phone number");
70    }
71
72    #[test]
73    fn error_auth_error_displays_correctly() {
74        let e = Error::AuthError;
75        assert_eq!(e.to_string(), "authentication error");
76    }
77
78    #[test]
79    fn error_network_error_displays_message() {
80        let e = Error::NetworkError("connection refused".into());
81        assert_eq!(e.to_string(), "network error: connection refused");
82    }
83
84    #[test]
85    fn error_api_error_displays_status_and_message() {
86        let e = Error::ApiError {
87            status: 500,
88            message: "internal server error".into(),
89        };
90        assert_eq!(e.to_string(), "api error 500: internal server error");
91    }
92}