blackjack/
match_object.rs

1// Copyright 2024 Ole Kliemann
2// SPDX-License-Identifier: Apache-2.0
3
4use serde_json::Value;
5
6pub fn contains(input: &Value, compare: &Value) -> bool {
7    match (input, compare) {
8        (Value::Object(map_input), Value::Object(map_compare)) => {
9            for (key, val_compare) in map_compare {
10                match map_input.get(key) {
11                    Some(val_input) => {
12                        if !contains(val_input, val_compare) {
13                            return false;
14                        }
15                    }
16                    None => return false,
17                }
18            }
19            true
20        }
21        (Value::Array(arr_input), Value::Array(arr_compare)) => {
22            for val_compare in arr_compare {
23                let mut found = false;
24                for val_input in arr_input {
25                    if contains(val_input, val_compare) {
26                        found = true;
27                        break;
28                    }
29                }
30                if !found {
31                    return false;
32                }
33            }
34            true
35        }
36        _ => input == compare,
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43    use rstest::rstest;
44    use serde_json::json;
45
46    #[rstest]
47    #[case(
48        json!({"a": 1, "b": 2}),
49        json!({"a": 1}),
50        true
51    )]
52    #[case(
53        json!({"a": 1, "b": {"c": 3, "d": 4}}),
54        json!({"b": {"c": 3}}),
55        true
56    )]
57    #[case(
58        json!({"a": [1, 2, 3], "b": 4}),
59        json!({"a": [2]}),
60        true
61    )]
62    #[case(
63        json!({"a": [1, 2, 3], "b": 4}),
64        json!({"a": [4]}),
65        false
66    )]
67    #[case(
68        json!(["apple", "banana", "cherry"]),
69        json!(["banana"]),
70        true
71    )]
72    #[case(
73        json!(["apple", "banana", "cherry"]),
74        json!(["banana", "date"]),
75        false
76    )]
77    #[case(
78        json!(null),
79        json!(null),
80        true
81    )]
82    #[case(
83        json!(null),
84        json!(1),
85        false
86    )]
87    #[case(
88        json!(1),
89        json!(1),
90        true
91    )]
92    #[case(
93        json!(1),
94        json!(2),
95        false
96    )]
97    #[case(
98        json!({"a": {"b": {"c": 1}}}),
99        json!({"a": {"b": {"c": 1}}}),
100        true
101    )]
102    #[case(
103        json!({"a": {"b": {"c": 1, "d": 2}}}),
104        json!({"a": {"b": {"c": 1}}}),
105        true
106    )]
107    #[case(
108        json!({"a": {"b": {"c": 1}}}),
109        json!({"a": {"b": {"c": 2}}}),
110        false
111    )]
112    #[case(
113        json!({"a": [ {"b": 1}, {"b": 2}, {"b": 3} ]}),
114        json!({"a": [ {"b": 2} ]}),
115        true
116    )]
117    #[case(
118        json!({"a": [ {"b": 1}, {"b": 2}, {"b": 3} ]}),
119        json!({"a": [ {"b": 4} ]}),
120        false
121    )]
122    #[case(
123        json!({"a": {"b": [1, 2, 3]}}),
124        json!({"a": {"b": [2, 3]}}),
125        true
126    )]
127    #[case(
128        json!({"a": {"b": [1, 2, 3]}}),
129        json!({"a": {"b": [4]}}),
130        false
131    )]
132    #[case(
133        json!({"a": {"b": 1}}),
134        json!({"a": {"b": 2}}),
135        false
136    )]
137    #[case(
138        json!({"a": [ { "c": "foo", "b": false} ]}),
139        json!({"a": [ { "c": "foo", "b": true} ]}),
140        false
141    )]
142    #[case(
143        json!({"a": [ { "c": "foo", "b": true} ]}),
144        json!({"a": [ { "c": "foo", "b": true} ]}),
145        true
146    )]
147    #[case(
148        json!({
149            "spec": "some_spec",
150            "status": {
151              "conditions": [
152                {
153                  "lastProbeTime": null,
154                  "lastTransitionTime": "2024-11-02T15:49:19Z",
155                  "status": "True",
156                  "type": "Ready"
157                },
158                {
159                  "lastProbeTime": null,
160                  "lastTransitionTime": "2024-11-02T15:49:19Z",
161                  "status": "True",
162                  "type": "ContainersReady"
163                },
164                {
165                  "lastProbeTime": null,
166                  "lastTransitionTime": "2024-11-02T15:49:14Z",
167                  "status": "True",
168                  "type": "PodScheduled"
169                }
170              ],
171              "containerStatuses": [
172                {
173                  "containerID": "docker://1b9a81f558cc5980a152a554ba6b03866062e91958c0af72c8290b62633dd2f7",
174                  "image": "eclipse-mosquitto:2",
175                  "state": {
176                    "running": {
177                      "startedAt": "2024-11-02T15:49:19Z"
178                    }
179                  },
180                  "volumeMounts": [
181                    {
182                      "mountPath": "/mosquitto/config",
183                      "name": "configuration"
184                    },
185                    {
186                      "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
187                      "name": "kube-api-access-dtsbh",
188                      "readOnly": true,
189                      "recursiveReadOnly": "Disabled"
190                    }
191                  ]
192                }
193              ]
194            }
195        }),
196        json!({
197            "status": {
198              "conditions": [
199                {
200                  "type": "Ready",
201                  "status": "True"
202                }
203              ]
204            }
205        }),
206        true
207    )]
208    #[case(
209        json!({
210            "spec": "some_spec",
211            "status": {
212              "conditions": [
213                {
214                  "lastProbeTime": null,
215                  "lastTransitionTime": "2024-11-02T15:49:19Z",
216                  "status": "False",
217                  "type": "Ready"
218                },
219                {
220                  "lastProbeTime": null,
221                  "lastTransitionTime": "2024-11-02T15:49:19Z",
222                  "status": "True",
223                  "type": "ContainersReady"
224                },
225                {
226                  "lastProbeTime": null,
227                  "lastTransitionTime": "2024-11-02T15:49:14Z",
228                  "status": "True",
229                  "type": "PodScheduled"
230                }
231              ],
232              "containerStatuses": [
233                {
234                  "containerID": "docker://1b9a81f558cc5980a152a554ba6b03866062e91958c0af72c8290b62633dd2f7",
235                  "image": "eclipse-mosquitto:2",
236                  "state": {
237                    "running": {
238                      "startedAt": "2024-11-02T15:49:19Z"
239                    }
240                  },
241                  "volumeMounts": [
242                    {
243                      "mountPath": "/mosquitto/config",
244                      "name": "configuration"
245                    },
246                    {
247                      "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
248                      "name": "kube-api-access-dtsbh",
249                      "readOnly": true,
250                      "recursiveReadOnly": "Disabled"
251                    }
252                  ]
253                }
254              ]
255            }
256        }),
257        json!({
258            "status": {
259              "conditions": [
260                {
261                  "type": "Ready",
262                  "status": "True"
263                }
264              ]
265            }
266        }),
267        false
268    )]
269    fn test_contains(#[case] input: Value, #[case] compare: Value, #[case] expected: bool) {
270        let result = contains(&input, &compare);
271        assert_eq!(result, expected);
272    }
273}