use serde::Deserialize;
use std::collections::HashMap;
use indexmap::IndexMap;
pub mod body_kind;
pub mod body_operator;
use super::util::fmt_condition_connector;
use crate::{
parsed_request::ParsedRequest,
util::json::json_value_by_jsonpath,
};
use body_kind::BodyKind;
use body_operator::BodyOperator;
#[derive(Clone, Debug, Deserialize)]
#[serde(transparent)]
pub struct Body(pub HashMap<BodyKind, IndexMap<String, BodyConditionStatement>>);
#[derive(Clone, Debug, Deserialize)]
pub struct BodyConditionStatement {
pub op: Option<BodyOperator>,
pub value: String,
}
impl std::fmt::Display for BodyConditionStatement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}`{}`", self.op.clone().unwrap_or_default(), self.value)
}
}
impl Body {
pub fn is_match(&self, parsed_request: &ParsedRequest) -> bool {
let request_body_json = match parsed_request.body_json.as_ref() {
Some(x) => x,
None => return false,
};
let matcher_body_json_condition = match self.0.get(&BodyKind::Json) {
Some(x) if !x.is_empty() => x,
_ => return false,
};
matcher_body_json_condition.iter().all(
|(matcher_json_condition_key, matcher_json_condition_statement)| {
let op = matcher_json_condition_statement
.op
.clone()
.unwrap_or_default();
if op == BodyOperator::Absent {
return json_value_by_jsonpath(
request_body_json,
matcher_json_condition_key,
)
.is_none();
}
let resolved = match json_value_by_jsonpath(
request_body_json,
matcher_json_condition_key,
) {
Some(v) => v,
None => return false,
};
op.is_match(resolved, &matcher_json_condition_statement.value)
},
)
}
pub fn validate(&self) -> bool {
if self.0.is_empty() {
return false;
}
for (_, body_kind_map) in self.0.iter() {
if body_kind_map.is_empty() {
return false;
}
}
true
}
}
impl std::fmt::Display for Body {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (body_kind, body_condition) in self.0.iter() {
let s = body_condition
.iter()
.map(|(key, statement)| format!("{}{}", key, statement))
.collect::<Vec<String>>()
.join(fmt_condition_connector().as_str());
let _ = write!(f, "[{}] {}", body_kind, s);
}
Ok(())
}
}
#[cfg(test)]
mod tests;