Skip to main content

trueno/
error.rs

1//! Error types for Trueno operations
2
3use thiserror::Error;
4
5use crate::Backend;
6
7/// Result type for Trueno operations
8pub type Result<T> = std::result::Result<T, TruenoError>;
9
10/// Errors that can occur during Trueno operations
11#[derive(Debug, Clone, Error, PartialEq, Eq)]
12pub enum TruenoError {
13    /// Backend not supported on this platform
14    #[error("Backend not supported on this platform: {0:?}")]
15    UnsupportedBackend(Backend),
16
17    /// Size mismatch between operands
18    #[error("Size mismatch: expected {expected}, got {actual}")]
19    SizeMismatch {
20        /// Expected size
21        expected: usize,
22        /// Actual size
23        actual: usize,
24    },
25
26    /// GPU error
27    #[error("GPU error: {0}")]
28    GpuError(String),
29
30    /// Invalid input
31    #[error("Invalid input: {0}")]
32    InvalidInput(String),
33
34    /// Division by zero (e.g., normalizing zero vector)
35    #[error("Division by zero")]
36    DivisionByZero,
37
38    /// Empty vector (e.g., computing mean of empty vector)
39    #[error("Empty vector")]
40    EmptyVector,
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_unsupported_backend_error() {
49        let err = TruenoError::UnsupportedBackend(Backend::AVX512);
50        assert_eq!(err.to_string(), "Backend not supported on this platform: AVX512");
51    }
52
53    #[test]
54    fn test_size_mismatch_error() {
55        let err = TruenoError::SizeMismatch { expected: 10, actual: 5 };
56        assert_eq!(err.to_string(), "Size mismatch: expected 10, got 5");
57    }
58
59    #[test]
60    fn test_gpu_error() {
61        let err = TruenoError::GpuError("Device not found".to_string());
62        assert_eq!(err.to_string(), "GPU error: Device not found");
63    }
64
65    #[test]
66    fn test_invalid_input_error() {
67        let err = TruenoError::InvalidInput("Empty vector".to_string());
68        assert_eq!(err.to_string(), "Invalid input: Empty vector");
69    }
70
71    #[test]
72    fn test_error_equality() {
73        let err1 = TruenoError::SizeMismatch { expected: 10, actual: 5 };
74        let err2 = TruenoError::SizeMismatch { expected: 10, actual: 5 };
75        assert_eq!(err1, err2);
76    }
77
78    #[test]
79    fn test_division_by_zero_error() {
80        let err = TruenoError::DivisionByZero;
81        assert_eq!(err.to_string(), "Division by zero");
82    }
83
84    #[test]
85    fn test_empty_vector_error() {
86        let err = TruenoError::EmptyVector;
87        assert_eq!(err.to_string(), "Empty vector");
88    }
89
90    // =========================================================================
91    // Debug trait coverage
92    // =========================================================================
93
94    #[test]
95    fn test_error_debug_unsupported_backend() {
96        let err = TruenoError::UnsupportedBackend(Backend::AVX512);
97        let debug = format!("{:?}", err);
98        assert!(debug.contains("UnsupportedBackend"));
99        assert!(debug.contains("AVX512"));
100    }
101
102    #[test]
103    fn test_error_debug_size_mismatch() {
104        let err = TruenoError::SizeMismatch { expected: 100, actual: 50 };
105        let debug = format!("{:?}", err);
106        assert!(debug.contains("SizeMismatch"));
107        assert!(debug.contains("100"));
108        assert!(debug.contains("50"));
109    }
110
111    #[test]
112    fn test_error_debug_gpu_error() {
113        let err = TruenoError::GpuError("out of memory".to_string());
114        let debug = format!("{:?}", err);
115        assert!(debug.contains("GpuError"));
116        assert!(debug.contains("out of memory"));
117    }
118
119    #[test]
120    fn test_error_debug_invalid_input() {
121        let err = TruenoError::InvalidInput("negative dimension".to_string());
122        let debug = format!("{:?}", err);
123        assert!(debug.contains("InvalidInput"));
124        assert!(debug.contains("negative dimension"));
125    }
126
127    #[test]
128    fn test_error_debug_division_by_zero() {
129        let err = TruenoError::DivisionByZero;
130        let debug = format!("{:?}", err);
131        assert!(debug.contains("DivisionByZero"));
132    }
133
134    #[test]
135    fn test_error_debug_empty_vector() {
136        let err = TruenoError::EmptyVector;
137        let debug = format!("{:?}", err);
138        assert!(debug.contains("EmptyVector"));
139    }
140
141    // =========================================================================
142    // Error inequality (PartialEq, Eq)
143    // =========================================================================
144
145    #[test]
146    fn test_error_inequality_different_variants() {
147        let err1 = TruenoError::DivisionByZero;
148        let err2 = TruenoError::EmptyVector;
149        assert_ne!(err1, err2);
150    }
151
152    #[test]
153    fn test_error_inequality_different_values() {
154        let err1 = TruenoError::SizeMismatch { expected: 10, actual: 5 };
155        let err2 = TruenoError::SizeMismatch { expected: 20, actual: 5 };
156        assert_ne!(err1, err2);
157    }
158
159    #[test]
160    fn test_error_equality_gpu_errors() {
161        let err1 = TruenoError::GpuError("same".to_string());
162        let err2 = TruenoError::GpuError("same".to_string());
163        assert_eq!(err1, err2);
164    }
165
166    #[test]
167    fn test_error_inequality_gpu_errors() {
168        let err1 = TruenoError::GpuError("err a".to_string());
169        let err2 = TruenoError::GpuError("err b".to_string());
170        assert_ne!(err1, err2);
171    }
172
173    #[test]
174    fn test_error_equality_invalid_input() {
175        let err1 = TruenoError::InvalidInput("test".to_string());
176        let err2 = TruenoError::InvalidInput("test".to_string());
177        assert_eq!(err1, err2);
178    }
179
180    #[test]
181    fn test_error_inequality_invalid_input() {
182        let err1 = TruenoError::InvalidInput("a".to_string());
183        let err2 = TruenoError::InvalidInput("b".to_string());
184        assert_ne!(err1, err2);
185    }
186
187    // =========================================================================
188    // Display formatting for all variants (with varied content)
189    // =========================================================================
190
191    #[test]
192    fn test_unsupported_backend_all_backends() {
193        let backends = [
194            (Backend::Scalar, "Scalar"),
195            (Backend::SSE2, "SSE2"),
196            (Backend::AVX, "AVX"),
197            (Backend::AVX2, "AVX2"),
198            (Backend::AVX512, "AVX512"),
199            (Backend::NEON, "NEON"),
200            (Backend::WasmSIMD, "WasmSIMD"),
201            (Backend::GPU, "GPU"),
202            (Backend::Auto, "Auto"),
203        ];
204        for (backend, name) in backends {
205            let err = TruenoError::UnsupportedBackend(backend);
206            let msg = err.to_string();
207            assert!(msg.contains(name), "Expected '{}' in '{}'", name, msg);
208        }
209    }
210
211    #[test]
212    fn test_size_mismatch_various_values() {
213        let err = TruenoError::SizeMismatch { expected: 0, actual: 0 };
214        assert_eq!(err.to_string(), "Size mismatch: expected 0, got 0");
215
216        let err = TruenoError::SizeMismatch { expected: 1000000, actual: 999999 };
217        assert!(err.to_string().contains("1000000"));
218        assert!(err.to_string().contains("999999"));
219    }
220
221    #[test]
222    fn test_gpu_error_empty_message() {
223        let err = TruenoError::GpuError(String::new());
224        assert_eq!(err.to_string(), "GPU error: ");
225    }
226
227    #[test]
228    fn test_invalid_input_empty_message() {
229        let err = TruenoError::InvalidInput(String::new());
230        assert_eq!(err.to_string(), "Invalid input: ");
231    }
232
233    // =========================================================================
234    // std::error::Error trait coverage
235    // =========================================================================
236
237    #[test]
238    fn test_error_is_std_error() {
239        let err = TruenoError::DivisionByZero;
240        // Verify it implements std::error::Error
241        let _: &dyn std::error::Error = &err;
242    }
243
244    #[test]
245    fn test_error_source_is_none() {
246        use std::error::Error;
247        let err = TruenoError::DivisionByZero;
248        assert!(err.source().is_none());
249
250        let err = TruenoError::EmptyVector;
251        assert!(err.source().is_none());
252
253        let err = TruenoError::GpuError("test".to_string());
254        assert!(err.source().is_none());
255
256        let err = TruenoError::InvalidInput("test".to_string());
257        assert!(err.source().is_none());
258
259        let err = TruenoError::SizeMismatch { expected: 1, actual: 2 };
260        assert!(err.source().is_none());
261
262        let err = TruenoError::UnsupportedBackend(Backend::Scalar);
263        assert!(err.source().is_none());
264    }
265
266    // =========================================================================
267    // Result type alias coverage
268    // =========================================================================
269
270    #[test]
271    fn test_result_type_alias_ok() {
272        let result: Result<i32> = Ok(42);
273        assert!(result.is_ok());
274        assert_eq!(result, Ok(42));
275    }
276
277    #[test]
278    fn test_result_type_alias_err() {
279        let result: Result<i32> = Err(TruenoError::EmptyVector);
280        assert!(result.is_err());
281    }
282
283    // =========================================================================
284    // Clone / copy semantics
285    // =========================================================================
286
287    #[test]
288    fn test_error_clone_all_variants() {
289        let errors: Vec<TruenoError> = vec![
290            TruenoError::UnsupportedBackend(Backend::AVX512),
291            TruenoError::SizeMismatch { expected: 10, actual: 5 },
292            TruenoError::GpuError("test clone".to_string()),
293            TruenoError::InvalidInput("test clone".to_string()),
294            TruenoError::DivisionByZero,
295            TruenoError::EmptyVector,
296        ];
297
298        for err in &errors {
299            let cloned = err.clone();
300            assert_eq!(*err, cloned, "Clone mismatch for {:?}", err);
301        }
302    }
303}