Skip to content

Commit

Permalink
Fixes #30 : allow extracting several fields or properties in iterable…
Browse files Browse the repository at this point in the history
… or array assertions
  • Loading branch information
joel-costigliola committed Apr 12, 2013
1 parent eabb566 commit 3386120
Show file tree
Hide file tree
Showing 16 changed files with 536 additions and 160 deletions.
93 changes: 79 additions & 14 deletions src/main/java/org/assertj/core/api/AbstractIterableAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.List;

import org.assertj.core.groups.FieldsOrPropertiesExtractor;
import org.assertj.core.groups.Tuple;
import org.assertj.core.internal.ComparatorBasedComparisonStrategy;
import org.assertj.core.internal.Iterables;
import org.assertj.core.util.VisibleForTesting;
Expand All @@ -44,8 +45,7 @@
* @author Mikhail Mazursky
*/
public abstract class AbstractIterableAssert<S extends AbstractIterableAssert<S, A, T>, A extends Iterable<T>, T>
extends AbstractAssert<S, A>
implements ObjectEnumerableAssert<S, T> {
extends AbstractAssert<S, A> implements ObjectEnumerableAssert<S, T> {

@VisibleForTesting
Iterables iterables = Iterables.instance();
Expand Down Expand Up @@ -280,14 +280,14 @@ public S usingDefaultElementComparator() {
* 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.
* <p>
* It allows you to test a field/property of the the Iterable's elements instead of testing the elements themselves,
* 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 !
* <p>
* Let's take an example to make things clearer :
*
* <pre>
* // 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 works when extracting their values.
* // they can be public field or properties, both can be extracted.
* List&lt;TolkienCharacter&gt; fellowshipOfTheRing = new ArrayList&lt;TolkienCharacter&gt;();
*
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Frodo&quot;, 33, HOBBIT));
Expand All @@ -305,30 +305,95 @@ public S usingDefaultElementComparator() {
* .contains(&quot;Boromir&quot;, &quot;Gandalf&quot;, &quot;Frodo&quot;)
* .doesNotContain(&quot;Sauron&quot;, &quot;Elrond&quot;);
*
* // you can extract nested field/property like the name of Race :
* // you can extract nested property/field like the name of Race :
*
* assertThat(fellowshipOfTheRing).extracting(&quot;race.name&quot;)
* .contains(&quot;Hobbit&quot;, &quot;Elf&quot;)
* .doesNotContain(&quot;Orc&quot;);
* </pre>
*
* A field with the given name is looked for first, if it is not accessible (ie. does not exist or is not public),
* then a property with the given name is looked for.
* A property with the given name is looked for first, if it does'nt exist then a field with the given name is looked
* for, if no field accessible (ie. does not exist or is not public) an IntrospectionError is thrown.
* <p>
* It only works if all objects have the field or all objects have the property with the given name, i.e. it won't
* work if half of the objects have the field and the other the property.
* It only works if <b>all</b> objects have the field or all objects have the property with the given name, i.e. it
* won't work if half of the objects have the field and the other the property.
* <p>
* Note that the order of extracted field/property values is consistent with the iteration order of the Iterable under
* 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 fieldOrProperty the field/property to extract from the Iterable under test
* @return a new assertion object whose object under test is the list of extracted field/property values.
* @param propertyOrField the property/field to extract from 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 (or field exists but is not public)
* in one of the initial Iterable's element.
*/
public ListAssert<Object> extracting(String fieldOrProperty) {
List<Object> values = FieldsOrPropertiesExtractor.extract(fieldOrProperty, actual);
public ListAssert<Object> extracting(String propertyOrField) {
List<Object> values = FieldsOrPropertiesExtractor.extract(propertyOrField, actual);
return new ListAssert<Object>(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.
* <p>
* 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 !
* <p>
* 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).
* <p>
* Let's take an example to make things clearer :
*
* <pre>
* // 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&lt;TolkienCharacter&gt; fellowshipOfTheRing = new ArrayList&lt;TolkienCharacter&gt;();
*
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Frodo&quot;, 33, HOBBIT));
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Sam&quot;, 38, HOBBIT));
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Gandalf&quot;, 2020, MAIA));
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Legolas&quot;, 1000, ELF));
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Pippin&quot;, 28, HOBBIT));
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Gimli&quot;, 139, DWARF));
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Aragorn&quot;, 87, MAN);
* fellowshipOfTheRing.add(new TolkienCharacter(&quot;Boromir&quot;, 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"));
* </pre>
*
* A property with the given name is looked for first, if it does'nt exist then a field with the given name is looked
* for, if no field accessible (ie. does not exist or is not public) an IntrospectionError is thrown.
* <p>
* It only works if <b>all</b> objects have the field or all objects have the property with the given name, i.e. it
* won't work if half of the objects have the field and the other the property.
* <p>
* 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 propertiesOrFields the properties/fields to extract from the initial 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 (or field exists but is not
* public) in one of the initial Iterable's element.
*/
public ListAssert<Tuple> extracting(String... propertiesOrFields) {
List<Tuple> values = FieldsOrPropertiesExtractor.extract(actual, propertiesOrFields);
return new ListAssert<Tuple>(values);
}

}
Loading

0 comments on commit 3386120

Please sign in to comment.