Development Documentation (main branch) - For stable release docs, see docs.rs/eidetica

eidetica/entry/
errors.rs

1//! Entry-specific error types for the Eidetica library.
2//!
3//! This module defines structured error types for entry operations and validation,
4//! providing better error context and type safety.
5
6use thiserror::Error;
7
8/// Errors that can occur during entry operations.
9///
10/// # Stability
11///
12/// - New variants may be added in minor versions (enum is `#[non_exhaustive]`)
13/// - Existing variants will not be removed in minor versions
14/// - Field additions/changes require a major version bump
15/// - Helper methods like `is_*()` provide stable APIs
16#[non_exhaustive]
17#[derive(Debug, Error)]
18pub enum EntryError {
19    /// Entry validation failed during creation or processing
20    #[error("Entry validation failed: {reason}")]
21    ValidationFailed {
22        /// Reason why entry validation failed
23        reason: String,
24    },
25
26    /// Entry serialization failed
27    #[error("Entry serialization failed: {context}")]
28    SerializationFailed {
29        /// Context where serialization failed
30        context: String,
31    },
32
33    /// Entry structure is invalid
34    #[error("Invalid entry structure: {reason}")]
35    InvalidStructure {
36        /// Reason why the entry structure is invalid
37        reason: String,
38    },
39
40    /// Invalid _index subtree data during entry building
41    #[error("Invalid _index subtree data: {reason}")]
42    InvalidIndexData {
43        /// Reason why the _index data is invalid
44        reason: String,
45    },
46}
47
48impl EntryError {
49    /// Check if this error is validation-related.
50    pub fn is_validation_error(&self) -> bool {
51        matches!(
52            self,
53            EntryError::ValidationFailed { .. } | EntryError::InvalidStructure { .. }
54        )
55    }
56
57    /// Check if this error is serialization-related.
58    pub fn is_serialization_error(&self) -> bool {
59        matches!(self, EntryError::SerializationFailed { .. })
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use crate::entry::id::IdError;
67
68    #[test]
69    fn test_id_error_direct_conversion() {
70        let id_err = IdError::InvalidFormat("not hex".to_string());
71        let main_err: crate::Error = id_err.into();
72
73        assert!(main_err.is_id_error());
74        assert!(main_err.is_validation_error());
75        assert_eq!(main_err.module(), "id");
76    }
77
78    #[test]
79    fn test_unknown_algorithm_error() {
80        let id_err = IdError::UnknownAlgorithm("md5".to_string());
81        let main_err: crate::Error = id_err.into();
82
83        assert!(main_err.is_id_error());
84        assert!(main_err.is_validation_error());
85        assert_eq!(main_err.module(), "id");
86    }
87
88    #[test]
89    fn test_length_error() {
90        let id_err = IdError::InvalidLength {
91            expected: 64,
92            got: 32,
93        };
94        let main_err: crate::Error = id_err.into();
95
96        assert!(main_err.is_id_error());
97        assert!(main_err.is_validation_error());
98        assert_eq!(main_err.module(), "id");
99    }
100
101    #[test]
102    fn test_error_helpers() {
103        let err = EntryError::ValidationFailed {
104            reason: "test".to_string(),
105        };
106        assert!(err.is_validation_error());
107        assert!(!err.is_serialization_error());
108
109        let err = EntryError::SerializationFailed {
110            context: "test".to_string(),
111        };
112        assert!(!err.is_validation_error());
113        assert!(err.is_serialization_error());
114
115        let err = EntryError::InvalidStructure {
116            reason: "test".to_string(),
117        };
118        assert!(err.is_validation_error());
119        assert!(!err.is_serialization_error());
120    }
121
122    #[test]
123    fn test_error_conversion_to_main() {
124        let entry_err = EntryError::ValidationFailed {
125            reason: "test".to_string(),
126        };
127        let main_err: crate::Error = entry_err.into();
128
129        // Should convert to Entry error
130        assert!(main_err.is_entry_error());
131        assert!(!main_err.is_id_error());
132        assert!(main_err.is_validation_error());
133    }
134
135    #[test]
136    fn test_id_error_integration() {
137        use crate::entry::id::IdError;
138
139        // Test direct ID error conversion
140        let id_err = IdError::InvalidLength {
141            expected: 64,
142            got: 32,
143        };
144        let main_err: crate::Error = id_err.into();
145
146        assert!(!main_err.is_entry_error());
147        assert!(main_err.is_id_error());
148        assert!(main_err.is_validation_error());
149        assert_eq!(main_err.module(), "id");
150
151        // Test Blake3 algorithm error
152        let id_err = IdError::UnknownAlgorithm("md5".to_string());
153        let main_err: crate::Error = id_err.into();
154
155        assert!(!main_err.is_entry_error());
156        assert!(main_err.is_id_error());
157        assert!(main_err.is_validation_error());
158
159        // Verify the error message contains the expected information
160        let error_string = main_err.to_string();
161        assert!(error_string.contains("md5"));
162    }
163
164    #[test]
165    fn test_error_categorization_comprehensive() {
166        // Test that different types of errors are properly categorized
167        let id_errors = vec![
168            IdError::InvalidFormat("not hex".to_string()),
169            IdError::InvalidLength {
170                expected: 64,
171                got: 32,
172            },
173            IdError::UnknownAlgorithm("sha1".to_string()),
174            IdError::InvalidHex("contains G".to_string()),
175        ];
176
177        for id_err in id_errors {
178            let main_err: crate::Error = id_err.into();
179
180            // All ID errors should be validation errors
181            assert!(main_err.is_id_error());
182            assert!(main_err.is_validation_error());
183            assert!(!main_err.is_entry_error());
184            assert!(!main_err.is_entry_serialization_error());
185            assert!(!main_err.is_io_error());
186            assert_eq!(main_err.module(), "id");
187        }
188
189        // Test non-ID entry errors
190        let validation_err = EntryError::ValidationFailed {
191            reason: "test".to_string(),
192        };
193        let main_err: crate::Error = validation_err.into();
194        assert!(main_err.is_validation_error());
195        assert!(main_err.is_entry_error());
196        assert!(!main_err.is_id_error());
197
198        let serialization_err = EntryError::SerializationFailed {
199            context: "test".to_string(),
200        };
201        let main_err: crate::Error = serialization_err.into();
202        assert!(main_err.is_entry_serialization_error());
203        assert!(main_err.is_entry_error());
204        assert!(!main_err.is_validation_error());
205        assert!(!main_err.is_id_error());
206    }
207}