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}