yaml_schema/schemas/
all_of.rs1use log::debug;
2
3use saphyr::AnnotatedMapping;
4use saphyr::MarkedYaml;
5use saphyr::YamlData;
6
7use crate::Context;
8use crate::Error;
9use crate::Result;
10use crate::Validator;
11use crate::YamlSchema;
12use crate::loader;
13use crate::utils::format_vec;
14
15#[derive(Debug, Default, PartialEq)]
19pub struct AllOfSchema {
20 pub all_of: Vec<YamlSchema>,
21}
22
23impl std::fmt::Display for AllOfSchema {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 write!(f, "allOf:{}", format_vec(&self.all_of))
26 }
27}
28
29impl<'r> TryFrom<&MarkedYaml<'r>> for AllOfSchema {
30 type Error = crate::Error;
31
32 fn try_from(value: &MarkedYaml<'r>) -> Result<Self> {
33 if let YamlData::Mapping(mapping) = &value.data {
34 AllOfSchema::try_from(mapping)
35 } else {
36 Err(expected_mapping!(value))
37 }
38 }
39}
40
41impl<'r> TryFrom<&AnnotatedMapping<'r, MarkedYaml<'r>>> for AllOfSchema {
42 type Error = crate::Error;
43
44 fn try_from(mapping: &AnnotatedMapping<'r, MarkedYaml<'r>>) -> crate::Result<Self> {
45 let all_of = match mapping.get(&MarkedYaml::value_from_str("allOf")) {
46 Some(value) => loader::load_array_of_schemas_marked(value)?,
47 None => {
48 debug!("[allOf] No `allOf` key found!");
49 Vec::new()
50 }
51 };
52 Ok(AllOfSchema { all_of })
53 }
54}
55
56impl Validator for AllOfSchema {
57 fn validate(&self, context: &Context, value: &saphyr::MarkedYaml) -> Result<()> {
58 let all_of_is_valid = validate_all_of(&self.all_of, context, value)?;
59 debug!("[AllOf#validate] all_of_is_valid: {all_of_is_valid}");
60 if !all_of_is_valid {
61 debug!("[AllOf#validate] Not all of the schemas in `allOf` matched!");
62 context.add_error(value, "Not all of the schemas in `allOf` matched!");
63 fail_fast!(context);
64 }
65 Ok(())
66 }
67}
68
69pub fn validate_all_of(
70 schemas: &[YamlSchema],
71 context: &Context,
72 value: &saphyr::MarkedYaml,
73) -> Result<bool> {
74 for schema in schemas {
75 debug!("[AllOf#validate_all_of] Validating value: {value:?} against schema: {schema:?}");
76 let sub_context = context.get_sub_context();
78 let sub_result = schema.validate(&sub_context, value);
79 match sub_result {
80 Ok(()) => {
81 debug!("[AllOf#validate_all_of] schema {schema:?} validated");
82 debug!(
83 "[AllOf#validate_all_of] sub_context.has_errors(): {}",
84 sub_context.has_errors()
85 );
86 if sub_context.has_errors() {
87 return Ok(false);
88 }
89 }
90 Err(Error::FailFast) => return Ok(false),
91 Err(e) => return Err(e),
92 }
93 }
94 Ok(true)
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::schemas::StringSchema;
102 use saphyr::LoadableYamlNode;
103
104 fn create_test_schema() -> AllOfSchema {
105 AllOfSchema {
106 all_of: vec![
107 StringSchema::builder().min_length(1).build().into(),
108 StringSchema::builder().max_length(5).build().into(),
109 ],
110 }
111 }
112
113 #[test]
114 fn test_validate_all_of() {
115 let schema = create_test_schema();
116 let context = Context::default();
117 let docs = MarkedYaml::load_from_str("valid").unwrap();
118 let value = docs.first().unwrap();
119
120 let result = schema.validate(&context, value);
121
122 assert!(result.is_ok());
123 assert!(!context.has_errors());
124 }
125
126 #[test]
127 fn test_validate_all_of_invalid() {
128 let schema = create_test_schema();
129 let context = Context::default();
130 let docs = MarkedYaml::load_from_str("too long").unwrap();
131 let value = docs.first().unwrap();
132
133 let result = schema.validate(&context, value);
134
135 assert!(result.is_ok());
136 assert!(context.has_errors());
137 let errors = context.errors.borrow();
138 let error = errors.first().unwrap();
139 assert_eq!("Not all of the schemas in `allOf` matched!", error.error);
140 }
141}