diff --git a/assertj-core/src/main/java/org/assertj/core/error/ShouldBeEqual.java b/assertj-core/src/main/java/org/assertj/core/error/ShouldBeEqual.java index f0510b6bf1..f0650b2f9c 100644 --- a/assertj-core/src/main/java/org/assertj/core/error/ShouldBeEqual.java +++ b/assertj-core/src/main/java/org/assertj/core/error/ShouldBeEqual.java @@ -28,6 +28,7 @@ import org.assertj.core.internal.StandardComparisonStrategy; import org.assertj.core.presentation.Representation; import org.assertj.core.util.VisibleForTesting; +import org.assertj.core.util.introspection.ClassUtils; /** * Creates an {@link AssertionError} indicating that an assertion that verifies that two objects are equal @@ -195,18 +196,20 @@ protected String indent(String valueRepresentation) { } /** - * Builds and returns an error message from description using {@link #detailedExpected()} and - * {@link #detailedActual()} detailed representation. + * Builds and returns an error message from description using {@link #detailedExpected(boolean)} and + * {@link #detailedActual(boolean)} detailed representation. * * @param description the {@link Description} used to build the returned error message * @param representation the {@link org.assertj.core.presentation.Representation} used to build String representation * of object - * @return the error message from description using {@link #detailedExpected()} and {@link #detailedActual()} + * @return the error message from description using {@link #detailedExpected(boolean)} and {@link #detailedActual(boolean)} * detailed representation. */ protected String defaultDetailedErrorMessage(Description description, Representation representation) { - String actualRepresentation = detailedActual(); - String expectedRepresentation = detailedExpected(); + boolean sameClassNameInDifferentPackages = ClassUtils.areClassesWithSameNameInDifferentPackages(actual.getClass(), + expected.getClass()); + String actualRepresentation = detailedActual(sameClassNameInDifferentPackages); + String expectedRepresentation = detailedExpected(sameClassNameInDifferentPackages); if (hasMultilineValue(actualRepresentation, expectedRepresentation)) { return errorMessageForMultilineValues(description, representation, actualRepresentation, expectedRepresentation); } @@ -255,12 +258,12 @@ private AssertionError newComparisonFailure(String description) throws Exception return o instanceof AssertionError ? (AssertionError) o : null; } - protected String detailedActual() { - return representation.unambiguousToStringOf(actual); + protected String detailedActual(boolean sameClassWithDifferentPackages) { + return representation.unambiguousToStringOf(actual, sameClassWithDifferentPackages); } - protected String detailedExpected() { - return representation.unambiguousToStringOf(expected); + protected String detailedExpected(boolean sameClassWithDifferentPackages) { + return representation.unambiguousToStringOf(expected, sameClassWithDifferentPackages); } @Override diff --git a/assertj-core/src/main/java/org/assertj/core/internal/UnambiguousRepresentation.java b/assertj-core/src/main/java/org/assertj/core/internal/UnambiguousRepresentation.java index abe5609533..1e7d0dcda2 100644 --- a/assertj-core/src/main/java/org/assertj/core/internal/UnambiguousRepresentation.java +++ b/assertj-core/src/main/java/org/assertj/core/internal/UnambiguousRepresentation.java @@ -19,7 +19,7 @@ /** * Utility class around {@link Representation} to provide the {@link Representation#toStringOf(Object) toStringOf} * representations of {@code actual} and {@code expected} when they are different, and their - * {@link Representation#unambiguousToStringOf(Object) unambiguousToStringOf} representations if not. + * {@link Representation#unambiguousToStringOf(Object, boolean) unambiguousToStringOf} representations if not. */ public class UnambiguousRepresentation { @@ -33,10 +33,10 @@ public UnambiguousRepresentation(Representation representation, Object actual, O boolean sameRepresentation = Objects.equals(actualRepresentation, expectedRepresentation); this.actual = sameRepresentation - ? representation.unambiguousToStringOf(actual) + ? representation.unambiguousToStringOf(actual, false) : actualRepresentation; this.expected = sameRepresentation - ? representation.unambiguousToStringOf(expected) + ? representation.unambiguousToStringOf(expected, false) : expectedRepresentation; } diff --git a/assertj-core/src/main/java/org/assertj/core/presentation/CompositeRepresentation.java b/assertj-core/src/main/java/org/assertj/core/presentation/CompositeRepresentation.java index 7c2af9b9a8..5f406ce004 100644 --- a/assertj-core/src/main/java/org/assertj/core/presentation/CompositeRepresentation.java +++ b/assertj-core/src/main/java/org/assertj/core/presentation/CompositeRepresentation.java @@ -41,13 +41,13 @@ public String toStringOf(Object object) { } @Override - public String unambiguousToStringOf(Object object) { + public String unambiguousToStringOf(Object object, boolean shouldKeepPackage) { // don't create streams for performance reasons and because this code is simple enough (even not as elegant as with stream) for (Representation representation : representations) { - String value = representation.unambiguousToStringOf(object); + String value = representation.unambiguousToStringOf(object, shouldKeepPackage); if (value != null) return value; } - return STANDARD_REPRESENTATION.unambiguousToStringOf(object); + return STANDARD_REPRESENTATION.unambiguousToStringOf(object, shouldKeepPackage); } @Override diff --git a/assertj-core/src/main/java/org/assertj/core/presentation/Representation.java b/assertj-core/src/main/java/org/assertj/core/presentation/Representation.java index c876af310d..afbdc51700 100644 --- a/assertj-core/src/main/java/org/assertj/core/presentation/Representation.java +++ b/assertj-core/src/main/java/org/assertj/core/presentation/Representation.java @@ -65,16 +65,17 @@ public interface Representation { String toStringOf(Object object); /** - * Override this method to return a {@code String} representation of the given object that is unambigous so that it can + * Override this method to return a {@code String} representation of the given object that is unambigous so that it can * be differentiated from other objects with the same {@link #toStringOf(Object)} representation. *

- * The default implementation calls {@link #toStringOf(Object)} but the {@link StandardRepresentation} adds - * the object hexadecimal identity hash code. + * The default implementation calls {@link #toStringOf(Object)} but the {@link StandardRepresentation} adds + * the object hexadecimal identity hash code. * - * @param object the object to represent. + * @param object the object to represent. + * @param shouldKeepPackage if we should display the object's package * @return the unambiguous {@code toString} representation of the given object. */ - default String unambiguousToStringOf(Object object) { + default String unambiguousToStringOf(Object object, boolean shouldKeepPackage) { return toStringOf(object); } diff --git a/assertj-core/src/main/java/org/assertj/core/presentation/StandardRepresentation.java b/assertj-core/src/main/java/org/assertj/core/presentation/StandardRepresentation.java index 57de0b4121..0a0df863ae 100644 --- a/assertj-core/src/main/java/org/assertj/core/presentation/StandardRepresentation.java +++ b/assertj-core/src/main/java/org/assertj/core/presentation/StandardRepresentation.java @@ -297,14 +297,21 @@ private static boolean hasOverriddenToStringInSubclassOf(Class objectClass, C * Returns the {@code String} representation of the given object with its type and hexadecimal identity hash code so that * it can be differentiated from other objects with the same {@link #toStringOf(Object)} representation. * - * @param obj the object to represent. + * @param obj the object to represent. + * @param shouldKeepPackage * @return the unambiguous {@code toString} representation of the given object. */ @Override - public String unambiguousToStringOf(Object obj) { + public String unambiguousToStringOf(Object obj, boolean shouldKeepPackage) { + if (obj == null) return null; // some types have already an unambiguous toString, no need to double down if (hasAlreadyAnUnambiguousToStringOf(obj)) return toStringOf(obj); - return obj == null ? null : String.format("%s (%s@%s)", toStringOf(obj), classNameOf(obj), identityHexCodeOf(obj)); + return obj == null ? null + : String.format("%s (%s@%s)", toStringOf(obj), getObject(obj, shouldKeepPackage), identityHexCodeOf(obj)); + } + + private Object getObject(Object obj, boolean shouldKeepPackage) { + return shouldKeepPackage ? packageAndClassNameOf(obj) : classNameOf(obj); } @Override @@ -740,6 +747,10 @@ private static Object classNameOf(Object obj) { return obj.getClass().isAnonymousClass() ? obj.getClass().getName() : obj.getClass().getSimpleName(); } + private static Object packageAndClassNameOf(Object obj) { + return String.format("%s.%s", obj.getClass().getPackageName(), classNameOf(obj)); + } + private String defaultToStringWithClassNameDisambiguation(Object o) { return o.toString() + classNameDisambiguation(o); } diff --git a/assertj-core/src/main/java/org/assertj/core/util/introspection/ClassUtils.java b/assertj-core/src/main/java/org/assertj/core/util/introspection/ClassUtils.java index 4590b5707c..ad6e7f9193 100644 --- a/assertj-core/src/main/java/org/assertj/core/util/introspection/ClassUtils.java +++ b/assertj-core/src/main/java/org/assertj/core/util/introspection/ClassUtils.java @@ -145,4 +145,17 @@ public static boolean isOptionalOrPrimitiveOptional(final Class type) { public static boolean isInJavaLangPackage(final Class type) { return type != null && type.getName().startsWith("java.lang"); } + + /** + * Returns whether the given {@code type1} and {@code type2} have the same name but are + * located in different packages + * + * @param type1 first class to compare + * @param type2 the class to compare to + * @return true if the given {@code type1} have the same name as {@code type2} but is + * in a different package + */ + public static boolean areClassesWithSameNameInDifferentPackages(Class type1, Class type2) { + return type1.getSimpleName().equals(type2.getSimpleName()) && !type1.getPackageName().equals(type2.getPackageName()); + } } diff --git a/assertj-core/src/test/java/org/assertj/core/internal/UnambiguousRepresentation_Test.java b/assertj-core/src/test/java/org/assertj/core/internal/UnambiguousRepresentation_Test.java index 52f90da28d..a96a0a114f 100644 --- a/assertj-core/src/test/java/org/assertj/core/internal/UnambiguousRepresentation_Test.java +++ b/assertj-core/src/test/java/org/assertj/core/internal/UnambiguousRepresentation_Test.java @@ -53,8 +53,8 @@ void should_use_unambiguousToStringOf_whe_toStringOf_are_equal() { Object expected = new Object(); given(representation.toStringOf(actual)).willReturn("representation"); given(representation.toStringOf(expected)).willReturn("representation"); - given(representation.unambiguousToStringOf(actual)).willReturn("actual"); - given(representation.unambiguousToStringOf(expected)).willReturn("expected"); + given(representation.unambiguousToStringOf(actual, false)).willReturn("actual"); + given(representation.unambiguousToStringOf(expected, false)).willReturn("expected"); // WHEN UnambiguousRepresentation actualRepresentation = new UnambiguousRepresentation(representation, actual, expected); // THEN diff --git a/assertj-core/src/test/java/org/assertj/core/presentation/CompositeRepresentation_Test.java b/assertj-core/src/test/java/org/assertj/core/presentation/CompositeRepresentation_Test.java index c03050d0fc..925b88de9e 100644 --- a/assertj-core/src/test/java/org/assertj/core/presentation/CompositeRepresentation_Test.java +++ b/assertj-core/src/test/java/org/assertj/core/presentation/CompositeRepresentation_Test.java @@ -34,7 +34,7 @@ void should_use_representation_with_highest_priority() { CompositeRepresentation compositeRepresentation = new CompositeRepresentation(representations); // WHEN String toString = compositeRepresentation.toStringOf("foo"); - String unambiguousToString = compositeRepresentation.unambiguousToStringOf("foo"); + String unambiguousToString = compositeRepresentation.unambiguousToStringOf("foo", false); // THEN then(toString).isEqualTo("3"); then(unambiguousToString).isEqualTo("3"); @@ -48,7 +48,9 @@ void should_use_standard_representation_if_composite_representation_is_not_given Object longNumber = 123L; // THEN then(compositeRepresentation.toStringOf(longNumber)).isEqualTo(STANDARD_REPRESENTATION.toStringOf(longNumber)); - then(compositeRepresentation.unambiguousToStringOf(longNumber)).isEqualTo(STANDARD_REPRESENTATION.unambiguousToStringOf(longNumber)); + then(compositeRepresentation.unambiguousToStringOf(longNumber, + false)).isEqualTo(STANDARD_REPRESENTATION.unambiguousToStringOf(longNumber, + false)); } @Test @@ -86,7 +88,7 @@ public int getPriority() { } @Override - public String unambiguousToStringOf(Object object) { + public String unambiguousToStringOf(Object object, boolean shouldKeepPackage) { return "" + getPriority(); } diff --git a/assertj-core/src/test/java/org/assertj/core/presentation/StandardRepresentation_unambiguousToStringOf_Test.java b/assertj-core/src/test/java/org/assertj/core/presentation/StandardRepresentation_unambiguousToStringOf_Test.java index 88d44ec8d1..c03bbeb11b 100644 --- a/assertj-core/src/test/java/org/assertj/core/presentation/StandardRepresentation_unambiguousToStringOf_Test.java +++ b/assertj-core/src/test/java/org/assertj/core/presentation/StandardRepresentation_unambiguousToStringOf_Test.java @@ -48,7 +48,7 @@ import org.junit.jupiter.api.Test; /** - * Tests for {@link StandardRepresentation#unambiguousToStringOf(Object)}. + * Tests for {@link Representation#unambiguousToStringOf(Object, boolean)}. * * @author Alexandre Dutra */ @@ -405,8 +405,34 @@ void isEqualTo_should_show_disambiguated_objects_with_same_hash_code_and_toStrin .hasMessageContaining(unambiguousToStringOf(ambiguous2)); } + @Test + void should_get_unambiguous_representation_with_package() { + // GIVEN + Person person = new Person(); + boolean shouldKeepPackageName = true; + + // WHEN + String unambiguousRepresentation = STANDARD_REPRESENTATION.unambiguousToStringOf(person, shouldKeepPackageName); + + // THEN + assertThat(unambiguousRepresentation).isEqualTo("Person [name=null, age=0, account=0] (org.assertj.core.presentation.Person@3d299e3)"); + } + + @Test + void should_get_unambiguous_representation_without_package() { + // GIVEN + Person person = new Person(); + boolean shouldKeepPackageName = false; + + // WHEN + String unambiguousRepresentation = STANDARD_REPRESENTATION.unambiguousToStringOf(person, shouldKeepPackageName); + + // THEN + assertThat(unambiguousRepresentation).isEqualTo("Person [name=null, age=0, account=0] (Person@3d299e3)"); + } + private static String unambiguousToStringOf(Object o) { - return STANDARD_REPRESENTATION.unambiguousToStringOf(o); + return STANDARD_REPRESENTATION.unambiguousToStringOf(o, false); } private static class MyTestFile extends File { diff --git a/assertj-core/src/test/java/org/assertj/core/util/introspection/ClassUtils_areSameClassInDifferentPackages_Test.java b/assertj-core/src/test/java/org/assertj/core/util/introspection/ClassUtils_areSameClassInDifferentPackages_Test.java new file mode 100644 index 0000000000..49becdf890 --- /dev/null +++ b/assertj-core/src/test/java/org/assertj/core/util/introspection/ClassUtils_areSameClassInDifferentPackages_Test.java @@ -0,0 +1,35 @@ +package org.assertj.core.util.introspection; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.BDDAssertions.then; + +class ClassUtils_areSameClassInDifferentPackages_Test { + + @Test + void areClassesWithSameNameInDifferentPackages() { + // WHEN + boolean areSameClassInDifferentPackages = ClassUtils.areClassesWithSameNameInDifferentPackages(java.util.Date.class, + java.sql.Date.class); + // THEN + then(areSameClassInDifferentPackages).isTrue(); + } + + @Test + void areClassesWithSameNameInDifferentPackagesForSameClass() { + // WHEN + boolean areSameClassInDifferentPackages = ClassUtils.areClassesWithSameNameInDifferentPackages(java.util.Date.class, + java.util.Date.class); + // THEN + then(areSameClassInDifferentPackages).isFalse(); + } + + @Test + void areNotClassesWithSameNameInDifferentPackages() { + // WHEN + boolean areSameClassInDifferentPackages = ClassUtils.areClassesWithSameNameInDifferentPackages(java.util.Date.class, + java.text.DateFormat.class); + // THEN + then(areSameClassInDifferentPackages).isFalse(); + } +}