1use std::fmt;
3
4pub type NythosResult<T> = Result<T, AuthError>;
6
7#[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}