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("Insufficient permissions - administrator privileges required")]
41 InsufficientPermissions,
42
43 #[error("Windows Filtering Platform service not available")]
45 ServiceNotAvailable,
46
47 #[error("Win32 error {code}: {message}")]
49 Win32Error { code: u32, message: String },
50
51 #[error("{0}")]
53 Other(String),
54}
55
56impl From<WIN32_ERROR> for WfpError {
57 fn from(error: WIN32_ERROR) -> Self {
58 let code = error.0;
59 let message = match code {
60 5 => "Access denied".to_string(),
61 1062 => "Service not started".to_string(),
62 1075 => "Service dependency does not exist".to_string(),
63 _ => format!("Unknown Win32 error: {}", code),
64 };
65
66 WfpError::Win32Error { code, message }
67 }
68}
69
70pub type WfpResult<T> = std::result::Result<T, WfpError>;
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn test_error_display_messages() {
78 assert_eq!(
79 WfpError::EngineOpenFailed.to_string(),
80 "Failed to open WFP engine session"
81 );
82 assert_eq!(
83 WfpError::InsufficientPermissions.to_string(),
84 "Insufficient permissions - administrator privileges required"
85 );
86 assert_eq!(
87 WfpError::ServiceNotAvailable.to_string(),
88 "Windows Filtering Platform service not available"
89 );
90 assert_eq!(
91 WfpError::TransactionBeginFailed.to_string(),
92 "Failed to begin WFP transaction"
93 );
94 assert_eq!(
95 WfpError::TransactionCommitFailed.to_string(),
96 "Failed to commit WFP transaction"
97 );
98 assert_eq!(
99 WfpError::TransactionAbortFailed.to_string(),
100 "Failed to abort WFP transaction"
101 );
102 }
103
104 #[test]
105 fn test_error_display_with_details() {
106 let err = WfpError::FilterAddFailed("test error".into());
107 assert_eq!(err.to_string(), "Failed to add filter: test error");
108
109 let err = WfpError::FilterDeleteFailed("filter 42".into());
110 assert_eq!(err.to_string(), "Failed to delete filter: filter 42");
111
112 let err = WfpError::Other("something happened".into());
113 assert_eq!(err.to_string(), "something happened");
114 }
115
116 #[test]
117 fn test_win32_error_display() {
118 let err = WfpError::Win32Error {
119 code: 5,
120 message: "Access denied".into(),
121 };
122 assert_eq!(err.to_string(), "Win32 error 5: Access denied");
123 }
124
125 #[test]
126 fn test_win32_error_conversion_access_denied() {
127 let err: WfpError = WIN32_ERROR(5).into();
128 match err {
129 WfpError::Win32Error { code, message } => {
130 assert_eq!(code, 5);
131 assert_eq!(message, "Access denied");
132 }
133 _ => panic!("Expected Win32Error"),
134 }
135 }
136
137 #[test]
138 fn test_win32_error_conversion_service_not_started() {
139 let err: WfpError = WIN32_ERROR(1062).into();
140 match err {
141 WfpError::Win32Error { code, message } => {
142 assert_eq!(code, 1062);
143 assert_eq!(message, "Service not started");
144 }
145 _ => panic!("Expected Win32Error"),
146 }
147 }
148
149 #[test]
150 fn test_win32_error_conversion_dependency_missing() {
151 let err: WfpError = WIN32_ERROR(1075).into();
152 match err {
153 WfpError::Win32Error { code, message } => {
154 assert_eq!(code, 1075);
155 assert_eq!(message, "Service dependency does not exist");
156 }
157 _ => panic!("Expected Win32Error"),
158 }
159 }
160
161 #[test]
162 fn test_win32_error_conversion_unknown() {
163 let err: WfpError = WIN32_ERROR(9999).into();
164 match err {
165 WfpError::Win32Error { code, message } => {
166 assert_eq!(code, 9999);
167 assert!(message.contains("Unknown"));
168 }
169 _ => panic!("Expected Win32Error"),
170 }
171 }
172}