Skip to main content

orion_error/
testing.rs

1use crate::reason::{ErrorCategory, ErrorIdentityProvider};
2use crate::{core::DomainReason, StructError};
3
4#[allow(dead_code)]
5// Testing-only assertion trait (no message).
6pub trait TestAssert {
7    type Output;
8    fn assert(self) -> Self::Output;
9}
10
11#[allow(dead_code)]
12// Testing-only assertion trait (with message).
13pub trait TestAssertWithMsg<A> {
14    type Output;
15    fn assert(self, msg: A) -> Self::Output;
16}
17
18impl<T, E> TestAssert for Result<T, E>
19where
20    E: std::fmt::Display,
21{
22    type Output = T;
23
24    fn assert(self) -> T {
25        self.unwrap_or_else(|e| panic!("[TEST ASSERTION FAILED] \n Error details: {e}"))
26    }
27}
28
29impl<T, E> TestAssertWithMsg<&str> for Result<T, E>
30where
31    E: std::fmt::Display,
32{
33    type Output = T;
34
35    fn assert(self, msg: &str) -> T {
36        self.unwrap_or_else(|e| panic!("[TEST ASSERTION FAILED] {msg} \n Error details: {e}"))
37    }
38}
39
40impl<T> TestAssert for Option<T> {
41    type Output = T;
42
43    fn assert(self) -> T {
44        self.unwrap_or_else(|| panic!("[OPTION ASSERTION FAILED] ",))
45    }
46}
47
48/// Assert that the error's **stable code string** matches.
49///
50/// This asserts [`ErrorIdentityProvider::stable_code`], **not** the numeric
51/// [`ErrorCode::error_code`]. For numeric assertions, call `.error_code()` directly.
52///
53/// # Example
54///
55/// ```rust
56/// use orion_error::UnifiedReason;
57/// use orion_error::dev::testing::assert_err_code;
58/// use orion_error::StructError;
59///
60/// let err = StructError::from(UnifiedReason::system_error());
61/// assert_err_code(&err, "sys.io_error");
62/// ```
63pub fn assert_err_code<R>(err: &StructError<R>, code: &str)
64where
65    R: DomainReason + ErrorIdentityProvider,
66{
67    assert_eq!(err.reason().stable_code(), code);
68}
69
70/// Assert that the error's [`ErrorCategory`] matches.
71pub fn assert_err_category<R>(err: &StructError<R>, category: ErrorCategory)
72where
73    R: DomainReason + ErrorIdentityProvider,
74{
75    assert_eq!(err.reason().error_category(), category);
76}
77
78pub fn assert_err_identity<R>(err: &StructError<R>, code: &str, category: ErrorCategory)
79where
80    R: DomainReason + ErrorIdentityProvider,
81{
82    assert_err_code(err, code);
83    assert_err_category(err, category);
84}
85
86pub fn assert_err_operation<R>(err: &StructError<R>, operation: &str)
87where
88    R: DomainReason,
89{
90    assert_eq!(err.action_main().as_deref(), Some(operation));
91}
92
93pub fn assert_err_path<R>(err: &StructError<R>, path: &str)
94where
95    R: DomainReason,
96{
97    assert_eq!(err.target_path().as_deref(), Some(path));
98}
99
100#[cfg(test)]
101mod tests {
102    use super::{
103        assert_err_category, assert_err_code, assert_err_identity, assert_err_operation,
104        assert_err_path,
105    };
106    use crate::conversion::ErrorWith;
107    use crate::reason::ErrorCategory;
108    use crate::{StructError, UnifiedReason};
109
110    #[test]
111    fn test_assert_err_code_helper() {
112        let err = StructError::from(UnifiedReason::system_error());
113        assert_err_code(&err, "sys.io_error");
114    }
115
116    #[test]
117    fn test_assert_err_category_helper() {
118        let err = StructError::from(UnifiedReason::business_error());
119        assert_err_category(&err, ErrorCategory::Biz);
120    }
121
122    #[test]
123    fn test_assert_err_identity_helper() {
124        let err = StructError::from(UnifiedReason::network_error());
125        assert_err_identity(&err, "sys.network_error", ErrorCategory::Sys);
126    }
127
128    #[test]
129    fn test_assert_err_operation_helper() {
130        let err = StructError::from(UnifiedReason::system_error())
131            .with_detail("read config failed")
132            .doing("load config");
133        assert_err_operation(&err, "load config");
134    }
135
136    #[test]
137    fn test_assert_err_path_helper() {
138        let err = StructError::from(UnifiedReason::system_error())
139            .with_detail("read config failed")
140            .doing("load config")
141            .at("config.toml");
142        assert_err_path(&err, "load config / config.toml");
143    }
144}