Skip to main content

async_graphql_test/matchers/
should_contain.rs

1use std::fmt::{Display, Formatter};
2
3use async_graphql::async_trait::async_trait;
4use async_graphql::{Any, Context, CustomDirective, Directive, ResolveFut, ServerResult, Value};
5
6use super::{MatcherError, ValueTypeName};
7
8#[Directive(location = "Field", name = "shouldContain")]
9pub fn should_contain(item: Any) -> impl CustomDirective {
10    ShouldContain { item: item.0 }
11}
12
13struct ShouldContain {
14    item: Value,
15}
16
17impl Display for ShouldContain {
18    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
19        self.item.fmt(f)
20    }
21}
22
23#[async_trait]
24impl CustomDirective for ShouldContain {
25    async fn resolve_field(
26        &self,
27        ctx: &Context<'_>,
28        resolve: ResolveFut<'_>,
29    ) -> ServerResult<Option<Value>> {
30        match resolve.await {
31            Ok(None) => Ok(None),
32            Ok(Some(Value::List(list))) => {
33                if list.iter().any(|it| self.item.eq(it)) {
34                    Ok(Some(Value::List(list)))
35                } else {
36                    Err(MatcherError::new(
37                        ctx.item.pos,
38                        format!(
39                            "Expected value: {}\nReceived array: {}",
40                            self.item,
41                            Value::List(list)
42                        ),
43                    ))
44                }
45            }
46            Ok(Some(Value::String(string))) => {
47                if let Value::String(value) = &self.item {
48                    if string.contains(value) {
49                        Ok(Some(Value::String(string)))
50                    } else {
51                        Err(MatcherError::new(
52                            ctx.item.pos,
53                            format!(
54                                "Expected value to match:\n  {self}\nReceived:\n  \"{string}\""
55                            ),
56                        ))
57                    }
58                } else {
59                    let type_name = ValueTypeName(&self.item);
60                    Err(MatcherError::new(
61                        ctx.item.pos,
62                        format!(
63                            "@shouldContain error: passed value must be a string.\nPassed has type:  {type_name}\nReceived has value: {self}"
64                        ),
65                    ))
66                }
67            }
68            Ok(Some(value)) => {
69                let type_name = ValueTypeName(&value);
70                Err(MatcherError::new(
71                    ctx.item.pos,
72                    format!(
73                        "@shouldContain error: received value must be an array or a string.\nReceived has type:  {type_name}\nReceived has value: {value}"
74                    ),
75                ))
76            }
77            Err(err) => Err(MatcherError::unexpected_error(err)),
78        }
79    }
80}