Skip to content

Commit

Permalink
Allow to ignore custom equals method by regexes.
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-costigliola committed Feb 13, 2019
1 parent baaa286 commit 1b32e2d
Show file tree
Hide file tree
Showing 16 changed files with 360 additions and 212 deletions.
Expand Up @@ -7,34 +7,30 @@

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import org.assertj.core.annotations.Beta;
import org.assertj.core.internal.TypeComparators;
import org.assertj.core.presentation.Representation;

@Beta
public class RecursiveComparisonConfiguration {

private static final String NEWLINE = format("%n");

private boolean strictTypeCheck = true;
// private boolean strictTypeCheck = true;

private boolean ignoreAllActualNullFields = false;
private Set<FieldLocation> ignoredFields = new LinkedHashSet<>();

private boolean ignoreCustomEquals = false;
private List<Pattern> ignoredCustomEqualsRegexes = new ArrayList<>();

private Set<Class> forceRecursiveComparisonForTypes = new HashSet<>();
private Set<FieldLocation> forceRecursiveComparisonForFields = new HashSet<>();
// private Set<Class> forceRecursiveComparisonForTypes = new HashSet<>();
// private Set<FieldLocation> forceRecursiveComparisonForFields = new HashSet<>();

private TypeComparators comparatorForTypes = new TypeComparators();
private FieldComparators comparatorForFields = new FieldComparators();
// private TypeComparators comparatorForTypes = new TypeComparators();
// private FieldComparators comparatorForFields = new FieldComparators();

private List<Pattern> ignoredFieldsRegexes = new ArrayList<>();

Expand Down Expand Up @@ -73,36 +69,6 @@ public void setIgnoreAllActualNullFields(boolean ignoreAllActualNullFields) {
this.ignoreAllActualNullFields = ignoreAllActualNullFields;
}

@Override
public String toString() {
return multiLineDescription(CONFIGURATION_PROVIDER.representation());
}

public String multiLineDescription(Representation representation) {
StringBuilder description = new StringBuilder();
if (ignoreAllActualNullFields) description.append("- all actual null fields were ignored in the comparison").append(NEWLINE);
if (!ignoredFields.isEmpty())
description.append(format("- the following fields were ignored in the comparison: %s%n", describeIgnoredFields()));
if (!ignoredFieldsRegexes.isEmpty())
description.append(format("- the following regexes were used to ignore fields in the comparison: %s%n",
describeIgnoredFieldsRegexes()));
return description.toString();
}

private String describeIgnoredFields() {
List<String> fieldsDescription = ignoredFields.stream()
.map(FieldLocation::getFieldPath)
.collect(toList());
return join(fieldsDescription).with(", ");
}

private String describeIgnoredFieldsRegexes() {
List<String> fieldsDescription = ignoredFieldsRegexes.stream()
.map(Pattern::pattern)
.collect(toList());
return join(fieldsDescription).with(", ");
}

/**
* Register the given field paths as to be ignored in the comparison.
* <p>
Expand All @@ -125,6 +91,50 @@ boolean shouldIgnore(DualKey dualKey) {
|| matchesAnIgnoredRegex(dualKey);
}

public void ignoreFieldsByRegexes(String... regexes) {
this.ignoredFieldsRegexes = Stream.of(regexes)
.map(Pattern::compile)
.collect(toList());
}

public void ignoreCustomEqualsByRegexes(String... regexes) {
this.ignoredCustomEqualsRegexes = Stream.of(regexes)
.map(Pattern::compile)
.collect(toList());
}

public boolean shouldIgnoreOverriddenEquals(Class<? extends Object> clazz) {
return matchesAnIgnoreOverriddenEqualsRegex(clazz);
}

@Override
public String toString() {
return multiLineDescription(CONFIGURATION_PROVIDER.representation());
}

public String multiLineDescription(Representation representation) { // TODO use representation ?
StringBuilder description = new StringBuilder();
if (ignoreAllActualNullFields) description.append(format("- all actual null fields were ignored in the comparison%n"));
if (!ignoredFields.isEmpty())
description.append(format("- the following fields were ignored in the comparison: %s%n", describeIgnoredFields()));
if (!ignoredFieldsRegexes.isEmpty())
description.append(format("- the following regexes were used to ignore fields in the comparison: %s%n",
describeRegexes(ignoredFieldsRegexes)));
if (!ignoredCustomEqualsRegexes.isEmpty())
description.append(format("- the following regexes were used to ignore overridden equals methods in the comparison: %s%n",
describeRegexes(ignoredCustomEqualsRegexes)));
return description.toString();
}

// private stuff

private boolean matchesAnIgnoreOverriddenEqualsRegex(Class<? extends Object> clazz) {
if (this.ignoredCustomEqualsRegexes.isEmpty()) return false; // shortcut
String canonicalName = clazz.getCanonicalName();
return this.ignoredCustomEqualsRegexes.stream()
.anyMatch(regex -> regex.matcher(canonicalName).matches());
}

private boolean matchesAnIgnoredNullField(DualKey dualKey) {
return ignoreAllActualNullFields && dualKey.key1 == null;
}
Expand All @@ -139,9 +149,18 @@ private boolean matchesAnIgnoredField(DualKey dualKey) {
.anyMatch(fieldLocation -> fieldLocation.matches(dualKey.concatenatedPath));
}

public void ignoreFieldsByRegexes(String... regexes) {
this.ignoredFieldsRegexes = Stream.of(regexes)
.map(Pattern::compile)
.collect(toList());
private String describeIgnoredFields() {
List<String> fieldsDescription = ignoredFields.stream()
.map(FieldLocation::getFieldPath)
.collect(toList());
return join(fieldsDescription).with(", ");
}

private String describeRegexes(List<Pattern> regexes) {
List<String> fieldsDescription = regexes.stream()
.map(Pattern::pattern)
.collect(toList());
return join(fieldsDescription).with(", ");
}

}
Expand Up @@ -209,7 +209,8 @@ private static List<ComparisonDifference> determineDifferences(Object actual, Ob
continue;
}

if (hasCustomEquals(key1.getClass())) {
if (!recursiveComparisonConfiguration.shouldIgnoreOverriddenEquals(key1.getClass())
&& hasCustomEquals(key1.getClass())) {
if (!key1.equals(key2)) {
differences.add(new ComparisonDifference(currentPath, key1, key2));
continue;
Expand Down
Expand Up @@ -23,7 +23,7 @@ public void should_show_that_null_fields_are_ignored() {
recursiveComparisonConfiguration.setIgnoreAllActualNullFields(true);
String multiLineDescription = recursiveComparisonConfiguration.multiLineDescription(STANDARD_REPRESENTATION);
// THEN
assertThat(multiLineDescription).isEqualTo(format("- all actual null fields were ignored in the comparison%n"));
assertThat(multiLineDescription).contains(format("- all actual null fields were ignored in the comparison%n"));
}

@Test
Expand All @@ -32,7 +32,7 @@ public void should_show_that_some_given_fields_are_ignored() {
recursiveComparisonConfiguration.ignoreFields("foo", "bar", "foo.bar");
String multiLineDescription = recursiveComparisonConfiguration.multiLineDescription(STANDARD_REPRESENTATION);
// THEN
assertThat(multiLineDescription).isEqualTo(format("- the following fields were ignored in the comparison: foo, bar, foo.bar%n"));
assertThat(multiLineDescription).contains(format("- the following fields were ignored in the comparison: foo, bar, foo.bar%n"));
}

@Test
Expand All @@ -41,9 +41,19 @@ public void should_show_the_regexes_used_to_ignore_fields() {
recursiveComparisonConfiguration.ignoreFieldsByRegexes("foo", "bar", "foo.bar");
String multiLineDescription = recursiveComparisonConfiguration.multiLineDescription(STANDARD_REPRESENTATION);
// THEN
assertThat(multiLineDescription).isEqualTo(format("- the following regexes were used to ignore fields in the comparison: foo, bar, foo.bar%n"));
assertThat(multiLineDescription).contains(format("- the following regexes were used to ignore fields in the comparison: foo, bar, foo.bar%n"));
}

@Test
public void should_show_the_when_overridden_equals_were_used() {
// WHEN
String multiLineDescription = recursiveComparisonConfiguration.multiLineDescription(STANDARD_REPRESENTATION);
// THEN
assertThat(multiLineDescription).contains(format("- overridden equals methods were used in the recursive comparison%n"));
}

// TODO should_show_the_ignored_overridden_equals_methods_regexes

@Test
public void should_show_a_complete_multiline_description() {
// WHEN
Expand All @@ -53,7 +63,8 @@ public void should_show_a_complete_multiline_description() {
String multiLineDescription = recursiveComparisonConfiguration.multiLineDescription(STANDARD_REPRESENTATION);
// THEN
// @format:off
assertThat(multiLineDescription).isEqualTo(format("- all actual null fields were ignored in the comparison%n" +
assertThat(multiLineDescription).isEqualTo(format("- overridden equals methods were used in the recursive comparison%n" +
"- all actual null fields were ignored in the comparison%n" +
"- the following fields were ignored in the comparison: foo, bar, foo.bar%n" +
"- the following regexes were used to ignore fields in the comparison: f.*, .ba., ..b%%sr..%n"));
// @format:on
Expand Down
@@ -0,0 +1,53 @@
/*
* 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-2018 the original author or authors.
*/
package org.assertj.core.internal.objects;

import static org.assertj.core.error.ShouldBeEqualByComparingFieldByFieldRecursively.shouldBeEqualByComparingFieldByFieldRecursively;
import static org.assertj.core.test.TestData.someInfo;
import static org.assertj.core.util.Lists.list;
import static org.mockito.Mockito.verify;

import org.assertj.core.api.AssertionInfo;
import org.assertj.core.api.recursive.comparison.ComparisonDifference;
import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration;
import org.assertj.core.internal.ObjectsBaseTest;
import org.junit.jupiter.api.BeforeEach;

public class Objects_assertIsEqualToUsingRecursiveComparison_BaseTest extends ObjectsBaseTest {

static final AssertionInfo INFO = someInfo();
RecursiveComparisonConfiguration recursiveComparisonConfiguration;

@BeforeEach
public void setup() {
recursiveComparisonConfiguration = new RecursiveComparisonConfiguration();
}

void verifyShouldBeEqualByComparingFieldByFieldRecursivelyCall(Object actual, Object expected,
ComparisonDifference... differences) {
verify(failures).failure(INFO, shouldBeEqualByComparingFieldByFieldRecursively(actual,
expected,
list(differences),
recursiveComparisonConfiguration,
INFO.representation()));
}

void compareRecusively(Object actual, Object expected,
RecursiveComparisonConfiguration recursiveComparisonConfiguration) {
objects.assertIsEqualToUsingRecursiveComparison(INFO, actual, expected, recursiveComparisonConfiguration);
}

static ComparisonDifference diff(String path, Object actual, Object other) {
return new ComparisonDifference(list(path), actual, other);
}
}

0 comments on commit 1b32e2d

Please sign in to comment.