sdf_metadata/util/
validate.rs1use 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}