@Test
  public void should_not_match_against_non_matching_single_bean() {
    Person person = new Person("Bill", "Kidd");

    BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));
    BeanMatcher lastNameIsOddie = BeanMatchers.the("lastName", is("Oddie"));

    assertThat(BeanMatcherAsserts.matches(person, firstNameIsBill, lastNameIsOddie)).isFalse();
  }
  @Test
  public void should_match_against_a_single_bean() {
    Map<String, String> person = mappedPerson("Bill", "Oddie");

    BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));
    BeanMatcher lastNameIsOddie = BeanMatchers.the("lastName", is("Oddie"));

    assertThat(BeanMatcherAsserts.matches(person, firstNameIsBill, lastNameIsOddie)).isTrue();
  }
  @Test
  public void should_report_dodgy_field_if_cant_read_field_value() {
    DodgyBean person = new DodgyBean("Bill", "Kidd");

    expectedException.expect(IllegalArgumentException.class);
    expectedException.expectMessage(containsString("Could not find property value for firstName"));

    BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));
    BeanMatcher lastNameIsOddie = BeanMatchers.the("lastName", is("Oddie"));

    BeanMatcherAsserts.shouldMatch(person, firstNameIsBill, lastNameIsOddie);
  }
  @Test
  public void should_return_matching_element() {
    Map<String, String> bill = mappedPerson("Bill", "Oddie");
    Map<String, String> graham = mappedPerson("Graeam", "Garden");
    Map<String, String> tim = mappedPerson("Tim", "Brooke-Taylor");
    List<Map<String, String>> persons = Arrays.asList(bill, graham, tim);

    BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));
    BeanMatcher lastNameIsOddie = BeanMatchers.the("lastName", is("Oddie"));

    assertThat(BeanMatcherAsserts.filterElements(persons, firstNameIsBill, lastNameIsOddie))
        .contains(bill);
  }
  @Test
  public void should_fail_filter_if_no_matching_elements_found() {
    List<Map<String, String>> persons =
        Arrays.asList(
            mappedPerson("Bill", "Kidd"),
            mappedPerson("Graeam", "Garden"),
            mappedPerson("Tim", "Brooke-Taylor"));

    BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));
    BeanMatcher lastNameIsOddie = BeanMatchers.the("lastName", is("Oddie"));

    assertThat(BeanMatcherAsserts.matches(persons, firstNameIsBill, lastNameIsOddie)).isFalse();
  }
  @Test
  public void should_filter_list_of_beans_by_matchers() {
    List<Map<String, String>> persons =
        Arrays.asList(
            mappedPerson("Bill", "Oddie"),
            mappedPerson("Graeam", "Garden"),
            mappedPerson("Tim", "Brooke-Taylor"));

    BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));
    BeanMatcher lastNameIsOddie = BeanMatchers.the("lastName", is("Oddie"));

    assertThat(BeanMatcherAsserts.matches(persons, firstNameIsBill, lastNameIsOddie)).isTrue();
  }
  @Test
  public void should_check_the_size_of_a_collection_and_its_contents() {
    List<Map<String, String>> persons =
        Arrays.asList(
            mappedPerson("Bill", "Oddie"),
            mappedPerson("Bill", "Kidd"),
            mappedPerson("Graeam", "Garden"),
            mappedPerson("Tim", "Brooke-Taylor"));

    BeanMatcher containsTwoEntries = BeanMatchers.the_count(is(2));
    BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));

    BeanMatcherAsserts.shouldMatch(persons, containsTwoEntries, firstNameIsBill);
  }
 @Test
 public void should_obtain_instanciated_matcher_from_matcher() {
   Matcher<Object> matcher =
       ((BeanFieldMatcher) BeanMatchers.the("firstName", is("Bill"))).getMatcher();
   Person person = new Person("Bill", "Oddie");
   assertThat(matcher.matches(person)).isTrue();
 }
  @Test
  public void should_check_field_uniqueness() {
    List<Map<String, String>> persons =
        Arrays.asList(
            mappedPerson("Bill", "Oddie"),
            mappedPerson("Bill", "Kidd"),
            mappedPerson("Graeam", "Garden"),
            mappedPerson("Tim", "Brooke-Taylor"));

    BeanMatcher containsTwoEntries = BeanMatchers.the_count(is(2));
    BeanMatcher lastNamesAreDifferent = BeanMatchers.each("lastName").isDifferent();
    BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));

    BeanMatcherAsserts.shouldMatch(
        persons, containsTwoEntries, firstNameIsBill, lastNamesAreDifferent);
  }
  @Test
  public void should_raise_issue_if_fields_cant_be_introspected() {
    DodgyBean person = new DodgyBean("Bill", "Kidd");

    expectedException.expect(IllegalArgumentException.class);
    expectedException.expectMessage(containsString("Could not read bean properties"));

    BeanMatcher lastNameIsOddie = BeanMatchers.the("lastName", is("Oddie"));

    BeanMatcherAsserts.shouldMatch(person, lastNameIsOddie);
  }
  @Test
  public void should_fail_test_if_field_does_not_exist() {
    DodgyBean person = new DodgyBean("Bill", "Oddie");

    expectedException.expect(IllegalArgumentException.class);
    expectedException.expectMessage(
        containsString("Could not find property value for field-does-not-exist"));

    BeanMatcher lastNameIsOddie = BeanMatchers.the("field-does-not-exist", is("Oddie"));

    BeanMatcherAsserts.shouldMatch(person, lastNameIsOddie);
  }
  @Test
  public void should_return_no_elements_if_no_matching_elements_found() {
    Map<String, String> billoddie = mappedPerson("Bill", "Oddie");
    Map<String, String> billkidd = mappedPerson("Bill", "Kidd");
    Map<String, String> graham = mappedPerson("Graeam", "Garden");
    Map<String, String> tim = mappedPerson("Tim", "Brooke-Taylor");
    List<Map<String, String>> persons = Arrays.asList(billoddie, billkidd, graham, tim);

    BeanMatcher firstNameIsJoe = BeanMatchers.the("firstName", is("Joe"));

    assertThat(BeanMatcherAsserts.filterElements(persons, firstNameIsJoe)).isEmpty();
  }
  @Test
  public void should_display_detailed_diagnostics_when_a_single_bean_fails_to_match() {
    Person person = new Person("Bill", "Kidd");

    boolean assertionThrown = false;
    String exceptionMessage = null;
    try {
      BeanMatcher firstNameIsBill = BeanMatchers.the("firstName", is("Bill"));
      BeanMatcher lastNameIsOddie = BeanMatchers.the("lastName", is("Oddie"));

      BeanMatcherAsserts.shouldMatch(person, firstNameIsBill, lastNameIsOddie);
    } catch (AssertionError e) {
      assertionThrown = true;
      exceptionMessage = e.getMessage();
    }
    assertThat(assertionThrown, is(true));
    assertThat(
        exceptionMessage,
        allOf(
            containsString("Expected [firstName is 'Bill', lastName is 'Oddie'] but was"),
            containsString("firstName = 'Bill'"),
            containsString("lastName = 'Kidd")));
  }
 @Test
 public void should_obtain_matcher_from_fluent_static_method() {
   BeanFieldMatcher matcher = (BeanFieldMatcher) BeanMatchers.the("firstName", is("Bill"));
   Person person = new Person("Bill", "Oddie");
   assertThat(matcher.matches(person)).isTrue();
 }
 @Test
 public void instanciated_matcher_should_provide_meaningful_description() {
   Matcher<Object> matcher =
       ((BeanFieldMatcher) BeanMatchers.the("firstName", is("Bill"))).getMatcher();
   assertThat(matcher.toString()).isEqualTo("firstName is 'Bill'");
 }