sz_rust_addons_loader/
error.rs1use thiserror::Error;
16
17#[derive(Debug, Error)]
19pub enum AddonLoaderError {
20 #[error("addon '{0}' not found")]
22 AddonNotFound(String),
23
24 #[error("addon '{0}' is disabled")]
26 AddonDisabled(String),
27
28 #[error("addon controller '{0}' not found")]
30 ControllerNotFound(String),
31
32 #[error("addon action '{0}' not found")]
34 ActionNotFound(String),
35
36 #[error("failed to parse manifest for addon '{addon}': {reason}")]
38 ManifestParse {
39 addon: String,
41 reason: String,
43 },
44
45 #[error("failed to scan addons directory '{path}': {source}")]
47 ScanDir {
48 path: String,
50 source: std::io::Error,
52 },
53
54 #[error("failed to read file '{path}': {source}")]
56 ReadFile {
57 path: String,
59 source: std::io::Error,
61 },
62
63 #[error("autoload failed: class '{class}' not mapped to any file")]
65 AutoloadMiss {
66 class: String,
68 },
69
70 #[error("failed to register hook '{hook}' for addon '{addon}'")]
72 HookRegister {
73 hook: String,
75 addon: String,
77 },
78
79 #[error("failed to parse route '{url}': {reason}")]
81 RouteParse {
82 url: String,
84 reason: String,
86 },
87}
88
89impl From<std::io::Error> for AddonLoaderError {
90 fn from(err: std::io::Error) -> Self {
91 AddonLoaderError::ReadFile {
92 path: "<unknown>".to_string(),
93 source: err,
94 }
95 }
96}
97
98pub type AddonLoaderResult<T> = Result<T, AddonLoaderError>;
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_addon_not_found_display() {
107 let err = AddonLoaderError::AddonNotFound("operate".to_string());
108 assert_eq!(err.to_string(), "addon 'operate' not found");
109 }
110
111 #[test]
112 fn test_addon_disabled_display() {
113 let err = AddonLoaderError::AddonDisabled("test".to_string());
114 assert_eq!(err.to_string(), "addon 'test' is disabled");
115 }
116
117 #[test]
118 fn test_controller_not_found_display() {
119 let err = AddonLoaderError::ControllerNotFound("admin.Order".to_string());
120 assert_eq!(err.to_string(), "addon controller 'admin.Order' not found");
121 }
122
123 #[test]
124 fn test_action_not_found_display() {
125 let err = AddonLoaderError::ActionNotFound("index".to_string());
126 assert_eq!(err.to_string(), "addon action 'index' not found");
127 }
128
129 #[test]
130 fn test_manifest_parse_display() {
131 let err = AddonLoaderError::ManifestParse {
132 addon: "operate".to_string(),
133 reason: "missing $info array".to_string(),
134 };
135 assert!(err.to_string().contains("operate"));
136 assert!(err.to_string().contains("missing $info array"));
137 }
138
139 #[test]
140 fn test_scan_dir_display() {
141 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "no such directory");
142 let err = AddonLoaderError::ScanDir {
143 path: "/addons".to_string(),
144 source: io_err,
145 };
146 assert!(err.to_string().contains("/addons"));
147 }
148
149 #[test]
150 fn test_read_file_display() {
151 let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "denied");
152 let err = AddonLoaderError::ReadFile {
153 path: "/addons/operate/Plugin.php".to_string(),
154 source: io_err,
155 };
156 assert!(err.to_string().contains("Plugin.php"));
157 }
158
159 #[test]
160 fn test_autoload_miss_display() {
161 let err = AddonLoaderError::AutoloadMiss {
162 class: "addons\\operate\\Plugin".to_string(),
163 };
164 assert!(err.to_string().contains("addons\\operate\\Plugin"));
165 }
166
167 #[test]
168 fn test_hook_register_display() {
169 let err = AddonLoaderError::HookRegister {
170 hook: "AddonsInit".to_string(),
171 addon: "operate".to_string(),
172 };
173 assert!(err.to_string().contains("AddonsInit"));
174 assert!(err.to_string().contains("operate"));
175 }
176
177 #[test]
178 fn test_route_parse_display() {
179 let err = AddonLoaderError::RouteParse {
180 url: "/addons/operate".to_string(),
181 reason: "missing controller".to_string(),
182 };
183 assert!(err.to_string().contains("/addons/operate"));
184 }
185
186 #[test]
187 fn test_from_io_error() {
188 let io_err = std::io::Error::other("test");
189 let err: AddonLoaderError = io_err.into();
190 assert!(matches!(err, AddonLoaderError::ReadFile { .. }));
191 }
192
193 #[test]
194 fn test_result_alias_ok() {
195 let result: AddonLoaderResult<i32> = Ok(42);
196 match result {
197 Ok(v) => assert_eq!(v, 42),
198 Err(_) => panic!("expected Ok"),
199 }
200 }
201
202 #[test]
203 fn test_result_alias_err() {
204 let result: AddonLoaderResult<i32> = Err(AddonLoaderError::AddonNotFound("x".to_string()));
205 assert!(result.is_err());
206 }
207}