sdf_metadata/util/
validate.rs

1use crate::wit::metadata::MetadataType;
2
3use super::{
4    config_error::{ConfigError, INDENT},
5    sdf_types_map::SdfTypesMap,
6    validation_error::ValidationError,
7    validation_failure::ValidationFailure,
8};
9
10use crate::metadata::metadata::sdf_type::SdfTypeValidationError;
11
12pub(crate) trait SimpleValidate {
13    fn validate(&self) -> Result<(), ValidationError>;
14}
15
16pub(crate) fn validate_all<T: SimpleValidate>(items: &[T]) -> Result<(), ValidationFailure> {
17    let mut errors = ValidationFailure::new();
18
19    for item in items {
20        if let Err(state_error) = item.validate() {
21            errors.push(&state_error);
22        }
23    }
24
25    if errors.any() {
26        Err(errors)
27    } else {
28        Ok(())
29    }
30}
31
32#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
33pub struct MetadataTypeValidationFailure {
34    pub name: String,
35    pub errors: Vec<MetadataTypeValidationError>,
36}
37
38impl ConfigError for MetadataTypeValidationFailure {
39    fn readable(&self, indents: usize) -> String {
40        let indent = INDENT.repeat(indents);
41
42        let mut result = format!("{}Defined type `{}` is invalid:\n", indent, self.name);
43
44        for error in &self.errors {
45            result.push_str(&error.readable(indents + 1));
46        }
47
48        result
49    }
50}
51
52#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
53pub enum MetadataTypeValidationError {
54    EmptyName,
55    SdfType(SdfTypeValidationError),
56}
57
58impl ConfigError for MetadataTypeValidationError {
59    fn readable(&self, indents: usize) -> String {
60        let indent = INDENT.repeat(indents);
61
62        match self {
63            MetadataTypeValidationError::EmptyName => {
64                format!("{}Name cannot be empty\n", indent)
65            }
66            MetadataTypeValidationError::SdfType(error) => error.readable(indents),
67        }
68    }
69}
70
71impl MetadataType {
72    pub fn validate(&self, types_map: &SdfTypesMap) -> Result<(), MetadataTypeValidationFailure> {
73        let mut failure = MetadataTypeValidationFailure {
74            name: self.name.to_string(),
75            errors: vec![],
76        };
77
78        if self.name.is_empty() {
79            failure.errors.push(MetadataTypeValidationError::EmptyName);
80        }
81
82        if let Err(failures) = self.type_.validate(types_map) {
83            failure
84                .errors
85                .push(MetadataTypeValidationError::SdfType(failures));
86        }
87
88        if failure.errors.is_empty() {
89            Ok(())
90        } else {
91            Err(failure)
92        }
93    }
94}
95
96#[cfg(test)]
97mod test {
98    use crate::{
99        metadata::metadata::sdf_type::SdfTypeValidationError,
100        util::validate::MetadataTypeValidationError,
101        wit::{
102            io::TypeRef,
103            metadata::{MetadataType, SdfType, SdfTypeOrigin},
104        },
105    };
106
107    #[test]
108    fn test_validate() {
109        let type_ = MetadataType {
110            name: "my-type".to_string(),
111            type_: SdfType::Named(TypeRef {
112                name: "foobar".to_string(),
113            }),
114            origin: SdfTypeOrigin::Local,
115        };
116
117        let res = type_
118            .validate(&Default::default())
119            .expect_err("failed to validate");
120
121        assert!(res.errors.contains(&MetadataTypeValidationError::SdfType(
122            SdfTypeValidationError::InvalidRef("foobar".to_string())
123        )));
124    }
125
126    #[test]
127    fn test_validate_invalid_ref_state() {
128        let type_ = MetadataType {
129            name: "my-type".to_string(),
130            type_: SdfType::Named(TypeRef {
131                name: "arrow-row".to_string(),
132            }),
133            origin: SdfTypeOrigin::Local,
134        };
135
136        let res = type_
137            .validate(&Default::default())
138            .expect_err("failed to validate");
139
140        assert!(res.errors.contains(&MetadataTypeValidationError::SdfType(
141            SdfTypeValidationError::InvalidSyntax("arrow-row".to_string())
142        )));
143    }
144}