[LANG-1724] Customize text pattern in DiffResult#toString()

- Add DiffBuilder.Builder
- Add DiffBuilder.builder()
This commit is contained in:
Gary Gregory 2023-12-11 15:18:47 -05:00
parent d0f012d736
commit aa4eef85cf
6 changed files with 302 additions and 253 deletions

View File

@ -26,7 +26,7 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>commons-lang3</artifactId>
<version>3.14.1-SNAPSHOT</version>
<version>3.15.0-SNAPSHOT</version>
<name>Apache Commons Lang</name>
<inceptionYear>2001</inceptionYear>
@ -47,7 +47,7 @@
<connection>scm:git:http://gitbox.apache.org/repos/asf/commons-lang.git</connection>
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/commons-lang.git</developerConnection>
<url>https://gitbox.apache.org/repos/asf?p=commons-lang.git</url>
<tag>rel/commons-lang-3.14.0</tag>
<tag>rel/commons-lang-3.15.0</tag>
</scm>
<developers>
@ -607,8 +607,8 @@
<commons.packageId>lang3</commons.packageId>
<commons.module.name>org.apache.commons.lang3</commons.module.name>
<!-- Current 3.x release series -->
<commons.release.version>3.14.1</commons.release.version>
<commons.release.next>3.14.2</commons.release.next>
<commons.release.version>3.15.0</commons.release.version>
<commons.release.next>3.15.1</commons.release.next>
<commons.release.desc>(Java 8+)</commons.release.desc>
<!-- Previous 2.x release series -->
<commons.release.2.version>2.6</commons.release.2.version>

View File

@ -45,7 +45,11 @@ The <action> type attribute can be add,update,fix,remove.
<title>Apache Commons Lang Release Notes</title>
</properties>
<body>
<release version="3.14.1" date="202Y-MM-DD" description="New features and bug fixes (Java 8 or above).">
<release version="3.15.0" date="202Y-MM-DD" description="New features and bug fixes (Java 8 or above).">
<!-- ADD -->
<action issue="LANG-1724" type="add" dev="ggregory" due-to="Gary Gregory, Dennis Baerten">Customize text pattern in DiffResult#toString().</action>
<action issue="LANG-1724" type="add" dev="ggregory" due-to="Gary Gregory">Add DiffBuilder.Builder</action>
<action issue="LANG-1724" type="add" dev="ggregory" due-to="Gary Gregory">Add DiffBuilder.builder()</action>
<!-- FIX -->
<action type="fix" dev="ggregory" due-to="Miklós Karakó, Gary Gregory">Improve Javadoc in ExceptionUtils #1136.</action>
<action type="fix" dev="ggregory" due-to="Saiharshith Karuneegar Ramesh, Gary Gregory">Fixed two non-deterministic tests in EnumUtilsTest.java #1131.</action>

View File

@ -52,10 +52,8 @@ import org.apache.commons.lang3.ObjectUtils;
* </pre>
*
* <p>
* The {@link ToStringStyle} passed to the constructor is embedded in the
* returned {@link DiffResult} and influences the style of the
* {@code DiffResult.toString()} method. This style choice can be overridden by
* calling {@link DiffResult#toString(ToStringStyle)}.
* The {@link ToStringStyle} passed to the constructor is embedded in the returned {@link DiffResult} and influences the style of the
* {@code DiffResult.toString()} method. This style choice can be overridden by calling {@link DiffResult#toString(ToStringStyle)}.
* </p>
* <p>
* See {@link ReflectionDiffBuilder} for a reflection based version of this class.
@ -71,6 +69,89 @@ import org.apache.commons.lang3.ObjectUtils;
*/
public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Constructs a new instance.
*
* @param <T> type of the left and right object.
* @since 3.15.0
*/
public static final class Builder<T> {
private T left;
private T right;
private ToStringStyle style;
private boolean testObjectsEquals = true;
private String toStringFormat = TO_STRING_FORMAT;
/**
* Builds a new configured {@link DiffBuilder}.
*
* @return a new configured {@link DiffBuilder}.
*/
public DiffBuilder<T> build() {
return new DiffBuilder<>(left, right, style, testObjectsEquals, toStringFormat);
}
/**
* Sets the left object.
*
* @param left the left object.
* @return this.
*/
public Builder<T> setLeft(final T left) {
this.left = left;
return this;
}
/**
* Sets the right object.
*
* @param right the left object.
* @return this.
*/
public Builder<T> setRight(final T right) {
this.right = right;
return this;
}
/**
* Sets the style will to use when outputting the objects, {@code null} uses the default.
*
* @param style the style to use when outputting the objects, {@code null} uses the default.
* @return this.
*/
public Builder<T> setStyle(final ToStringStyle style) {
this.style = style != null ? style : ToStringStyle.DEFAULT_STYLE;
return this;
}
/**
* Sets whether to test if left and right are the same or equal. All of the append(fieldName, left, right) methods will abort without creating a field
* {@link Diff} if the trivially equal test is enabled and returns true. The result of this test is never changed throughout the life of this
* {@link DiffBuilder}.
*
* @param testObjectsEquals If true, this will test if lhs and rhs are the same or equal. All of the append(fieldName, left, right) methods will abort
* without creating a field {@link Diff} if the trivially equal test is enabled and returns true. The result of this test is
* never changed throughout the life of this {@link DiffBuilder}.
* @return this.
*/
public Builder<T> setTestObjectsEquals(final boolean testObjectsEquals) {
this.testObjectsEquals = testObjectsEquals;
return this;
}
/**
* Sets the two-argument format string for {@link String#format(String, Object...)}, for example {@code "%s differs from %s"}.
*
* @param toStringFormat {@code null} uses the default.
* @return this.
*/
public Builder<T> setToStringFormat(final String toStringFormat) {
this.toStringFormat = toStringFormat != null ? toStringFormat : TO_STRING_FORMAT;
return this;
}
}
private static final class SDiff<T> extends Diff<T> {
private static final long serialVersionUID = 1L;
@ -94,8 +175,20 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
}
}
static final String TO_STRING_FORMAT = "%s differs from %s";
/**
* Constructs a new {@link Builder}.
*
* @param <T> type of the left and right object.
* @return a new {@link Builder}.
* @since 3.15.0
*/
public static <T> Builder<T> builder() {
return new Builder<>();
}
private final List<Diff<?>> diffs;
private final boolean equals;
private final T left;
@ -107,64 +200,56 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
* Constructs a builder for the specified objects with the specified style.
*
* <p>
* If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will
* not evaluate any calls to {@code append(...)} and will return an empty
* If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will not evaluate any calls to {@code append(...)} and will return an empty
* {@link DiffResult} when {@link #build()} is executed.
* </p>
*
* <p>
* This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)}
* with the testTriviallyEqual flag enabled.
* This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)} with the testTriviallyEqual flag enabled.
* </p>
*
* @param lhs
* {@code this} object
* @param rhs
* the object to diff against
* @param style
* the style will use when outputting the objects, {@code null}
* uses the default
* @throws NullPointerException
* if {@code lhs} or {@code rhs} is {@code null}
* @param left {@code this} object
* @param right the object to diff against
* @param style the style to use when outputting the objects, {@code null} uses the default
* @throws NullPointerException if {@code lhs} or {@code rhs} is {@code null}
* @deprecated Use {@link Builder}.
*/
public DiffBuilder(final T lhs, final T rhs, final ToStringStyle style) {
this(lhs, rhs, style, true);
@Deprecated
public DiffBuilder(final T left, final T right, final ToStringStyle style) {
this(left, right, style, true);
}
/**
* Constructs a builder for the specified objects with the specified style.
*
* <p>
* If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will
* not evaluate any calls to {@code append(...)} and will return an empty
* If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will not evaluate any calls to {@code append(...)} and will return an empty
* {@link DiffResult} when {@link #build()} is executed.
* </p>
*
* @param lhs
* {@code this} object
* @param rhs
* the object to diff against
* @param style
* the style will use when outputting the objects, {@code null}
* uses the default
* @param testObjectsEquals
* If true, this will test if lhs and rhs are the same or equal.
* All of the append(fieldName, lhs, rhs) methods will abort
* without creating a field {@link Diff} if the trivially equal
* test is enabled and returns true. The result of this test
* is never changed throughout the life of this {@link DiffBuilder}.
* @throws NullPointerException
* if {@code lhs} or {@code rhs} is {@code null}
* @param left {@code this} object
* @param right the object to diff against
* @param style the style to use when outputting the objects, {@code null} uses the default
* @param testObjectsEquals If true, this will test if lhs and rhs are the same or equal. All of the append(fieldName, lhs, rhs) methods will abort without
* creating a field {@link Diff} if the trivially equal test is enabled and returns true. The result of this test is never changed
* throughout the life of this {@link DiffBuilder}.
* @throws NullPointerException if {@code lhs} or {@code rhs} is {@code null}
* @since 3.4
* @deprecated Use {@link Builder}.
*/
public DiffBuilder(final T lhs, final T rhs, final ToStringStyle style, final boolean testObjectsEquals) {
this.left = Objects.requireNonNull(lhs, "lhs");
this.right = Objects.requireNonNull(rhs, "rhs");
@Deprecated
public DiffBuilder(final T left, final T right, final ToStringStyle style, final boolean testObjectsEquals) {
this(left, right, style, testObjectsEquals, TO_STRING_FORMAT);
}
private DiffBuilder(final T left, final T right, final ToStringStyle style, final boolean testObjectsEquals, final String toStringFormat) {
this.left = Objects.requireNonNull(left, "left");
this.right = Objects.requireNonNull(right, "right");
this.diffs = new ArrayList<>();
this.toStringFormat = DiffBuilder.TO_STRING_FORMAT;
this.toStringFormat = toStringFormat;
this.style = style != null ? style : ToStringStyle.DEFAULT_STYLE;
// Don't compare any fields if objects equal
this.equals = testObjectsEquals && Objects.equals(lhs, rhs);
this.equals = testObjectsEquals && Objects.equals(left, right);
}
private <F> DiffBuilder<T> add(final String fieldName, final Supplier<F> left, final Supplier<F> right, final Class<F> type) {
@ -175,15 +260,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code boolean}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code boolean}
* @param rhs
* the right-hand side {@code boolean}
* @param fieldName the field name
* @param lhs the left-hand side {@code boolean}
* @param rhs the right-hand side {@code boolean}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final boolean lhs, final boolean rhs) {
return equals || lhs == rhs ? this : add(fieldName, () -> Boolean.valueOf(lhs), () -> Boolean.valueOf(rhs), Boolean.class);
@ -192,15 +273,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code boolean[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code boolean[]}
* @param rhs
* the right-hand side {@code boolean[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code boolean[]}
* @param rhs the right-hand side {@code boolean[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final boolean[] lhs, final boolean[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Boolean[].class);
@ -209,15 +286,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code byte}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code byte}
* @param rhs
* the right-hand side {@code byte}
* @param fieldName the field name
* @param lhs the left-hand side {@code byte}
* @param rhs the right-hand side {@code byte}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final byte lhs, final byte rhs) {
return equals || lhs == rhs ? this : add(fieldName, () -> Byte.valueOf(lhs), () -> Byte.valueOf(rhs), Byte.class);
@ -226,15 +299,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code byte[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code byte[]}
* @param rhs
* the right-hand side {@code byte[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code byte[]}
* @param rhs the right-hand side {@code byte[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final byte[] lhs, final byte[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Byte[].class);
@ -243,15 +312,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code char}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code char}
* @param rhs
* the right-hand side {@code char}
* @param fieldName the field name
* @param lhs the left-hand side {@code char}
* @param rhs the right-hand side {@code char}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final char lhs, final char rhs) {
return equals || lhs == rhs ? this : add(fieldName, () -> Character.valueOf(lhs), () -> Character.valueOf(rhs), Character.class);
@ -260,15 +325,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code char[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code char[]}
* @param rhs
* the right-hand side {@code char[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code char[]}
* @param rhs the right-hand side {@code char[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final char[] lhs, final char[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Character[].class);
@ -278,9 +339,7 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
* Append diffs from another {@link DiffResult}.
*
* <p>
* Useful this method to compare properties which are
* themselves Diffable and would like to know which specific part of
* it is different.
* Useful this method to compare properties which are themselves Diffable and would like to know which specific part of it is different.
* </p>
*
* <pre>
@ -299,10 +358,8 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
* }
* </pre>
*
* @param fieldName
* the field name
* @param diffResult
* the {@link DiffResult} to append
* @param fieldName the field name
* @param diffResult the {@link DiffResult} to append
* @return this
* @throws NullPointerException if field name is {@code null} or diffResult is {@code null}
* @since 3.5
@ -319,15 +376,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code double}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code double}
* @param rhs
* the right-hand side {@code double}
* @param fieldName the field name
* @param lhs the left-hand side {@code double}
* @param rhs the right-hand side {@code double}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final double lhs, final double rhs) {
return equals || Double.doubleToLongBits(lhs) == Double.doubleToLongBits(rhs) ? this
@ -337,15 +390,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code double[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code double[]}
* @param rhs
* the right-hand side {@code double[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code double[]}
* @param rhs the right-hand side {@code double[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final double[] lhs, final double[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Double[].class);
@ -354,15 +403,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code float}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code float}
* @param rhs
* the right-hand side {@code float}
* @param fieldName the field name
* @param lhs the left-hand side {@code float}
* @param rhs the right-hand side {@code float}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final float lhs, final float rhs) {
return equals || Float.floatToIntBits(lhs) == Float.floatToIntBits(rhs) ? this
@ -372,15 +417,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code float[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code float[]}
* @param rhs
* the right-hand side {@code float[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code float[]}
* @param rhs the right-hand side {@code float[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final float[] lhs, final float[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Float[].class);
@ -389,15 +430,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code int}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code int}
* @param rhs
* the right-hand side {@code int}
* @param fieldName the field name
* @param lhs the left-hand side {@code int}
* @param rhs the right-hand side {@code int}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final int lhs, final int rhs) {
return equals || lhs == rhs ? this : add(fieldName, () -> Integer.valueOf(lhs), () -> Integer.valueOf(rhs), Integer.class);
@ -406,15 +443,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code int[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code int[]}
* @param rhs
* the right-hand side {@code int[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code int[]}
* @param rhs the right-hand side {@code int[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final int[] lhs, final int[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Integer[].class);
@ -423,15 +456,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code long}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code long}
* @param rhs
* the right-hand side {@code long}
* @param fieldName the field name
* @param lhs the left-hand side {@code long}
* @param rhs the right-hand side {@code long}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final long lhs, final long rhs) {
return equals || lhs == rhs ? this : add(fieldName, () -> Long.valueOf(lhs), () -> Long.valueOf(rhs), Long.class);
@ -440,15 +469,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code long[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code long[]}
* @param rhs
* the right-hand side {@code long[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code long[]}
* @param rhs the right-hand side {@code long[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final long[] lhs, final long[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Long[].class);
@ -457,69 +482,57 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@link Objects}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@link Object}
* @param rhs
* the right-hand side {@link Object}
* @param fieldName the field name
* @param lhs the left-hand side {@link Object}
* @param rhs the right-hand side {@link Object}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final Object lhs, final Object rhs) {
if (equals || lhs == rhs) {
return this;
}
// rhs cannot be null, as lhs != rhs
final Object objectToTest = lhs != null ? lhs : rhs;
if (ObjectUtils.isArray(objectToTest)) {
if (objectToTest instanceof boolean[]) {
final Object test = lhs != null ? lhs : rhs;
if (ObjectUtils.isArray(test)) {
if (test instanceof boolean[]) {
return append(fieldName, (boolean[]) lhs, (boolean[]) rhs);
}
if (objectToTest instanceof byte[]) {
if (test instanceof byte[]) {
return append(fieldName, (byte[]) lhs, (byte[]) rhs);
}
if (objectToTest instanceof char[]) {
if (test instanceof char[]) {
return append(fieldName, (char[]) lhs, (char[]) rhs);
}
if (objectToTest instanceof double[]) {
if (test instanceof double[]) {
return append(fieldName, (double[]) lhs, (double[]) rhs);
}
if (objectToTest instanceof float[]) {
if (test instanceof float[]) {
return append(fieldName, (float[]) lhs, (float[]) rhs);
}
if (objectToTest instanceof int[]) {
if (test instanceof int[]) {
return append(fieldName, (int[]) lhs, (int[]) rhs);
}
if (objectToTest instanceof long[]) {
if (test instanceof long[]) {
return append(fieldName, (long[]) lhs, (long[]) rhs);
}
if (objectToTest instanceof short[]) {
if (test instanceof short[]) {
return append(fieldName, (short[]) lhs, (short[]) rhs);
}
return append(fieldName, (Object[]) lhs, (Object[]) rhs);
}
// Not array type
if (Objects.equals(lhs, rhs)) {
return this;
}
add(fieldName, () -> lhs, () -> rhs, Object.class);
return this;
return Objects.equals(lhs, rhs) ? this : add(fieldName, () -> lhs, () -> rhs, Object.class);
}
/**
* Test if two {@code Object[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code Object[]}
* @param rhs
* the right-hand side {@code Object[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code Object[]}
* @param rhs the right-hand side {@code Object[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final Object[] lhs, final Object[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> lhs, () -> rhs, Object[].class);
@ -528,15 +541,11 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code short}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code short}
* @param rhs
* the right-hand side {@code short}
* @param fieldName the field name
* @param lhs the left-hand side {@code short}
* @param rhs the right-hand side {@code short}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final short lhs, final short rhs) {
return equals || lhs == rhs ? this : add(fieldName, () -> Short.valueOf(lhs), () -> Short.valueOf(rhs), Short.class);
@ -545,26 +554,20 @@ public class DiffBuilder<T> implements Builder<DiffResult<T>> {
/**
* Test if two {@code short[]}s are equal.
*
* @param fieldName
* the field name
* @param lhs
* the left-hand side {@code short[]}
* @param rhs
* the right-hand side {@code short[]}
* @param fieldName the field name
* @param lhs the left-hand side {@code short[]}
* @param rhs the right-hand side {@code short[]}
* @return this
* @throws NullPointerException
* if field name is {@code null}
* @throws NullPointerException if field name is {@code null}
*/
public DiffBuilder<T> append(final String fieldName, final short[] lhs, final short[] rhs) {
return equals || Arrays.equals(lhs, rhs) ? this : add(fieldName, () -> ArrayUtils.toObject(lhs), () -> ArrayUtils.toObject(rhs), Short[].class);
}
/**
* Builds a {@link DiffResult} based on the differences appended to this
* builder.
* Builds a {@link DiffResult} based on the differences appended to this builder.
*
* @return a {@link DiffResult} containing the differences between the two
* objects.
* @return a {@link DiffResult} containing the differences between the two objects.
*/
@Override
public DiffResult<T> build() {

View File

@ -105,7 +105,7 @@ public class ReflectionDiffBuilder<T> implements Builder<DiffResult<T>> {
public ReflectionDiffBuilder(final T lhs, final T rhs, final ToStringStyle style) {
this.left = lhs;
this.right = rhs;
this.diffBuilder = new DiffBuilder<>(lhs, rhs, style);
this.diffBuilder = DiffBuilder.<T>builder().setLeft(lhs).setRight(rhs).setStyle(style).build();
}
private boolean accept(final Field field) {

View File

@ -146,13 +146,38 @@ public class DiffBuilderTest extends AbstractLangTest {
}
@Test
public void testByteArrayEqualAsObject() {
final DiffResult<String> list = new DiffBuilder<>("String1", "String2", SHORT_STYLE).append("foo", new boolean[] { false }, new boolean[] { false })
.append("foo", new byte[] { 0x01 }, new byte[] { 0x01 }).append("foo", new char[] { 'a' }, new char[] { 'a' })
.append("foo", new double[] { 1.0 }, new double[] { 1.0 }).append("foo", new float[] { 1.0F }, new float[] { 1.0F })
.append("foo", new int[] { 1 }, new int[] { 1 }).append("foo", new long[] { 1L }, new long[] { 1L })
.append("foo", new short[] { 1 }, new short[] { 1 }).append("foo", new Object[] { 1, "two" }, new Object[] { 1, "two" }).build();
public void testByteArrayEqualAsObject1() {
// @formatter:off
final DiffResult<String> list = DiffBuilder.<String>builder().setLeft("String1").setRight("String2").setStyle(SHORT_STYLE).build()
.append("foo", new boolean[] { false }, new boolean[] { false })
.append("foo", new byte[] { 0x01 }, new byte[] { 0x01 })
.append("foo", new char[] { 'a' }, new char[] { 'a' })
.append("foo", new double[] { 1.0 }, new double[] { 1.0 })
.append("foo", new float[] { 1.0F }, new float[] { 1.0F })
.append("foo", new int[] { 1 }, new int[] { 1 })
.append("foo", new long[] { 1L }, new long[] { 1L })
.append("foo", new short[] { 1 }, new short[] { 1 })
.append("foo", new Object[] { 1, "two" }, new Object[] { 1, "two" })
.build();
// @formatter:off
assertEquals(0, list.getNumberOfDiffs());
}
@Test
public void testByteArrayEqualAsObjectDeprecated() {
// @formatter:off
final DiffResult<String> list = new DiffBuilder<>("String1", "String2", SHORT_STYLE)
.append("foo", new boolean[] { false }, new boolean[] { false })
.append("foo", new byte[] { 0x01 }, new byte[] { 0x01 })
.append("foo", new char[] { 'a' }, new char[] { 'a' })
.append("foo", new double[] { 1.0 }, new double[] { 1.0 })
.append("foo", new float[] { 1.0F }, new float[] { 1.0F })
.append("foo", new int[] { 1 }, new int[] { 1 })
.append("foo", new long[] { 1L }, new long[] { 1L })
.append("foo", new short[] { 1 }, new short[] { 1 })
.append("foo", new Object[] { 1, "two" }, new Object[] { 1, "two" })
.build();
// @formatter:off
assertEquals(0, list.getNumberOfDiffs());
}

View File

@ -34,6 +34,7 @@ public class DiffResultTest extends AbstractLangTest {
private static final class EmptyClass {
// empty
}
private static final class SimpleClass implements Diffable<SimpleClass> {
static String getFieldName() {
return "booleanField";
@ -47,11 +48,10 @@ public class DiffResultTest extends AbstractLangTest {
@Override
public DiffResult<SimpleClass> diff(final SimpleClass obj) {
return new DiffBuilder<>(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
.append(getFieldName(), booleanField, obj.booleanField)
.build();
return new DiffBuilder<>(this, obj, ToStringStyle.SHORT_PREFIX_STYLE).append(getFieldName(), booleanField, obj.booleanField).build();
}
}
private static final ToStringStyle SHORT_STYLE = ToStringStyle.SHORT_PREFIX_STYLE;
private static final SimpleClass SIMPLE_FALSE = new SimpleClass(false);
@ -101,63 +101,80 @@ public class DiffResultTest extends AbstractLangTest {
final List<Diff<?>> diffs = lhs.diff(rhs).getDiffs();
final DiffResult<SimpleClass> list = new DiffResult<>(lhs, rhs, diffs, SHORT_STYLE, DiffBuilder.TO_STRING_FORMAT);
assertEquals(diffs, list.getDiffs());
assertEquals(1, list.getNumberOfDiffs());
assertThrows(UnsupportedOperationException.class, () -> list.getDiffs().remove(0));
final DiffResult<SimpleClass> result = new DiffResult<>(lhs, rhs, diffs, SHORT_STYLE, DiffBuilder.TO_STRING_FORMAT);
assertEquals(diffs, result.getDiffs());
assertEquals(1, result.getNumberOfDiffs());
assertThrows(UnsupportedOperationException.class, () -> result.getDiffs().remove(0));
}
@Test
public void testNoDifferencesString() {
final DiffResult<SimpleClass> diffResult = new DiffBuilder<>(SIMPLE_TRUE, SIMPLE_TRUE,
SHORT_STYLE).build();
final DiffResult<SimpleClass> diffResult = DiffBuilder.<SimpleClass>builder().setLeft(SIMPLE_TRUE).setRight(SIMPLE_TRUE).setStyle(SHORT_STYLE).build()
.build();
assertEquals(DiffResult.OBJECTS_SAME_STRING, diffResult.toString());
}
@Test
public void testNullLhs() {
assertThrows(NullPointerException.class,
() -> new DiffResult<>(null, SIMPLE_FALSE, SIMPLE_TRUE.diff(SIMPLE_FALSE).getDiffs(), SHORT_STYLE, DiffBuilder.TO_STRING_FORMAT));
() -> new DiffResult<>(null, SIMPLE_FALSE, SIMPLE_TRUE.diff(SIMPLE_FALSE).getDiffs(), SHORT_STYLE, DiffBuilder.TO_STRING_FORMAT));
}
@Test
public void testNullList() {
assertThrows(NullPointerException.class,
() -> new DiffResult<>(SIMPLE_TRUE, SIMPLE_FALSE, null, SHORT_STYLE, null));
assertThrows(NullPointerException.class, () -> new DiffResult<>(SIMPLE_TRUE, SIMPLE_FALSE, null, SHORT_STYLE, null));
}
@Test
public void testNullRhs() {
assertThrows(NullPointerException.class,
() -> new DiffResult<>(SIMPLE_TRUE, null, SIMPLE_TRUE.diff(SIMPLE_FALSE).getDiffs(), SHORT_STYLE, DiffBuilder.TO_STRING_FORMAT));
() -> new DiffResult<>(SIMPLE_TRUE, null, SIMPLE_TRUE.diff(SIMPLE_FALSE).getDiffs(), SHORT_STYLE, DiffBuilder.TO_STRING_FORMAT));
}
@Test
public void testToStringOutput() {
final DiffResult<EmptyClass> list = new DiffBuilder<>(new EmptyClass(), new EmptyClass(),
ToStringStyle.SHORT_PREFIX_STYLE).append("test", false, true)
// @formatter:off
final DiffResult<EmptyClass> result = DiffBuilder.<EmptyClass>builder()
.setLeft(new EmptyClass())
.setRight(new EmptyClass())
.setStyle(ToStringStyle.SHORT_PREFIX_STYLE)
.build()
.append("test", false, true)
.build();
assertEquals(
"DiffResultTest.EmptyClass[test=false] differs from DiffResultTest.EmptyClass[test=true]",
list.toString());
// @formatter:on
assertEquals("DiffResultTest.EmptyClass[test=false] differs from DiffResultTest.EmptyClass[test=true]", result.toString());
}
@Test
public void testToStringFormat() {
// @formatter:off
final DiffResult<EmptyClass> result = DiffBuilder.<EmptyClass>builder()
.setLeft(new EmptyClass())
.setRight(new EmptyClass())
.setStyle(ToStringStyle.SHORT_PREFIX_STYLE)
.setToStringFormat("%s <> %s")
.build()
.append("test", false, true)
.build();
// @formatter:on
assertEquals("DiffResultTest.EmptyClass[test=false] <> DiffResultTest.EmptyClass[test=true]", result.toString());
}
@Test
public void testToStringSpecifyStyleOutput() {
final DiffResult<SimpleClass> list = SIMPLE_FALSE.diff(SIMPLE_TRUE);
assertEquals(list.getToStringStyle(), SHORT_STYLE);
final DiffResult<SimpleClass> result = SIMPLE_FALSE.diff(SIMPLE_TRUE);
assertEquals(result.getToStringStyle(), SHORT_STYLE);
final String lhsString = new ToStringBuilder(SIMPLE_FALSE,
ToStringStyle.MULTI_LINE_STYLE).append(
SimpleClass.getFieldName(), SIMPLE_FALSE.booleanField).build();
// @formatter:off
final String lhsString = new ToStringBuilder(SIMPLE_FALSE, ToStringStyle.MULTI_LINE_STYLE)
.append(SimpleClass.getFieldName(), SIMPLE_FALSE.booleanField)
.build();
final String rhsString = new ToStringBuilder(SIMPLE_TRUE,
ToStringStyle.MULTI_LINE_STYLE).append(
SimpleClass.getFieldName(), SIMPLE_TRUE.booleanField).build();
final String rhsString = new ToStringBuilder(SIMPLE_TRUE, ToStringStyle.MULTI_LINE_STYLE)
.append(SimpleClass.getFieldName(), SIMPLE_TRUE.booleanField)
.build();
// @formatter:on
final String expectedOutput = String.format("%s differs from %s", lhsString,
rhsString);
assertEquals(expectedOutput,
list.toString(ToStringStyle.MULTI_LINE_STYLE));
assertEquals(String.format("%s differs from %s", lhsString, rhsString), result.toString(ToStringStyle.MULTI_LINE_STYLE));
}
}