com.fitbur.assertj.api.AbstractIterableAssert Maven / Gradle / Ivy
/**
* 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 extends T>, 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 extends T> 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 extends T> 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 super T> condition) {
iterables.assertAre(info, actual, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S areNot(Condition super T> condition) {
iterables.assertAreNot(info, actual, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S have(Condition super T> condition) {
iterables.assertHave(info, actual, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S doNotHave(Condition super T> condition) {
iterables.assertDoNotHave(info, actual, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S areAtLeastOne(Condition super T> condition) {
areAtLeast(1, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S areAtLeast(int times, Condition super T> condition) {
iterables.assertAreAtLeast(info, actual, times, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S areAtMost(int times, Condition super T> condition) {
iterables.assertAreAtMost(info, actual, times, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S areExactly(int times, Condition super T> condition) {
iterables.assertAreExactly(info, actual, times, condition);
return myself;
}
/** {@inheritDoc} */
@Override
public S haveAtLeastOne(Condition super T> condition) {
return haveAtLeast(1, condition);
}
/**
* {@inheritDoc}
*/
@Override
public S haveAtLeast(int times, Condition super T> condition) {
iterables.assertHaveAtLeast(info, actual, times, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S haveAtMost(int times, Condition super T> condition) {
iterables.assertHaveAtMost(info, actual, times, condition);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S haveExactly(int times, Condition super T> 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 extends T> iterable) {
iterables.assertContainsAll(info, actual, iterable);
return myself;
}
/**
* {@inheritDoc}
*/
@Override
public S usingElementComparator(Comparator super T> 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
© 2015 - 2024 Weber Informatics LLC | Privacy Policy