Coverage Report

Created: 2025-06-23 14:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/b/lab/denet/src/error.rs
Line
Count
Source
1
//! Error types for the denet library
2
//!
3
//! This module provides comprehensive error handling for all denet operations,
4
//! including process monitoring, I/O operations, and system interactions.
5
6
use std::fmt;
7
8
/// Main error type for denet operations
9
#[derive(Debug)]
10
pub enum DenetError {
11
    /// I/O related errors (file operations, network, etc.)
12
    Io(std::io::Error),
13
    /// Process not found or inaccessible
14
    ProcessNotFound(usize),
15
    /// Process access denied
16
    ProcessAccessDenied(usize),
17
    /// System time errors
18
    SystemTime(std::time::SystemTimeError),
19
    /// JSON serialization/deserialization errors
20
    Serialization(serde_json::Error),
21
    /// Configuration or parameter validation errors
22
    InvalidConfiguration(String),
23
    /// Platform-specific operation not supported
24
    PlatformNotSupported(String),
25
    /// eBPF initialization or operation errors
26
    EbpfInitError(String),
27
    /// eBPF not supported on this platform
28
    EbpfNotSupported(String),
29
    /// Generic error with message
30
    Other(String),
31
}
32
33
impl fmt::Display for DenetError {
34
12
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35
12
        match self {
36
2
            DenetError::Io(err) => write!(f, "I/O error: {err}"),
37
2
            DenetError::ProcessNotFound(pid) => write!(f, "Process not found: {pid}"),
38
1
            DenetError::ProcessAccessDenied(pid) => write!(f, "Access denied for process: {pid}"),
39
1
            DenetError::SystemTime(err) => write!(f, "System time error: {err}"),
40
1
            DenetError::Serialization(err) => write!(f, "Serialization error: {err}"),
41
1
            DenetError::InvalidConfiguration(msg) => write!(f, "Invalid configuration: {msg}"),
42
1
            DenetError::PlatformNotSupported(msg) => write!(f, "Platform not supported: {msg}"),
43
1
            DenetError::EbpfInitError(msg) => write!(f, "eBPF initialization error: {msg}"),
44
1
            DenetError::EbpfNotSupported(msg) => write!(f, "eBPF not supported: {msg}"),
45
1
            DenetError::Other(msg) => write!(f, "Error: {msg}"),
46
        }
47
12
    }
48
}
49
50
impl std::error::Error for DenetError {
51
10
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
52
10
        match *self {
53
1
            DenetError::Io(ref err) => Some(err),
54
1
            DenetError::SystemTime(ref err) => Some(err),
55
1
            DenetError::Serialization(ref err) => Some(err),
56
7
            _ => None,
57
        }
58
10
    }
59
}
60
61
// Conversions from standard library errors
62
impl From<std::io::Error> for DenetError {
63
1
    fn from(err: std::io::Error) -> Self {
64
1
        DenetError::Io(err)
65
1
    }
66
}
67
68
impl From<std::time::SystemTimeError> for DenetError {
69
1
    fn from(err: std::time::SystemTimeError) -> Self {
70
1
        DenetError::SystemTime(err)
71
1
    }
72
}
73
74
impl From<serde_json::Error> for DenetError {
75
1
    fn from(err: serde_json::Error) -> Self {
76
1
        DenetError::Serialization(err)
77
1
    }
78
}
79
80
// Additional conversions for compatibility
81
impl From<DenetError> for std::io::Error {
82
2
    fn from(err: DenetError) -> Self {
83
2
        match err {
84
1
            DenetError::Io(io_err) => io_err,
85
1
            _ => std::io::Error::other(err.to_string()),
86
        }
87
2
    }
88
}
89
90
/// Convenience type alias for Results with DenetError
91
pub type Result<T> = std::result::Result<T, DenetError>;
92
93
/// Convert DenetError to PyO3 error for Python bindings
94
#[cfg(feature = "python")]
95
impl From<DenetError> for pyo3::PyErr {
96
    fn from(err: DenetError) -> Self {
97
        use pyo3::exceptions::*;
98
        match err {
99
            DenetError::Io(_) => PyIOError::new_err(err.to_string()),
100
            DenetError::ProcessNotFound(_) => PyRuntimeError::new_err(err.to_string()),
101
            DenetError::ProcessAccessDenied(_) => PyPermissionError::new_err(err.to_string()),
102
            DenetError::InvalidConfiguration(_) => PyValueError::new_err(err.to_string()),
103
            DenetError::PlatformNotSupported(_) => PyNotImplementedError::new_err(err.to_string()),
104
            DenetError::EbpfInitError(_) => PyRuntimeError::new_err(err.to_string()),
105
            DenetError::EbpfNotSupported(_) => PyNotImplementedError::new_err(err.to_string()),
106
            _ => PyRuntimeError::new_err(err.to_string()),
107
        }
108
    }
109
}
110
111
#[cfg(test)]
112
mod tests {
113
    use super::*;
114
    use std::error::Error;
115
    use std::io;
116
117
    #[test]
118
1
    fn test_denet_error_display() {
119
1
        // Test IO error display
120
1
        let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
121
1
        let denet_err = DenetError::Io(io_err);
122
1
        assert!(denet_err.to_string().contains("I/O error"));
123
1
        assert!(denet_err.to_string().contains("file not found"));
124
125
        // Test process not found error
126
1
        let pid = 12345;
127
1
        let err = DenetError::ProcessNotFound(pid);
128
1
        assert_eq!(err.to_string(), format!("Process not found: {}", pid));
129
130
        // Test process access denied error
131
1
        let err = DenetError::ProcessAccessDenied(pid);
132
1
        assert_eq!(
133
1
            err.to_string(),
134
1
            format!("Access denied for process: {}", pid)
135
1
        );
136
137
        // Test system time error
138
1
        let time_err = std::time::SystemTime::now()
139
1
            .duration_since(std::time::SystemTime::now() + std::time::Duration::from_secs(1))
140
1
            .unwrap_err();
141
1
        let err = DenetError::SystemTime(time_err);
142
1
        assert!(err.to_string().contains("System time error"));
143
144
        // Test serialization error
145
1
        let json_err = serde_json::Error::io(io::Error::new(io::ErrorKind::Other, "JSON error"));
146
1
        let err = DenetError::Serialization(json_err);
147
1
        assert!(err.to_string().contains("Serialization error"));
148
149
        // Test invalid configuration error
150
1
        let msg = "Invalid config parameter";
151
1
        let err = DenetError::InvalidConfiguration(msg.to_string());
152
1
        assert_eq!(err.to_string(), format!("Invalid configuration: {}", msg));
153
154
        // Test platform not supported error
155
1
        let msg = "Windows feature";
156
1
        let err = DenetError::PlatformNotSupported(msg.to_string());
157
1
        assert_eq!(err.to_string(), format!("Platform not supported: {}", msg));
158
159
        // Test eBPF initialization error
160
1
        let msg = "Failed to initialize BPF";
161
1
        let err = DenetError::EbpfInitError(msg.to_string());
162
1
        assert_eq!(
163
1
            err.to_string(),
164
1
            format!("eBPF initialization error: {}", msg)
165
1
        );
166
167
        // Test eBPF not supported error
168
1
        let msg = "Kernel too old";
169
1
        let err = DenetError::EbpfNotSupported(msg.to_string());
170
1
        assert_eq!(err.to_string(), format!("eBPF not supported: {}", msg));
171
172
        // Test other error
173
1
        let msg = "Generic error";
174
1
        let err = DenetError::Other(msg.to_string());
175
1
        assert_eq!(err.to_string(), format!("Error: {}", msg));
176
1
    }
177
178
    #[test]
179
1
    fn test_denet_error_source() {
180
1
        // Test IO error source
181
1
        let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
182
1
        let denet_err = DenetError::Io(io_err);
183
1
        assert!(denet_err.source().is_some());
184
185
        // Test system time error source
186
1
        let time_err = std::time::SystemTime::now()
187
1
            .duration_since(std::time::SystemTime::now() + std::time::Duration::from_secs(1))
188
1
            .unwrap_err();
189
1
        let denet_err = DenetError::SystemTime(time_err);
190
1
        assert!(denet_err.source().is_some());
191
192
        // Test serialization error source
193
1
        let json_err = serde_json::Error::io(io::Error::new(io::ErrorKind::Other, "JSON error"));
194
1
        let denet_err = DenetError::Serialization(json_err);
195
1
        assert!(denet_err.source().is_some());
196
197
        // Test errors without source
198
1
        assert!(DenetError::ProcessNotFound(123).source().is_none());
199
1
        assert!(DenetError::ProcessAccessDenied(456).source().is_none());
200
1
        assert!(DenetError::InvalidConfiguration("test".to_string())
201
1
            .source()
202
1
            .is_none());
203
1
        assert!(DenetError::PlatformNotSupported("test".to_string())
204
1
            .source()
205
1
            .is_none());
206
1
        assert!(DenetError::EbpfInitError("test".to_string())
207
1
            .source()
208
1
            .is_none());
209
1
        assert!(DenetError::EbpfNotSupported("test".to_string())
210
1
            .source()
211
1
            .is_none());
212
1
        assert!(DenetError::Other("test".to_string()).source().is_none());
213
1
    }
214
215
    #[test]
216
1
    fn test_error_conversions_from_std() {
217
1
        // Test From<io::Error>
218
1
        let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
219
1
        let denet_err: DenetError = io_err.into();
220
1
        match denet_err {
221
1
            DenetError::Io(_) => (),
222
0
            _ => panic!("Expected Io error variant"),
223
        }
224
225
        // Test From<SystemTimeError>
226
1
        let time_err = std::time::SystemTime::now()
227
1
            .duration_since(std::time::SystemTime::now() + std::time::Duration::from_secs(1))
228
1
            .unwrap_err();
229
1
        let denet_err: DenetError = time_err.into();
230
1
        match denet_err {
231
1
            DenetError::SystemTime(_) => (),
232
0
            _ => panic!("Expected SystemTime error variant"),
233
        }
234
235
        // Test From<serde_json::Error>
236
1
        let json_err = serde_json::Error::io(io::Error::new(io::ErrorKind::Other, "JSON error"));
237
1
        let denet_err: DenetError = json_err.into();
238
1
        match denet_err {
239
1
            DenetError::Serialization(_) => (),
240
0
            _ => panic!("Expected Serialization error variant"),
241
        }
242
1
    }
243
244
    #[test]
245
1
    fn test_error_conversion_to_io_error() {
246
1
        // Test From<DenetError> for io::Error - IO variant
247
1
        let original_io_err = io::Error::new(io::ErrorKind::NotFound, "original io error");
248
1
        let denet_err = DenetError::Io(original_io_err);
249
1
        let converted_io_err: io::Error = denet_err.into();
250
1
        assert!(converted_io_err.to_string().contains("original io error"));
251
252
        // Test From<DenetError> for io::Error - non-IO variant
253
1
        let original_err = DenetError::ProcessNotFound(123);
254
1
        let io_err: io::Error = original_err.into();
255
1
        assert!(io_err.to_string().contains("Process not found"));
256
1
    }
257
258
    #[test]
259
1
    fn test_result_type_alias() {
260
1
        // Test with success
261
1
        let result: Result<i32> = Ok(42);
262
1
        assert_eq!(result.unwrap(), 42);
263
264
        // Test with error
265
1
        let error_result: Result<i32> = Err(DenetError::Other("test error".to_string()));
266
1
        assert!(error_result.is_err());
267
1
        match error_result {
268
1
            Err(DenetError::Other(msg)) => assert_eq!(msg, "test error"),
269
0
            _ => panic!("Expected Other error variant"),
270
        }
271
1
    }
272
273
    #[test]
274
1
    fn test_denet_error_debug() {
275
1
        let err = DenetError::ProcessNotFound(123);
276
1
        let debug_str = format!("{:?}", err);
277
1
        assert!(debug_str.contains("ProcessNotFound"));
278
1
        assert!(debug_str.contains("123"));
279
1
    }
280
281
    #[cfg(feature = "python")]
282
    #[test]
283
    fn test_python_error_conversion() {
284
        use pyo3::exceptions::*;
285
        use pyo3::Python;
286
287
        Python::with_gil(|py| {
288
            // Test IO error conversion
289
            let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
290
            let denet_err = DenetError::Io(io_err);
291
            let py_err: pyo3::PyErr = denet_err.into();
292
            assert!(py_err.is_instance_of::<PyIOError>(py));
293
294
            // Test ProcessNotFound conversion
295
            let denet_err = DenetError::ProcessNotFound(123);
296
            let py_err: pyo3::PyErr = denet_err.into();
297
            assert!(py_err.is_instance_of::<PyRuntimeError>(py));
298
299
            // Test ProcessAccessDenied conversion
300
            let denet_err = DenetError::ProcessAccessDenied(123);
301
            let py_err: pyo3::PyErr = denet_err.into();
302
            assert!(py_err.is_instance_of::<PyPermissionError>(py));
303
304
            // Test InvalidConfiguration conversion
305
            let denet_err = DenetError::InvalidConfiguration("test".to_string());
306
            let py_err: pyo3::PyErr = denet_err.into();
307
            assert!(py_err.is_instance_of::<PyValueError>(py));
308
309
            // Test PlatformNotSupported conversion
310
            let denet_err = DenetError::PlatformNotSupported("test".to_string());
311
            let py_err: pyo3::PyErr = denet_err.into();
312
            assert!(py_err.is_instance_of::<PyNotImplementedError>(py));
313
314
            // Test EbpfInitError conversion
315
            let denet_err = DenetError::EbpfInitError("test".to_string());
316
            let py_err: pyo3::PyErr = denet_err.into();
317
            assert!(py_err.is_instance_of::<PyRuntimeError>(py));
318
319
            // Test EbpfNotSupported conversion
320
            let denet_err = DenetError::EbpfNotSupported("test".to_string());
321
            let py_err: pyo3::PyErr = denet_err.into();
322
            assert!(py_err.is_instance_of::<PyNotImplementedError>(py));
323
324
            // Test Other error conversion (fallback)
325
            let denet_err = DenetError::Other("test".to_string());
326
            let py_err: pyo3::PyErr = denet_err.into();
327
            assert!(py_err.is_instance_of::<PyRuntimeError>(py));
328
329
            // Test SystemTime error conversion (fallback)
330
            let time_err = std::time::SystemTime::now()
331
                .duration_since(std::time::SystemTime::now() + std::time::Duration::from_secs(1))
332
                .unwrap_err();
333
            let denet_err = DenetError::SystemTime(time_err);
334
            let py_err: pyo3::PyErr = denet_err.into();
335
            assert!(py_err.is_instance_of::<PyRuntimeError>(py));
336
337
            // Test Serialization error conversion (fallback)
338
            let json_err =
339
                serde_json::Error::io(io::Error::new(io::ErrorKind::Other, "JSON error"));
340
            let denet_err = DenetError::Serialization(json_err);
341
            let py_err: pyo3::PyErr = denet_err.into();
342
            assert!(py_err.is_instance_of::<PyRuntimeError>(py));
343
        });
344
    }
345
}