Skip to main content

canic_core/api/
error.rs

1use crate::{InternalError, dto::error::Error};
2
3const fn internal_error_to_public(err: &InternalError) -> Error {
4    err.public_error()
5}
6
7impl From<&InternalError> for Error {
8    fn from(err: &InternalError) -> Self {
9        internal_error_to_public(err)
10    }
11}
12
13impl From<InternalError> for Error {
14    fn from(err: InternalError) -> Self {
15        internal_error_to_public(&err)
16    }
17}
18
19// -----------------------------------------------------------------------------
20// Tests
21// -----------------------------------------------------------------------------
22
23#[cfg(test)]
24mod tests {
25    use super::*;
26    use crate::{
27        access::AccessError,
28        domain::policy::pure::{
29            component_allocation::ComponentAllocationPolicyError,
30            component_child_allocation::ComponentChildAllocationPolicyError,
31        },
32        ids::CanisterRole,
33    };
34
35    #[test]
36    fn internal_error_mapping_uses_registered_semantic_causes() {
37        let access: Error = InternalError::from(AccessError::ControllerRequired).into();
38        assert_eq!(
39            access.code(),
40            crate::diagnostics::codes::AUTHORITY_UNAVAILABLE.raw_code()
41        );
42
43        let domain_config: Error = InternalError::projected(
44            crate::diagnostics::codes::CONFIGURATION_INVALID,
45            crate::diagnostics::codes::REQUEST_INVALID,
46        )
47        .into();
48        assert_eq!(
49            domain_config.code(),
50            crate::diagnostics::codes::REQUEST_INVALID.raw_code()
51        );
52
53        let domain_other: Error = InternalError::conflict().into();
54        assert_eq!(
55            domain_other.code(),
56            crate::diagnostics::codes::STATE_CONFLICT.raw_code()
57        );
58
59        let invariant: Error = InternalError::invariant().into();
60        assert_eq!(
61            invariant.code(),
62            crate::diagnostics::codes::STATE_INVALID.raw_code()
63        );
64
65        let infra: Error = InternalError::platform_failure().into();
66        assert_eq!(
67            infra.code(),
68            crate::diagnostics::codes::STATE_FAILED.raw_code()
69        );
70
71        let ops: Error = InternalError::state_failure().into();
72        assert_eq!(
73            ops.code(),
74            crate::diagnostics::codes::STATE_FAILED.raw_code()
75        );
76
77        let workflow: Error = InternalError::lifecycle_failure().into();
78        assert_eq!(
79            workflow.code(),
80            crate::diagnostics::codes::STATE_FAILED.raw_code()
81        );
82
83        let invalid_allocation: Error =
84            InternalError::from(ComponentAllocationPolicyError::EmptyOperationId).into();
85        assert_eq!(
86            invalid_allocation.code(),
87            crate::diagnostics::codes::REQUEST_INCOMPLETE.raw_code()
88        );
89
90        let exhausted_allocation: Error =
91            InternalError::from(ComponentAllocationPolicyError::ComponentCapacityExhausted).into();
92        assert_eq!(
93            exhausted_allocation.code(),
94            crate::diagnostics::codes::CAPACITY_LIMIT.raw_code()
95        );
96
97        let invalid_authority: Error =
98            InternalError::from(ComponentAllocationPolicyError::RootTopologyDigestMismatch).into();
99        assert_eq!(
100            invalid_authority.code(),
101            crate::diagnostics::codes::DIGEST_CONFLICT.raw_code()
102        );
103
104        let forbidden_child: Error =
105            InternalError::from(ComponentChildAllocationPolicyError::SpawnGrantMissing {
106                parent_role: CanisterRole::new("project_hub"),
107                child_role: CanisterRole::new("project_ledger"),
108            })
109            .into();
110        assert_eq!(
111            forbidden_child.code(),
112            crate::diagnostics::codes::CONFIGURATION_UNAVAILABLE.raw_code()
113        );
114
115        let stale_child: Error = InternalError::from(
116            ComponentChildAllocationPolicyError::ComponentRegistryAuthorityMismatch,
117        )
118        .into();
119        assert_eq!(
120            stale_child.code(),
121            crate::diagnostics::codes::AUTHORITY_CONFLICT.raw_code()
122        );
123
124        let exhausted_child: Error = InternalError::from(
125            ComponentChildAllocationPolicyError::ComponentDescendantCapacityExhausted,
126        )
127        .into();
128        assert_eq!(
129            exhausted_child.code(),
130            crate::diagnostics::codes::CAPACITY_LIMIT.raw_code()
131        );
132
133        let token_expired: Error = AccessError::DelegatedAuthTokenExpired.into();
134        assert_eq!(
135            token_expired.code(),
136            crate::diagnostics::codes::AUTH_TOKEN_EXPIRED.raw_code()
137        );
138
139        let cert_expired: Error = AccessError::DelegatedAuthCertExpired.into();
140        assert_eq!(
141            cert_expired.code(),
142            crate::diagnostics::codes::AUTH_CERT_EXPIRED.raw_code()
143        );
144    }
145
146    #[test]
147    fn public_error_is_preserved_without_remap() {
148        let public = Error::from_registered(crate::diagnostics::codes::COLLECTION_UNAVAILABLE);
149        let remapped: Error =
150            InternalError::public(crate::diagnostics::codes::COLLECTION_UNAVAILABLE).into();
151        assert_eq!(remapped, public);
152    }
153}