yaml_schema/validation/
one_of.rs1use log::{debug, error};
2
3use super::Validator;
4
5use crate::Context;
6use crate::Error;
7use crate::Result;
8use crate::YamlSchema;
9impl Validator for crate::schemas::OneOfSchema {
10 fn validate(&self, context: &Context, value: &saphyr::MarkedYaml) -> Result<()> {
11 let one_of_is_valid = validate_one_of(context, &self.one_of, value)?;
12 if !one_of_is_valid {
13 error!("OneOf: None of the schemas in `oneOf` matched!");
14 context.add_error(value, "None of the schemas in `oneOf` matched!");
15 fail_fast!(context);
16 }
17 Ok(())
18 }
19}
20
21pub fn validate_one_of(
22 context: &Context,
23 schemas: &Vec<YamlSchema>,
24 value: &saphyr::MarkedYaml,
25) -> Result<bool> {
26 let mut one_of_is_valid = false;
27 for schema in schemas {
28 debug!(
29 "[OneOf] Validating value: {:?} against schema: {}",
30 &value.data, schema
31 );
32 let sub_context = context.get_sub_context();
33 let sub_result = schema.validate(&sub_context, value);
34 match sub_result {
35 Ok(()) | Err(Error::FailFast) => {
36 debug!(
37 "[OneOf] sub_context.errors: {}",
38 sub_context.errors.borrow().len()
39 );
40 if sub_context.has_errors() {
41 continue;
42 }
43
44 if one_of_is_valid {
45 error!("[OneOf] Value matched multiple schemas in `oneOf`!");
46 context.add_error(value, "Value matched multiple schemas in `oneOf`!");
47 fail_fast!(context);
48 } else {
49 one_of_is_valid = true;
50 }
51 }
52 Err(e) => return Err(e),
53 }
54 }
55 debug!("OneOf: one_of_is_valid: {one_of_is_valid}");
56 Ok(one_of_is_valid)
57}
58
59#[cfg(test)]
60mod tests {
61 use crate::RootSchema;
62 use crate::Schema;
63 use saphyr::LoadableYamlNode;
64
65 #[test]
66 fn test_validate_one_of_with_array_of_schemas() {
67 let root_schema = RootSchema::load_from_str(
68 r##"
69 $defs:
70 schema:
71 type: object
72 properties:
73 type:
74 enum: [string, object, number, integer, boolean, enum, array, oneOf, anyOf, not]
75 array_of_schemas:
76 type: array
77 items:
78 $ref: "#/$defs/schema"
79 oneOf:
80 - type: boolean
81 - $ref: "#/$defs/array_of_schemas"
82 "##,
83 )
84 .unwrap();
85 println!("root_schema: {root_schema:#?}");
86 let root_schema_schema = root_schema.schema.as_ref().schema.as_ref().unwrap();
87 if let Schema::OneOf(one_of_schema) = root_schema_schema {
88 println!("one_of_schema: {one_of_schema:#?}");
89 } else {
90 panic!("Expected Schema::OneOf, but got: {root_schema_schema:?}");
91 }
92
93 let s = r#"
94 false
95 "#;
96 let docs = saphyr::MarkedYaml::load_from_str(s).unwrap();
97 let value = docs.first().unwrap();
98 let context = crate::Context::with_root_schema(&root_schema, false);
99 let result = root_schema.validate(&context, value);
100 println!("result: {result:#?}");
101 assert!(result.is_ok());
102 for error in context.errors.borrow().iter() {
103 println!("error: {error:#?}");
104 }
105 assert!(!context.has_errors());
106 }
107}