Skip to main content

nythos_core/
error.rs

1//! Core error types shared across `nythos-core`.
2use std::fmt;
3
4/// Standard result type for core operations.
5pub type NythosResult<T> = Result<T, AuthError>;
6
7/// Common failure type for domain and application-level auth logic.
8///
9/// This error model is intentionally transport-agnostic. It does not encode
10/// HTTP status codes, framework errors, or infra-specific concerns.
11#[non_exhaustive]
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum AuthError {
14    UserNotFound,
15    InvalidCredentials,
16    AccountLocked,
17    SessionRevoked,
18    SessionExpired,
19    TenantNotFound,
20    PermissionDenied,
21    ValidationError(String),
22    Internal(String),
23}
24
25impl fmt::Display for AuthError {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        match self {
28            AuthError::UserNotFound => f.write_str("user not found"),
29            AuthError::InvalidCredentials => f.write_str("invalid credentials"),
30            AuthError::AccountLocked => f.write_str("account locked"),
31            AuthError::SessionRevoked => f.write_str("session revoked"),
32            AuthError::SessionExpired => f.write_str("session expired"),
33            AuthError::TenantNotFound => f.write_str("tenant not found"),
34            AuthError::PermissionDenied => f.write_str("permission denied"),
35            AuthError::ValidationError(msg) => write!(f, "validation error: {}", msg),
36            AuthError::Internal(msg) => write!(f, "internal error: {}", msg),
37        }
38    }
39}
40
41impl std::error::Error for AuthError {}
42
43#[cfg(test)]
44mod tests {
45    use super::{AuthError, NythosResult};
46
47    #[test]
48    fn string_payload_variants_preserve_messages() {
49        let validation_error = AuthError::ValidationError("invalid email".to_owned());
50        let internal_error = AuthError::Internal("signer unavailable".to_owned());
51
52        assert_eq!(
53            validation_error.to_string(),
54            "validation error: invalid email"
55        );
56
57        assert_eq!(
58            internal_error.to_string(),
59            "internal error: signer unavailable"
60        );
61    }
62
63    #[test]
64    fn unit_variants_match_as_expected() {
65        let err = AuthError::InvalidCredentials;
66
67        assert!(matches!(err, AuthError::InvalidCredentials));
68        assert_ne!(err, AuthError::UserNotFound);
69    }
70
71    #[test]
72    fn display_messages_are_transport_agnostic() {
73        assert_eq!(AuthError::UserNotFound.to_string(), "user not found");
74        assert_eq!(
75            AuthError::ValidationError("bad input".to_owned()).to_string(),
76            "validation error: bad input"
77        );
78        assert_eq!(
79            AuthError::Internal("store failed".to_owned()).to_string(),
80            "internal error: store failed"
81        );
82    }
83
84    #[test]
85    fn nythos_result_alias_uses_auth_error() {
86        fn fails() -> NythosResult<()> {
87            Err(AuthError::SessionExpired)
88        }
89
90        let result = fails();
91
92        assert!(matches!(result, Err(AuthError::SessionExpired)));
93    }
94}