stackerror/
lib.rs

1#![doc = include_str!("../README.md")]
2
3pub mod codes;
4pub mod error;
5#[cfg(feature = "http")]
6mod from_http;
7#[cfg(feature = "reqwest")]
8mod from_reqwest;
9mod from_std_io;
10pub mod macros;
11pub mod prelude;
12
13pub use prelude::*;
14pub use stackerror_impl::derive_stack_error;
15
16#[cfg(test)]
17mod tests {
18    use super::*;
19
20    #[test]
21    fn test_error_builds_empty() {
22        let error = StackError::new();
23        assert_eq!(format!("{:?}", error), "");
24    }
25
26    #[test]
27    fn test_error_builds_from_msg() {
28        let error = StackError::from_msg("Test error");
29        assert_eq!(format!("{:?}", error), "Test error");
30    }
31
32    #[test]
33    fn test_error_has_err() {
34        let error = StackError::new().with_err_msg("Test error");
35        assert_eq!(format!("{:?}", error), "Test error");
36    }
37
38    #[test]
39    fn test_error_has_code() {
40        let error = StackError::new().with_err_code(ErrorCode::RuntimeInvalidValue);
41        assert_eq!(error.err_code(), Some(&ErrorCode::RuntimeInvalidValue));
42    }
43
44    #[test]
45    fn test_error_has_uri() {
46        let error = StackError::new().with_err_uri("https://example.com/error".to_string());
47        assert_eq!(error.err_uri(), Some("https://example.com/error"));
48    }
49
50    #[test]
51    fn test_error_stacks() {
52        let base_error = StackError::from_msg("Base error")
53            .with_err_code(ErrorCode::RuntimeInvalidValue)
54            .with_err_uri("https://example.com/base".to_string());
55        let stacked_error = base_error.stack_err_msg("Stacked error");
56        assert_eq!(format!("{:?}", stacked_error), "Base error\nStacked error");
57        assert_eq!(
58            stacked_error.err_code(),
59            Some(&ErrorCode::RuntimeInvalidValue)
60        );
61        assert_eq!(stacked_error.err_uri(), Some("https://example.com/base"));
62    }
63
64    #[test]
65    fn test_from_std_io_for_stackerror() {
66        let io_err = std::io::Error::from(std::io::ErrorKind::NotFound);
67        let err: StackError = io_err.into();
68        assert_eq!(err.err_code(), Some(&ErrorCode::IoNotFound));
69    }
70
71    #[cfg(feature = "http")]
72    #[test]
73    fn test_from_http_status_for_stackerror() {
74        let status = http::StatusCode::NOT_FOUND;
75        let err: StackError = status.into();
76        assert_eq!(err.err_code(), Some(&ErrorCode::HttpNotFound));
77    }
78
79    #[cfg(feature = "reqwest")]
80    #[test]
81    fn test_from_reqwest_error_for_stackerror() {
82        // Build-time request error (invalid header) -> no HTTP status
83        let client = reqwest::Client::builder().build().unwrap();
84        let req_err = client
85            .get("http://example.com")
86            .header("\n", "value")
87            .build()
88            .unwrap_err();
89        let err: StackError = req_err.into();
90        assert_eq!(err.err_code(), None);
91    }
92
93    // Add this custom error struct
94    #[derive_stack_error]
95    struct LibError(StackError);
96
97    #[test]
98    fn test_custom_builds_empty() {
99        let error = LibError::new();
100        assert_eq!(format!("{:?}", error), "");
101    }
102
103    #[test]
104    fn test_custom_builds_from_msg() {
105        let error = LibError::from_msg("Test error");
106        assert_eq!(format!("{:?}", error), "Test error");
107    }
108
109    #[test]
110    fn test_custom_has_err() {
111        let error = LibError::new().with_err_msg("Test error");
112        assert_eq!(format!("{:?}", error), "Test error");
113    }
114
115    #[test]
116    fn test_custom_has_code() {
117        let error = LibError::new().with_err_code(ErrorCode::RuntimeInvalidValue);
118        assert_eq!(error.err_code(), Some(&ErrorCode::RuntimeInvalidValue));
119    }
120
121    #[test]
122    fn test_custom_has_uri() {
123        let error = LibError::new().with_err_uri("https://example.com/error".to_string());
124        assert_eq!(error.err_uri(), Some("https://example.com/error"));
125    }
126
127    #[test]
128    fn test_custom_stacks() {
129        let base_error = LibError::from_msg("Base error")
130            .with_err_code(ErrorCode::RuntimeInvalidValue)
131            .with_err_uri("https://example.com/base".to_string());
132        let stacked_error = base_error.stack_err_msg("Stacked error");
133        assert_eq!(format!("{:?}", stacked_error), "Base error\nStacked error");
134        assert_eq!(
135            stacked_error.err_code(),
136            Some(&ErrorCode::RuntimeInvalidValue)
137        );
138        assert_eq!(stacked_error.err_uri(), Some("https://example.com/base"));
139    }
140
141    #[test]
142    fn test_from_std_io_for_custom_error() {
143        let io_err = std::io::Error::from(std::io::ErrorKind::PermissionDenied);
144        let err: LibError = io_err.into();
145        assert_eq!(err.err_code(), Some(&ErrorCode::IoPermissionDenied));
146    }
147
148    // NOTE: don't need to test other from impls in custom error since they
149    // are handled by a generic impl block
150}