1use crate::{InternalError, InternalErrorClass, InternalErrorOrigin, dto::error::Error};
2
3fn internal_error_to_public(err: &InternalError) -> Error {
4 if let Some(public) = err.public_error() {
5 return public.clone();
6 }
7
8 match err.class() {
9 InternalErrorClass::Access => Error::unauthorized(err.to_string()),
10
11 InternalErrorClass::Domain => match err.origin() {
12 InternalErrorOrigin::Config => Error::invalid(err.to_string()),
13 _ => Error::conflict(err.to_string()),
14 },
15
16 InternalErrorClass::Invariant => Error::invariant(err.to_string()),
17
18 InternalErrorClass::Infra | InternalErrorClass::Ops | InternalErrorClass::Workflow => {
19 Error::internal(err.to_string())
20 }
21 }
22}
23
24impl From<&InternalError> for Error {
25 fn from(err: &InternalError) -> Self {
26 internal_error_to_public(err)
27 }
28}
29
30impl From<InternalError> for Error {
31 fn from(err: InternalError) -> Self {
32 internal_error_to_public(&err)
33 }
34}
35
36#[cfg(test)]
41mod tests {
42 use super::*;
43 use crate::{access::AccessError, dto::error::ErrorCode};
44
45 #[test]
46 fn internal_error_mapping_matches_class_contract() {
47 let access: Error = InternalError::from(AccessError::Denied("denied".to_string())).into();
48 assert_eq!(access.code, ErrorCode::Unauthorized);
49
50 let domain_config: Error =
51 InternalError::domain(InternalErrorOrigin::Config, "bad config").into();
52 assert_eq!(domain_config.code, ErrorCode::InvalidInput);
53
54 let domain_other: Error =
55 InternalError::domain(InternalErrorOrigin::Domain, "conflict").into();
56 assert_eq!(domain_other.code, ErrorCode::Conflict);
57
58 let invariant: Error =
59 InternalError::invariant(InternalErrorOrigin::Ops, "broken invariant").into();
60 assert_eq!(invariant.code, ErrorCode::InvariantViolation);
61
62 let infra: Error = InternalError::infra(InternalErrorOrigin::Infra, "infra fail").into();
63 assert_eq!(infra.code, ErrorCode::Internal);
64
65 let ops: Error = InternalError::ops(InternalErrorOrigin::Ops, "ops fail").into();
66 assert_eq!(ops.code, ErrorCode::Internal);
67
68 let workflow: Error =
69 InternalError::workflow(InternalErrorOrigin::Workflow, "workflow fail").into();
70 assert_eq!(workflow.code, ErrorCode::Internal);
71 }
72
73 #[test]
74 fn public_error_is_preserved_without_remap() {
75 let public = Error::not_found("missing");
76 let remapped: Error = InternalError::public(public.clone()).into();
77 assert_eq!(remapped, public);
78 }
79}