use crate::core::style::{ALL_OK_HEADER, AT_LESAT_ONE_OK_HEADER};
use crate::core::{strings, style, Format, FormattedOutput, Formatter, Matcher};
use crate::matchers::combinators::{CombinatorContext, CombinatorMatcher, CombinatorMode};
use crate::matchers::SomeFailures;
use super::HeaderFormat;
#[non_exhaustive]
#[derive(Debug, Default)]
pub struct SomeFailuresFormat;
impl SomeFailuresFormat {
pub fn new() -> Self {
Self
}
}
impl Format for SomeFailuresFormat {
type Value = SomeFailures;
fn fmt(&self, f: &mut Formatter, value: Self::Value) -> crate::Result<()> {
let num_failures = value.len();
let failure_indent =
strings::whitespace((strings::int_len(num_failures, 10) + style::INDENT_LEN) as usize);
for (i, maybe_fail) in value.into_iter().enumerate() {
if let Some(fail) = maybe_fail {
f.set_style(style::index());
f.write_str(&format!(
"{}[{}] ",
strings::pad_int(i, num_failures, 10),
i,
));
f.reset_style();
f.set_style(style::failure());
f.write_str(style::FAILED_MSG);
f.reset_style();
f.write_char('\n');
f.write_fmt(FormattedOutput::from(fail).indented(failure_indent.as_ref()));
f.write_char('\n');
};
}
Ok(())
}
}
pub fn each<'a, T>(block: impl FnOnce(&mut CombinatorContext<T>) + 'a) -> Matcher<'a, T, T>
where
T: 'a,
{
Matcher::transform(
CombinatorMatcher::new(CombinatorMode::All, block),
HeaderFormat::new(
SomeFailuresFormat::new(),
ALL_OK_HEADER,
AT_LESAT_ONE_OK_HEADER,
),
)
}
#[cfg(test)]
mod tests {
use super::each;
use crate::{be_gt, be_lt, expect};
#[test]
fn succeeds_when_all_matchers_succeed() {
expect!(1).to(each(|ctx| ctx.copied().to(be_lt(2)).to(be_gt(0)).done()));
}
#[test]
fn succeeds_when_not_all_matchers_succeed() {
expect!(1).to_not(each(|ctx| ctx.copied().to(be_lt(0)).to(be_gt(0)).done()));
}
#[test]
#[should_panic]
fn fails_when_all_matchers_succeed() {
expect!(1).to_not(each(|ctx| ctx.copied().to(be_lt(2)).to(be_gt(0)).done()));
}
#[test]
#[should_panic]
fn fails_when_not_all_matchers_succeed() {
expect!(1).to(each(|ctx| ctx.copied().to(be_lt(0)).to(be_gt(0)).done()));
}
}