Skip to main content

dendryform_parse/
error.rs

1//! Parse error types.
2
3use std::fmt;
4
5/// Errors that occur when parsing a diagram file.
6#[derive(Debug)]
7#[non_exhaustive]
8pub enum ParseError {
9    /// YAML deserialization failed.
10    Yaml(serde_yml::Error),
11    /// JSON deserialization failed.
12    Json(serde_json::Error),
13    /// File I/O failed.
14    Io(std::io::Error),
15    /// Post-deserialization validation failed.
16    Validation(dendryform_core::ValidationError),
17}
18
19impl fmt::Display for ParseError {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        match self {
22            Self::Yaml(e) => write!(f, "YAML parse error: {e}"),
23            Self::Json(e) => write!(f, "JSON parse error: {e}"),
24            Self::Io(e) => write!(f, "I/O error: {e}"),
25            Self::Validation(e) => write!(f, "validation error: {e}"),
26        }
27    }
28}
29
30impl std::error::Error for ParseError {
31    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
32        match self {
33            Self::Yaml(e) => Some(e),
34            Self::Json(e) => Some(e),
35            Self::Io(e) => Some(e),
36            Self::Validation(e) => Some(e),
37        }
38    }
39}
40
41impl From<serde_yml::Error> for ParseError {
42    fn from(e: serde_yml::Error) -> Self {
43        Self::Yaml(e)
44    }
45}
46
47impl From<serde_json::Error> for ParseError {
48    fn from(e: serde_json::Error) -> Self {
49        Self::Json(e)
50    }
51}
52
53impl From<std::io::Error> for ParseError {
54    fn from(e: std::io::Error) -> Self {
55        Self::Io(e)
56    }
57}
58
59impl From<dendryform_core::ValidationError> for ParseError {
60    fn from(e: dendryform_core::ValidationError) -> Self {
61        Self::Validation(e)
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use dendryform_core::ValidationError;
69
70    #[test]
71    fn test_display_yaml() {
72        let yaml_err: Result<serde_yml::Value, _> = serde_yml::from_str("[invalid yaml {");
73        let err = ParseError::Yaml(yaml_err.unwrap_err());
74        let msg = format!("{err}");
75        assert!(msg.contains("YAML parse error"));
76    }
77
78    #[test]
79    fn test_display_json() {
80        let json_err: Result<serde_json::Value, _> = serde_json::from_str("{invalid json");
81        let err = ParseError::Json(json_err.unwrap_err());
82        let msg = format!("{err}");
83        assert!(msg.contains("JSON parse error"));
84    }
85
86    #[test]
87    fn test_display_io() {
88        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
89        let err = ParseError::Io(io_err);
90        let msg = format!("{err}");
91        assert!(msg.contains("I/O error"));
92    }
93
94    #[test]
95    fn test_display_validation() {
96        let inner = ValidationError::MissingField { field: "title" };
97        let err = ParseError::Validation(inner);
98        let msg = format!("{err}");
99        assert!(msg.contains("validation error"));
100        assert!(msg.contains("title"));
101    }
102
103    #[test]
104    fn test_source_yaml() {
105        let yaml_err: Result<serde_yml::Value, _> = serde_yml::from_str("[bad {");
106        let err = ParseError::Yaml(yaml_err.unwrap_err());
107        assert!(std::error::Error::source(&err).is_some());
108    }
109
110    #[test]
111    fn test_source_json() {
112        let json_err: Result<serde_json::Value, _> = serde_json::from_str("{bad");
113        let err = ParseError::Json(json_err.unwrap_err());
114        assert!(std::error::Error::source(&err).is_some());
115    }
116
117    #[test]
118    fn test_source_io() {
119        let io_err = std::io::Error::new(std::io::ErrorKind::Other, "test");
120        let err = ParseError::Io(io_err);
121        assert!(std::error::Error::source(&err).is_some());
122    }
123
124    #[test]
125    fn test_source_validation() {
126        let inner = ValidationError::MissingField { field: "id" };
127        let err = ParseError::Validation(inner);
128        assert!(std::error::Error::source(&err).is_some());
129    }
130
131    #[test]
132    fn test_from_yaml_error() {
133        let yaml_err: Result<serde_yml::Value, _> = serde_yml::from_str("[bad {");
134        let inner = yaml_err.unwrap_err();
135        let err: ParseError = inner.into();
136        assert!(matches!(err, ParseError::Yaml(_)));
137    }
138
139    #[test]
140    fn test_from_json_error() {
141        let json_err: Result<serde_json::Value, _> = serde_json::from_str("{bad");
142        let inner = json_err.unwrap_err();
143        let err: ParseError = inner.into();
144        assert!(matches!(err, ParseError::Json(_)));
145    }
146
147    #[test]
148    fn test_from_io_error() {
149        let inner = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "denied");
150        let err: ParseError = inner.into();
151        assert!(matches!(err, ParseError::Io(_)));
152    }
153
154    #[test]
155    fn test_from_validation_error() {
156        let inner = ValidationError::EmptyTier { id: "t".to_owned() };
157        let err: ParseError = inner.into();
158        assert!(matches!(err, ParseError::Validation(_)));
159    }
160
161    #[test]
162    fn test_debug_format() {
163        let err = ParseError::Validation(ValidationError::MissingField { field: "id" });
164        let debug = format!("{err:?}");
165        assert!(debug.contains("Validation"));
166    }
167}