1use thiserror::Error;
4
5#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum UsnError {
9 #[error("Access denied: Administrator privileges required.")]
10 PermissionError,
11
12 #[error("Invalid mount point: {0}")]
13 InvalidMountPointError(String),
14
15 #[error("IO error: {0}")]
16 IoError(#[from] std::io::Error),
17
18 #[error("Windows API error: {0}")]
19 WinApiError(#[from] windows::core::Error),
20
21 #[error("Other error: {0}")]
22 OtherError(String),
23}
24
25#[cfg(test)]
26mod tests {
27 use super::*;
28 use std::io::{Error as IoError, ErrorKind};
29 use windows::Win32::Foundation::ERROR_ACCESS_DENIED;
30
31 mod error_variant_tests {
33 use super::*;
34
35 #[test]
36 fn test_permission_error_display() {
37 let error = UsnError::PermissionError;
38 let error_string = error.to_string();
39 assert_eq!(
40 error_string,
41 "Access denied: Administrator privileges required."
42 );
43 }
44
45 #[test]
46 fn test_invalid_mount_point_error_display() {
47 let mount_point = "C:\\invalid\\path";
48 let error = UsnError::InvalidMountPointError(mount_point.to_string());
49 let error_string = error.to_string();
50 assert_eq!(error_string, "Invalid mount point: C:\\invalid\\path");
51 }
52
53 #[test]
54 fn test_other_error_display() {
55 let message = "Custom error message";
56 let error = UsnError::OtherError(message.to_string());
57 let error_string = error.to_string();
58 assert_eq!(error_string, "Other error: Custom error message");
59 }
60
61 #[test]
62 fn test_io_error_conversion() {
63 let io_error = IoError::new(ErrorKind::NotFound, "File not found");
64 let usn_error = UsnError::from(io_error);
65
66 match usn_error {
67 UsnError::IoError(ref e) => {
68 assert_eq!(e.kind(), ErrorKind::NotFound);
69 assert_eq!(e.to_string(), "File not found");
70 }
71 _ => panic!("Expected IoError variant"),
72 }
73 }
74
75 #[test]
76 fn test_windows_error_conversion() {
77 let win_error = windows::core::Error::from(ERROR_ACCESS_DENIED);
78 let usn_error = UsnError::from(win_error);
79
80 match usn_error {
81 UsnError::WinApiError(ref e) => {
82 assert_eq!(e.code(), ERROR_ACCESS_DENIED.into());
83 }
84 _ => panic!("Expected WinApiError variant"),
85 }
86 }
87
88 #[test]
89 fn test_error_chain_display() {
90 let io_error = IoError::new(ErrorKind::PermissionDenied, "Access denied");
91 let usn_error = UsnError::from(io_error);
92 let error_string = usn_error.to_string();
93 assert!(error_string.contains("IO error:"));
94 assert!(error_string.contains("Access denied"));
95 }
96 }
97
98 mod error_handling_tests {
100 use super::*;
101
102 #[test]
103 fn test_result_type_integration() {
104 fn returns_permission_error() -> Result<(), UsnError> {
106 Err(UsnError::PermissionError)
107 }
108
109 fn returns_ok() -> Result<String, UsnError> {
110 Ok("success".to_string())
111 }
112
113 assert!(returns_permission_error().is_err());
114 assert!(returns_ok().is_ok());
115 assert_eq!(returns_ok().unwrap(), "success");
116 }
117
118 #[test]
119 fn test_error_source_chain() {
120 use std::error::Error;
121
122 let io_error = IoError::new(ErrorKind::NotFound, "Original error");
123 let usn_error = UsnError::from(io_error);
124
125 assert!(usn_error.source().is_some());
127 if let UsnError::IoError(ref e) = usn_error {
128 assert_eq!(e.to_string(), "Original error");
129 }
130 }
131 }
132
133 mod usn_specific_error_tests {
135 use super::*;
136
137 #[test]
138 fn test_common_permission_scenarios() {
139 let error = UsnError::PermissionError;
141 assert!(
142 error
143 .to_string()
144 .contains("Administrator privileges required")
145 );
146 }
147
148 #[test]
149 fn test_mount_point_error_scenarios() {
150 let invalid_paths = vec![
151 "Z:\\nonexistent",
152 "\\\\invalid\\unc\\path",
153 "C:\\path\\that\\does\\not\\exist",
154 "",
155 ];
156
157 for path in invalid_paths {
158 let error = UsnError::InvalidMountPointError(path.to_string());
159 assert!(error.to_string().contains("Invalid mount point:"));
160 assert!(error.to_string().contains(path));
161 }
162 }
163
164 #[test]
165 fn test_windows_api_error_codes() {
166 use windows::Win32::Foundation::{ERROR_FILE_NOT_FOUND, ERROR_INVALID_HANDLE};
167
168 let error_codes = vec![
169 ERROR_ACCESS_DENIED,
170 ERROR_FILE_NOT_FOUND,
171 ERROR_INVALID_HANDLE,
172 ];
173
174 for code in error_codes {
175 let win_error = windows::core::Error::from(code);
176 let usn_error = UsnError::from(win_error);
177
178 if let UsnError::WinApiError(ref e) = usn_error {
179 assert_eq!(e.code(), code.into());
180 } else {
181 panic!("Expected WinApiError variant");
182 }
183 }
184 }
185 }
186}