reinhardt_admin/types/
errors.rs1use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum AdminError {
8 #[error("Model '{0}' is not registered with admin")]
10 ModelNotRegistered(String),
11
12 #[error("Permission denied: {0}")]
14 PermissionDenied(String),
15
16 #[error("Invalid action: {0}")]
18 InvalidAction(String),
19
20 #[error("Database error: {0}")]
22 DatabaseError(String),
23
24 #[error("Validation error: {0}")]
26 ValidationError(String),
27
28 #[error("Template rendering error: {0}")]
30 TemplateError(String),
31}
32
33pub type AdminResult<T> = Result<T, AdminError>;
35
36#[cfg(all(test, server))]
37mod tests {
38 use super::*;
39 use rstest::rstest;
40
41 #[rstest]
42 #[case::model_not_registered(
43 AdminError::ModelNotRegistered("User".to_string()),
44 "Model 'User' is not registered with admin"
45 )]
46 #[case::permission_denied(
47 AdminError::PermissionDenied("insufficient role".to_string()),
48 "Permission denied: insufficient role"
49 )]
50 #[case::invalid_action(
51 AdminError::InvalidAction("bulk_delete".to_string()),
52 "Invalid action: bulk_delete"
53 )]
54 #[case::database_error(
55 AdminError::DatabaseError("connection timeout".to_string()),
56 "Database error: connection timeout"
57 )]
58 #[case::validation_error(
59 AdminError::ValidationError("email is required".to_string()),
60 "Validation error: email is required"
61 )]
62 #[case::template_error(
63 AdminError::TemplateError("missing variable".to_string()),
64 "Template rendering error: missing variable"
65 )]
66 fn test_admin_error_display_all_variants(#[case] error: AdminError, #[case] expected: &str) {
67 let display = error.to_string();
69
70 assert_eq!(display, expected);
72 }
73
74 #[cfg(server)]
75 #[rstest]
76 #[case::model_not_registered(
77 AdminError::ModelNotRegistered("Article".to_string()),
78 "Article"
79 )]
80 #[case::permission_denied(
81 AdminError::PermissionDenied("no access".to_string()),
82 "no access"
83 )]
84 #[case::invalid_action(
85 AdminError::InvalidAction("export".to_string()),
86 "export"
87 )]
88 #[case::database_error(
89 AdminError::DatabaseError("deadlock".to_string()),
90 "deadlock"
91 )]
92 #[case::validation_error(
93 AdminError::ValidationError("too long".to_string()),
94 "too long"
95 )]
96 #[case::template_error(
97 AdminError::TemplateError("syntax error".to_string()),
98 "syntax error"
99 )]
100 fn test_admin_error_to_core_error_mapping(
101 #[case] admin_error: AdminError,
102 #[case] expected_msg: &str,
103 ) {
104 let core_error: reinhardt_core::exception::Error = admin_error.into();
106
107 let display = core_error.to_string();
109 assert!(
110 display.contains(expected_msg),
111 "Core error display '{}' should contain '{}'",
112 display,
113 expected_msg
114 );
115 }
116
117 #[rstest]
118 fn test_admin_error_model_not_registered_includes_model_name() {
119 let model_name = "CustomWidget";
121 let error = AdminError::ModelNotRegistered(model_name.to_string());
122
123 let display = error.to_string();
125
126 assert!(
128 display.contains(model_name),
129 "Error message '{}' should contain model name '{}'",
130 display,
131 model_name
132 );
133 }
134
135 #[rstest]
136 fn test_admin_error_permission_denied_includes_reason() {
137 let reason = "user lacks admin privileges";
139 let error = AdminError::PermissionDenied(reason.to_string());
140
141 let display = error.to_string();
143
144 assert!(
146 display.contains(reason),
147 "Error message '{}' should contain reason '{}'",
148 display,
149 reason
150 );
151 }
152
153 #[rstest]
154 #[case::model_not_registered(AdminError::ModelNotRegistered("M".to_string()))]
155 #[case::permission_denied(AdminError::PermissionDenied("P".to_string()))]
156 #[case::invalid_action(AdminError::InvalidAction("A".to_string()))]
157 #[case::database_error(AdminError::DatabaseError("D".to_string()))]
158 #[case::validation_error(AdminError::ValidationError("V".to_string()))]
159 #[case::template_error(AdminError::TemplateError("T".to_string()))]
160 fn test_admin_error_debug_format_differs_from_display(#[case] error: AdminError) {
161 let debug_output = format!("{:?}", error);
163 let display_output = format!("{}", error);
164
165 assert_ne!(
167 debug_output, display_output,
168 "Debug '{debug_output}' and Display '{display_output}' should differ"
169 );
170 }
171}
172
173#[cfg(server)]
175impl From<AdminError> for reinhardt_core::exception::Error {
176 fn from(err: AdminError) -> Self {
177 match err {
178 AdminError::ModelNotRegistered(msg) => reinhardt_core::exception::Error::NotFound(msg),
179 AdminError::PermissionDenied(msg) => {
180 reinhardt_core::exception::Error::Authorization(msg)
181 }
182 AdminError::InvalidAction(msg) => reinhardt_core::exception::Error::Http(msg),
183 AdminError::DatabaseError(msg) => reinhardt_core::exception::Error::Database(msg),
184 AdminError::ValidationError(msg) => reinhardt_core::exception::Error::Validation(msg),
185 AdminError::TemplateError(msg) => {
186 reinhardt_core::exception::Error::Other(anyhow::anyhow!(msg))
187 }
188 }
189 }
190}