use std::fmt::{Display, Formatter};
use async_graphql::async_trait::async_trait;
use async_graphql::{Context, CustomDirective, Directive, ResolveFut, ServerResult, Value};
use super::MatcherError;
#[Directive(location = "Field", name = "shouldThrow")]
pub fn should_throw(
msg_like: Option<String>,
msg_like_regex: Option<String>,
) -> impl CustomDirective {
if let Some(sub) = msg_like {
return ShouldThrow::String(sub);
}
if let Some(regex) = msg_like_regex {
return ShouldThrow::Regex(
regex::Regex::new(®ex)
.map_err(|err| format!("incorrect regular expression: {err}"))
.unwrap(),
);
}
ShouldThrow::Wildcard
}
enum ShouldThrow {
Wildcard,
Regex(regex::Regex),
String(String),
}
impl Display for ShouldThrow {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ShouldThrow::Wildcard => write!(f, "*"),
ShouldThrow::Regex(regex) => write!(f, "/{regex}/"),
ShouldThrow::String(sub) => sub.fmt(f),
}
}
}
impl ShouldThrow {
pub fn matches(&self, text: &str) -> bool {
match self {
ShouldThrow::Wildcard => true,
ShouldThrow::String(sub) => text.contains(sub),
ShouldThrow::Regex(regex) => regex.is_match(text),
}
}
}
#[async_trait]
impl CustomDirective for ShouldThrow {
async fn resolve_field(
&self,
ctx: &Context<'_>,
resolve: ResolveFut<'_>,
) -> ServerResult<Option<Value>> {
match resolve.await {
Ok(_) => Err(MatcherError::new(
ctx.item.pos,
"Expected the function to throw an error.\nBut it didn't throw anything.".into(),
)),
Err(err) => {
if self.matches(&err.message) {
Ok(None)
} else {
Err(MatcherError::new(
ctx.item.pos,
format!("Expected: \"{self}\"\nReceived: \"{}\"", err.message),
))
}
}
}
}
}