use crate::JsonType;
use crate::expect::ops::ExpectArray;
use crate::expect_core::Context;
use crate::expect_core::ExpectOpError;
use crate::expect_core::ExpectOpResult;
use crate::internals::objects::ArrayObject;
use crate::internals::utils::bipartite_match;
use serde::Deserialize;
use serde::Serialize;
use serde_json::Value;
use std::collections::HashSet;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ExpectArraySubOp {
Empty,
NotEmpty,
MinLen(usize),
Len(usize),
MaxLen(usize),
Contains(Vec<Value>),
EqUnordered(Vec<Value>),
AllUnique,
AllEqual(Value),
}
impl ExpectArraySubOp {
pub(crate) fn on_array(
&self,
parent: &ExpectArray,
context: &mut Context<'_>,
received: &[Value],
) -> ExpectOpResult<()> {
match self {
Self::Empty => Self::on_array_empty(parent, context, received),
Self::NotEmpty => Self::on_array_not_empty(parent, context, received),
Self::MinLen(min_len) => Self::on_array_min_len(*min_len, parent, context, received),
Self::Len(len) => Self::on_array_len(*len, parent, context, received),
Self::MaxLen(max_len) => Self::on_array_max_len(*max_len, parent, context, received),
Self::Contains(expected_values) => {
Self::on_array_contains(expected_values, parent, context, received)
}
Self::EqUnordered(expected_values) => {
Self::on_array_eq_unordered(expected_values, parent, context, received)
}
Self::AllUnique => Self::on_array_unique(parent, context, received),
Self::AllEqual(expected_value) => {
Self::on_array_all_equal(expected_value, parent, context, received)
}
}
}
fn on_array_empty(
parent: &ExpectArray,
context: &mut Context<'_>,
received_values: &[Value],
) -> ExpectOpResult<()> {
if !received_values.is_empty() {
let error_message = format!(
r#"expected empty array
received {}"#,
ArrayObject::from(received_values.iter().cloned())
);
return Err(ExpectOpError::custom(parent, context, error_message));
}
Ok(())
}
fn on_array_not_empty(
parent: &ExpectArray,
context: &mut Context<'_>,
received_values: &[Value],
) -> ExpectOpResult<()> {
if received_values.is_empty() {
let error_message = format!(
r#"expected non-empty array
received {}"#,
ArrayObject::from(received_values.iter().cloned())
);
return Err(ExpectOpError::custom(parent, context, error_message));
}
Ok(())
}
fn on_array_min_len(
min_len: usize,
parent: &ExpectArray,
context: &mut Context<'_>,
received: &[Value],
) -> ExpectOpResult<()> {
if received.len() < min_len {
let error_message = format!(
r#"expected array to have at least {} elements, but it has {}.
received {}"#,
min_len,
received.len(),
ArrayObject::from(received.to_owned())
);
return Err(ExpectOpError::custom(parent, context, error_message));
}
Ok(())
}
fn on_array_len(
len: usize,
parent: &ExpectArray,
context: &mut Context<'_>,
received: &[Value],
) -> ExpectOpResult<()> {
if received.len() != len {
let error_message = format!(
r#"expected array to have {} elements, but it has {}.
received {}"#,
len,
received.len(),
ArrayObject::from(received.to_owned())
);
return Err(ExpectOpError::custom(parent, context, error_message));
}
Ok(())
}
fn on_array_max_len(
max_len: usize,
parent: &ExpectArray,
context: &mut Context<'_>,
received: &[Value],
) -> ExpectOpResult<()> {
if received.len() > max_len {
let error_message = format!(
r#"expected array to have at most {} elements, but it has {}.
received {}"#,
max_len,
received.len(),
ArrayObject::from(received.to_owned())
);
return Err(ExpectOpError::custom(parent, context, error_message));
}
Ok(())
}
fn on_array_contains(
expected_values: &[Value],
_parent: &ExpectArray,
context: &mut Context<'_>,
received_values: &[Value],
) -> ExpectOpResult<()> {
for expected in expected_values {
let is_found = received_values
.iter()
.any(|received| context.json_eq(received, expected).is_ok());
if !is_found {
return Err(ExpectOpError::ContainsNotFound {
context: context.to_static(),
json_type: JsonType::Array,
expected: expected.clone().into(),
received: ArrayObject::from(received_values.to_owned()).into(),
});
}
}
Ok(())
}
fn on_array_eq_unordered(
expected_values: &[Value],
_parent: &ExpectArray,
context: &mut Context<'_>,
received_values: &[Value],
) -> ExpectOpResult<()> {
if expected_values.len() != received_values.len() {
return Err(ExpectOpError::ArrayUnorderedMismatch {
context: context.to_static(),
expected_array: ArrayObject::from(expected_values.to_owned()),
received_array: ArrayObject::from(received_values.to_owned()),
});
}
let expected_len = expected_values.len();
let mut edges: Vec<(usize, usize)> = Vec::new();
for (expected_index, expected_value) in expected_values.iter().enumerate() {
for (received_index, received_value) in received_values.iter().enumerate() {
if context.json_eq(received_value, expected_value).is_ok() {
edges.push((expected_index, received_index));
}
}
}
let matches = bipartite_match(expected_len, &edges);
if matches.iter().any(|m| m.is_none()) {
return Err(ExpectOpError::ArrayUnorderedMismatch {
context: context.to_static(),
expected_array: ArrayObject::from(expected_values.to_owned()),
received_array: ArrayObject::from(received_values.to_owned()),
});
}
Ok(())
}
fn on_array_unique(
_parent: &ExpectArray,
context: &mut Context<'_>,
received_values: &[Value],
) -> ExpectOpResult<()> {
let mut seen = HashSet::<&Value>::new();
for (index, value) in received_values.iter().enumerate() {
let is_duplicate = !seen.insert(value);
if is_duplicate {
context.push(index);
return Err(ExpectOpError::ArrayContainsDuplicate {
context: context.to_static(),
duplicate: value.clone().into(),
received_array: ArrayObject::from(received_values.to_owned()),
});
}
}
Ok(())
}
fn on_array_all_equal(
expected_value: &Value,
_parent: &ExpectArray,
context: &mut Context<'_>,
received_values: &[Value],
) -> ExpectOpResult<()> {
for (index, value) in received_values.iter().enumerate() {
context
.with_path(index)
.json_eq(value, expected_value)
.map_err(|error| ExpectOpError::ArrayAllEqual {
error: Box::new(error),
received_full_array: ArrayObject::from(received_values.to_owned()),
})?;
}
Ok(())
}
}