Skip to content

Commit

Permalink
flatExtracting for map: extends flattening to arrays or any kind of i…
Browse files Browse the repository at this point in the history
…terable map values
  • Loading branch information
joel-costigliola committed Oct 21, 2017
1 parent 3723a09 commit e7bd4af
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 51 deletions.
66 changes: 50 additions & 16 deletions src/main/java/org/assertj/core/api/AbstractMapAssert.java
Expand Up @@ -13,12 +13,18 @@
package org.assertj.core.api;

import static org.assertj.core.data.MapEntry.entry;
import static org.assertj.core.extractor.Extractors.byName;
import static org.assertj.core.util.Arrays.array;
import static org.assertj.core.util.Arrays.isArray;
import static org.assertj.core.util.IterableUtil.toCollection;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.assertj.core.description.Description;
import org.assertj.core.groups.Tuple;
import org.assertj.core.internal.Maps;
import org.assertj.core.util.CheckReturnValue;
import org.assertj.core.util.Preconditions;
Expand Down Expand Up @@ -1155,36 +1161,64 @@ public AbstractObjectArrayAssert<?, Object> extracting(String... keys) {
}

/**
* Flatten the list of values of the given keys from the actual map under test into an array, this new array becoming
* the object under test.
* Flatten the values of the given keys from the actual map under test into a new array, this new array becoming the object under test.
* <p>
* If a given key is not present in the map under test, a {@code null} value is extracted.
* <p>
* If a given key value is not an {@link Iterable} or an array, it is simply extracted but (obviously) not flattened.
* <p>
* Example:
* <pre><code class='java'> Map&lt;String, List&lt;String&gt; map = new HashMap&lt;&gt;();
* map.put("name", Arrays.asList("Dave", "Jeff"));
* map.put("job", Arrays.asList("Plumber", "Builder"));
* map.put("city", Arrays.asList("Dover", "Boston", "Paris"));
*
* assertThat(map).flatExtracting("name","job","city")
* .containsExactly("Dave", "Jeff", "Plumber", "Builder", "Dover", "Boston", "Paris");
* <pre><code class='java'> List&lt;String&gt; names = asList("Dave", "Jeff");
* LinkedHashSet&lt;String&gt; jobs = newLinkedHashSet("Plumber", "Builder");
* Iterable&lt;String&gt; cities = asList("Dover", "Boston", "Paris");
* int[] ranks = { 1, 2, 3 };
*
* Map&lt;String, Object&gt; map = new LinkedHashMap<>();
* map.put("name", names);
* map.put("job", jobs);
* map.put("city", cities);
* map.put("rank", ranks);
*
* assertThat(map).flatExtracting("name","job","city", "rank")
* .containsExactly("Dave", "Jeff",
* "Plumber", "Builder",
* "Dover", "Boston", "Paris"
* 1, 2, 3);
*
* // order of values is the order of key then key values:
* // the order of values in the resulting array is the order of map keys then key values:
* assertThat(map).flatExtracting("city", "job", "name")
* .containsExactly("Dover", "Boston", "Paris", "Plumber", "Builder", "Dave", "Jeff");
* .containsExactly("Dover", "Boston", "Paris",
* "Plumber", "Builder",
* "Dave", "Jeff");
*
* // contains exactly null twice (one for each unknown keys)
* assertThat(map).flatExtracting("foo", "bar")
* .containsExactly(null, null);</code></pre>
* assertThat(map).flatExtracting("foo", "name", "bar")
* .containsExactly(null, "Dave", "Jeff", null);
*
* // if the key value is not an iterable/array, it will be simply extracted but not flattened.
* map.put("year", 2017));
* assertThat(map).flatExtracting("name","job","year")
* .containsExactly("Dave", "Jeff", "Plumber", "Builder", "Dover", 2017);</code></pre>
* <p>
* Note that the order of values in the resulting array is the order of the map keys iteration then key values.
*
* @param keys the keys used to get values from the map under test
* @return a new assertion object whose object under test is the array containing the extracted map values
* @return a new assertion object whose object under test is the array containing the extracted flattened map values
*/
@CheckReturnValue
@Override
public AbstractObjectArrayAssert<?, Object> flatExtracting(String... keys) {
return super.flatExtracting(keys);
Tuple values = byName(keys).extract(actual);
List<Object> valuesFlattened = flatten(values.toList());
return extracting(valuesFlattened, keys);
}

private static List<Object> flatten(Iterable<Object> collectionToFlatten) {
List<Object> result = new ArrayList<>();
for (Object item : collectionToFlatten) {
if (item instanceof Iterable<?>) result.addAll(toCollection((Iterable<?>) item));
else if (isArray(item)) result.addAll(org.assertj.core.util.Arrays.asList(item));
else result.add(item);
}
return result;
}
}
22 changes: 2 additions & 20 deletions src/main/java/org/assertj/core/api/AbstractObjectAssert.java
Expand Up @@ -16,8 +16,6 @@
import static org.assertj.core.extractor.Extractors.byName;
import static org.assertj.core.extractor.Extractors.extractedDescriptionOf;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -551,28 +549,12 @@ public AbstractObjectArrayAssert<?, Object> extracting(String... propertiesOrFie
Tuple values = byName(propertiesOrFields).extract(actual);
return extracting(values.toList(), propertiesOrFields);
}
private AbstractObjectArrayAssert<?, Object> extracting(List<Object> values, String...propertiesOrFields) {

AbstractObjectArrayAssert<?, Object> extracting(List<Object> values, String... propertiesOrFields) {
String extractedPropertiesOrFieldsDescription = extractedDescriptionOf(propertiesOrFields);
String description = mostRelevantDescription(info.description(), extractedPropertiesOrFieldsDescription);
return new ObjectArrayAssert<>(values.toArray()).as(description);
}

@CheckReturnValue
public AbstractObjectArrayAssert<?, Object> flatExtracting(String... keys) {
Tuple values = byName(keys).extract(actual);
List<Object> valuesFlattened = flattenNonRecursive(values.toList());
return extracting(valuesFlattened,keys);
}

private static List<Object> flattenNonRecursive(Collection<Object> list) {
List<Object> result = new ArrayList<>();
for (Object item : list) {
if (item instanceof List<?>) result.addAll((List<?>) item);
else result.add(item);
}
return result;
}

/**
* Assert that the object under test (actual) is equal to the given object based on recursive a property/field by property/field comparison (including
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/assertj/core/util/IterableUtil.java
Expand Up @@ -108,7 +108,7 @@ public static <T> T[] toArray(Iterable<? extends T> iterable, Class<T> type) {
return collection.toArray(array);
}

private static <T> Collection<T> toCollection(Iterable<T> iterable) {
public static <T> Collection<T> toCollection(Iterable<T> iterable) {
return iterable instanceof Collection ? (Collection<T>) iterable : newArrayList(iterable);
}

Expand Down
Expand Up @@ -14,9 +14,11 @@

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.util.Arrays.array;
import static org.assertj.core.util.Sets.newLinkedHashSet;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.LinkedHashSet;
import java.util.Map;

import org.assertj.core.api.MapAssert;
Expand All @@ -30,31 +32,43 @@
*/
public class MapAssert_flatExtracting_Test {

private Map<String, List<String>> mapOfList;
private Map<String, Object> map;

@Before
public void beforeEachTest() {
mapOfList = new LinkedHashMap<>();
mapOfList.put("name", asList("Dave", "Jeff"));
mapOfList.put("job", asList("Plumber", "Builder"));
mapOfList.put("city", asList("Dover", "Boston", "Paris"));
String[] names = array("Dave", "Jeff");
LinkedHashSet<String> jobs = newLinkedHashSet("Plumber", "Builder");
Iterable<String> cities = asList("Dover", "Boston", "Paris");
int[] ranks = { 1, 2, 3 };
map = new LinkedHashMap<>();
map.put("name", names);
map.put("job", jobs);
map.put("city", cities);
map.put("rank", ranks);
}

@Test
public void should_allow_assertions_on_flattened_values_extracted_from_given_map_keys() {
assertThat(mapOfList).flatExtracting("name", "job", "city")
.containsExactly("Dave", "Jeff", "Plumber", "Builder", "Dover", "Boston", "Paris");
assertThat(map).flatExtracting("name", "job", "city", "rank")
.containsExactly("Dave", "Jeff", "Plumber", "Builder", "Dover", "Boston", "Paris", 1, 2, 3);
// order of values is the order of key then key values
assertThat(mapOfList).flatExtracting("city", "job", "name")
.containsExactly("Dover", "Boston", "Paris", "Plumber", "Builder", "Dave", "Jeff");
assertThat(map).flatExtracting("city", "job", "name")
.containsExactly("Dover", "Boston", "Paris", "Plumber", "Builder", "Dave", "Jeff");
}

@Test
public void should_extract_null_from_unknown_key() {
assertThat(mapOfList).flatExtracting("name", "id", "city")
.containsExactly("Dave", "Jeff", null, "Dover", "Boston", "Paris");
assertThat(mapOfList).flatExtracting("foo", "bar")
.containsOnlyNulls();
assertThat(map).flatExtracting("name", "id", "city")
.containsExactly("Dave", "Jeff", null, "Dover", "Boston", "Paris");
assertThat(map).flatExtracting("foo", "bar")
.containsOnlyNulls();
}

@Test
public void should_extract_but_not_flatten_non_collection_values() {
map.put("year", 2017);
assertThat(map).flatExtracting("name", "job", "year")
.containsExactly("Dave", "Jeff", "Plumber", "Builder", 2017);
}

}
@@ -0,0 +1,54 @@
/**
* 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-2017 the original author or authors.
*/
package org.assertj.core.api.object;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

public class ObjectAssert_flatExtracting_Test {

private Map<String, List<String>> mapOfList;

@Before
public void beforeEachTest() {
mapOfList = new LinkedHashMap<>();
mapOfList.put("name", asList("Dave", "Jeff"));
mapOfList.put("job", asList("Plumber", "Builder"));
mapOfList.put("city", asList("Dover", "Boston", "Paris"));
}

@Test
public void should_allow_assertions_on_flattened_values_extracted_from_given_map_keys() {
assertThat(mapOfList).flatExtracting("name", "job", "city")
.containsExactly("Dave", "Jeff", "Plumber", "Builder", "Dover", "Boston", "Paris");
// order of values is the order of key then key values
assertThat(mapOfList).flatExtracting("city", "job", "name")
.containsExactly("Dover", "Boston", "Paris", "Plumber", "Builder", "Dave", "Jeff");
}

@Test
public void should_extract_null_from_unknown_key() {
assertThat(mapOfList).flatExtracting("name", "id", "city")
.containsExactly("Dave", "Jeff", null, "Dover", "Boston", "Paris");
assertThat(mapOfList).flatExtracting("foo", "bar")
.containsOnlyNulls();
}

}

0 comments on commit e7bd4af

Please sign in to comment.