Skip to content

Commit

Permalink
Ignored fields now works when field is missing in expected instead of…
Browse files Browse the repository at this point in the history
… simply ignoring the field value but requiring the field to be in the expected class
  • Loading branch information
joel-costigliola committed Feb 13, 2019
1 parent d616ad7 commit b080f3e
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 12 deletions.
Expand Up @@ -25,6 +25,7 @@
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;

Expand Down Expand Up @@ -235,7 +236,21 @@ public String multiLineDescription(Representation representation) {
boolean shouldIgnore(DualKey dualKey) {
return matchesAnIgnoredNullField(dualKey)
|| matchesAnIgnoredField(dualKey)
|| matchesAnIgnoredRegex(dualKey);
|| matchesAnIgnoredFieldRegex(dualKey);
}

Predicate<String> shouldKeepField(String parentConcatenatedPath) {
return fieldName -> shouldKeepField(parentConcatenatedPath, fieldName);
}

private boolean shouldKeepField(String parentPath, String fieldName) {
String fieldConcatenatedPath = concatenatedPath(parentPath, fieldName);
return !matchesAnIgnoredField(fieldConcatenatedPath) && !matchesAnIgnoredFieldRegex(fieldConcatenatedPath);
}

// TODO move somewhere else ?
private static String concatenatedPath(String parentPath, String name) {
return parentPath.isEmpty() ? name : format("%s.%s", parentPath, name);
}

boolean shouldIgnoreOverriddenEqualsOf(DualKey dualKey) {
Expand Down Expand Up @@ -318,14 +333,22 @@ private boolean matchesAnIgnoredNullField(DualKey dualKey) {
return ignoreAllActualNullFields && dualKey.key1 == null;
}

private boolean matchesAnIgnoredRegex(DualKey dualKey) {
private boolean matchesAnIgnoredFieldRegex(String fieldConcatenatedPath) {
return ignoredFieldsRegexes.stream()
.anyMatch(regex -> regex.matcher(dualKey.concatenatedPath).matches());
.anyMatch(regex -> regex.matcher(fieldConcatenatedPath).matches());
}

private boolean matchesAnIgnoredFieldRegex(DualKey dualKey) {
return matchesAnIgnoredFieldRegex(dualKey.concatenatedPath);
}

private boolean matchesAnIgnoredField(DualKey dualKey) {
return matchesAnIgnoredField(dualKey.concatenatedPath);
}

private boolean matchesAnIgnoredField(String fieldConcatenatedPath) {
return ignoredFields.stream()
.anyMatch(fieldLocation -> fieldLocation.matches(dualKey.concatenatedPath));
.anyMatch(fieldLocation -> fieldLocation.matches(fieldConcatenatedPath));
}

private String describeIgnoredFields() {
Expand Down
Expand Up @@ -13,10 +13,12 @@
package org.assertj.core.api.recursive.comparison;

import static java.lang.String.format;
import static java.util.stream.Collectors.toSet;
import static org.assertj.core.api.recursive.comparison.ComparisonDifference.rootComparisonDifference;
import static org.assertj.core.internal.Objects.getDeclaredFieldsIncludingInherited;
import static org.assertj.core.util.Lists.list;
import static org.assertj.core.util.Sets.newHashSet;
import static org.assertj.core.util.Strings.join;
import static org.assertj.core.util.introspection.PropertyOrFieldSupport.COMPARISON;

import java.lang.reflect.Array;
Expand Down Expand Up @@ -79,7 +81,8 @@ public List<ComparisonDifference> determineDifferences(Object actual, Object exp
if (recursiveComparisonConfiguration.isInStrictTypeCheckingMode() && expectedTypeIsNotSubtypeOfActualType(actual, expected)) {
return list(expectedAndActualTypeDifference(actual, expected));
}
return determineDifferences(actual, expected, null, recursiveComparisonConfiguration);
List<String> rootPath = list();
return determineDifferences(actual, expected, rootPath, recursiveComparisonConfiguration);
}

private static List<ComparisonDifference> determineDifferences(Object actual, Object expected, List<String> parentPath,
Expand Down Expand Up @@ -236,8 +239,8 @@ && hasCustomEquals(actualFieldClass)) {
continue;
}

Set<String> key1FieldsNames = getFieldsNames(getDeclaredFieldsIncludingInherited(actualFieldClass));
Set<String> key2FieldsNames = getFieldsNames(getDeclaredFieldsIncludingInherited(expectedFieldClass));
Set<String> key1FieldsNames = getNonIgnoredFieldNames(actualFieldClass, currentPath, recursiveComparisonConfiguration);
Set<String> key2FieldsNames = getFieldsNames(expectedFieldClass);
if (!key2FieldsNames.containsAll(key1FieldsNames)) {
Set<String> key1FieldsNamesNotInKey2 = newHashSet(key1FieldsNames);
key1FieldsNamesNotInKey2.removeAll(key2FieldsNames);
Expand Down Expand Up @@ -276,15 +279,15 @@ private static boolean hasCustomComparator(DualKey dualKey, RecursiveComparisonC
private static Deque<DualKey> initStack(Object actual, Object expected, List<String> parentPath,
RecursiveComparisonConfiguration recursiveComparisonConfiguration) {
Deque<DualKey> stack = new DualKeyDeque(recursiveComparisonConfiguration);
boolean isRootObject = parentPath == null;
List<String> currentPath = isRootObject ? new ArrayList<>() : parentPath;
boolean isRootObject = parentPath.isEmpty();
List<String> currentPath = new ArrayList<>(parentPath);
DualKey basicDualKey = new DualKey(currentPath, actual, expected);
if (actual != null && expected != null && !isContainerType(actual) && !isContainerType(expected)
&& (isRootObject || !hasCustomComparator(basicDualKey, recursiveComparisonConfiguration))) {
// disregard the equals method and start comparing fields
Set<String> actualFieldsNameSet = getFieldsNames(getDeclaredFieldsIncludingInherited(actual.getClass()));
Set<String> actualFieldsNameSet = getNonIgnoredFieldNames(actual.getClass(), parentPath, recursiveComparisonConfiguration);
if (!actualFieldsNameSet.isEmpty()) {
Set<String> expectedFieldsNameSet = getFieldsNames(getDeclaredFieldsIncludingInherited(expected.getClass()));
Set<String> expectedFieldsNameSet = getFieldsNames(expected.getClass());
if (!expectedFieldsNameSet.containsAll(actualFieldsNameSet)) {
stack.addFirst(basicDualKey);
} else {
Expand All @@ -306,7 +309,17 @@ private static Deque<DualKey> initStack(Object actual, Object expected, List<Str
return stack;
}

private static Set<String> getFieldsNames(Collection<Field> fields) {
private static Set<String> getNonIgnoredFieldNames(Class<?> actualClass, List<String> parentPath,
RecursiveComparisonConfiguration recursiveComparisonConfiguration) {
String parentConcatenatedPath = join(parentPath).with(".");
// need to ignore fields according to the configuration
return getFieldsNames(actualClass).stream()
.filter(recursiveComparisonConfiguration.shouldKeepField(parentConcatenatedPath))
.collect(toSet());
}

private static Set<String> getFieldsNames(Class<?> clazz) {
Collection<Field> fields = getDeclaredFieldsIncludingInherited(clazz);
Set<String> fieldNames = new LinkedHashSet<>();
for (Field field : fields) {
fieldNames.add(field.getName());
Expand Down
Expand Up @@ -219,6 +219,11 @@ private static Stream<Arguments> recursivelyEqualObjectsIgnoringGivenFields() {
Person person1 = new Person("John");
person1.home.address.number = 1;

Person giant1 = new Giant();
giant1.name = "Giant John";
((Giant) giant1).height = 3.1;
giant1.home.address.number = 1;

Person person2 = new Person("Jack");
person2.home.address.number = 1;

Expand Down Expand Up @@ -249,6 +254,9 @@ private static Stream<Arguments> recursivelyEqualObjectsIgnoringGivenFields() {

return Stream.of(Arguments.of(person1, person2, "same data and type, except for one ignored field",
list("name")),
Arguments.of(giant1, person1,
"different type, same data except name and height which is not even a field from person1",
list("name", "height")),
Arguments.of(person3, person4, "same data, different type, except for several ignored fields",
list("name", "home.address.number")),
Arguments.of(person5, person6, "same data except for one subfield of an ignored field",
Expand Down

0 comments on commit b080f3e

Please sign in to comment.