expect_json/expect/ops/expect_array/
expect_array.rs

1use crate::expect::ops::expect_array::ExpectArraySubOp;
2use crate::expect_core::expect_op;
3use crate::expect_core::Context;
4use crate::expect_core::ExpectOp;
5use crate::expect_core::ExpectOpResult;
6use crate::JsonType;
7use serde_json::Value;
8use std::fmt::Debug;
9
10#[expect_op(internal, name = "array")]
11#[derive(Debug, Clone, Default, PartialEq)]
12pub struct ExpectArray {
13    sub_ops: Vec<ExpectArraySubOp>,
14}
15
16impl ExpectArray {
17    pub(crate) fn new() -> Self {
18        Self { sub_ops: vec![] }
19    }
20
21    pub fn empty(mut self) -> Self {
22        self.sub_ops.push(ExpectArraySubOp::Empty);
23        self
24    }
25
26    pub fn not_empty(mut self) -> Self {
27        self.sub_ops.push(ExpectArraySubOp::NotEmpty);
28        self
29    }
30
31    pub fn len(mut self, len: usize) -> Self {
32        self.sub_ops.push(ExpectArraySubOp::Len(len));
33        self
34    }
35
36    pub fn min_len(mut self, min_len: usize) -> Self {
37        self.sub_ops.push(ExpectArraySubOp::MinLen(min_len));
38        self
39    }
40
41    pub fn max_len(mut self, max_len: usize) -> Self {
42        self.sub_ops.push(ExpectArraySubOp::MaxLen(max_len));
43        self
44    }
45
46    pub fn contains<I, V>(mut self, expected_values: I) -> Self
47    where
48        I: IntoIterator<Item = V>,
49        V: Into<Value>,
50    {
51        let inner_expected_values = expected_values
52            .into_iter()
53            .map(Into::into)
54            .collect::<Vec<_>>();
55        self.sub_ops
56            .push(ExpectArraySubOp::Contains(inner_expected_values));
57        self
58    }
59
60    /// Expects all values in the array match the expected value.
61    /// This can be an exact value, or an `ExpectOp`.
62    ///
63    /// Note an empty array will match this.
64    ///
65    /// ```rust
66    /// # async fn test() -> Result<(), Box<dyn ::std::error::Error>> {
67    /// #
68    /// # use axum::Router;
69    /// # use axum::extract::Json;
70    /// # use axum::routing::get;
71    /// # use axum_test::TestServer;
72    /// # use serde_json::json;
73    /// #
74    /// # let server = TestServer::new(Router::new())?;
75    /// #
76    /// use axum_test::expect_json;
77    ///
78    /// let server = TestServer::new(Router::new())?;
79    ///
80    /// server.get(&"/users")
81    ///     .await
82    ///     .assert_json(&json!(expect_json::array().all(
83    ///         json!({
84    ///             "name": expect_json::string().not_empty(),
85    ///             "email": expect_json::email(),
86    ///         })
87    ///     )));
88    /// #
89    /// # Ok(()) }
90    /// ```
91    pub fn all<V>(mut self, expected: V) -> Self
92    where
93        V: Into<Value>,
94    {
95        self.sub_ops
96            .push(ExpectArraySubOp::AllEqual(expected.into()));
97        self
98    }
99
100    /// Expects all values in the array are unique. No duplicates.
101    ///
102    /// ```rust
103    /// # async fn test() -> Result<(), Box<dyn ::std::error::Error>> {
104    /// #
105    /// # use axum::Router;
106    /// # use axum::extract::Json;
107    /// # use axum::routing::get;
108    /// # use axum_test::TestServer;
109    /// # use serde_json::json;
110    /// #
111    /// # let server = TestServer::new(Router::new())?;
112    /// #
113    /// use axum_test::expect_json;
114    ///
115    /// let server = TestServer::new(Router::new())?;
116    ///
117    /// server.get(&"/users")
118    ///     .await
119    ///     .assert_json(&json!({
120    ///         // expect an array of unique UUIDs
121    ///         "user_ids": expect_json::array()
122    ///             .all(expect_json::uuid())
123    ///             .unique(),
124    ///     }));
125    /// #
126    /// # Ok(()) }
127    /// ```
128    pub fn unique(mut self) -> Self {
129        self.sub_ops.push(ExpectArraySubOp::AllUnique);
130        self
131    }
132}
133
134impl ExpectOp for ExpectArray {
135    fn on_array(&self, context: &mut Context, received: &[Value]) -> ExpectOpResult<()> {
136        for sub_op in &self.sub_ops {
137            sub_op.on_array(self, context, received)?;
138        }
139
140        Ok(())
141    }
142
143    fn debug_supported_types(&self) -> &'static [JsonType] {
144        &[JsonType::Array]
145    }
146}
147
148#[cfg(test)]
149mod test_contains {
150    use crate::expect;
151    use crate::expect_json_eq;
152    use pretty_assertions::assert_eq;
153    use serde_json::json;
154
155    #[test]
156    fn it_should_be_equal_for_identical_numeric_arrays() {
157        let left = json!([1, 2, 3]);
158        let right = json!(expect::array().contains([1, 2, 3]));
159
160        let output = expect_json_eq(&left, &right);
161        assert!(output.is_ok());
162    }
163
164    #[test]
165    fn it_should_be_equal_for_reversed_identical_numeric_arrays() {
166        let left = json!([1, 2, 3]);
167        let right = json!(expect::array().contains([3, 2, 1]));
168
169        let output = expect_json_eq(&left, &right);
170        assert!(output.is_ok());
171    }
172
173    #[test]
174    fn it_should_be_equal_for_partial_contains() {
175        let left = json!([0, 1, 2, 3, 4, 5]);
176        let right = json!(expect::array().contains([1, 2, 3]));
177
178        let output = expect_json_eq(&left, &right);
179        assert!(output.is_ok());
180    }
181
182    #[test]
183    fn it_should_error_for_totall_different_values() {
184        let left = json!([0, 1, 2, 3]);
185        let right = json!(expect::array().contains([4, 5, 6]));
186
187        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
188        assert_eq!(
189            output,
190            r#"Json array at root does not contain expected value:
191    expected array to contain 4, but it was not found.
192    received [0, 1, 2, 3]"#
193        );
194    }
195
196    #[test]
197    fn it_should_be_ok_for_empty_contains() {
198        let left = json!([0, 1, 2, 3]);
199        let right = json!(expect::array().contains([] as [u32; 0]));
200
201        let output = expect_json_eq(&left, &right);
202        assert!(output.is_ok());
203    }
204
205    #[test]
206    fn it_should_error_if_used_against_the_wrong_type() {
207        let left = json!("🦊");
208        let right = json!(expect::array().contains([4, 5, 6]));
209
210        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
211        assert_eq!(
212            output,
213            r#"Json expect::array() at root, received wrong type:
214    expected array
215    received string "🦊""#
216        );
217    }
218
219    #[test]
220    fn it_should_handle_nested_contains() {
221        let left = json!([
222            {
223                "text": "Hello",
224                "author": "Jane Candle"
225            },
226            {
227                "text": "Goodbye",
228                "author": "John Lighthouse"
229            }
230        ]);
231
232        let right = json!(expect::array().contains([json!({
233            "text": "Hello",
234            "author": expect::string().contains("Jane"),
235        }),]));
236
237        let output = expect_json_eq(&left, &right);
238        assert!(output.is_ok(), "{}", output.unwrap_err().to_string());
239    }
240
241    #[test]
242    fn it_should_fail_nested_contains_that_do_not_match() {
243        let left = json!([
244            {
245                "text": "Hello",
246                "author": "Jane Candle"
247            },
248            {
249                "text": "Goodbye",
250                "author": "John Lighthouse"
251            }
252        ]);
253
254        let right = json!(expect::array().contains([json!({
255            "text": "Hello",
256            "author": expect::string().contains("🦊"),
257        }),]));
258
259        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
260        assert_eq!(
261            output,
262            r#"Json array at root does not contain expected value:
263    expected array to contain {
264        "author": expect::string(),
265        "text": "Hello"
266    }, but it was not found.
267    received [
268        {
269            "author": "Jane Candle",
270            "text": "Hello"
271        },
272        {
273            "author": "John Lighthouse",
274            "text": "Goodbye"
275        }
276    ]"#
277        );
278    }
279}
280
281#[cfg(test)]
282mod test_empty {
283    use crate::expect;
284    use crate::expect_json_eq;
285    use pretty_assertions::assert_eq;
286    use serde_json::json;
287
288    #[test]
289    fn it_should_pass_when_array_is_empty() {
290        let left = json!([]);
291        let right = json!(expect::array().empty());
292
293        let output = expect_json_eq(&left, &right);
294        assert!(output.is_ok(), "assertion error: {output:#?}");
295    }
296
297    #[test]
298    fn it_should_fail_when_array_is_not_empty() {
299        let left = json!([1, 2, 3]);
300        let right = json!(expect::array().empty());
301
302        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
303        assert_eq!(
304            output,
305            r#"Json expect::array() error at root:
306    expected empty array
307    received [1, 2, 3]"#
308        );
309    }
310}
311
312#[cfg(test)]
313mod test_not_empty {
314    use crate::expect;
315    use crate::expect_json_eq;
316    use pretty_assertions::assert_eq;
317    use serde_json::json;
318
319    #[test]
320    fn it_should_pass_when_array_is_not_empty() {
321        let left = json!([1]);
322        let right = json!(expect::array().not_empty());
323
324        let output = expect_json_eq(&left, &right);
325        assert!(output.is_ok(), "assertion error: {output:#?}");
326    }
327
328    #[test]
329    fn it_should_fail_when_array_is_empty() {
330        let left = json!([]);
331        let right = json!(expect::array().not_empty());
332
333        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
334        assert_eq!(
335            output,
336            r#"Json expect::array() error at root:
337    expected non-empty array
338    received []"#
339        );
340    }
341}
342
343#[cfg(test)]
344mod test_min_len {
345    use crate::expect;
346    use crate::expect_json_eq;
347    use pretty_assertions::assert_eq;
348    use serde_json::json;
349
350    #[test]
351    fn it_should_pass_when_array_has_exactly_enough_elements() {
352        let left = json!([1, 2, 3]);
353        let right = json!(expect::array().min_len(3));
354
355        let output = expect_json_eq(&left, &right);
356        assert!(output.is_ok(), "assertion error: {output:#?}");
357    }
358
359    #[test]
360    fn it_should_pass_when_array_has_more_than_enough_elements() {
361        let left = json!([1, 2, 3, 4, 5]);
362        let right = json!(expect::array().min_len(3));
363
364        let output = expect_json_eq(&left, &right);
365        assert!(output.is_ok(), "assertion error: {output:#?}");
366    }
367
368    #[test]
369    fn it_should_fail_when_array_has_too_few_elements() {
370        let left = json!([1, 2, 3]);
371        let right = json!(expect::array().min_len(4));
372
373        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
374        assert_eq!(
375            output,
376            r#"Json expect::array() error at root:
377    expected array to have at least 4 elements, but it has 3.
378    received [1, 2, 3]"#
379        );
380    }
381}
382
383#[cfg(test)]
384mod test_len {
385    use crate::expect;
386    use crate::expect_json_eq;
387    use pretty_assertions::assert_eq;
388    use serde_json::json;
389
390    #[test]
391    fn it_should_pass_when_array_has_exactly_enough_elements() {
392        let left = json!([1, 2, 3]);
393        let right = json!(expect::array().len(3));
394
395        let output = expect_json_eq(&left, &right);
396        assert!(output.is_ok(), "assertion error: {output:#?}");
397    }
398
399    #[test]
400    fn it_should_fail_when_array_has_more_than_enough_elements() {
401        let left = json!([1, 2, 3, 4, 5]);
402        let right = json!(expect::array().len(3));
403
404        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
405        assert_eq!(
406            output,
407            r#"Json expect::array() error at root:
408    expected array to have 3 elements, but it has 5.
409    received [1, 2, 3, 4, 5]"#
410        );
411    }
412
413    #[test]
414    fn it_should_fail_when_array_has_too_few_elements() {
415        let left = json!([1, 2, 3]);
416        let right = json!(expect::array().len(4));
417
418        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
419        assert_eq!(
420            output,
421            r#"Json expect::array() error at root:
422    expected array to have 4 elements, but it has 3.
423    received [1, 2, 3]"#
424        );
425    }
426}
427
428#[cfg(test)]
429mod test_max_len {
430    use crate::expect;
431    use crate::expect_json_eq;
432    use pretty_assertions::assert_eq;
433    use serde_json::json;
434
435    #[test]
436    fn it_should_pass_when_array_has_exactly_enough_elements() {
437        let left = json!([1, 2, 3]);
438        let right = json!(expect::array().max_len(3));
439
440        let output = expect_json_eq(&left, &right);
441        assert!(output.is_ok(), "assertion error: {output:#?}");
442    }
443
444    #[test]
445    fn it_should_pass_when_array_has_less_than_enough_elements() {
446        let left = json!([1, 2]);
447        let right = json!(expect::array().max_len(6));
448
449        let output = expect_json_eq(&left, &right);
450        assert!(output.is_ok(), "assertion error: {output:#?}");
451    }
452
453    #[test]
454    fn it_should_fail_when_array_has_too_few_elements() {
455        let left = json!([1, 2, 3, 4]);
456        let right = json!(expect::array().max_len(3));
457
458        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
459        assert_eq!(
460            output,
461            r#"Json expect::array() error at root:
462    expected array to have at most 3 elements, but it has 4.
463    received [1, 2, 3, 4]"#
464        );
465    }
466}
467
468#[cfg(test)]
469mod test_all {
470    use crate::expect;
471    use crate::expect_json_eq;
472    use pretty_assertions::assert_eq;
473    use serde_json::json;
474
475    #[test]
476    fn it_should_pass_when_array_is_empty() {
477        let left = json!([]);
478        let right = json!(expect::array().all(expect::string()));
479
480        let output = expect_json_eq(&left, &right);
481        assert!(output.is_ok(), "assertion error: {output:#?}");
482    }
483
484    #[test]
485    fn it_should_pass_with_mix_of_operations() {
486        let left = json!([
487            "123e4567-e89b-12d3-a456-426614174000",
488            "123e4567-e89b-12d3-a456-426614174001",
489            "123e4567-e89b-12d3-a456-426614174002",
490        ]);
491        let right = json!(expect::array().all(expect::uuid()).len(3).unique());
492
493        let output = expect_json_eq(&left, &right);
494        assert!(output.is_ok(), "assertion error: {output:#?}");
495    }
496
497    #[test]
498    fn it_should_fail_with_mix_of_operations() {
499        let left = json!([
500            "123e4567-e89b-12d3-a456-426614174000",
501            "123e4567-e89b-12d3-a456-426614174001",
502            "123e4567-e89b-12d3-a456-426614174002",
503            "123e4567-e89b-12d3-a456-426614174003",
504        ]);
505        let right = json!(expect::array().all(expect::uuid()).len(3).unique());
506
507        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
508        assert_eq!(
509            output,
510            r#"Json expect::array() error at root:
511    expected array to have 3 elements, but it has 4.
512    received ["123e4567-e89b-12d3-a456-426614174000", "123e4567-e89b-12d3-a456-426614174001", "123e4567-e89b-12d3-a456-426614174002", "123e4567-e89b-12d3-a456-426614174003"]"#
513        );
514    }
515
516    #[test]
517    fn it_should_fail_when_array_values_do_not_match_expect_op() {
518        let left = json!([1, 2, 3]);
519        let right = json!(expect::array().all(expect::string()));
520
521        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
522        assert_eq!(
523            output,
524            r#"Json expect::string() at root[0], received wrong type:
525    expected string
526    received integer 1
527    received full array [1, 2, 3]"#
528        );
529    }
530
531    #[test]
532    fn it_should_fail_when_array_values_do_not_match_values() {
533        let left = json!([1, 2, 3]);
534        let right = json!(expect::array().all("🦊"));
535
536        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
537        assert_eq!(
538            output,
539            r#"Json values at root[0] are different types:
540    expected string "🦊"
541    received integer 1
542    received full array [1, 2, 3]"#
543        );
544    }
545
546    #[test]
547    fn it_should_pass_when_array_values_do_match_expect_op() {
548        let left = json!(["alice@example.com", "bob@example.com"]);
549        let right = json!(expect::array().all(expect::email()));
550
551        let output = expect_json_eq(&left, &right);
552        assert!(output.is_ok(), "assertion error: {output:#?}");
553    }
554
555    #[test]
556    fn it_should_pass_when_array_values_do_match_values() {
557        let left = json!([1, 1, 1]);
558        let right = json!(expect::array().all(1));
559
560        let output = expect_json_eq(&left, &right);
561        assert!(output.is_ok(), "assertion error: {output:#?}");
562    }
563
564    #[test]
565    fn it_should_pass_when_array_values_do_match_complex_objects() {
566        let left = json!([
567            {
568                "name": "Alice Candles",
569                "email": "alice@example.com"
570            },
571            {
572                "name": "Bob Kettles",
573                "email": "bob@example.com"
574            },
575        ]);
576
577        let right = json!(expect::array().all(json!({
578            "name": expect::string().not_empty(),
579            "email": expect::email(),
580        })));
581
582        let output = expect_json_eq(&left, &right);
583        assert!(output.is_ok(), "assertion error: {output:#?}");
584    }
585
586    #[test]
587    fn it_should_not_pass_when_array_values_do_not_match_complex_objects() {
588        let left = json!([
589            {
590                "name": "Alice Candles",
591                "email": "alice@example.com"
592            },
593            {
594                "name": "",
595                "email": "bob@example.com"
596            },
597        ]);
598
599        let right = json!(expect::array().all(json!({
600            "name": expect::string().not_empty(),
601            "email": expect::email(),
602        })));
603
604        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
605        assert_eq!(
606            output,
607            r#"Json expect::string() error at root[1].name:
608    expected non-empty string
609    received ""
610    received full array [
611        {
612            "email": "alice@example.com",
613            "name": "Alice Candles"
614        },
615        {
616            "email": "bob@example.com",
617            "name": ""
618        }
619    ]"#
620        );
621    }
622}
623
624#[cfg(test)]
625mod test_unique {
626    use crate::expect;
627    use crate::expect_json_eq;
628    use pretty_assertions::assert_eq;
629    use serde_json::json;
630
631    #[test]
632    fn it_should_pass_when_array_is_empty() {
633        let left = json!([]);
634        let right = json!(expect::array().unique());
635
636        let output = expect_json_eq(&left, &right);
637        assert!(output.is_ok(), "assertion error: {output:#?}");
638    }
639
640    #[test]
641    fn it_should_fail_when_array_is_not_unique() {
642        let left = json!([1, 1, 2]);
643        let right = json!(expect::array().unique());
644
645        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
646        assert_eq!(
647            output,
648            r#"Json expect::array() error at root[1],
649    expected array to contain all unique values.
650    found duplicate 1
651    received full array [1, 1, 2]"#
652        );
653    }
654}