torii_core/error/
mod.rs

1pub mod utilities;
2
3use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum Error {
7    #[error("Authentication error: {0}")]
8    Auth(#[from] AuthError),
9
10    #[error("Storage error: {0}")]
11    Storage(#[from] StorageError),
12
13    #[error("Validation error: {0}")]
14    Validation(#[from] ValidationError),
15
16    #[error("Event error: {0}")]
17    Event(#[from] EventError),
18
19    #[error("Session error: {0}")]
20    Session(#[from] SessionError),
21
22    #[error("Cryptographic error: {0}")]
23    Crypto(#[from] CryptoError),
24}
25
26#[derive(Debug, Error)]
27pub enum AuthError {
28    #[error("Invalid credentials")]
29    InvalidCredentials,
30
31    #[error("User not found")]
32    UserNotFound,
33
34    #[error("User already exists")]
35    UserAlreadyExists,
36
37    #[error("Email not verified")]
38    EmailNotVerified,
39
40    #[error("Unsupported authentication method: {0}")]
41    UnsupportedMethod(String),
42
43    #[error("Account already linked")]
44    AccountAlreadyLinked,
45
46    #[error("Password hash error: {0}")]
47    PasswordHashError(String),
48}
49
50#[derive(Debug, Error)]
51pub enum SessionError {
52    #[error("Session not found")]
53    NotFound,
54
55    #[error("Session expired")]
56    Expired,
57
58    #[error("Session already exists")]
59    AlreadyExists,
60
61    #[error("Invalid token: {0}")]
62    InvalidToken(String),
63}
64
65#[derive(Debug, Error)]
66pub enum StorageError {
67    #[error("Database error: {0}")]
68    Database(String),
69
70    #[error("Migration error: {0}")]
71    Migration(String),
72
73    #[error("Connection error: {0}")]
74    Connection(String),
75
76    #[error("Record not found")]
77    NotFound,
78
79    #[error("Constraint violation: {0}")]
80    Constraint(String),
81}
82
83#[derive(Debug, Error)]
84pub enum ValidationError {
85    #[error("Invalid email format: {0}")]
86    InvalidEmail(String),
87
88    #[error("Invalid password: {0}")]
89    InvalidPassword(String),
90
91    #[error("Weak password")]
92    WeakPassword,
93
94    #[error("Invalid name: {0}")]
95    InvalidName(String),
96
97    #[error("Invalid user ID: {0}")]
98    InvalidUserId(String),
99
100    #[error("Invalid provider: {0}")]
101    InvalidProvider(String),
102
103    #[error("Invalid field: {0}")]
104    InvalidField(String),
105
106    #[error("Missing required field: {0}")]
107    MissingField(String),
108}
109
110#[derive(Debug, Error)]
111pub enum EventError {
112    #[error("Event bus error: {0}")]
113    BusError(String),
114
115    #[error("Event handler error: {0}")]
116    HandlerError(String),
117}
118
119#[derive(Debug, Error)]
120pub enum CryptoError {
121    #[error("JWT signing failed: {0}")]
122    JwtSigning(String),
123
124    #[error("JWT verification failed: {0}")]
125    JwtVerification(String),
126
127    #[error("Password hashing failed: {0}")]
128    PasswordHash(String),
129
130    #[error("Passkey operation failed: {0}")]
131    Passkey(String),
132}
133
134impl Error {
135    pub fn is_auth_error(&self) -> bool {
136        matches!(
137            self,
138            Error::Auth(AuthError::InvalidCredentials)
139                | Error::Auth(AuthError::UserNotFound)
140                | Error::Auth(AuthError::UserAlreadyExists)
141        )
142    }
143
144    pub fn is_validation_error(&self) -> bool {
145        matches!(
146            self,
147            Error::Validation(ValidationError::InvalidEmail(_))
148                | Error::Validation(ValidationError::WeakPassword)
149                | Error::Validation(ValidationError::InvalidField(_))
150                | Error::Validation(ValidationError::MissingField(_))
151        )
152    }
153
154    pub fn is_storage_error(&self) -> bool {
155        matches!(self, Error::Storage(_))
156    }
157
158    pub fn is_session_error(&self) -> bool {
159        matches!(self, Error::Session(_))
160    }
161
162    pub fn is_crypto_error(&self) -> bool {
163        matches!(self, Error::Crypto(_))
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn test_error_display() {
173        let auth_error = Error::Auth(AuthError::InvalidCredentials);
174        assert_eq!(
175            auth_error.to_string(),
176            "Authentication error: Invalid credentials"
177        );
178
179        let validation_error =
180            Error::Validation(ValidationError::InvalidEmail("test@".to_string()));
181        assert_eq!(
182            validation_error.to_string(),
183            "Validation error: Invalid email format: test@"
184        );
185
186        let storage_error = Error::Storage(StorageError::NotFound);
187        assert_eq!(storage_error.to_string(), "Storage error: Record not found");
188    }
189
190    #[test]
191    fn test_auth_error_variants() {
192        let invalid_creds = AuthError::InvalidCredentials;
193        assert_eq!(invalid_creds.to_string(), "Invalid credentials");
194
195        let user_not_found = AuthError::UserNotFound;
196        assert_eq!(user_not_found.to_string(), "User not found");
197
198        let user_exists = AuthError::UserAlreadyExists;
199        assert_eq!(user_exists.to_string(), "User already exists");
200
201        let unsupported = AuthError::UnsupportedMethod("WebAuthn".to_string());
202        assert_eq!(
203            unsupported.to_string(),
204            "Unsupported authentication method: WebAuthn"
205        );
206    }
207
208    #[test]
209    fn test_is_auth_error() {
210        assert!(Error::Auth(AuthError::InvalidCredentials).is_auth_error());
211        assert!(Error::Auth(AuthError::UserNotFound).is_auth_error());
212        assert!(Error::Auth(AuthError::UserAlreadyExists).is_auth_error());
213        assert!(!Error::Auth(AuthError::EmailNotVerified).is_auth_error());
214        assert!(!Error::Storage(StorageError::NotFound).is_auth_error());
215    }
216
217    #[test]
218    fn test_is_validation_error() {
219        assert!(
220            Error::Validation(ValidationError::InvalidEmail("test".to_string()))
221                .is_validation_error()
222        );
223        assert!(Error::Validation(ValidationError::WeakPassword).is_validation_error());
224        assert!(
225            Error::Validation(ValidationError::InvalidField("name".to_string()))
226                .is_validation_error()
227        );
228        assert!(
229            Error::Validation(ValidationError::MissingField("email".to_string()))
230                .is_validation_error()
231        );
232        assert!(!Error::Auth(AuthError::InvalidCredentials).is_validation_error());
233    }
234
235    #[test]
236    fn test_session_error_variants() {
237        let not_found = SessionError::NotFound;
238        assert_eq!(not_found.to_string(), "Session not found");
239
240        let expired = SessionError::Expired;
241        assert_eq!(expired.to_string(), "Session expired");
242
243        let invalid_token = SessionError::InvalidToken("malformed".to_string());
244        assert_eq!(invalid_token.to_string(), "Invalid token: malformed");
245    }
246
247    #[test]
248    fn test_storage_error_variants() {
249        let db_error = StorageError::Database("connection failed".to_string());
250        assert_eq!(db_error.to_string(), "Database error: connection failed");
251
252        let not_found = StorageError::NotFound;
253        assert_eq!(not_found.to_string(), "Record not found");
254    }
255
256    #[test]
257    fn test_validation_error_variants() {
258        let invalid_email = ValidationError::InvalidEmail("bad@".to_string());
259        assert_eq!(invalid_email.to_string(), "Invalid email format: bad@");
260
261        let weak_password = ValidationError::WeakPassword;
262        assert_eq!(weak_password.to_string(), "Weak password");
263
264        let missing_field = ValidationError::MissingField("username".to_string());
265        assert_eq!(
266            missing_field.to_string(),
267            "Missing required field: username"
268        );
269    }
270
271    #[test]
272    fn test_event_error_variants() {
273        let bus_error = EventError::BusError("dispatcher failed".to_string());
274        assert_eq!(bus_error.to_string(), "Event bus error: dispatcher failed");
275
276        let handler_error = EventError::HandlerError("timeout".to_string());
277        assert_eq!(handler_error.to_string(), "Event handler error: timeout");
278    }
279
280    #[test]
281    fn test_error_from_conversions() {
282        let auth_error = AuthError::InvalidCredentials;
283        let error: Error = auth_error.into();
284        assert!(matches!(error, Error::Auth(AuthError::InvalidCredentials)));
285
286        let validation_error = ValidationError::WeakPassword;
287        let error: Error = validation_error.into();
288        assert!(matches!(
289            error,
290            Error::Validation(ValidationError::WeakPassword)
291        ));
292    }
293}