async_graphql_test/matchers/
should_contain.rs1use 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}