Coverage Report

Created: 2026-01-25 15:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/realizar/src/error.rs
Line
Count
Source
1
//! Error types for Realizar
2
//!
3
//! This module defines all error types used throughout the library.
4
5
use thiserror::Error;
6
7
/// Result type alias for Realizar operations
8
pub type Result<T> = std::result::Result<T, RealizarError>;
9
10
/// Error type for all Realizar operations
11
#[derive(Error, Debug, Clone, PartialEq)]
12
pub enum RealizarError {
13
    /// Shape mismatch between tensors
14
    #[error("Shape mismatch: expected {expected:?}, got {actual:?}")]
15
    ShapeMismatch {
16
        /// Expected shape
17
        expected: Vec<usize>,
18
        /// Actual shape
19
        actual: Vec<usize>,
20
    },
21
22
    /// Invalid shape specification
23
    #[error("Invalid shape: {reason}")]
24
    InvalidShape {
25
        /// Reason for invalidity
26
        reason: String,
27
    },
28
29
    /// Data size does not match shape
30
    #[error("Data size {data_size} does not match shape {shape:?} (expected {expected})")]
31
    DataShapeMismatch {
32
        /// Actual data size
33
        data_size: usize,
34
        /// Specified shape
35
        shape: Vec<usize>,
36
        /// Expected size from shape
37
        expected: usize,
38
    },
39
40
    /// Invalid dimension for operation
41
    #[error("Invalid dimension {dim} for tensor with {ndim} dimensions")]
42
    InvalidDimension {
43
        /// Requested dimension
44
        dim: usize,
45
        /// Number of dimensions
46
        ndim: usize,
47
    },
48
49
    /// Matrix multiplication dimension mismatch
50
    #[error("Matrix multiplication dimension mismatch: ({m}×{k}) × ({k2}×{n})")]
51
    MatmulDimensionMismatch {
52
        /// Rows in first matrix
53
        m: usize,
54
        /// Columns in first matrix / rows in second matrix
55
        k: usize,
56
        /// Rows in second matrix (should equal k)
57
        k2: usize,
58
        /// Columns in second matrix
59
        n: usize,
60
    },
61
62
    /// Operation not supported for this tensor type
63
    #[error("Operation '{operation}' not supported: {reason}")]
64
    UnsupportedOperation {
65
        /// Operation name
66
        operation: String,
67
        /// Reason it's not supported
68
        reason: String,
69
    },
70
71
    /// Trueno backend error
72
    #[error("Trueno backend error: {0}")]
73
    TruenoError(String),
74
75
    /// Index out of bounds
76
    #[error("Index out of bounds: index {index} for dimension of size {size}")]
77
    IndexOutOfBounds {
78
        /// Requested index
79
        index: usize,
80
        /// Size of dimension
81
        size: usize,
82
    },
83
84
    /// Model registry error
85
    #[error("Model registry error: {0}")]
86
    RegistryError(String),
87
88
    /// Model not found in registry
89
    #[error("Model '{0}' not found")]
90
    ModelNotFound(String),
91
92
    /// Model already registered
93
    #[error("Model '{0}' already registered")]
94
    ModelAlreadyExists(String),
95
96
    /// MOE routing error
97
    #[error("MOE routing error: {0}")]
98
    MoeError(String),
99
100
    /// Expert capacity exceeded
101
    #[error("Expert {expert_id} capacity exceeded: {queue_depth}/{capacity}")]
102
    ExpertCapacityExceeded {
103
        /// Expert index
104
        expert_id: usize,
105
        /// Current queue depth
106
        queue_depth: usize,
107
        /// Maximum capacity
108
        capacity: usize,
109
    },
110
111
    /// Invalid URI format
112
    #[error("Invalid URI: {0}")]
113
    InvalidUri(String),
114
115
    /// File format error
116
    #[error("Format error: {reason}")]
117
    FormatError {
118
        /// Reason for format error
119
        reason: String,
120
    },
121
122
    /// IO error
123
    #[error("IO error: {message}")]
124
    IoError {
125
        /// Error message
126
        message: String,
127
    },
128
129
    /// Connection error (network/HTTP)
130
    #[error("Connection error: {0}")]
131
    ConnectionError(String),
132
133
    /// GPU compute error
134
    #[error("GPU error: {reason}")]
135
    GpuError {
136
        /// Reason for GPU error
137
        reason: String,
138
    },
139
140
    /// Invalid configuration error
141
    #[error("Invalid configuration: {0}")]
142
    InvalidConfiguration(String),
143
144
    /// Inference execution error
145
    #[error("Inference error: {0}")]
146
    InferenceError(String),
147
}
148
149
#[cfg(test)]
150
mod tests {
151
    use super::*;
152
153
    #[test]
154
1
    fn test_error_display() {
155
1
        let err = RealizarError::ShapeMismatch {
156
1
            expected: vec![3, 3],
157
1
            actual: vec![2, 2],
158
1
        };
159
1
        assert!(err.to_string().contains("Shape mismatch"));
160
1
    }
161
162
    #[test]
163
1
    fn test_error_equality() {
164
1
        let err1 = RealizarError::InvalidShape {
165
1
            reason: "Empty shape".to_string(),
166
1
        };
167
1
        let err2 = RealizarError::InvalidShape {
168
1
            reason: "Empty shape".to_string(),
169
1
        };
170
1
        assert_eq!(err1, err2);
171
1
    }
172
173
    // ========================================================================
174
    // Coverage Tests: All Error Variants
175
    // ========================================================================
176
177
    #[test]
178
1
    fn test_data_shape_mismatch_display() {
179
1
        let err = RealizarError::DataShapeMismatch {
180
1
            data_size: 10,
181
1
            shape: vec![2, 3],
182
1
            expected: 6,
183
1
        };
184
1
        let msg = err.to_string();
185
1
        assert!(msg.contains("10"));
186
1
        assert!(msg.contains("6"));
187
1
    }
188
189
    #[test]
190
1
    fn test_invalid_dimension_display() {
191
1
        let err = RealizarError::InvalidDimension { dim: 5, ndim: 3 };
192
1
        let msg = err.to_string();
193
1
        assert!(msg.contains("5"));
194
1
        assert!(msg.contains("3"));
195
1
    }
196
197
    #[test]
198
1
    fn test_matmul_dimension_mismatch_display() {
199
1
        let err = RealizarError::MatmulDimensionMismatch {
200
1
            m: 2,
201
1
            k: 3,
202
1
            k2: 4,
203
1
            n: 5,
204
1
        };
205
1
        let msg = err.to_string();
206
1
        assert!(msg.contains("2"));
207
1
        assert!(msg.contains("3"));
208
1
        assert!(msg.contains("4"));
209
1
        assert!(msg.contains("5"));
210
1
    }
211
212
    #[test]
213
1
    fn test_unsupported_operation_display() {
214
1
        let err = RealizarError::UnsupportedOperation {
215
1
            operation: "transpose".to_string(),
216
1
            reason: "not implemented".to_string(),
217
1
        };
218
1
        let msg = err.to_string();
219
1
        assert!(msg.contains("transpose"));
220
1
        assert!(msg.contains("not implemented"));
221
1
    }
222
223
    #[test]
224
1
    fn test_trueno_error_display() {
225
1
        let err = RealizarError::TruenoError("kernel failed".to_string());
226
1
        assert!(err.to_string().contains("kernel failed"));
227
1
    }
228
229
    #[test]
230
1
    fn test_index_out_of_bounds_display() {
231
1
        let err = RealizarError::IndexOutOfBounds { index: 10, size: 5 };
232
1
        let msg = err.to_string();
233
1
        assert!(msg.contains("10"));
234
1
        assert!(msg.contains("5"));
235
1
    }
236
237
    #[test]
238
1
    fn test_registry_error_display() {
239
1
        let err = RealizarError::RegistryError("lock failed".to_string());
240
1
        assert!(err.to_string().contains("lock failed"));
241
1
    }
242
243
    #[test]
244
1
    fn test_model_not_found_display() {
245
1
        let err = RealizarError::ModelNotFound("llama-7b".to_string());
246
1
        assert!(err.to_string().contains("llama-7b"));
247
1
    }
248
249
    #[test]
250
1
    fn test_model_already_exists_display() {
251
1
        let err = RealizarError::ModelAlreadyExists("phi-2".to_string());
252
1
        assert!(err.to_string().contains("phi-2"));
253
1
    }
254
255
    #[test]
256
1
    fn test_moe_error_display() {
257
1
        let err = RealizarError::MoeError("routing failed".to_string());
258
1
        assert!(err.to_string().contains("routing failed"));
259
1
    }
260
261
    #[test]
262
1
    fn test_expert_capacity_exceeded_display() {
263
1
        let err = RealizarError::ExpertCapacityExceeded {
264
1
            expert_id: 3,
265
1
            queue_depth: 10,
266
1
            capacity: 8,
267
1
        };
268
1
        let msg = err.to_string();
269
1
        assert!(msg.contains("3"));
270
1
        assert!(msg.contains("10"));
271
1
        assert!(msg.contains("8"));
272
1
    }
273
274
    #[test]
275
1
    fn test_invalid_uri_display() {
276
1
        let err = RealizarError::InvalidUri("bad://url".to_string());
277
1
        assert!(err.to_string().contains("bad://url"));
278
1
    }
279
280
    #[test]
281
1
    fn test_format_error_display() {
282
1
        let err = RealizarError::FormatError {
283
1
            reason: "invalid header".to_string(),
284
1
        };
285
1
        assert!(err.to_string().contains("invalid header"));
286
1
    }
287
288
    #[test]
289
1
    fn test_io_error_display() {
290
1
        let err = RealizarError::IoError {
291
1
            message: "file not found".to_string(),
292
1
        };
293
1
        assert!(err.to_string().contains("file not found"));
294
1
    }
295
296
    #[test]
297
1
    fn test_connection_error_display() {
298
1
        let err = RealizarError::ConnectionError("timeout".to_string());
299
1
        assert!(err.to_string().contains("timeout"));
300
1
    }
301
302
    #[test]
303
1
    fn test_gpu_error_display() {
304
1
        let err = RealizarError::GpuError {
305
1
            reason: "out of memory".to_string(),
306
1
        };
307
1
        assert!(err.to_string().contains("out of memory"));
308
1
    }
309
310
    #[test]
311
1
    fn test_invalid_configuration_display() {
312
1
        let err = RealizarError::InvalidConfiguration("missing field".to_string());
313
1
        assert!(err.to_string().contains("missing field"));
314
1
    }
315
316
    #[test]
317
1
    fn test_inference_error_display() {
318
1
        let err = RealizarError::InferenceError("model failed".to_string());
319
1
        assert!(err.to_string().contains("model failed"));
320
1
    }
321
322
    #[test]
323
1
    fn test_error_debug() {
324
1
        let err = RealizarError::ShapeMismatch {
325
1
            expected: vec![1, 2],
326
1
            actual: vec![3, 4],
327
1
        };
328
1
        let debug = format!("{:?}", err);
329
1
        assert!(debug.contains("ShapeMismatch"));
330
1
    }
331
332
    #[test]
333
1
    fn test_error_clone() {
334
1
        let err = RealizarError::InvalidShape {
335
1
            reason: "test".to_string(),
336
1
        };
337
1
        let cloned = err.clone();
338
1
        assert_eq!(err, cloned);
339
1
    }
340
}