valico/json_schema/keywords/
dependencies.rs

1use serde_json::{Value};
2use std::collections;
3
4use super::super::schema;
5use super::super::validators;
6use super::super::helpers;
7
8#[allow(missing_copy_implementations)]
9pub struct Dependencies;
10impl super::Keyword for Dependencies {
11    fn compile(&self, def: &Value, ctx: &schema::WalkContext) -> super::KeywordResult {
12        let deps = keyword_key_exists!(def, "dependencies");
13
14        if !deps.is_object() {
15            return Err(schema::SchemaError::Malformed {
16                path: ctx.fragment.join("/"),
17                detail: "The value of this keyword MUST be an object.".to_string()
18            })
19        }
20
21        let deps = deps.as_object().unwrap();
22        let mut items = collections::HashMap::new();
23
24        for (key, item) in deps.iter() {
25            if item.is_object() {
26
27                items.insert(key.clone(), validators::dependencies::DepKind::Schema(
28                    helpers::alter_fragment_path(ctx.url.clone(), [
29                        ctx.escaped_fragment().as_ref(),
30                        "dependencies",
31                        helpers::encode(key).as_ref()
32                    ].join("/"))
33                ));
34
35            } else if item.is_array() {
36
37                let item = item.as_array().unwrap();
38
39                if item.len() == 0 {
40                    return Err(schema::SchemaError::Malformed {
41                        path: ctx.fragment.join("/"),
42                        detail: "If the value is an array, it MUST have at least one element.".to_string()
43                    })
44                }
45
46                let mut keys = vec![];
47
48                for key in item.iter() {
49                    if key.is_string() {
50                        keys.push(key.as_str().unwrap().to_string())
51                    } else {
52                        return Err(schema::SchemaError::Malformed {
53                            path: ctx.fragment.join("/"),
54                            detail: "Each element MUST be a string, and elements in the array MUST be unique.".to_string()
55                        })
56                    }
57                }
58
59                items.insert(key.clone(), validators::dependencies::DepKind::Property(
60                    keys
61                ));
62
63            } else {
64                return Err(schema::SchemaError::Malformed {
65                    path: ctx.fragment.join("/"),
66                    detail: "Each value of this object MUST be either an object or an array.".to_string()
67                })
68            }
69        }
70
71        Ok(Some(Box::new(validators::Dependencies {
72            items: items
73        })))
74
75    }
76}
77
78#[cfg(test)] use super::super::scope;
79#[cfg(test)] use super::super::builder;
80#[cfg(test)] use jsonway;
81
82#[test]
83fn validate_dependencies() {
84    let mut scope = scope::Scope::new();
85    let schema = scope.compile_and_return(builder::schema(|s| {
86        s.dependencies(|deps| {
87            deps.schema("isbn", |isbn| {
88                isbn.required(vec!["price".to_string()]);
89                isbn.properties(|props| {
90                    props.insert("price", |price| {
91                        price.multiple_of(5f64);
92                    })
93                })
94            });
95            deps.property("item_id", vec!["item_name".to_string()]);
96        });
97    }).into_json(), true).ok().unwrap();
98
99    assert_eq!(schema.validate(&jsonway::object(|obj| {
100        obj.set("isbn", "some_isbn".to_string());
101    }).unwrap()).is_valid(), false);
102
103    assert_eq!(schema.validate(&jsonway::object(|obj| {
104        obj.set("isbn", "some_isbn".to_string());
105        obj.set("price", 773);
106    }).unwrap()).is_valid(), false);
107
108    assert_eq!(schema.validate(&jsonway::object(|obj| {
109        obj.set("isbn", "some_isbn".to_string());
110        obj.set("price", 775);
111    }).unwrap()).is_valid(), true);
112
113    assert_eq!(schema.validate(&jsonway::object(|obj| {
114        obj.set("item_id", "some_id".to_string());
115    }).unwrap()).is_valid(), false);
116
117    assert_eq!(schema.validate(&jsonway::object(|obj| {
118        obj.set("item_id", "some_id".to_string());
119        obj.set("item_name", "some_name".to_string());
120    }).unwrap()).is_valid(), true);
121
122}
123
124#[test]
125fn malformed() {
126    let mut scope = scope::Scope::new();
127
128    assert!(scope.compile_and_return(jsonway::object(|schema| {
129        schema.object("dependencies", |deps| {
130            deps.set("isbn", 10);
131        });
132    }).unwrap(), true).is_err());
133
134    assert!(scope.compile_and_return(jsonway::object(|schema| {
135        schema.object("dependencies", |deps| {
136            deps.array("item_id", |item_id| {
137                item_id.push(10)
138            });
139        });
140    }).unwrap(), true).is_err());
141}