expect_json/expects/ops/expect_array/
expect_array.rs

1use crate::expect_op;
2use crate::ops::expect_array::ExpectArraySubOp;
3use crate::Context;
4use crate::ExpectOp;
5use crate::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 is_empty(mut self) -> Self {
22        self.sub_ops.push(ExpectArraySubOp::IsEmpty);
23        self
24    }
25
26    pub fn is_not_empty(mut self) -> Self {
27        self.sub_ops.push(ExpectArraySubOp::IsNotEmpty);
28        self
29    }
30
31    pub fn min_len(mut self, min_len: usize) -> Self {
32        self.sub_ops.push(ExpectArraySubOp::MinLen(min_len));
33        self
34    }
35
36    pub fn len(mut self, len: usize) -> Self {
37        self.sub_ops.push(ExpectArraySubOp::Len(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::expect;
77    ///
78    /// let server = TestServer::new(Router::new())?;
79    ///
80    /// server.get(&"/users")
81    ///     .await
82    ///     .assert_json(&json!(expect::array().all(
83    ///         json!({
84    ///             "name": expect::string().is_not_empty(),
85    ///             "email": expect::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::expect;
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::array()
122    ///             .all(expect::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 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
242#[cfg(test)]
243mod test_is_empty {
244    use crate::expect;
245    use crate::expect_json_eq;
246    use pretty_assertions::assert_eq;
247    use serde_json::json;
248
249    #[test]
250    fn it_should_pass_when_array_is_empty() {
251        let left = json!([]);
252        let right = json!(expect::array().is_empty());
253
254        let output = expect_json_eq(&left, &right);
255        assert!(output.is_ok(), "assertion error: {output:#?}");
256    }
257
258    #[test]
259    fn it_should_fail_when_array_is_not_empty() {
260        let left = json!([1, 2, 3]);
261        let right = json!(expect::array().is_empty());
262
263        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
264        assert_eq!(
265            output,
266            format!(
267                r#"Json expect::array() error at root:
268    expected empty array
269    received [1, 2, 3]"#
270            )
271        );
272    }
273}
274
275#[cfg(test)]
276mod test_is_not_empty {
277    use crate::expect;
278    use crate::expect_json_eq;
279    use pretty_assertions::assert_eq;
280    use serde_json::json;
281
282    #[test]
283    fn it_should_pass_when_array_is_not_empty() {
284        let left = json!([1]);
285        let right = json!(expect::array().is_not_empty());
286
287        let output = expect_json_eq(&left, &right);
288        assert!(output.is_ok(), "assertion error: {output:#?}");
289    }
290
291    #[test]
292    fn it_should_fail_when_array_is_empty() {
293        let left = json!([]);
294        let right = json!(expect::array().is_not_empty());
295
296        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
297        assert_eq!(
298            output,
299            format!(
300                r#"Json expect::array() error at root:
301    expected non-empty array
302    received []"#
303            )
304        );
305    }
306}
307
308#[cfg(test)]
309mod test_min_len {
310    use crate::expect;
311    use crate::expect_json_eq;
312    use pretty_assertions::assert_eq;
313    use serde_json::json;
314
315    #[test]
316    fn it_should_pass_when_array_has_exactly_enough_elements() {
317        let left = json!([1, 2, 3]);
318        let right = json!(expect::array().min_len(3));
319
320        let output = expect_json_eq(&left, &right);
321        assert!(output.is_ok(), "assertion error: {output:#?}");
322    }
323
324    #[test]
325    fn it_should_pass_when_array_has_more_than_enough_elements() {
326        let left = json!([1, 2, 3, 4, 5]);
327        let right = json!(expect::array().min_len(3));
328
329        let output = expect_json_eq(&left, &right);
330        assert!(output.is_ok(), "assertion error: {output:#?}");
331    }
332
333    #[test]
334    fn it_should_fail_when_array_has_too_few_elements() {
335        let left = json!([1, 2, 3]);
336        let right = json!(expect::array().min_len(4));
337
338        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
339        assert_eq!(
340            output,
341            format!(
342                r#"Json expect::array() error at root:
343    expected array to have at least 4 elements, but it has 3.
344    received [1, 2, 3]"#
345            )
346        );
347    }
348}
349
350#[cfg(test)]
351mod test_len {
352    use crate::expect;
353    use crate::expect_json_eq;
354    use pretty_assertions::assert_eq;
355    use serde_json::json;
356
357    #[test]
358    fn it_should_pass_when_array_has_exactly_enough_elements() {
359        let left = json!([1, 2, 3]);
360        let right = json!(expect::array().len(3));
361
362        let output = expect_json_eq(&left, &right);
363        assert!(output.is_ok(), "assertion error: {output:#?}");
364    }
365
366    #[test]
367    fn it_should_fail_when_array_has_more_than_enough_elements() {
368        let left = json!([1, 2, 3, 4, 5]);
369        let right = json!(expect::array().len(3));
370
371        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
372        assert_eq!(
373            output,
374            format!(
375                r#"Json expect::array() error at root:
376    expected array to have 3 elements, but it has 5.
377    received [1, 2, 3, 4, 5]"#
378            )
379        );
380    }
381
382    #[test]
383    fn it_should_fail_when_array_has_too_few_elements() {
384        let left = json!([1, 2, 3]);
385        let right = json!(expect::array().len(4));
386
387        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
388        assert_eq!(
389            output,
390            format!(
391                r#"Json expect::array() error at root:
392    expected array to have 4 elements, but it has 3.
393    received [1, 2, 3]"#
394            )
395        );
396    }
397}
398
399#[cfg(test)]
400mod test_max_len {
401    use crate::expect;
402    use crate::expect_json_eq;
403    use pretty_assertions::assert_eq;
404    use serde_json::json;
405
406    #[test]
407    fn it_should_pass_when_array_has_exactly_enough_elements() {
408        let left = json!([1, 2, 3]);
409        let right = json!(expect::array().max_len(3));
410
411        let output = expect_json_eq(&left, &right);
412        assert!(output.is_ok(), "assertion error: {output:#?}");
413    }
414
415    #[test]
416    fn it_should_pass_when_array_has_less_than_enough_elements() {
417        let left = json!([1, 2]);
418        let right = json!(expect::array().max_len(6));
419
420        let output = expect_json_eq(&left, &right);
421        assert!(output.is_ok(), "assertion error: {output:#?}");
422    }
423
424    #[test]
425    fn it_should_fail_when_array_has_too_few_elements() {
426        let left = json!([1, 2, 3, 4]);
427        let right = json!(expect::array().max_len(3));
428
429        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
430        assert_eq!(
431            output,
432            format!(
433                r#"Json expect::array() error at root:
434    expected array to have at most 3 elements, but it has 4.
435    received [1, 2, 3, 4]"#
436            )
437        );
438    }
439}
440
441#[cfg(test)]
442mod test_all {
443    use crate::expect;
444    use crate::expect_json_eq;
445    use pretty_assertions::assert_eq;
446    use serde_json::json;
447
448    #[test]
449    fn it_should_pass_when_array_is_empty() {
450        let left = json!([]);
451        let right = json!(expect::array().all(expect::string()));
452
453        let output = expect_json_eq(&left, &right);
454        assert!(output.is_ok(), "assertion error: {output:#?}");
455    }
456
457    #[test]
458    fn it_should_pass_with_mix_of_operations() {
459        let left = json!([
460            "123e4567-e89b-12d3-a456-426614174000",
461            "123e4567-e89b-12d3-a456-426614174001",
462            "123e4567-e89b-12d3-a456-426614174002",
463        ]);
464        let right = json!(expect::array().all(expect::uuid()).len(3).unique());
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_with_mix_of_operations() {
472        let left = json!([
473            "123e4567-e89b-12d3-a456-426614174000",
474            "123e4567-e89b-12d3-a456-426614174001",
475            "123e4567-e89b-12d3-a456-426614174002",
476            "123e4567-e89b-12d3-a456-426614174003",
477        ]);
478        let right = json!(expect::array().all(expect::uuid()).len(3).unique());
479
480        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
481        assert_eq!(
482            output,
483            format!(
484                r#"Json expect::array() error at root:
485    expected array to have 3 elements, but it has 4.
486    received ["123e4567-e89b-12d3-a456-426614174000", "123e4567-e89b-12d3-a456-426614174001", "123e4567-e89b-12d3-a456-426614174002", "123e4567-e89b-12d3-a456-426614174003"]"#
487            )
488        );
489    }
490
491    #[test]
492    fn it_should_fail_when_array_values_do_not_match_expect_op() {
493        let left = json!([1, 2, 3]);
494        let right = json!(expect::array().all(expect::string()));
495
496        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
497        assert_eq!(
498            output,
499            format!(
500                r#"Json expect::string() at root[0], received wrong type:
501    expected string
502    received integer 1
503    received full array [1, 2, 3]"#
504            )
505        );
506    }
507
508    #[test]
509    fn it_should_fail_when_array_values_do_not_match_values() {
510        let left = json!([1, 2, 3]);
511        let right = json!(expect::array().all("🦊"));
512
513        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
514        assert_eq!(
515            output,
516            format!(
517                r#"Json values at root[0] are different types:
518    expected string "🦊"
519    received integer 1
520    received full array [1, 2, 3]"#
521            )
522        );
523    }
524
525    #[test]
526    fn it_should_pass_when_array_values_do_match_expect_op() {
527        let left = json!(["alice@example.com", "bob@example.com"]);
528        let right = json!(expect::array().all(expect::email()));
529
530        let output = expect_json_eq(&left, &right);
531        assert!(output.is_ok(), "assertion error: {output:#?}");
532    }
533
534    #[test]
535    fn it_should_pass_when_array_values_do_match_values() {
536        let left = json!([1, 1, 1]);
537        let right = json!(expect::array().all(1));
538
539        let output = expect_json_eq(&left, &right);
540        assert!(output.is_ok(), "assertion error: {output:#?}");
541    }
542
543    #[test]
544    fn it_should_pass_when_array_values_do_match_complex_objects() {
545        let left = json!([
546            {
547                "name": "Alice Candles",
548                "email": "alice@example.com"
549            },
550            {
551                "name": "Bob Kettles",
552                "email": "bob@example.com"
553            },
554        ]);
555
556        let right = json!(expect::array().all(json!({
557            "name": expect::string().is_not_empty(),
558            "email": expect::email(),
559        })));
560
561        let output = expect_json_eq(&left, &right);
562        assert!(output.is_ok(), "assertion error: {output:#?}");
563    }
564
565    #[test]
566    fn it_should_not_pass_when_array_values_do_not_match_complex_objects() {
567        let left = json!([
568            {
569                "name": "Alice Candles",
570                "email": "alice@example.com"
571            },
572            {
573                "name": "",
574                "email": "bob@example.com"
575            },
576        ]);
577
578        let right = json!(expect::array().all(json!({
579            "name": expect::string().is_not_empty(),
580            "email": expect::email(),
581        })));
582
583        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
584        assert_eq!(
585            output,
586            format!(
587                r#"Json expect::string() error at root[1].name:
588    expected non-empty string
589    received ""
590    received full array [
591        {{
592            "email": "alice@example.com",
593            "name": "Alice Candles"
594        }},
595        {{
596            "email": "bob@example.com",
597            "name": ""
598        }}
599    ]"#
600            )
601        );
602    }
603}
604
605#[cfg(test)]
606mod test_unique {
607    use crate::expect;
608    use crate::expect_json_eq;
609    use pretty_assertions::assert_eq;
610    use serde_json::json;
611
612    #[test]
613    fn it_should_pass_when_array_is_empty() {
614        let left = json!([]);
615        let right = json!(expect::array().unique());
616
617        let output = expect_json_eq(&left, &right);
618        assert!(output.is_ok(), "assertion error: {output:#?}");
619    }
620
621    #[test]
622    fn it_should_fail_when_array_is_not_unique() {
623        let left = json!([1, 1, 2]);
624        let right = json!(expect::array().unique());
625
626        let output = expect_json_eq(&left, &right).unwrap_err().to_string();
627        assert_eq!(
628            output,
629            format!(
630                r#"Json expect::array() error at root[1],
631    expected array to contain all unique values.
632    found duplicate 1
633    received full array [1, 1, 2]"#
634            )
635        );
636    }
637}