All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fitbur.assertj.api.AbstractIterableAssert Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
/**
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * Copyright 2012-2016 the original author or authors.
 */
package com.fitbur.assertj.api;

import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.stream;
import static com.fitbur.assertj.api.filter.Filters.filter;
import static com.fitbur.assertj.extractor.Extractors.byName;
import static com.fitbur.assertj.extractor.Extractors.resultOf;
import static com.fitbur.assertj.util.Arrays.isArray;
import static com.fitbur.assertj.util.IterableUtil.toArray;
import static com.fitbur.assertj.util.Lists.newArrayList;
import static com.fitbur.assertj.util.Preconditions.checkNotNull;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

import com.fitbur.assertj.api.filter.FilterOperator;
import com.fitbur.assertj.api.filter.Filters;
import com.fitbur.assertj.api.iterable.Extractor;
import com.fitbur.assertj.condition.Not;
import com.fitbur.assertj.description.Description;
import com.fitbur.assertj.groups.FieldsOrPropertiesExtractor;
import com.fitbur.assertj.groups.Tuple;
import com.fitbur.assertj.internal.CommonErrors;
import com.fitbur.assertj.internal.ComparatorBasedComparisonStrategy;
import com.fitbur.assertj.internal.ComparisonStrategy;
import com.fitbur.assertj.internal.FieldByFieldComparator;
import com.fitbur.assertj.internal.IgnoringFieldsComparator;
import com.fitbur.assertj.internal.IterableElementComparisonStrategy;
import com.fitbur.assertj.internal.Iterables;
import com.fitbur.assertj.internal.ObjectArrays;
import com.fitbur.assertj.internal.Objects;
import com.fitbur.assertj.internal.OnFieldsComparator;
import com.fitbur.assertj.util.VisibleForTesting;
import com.fitbur.assertj.util.introspection.IntrospectionError;

/**
 * Base class for implementations of {@link ObjectEnumerableAssert} whose actual value type is
 * {@link Collection}.
 *
 * @param  the "self" type of this assertion class. Please read "Emulating 'self types' using Java Generics to simplify fluent API implementation"
 *          for more details.
 * @param  the type of the "actual" value.
 * @param  the type of elements of the "actual" value.
 * @author Yvonne Wang
 * @author Alex Ruiz
 * @author Mathieu Baechler
 * @author Joel Costigliola
 * @author Maciej Jaskowski
 * @author Nicolas François
 * @author Mikhail Mazursky
 * @author Mateusz Haligowski
 * @author Lovro Pandzic
 */
public abstract class AbstractIterableAssert, A extends Iterable, T>
    extends AbstractAssert implements ObjectEnumerableAssert {

  @VisibleForTesting
  Iterables iterables = Iterables.instance();

  protected AbstractIterableAssert(A actual, Class selfType) {
    super(actual, selfType);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void isNullOrEmpty() {
    iterables.assertNullOrEmpty(info, actual);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void isEmpty() {
    iterables.assertEmpty(info, actual);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S isNotEmpty() {
    iterables.assertNotEmpty(info, actual);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S hasSize(int expected) {
    iterables.assertHasSize(info, actual, expected);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S hasSameSizeAs(Object other) {
    iterables.assertHasSameSizeAs(info, actual, other);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S hasSameSizeAs(Iterable other) {
    iterables.assertHasSameSizeAs(info, actual, other);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S contains(@SuppressWarnings("unchecked") T... values) {
    iterables.assertContains(info, actual, values);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S containsOnly(@SuppressWarnings("unchecked") T... values) {
    iterables.assertContainsOnly(info, actual, values);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S containsOnlyOnce(@SuppressWarnings("unchecked") T... values) {
    iterables.assertContainsOnlyOnce(info, actual, values);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S containsExactly(@SuppressWarnings("unchecked") T... values) {
    iterables.assertContainsExactly(info, actual, values);
    return myself;
  }

  /** {@inheritDoc} */
  @Override
  public S containsExactlyInAnyOrder(@SuppressWarnings("unchecked") T... values) {
    iterables.assertContainsExactlyInAnyOrder(info, actual, values);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S isSubsetOf(Iterable values) {
    iterables.assertIsSubsetOf(info, actual, values);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S isSubsetOf(@SuppressWarnings("unchecked") T... values) {
    iterables.assertIsSubsetOf(info, actual, Arrays.asList(values));
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S containsSequence(@SuppressWarnings("unchecked") T... sequence) {
    iterables.assertContainsSequence(info, actual, sequence);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S containsSubsequence(@SuppressWarnings("unchecked") T... sequence) {
    iterables.assertContainsSubsequence(info, actual, sequence);
    return myself;
  }

  @Override
  public S doesNotContain(@SuppressWarnings("unchecked") T... values) {
    iterables.assertDoesNotContain(info, actual, values);
    return myself;
  }

  @Override
  public S doesNotContainAnyElementsOf(Iterable iterable) {
    iterables.assertDoesNotContainAnyElementsOf(info, actual, iterable);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S doesNotHaveDuplicates() {
    iterables.assertDoesNotHaveDuplicates(info, actual);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S startsWith(@SuppressWarnings("unchecked") T... sequence) {
    iterables.assertStartsWith(info, actual, sequence);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S endsWith(@SuppressWarnings("unchecked") T... sequence) {
    iterables.assertEndsWith(info, actual, sequence);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S containsNull() {
    iterables.assertContainsNull(info, actual);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S doesNotContainNull() {
    iterables.assertDoesNotContainNull(info, actual);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S are(Condition condition) {
    iterables.assertAre(info, actual, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S areNot(Condition condition) {
    iterables.assertAreNot(info, actual, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S have(Condition condition) {
    iterables.assertHave(info, actual, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S doNotHave(Condition condition) {
    iterables.assertDoNotHave(info, actual, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S areAtLeastOne(Condition condition) {
    areAtLeast(1, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S areAtLeast(int times, Condition condition) {
    iterables.assertAreAtLeast(info, actual, times, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S areAtMost(int times, Condition condition) {
    iterables.assertAreAtMost(info, actual, times, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S areExactly(int times, Condition condition) {
    iterables.assertAreExactly(info, actual, times, condition);
    return myself;
  }

  /** {@inheritDoc} */
  @Override
  public S haveAtLeastOne(Condition condition) {
    return haveAtLeast(1, condition);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S haveAtLeast(int times, Condition condition) {
    iterables.assertHaveAtLeast(info, actual, times, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S haveAtMost(int times, Condition condition) {
    iterables.assertHaveAtMost(info, actual, times, condition);
    return myself;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public S haveExactly(int times, Condition condition) {
    iterables.assertHaveExactly(info, actual, times, condition);
    return myself;
  }

  /**
   * Verifies that at least one element in the actual {@code Iterable} belong to the specified type (matching includes
   * subclasses of the given type).
   * 

* Example: *

 List<Number> numbers = new ArrayList<Number>();
   * numbers.add(1);
   * numbers.add(2L);
   * 
   * // successful assertion:
   * assertThat(numbers).hasAtLeastOneElementOfType(Long.class);
   * 
   * // assertion failure:
   * assertThat(numbers).hasAtLeastOneElementOfType(Float.class);
* * @param expectedType the expected type. * @return this assertion object. * @throws NullPointerException if the given type is {@code null}. * @throws AssertionError if the actual {@code Object} group does not have any elements of the given type. */ @Override public S hasAtLeastOneElementOfType(Class expectedType) { // reuse code from object arrays as the logic is the same // (ok since this assertion don't rely on comparison strategy) ObjectArrays.instance().assertHasAtLeastOneElementOfType(info, toArray(actual), expectedType); return myself; } /** * Verifies that all the elements in the actual {@code Iterable} belong to the specified type (matching includes * subclasses of the given type). *

* Example: *

 List<Number> numbers = new ArrayList<Number>();
   * numbers.add(1);
   * numbers.add(2);
   * numbers.add(3);
   * 
   * // successful assertion:
   * assertThat(numbers).hasOnlyElementsOfType(Number.class);
   * assertThat(numbers).hasOnlyElementsOfType(Integer.class);
   * 
   * // assertion failure:
   * assertThat(numbers).hasOnlyElementsOfType(Long.class);
* * @param expectedType the expected type. * @return this assertion object. * @throws NullPointerException if the given type is {@code null}. * @throws AssertionError if one element is not of the expected type. */ @Override public S hasOnlyElementsOfType(Class expectedType) { // reuse code from object arrays as the logic is the same // (ok since this assertion don't rely on comparison strategy) ObjectArrays.instance().assertHasOnlyElementsOfType(info, toArray(actual), expectedType); return myself; } /** * {@inheritDoc} */ @Override public S containsAll(Iterable iterable) { iterables.assertContainsAll(info, actual, iterable); return myself; } /** * {@inheritDoc} */ @Override public S usingElementComparator(Comparator elementComparator) { this.iterables = new Iterables(new ComparatorBasedComparisonStrategy(elementComparator)); // to have the same semantics on base assertions like isEqualTo, we need to use an iterable comparator comparing // elements with elementComparator parameter objects = new Objects(new IterableElementComparisonStrategy<>(elementComparator)); return myself; } /** * {@inheritDoc} */ @Override public S usingDefaultElementComparator() { usingDefaultComparator(); this.iterables = Iterables.instance(); return myself; } /** * Extract the values of given field or property from the Iterable's elements under test into a new Iterable, this new * Iterable becoming the Iterable under test. *

* It allows you to test a property/field of the the Iterable's elements instead of testing the elements themselves, * it can be sometimes much less work ! *

* Let's take an example to make things clearer : *

 // Build a list of TolkienCharacter, a TolkienCharacter has a name, and age and a Race (a specific class)
   * // they can be public field or properties, both can be extracted.
   * List<TolkienCharacter> fellowshipOfTheRing = new ArrayList<TolkienCharacter>();
   * 
   * fellowshipOfTheRing.add(new TolkienCharacter("Frodo", 33, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Sam", 38, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gandalf", 2020, MAIA));
   * fellowshipOfTheRing.add(new TolkienCharacter("Legolas", 1000, ELF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Pippin", 28, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gimli", 139, DWARF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Aragorn", 87, MAN);
   * fellowshipOfTheRing.add(new TolkienCharacter("Boromir", 37, MAN));
   * 
   * // let's verify the names of TolkienCharacter in fellowshipOfTheRing :
   * 
   * assertThat(fellowshipOfTheRing).extracting("name")
   *           .contains("Boromir", "Gandalf", "Frodo")
   *           .doesNotContain("Sauron", "Elrond");
   * 
   * // you can extract nested property/field like the name of Race :
   * 
   * assertThat(fellowshipOfTheRing).extracting("race.name")
   *                                .contains("Hobbit", "Elf")
   *                                .doesNotContain("Orc");
*

* A property with the given name is looked for first, if it doesn't exist then a field with the given name is looked * for, if the field does not exist an {@link IntrospectionError} is thrown, by default private fields are read but * you can change this with {@link Assertions#setAllowComparingPrivateFields(boolean)}, trying to read a private field * when it's not allowed leads to an {@link IntrospectionError}. *

* Note that the order of extracted property/field values is consistent with the iteration order of the Iterable under * test, for example if it's a {@link HashSet}, you won't be able to make any assumptions on the extracted values * order. *


*

* Extracting also support maps, that is, instead of extracting values from an Object, it extract maps values * corresponding to the given keys. *

* Example: *

 Employee yoda = new Employee(1L, new Name("Yoda"), 800);
   * Employee luke = new Employee(2L, new Name("Luke"), 22);
   * Employee han = new Employee(3L, new Name("Han"), 31);
   * 
   * // build two maps
   * Map<String, Employee> map1 = new HashMap<>();
   * map1.put("key1", yoda);
   * map1.put("key2", luke);
   * 
   * Map<String, Employee> map2 = new HashMap<>();
   * map2.put("key1", yoda);
   * map2.put("key2", han);
   * 
   * // instead of a list of objects, we have a list of maps 
   * List<Map<String, Employee>> maps = asList(map1, map2);
   * 
   * // extracting a property in that case = get values from maps using property as a key
   * assertThat(maps).extracting("key2").containsExactly(luke, han);
   * assertThat(maps).extracting("key1").containsExactly(yoda, yoda);
   * 
   * // type safe version
   * assertThat(maps).extracting(key2, Employee.class).containsExactly(luke, han); 
   * 
   * // it works with several keys, extracted values being wrapped in a Tuple
   * assertThat(maps).extracting("key1", "key2").containsExactly(tuple(yoda, luke), tuple(yoda, han));
   * 
   * // unknown keys leads to null (map behavior)
   * assertThat(maps).extracting("bad key").containsExactly(null, null);
* * @param propertyOrField the property/field to extract from the elements of the Iterable under test * @return a new assertion object whose object under test is the list of extracted property/field values. * @throws IntrospectionError if no field or property exists with the given name in one of the initial * Iterable's element. */ public ListAssert extracting(String propertyOrField) { List values = FieldsOrPropertiesExtractor.extract(actual, byName(propertyOrField)); return new ListAssert<>(values); } /** * Extract the result of given method invocation on the Iterable's elements under test into a new Iterable, this new * Iterable becoming the Iterable under test. *

* It allows you to test the method results of the Iterable's elements instead of testing the elements themselves, it * is especially useful for classes that does not conform to Java Bean's getter specification (i.e. public String * toString() or public String status() instead of public String getStatus()). *

* Let's take an example to make things clearer : *

 // Build a array of WesterosHouse, a WesterosHouse has a method: public String sayTheWords()
   * 
   * List<WesterosHouse> greatHouses = new ArrayList<WesterosHouse>();
   * greatHouses.add(new WesterosHouse("Stark", "Winter is Coming"));
   * greatHouses.add(new WesterosHouse("Lannister", "Hear Me Roar!"));
   * greatHouses.add(new WesterosHouse("Greyjoy", "We Do Not Sow"));
   * greatHouses.add(new WesterosHouse("Baratheon", "Our is the Fury"));
   * greatHouses.add(new WesterosHouse("Martell", "Unbowed, Unbent, Unbroken"));
   * greatHouses.add(new WesterosHouse("Tyrell", "Growing Strong"));
   * 
   * // let's verify the words of the great houses of Westeros:
   * assertThat(greatHouses).extractingResultOf("sayTheWords")
   *                        .contains("Winter is Coming", "We Do Not Sow", "Hear Me Roar")
   *                        .doesNotContain("Lannisters always pay their debts");
* * Following requirements have to be met to extract method results: *
    *
  • method has to be public,
  • *
  • method cannot accept any arguments,
  • *
  • method cannot return void.
  • *
*

* Note that the order of extracted results is consistent with the iteration order of the Iterable under test, for * example if it's a {@link HashSet}, you won't be able to make any assumptions on the extracted results order. * * @param method the name of the method which result is to be extracted from the array under test * @return a new assertion object whose object under test is the Iterable of extracted values. * @throws IllegalArgumentException if no method exists with the given name, or method is not public, or method does * return void, or method accepts arguments. */ public ListAssert extractingResultOf(String method) { List values = FieldsOrPropertiesExtractor.extract(actual, resultOf(method)); return new ListAssert<>(values); } /** * Extract the result of given method invocation on the Iterable's elements under test into a new list of the given * class, this new List becoming the object under test. *

* It allows you to test the method results of the Iterable's elements instead of testing the elements themselves, it * is especially useful for classes that does not conform to Java Bean's getter specification (i.e. public String * toString() or public String status() instead of public String getStatus()). *

* Let's take an example to make things clearer : *

 // Build a array of WesterosHouse, a WesterosHouse has a method: public String sayTheWords()
   * List<WesterosHouse> greatHouses = new ArrayList<WesterosHouse>();
   * greatHouses.add(new WesterosHouse("Stark", "Winter is Coming"));
   * greatHouses.add(new WesterosHouse("Lannister", "Hear Me Roar!"));
   * greatHouses.add(new WesterosHouse("Greyjoy", "We Do Not Sow"));
   * greatHouses.add(new WesterosHouse("Baratheon", "Our is the Fury"));
   * greatHouses.add(new WesterosHouse("Martell", "Unbowed, Unbent, Unbroken"));
   * greatHouses.add(new WesterosHouse("Tyrell", "Growing Strong"));
   * 
   * // let's verify the words of the great houses of Westeros:
   * assertThat(greatHouses).extractingResultOf("sayTheWords", String.class)
   *                        .contains("Winter is Coming", "We Do Not Sow", "Hear Me Roar")
   *                        .doesNotContain("Lannisters always pay their debts");
* * Following requirements have to be met to extract method results: *
    *
  • method has to be public,
  • *
  • method cannot accept any arguments,
  • *
  • method cannot return void.
  • *
*

* Note that the order of extracted property/field values is consistent with the iteration order of the Iterable under * test, for example if it's a {@link HashSet}, you won't be able to make any assumptions of the extracted values * order. * * @param method the name of the method which result is to be extracted from the array under test * @param extractedType type of element of the extracted List * @return a new assertion object whose object under test is the Iterable of extracted values. * @throws IllegalArgumentException if no method exists with the given name, or method is not public, or method does * return void or method accepts arguments. */ public

ListAssert

extractingResultOf(String method, Class

extractedType) { @SuppressWarnings("unchecked") List

values = (List

) FieldsOrPropertiesExtractor.extract(actual, resultOf(method)); return new ListAssert<>(values); } /** * Extract the values of given field or property from the Iterable's elements under test into a new Iterable, this new * Iterable becoming the Iterable under test. *

* It allows you to test a property/field of the the Iterable's elements instead of testing the elements themselves, * it can be sometimes much less work ! *

* Let's take an example to make things clearer : *

 // Build a list of TolkienCharacter, a TolkienCharacter has a name, and age and a Race (a specific class)
   * // they can be public field or properties, both can be extracted.
   * List<TolkienCharacter> fellowshipOfTheRing = new ArrayList<TolkienCharacter>();
   * 
   * fellowshipOfTheRing.add(new TolkienCharacter("Frodo", 33, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Sam", 38, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gandalf", 2020, MAIA));
   * fellowshipOfTheRing.add(new TolkienCharacter("Legolas", 1000, ELF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Pippin", 28, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gimli", 139, DWARF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Aragorn", 87, MAN);
   * fellowshipOfTheRing.add(new TolkienCharacter("Boromir", 37, MAN));
   * 
   * // let's verify the names of TolkienCharacter in fellowshipOfTheRing :
   * assertThat(fellowshipOfTheRing).extracting("name", String.class)
   *           .contains("Boromir", "Gandalf", "Frodo")
   *           .doesNotContain("Sauron", "Elrond");
   * 
   * // you can extract nested property/field like the name of Race :
   * assertThat(fellowshipOfTheRing).extracting("race.name", String.class)
   *                                .contains("Hobbit", "Elf")
   *                                .doesNotContain("Orc");
* * A property with the given name is looked for first, if it doesn't exist then a field with the given name is looked * for, if the field does not exist an {@link IntrospectionError} is thrown, by default private fields are read but * you can change this with {@link Assertions#setAllowComparingPrivateFields(boolean)}, trying to read a private field * when it's not allowed leads to an {@link IntrospectionError}. *

* Note that the order of extracted property/field values is consistent with the iteration order of the Iterable under * test, for example if it's a {@link HashSet}, you won't be able to make any assumptions on the extracted values * order. *


*

* Extracting also support maps, that is, instead of extracting values from an Object, it extract maps values * corresponding to the given keys. *

* Example: *

 Employee yoda = new Employee(1L, new Name("Yoda"), 800);
   * Employee luke = new Employee(2L, new Name("Luke"), 22);
   * Employee han = new Employee(3L, new Name("Han"), 31);
   * 
   * // build two maps
   * Map<String, Employee> map1 = new HashMap<>();
   * map1.put("key1", yoda);
   * map1.put("key2", luke);
   * 
   * Map<String, Employee> map2 = new HashMap<>();
   * map2.put("key1", yoda);
   * map2.put("key2", han);
   * 
   * // instead of a list of objects, we have a list of maps 
   * List<Map<String, Employee>> maps = asList(map1, map2);
   * 
   * // extracting a property in that case = get values from maps using property as a key
   * assertThat(maps).extracting(key2, Employee.class).containsExactly(luke, han); 
   * 
   * // non type safe version
   * assertThat(maps).extracting("key2").containsExactly(luke, han);
   * assertThat(maps).extracting("key1").containsExactly(yoda, yoda);
   * 
   * // it works with several keys, extracted values being wrapped in a Tuple
   * assertThat(maps).extracting("key1", "key2").containsExactly(tuple(yoda, luke), tuple(yoda, han));
   * 
   * // unknown keys leads to null (map behavior)
   * assertThat(maps).extracting("bad key").containsExactly(null, null);
* * @param propertyOrField the property/field to extract from the Iterable under test * @param extractingType type to return * @return a new assertion object whose object under test is the list of extracted property/field values. * @throws IntrospectionError if no field or property exists with the given name in one of the initial * Iterable's element. */ public

ListAssert

extracting(String propertyOrField, Class

extractingType) { @SuppressWarnings("unchecked") List

values = (List

) FieldsOrPropertiesExtractor.extract(actual, byName(propertyOrField)); return new ListAssert<>(values); } /** * Extract the values of given fields/properties from the Iterable's elements under test into a new Iterable composed * of Tuple (a simple data structure), this new Iterable becoming the Iterable under test. *

* It allows you to test fields/properties of the the Iterable's elements instead of testing the elements themselves, * it can be sometimes much less work! *

* The Tuple data corresponds to the extracted values of the given fields/properties, for instance if you ask to * extract "id", "name" and "email" then each Tuple data will be composed of id, name and email extracted from the * element of the initial Iterable (the Tuple's data order is the same as the given fields/properties order). *

* Let's take an example to make things clearer : *

 // Build a list of TolkienCharacter, a TolkienCharacter has a name, and age and a Race (a specific class)
   * // they can be public field or properties, both can be extracted.
   * List<TolkienCharacter> fellowshipOfTheRing = new ArrayList<TolkienCharacter>();
   * 
   * fellowshipOfTheRing.add(new TolkienCharacter("Frodo", 33, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Sam", 38, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gandalf", 2020, MAIA));
   * fellowshipOfTheRing.add(new TolkienCharacter("Legolas", 1000, ELF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Pippin", 28, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gimli", 139, DWARF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Aragorn", 87, MAN);
   * fellowshipOfTheRing.add(new TolkienCharacter("Boromir", 37, MAN));
   * 
   * // let's verify 'name' and 'age' of some TolkienCharacter in fellowshipOfTheRing :
   * assertThat(fellowshipOfTheRing).extracting("name", "age")
   *                                .contains(tuple("Boromir", 37),
   *                                          tuple("Sam", 38),
   *                                          tuple("Legolas", 1000));
   * 
   * 
   * // extract 'name', 'age' and Race name values :
   * assertThat(fellowshipOfTheRing).extracting("name", "age", "race.name")
   *                                .contains(tuple("Boromir", 37, "Man"),
   *                                          tuple("Sam", 38, "Hobbit"),
   *                                          tuple("Legolas", 1000, "Elf"));
* * A property with the given name is looked for first, if it doesn't exist then a field with the given name is looked * for, if the field does not exist an {@link IntrospectionError} is thrown, by default private fields are read but * you can change this with {@link Assertions#setAllowComparingPrivateFields(boolean)}, trying to read a private field * when it's not allowed leads to an {@link IntrospectionError}. *

* Note that the order of extracted property/field values is consistent with the iteration order of the Iterable under * test, for example if it's a {@link HashSet}, you won't be able to make any assumptions on the extracted values * order. *


*

* Extracting also support maps, that is, instead of extracting values from an Object, it extract maps values * corresponding to the given keys. *

* Example: *

 Employee yoda = new Employee(1L, new Name("Yoda"), 800);
   * Employee luke = new Employee(2L, new Name("Luke"), 22);
   * Employee han = new Employee(3L, new Name("Han"), 31);
   * 
   * // build two maps
   * Map<String, Employee> map1 = new HashMap<>();
   * map1.put("key1", yoda);
   * map1.put("key2", luke);
   * 
   * Map<String, Employee> map2 = new HashMap<>();
   * map2.put("key1", yoda);
   * map2.put("key2", han);
   * 
   * // instead of a list of objects, we have a list of maps 
   * List<Map<String, Employee>> maps = asList(map1, map2);
   * 
   * // extracting a property in that case = get values from maps using property as a key
   * assertThat(maps).extracting("key2").containsExactly(luke, han);
   * assertThat(maps).extracting("key1").containsExactly(yoda, yoda);
   * 
   * // it works with several keys, extracted values being wrapped in a Tuple
   * assertThat(maps).extracting("key1", "key2").containsExactly(tuple(yoda, luke), tuple(yoda, han));
   * 
   * // unknown keys leads to null (map behavior)
   * assertThat(maps).extracting("bad key").containsExactly(null, null);
* * @param propertiesOrFields the properties/fields to extract from the elements of the Iterable under test * @return a new assertion object whose object under test is the list of Tuple with extracted properties/fields values * as data. * @throws IntrospectionError if one of the given name does not match a field or property in one of the initial * Iterable's element. */ public ListAssert extracting(String... propertiesOrFields) { List values = FieldsOrPropertiesExtractor.extract(actual, byName(propertiesOrFields)); return new ListAssert<>(values); } /** * Extract the values from Iterable's elements under test by applying an extracting function on them. The returned * iterable becomes a new object under test. *

* It allows to test values from the elements in more safe way than by using {@link #extracting(String)}, as it * doesn't utilize introspection. *

* Let's have a look at an example : *

 // Build a list of TolkienCharacter, a TolkienCharacter has a name, and age and a Race (a specific class)
   * // they can be public field or properties, both can be extracted.
   * List<TolkienCharacter> fellowshipOfTheRing = new ArrayList<TolkienCharacter>();
   * 
   * fellowshipOfTheRing.add(new TolkienCharacter("Frodo", 33, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Sam", 38, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gandalf", 2020, MAIA));
   * fellowshipOfTheRing.add(new TolkienCharacter("Legolas", 1000, ELF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Pippin", 28, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gimli", 139, DWARF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Aragorn", 87, MAN);
   * fellowshipOfTheRing.add(new TolkienCharacter("Boromir", 37, MAN));
   * 
   * // fellowship has hobbitses, right, my presioussss?
   * assertThat(fellowshipOfTheRing).extracting(TolkienCharacter::getRace).contains(HOBBIT);
* * Note that the order of extracted property/field values is consistent with the iteration order of the Iterable under * test, for example if it's a {@link HashSet}, you won't be able to make any assumptions on the extracted values * order. * * @param extractor the object transforming input object to desired one * @return a new assertion object whose object under test is the list of values extracted */ public ListAssert extracting(Extractor extractor) { List values = FieldsOrPropertiesExtractor.extract(actual, extractor); return new ListAssert<>(values); } /** * Extract the Iterable values from Iterable's elements under test by applying an Iterable extracting function on them * and concatenating the result lists. The returned iterable becomes a new object under test. *

* It allows testing the results of extracting values that are represented by Iterables. *

* For example: *

 CartoonCharacter bart = new CartoonCharacter("Bart Simpson");
   * CartoonCharacter lisa = new CartoonCharacter("Lisa Simpson");
   * CartoonCharacter maggie = new CartoonCharacter("Maggie Simpson");
   * CartoonCharacter homer = new CartoonCharacter("Homer Simpson");
   * homer.addChildren(bart, lisa, maggie);
   * 
   * CartoonCharacter pebbles = new CartoonCharacter("Pebbles Flintstone");
   * CartoonCharacter fred = new CartoonCharacter("Fred Flintstone");
   * fred.getChildren().add(pebbles);
   * 
   * List<CartoonCharacter> parents = newArrayList(homer, fred);
   * // check children
   * assertThat(parent).flatExtracting(CartoonCharacter::getChildren)
   *                   .containsOnly(bart, lisa, maggie, pebbles);
* * The order of extracted values is consisted with both the order of the collection itself, as well as the extracted * collections. * * @param extractor the object transforming input object to an Iterable of desired ones * @return a new assertion object whose object under test is the list of values extracted */ public ListAssert flatExtracting(Extractor> extractor) { List result = newArrayList(); final List> extractedValues = FieldsOrPropertiesExtractor.extract(actual, extractor); for (Collection iterable : extractedValues) { result.addAll(iterable); } return new ListAssert<>(result); } /** * Extract from Iterable's elements the Iterable/Array values corresponding to the given property/field name and * concatenate them into a single list becoming the new object under test. *

* It allows testing the elements of extracting values that are represented by iterables or arrays. *

* For example: *

 CartoonCharacter bart = new CartoonCharacter("Bart Simpson");
   * CartoonCharacter lisa = new CartoonCharacter("Lisa Simpson");
   * CartoonCharacter maggie = new CartoonCharacter("Maggie Simpson");
   * CartoonCharacter homer = new CartoonCharacter("Homer Simpson");
   * homer.addChildren(bart, lisa, maggie);
   *
   * CartoonCharacter pebbles = new CartoonCharacter("Pebbles Flintstone");
   * CartoonCharacter fred = new CartoonCharacter("Fred Flintstone");
   * fred.getChildren().add(pebbles);
   *
   * List<CartoonCharacter> parents = newArrayList(homer, fred);
   * // check children
   * assertThat(parents).flatExtracting("children")
   *                    .containsOnly(bart, lisa, maggie, pebbles);
* * The order of extracted values is consisted with both the order of the collection itself, as well as the extracted * collections. * * @param propertyName the object transforming input object to an Iterable of desired ones * @return a new assertion object whose object under test is the list of values extracted * @throws IllegalArgumentException if one of the extracted property value was not an array or an iterable. */ public ListAssert flatExtracting(String propertyName) { List extractedValues = newArrayList(); List extractedGroups = FieldsOrPropertiesExtractor.extract(actual, byName(propertyName)); for (Object group : extractedGroups) { // expecting group to be an iterable or an array if (isArray(group)) { int size = Array.getLength(group); for (int i = 0; i < size; i++) { extractedValues.add(Array.get(group, i)); } } else if (group instanceof Iterable) { Iterable iterable = (Iterable) group; for (Object value : iterable) { extractedValues.add(value); } } else { CommonErrors.wrongElementTypeForFlatExtracting(group); } } return new ListAssert<>(extractedValues); } /** * Use the given {@link Function}s to extract the values from the {@link Iterable}'s elements into a new {@link Iterable} * composed of {@link Tuple}s (a simple data structure containing the extracted values), this new {@link Iterable} becoming the * object under test. *

* It allows you to test values from the {@link Iterable}'s elements instead of testing the elements themselves, which sometimes can be * much less work! *

* The Tuple data corresponds to the extracted values from the Iterable's elements, for instance if you pass functions * extracting "id", "name" and "email" values then each Tuple data will be composed of an id, a name and an email * extracted from the element of the initial Iterable (the Tuple's data order is the same as the given functions * order). *

* Let's take a look at an example to make things clearer : *

 // Build a list of TolkienCharacter, a TolkienCharacter has a name, and age and a Race (a specific class)
   * // they can be public field or properties, both can be extracted.
   * List<TolkienCharacter> fellowshipOfTheRing = new ArrayList<TolkienCharacter>();
   * 
   * fellowshipOfTheRing.add(new TolkienCharacter("Frodo", 33, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Sam", 38, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gandalf", 2020, MAIA));
   * fellowshipOfTheRing.add(new TolkienCharacter("Legolas", 1000, ELF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Pippin", 28, HOBBIT));
   * fellowshipOfTheRing.add(new TolkienCharacter("Gimli", 139, DWARF));
   * fellowshipOfTheRing.add(new TolkienCharacter("Aragorn", 87, MAN);
   * fellowshipOfTheRing.add(new TolkienCharacter("Boromir", 37, MAN));
   * 
   * // let's verify 'name', 'age' and Race of some TolkienCharacter in fellowshipOfTheRing :
   * assertThat(fellowshipOfTheRing).extracting(TolkienCharacter::getName,
   *                                            character -> character.getAge(),
   *                                            TolkienCharacter::getRace)
   *                                .containsOnly(tuple("Frodo", 33, HOBBIT),
   *                                              tuple("Sam", 38, HOBBIT),
   *                                              tuple("Gandalf", 2020, MAIA),
   *                                              tuple("Legolas", 1000, ELF),
   *                                              tuple("Pippin", 28, HOBBIT),
   *                                              tuple("Gimli", 139, DWARF),
   *                                              tuple("Aragorn", 87, MAN),
   *                                              tuple("Boromir", 37, MAN));
* You can use lambda expression or a method reference to extract the expected values. *

* Use {@link Tuple#tuple(Object...)} to initialize the expected values. *

* Note that the order of the extracted tuples list is consistent with the iteration order of the Iterable under test, * for example if it's a {@link HashSet}, you won't be able to make any assumptions on the extracted tuples order. * * @param extractors the extractor functions to extract a value from an element of the Iterable under test. * @return a new assertion object whose object under test is the list of Tuples containing the extracted values. */ @SafeVarargs public final ListAssert extracting(Function... extractors) { // combine all extractors into one function Function tupleExtractor = objectToExtractValueFrom -> { Tuple tuple = new Tuple(); for (Function extractor : extractors) { // extract value one by one tuple.addData(extractor.apply(objectToExtractValueFrom)); } return tuple; }; List tuples = stream(actual.spliterator(), false).map(tupleExtractor) .collect(toList()); return new ListAssert(tuples); } /** * Same as {@link #containsExactly(Object[])} but handle the {@link Iterable} to array conversion. Same semantic as * {@link #containsExactly(Object...)} : verifies that actual contains all the elements of the given iterable and * nothing else in the same order. *

* Example : * *

 Iterable<Ring> elvesRings = newArrayList(vilya, nenya, narya);
   * 
   * // assertion will pass
   * assertThat(elvesRings).containsExactly(newLinkedList(vilya, nenya, narya));
   * 
   * // assertion will fail as actual and expected order differ
   * assertThat(elvesRings).containsExactly(newLinkedList(nenya, vilya, narya));
* * @param iterable the given {@code Iterable} we will get elements from. */ @Override public S containsExactlyElementsOf(Iterable iterable) { return containsExactly(toArray(iterable)); } /** * {@inheritDoc} */ @Override public S containsOnlyElementsOf(Iterable iterable) { return containsOnly(toArray(iterable)); } /** * {@inheritDoc} */ @Override public S hasSameElementsAs(Iterable iterable) { return containsOnlyElementsOf(iterable); } /** * Use field/property by field/property comparison (including inherited fields/properties) instead of relying on * actual type A equals method to compare group elements for incoming assertion checks. Private fields * are included but this can be disabled using {@link Assertions#setAllowExtractingPrivateFields(boolean)}. *

* This can be handy if equals method of the objects to compare does not suit you. *

* Note that the comparison is not recursive, if one of the fields/properties is an Object, it will be compared * to the other field/property using its equals method. *

* Example: *
 TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
   * TolkienCharacter frodoClone = new TolkienCharacter("Frodo", 33, HOBBIT);
   * 
   * // Fail if equals has not been overridden in TolkienCharacter as equals default implementation only compares references
   * assertThat(newArrayList(frodo)).contains(frodoClone);
   * 
   * // frodo and frodoClone are equals when doing a field by field comparison.
   * assertThat(newArrayList(frodo)).usingFieldByFieldElementComparator().contains(frodoClone);
* * @return {@code this} assertion object. */ public S usingFieldByFieldElementComparator() { return usingElementComparator(new FieldByFieldComparator()); } /** * Use field/property by field/property comparison on the given fields/properties only (including inherited * fields/properties)instead of relying on actual type A equals method to compare group elements for * incoming assertion checks. Private fields are included but this can be disabled using * {@link Assertions#setAllowExtractingPrivateFields(boolean)}. *

* This can be handy if equals method of the objects to compare does not suit you. *

* Note that the comparison is not recursive, if one of the fields/properties is an Object, it will be compared * to the other field/property using its equals method. *

* Example: *
 TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
   * TolkienCharacter sam = new TolkienCharacter("Sam", 38, HOBBIT);
   * 
   * // frodo and sam both are hobbits, so they are equals when comparing only race
   * assertThat(newArrayList(frodo)).usingElementComparatorOnFields("race").contains(sam); // OK
   * 
   * // ... but not when comparing both name and race
   * assertThat(newArrayList(frodo)).usingElementComparatorOnFields("name", "race").contains(sam); // FAIL
* * @return {@code this} assertion object. */ public S usingElementComparatorOnFields(String... fields) { return usingElementComparator(new OnFieldsComparator(fields)); } protected S usingComparisonStrategy(ComparisonStrategy comparisonStrategy) { iterables = new Iterables(comparisonStrategy); return myself; } /** * Use field/property by field/property on all fields/properties except the given ones (including inherited * fields/properties)instead of relying on actual type A equals method to compare group elements for * incoming assertion checks. Private fields are included but this can be disabled using * {@link Assertions#setAllowExtractingPrivateFields(boolean)}. *

* This can be handy if equals method of the objects to compare does not suit you. *

* Note that the comparison is not recursive, if one of the fields/properties is an Object, it will be compared * to the other field/property using its equals method. *

* Example: *
 TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
   * TolkienCharacter sam = new TolkienCharacter("Sam", 38, HOBBIT);
   * 
   * // frodo and sam both are hobbits, so they are equals when comparing only race (i.e. ignoring all other fields)
   * assertThat(newArrayList(frodo)).usingElementComparatorIgnoringFields("name", "age").contains(sam); // OK
   * 
   * // ... but not when comparing both name and race
   * assertThat(newArrayList(frodo)).usingElementComparatorIgnoringFields("age").contains(sam); // FAIL
* * @return {@code this} assertion object. */ public S usingElementComparatorIgnoringFields(String... fields) { return usingElementComparator(new IgnoringFieldsComparator(fields)); } /** * Enable hexadecimal representation of Iterable elements instead of standard representation in error messages. *

* It can be useful to better understand what the error was with a more meaningful error message. *

* Example *

 final List<Byte> bytes = newArrayList((byte) 0x10, (byte) 0x20);
* * With standard error message: *
 assertThat(bytes).contains((byte)0x30);
   * 
   * Expecting:
   *  <[16, 32]>
   * to contain:
   *  <[48]>
   * but could not find:
   *  <[48]>
* * With Hexadecimal error message: *
 assertThat(bytes).inHexadecimal().contains((byte)0x30);
   * 
   * Expecting:
   *  <[0x10, 0x20]>
   * to contain:
   *  <[0x30]>
   * but could not find:
   *  <[0x30]>
* * @return {@code this} assertion object. */ @Override public S inHexadecimal() { return super.inHexadecimal(); } /** * Enable binary representation of Iterable elements instead of standard representation in error messages. *

* Example: *

 final List<Byte> bytes = newArrayList((byte) 0x10, (byte) 0x20);
* * With standard error message: *
 assertThat(bytes).contains((byte)0x30);
   * 
   * Expecting:
   *  <[16, 32]>
   * to contain:
   *  <[48]>
   * but could not find:
   *  <[48]>
* * With binary error message: *
 assertThat(bytes).inBinary().contains((byte)0x30);
   * 
   * Expecting:
   *  <[0b00010000, 0b00100000]>
   * to contain:
   *  <[0b00110000]>
   * but could not find:
   *  <[0b00110000]>
* * @return {@code this} assertion object. */ @Override public S inBinary() { return super.inBinary(); } /** * Filter the iterable under test keeping only elements having a property or field equal to {@code expectedValue}, the * property/field is specified by {@code propertyOrFieldName} parameter. *

* The filter first tries to get the value from a property (named {@code propertyOrFieldName}), if no such property * exists it tries to read the value from a field. Reading private fields is supported by default, this can be * globally disabled by calling {@link Assertions#setAllowExtractingPrivateFields(boolean) * Assertions.setAllowExtractingPrivateFields(false)}. *

* When reading nested property/field, if an intermediate value is null the whole nested property/field is * considered to be null, thus reading "address.street.name" value will return null if "street" value is null. *

* * As an example, let's check all employees 800 years old (yes, special employees): *

 Employee yoda   = new Employee(1L, new Name("Yoda"), 800);
   * Employee obiwan = new Employee(2L, new Name("Obiwan"), 800);
   * Employee luke   = new Employee(3L, new Name("Luke", "Skywalker"), 26);
   * Employee noname = new Employee(4L, null, 50);
   * 
   * List<Employee> employees = newArrayList(yoda, luke, obiwan, noname);
   *
   * assertThat(employees).filteredOn("age", 800)
   *                      .containsOnly(yoda, obiwan);
* * Nested properties/fields are supported: *
 // Name is bean class with 'first' and 'last' String properties
   *
   * // name is null for noname => it does not match the filter on "name.first" 
   * assertThat(employees).filteredOn("name.first", "Luke")
   *                      .containsOnly(luke);
   * 
   * assertThat(employees).filteredOn("name.last", "Vader")
   *                      .isEmpty();
*

* If you want to filter on null value, use {@link #filteredOnNull(String)} as Java will resolve the call to * {@link #filteredOn(String, FilterOperator)} instead of this method. *

* An {@link IntrospectionError} is thrown if the given propertyOrFieldName can't be found in one of the iterable * elements. *

* You can chain filters: *

 // fellowshipOfTheRing is a list of TolkienCharacter having race and name fields
   * // 'not' filter is statically imported from Assertions.not 
   * 
   * assertThat(fellowshipOfTheRing).filteredOn("race.name", "Man")
   *                                .filteredOn("name", not("Boromir"))
   *                                .containsOnly(aragorn);
* * If you need more complex filter, use {@link #filteredOn(Predicate)} or {@link #filteredOn(Condition)}. * * @param propertyOrFieldName the name of the property or field to read * @param expectedValue the value to compare element's property or field with * @return a new assertion object with the filtered iterable under test * @throws IllegalArgumentException if the given propertyOrFieldName is {@code null} or empty. * @throws IntrospectionError if the given propertyOrFieldName can't be found in one of the iterable elements. */ @SuppressWarnings("unchecked") public S filteredOn(String propertyOrFieldName, Object expectedValue) { Filters filter = filter((Iterable) actual); Iterable filteredIterable = filter.with(propertyOrFieldName, expectedValue).get(); return (S) new ListAssert<>(newArrayList(filteredIterable)); } /** * Filter the iterable under test keeping only elements whose property or field specified by * {@code propertyOrFieldName} is null. *

* The filter first tries to get the value from a property (named {@code propertyOrFieldName}), if no such property * exists it tries to read the value from a field. Reading private fields is supported by default, this can be * globally disabled by calling {@link Assertions#setAllowExtractingPrivateFields(boolean) * Assertions.setAllowExtractingPrivateFields(false)}. *

* When reading nested property/field, if an intermediate value is null the whole nested property/field is * considered to be null, thus reading "address.street.name" value will return null if "street" value is null. *

* As an example, let's check all employees 800 years old (yes, special employees): *

 Employee yoda   = new Employee(1L, new Name("Yoda"), 800);
   * Employee obiwan = new Employee(2L, new Name("Obiwan"), 800);
   * Employee luke   = new Employee(3L, new Name("Luke", "Skywalker"), 26);
   * Employee noname = new Employee(4L, null, 50);
   * 
   * List<Employee> employees = newArrayList(yoda, luke, obiwan, noname);
   *
   * assertThat(employees).filteredOnNull("name")
   *                      .containsOnly(noname);
* * Nested properties/fields are supported: *
 // Name is bean class with 'first' and 'last' String properties
   *
   * assertThat(employees).filteredOnNull("name.last")
   *                      .containsOnly(yoda, obiwan, noname);
* * An {@link IntrospectionError} is thrown if the given propertyOrFieldName can't be found in one of the iterable * elements. *

* If you need more complex filter, use {@link #filteredOn(Predicate)} or {@link #filteredOn(Condition)}. * * @param propertyOrFieldName the name of the property or field to read * @return a new assertion object with the filtered iterable under test * @throws IntrospectionError if the given propertyOrFieldName can't be found in one of the iterable elements. */ public S filteredOnNull(String propertyOrFieldName) { // need to cast nulll to Object otherwise it calls : // filteredOn(String propertyOrFieldName, FilterOperation filterOperation) return filteredOn(propertyOrFieldName, (Object) null); } /** * Filter the iterable under test keeping only elements having a property or field matching the filter expressed with * the {@link FilterOperator}, the property/field is specified by {@code propertyOrFieldName} parameter. *

* The existing filters are : *

    *
  • {@link Assertions#not(Object) not(Object)}
  • *
  • {@link Assertions#in(Object...) in(Object...)}
  • *
  • {@link Assertions#notIn(Object...) notIn(Object...)}
  • *
*

* Whatever filter is applied, it first tries to get the value from a property (named {@code propertyOrFieldName}), if * no such property exists it tries to read the value from a field. Reading private fields is supported by default, * this can be globally disabled by calling {@link Assertions#setAllowExtractingPrivateFields(boolean) * Assertions.setAllowExtractingPrivateFields(false)}. *

* When reading nested property/field, if an intermediate value is null the whole nested property/field is * considered to be null, thus reading "address.street.name" value will return null if "street" value is null. *

* * As an example, let's check stuff on some special employees : *

 Employee yoda   = new Employee(1L, new Name("Yoda"), 800);
   * Employee obiwan = new Employee(2L, new Name("Obiwan"), 800);
   * Employee luke   = new Employee(3L, new Name("Luke", "Skywalker"), 26);
   * 
   * List<Employee> employees = newArrayList(yoda, luke, obiwan, noname);
   *
   * // 'not' filter is statically imported from Assertions.not 
   * assertThat(employees).filteredOn("age", not(800))
   *                      .containsOnly(luke);
   * 
   * // 'in' filter is statically imported from Assertions.in
   * // Name is bean class with 'first' and 'last' String properties 
   * assertThat(employees).filteredOn("name.first", in("Yoda", "Luke"))
   *                      .containsOnly(yoda, luke);
   * 
   * // 'notIn' filter is statically imported from Assertions.notIn
   * assertThat(employees).filteredOn("name.first", notIn("Yoda", "Luke"))
   *                      .containsOnly(obiwan);
* * An {@link IntrospectionError} is thrown if the given propertyOrFieldName can't be found in one of the iterable * elements. *

* Note that combining filter operators is not supported, thus the following code is not correct: *

 // Combining filter operators like not(in(800)) is NOT supported
   * // -> throws UnsupportedOperationException
   * assertThat(employees).filteredOn("age", not(in(800)))
   *                      .contains(luke);
*

* You can chain filters: *

 // fellowshipOfTheRing is a list of TolkienCharacter having race and name fields
   * // 'not' filter is statically imported from Assertions.not 
   * 
   * assertThat(fellowshipOfTheRing).filteredOn("race.name", "Man")
   *                                .filteredOn("name", not("Boromir"))
   *                                .containsOnly(aragorn);
* * If you need more complex filter, use {@link #filteredOn(Predicate)} or {@link #filteredOn(Condition)}. * * @param propertyOrFieldName the name of the property or field to read * @param filterOperator the filter operator to apply * @return a new assertion object with the filtered iterable under test * @throws IllegalArgumentException if the given propertyOrFieldName is {@code null} or empty. */ @SuppressWarnings("unchecked") public S filteredOn(String propertyOrFieldName, FilterOperator filterOperator) { checkNotNull(filterOperator); Filters filter = filter((Iterable) actual).with(propertyOrFieldName); filterOperator.applyOn(filter); return (S) new ListAssert<>(newArrayList(filter.get())); } /** * Filter the iterable under test keeping only elements matching the given {@link Condition}. *

* If you prefer {@link Predicate} over {@link Condition}, use {@link #filteredOn(Predicate)}. *

* Example : check old employees whose age > 100: *

 Employee yoda   = new Employee(1L, new Name("Yoda"), 800);
   * Employee obiwan = new Employee(2L, new Name("Obiwan"), 800);
   * Employee luke   = new Employee(3L, new Name("Luke", "Skywalker"), 26);
   * Employee noname = new Employee(4L, null, 50);
   * 
   * List<Employee> employees = newArrayList(yoda, luke, obiwan, noname);
   * 
   * // old employee condition, "old employees" describes the condition in error message
   * // you just have to implement 'matches' method 
   * Condition<Employee> oldEmployees = new Condition<Employee>("old employees") {
   *       {@literal @}Override
   *       public boolean matches(Employee employee) {
   *         return employee.getAge() > 100;
   *       }
   *     };
   *   }
   * assertThat(employees).filteredOn(oldEmployees)
   *                      .containsOnly(yoda, obiwan);
* * You can combine {@link Condition} with condition operator like {@link Not}: *
 // 'not' filter is statically imported from Assertions.not
   * assertThat(employees).filteredOn(not(oldEmployees))
   *                      .contains(luke, noname);
* * @param condition the filter condition / predicate * @return a new assertion object with the filtered iterable under test * @throws IllegalArgumentException if the given condition is {@code null}. */ @SuppressWarnings("unchecked") public S filteredOn(Condition condition) { Filters filter = filter((Iterable) actual); Iterable filteredIterable = filter.being(condition).get(); return (S) new ListAssert<>(newArrayList(filteredIterable)); } /** * Filter the iterable under test keeping only elements matching the given {@link Predicate}. *

* Example : check old employees whose age > 100: * *

 Employee yoda   = new Employee(1L, new Name("Yoda"), 800);
   * Employee obiwan = new Employee(2L, new Name("Obiwan"), 800);
   * Employee luke   = new Employee(3L, new Name("Luke", "Skywalker"), 26);
   * 
   * List<Employee> employees = newArrayList(yoda, luke, obiwan);
   * 
   * assertThat(employees).filteredOn(employee -> employee.getAge() > 100)
   *                      .containsOnly(yoda, obiwan);
* * @param predicate the filter predicate * @return a new assertion object with the filtered iterable under test * @throws IllegalArgumentException if the given predicate is {@code null}. */ @SuppressWarnings("unchecked") public S filteredOn(Predicate predicate) { if (predicate == null) throw new IllegalArgumentException("The filter predicate should not be null"); return (S) new ListAssert<>(stream(actual.spliterator(), false).filter(predicate).collect(toList())); } /** * {@inheritDoc} */ @Override public S allMatch(Predicate predicate) { iterables.assertAllMatch(info, actual, predicate); return myself; } // override methods to avoid compilation error when chaining an AbstractAssert method with a AbstractIterableAssert // one on raw types. @Override public S as(String description, Object... args) { return super.as(description, args); } @Override public S as(Description description) { return super.as(description); } @Override public S describedAs(Description description) { return super.describedAs(description); } @Override public S describedAs(String description, Object... args) { return super.describedAs(description, args); } @Override public S doesNotHave(Condition condition) { return super.doesNotHave(condition); } @Override public S doesNotHaveSameClassAs(Object other) { return super.doesNotHaveSameClassAs(other); } @Override public S has(Condition condition) { return super.has(condition); } @Override public S hasSameClassAs(Object other) { return super.hasSameClassAs(other); } @Override public S hasToString(String expectedToString) { return super.hasToString(expectedToString); } @Override public S is(Condition condition) { return super.is(condition); } @Override public S isEqualTo(Object expected) { return super.isEqualTo(expected); } @Override public S isExactlyInstanceOf(Class type) { return super.isExactlyInstanceOf(type); } @Override public S isIn(Iterable values) { return super.isIn(values); } @Override public S isIn(Object... values) { return super.isIn(values); } @Override public S isInstanceOf(Class type) { return super.isInstanceOf(type); } @Override public S isInstanceOfAny(Class... types) { return super.isInstanceOfAny(types); } @Override public S isNot(Condition condition) { return super.isNot(condition); } @Override public S isNotEqualTo(Object other) { return super.isNotEqualTo(other); } @Override public S isNotExactlyInstanceOf(Class type) { return super.isNotExactlyInstanceOf(type); } @Override public S isNotIn(Iterable values) { return super.isNotIn(values); } @Override public S isNotIn(Object... values) { return super.isNotIn(values); } @Override public S isNotInstanceOf(Class type) { return super.isNotInstanceOf(type); } @Override public S isNotInstanceOfAny(Class... types) { return super.isNotInstanceOfAny(types); } @Override public S isNotOfAnyClassIn(Class... types) { return super.isNotOfAnyClassIn(types); } @Override public S isNotNull() { return super.isNotNull(); } @Override public S isNotSameAs(Object other) { return super.isNotSameAs(other); } @Override public S isOfAnyClassIn(Class... types) { return super.isOfAnyClassIn(types); } @Override public S isSameAs(Object expected) { return super.isSameAs(expected); } @Override public S overridingErrorMessage(String newErrorMessage, Object... args) { return super.overridingErrorMessage(newErrorMessage, args); } @Override public S usingDefaultComparator() { return super.usingDefaultComparator(); } @Override public S usingComparator(Comparator customComparator) { return super.usingComparator(customComparator); } @Override public S withFailMessage(String newErrorMessage, Object... args) { return super.withFailMessage(newErrorMessage, args); } @Override public S withThreadDumpOnError() { return super.withThreadDumpOnError(); } }