1use thiserror::Error;
6use windows::Win32::Foundation::WIN32_ERROR;
7
8#[derive(Error, Debug)]
10pub enum WfpError {
11 #[error("Failed to open WFP engine session")]
13 EngineOpenFailed,
14
15 #[error("Failed to close WFP engine session")]
17 EngineCloseFailed,
18
19 #[error("Failed to add filter: {0}")]
21 FilterAddFailed(String),
22
23 #[error("Failed to delete filter: {0}")]
25 FilterDeleteFailed(String),
26
27 #[error("Failed to begin WFP transaction")]
29 TransactionBeginFailed,
30
31 #[error("Failed to commit WFP transaction")]
33 TransactionCommitFailed,
34
35 #[error("Failed to abort WFP transaction")]
37 TransactionAbortFailed,
38
39 #[error("Application path not found or invalid: {0}")]
44 AppPathNotFound(String),
45
46 #[error("Insufficient permissions - administrator privileges required")]
48 InsufficientPermissions,
49
50 #[error("Windows Filtering Platform service not available")]
52 ServiceNotAvailable,
53
54 #[error("Win32 error {code}: {message}")]
56 Win32Error { code: u32, message: String },
57
58 #[error("{0}")]
60 Other(String),
61}
62
63impl From<WIN32_ERROR> for WfpError {
64 fn from(error: WIN32_ERROR) -> Self {
65 let code = error.0;
66 let message = match code {
67 5 => "Access denied".to_string(),
68 1062 => "Service not started".to_string(),
69 1075 => "Service dependency does not exist".to_string(),
70 _ => format!("Unknown Win32 error: {}", code),
71 };
72
73 WfpError::Win32Error { code, message }
74 }
75}
76
77pub type WfpResult<T> = std::result::Result<T, WfpError>;
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_error_display_messages() {
85 assert_eq!(
86 WfpError::EngineOpenFailed.to_string(),
87 "Failed to open WFP engine session"
88 );
89 assert_eq!(
90 WfpError::InsufficientPermissions.to_string(),
91 "Insufficient permissions - administrator privileges required"
92 );
93 assert_eq!(
94 WfpError::ServiceNotAvailable.to_string(),
95 "Windows Filtering Platform service not available"
96 );
97 assert_eq!(
98 WfpError::TransactionBeginFailed.to_string(),
99 "Failed to begin WFP transaction"
100 );
101 assert_eq!(
102 WfpError::TransactionCommitFailed.to_string(),
103 "Failed to commit WFP transaction"
104 );
105 assert_eq!(
106 WfpError::TransactionAbortFailed.to_string(),
107 "Failed to abort WFP transaction"
108 );
109 assert_eq!(
110 WfpError::AppPathNotFound(r"C:\missing.exe".into()).to_string(),
111 r"Application path not found or invalid: C:\missing.exe"
112 );
113 }
114
115 #[test]
116 fn test_error_display_with_details() {
117 let err = WfpError::FilterAddFailed("test error".into());
118 assert_eq!(err.to_string(), "Failed to add filter: test error");
119
120 let err = WfpError::FilterDeleteFailed("filter 42".into());
121 assert_eq!(err.to_string(), "Failed to delete filter: filter 42");
122
123 let err = WfpError::Other("something happened".into());
124 assert_eq!(err.to_string(), "something happened");
125 }
126
127 #[test]
128 fn test_win32_error_display() {
129 let err = WfpError::Win32Error {
130 code: 5,
131 message: "Access denied".into(),
132 };
133 assert_eq!(err.to_string(), "Win32 error 5: Access denied");
134 }
135
136 #[test]
137 fn test_win32_error_conversion_access_denied() {
138 let err: WfpError = WIN32_ERROR(5).into();
139 match err {
140 WfpError::Win32Error { code, message } => {
141 assert_eq!(code, 5);
142 assert_eq!(message, "Access denied");
143 }
144 _ => panic!("Expected Win32Error"),
145 }
146 }
147
148 #[test]
149 fn test_win32_error_conversion_service_not_started() {
150 let err: WfpError = WIN32_ERROR(1062).into();
151 match err {
152 WfpError::Win32Error { code, message } => {
153 assert_eq!(code, 1062);
154 assert_eq!(message, "Service not started");
155 }
156 _ => panic!("Expected Win32Error"),
157 }
158 }
159
160 #[test]
161 fn test_win32_error_conversion_dependency_missing() {
162 let err: WfpError = WIN32_ERROR(1075).into();
163 match err {
164 WfpError::Win32Error { code, message } => {
165 assert_eq!(code, 1075);
166 assert_eq!(message, "Service dependency does not exist");
167 }
168 _ => panic!("Expected Win32Error"),
169 }
170 }
171
172 #[test]
173 fn test_win32_error_conversion_unknown() {
174 let err: WfpError = WIN32_ERROR(9999).into();
175 match err {
176 WfpError::Win32Error { code, message } => {
177 assert_eq!(code, 9999);
178 assert!(message.contains("Unknown"));
179 }
180 _ => panic!("Expected Win32Error"),
181 }
182 }
183}