valico/json_schema/keywords/
contains.rs1use serde_json::Value;
2
3use crate::json_schema::SchemaVersion;
4
5use super::super::helpers;
6use super::super::schema;
7use super::super::validators;
8
9#[allow(missing_copy_implementations)]
10pub struct Contains;
11impl super::Keyword for Contains {
12 fn compile(&self, def: &Value, ctx: &schema::WalkContext) -> super::KeywordResult {
13 let contains = keyword_key_exists!(def, "contains");
14 let (max_contains, min_contains) = if ctx.version >= SchemaVersion::Draft2019_09 {
15 let max_contains = def
16 .get("maxContains")
17 .map(|v| {
18 v.as_u64().ok_or_else(|| schema::SchemaError::Malformed {
19 path: ctx.fragment.join("/"),
20 detail: "The value of maxContains MUST be a non-negative integer"
21 .to_string(),
22 })
23 })
24 .transpose()?;
25 let min_contains = def
26 .get("minContains")
27 .map(|v| {
28 v.as_u64().ok_or_else(|| schema::SchemaError::Malformed {
29 path: ctx.fragment.join("/"),
30 detail: "The value of minContains MUST be a non-negative integer"
31 .to_string(),
32 })
33 })
34 .transpose()?;
35 (max_contains, min_contains)
36 } else {
37 (None, None)
38 };
39
40 if contains.is_object() || contains.is_boolean() {
41 Ok(Some(Box::new(validators::Contains {
42 url: helpers::alter_fragment_path(
43 ctx.url.clone(),
44 [ctx.escaped_fragment().as_ref(), "contains"].join("/"),
45 ),
46 max_contains,
47 min_contains,
48 })))
49 } else {
50 Err(schema::SchemaError::Malformed {
51 path: ctx.fragment.join("/"),
52 detail: "The value of contains MUST be an object or a boolean".to_string(),
53 })
54 }
55 }
56}
57
58#[cfg(test)]
59pub mod tests {
60 use crate::json_schema::scope;
61 use serde_json::Value;
62
63 fn schema() -> Value {
64 json!({
65 "contains": {
66 "properties": {
67 "x": {
68 "type": "string",
69 "default": "buh"
70 },
71 }
72 }
73 })
74 }
75
76 #[test]
77 fn no_default_for_schema() {
78 let mut scope = scope::Scope::new().supply_defaults();
79 let schema = scope.compile_and_return(schema(), true).unwrap();
80 assert_eq!(schema.get_default(), None);
81 }
82
83 #[test]
84 fn default_for_first() {
85 let mut scope = scope::Scope::new().supply_defaults();
86 let schema = scope.compile_and_return(schema(), true).unwrap();
87 let result = schema.validate(&json!([{}, {}]));
88 assert!(result.is_strictly_valid());
89 assert_eq!(result.replacement, Some(json!([{"x": "buh"}, {}])));
90 }
91
92 #[test]
93 fn no_default_when_not_needed() {
94 let mut scope = scope::Scope::new().supply_defaults();
95 let schema = scope.compile_and_return(schema(), true).unwrap();
96 let result = schema.validate(&json!([{"x": "y"}, {}]));
97 assert!(result.is_strictly_valid());
98 assert_eq!(result.replacement, None);
99 }
100}