malbox_plugin_sdk/
error.rs1use thiserror::Error;
9
10#[derive(Debug, Error)]
12#[non_exhaustive]
13pub enum SdkError {
14 #[error("transport error: {0}")]
16 Transport(#[from] malbox_plugin_transport::error::TransportError),
17
18 #[error("initialization error: {0}")]
20 Init(String),
21
22 #[error("channel send failed: {0}")]
25 Channel(String),
26
27 #[error("{operation} timed out after {elapsed:?}")]
29 Timeout {
30 operation: &'static str,
31 elapsed: std::time::Duration,
32 },
33
34 #[error("invalid context: {0}")]
38 InvalidContext(&'static str),
39
40 #[error("serialization error: {0}")]
42 Serialization(#[from] serde_json::Error),
43
44 #[error("io error: {0}")]
46 Io(#[from] std::io::Error),
47
48 #[error("plugin error: {0}")]
50 Plugin(Box<dyn std::error::Error + Send + Sync>),
51}
52
53pub type Result<T> = std::result::Result<T, SdkError>;
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn io_error_converts_to_sdk_error() {
62 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
63 let sdk_err: SdkError = io_err.into();
64 assert!(matches!(sdk_err, SdkError::Io(_)));
65 }
66
67 #[test]
68 fn plugin_variant_wraps_custom_error() {
69 #[derive(Debug)]
70 struct MyErr(&'static str);
71 impl std::fmt::Display for MyErr {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 write!(f, "{}", self.0)
74 }
75 }
76 impl std::error::Error for MyErr {}
77
78 let err: SdkError = SdkError::Plugin(Box::new(MyErr("custom boom")));
79 assert!(err.to_string().contains("custom boom"));
80 }
81
82 #[test]
83 fn serde_error_converts_to_sdk_error() {
84 let json_err = serde_json::from_str::<String>("not json").unwrap_err();
85 let sdk_err: SdkError = json_err.into();
86 assert!(matches!(sdk_err, SdkError::Serialization(_)));
87 }
88
89 use std::time::Duration;
90
91 #[test]
92 fn channel_variant_formats_correctly() {
93 let err = SdkError::Channel("push_result: receiver dropped".to_string());
94 assert!(err.to_string().contains("channel send failed"));
95 assert!(err.to_string().contains("push_result"));
96 }
97
98 #[test]
99 fn timeout_variant_formats_correctly() {
100 let err = SdkError::Timeout {
101 operation: "some_operation",
102 elapsed: Duration::from_secs(5),
103 };
104 let s = err.to_string();
105 assert!(s.contains("some_operation"));
106 assert!(s.contains("timed out"));
107 }
108
109 #[test]
110 fn invalid_context_variant_formats_correctly() {
111 let err = SdkError::InvalidContext("push_result called outside on_task");
112 assert!(err.to_string().contains("invalid context"));
113 assert!(err.to_string().contains("push_result"));
114 }
115}