serde_valid/validation/object/
max_properties.rs

1use crate::{traits::Size, MaxPropertiesError};
2
3/// Max size validation of the object properties.
4///
5/// See <https://json-schema.org/understanding-json-schema/reference/object.html#size>
6///
7/// ```rust
8/// use std::collections::HashMap;
9///
10/// use serde_json::json;
11/// use serde_valid::{Validate, ValidateMaxProperties};
12///
13/// struct MyType(HashMap<String, String>);
14///
15/// impl ValidateMaxProperties for MyType {
16///     fn validate_max_properties(
17///         &self,
18///         max_properties: usize,
19///     ) -> Result<(), serde_valid::MaxPropertiesError> {
20///         self.0.validate_max_properties(max_properties)
21///     }
22/// }
23///
24/// #[derive(Validate)]
25/// struct TestStruct {
26///     #[validate(max_properties = 2)]
27///     val: MyType,
28/// }
29///
30/// let mut map = HashMap::new();
31/// map.insert("key1".to_string(), "value1".to_string());
32/// map.insert("key2".to_string(), "value2".to_string());
33/// map.insert("key3".to_string(), "value3".to_string());
34///
35/// let s = TestStruct { val: MyType(map) };
36///
37/// assert_eq!(
38///     s.validate().unwrap_err().to_string(),
39///     json!({
40///         "errors": [],
41///         "properties": {
42///             "val": {
43///                 "errors": ["The size of the properties must be `<= 2`."]
44///             }
45///         }
46///     })
47///     .to_string()
48/// );
49/// ```
50pub trait ValidateMaxProperties {
51    fn validate_max_properties(&self, max_properties: usize) -> Result<(), MaxPropertiesError>;
52}
53
54impl<T> ValidateMaxProperties for T
55where
56    T: Size,
57{
58    fn validate_max_properties(&self, max_properties: usize) -> Result<(), MaxPropertiesError> {
59        if max_properties >= self.size() {
60            Ok(())
61        } else {
62            Err(MaxPropertiesError::new(max_properties))
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use serde_json::json;
71    use std::collections::BTreeMap;
72    use std::collections::HashMap;
73
74    #[test]
75    fn test_validate_object_max_properties_hash_map_type() {
76        let mut map = HashMap::new();
77        map.insert("key1".to_string(), "value1".to_string());
78        map.insert("key2".to_string(), "value2".to_string());
79        map.insert("key3".to_string(), "value3".to_string());
80        assert!(ValidateMaxProperties::validate_max_properties(&map, 3).is_ok());
81    }
82
83    #[test]
84    fn test_validate_object_max_properties_btree_map_type() {
85        let mut map = BTreeMap::new();
86        map.insert("key1".to_string(), "value1".to_string());
87        map.insert("key2".to_string(), "value2".to_string());
88        map.insert("key3".to_string(), "value3".to_string());
89        assert!(ValidateMaxProperties::validate_max_properties(&map, 3).is_ok());
90    }
91
92    #[test]
93    fn test_validate_object_max_properties_json_map_type() {
94        let value = json!({
95            "key1": "value1",
96            "key2": "value2",
97            "key3": "value3",
98        });
99        let map = value.as_object().unwrap();
100
101        assert!(ValidateMaxProperties::validate_max_properties(map, 4).is_ok());
102        assert!(ValidateMaxProperties::validate_max_properties(map, 3).is_ok());
103    }
104
105    #[test]
106    fn test_validate_object_max_properties_is_false() {
107        let value = json!({
108            "key1": "value1",
109            "key2": "value2",
110            "key3": "value3",
111        });
112        let map = value.as_object().unwrap();
113
114        assert!(ValidateMaxProperties::validate_max_properties(map, 2).is_err());
115    }
116}