use std::any::type_name;
use crate::core::style::{ALL_FIELDS_OK_HEADER, AT_LESAT_ONE_FIELD_OK_HEADER};
use crate::core::{style, Format, FormattedOutput, Formatter, Matcher};
use crate::matchers::combinators::CombinatorMode;
use crate::matchers::fields::{FieldMatcher, FieldsSpec};
use crate::matchers::FailuresByField;
use super::HeaderFormat;
#[derive(Debug)]
pub struct ByFieldFormat {
type_name: String,
}
impl ByFieldFormat {
pub fn new(type_name: impl Into<String>) -> Self {
Self {
type_name: type_name.into(),
}
}
}
impl Format for ByFieldFormat {
type Value = FailuresByField;
fn fmt(&self, f: &mut Formatter, value: Self::Value) -> crate::Result<()> {
f.write_str(format!("{} {{\n", &self.type_name));
for (field_name, maybe_fail) in value {
f.write_str(format!("{}{}: ", style::indent(1), field_name));
if let Some(fail) = maybe_fail {
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(style::indent(2)));
} else {
f.set_style(style::success());
f.write_str(style::OK_MSG);
f.reset_style();
f.write_char('\n');
}
}
f.write_char('}');
Ok(())
}
}
pub fn match_fields<'a, T>(spec: FieldsSpec<'a, T>) -> Matcher<'a, T, ()>
where
T: 'a,
{
Matcher::transform(
FieldMatcher::new(CombinatorMode::All, spec),
HeaderFormat::new(
ByFieldFormat::new(type_name::<T>()),
ALL_FIELDS_OK_HEADER,
AT_LESAT_ONE_FIELD_OK_HEADER,
),
)
}
pub fn match_any_fields<'a, T>(spec: FieldsSpec<'a, T>) -> Matcher<'a, T, ()>
where
T: 'a,
{
Matcher::transform(
FieldMatcher::new(CombinatorMode::Any, spec),
HeaderFormat::new(
ByFieldFormat::new(type_name::<T>()),
AT_LESAT_ONE_FIELD_OK_HEADER,
ALL_FIELDS_OK_HEADER,
),
)
}
#[cfg(test)]
mod tests {
use super::{match_any_fields, match_fields};
use crate::{equal, expect, fields};
struct Value {
foo: String,
bar: u32,
}
#[test]
fn succeeds_when_all_matchers_succeed() {
let value = Value {
foo: "some string".into(),
bar: 1,
};
expect!(value).to(match_fields(fields!(Value {
foo: equal("some string"),
bar: equal(1),
})));
}
#[test]
fn succeeds_when_not_all_matchers_succeed() {
let value = Value {
foo: "some string".into(),
bar: 1,
};
expect!(value).to_not(match_fields(fields!(Value {
foo: equal("a different string"),
bar: equal(2),
})));
}
#[test]
#[should_panic]
fn fails_when_all_matchers_succeed() {
let value = Value {
foo: "some string".into(),
bar: 1,
};
expect!(value).to_not(match_fields(fields!(Value {
foo: equal("some string"),
bar: equal(1),
})));
}
#[test]
#[should_panic]
fn fails_when_not_all_matchers_succeed() {
let value = Value {
foo: "some string".into(),
bar: 1,
};
expect!(value).to(match_fields(fields!(Value {
foo: equal("a different string"),
bar: equal(2),
})));
}
#[test]
fn succeeds_when_any_matchers_succeed() {
let value = Value {
foo: "some string".into(),
bar: 1,
};
expect!(value).to(match_any_fields(fields!(Value {
foo: equal("a different string"),
bar: equal(1),
})));
}
#[test]
fn succeeds_when_not_any_matchers_succeed() {
let value = Value {
foo: "some string".into(),
bar: 1,
};
expect!(value).to_not(match_any_fields(fields!(Value {
foo: equal("a different string"),
bar: equal(2),
})));
}
#[test]
#[should_panic]
fn fails_when_any_matchers_succeed() {
let value = Value {
foo: "some string".into(),
bar: 1,
};
expect!(value).to_not(match_any_fields(fields!(Value {
foo: equal("a different string"),
bar: equal(1),
})));
}
#[test]
#[should_panic]
fn fails_when_not_any_matchers_succeed() {
let value = Value {
foo: "some string".into(),
bar: 1,
};
expect!(value).to(match_any_fields(fields!(Value {
foo: equal("a different string"),
bar: equal(2),
})));
}
}