use crate::assertion::{Assertion, AssertionResult, Hand, UnprocessableReason};
use crate::dsl::http::*;
use crate::dsl::json_path::{JsonPathDsl, JsonPathResult};
use crate::dsl::{Expression, Part};
use crate::grillon::LogSettings;
use crate::Response;
use http::HeaderValue;
use http::{header::AsHeaderName, HeaderMap, StatusCode};
use serde_json::Value;
#[derive(Clone)]
pub struct Assert {
pub headers: Option<HeaderMap>,
pub status: Option<StatusCode>,
pub json: Option<Option<Value>>,
pub response_time_ms: Option<u64>,
pub log_settings: LogSettings,
}
impl Assert {
pub async fn new(
response: Option<impl Response>,
response_time_ms: Option<u64>,
log_settings: LogSettings,
) -> Self {
if let Some(response) = response {
return Assert {
headers: Some(response.headers().clone()),
status: Some(response.status()),
json: Some(response.json().await),
response_time_ms,
log_settings,
};
};
Assert {
headers: None,
status: None,
json: None,
response_time_ms: None,
log_settings,
}
}
pub fn assert_fn<F>(self, func: F) -> Assert
where
F: for<'a> Fn(&'a Assert),
{
func(&self);
self
}
pub fn status<T>(self, expr: Expression<T>) -> Assert
where
T: StatusCodeDsl<StatusCode>,
{
if let Some(status) = self.status {
let _assertion = expr.value.eval(status, expr.predicate, &self.log_settings);
}
self
}
pub fn json_body<T>(self, expr: Expression<T>) -> Assert
where
T: JsonBodyDsl<Value>,
{
if let Some(json) = &self.json {
let actual = if let Some(body) = json.clone() {
body
} else {
let assertion = Assertion {
part: Part::JsonPath,
predicate: expr.predicate,
left: Hand::Empty::<Value>,
right: Hand::Empty,
result: AssertionResult::Unprocessable(UnprocessableReason::MissingJsonBody),
};
assertion.assert(&self.log_settings);
return self;
};
let _assertion = expr.value.eval(actual, expr.predicate, &self.log_settings);
}
self
}
pub fn json_path<T>(self, path: &str, expr: Expression<T>) -> Assert
where
T: JsonPathDsl<Value>,
{
use jsonpath_rust::JsonPathQuery;
if let Some(json) = &self.json {
let json_body = if let Some(body) = json.clone() {
body
} else {
let assertion = Assertion {
part: Part::JsonPath,
predicate: expr.predicate,
left: Hand::Empty::<Value>,
right: Hand::Empty,
result: AssertionResult::Unprocessable(UnprocessableReason::MissingJsonBody),
};
assertion.assert(&self.log_settings);
return self;
};
let jsonpath_value = match json_body.path(path) {
Ok(json) => json,
Err(_) => {
let assertion = Assertion {
part: Part::JsonPath,
predicate: expr.predicate,
left: Hand::Empty::<Value>,
right: Hand::Empty,
result: AssertionResult::Unprocessable(
UnprocessableReason::InvalidJsonPath(path.to_string()),
),
};
assertion.assert(&self.log_settings);
return self;
}
};
let jsonpath_res = JsonPathResult::new(path, jsonpath_value);
let _assertion = expr
.value
.eval(jsonpath_res, expr.predicate, &self.log_settings);
}
self
}
pub fn response_time<T>(self, expr: Expression<T>) -> Assert
where
T: TimeDsl<u64>,
{
if let Some(response_time_ms) = self.response_time_ms {
let _assertion = expr
.value
.eval(response_time_ms, expr.predicate, &self.log_settings);
}
self
}
pub fn headers<T>(self, expr: Expression<T>) -> Assert
where
T: HeadersDsl<HeaderMap>,
{
if let Some(headers) = &self.headers {
let _assertion = expr
.value
.eval(headers.clone(), expr.predicate, &self.log_settings);
}
self
}
pub fn header<H, T>(self, header_name: H, expr: Expression<T>) -> Assert
where
H: AsHeaderName,
T: HeaderDsl<HeaderValue>,
{
if let Some(headers) = self.headers.clone() {
if let Some(actual_header_val) = headers.get(header_name) {
let _assertion = expr.value.eval(
actual_header_val.clone(),
expr.predicate,
&self.log_settings,
);
} else {
let assertion = Assertion {
part: Part::Header,
predicate: expr.predicate,
left: Hand::Empty::<&str>,
right: Hand::Empty,
result: AssertionResult::Unprocessable(UnprocessableReason::MissingHeader),
};
assertion.assert(&self.log_settings);
}
}
self
}
}