Skip to main content

dendryform_layout/
error.rs

1//! Layout error types.
2
3use std::fmt;
4
5/// Errors that occur during layout computation.
6#[derive(Debug)]
7#[non_exhaustive]
8pub enum LayoutError {
9    /// A core validation error propagated during layout.
10    Validation(dendryform_core::ValidationError),
11    /// A layout constraint could not be satisfied.
12    ConstraintViolation {
13        /// Description of the violated constraint.
14        message: String,
15    },
16}
17
18impl fmt::Display for LayoutError {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            Self::Validation(e) => write!(f, "validation error during layout: {e}"),
22            Self::ConstraintViolation { message } => write!(f, "layout constraint: {message}"),
23        }
24    }
25}
26
27impl std::error::Error for LayoutError {
28    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
29        match self {
30            Self::Validation(e) => Some(e),
31            Self::ConstraintViolation { .. } => None,
32        }
33    }
34}
35
36impl From<dendryform_core::ValidationError> for LayoutError {
37    fn from(e: dendryform_core::ValidationError) -> Self {
38        Self::Validation(e)
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use dendryform_core::ValidationError;
46
47    #[test]
48    fn test_layout_error_display_validation() {
49        let inner = ValidationError::MissingField { field: "id" };
50        let err = LayoutError::Validation(inner);
51        let msg = format!("{err}");
52        assert!(msg.contains("validation error during layout"));
53        assert!(msg.contains("id"));
54    }
55
56    #[test]
57    fn test_layout_error_display_constraint_violation() {
58        let err = LayoutError::ConstraintViolation {
59            message: "columns must be > 0".to_owned(),
60        };
61        let msg = format!("{err}");
62        assert!(msg.contains("layout constraint"));
63        assert!(msg.contains("columns must be > 0"));
64    }
65
66    #[test]
67    fn test_layout_error_debug() {
68        let err = LayoutError::ConstraintViolation {
69            message: "test".to_owned(),
70        };
71        let debug = format!("{err:?}");
72        assert!(debug.contains("ConstraintViolation"));
73    }
74
75    #[test]
76    fn test_layout_error_source_validation() {
77        let inner = ValidationError::MissingField { field: "id" };
78        let err = LayoutError::Validation(inner);
79        let source = std::error::Error::source(&err);
80        assert!(source.is_some());
81    }
82
83    #[test]
84    fn test_layout_error_source_constraint_is_none() {
85        let err = LayoutError::ConstraintViolation {
86            message: "test".to_owned(),
87        };
88        let source = std::error::Error::source(&err);
89        assert!(source.is_none());
90    }
91
92    #[test]
93    fn test_layout_error_from_validation_error() {
94        let inner = ValidationError::EmptyTier {
95            id: "t1".to_owned(),
96        };
97        let err: LayoutError = inner.into();
98        assert!(matches!(err, LayoutError::Validation(_)));
99    }
100}