Skip to content

Commit

Permalink
Merge branch 'main' of github.com:assertj/assertj
Browse files Browse the repository at this point in the history
  • Loading branch information
java-coding-prodigy committed Nov 6, 2022
2 parents a4d7146 + 3bda0ee commit 67497c7
Show file tree
Hide file tree
Showing 105 changed files with 1,834 additions and 718 deletions.
4 changes: 2 additions & 2 deletions assertj-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.10.1</version>
<version>3.11</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -141,7 +141,7 @@
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.1.4.Final</version>
<version>6.1.5.Final</version>
<scope>test</scope>
<exclusions>
<exclusion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import java.util.function.BiPredicate;

import org.assertj.core.api.recursive.comparison.ComparisonDifference;
import org.assertj.core.api.recursive.comparison.DefaultRecursiveComparisonIntrospectionStrategy;
import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration;
import org.assertj.core.api.recursive.comparison.RecursiveComparisonDifferenceCalculator;
import org.assertj.core.api.recursive.comparison.RecursiveComparisonIntrospectionStrategy;
import org.assertj.core.internal.TypeComparators;
import org.assertj.core.util.CheckReturnValue;
import org.assertj.core.util.introspection.IntrospectionError;
Expand Down Expand Up @@ -1454,6 +1456,24 @@ public SELF withErrorMessageForType(String message, Class<?> type) {
return myself;
}

/**
* Defines how objects are introspected in the recursive comparison, that is:
* <ul>
* <li>how to traverse the graph of nodes to compare</li>
* <li>how to get a node value</li>
* </ul>
* <p>
* Default to {@link DefaultRecursiveComparisonIntrospectionStrategy} that introspects all fields (including inherited ones).
*
* @param introspectionStrategy the {@link RecursiveComparisonIntrospectionStrategy} to use
* @return this {@link RecursiveComparisonAssert} to chain other methods.
*/
@CheckReturnValue
public SELF withIntrospectionStrategy(RecursiveComparisonIntrospectionStrategy introspectionStrategy) {
recursiveComparisonConfiguration.setIntrospectionStrategy(introspectionStrategy);
return myself;
}

SELF withTypeComparators(TypeComparators typeComparators) {
Optional.ofNullable(typeComparators)
.map(TypeComparators::comparatorByTypes)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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-2022 the original author or authors.
*/
package org.assertj.core.api.recursive.comparison;

import static org.assertj.core.internal.Objects.getFieldsNames;

import java.util.HashSet;
import java.util.Set;

import org.assertj.core.util.introspection.FieldSupport;

/**
* A {@link RecursiveComparisonIntrospectionStrategy} that introspects fields including inherited ones but ignores static and
* synthetic fields.
*/
public class ComparingFields implements RecursiveComparisonIntrospectionStrategy {

public static final ComparingFields COMPARING_FIELDS = new ComparingFields();

@Override
public Set<String> getChildrenNodeNamesOf(Object node) {
return node == null ? new HashSet<>() : getFieldsNames(node.getClass());
}

@Override
public Object getChildNodeValue(String childNodeName, Object instance) {
return FieldSupport.comparison().fieldValue(childNodeName, Object.class, instance);
}

@Override
public String getDescription() {
return "comparing fields";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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-2022 the original author or authors.
*/
package org.assertj.core.api.recursive.comparison;

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toSet;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

import org.assertj.core.util.introspection.PropertySupport;

/**
* A {@link RecursiveComparisonIntrospectionStrategy} that introspects properties by looking at public getters like
* {@code getName()} or {@code isActive()}/{@code getActive()} for boolean properties.
*/
public class ComparingProperties implements RecursiveComparisonIntrospectionStrategy {

public static final ComparingProperties COMPARING_PROPERTIES = new ComparingProperties();

private static final String GET_PREFIX = "get";
private static final String IS_PREFIX = "is";

@Override
public Set<String> getChildrenNodeNamesOf(Object node) {
return node == null ? new HashSet<>() : getPropertiesNamesOf(node.getClass());
}

@Override
public Object getChildNodeValue(String childNodeName, Object instance) {
return PropertySupport.instance().propertyValueOf(childNodeName, Object.class, instance);
}

@Override
public String getDescription() {
return "comparing properties";
}

static Set<String> getPropertiesNamesOf(Class<?> clazz) {
return gettersIncludingInheritedOf(clazz).stream()
.map(Method::getName)
.map(ComparingProperties::toPropertyName)
.collect(toSet());
}

private static String toPropertyName(String methodName) {
String propertyWithCapitalLetter = methodName.startsWith(GET_PREFIX)
? methodName.substring(GET_PREFIX.length())
: methodName.substring(IS_PREFIX.length());
return propertyWithCapitalLetter.toLowerCase().charAt(0) + propertyWithCapitalLetter.substring(1);
}

public static Set<Method> gettersIncludingInheritedOf(Class<?> clazz) {
Set<Method> getters = gettersOf(clazz);
// get fields declared in superClass
Class<?> superClass = clazz.getSuperclass();
while (superClass != null && !superClass.getName().startsWith("java.lang")) {
getters.addAll(gettersOf(superClass));
superClass = superClass.getSuperclass();
}
return getters;
}

private static Set<Method> gettersOf(Class<?> clazz) {
return stream(clazz.getDeclaredMethods()).filter(method -> !isStatic(method))
.filter(ComparingProperties::isPublic)
.filter(ComparingProperties::isGetter)
.collect(toCollection(LinkedHashSet::new));
}

private static boolean isStatic(Method method) {
return Modifier.isStatic(method.getModifiers());
}

private static boolean isPublic(Method method) {
return Modifier.isPublic(method.getModifiers());
}

private static boolean isGetter(Method method) {
if (hasParameters(method)) return false;
return isRegularGetter(method) || isBooleanProperty(method);
}

private static boolean isRegularGetter(Method method) {
return method.getName().startsWith(GET_PREFIX);
}

private static boolean hasParameters(Method method) {
return method.getParameters().length > 0;
}

private static boolean isBooleanProperty(Method method) {
Class<?> returnType = method.getReturnType();
return method.getName().startsWith(IS_PREFIX) && (returnType.equals(boolean.class) || returnType.equals(Boolean.class));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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-2022 the original author or authors.
*/
package org.assertj.core.api.recursive.comparison;

import static org.assertj.core.util.introspection.PropertyOrFieldSupport.COMPARISON;

import java.util.HashSet;
import java.util.Set;

import org.assertj.core.internal.Objects;
import org.assertj.core.util.introspection.PropertyOrFieldSupport;

/**
* Introspects all fields (including inherited ones) and get their value according to {@link PropertyOrFieldSupport#getSimpleValue(String, Object)}.
* <p>
* There is a bit of discrepancy in this strategy as it looks for fields to compare but gets the value in this order: property
* first, then field and finally tries as map value if the instance is a map.
*/
public class DefaultRecursiveComparisonIntrospectionStrategy implements RecursiveComparisonIntrospectionStrategy {

@Override
public Set<String> getChildrenNodeNamesOf(Object node) {
return node == null ? new HashSet<>() : Objects.getFieldsNames(node.getClass());
}

@Override
public Object getChildNodeValue(String childNodeName, Object instance) {
return COMPARISON.getSimpleValue(childNodeName, instance);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public static FieldLocation rootFieldLocation() {
* @return true if this has the given parent (direct or indirect), false otherwise.
*/
public boolean hasParent(FieldLocation parent) {
// "." garantees that we compare path elements, this avoid making "name" a parent of "names"
// "." guarantees that we compare path elements, this avoids making "name" a parent of "names"
return pathToUseInRules.startsWith(parent.pathToUseInRules + ".");
}

Expand Down
Loading

0 comments on commit 67497c7

Please sign in to comment.