expect_json/expect/ops/expect_array/
expect_array.rs

1use crate::JsonType;
2use crate::expect::ops::expect_array::ExpectArraySubOp;
3use crate::expect_core::Context;
4use crate::expect_core::ExpectOp;
5use crate::expect_core::ExpectOpResult;
6use crate::expect_core::expect_op;
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 values in some order.
61    /// This can be an exact value, or an `ExpectOp`.
62    /// The lengths of the arrays must be equal.
63    pub fn eq_unordered<I, V>(mut self, expected_values: I) -> Self
64    where
65        I: IntoIterator<Item = V>,
66        V: Into<Value>,
67    {
68        let inner_expected_values = expected_values
69            .into_iter()
70            .map(Into::into)
71            .collect::<Vec<_>>();
72        self.sub_ops
73            .push(ExpectArraySubOp::EqUnordered(inner_expected_values));
74        self
75    }
76
77    /// Expects all values in the array match the expected value.
78    /// This can be an exact value, or an `ExpectOp`.
79    ///
80    /// Note an empty array will match this.
81    ///
82    /// ```rust
83    /// # async fn test() -> Result<(), Box<dyn ::std::error::Error>> {
84    /// #
85    /// # use axum::Router;
86    /// # use axum::extract::Json;
87    /// # use axum::routing::get;
88    /// # use axum_test::TestServer;
89    /// # use serde_json::json;
90    /// #
91    /// # let server = TestServer::new(Router::new())?;
92    /// #
93    /// use axum_test::expect_json;
94    ///
95    /// let server = TestServer::new(Router::new())?;
96    ///
97    /// server.get(&"/users")
98    ///     .await
99    ///     .assert_json(&json!(expect_json::array().all(
100    ///         json!({
101    ///             "name": expect_json::string().not_empty(),
102    ///             "email": expect_json::email(),
103    ///         })
104    ///     )));
105    /// #
106    /// # Ok(()) }
107    /// ```
108    pub fn all<V>(mut self, expected: V) -> Self
109    where
110        V: Into<Value>,
111    {
112        self.sub_ops
113            .push(ExpectArraySubOp::AllEqual(expected.into()));
114        self
115    }
116
117    /// Expects all values in the array are unique. No duplicates.
118    ///
119    /// ```rust
120    /// # async fn test() -> Result<(), Box<dyn ::std::error::Error>> {
121    /// #
122    /// # use axum::Router;
123    /// # use axum::extract::Json;
124    /// # use axum::routing::get;
125    /// # use axum_test::TestServer;
126    /// # use serde_json::json;
127    /// #
128    /// # let server = TestServer::new(Router::new())?;
129    /// #
130    /// use axum_test::expect_json;
131    ///
132    /// let server = TestServer::new(Router::new())?;
133    ///
134    /// server.get(&"/users")
135    ///     .await
136    ///     .assert_json(&json!({
137    ///         // expect an array of unique UUIDs
138    ///         "user_ids": expect_json::array()
139    ///             .all(expect_json::uuid())
140    ///             .unique(),
141    ///     }));
142    /// #
143    /// # Ok(()) }
144    /// ```
145    pub fn unique(mut self) -> Self {
146        self.sub_ops.push(ExpectArraySubOp::AllUnique);
147        self
148    }
149}
150
151impl ExpectOp for ExpectArray {
152    fn on_array(&self, context: &mut Context, received: &[Value]) -> ExpectOpResult<()> {
153        for sub_op in &self.sub_ops {
154            sub_op.on_array(self, context, received)?;
155        }
156
157        Ok(())
158    }
159
160    fn debug_supported_types(&self) -> &'static [JsonType] {
161        &[JsonType::Array]
162    }
163}
164
165#[cfg(test)]
166mod test_contains {
167    use crate::expect;
168    use crate::expect_json_eq;
169    use pretty_assertions::assert_eq;
170    use serde_json::json;
171
172    #[test]
173    fn it_should_be_equal_for_identical_numeric_arrays() {
174        let left = json!([1, 2, 3]);
175        let right = json!(expect::array().contains([1, 2, 3]));
176
177        let output = expect_json_eq(&left, &right);
178        assert!(output.is_ok());
179    }
180
181    #[test]
182    fn it_should_be_equal_for_reversed_identical_numeric_arrays() {
183        let left = json!([1, 2, 3]);
184        let right = json!(expect::array().contains([3, 2, 1]));
185
186        let output = expect_json_eq(&left, &right);
187        assert!(output.is_ok());
188    }
189
190    #[test]
191    fn it_should_be_equal_for_partial_contains() {
192        let left = json!([0, 1, 2, 3, 4, 5]);
193        let right = json!(expect::array().contains([1, 2, 3]));
194
195        let output = expect_json_eq(&left, &right);
196        assert!(output.is_ok());
197    }
198
199    #[test]
200    fn it_should_error_for_totall_different_values() {
201        let left = json!([0, 1, 2, 3]);
202        let right = json!(expect::array().contains([4, 5, 6]));
203
204        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
205        assert_eq!(
206            output,
207            r#"Json array at root does not contain expected value:
208    expected array to contain 4, but it was not found.
209    received [0, 1, 2, 3]"#
210        );
211    }
212
213    #[test]
214    fn it_should_be_ok_for_empty_contains() {
215        let left = json!([0, 1, 2, 3]);
216        let right = json!(expect::array().contains([] as [u32; 0]));
217
218        let output = expect_json_eq(&left, &right);
219        assert!(output.is_ok());
220    }
221
222    #[test]
223    fn it_should_error_if_used_against_the_wrong_type() {
224        let left = json!("🦊");
225        let right = json!(expect::array().contains([4, 5, 6]));
226
227        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
228        assert_eq!(
229            output,
230            r#"Json expect::array() at root, received wrong type:
231    expected array
232    received string "🦊""#
233        );
234    }
235
236    #[test]
237    fn it_should_handle_nested_contains() {
238        let left = json!([
239            {
240                "text": "Hello",
241                "author": "Jane Candle"
242            },
243            {
244                "text": "Goodbye",
245                "author": "John Lighthouse"
246            }
247        ]);
248
249        let right = json!(expect::array().contains([json!({
250            "text": "Hello",
251            "author": expect::string().contains("Jane"),
252        }),]));
253
254        let output = expect_json_eq(&left, &right);
255        assert!(output.is_ok(), "{}", output.unwrap_err().to_string());
256    }
257
258    #[test]
259    fn it_should_fail_nested_contains_that_do_not_match() {
260        let left = json!([
261            {
262                "text": "Hello",
263                "author": "Jane Candle"
264            },
265            {
266                "text": "Goodbye",
267                "author": "John Lighthouse"
268            }
269        ]);
270
271        let right = json!(expect::array().contains([json!({
272            "text": "Hello",
273            "author": expect::string().contains("🦊"),
274        }),]));
275
276        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
277        assert_eq!(
278            output,
279            r#"Json array at root does not contain expected value:
280    expected array to contain {
281        "author": expect::string(),
282        "text": "Hello"
283    }, but it was not found.
284    received [
285        {
286            "author": "Jane Candle",
287            "text": "Hello"
288        },
289        {
290            "author": "John Lighthouse",
291            "text": "Goodbye"
292        }
293    ]"#
294        );
295    }
296}
297
298#[cfg(test)]
299mod test_empty {
300    use crate::expect;
301    use crate::expect_json_eq;
302    use pretty_assertions::assert_eq;
303    use serde_json::json;
304
305    #[test]
306    fn it_should_pass_when_array_is_empty() {
307        let left = json!([]);
308        let right = json!(expect::array().empty());
309
310        let output = expect_json_eq(&left, &right);
311        assert!(output.is_ok(), "assertion error: {output:#?}");
312    }
313
314    #[test]
315    fn it_should_fail_when_array_is_not_empty() {
316        let left = json!([1, 2, 3]);
317        let right = json!(expect::array().empty());
318
319        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
320        assert_eq!(
321            output,
322            r#"Json expect::array() error at root:
323    expected empty array
324    received [1, 2, 3]"#
325        );
326    }
327}
328
329#[cfg(test)]
330mod test_not_empty {
331    use crate::expect;
332    use crate::expect_json_eq;
333    use pretty_assertions::assert_eq;
334    use serde_json::json;
335
336    #[test]
337    fn it_should_pass_when_array_is_not_empty() {
338        let left = json!([1]);
339        let right = json!(expect::array().not_empty());
340
341        let output = expect_json_eq(&left, &right);
342        assert!(output.is_ok(), "assertion error: {output:#?}");
343    }
344
345    #[test]
346    fn it_should_fail_when_array_is_empty() {
347        let left = json!([]);
348        let right = json!(expect::array().not_empty());
349
350        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
351        assert_eq!(
352            output,
353            r#"Json expect::array() error at root:
354    expected non-empty array
355    received []"#
356        );
357    }
358}
359
360#[cfg(test)]
361mod test_min_len {
362    use crate::expect;
363    use crate::expect_json_eq;
364    use pretty_assertions::assert_eq;
365    use serde_json::json;
366
367    #[test]
368    fn it_should_pass_when_array_has_exactly_enough_elements() {
369        let left = json!([1, 2, 3]);
370        let right = json!(expect::array().min_len(3));
371
372        let output = expect_json_eq(&left, &right);
373        assert!(output.is_ok(), "assertion error: {output:#?}");
374    }
375
376    #[test]
377    fn it_should_pass_when_array_has_more_than_enough_elements() {
378        let left = json!([1, 2, 3, 4, 5]);
379        let right = json!(expect::array().min_len(3));
380
381        let output = expect_json_eq(&left, &right);
382        assert!(output.is_ok(), "assertion error: {output:#?}");
383    }
384
385    #[test]
386    fn it_should_fail_when_array_has_too_few_elements() {
387        let left = json!([1, 2, 3]);
388        let right = json!(expect::array().min_len(4));
389
390        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
391        assert_eq!(
392            output,
393            r#"Json expect::array() error at root:
394    expected array to have at least 4 elements, but it has 3.
395    received [1, 2, 3]"#
396        );
397    }
398}
399
400#[cfg(test)]
401mod test_len {
402    use crate::expect;
403    use crate::expect_json_eq;
404    use pretty_assertions::assert_eq;
405    use serde_json::json;
406
407    #[test]
408    fn it_should_pass_when_array_has_exactly_enough_elements() {
409        let left = json!([1, 2, 3]);
410        let right = json!(expect::array().len(3));
411
412        let output = expect_json_eq(&left, &right);
413        assert!(output.is_ok(), "assertion error: {output:#?}");
414    }
415
416    #[test]
417    fn it_should_fail_when_array_has_more_than_enough_elements() {
418        let left = json!([1, 2, 3, 4, 5]);
419        let right = json!(expect::array().len(3));
420
421        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
422        assert_eq!(
423            output,
424            r#"Json expect::array() error at root:
425    expected array to have 3 elements, but it has 5.
426    received [1, 2, 3, 4, 5]"#
427        );
428    }
429
430    #[test]
431    fn it_should_fail_when_array_has_too_few_elements() {
432        let left = json!([1, 2, 3]);
433        let right = json!(expect::array().len(4));
434
435        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
436        assert_eq!(
437            output,
438            r#"Json expect::array() error at root:
439    expected array to have 4 elements, but it has 3.
440    received [1, 2, 3]"#
441        );
442    }
443}
444
445#[cfg(test)]
446mod test_max_len {
447    use crate::expect;
448    use crate::expect_json_eq;
449    use pretty_assertions::assert_eq;
450    use serde_json::json;
451
452    #[test]
453    fn it_should_pass_when_array_has_exactly_enough_elements() {
454        let left = json!([1, 2, 3]);
455        let right = json!(expect::array().max_len(3));
456
457        let output = expect_json_eq(&left, &right);
458        assert!(output.is_ok(), "assertion error: {output:#?}");
459    }
460
461    #[test]
462    fn it_should_pass_when_array_has_less_than_enough_elements() {
463        let left = json!([1, 2]);
464        let right = json!(expect::array().max_len(6));
465
466        let output = expect_json_eq(&left, &right);
467        assert!(output.is_ok(), "assertion error: {output:#?}");
468    }
469
470    #[test]
471    fn it_should_fail_when_array_has_too_few_elements() {
472        let left = json!([1, 2, 3, 4]);
473        let right = json!(expect::array().max_len(3));
474
475        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
476        assert_eq!(
477            output,
478            r#"Json expect::array() error at root:
479    expected array to have at most 3 elements, but it has 4.
480    received [1, 2, 3, 4]"#
481        );
482    }
483}
484
485#[cfg(test)]
486mod test_eq_unordered {
487    use crate::expect;
488    use crate::expect_json_eq;
489    use pretty_assertions::assert_eq;
490    use serde_json::json;
491
492    #[test]
493    fn it_should_pass_when_arrays_match_unordered() {
494        let left = json!([1, 2, 3]);
495        let right = json!(expect::array().eq_unordered([3, 2, 1]));
496
497        let output = expect_json_eq(&left, &right);
498        assert!(output.is_ok(), "assertion error: {output:#?}");
499    }
500
501    #[test]
502    fn it_should_fail_when_arrays_do_not_match_unordered() {
503        let left = json!([1, 2, 3]);
504        let right = json!(expect::array().eq_unordered([4, 5, 6]));
505
506        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
507        assert_eq!(
508            output,
509            r#"Json expect::array() error at root, mismatch:
510    expected array (up to order): [4, 5, 6],
511    received array: [1, 2, 3]"#
512        );
513    }
514
515    #[test]
516    fn it_should_fail_when_arrays_have_different_lengths() {
517        let left = json!([1, 2, 3]);
518        let right = json!(expect::array().eq_unordered([1, 2, 3, 4]));
519        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
520        assert_eq!(
521            output,
522            r#"Json expect::array() error at root, mismatch:
523    expected array (up to order): [1, 2, 3, 4],
524    received array: [1, 2, 3]"#
525        );
526    }
527
528    #[test]
529    fn it_should_pass_with_complex_matches() {
530        let left = json!(["Alice", "Bob", "Charlie"]);
531        let right = json!(expect::array().eq_unordered([
532            expect::string().contains("C"),
533            expect::string().contains("A"),
534            expect::string().contains("B"),
535        ]));
536        let output = expect_json_eq(&left, &right);
537        assert!(output.is_ok(), "assertion error: {output:#?}");
538    }
539
540    #[test]
541    fn it_should_pass_not_using_greedy_matching() {
542        // If we used greedy matching, "Alice" would match to the first expect::string(),
543        // then "Charlie" would fail.
544        let left = json!(["Alice", "Bob", "Charlie"]);
545        let right = json!(expect::array().eq_unordered([
546            expect::string(),
547            expect::string().contains("B"),
548            expect::string().contains("A"),
549        ]));
550        let output = expect_json_eq(&left, &right);
551        assert!(output.is_ok(), "assertion error: {output:#?}");
552    }
553
554    #[test]
555    fn it_should_pass_with_equal_elements() {
556        let left = json!(["Alice", "Alice", "Alice"]);
557        let right = json!(expect::array().eq_unordered([
558            expect::string().contains("A"),
559            expect::string().contains("A"),
560            expect::string().contains("A"),
561        ]));
562        let output = expect_json_eq(&left, &right);
563        assert!(output.is_ok(), "assertion error: {output:#?}");
564    }
565
566    #[test]
567    fn it_should_pass_on_a_multiset_with_bijection() {
568        let left = json!(["Alice", "Alice", "Bob"]);
569        let right = json!(expect::array().eq_unordered(["Bob", "Alice", "Alice"]));
570        let output = expect_json_eq(&left, &right);
571        assert!(output.is_ok(), "assertion error: {output:#?}");
572    }
573
574    #[test]
575    fn it_should_fail_when_there_is_no_bijection() {
576        // Both "Bob" and "Boris" should match the same expect::string().contains("B"),
577        // so there is no way to have a perfect matching.
578        let left = json!(["Alice", "Bob", "Boris"]);
579        let right = json!(expect::array().eq_unordered([
580            expect::string().contains("A"),
581            expect::string().contains("A"),
582            expect::string().contains("B"),
583        ]));
584        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
585        assert_eq!(
586            output,
587            r#"Json expect::array() error at root, mismatch:
588    expected array (up to order): [
589        expect::string(),
590        expect::string(),
591        expect::string()
592    ],
593    received array: ["Alice", "Bob", "Boris"]"#
594        );
595    }
596}
597
598#[cfg(test)]
599mod test_all {
600    use crate::expect;
601    use crate::expect_json_eq;
602    use pretty_assertions::assert_eq;
603    use serde_json::json;
604
605    #[test]
606    fn it_should_pass_when_array_is_empty() {
607        let left = json!([]);
608        let right = json!(expect::array().all(expect::string()));
609
610        let output = expect_json_eq(&left, &right);
611        assert!(output.is_ok(), "assertion error: {output:#?}");
612    }
613
614    #[test]
615    fn it_should_pass_with_mix_of_operations() {
616        let left = json!([
617            "123e4567-e89b-12d3-a456-426614174000",
618            "123e4567-e89b-12d3-a456-426614174001",
619            "123e4567-e89b-12d3-a456-426614174002",
620        ]);
621        let right = json!(expect::array().all(expect::uuid()).len(3).unique());
622
623        let output = expect_json_eq(&left, &right);
624        assert!(output.is_ok(), "assertion error: {output:#?}");
625    }
626
627    #[test]
628    fn it_should_fail_with_mix_of_operations() {
629        let left = json!([
630            "123e4567-e89b-12d3-a456-426614174000",
631            "123e4567-e89b-12d3-a456-426614174001",
632            "123e4567-e89b-12d3-a456-426614174002",
633            "123e4567-e89b-12d3-a456-426614174003",
634        ]);
635        let right = json!(expect::array().all(expect::uuid()).len(3).unique());
636
637        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
638        assert_eq!(
639            output,
640            r#"Json expect::array() error at root:
641    expected array to have 3 elements, but it has 4.
642    received ["123e4567-e89b-12d3-a456-426614174000", "123e4567-e89b-12d3-a456-426614174001", "123e4567-e89b-12d3-a456-426614174002", "123e4567-e89b-12d3-a456-426614174003"]"#
643        );
644    }
645
646    #[test]
647    fn it_should_fail_when_array_values_do_not_match_expect_op() {
648        let left = json!([1, 2, 3]);
649        let right = json!(expect::array().all(expect::string()));
650
651        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
652        assert_eq!(
653            output,
654            r#"Json expect::string() at root[0], received wrong type:
655    expected string
656    received integer 1
657    received full array [1, 2, 3]"#
658        );
659    }
660
661    #[test]
662    fn it_should_fail_when_array_values_do_not_match_values() {
663        let left = json!([1, 2, 3]);
664        let right = json!(expect::array().all("🦊"));
665
666        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
667        assert_eq!(
668            output,
669            r#"Json values at root[0] are different types:
670    expected string "🦊"
671    received integer 1
672    received full array [1, 2, 3]"#
673        );
674    }
675
676    #[test]
677    fn it_should_pass_when_array_values_do_match_expect_op() {
678        let left = json!(["alice@example.com", "bob@example.com"]);
679        let right = json!(expect::array().all(expect::email()));
680
681        let output = expect_json_eq(&left, &right);
682        assert!(output.is_ok(), "assertion error: {output:#?}");
683    }
684
685    #[test]
686    fn it_should_pass_when_array_values_do_match_values() {
687        let left = json!([1, 1, 1]);
688        let right = json!(expect::array().all(1));
689
690        let output = expect_json_eq(&left, &right);
691        assert!(output.is_ok(), "assertion error: {output:#?}");
692    }
693
694    #[test]
695    fn it_should_pass_when_array_values_do_match_complex_objects() {
696        let left = json!([
697            {
698                "name": "Alice Candles",
699                "email": "alice@example.com"
700            },
701            {
702                "name": "Bob Kettles",
703                "email": "bob@example.com"
704            },
705        ]);
706
707        let right = json!(expect::array().all(json!({
708            "name": expect::string().not_empty(),
709            "email": expect::email(),
710        })));
711
712        let output = expect_json_eq(&left, &right);
713        assert!(output.is_ok(), "assertion error: {output:#?}");
714    }
715
716    #[test]
717    fn it_should_not_pass_when_array_values_do_not_match_complex_objects() {
718        let left = json!([
719            {
720                "name": "Alice Candles",
721                "email": "alice@example.com"
722            },
723            {
724                "name": "",
725                "email": "bob@example.com"
726            },
727        ]);
728
729        let right = json!(expect::array().all(json!({
730            "name": expect::string().not_empty(),
731            "email": expect::email(),
732        })));
733
734        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
735        assert_eq!(
736            output,
737            r#"Json expect::string() error at root[1].name:
738    expected non-empty string
739    received ""
740    received full array [
741        {
742            "email": "alice@example.com",
743            "name": "Alice Candles"
744        },
745        {
746            "email": "bob@example.com",
747            "name": ""
748        }
749    ]"#
750        );
751    }
752}
753
754#[cfg(test)]
755mod test_unique {
756    use crate::expect;
757    use crate::expect_json_eq;
758    use pretty_assertions::assert_eq;
759    use serde_json::json;
760
761    #[test]
762    fn it_should_pass_when_array_is_empty() {
763        let left = json!([]);
764        let right = json!(expect::array().unique());
765
766        let output = expect_json_eq(&left, &right);
767        assert!(output.is_ok(), "assertion error: {output:#?}");
768    }
769
770    #[test]
771    fn it_should_fail_when_array_is_not_unique() {
772        let left = json!([1, 1, 2]);
773        let right = json!(expect::array().unique());
774
775        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
776        assert_eq!(
777            output,
778            r#"Json expect::array() error at root[1],
779    expected array to contain all unique values.
780    found duplicate 1
781    received full array [1, 1, 2]"#
782        );
783    }
784}