Java tutorial
/* * Copyright (c) 2016 Google, Inc. * * 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. */ package com.google.common.truth; import static com.google.common.base.Functions.identity; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.truth.DoubleSubject.checkTolerance; import static com.google.common.truth.Fact.fact; import static com.google.common.truth.Fact.simpleFact; import static com.google.common.truth.Facts.facts; import static com.google.common.truth.Platform.getStackTraceAsString; import static java.util.Arrays.asList; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import java.util.Arrays; import java.util.List; import org.checkerframework.checker.nullness.compatqual.NullableDecl; /** * Determines whether an instance of type {@code A} corresponds in some way to an instance of type * {@code E} for the purposes of a test assertion. For example, the implementation returned by the * {@link #tolerance(double)} factory method implements approximate equality between numeric values, * with values being said to correspond if the difference between them is does not exceed some fixed * tolerance. The instances of type {@code A} are typically actual values from a collection returned * by the code under test; the instances of type {@code E} are typically expected values with which * the actual values are compared by the test. * * <p>The correspondence is required to be consistent: for any given values {@code actual} and * {@code expected}, multiple invocations of {@code compare(actual, expected)} must consistently * return {@code true} or consistently return {@code false} (provided that neither value is * modified). Although {@code A} and {@code E} will often be the same types, they are <i>not</i> * required to be the same, and even if they are it is <i>not</i> required that the correspondence * should have any of the other properties of an equivalence relation (reflexivity, symmetry, or * transitivity). * * <p>Optionally, instances of this class can also provide functionality to format the difference * between values which do not correspond. This results in failure messages including formatted * diffs between expected and actual value, where possible. * * <p>The recommended approach for creating an instance of this class is to use one of the static * factory methods. The most general of these is {@link #from}; the other methods are more * convenient in specific cases. The optional diff-formatting functionality can be added using * {@link #formattingDiffsUsing}. (Alternatively, you can subclass this class yourself, but that is * generally not recommended.) * * <p>Instances of this are typically used via {@link IterableSubject#comparingElementsUsing}, * {@link MapSubject#comparingValuesUsing}, or {@link MultimapSubject#comparingValuesUsing}. * * @author Pete Gillin */ public abstract class Correspondence<A, E> { /** * Constructs a {@link Correspondence} that compares actual and expected elements using the given * binary predicate. * * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}. * * <p>Note that, if the data you are asserting about contains nulls, your predicate may be invoked * with null arguments. If this causes it to throw a {@link NullPointerException}, then your test * will fail. (See {@link Correspondence#compare} for more detail on how exceptions are handled.) * In particular, if your predicate is an instance method reference on the actual value (as in the * {@code String::contains} example below), your test will fail if it sees null actual values. * * <p>Example using an instance method reference: * * <pre>{@code * static final Correspondence<String, String> CONTAINS_SUBSTRING = * Correspondence.from(String::contains, "contains"); * }</pre> * * <p>Example using a static method reference: * * <pre>{@code * class MyRecordTestHelper { * static final Correspondence<MyRecord, MyRecord> EQUIVALENCE = * Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to"); * static boolean recordsEquivalent(@Nullable MyRecord actual, @Nullable MyRecord expected) { * // code to check whether records should be considered equivalent for testing purposes * } * } * }</pre> * * <p>Example using a lambda: * * <pre>{@code * static final Correspondence<Object, Class<?>> INSTANCE_OF = * Correspondence.from((obj, clazz) -> clazz.isInstance(obj), "is an instance of"); * }</pre> * * @param predicate a {@link BinaryPredicate} taking an actual and expected value (in that order) * and returning whether the actual value corresponds to the expected value in some way * @param description should fill the gap in a failure message of the form {@code "not true that * <some actual element> is an element that <description> <some expected element>"}, e.g. * {@code "contains"}, {@code "is an instance of"}, or {@code "is equivalent to"} */ public static <A, E> Correspondence<A, E> from(BinaryPredicate<A, E> predicate, String description) { return new FromBinaryPredicate<>(predicate, description); } /** * A functional interface for a binary predicate, to be used to test whether a pair of objects of * types {@code A} and {@code E} satisfy some condition. * * <p>This interface will normally be implemented using a lambda or a method reference, and the * resulting object will normally be passed directly to {@link Correspondence#from}. As a result, * you should almost never see {@code BinaryPredicate} used as the type of a field or variable, or * a return type. */ public interface BinaryPredicate<A, E> { /** * Returns whether or not the actual and expected values satisfy the condition defined by this * predicate. */ boolean apply(@NullableDecl A actual, @NullableDecl E expected); } private static final class FromBinaryPredicate<A, E> extends Correspondence<A, E> { private final BinaryPredicate<A, E> predicate; private final String description; private FromBinaryPredicate(BinaryPredicate<A, E> correspondencePredicate, String description) { this.predicate = checkNotNull(correspondencePredicate); this.description = checkNotNull(description); } @Override public boolean compare(@NullableDecl A actual, @NullableDecl E expected) { return predicate.apply(actual, expected); } @Override public String toString() { return description; } } /** * Constructs a {@link Correspondence} that compares elements by transforming the actual elements * using the given function and testing for equality with the expected elements. If the * transformed actual element (i.e. the output of the given function) is null, it will correspond * to a null expected element. * * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}. * * <p>Note that, if you the data you are asserting about contains null actual values, your * function may be invoked with a null argument. If this causes it to throw a {@link * NullPointerException}, then your test will fail. (See {@link Correspondence#compare} for more * detail on how exceptions are handled.) In particular, this applies if your function is an * instance method reference on the actual value (as in the example below). If you want a null * actual element to correspond to a null expected element, you must ensure that your function * transforms a null input to a null output. * * <p>Example: * * <pre>{@code * static final Correspondence<MyRecord, Integer> HAS_ID = * Correspondence.transforming(MyRecord::getId, "has an ID of"); * }</pre> * * This can be used as follows: * * <pre>{@code * assertThat(myRecords).comparingElementsUsing(HAS_ID).containsExactly(123, 456, 789); * }</pre> * * @param actualTransform a {@link Function} taking an actual value and returning a new value * which will be compared with an expected value to determine whether they correspond * @param description should fill the gap in a failure message of the form {@code "not true that * <some actual element> is an element that <description> <some expected element>"}, e.g. * {@code "has an ID of"} */ public static <A, E> Correspondence<A, E> transforming(Function<A, ? extends E> actualTransform, String description) { return new Transforming<>(actualTransform, identity(), description); } /** * Constructs a {@link Correspondence} that compares elements by transforming the actual and the * expected elements using the given functions and testing the transformed values for equality. If * an actual element is transformed to null, it will correspond to an expected element that is * also transformed to null. * * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}. * * <p>Note that, if you the data you are asserting about contains null actual or expected values, * the appropriate function may be invoked with a null argument. If this causes it to throw a * {@link NullPointerException}, then your test will fail. (See {@link Correspondence#compare} for * more detail on how exceptions are handled.) In particular, this applies if your function is an * instance method reference on the actual or expected value (as in the example below). If you * want a null actual element to correspond to a null expected element, you must ensure that your * functions both transform a null input to a null output. * * <p>If you want to apply the same function to both the actual and expected elements, just * provide the same argument twice. * * <p>Example: * * <pre>{@code * static final Correspondence<MyRequest, MyResponse> SAME_IDS = * Correspondence.transforming(MyRequest::getId, MyResponse::getId, "has the same ID as"); * }</pre> * * This can be used as follows: * * <pre>{@code * assertThat(myResponses).comparingElementsUsing(SAME_IDS).containsExactlyElementsIn(myRequests); * }</pre> * * @param actualTransform a {@link Function} taking an actual value and returning a new value * which will be compared with a transformed expected value to determine whether they * correspond * @param expectedTransform a {@link Function} taking an expected value and returning a new value * which will be compared with a transformed actual value * @param description should fill the gap in a failure message of the form {@code "not true that * <some actual element> is an element that <description> <some expected element>"}, e.g. * {@code "has the same ID as"} */ public static <A, E> Correspondence<A, E> transforming(Function<A, ?> actualTransform, Function<E, ?> expectedTransform, String description) { return new Transforming<>(actualTransform, expectedTransform, description); } private static final class Transforming<A, E> extends Correspondence<A, E> { private final Function<? super A, ?> actualTransform; private final Function<? super E, ?> expectedTransform; private final String description; private Transforming(Function<? super A, ?> actualTransform, Function<? super E, ?> expectedTransform, String description) { this.actualTransform = actualTransform; this.expectedTransform = expectedTransform; this.description = description; } @Override public boolean compare(@NullableDecl A actual, @NullableDecl E expected) { return Objects.equal(actualTransform.apply(actual), expectedTransform.apply(expected)); } @Override public String toString() { return description; } } /** * Returns a {@link Correspondence} between {@link Number} instances that considers instances to * correspond (i.e. {@link Correspondence#compare(Object, Object)} returns {@code true}) if the * double values of each instance (i.e. the result of calling {@link Number#doubleValue()} on * them) are finite values within {@code tolerance} of each other. * * <ul> * <li>It does not consider instances to correspond if either value is infinite or NaN. * <li>The conversion to double may result in a loss of precision for some numeric types. * <li>The {@link Correspondence#compare(Object, Object)} method throws a {@link * NullPointerException} if either {@link Number} instance is null. * </ul> * * @param tolerance an inclusive upper bound on the difference between the double values of the * two {@link Number} instances, which must be a non-negative finite value, i.e. not {@link * Double#NaN}, {@link Double#POSITIVE_INFINITY}, or negative, including {@code -0.0} */ public static Correspondence<Number, Number> tolerance(double tolerance) { return new TolerantNumericEquality(tolerance); } private static final class TolerantNumericEquality extends Correspondence<Number, Number> { private final double tolerance; private TolerantNumericEquality(double tolerance) { checkTolerance(tolerance); this.tolerance = tolerance; } @Override public boolean compare(Number actual, Number expected) { double actualDouble = checkNotNull(actual).doubleValue(); double expectedDouble = checkNotNull(expected).doubleValue(); return MathUtil.equalWithinTolerance(actualDouble, expectedDouble, tolerance); } @Override public String toString() { return "is a finite number within " + tolerance + " of"; } } /** * Constructor. Creating subclasses (anonymous or otherwise) of this class is <i>not * recommended</i>, but is possible via this constructor. The recommended approach is to use the * factory methods instead (see {@linkplain Correspondence class-level documentation}). * * @deprecated Construct an instance with the static factory methods instead. The most mechanical * migration is usually to {@link #from}. */ @Deprecated Correspondence() { } /** * Returns a new correspondence which is like this one, except that the given formatter may be * used to format the difference between a pair of elements that do not correspond. * * <p>Note that, if you the data you are asserting about contains null actual or expected values, * the formatter may be invoked with a null argument. If this causes it to throw a {@link * NullPointerException}, that will be taken to indicate that the values cannot be diffed. (See * {@link Correspondence#formatDiff} for more detail on how exceptions are handled.) If you think * null values are likely, it is slightly cleaner to have the formatter return null in that case * instead of throwing. * * <p>Example: * * <pre>{@code * class MyRecordTestHelper { * static final Correspondence<MyRecord, MyRecord> EQUIVALENCE = * Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to") * .formattingDiffsUsing(MyRecordTestHelper::formatRecordDiff); * static boolean recordsEquivalent(@Nullable MyRecord actual, @Nullable MyRecord expected) { * // code to check whether records should be considered equivalent for testing purposes * } * static String formatRecordDiff(@Nullable MyRecord actual, @Nullable MyRecord expected) { * // code to format the diff between the records * } * } * }</pre> */ public Correspondence<A, E> formattingDiffsUsing(DiffFormatter<? super A, ? super E> formatter) { return new FormattingDiffs<>(this, formatter); } /** * A functional interface to be used format the diff between a pair of objects of types {@code A} * and {@code E}. * * <p>This interface will normally be implemented using a lambda or a method reference, and the * resulting object will normally be passed directly to {@link * Correspondence#formattingDiffsUsing}. As a result, you should almost never see {@code * DiffFormatter} used as the type of a field or variable, or a return type. */ public interface DiffFormatter<A, E> { /** * Returns a {@link String} describing the difference between the {@code actual} and {@code * expected} values, if possible, or {@code null} if not. */ @NullableDecl String formatDiff(@NullableDecl A actual, @NullableDecl E expected); } private static class FormattingDiffs<A, E> extends Correspondence<A, E> { private final Correspondence<A, E> delegate; private final DiffFormatter<? super A, ? super E> formatter; FormattingDiffs(Correspondence<A, E> delegate, DiffFormatter<? super A, ? super E> formatter) { this.delegate = checkNotNull(delegate); this.formatter = checkNotNull(formatter); } @Override public boolean compare(@NullableDecl A actual, @NullableDecl E expected) { return delegate.compare(actual, expected); } @Override @NullableDecl public String formatDiff(@NullableDecl A actual, @NullableDecl E expected) { return formatter.formatDiff(actual, expected); } @Override public String toString() { return delegate.toString(); } } /** * Returns whether or not the {@code actual} value is said to correspond to the {@code expected} * value for the purposes of this test. * * <h3>Exception handling</h3> * * <p>Throwing a {@link RuntimeException} from this method indicates that this {@link * Correspondence} cannot compare the given values. Any assertion which encounters such an * exception during the course of evaluating its condition must not pass. However, an assertion is * not required to invoke this method for every pair of values in its input just in order to check * for exceptions, if it is able to evaluate its condition without doing so. * * <h4>Conventions for handling exceptions</h4> * * <p>(N.B. This section is only really of interest when implementing assertion methods that call * {@link Correspondence#compare}, not to users making such assertions in their tests.) * * <p>The only requirement on an assertion is that, if it encounters an exception from this * method, it must not pass. The simplest implementation choice is simply to allow the exception * to propagate. However, it is normally more helpful to catch the exception and instead fail with * a message which includes more information about the assertion in progress and the nature of the * failure. * * <p>By convention, an assertion may catch and store the exception and continue evaluating the * condition as if the method had returned false instead of throwing. If the assertion's condition * does not hold with this alternative behaviour, it may choose to fail with a message that gives * details about how the condition does not hold, additionally mentioning that assertions were * encountered and giving details about one of the stored exceptions. (See the first example * below.) If the assertion's condition does hold with this alternative behaviour, the requirement * that the assertion must not pass still applies, so it should fail with a message giving details * about one of the stored exceptions. (See the second and third examples below.) * * <p>This behaviour is only a convention and should only be implemented when it makes sense to do * so. In particular, in an assertion that has multiple stages, it may be better to only continue * evaluation to the end of the current stage, and fail citing a stored exception at the end of * the stage, rather than accumulating exceptions through the multiple stages. * * <h4>Examples of exception handling</h4> * * <p>Suppose that we have the correspondence * * <pre>{@code * static final Correspondence<String, String> CASE_INSENSITIVE_EQUALITY = * Correspondence.from(String::equalsIgnoreCase, "equals ignoring case"} * }</pre> * * whose {@code compare} method throws {@link NullPointerException} if the actual value is null. * The assertion * * <pre>{@code * assertThat(asList(null, "xyz", "abc", "def")) * .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY) * .containsExactly("ABC", "DEF", "GHI", "JKL"); * }</pre> * * may fail saying that the actual iterable contains unexpected values {@code null} and {@code * xyz} and is missing values corresponding to {@code GHI} and {@code JKL}, which is what it would * do if the {@code compare} method returned false instead of throwing, and additionally mention * the exception. (This is more helpful than allowing the {@link NullPointerException} to * propagate to the caller, or than failing with only a description of the exception.) * * <p>However, the assertions * * <pre>{@code * assertThat(asList(null, "xyz", "abc", "def")) * .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY) * .doesNotContain("MNO"); * }</pre> * * and * * <pre>{@code * assertThat(asList(null, "xyz", "abc", "def")) * .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY) * .doesNotContain(null); * }</pre> * * must both fail citing the exception, even though they would pass if the {@code compare} method * returned false. (Note that, in the latter case at least, it is likely that the test author's * intention was <i>not</i> for the test to pass with these values.) */ public abstract boolean compare(@NullableDecl A actual, @NullableDecl E expected); private static class StoredException { private static final Joiner ARGUMENT_JOINER = Joiner.on(", ").useForNull("null"); private final Exception exception; private final String methodName; private final List<Object> methodArguments; StoredException(Exception exception, String methodName, List<Object> methodArguments) { this.exception = checkNotNull(exception); this.methodName = checkNotNull(methodName); this.methodArguments = checkNotNull(methodArguments); } /** * Returns a String describing the exception stored. This includes a stack trace (except under * j2cl, where this is not available). It also has a separator at the end, so that when this * appears at the end of an {@code AssertionError} message, the stack trace of the stored * exception is distinguishable from the stack trace of the {@code AssertionError}. */ private String describe() { return Strings.lenientFormat("%s(%s) threw %s\n---", methodName, ARGUMENT_JOINER.join(methodArguments), getStackTraceAsString(exception)); } } /** * Helper object to store exceptions encountered while executing a {@link Correspondence} method. */ static final class ExceptionStore { private final String argumentLabel; private StoredException firstCompareException = null; private StoredException firstPairingException = null; private StoredException firstFormatDiffException = null; static ExceptionStore forIterable() { return new ExceptionStore("elements"); } static ExceptionStore forMapValues() { return new ExceptionStore("values"); } private ExceptionStore(String argumentLabel) { this.argumentLabel = argumentLabel; } /** * Adds an exception that was thrown during a {@code compare} call. * * @param callingClass The class from which the {@code compare} method was called. When * reporting failures, stack traces will be truncated above elements in this class. * @param exception The exception encountered * @param actual The {@code actual} argument to the {@code compare} call during which the * exception was encountered * @param expected The {@code expected} argument to the {@code compare} call during which the * exception was encountered */ void addCompareException(Class<?> callingClass, Exception exception, Object actual, Object expected) { if (firstCompareException == null) { truncateStackTrace(exception, callingClass); firstCompareException = new StoredException(exception, "compare", asList(actual, expected)); } } /** * Adds an exception that was thrown during an {@code apply} call on the function used to key * actual elements. * * @param callingClass The class from which the {@code apply} method was called. When reporting * failures, stack traces will be truncated above elements in this class. * @param exception The exception encountered * @param actual The {@code actual} argument to the {@code apply} call during which the * exception was encountered */ void addActualKeyFunctionException(Class<?> callingClass, Exception exception, Object actual) { if (firstPairingException == null) { truncateStackTrace(exception, callingClass); firstPairingException = new StoredException(exception, "actualKeyFunction.apply", asList(actual)); } } /** * Adds an exception that was thrown during an {@code apply} call on the function used to key * expected elements. * * @param callingClass The class from which the {@code apply} method was called. When reporting * failures, stack traces will be truncated above elements in this class. * @param exception The exception encountered * @param expected The {@code expected} argument to the {@code apply} call during which the * exception was encountered */ void addExpectedKeyFunctionException(Class<?> callingClass, Exception exception, Object expected) { if (firstPairingException == null) { truncateStackTrace(exception, callingClass); firstPairingException = new StoredException(exception, "expectedKeyFunction.apply", asList(expected)); } } /** * Adds an exception that was thrown during a {@code formatDiff} call. * * @param callingClass The class from which the {@code formatDiff} method was called. When * reporting failures, stack traces will be truncated above elements in this class. * @param exception The exception encountered * @param actual The {@code actual} argument to the {@code formatDiff} call during which the * exception was encountered * @param expected The {@code expected} argument to the {@code formatDiff} call during which the * exception was encountered */ void addFormatDiffException(Class<?> callingClass, Exception exception, Object actual, Object expected) { if (firstFormatDiffException == null) { truncateStackTrace(exception, callingClass); firstFormatDiffException = new StoredException(exception, "formatDiff", asList(actual, expected)); } } /** Returns whether any exceptions thrown during {@code compare} calls were stored. */ boolean hasCompareException() { return firstCompareException != null; } /** * Returns facts to use in a failure message when the exceptions from {@code compare} calls are * the main cause of the failure. At least one exception thrown during a {@code compare} call * must have been stored, and no exceptions from a {@code formatDiff} call. Assertions should * use this when exceptions were thrown while comparing elements and no more meaningful failure * was discovered by assuming a false return and continuing (see the javadoc for {@link * Correspondence#compare}). C.f. {@link #describeAsAdditionalInfo}. */ Facts describeAsMainCause() { checkState(firstCompareException != null); // We won't do pairing or diff formatting unless a more meaningful failure was found, and if a // more meaningful failure was found then we shouldn't be using this method: checkState(firstPairingException == null); checkState(firstFormatDiffException == null); return facts(simpleFact("one or more exceptions were thrown while comparing " + argumentLabel), fact("first exception", firstCompareException.describe())); } /** * If any exceptions are stored, returns facts to use in a failure message when the exceptions * should be noted as additional info; if empty, returns an empty list. Assertions should use * this when exceptions were thrown while comparing elements but more meaningful failures were * discovered by assuming a false return and continuing (see the javadoc for {@link * Correspondence#compare}), or when exceptions were thrown by other methods while generating * the failure message. C.f. {@link #describeAsMainCause}. */ Facts describeAsAdditionalInfo() { ImmutableList.Builder<Fact> builder = ImmutableList.builder(); if (firstCompareException != null) { builder.add(simpleFact( "additionally, one or more exceptions were thrown while comparing " + argumentLabel)); builder.add(fact("first exception", firstCompareException.describe())); } if (firstPairingException != null) { builder.add(simpleFact("additionally, one or more exceptions were thrown while keying " + argumentLabel + " for pairing")); builder.add(fact("first exception", firstPairingException.describe())); } if (firstFormatDiffException != null) { builder.add(simpleFact("additionally, one or more exceptions were thrown while formatting diffs")); builder.add(fact("first exception", firstFormatDiffException.describe())); } return facts(builder.build()); } private static void truncateStackTrace(Exception exception, Class<?> callingClass) { StackTraceElement[] original = exception.getStackTrace(); int keep = 0; while (keep < original.length && !original[keep].getClassName().equals(callingClass.getName())) { keep++; } exception.setStackTrace(Arrays.copyOf(original, keep)); } } /** * Invokes {@link #compare}, catching any exceptions. If the comparison does not throw, returns * the result. If it does throw, adds the exception to the given {@link ExceptionStore} and * returns false. This method can help with implementing the exception-handling policy described * above, but note that assertions using it <i>must</i> fail later if an exception was stored. */ final boolean safeCompare(@NullableDecl A actual, @NullableDecl E expected, ExceptionStore exceptions) { try { return compare(actual, expected); } catch (RuntimeException e) { exceptions.addCompareException(Correspondence.class, e, actual, expected); return false; } } /** * Returns a {@link String} describing the difference between the {@code actual} and {@code * expected} values, if possible, or {@code null} if not. * * <p>The implementation on the {@link Correspondence} base class always returns {@code null}. To * enable diffing, use {@link #formattingDiffsUsing} (or override this method in a subclass, but * factory methods are recommended over subclassing). * * <p>Assertions should only invoke this with parameters for which {@link #compare} returns {@code * false}. * * <p>If this throws an exception, that implies that it is not possible to describe the diffs. An * assertion will normally only call this method if it has established that its condition does not * hold: good practice dictates that, if this method throws, the assertion should catch the * exception and continue to describe the original failure as if this method had returned null, * mentioning the failure from this method as additional information. */ @NullableDecl public String formatDiff(@NullableDecl A actual, @NullableDecl E expected) { return null; } /** * Invokes {@link #formatDiff}, catching any exceptions. If the comparison does not throw, returns * the result. If it does throw, adds the exception to the given {@link ExceptionStore} and * returns null. */ @NullableDecl final String safeFormatDiff(@NullableDecl A actual, @NullableDecl E expected, ExceptionStore exceptions) { try { return formatDiff(actual, expected); } catch (RuntimeException e) { exceptions.addFormatDiffException(Correspondence.class, e, actual, expected); return null; } } /** * Returns a description of the correspondence, suitable to fill the gap in a failure message of * the form {@code "<some actual element> is an element that ... <some expected element>"}. Note * that this is a fragment of a verb phrase which takes a singular subject. * * <p>Example 1: For a {@code Correspondence<String, Integer>} that tests whether the actual * string parses to the expected integer, this would return {@code "parses to"} to result in a * failure message of the form {@code "<some actual string> is an element that parses to <some * expected integer>"}. * * <p>Example 2: For the {@code Correspondence<Number, Number>} returns by {@link #tolerance} this * returns {@code "is a finite number within " + tolerance + " of"} to result in a failure message * of the form {@code "<some actual number> is an element that is a finite number within 0.0001 of * <some expected number>"}. */ @Override public abstract String toString(); /** * @throws UnsupportedOperationException always * @deprecated {@link Object#equals(Object)} is not supported. If you meant to compare objects * using this {@link Correspondence}, use {@link #compare}. */ @Deprecated @Override public final boolean equals(@NullableDecl Object o) { throw new UnsupportedOperationException( "Correspondence.equals(object) is not supported. If you meant to compare objects, use" + " .compare(actual, expected) instead."); } /** * @throws UnsupportedOperationException always * @deprecated {@link Object#hashCode()} is not supported. */ @Deprecated @Override public final int hashCode() { throw new UnsupportedOperationException("Correspondence.hashCode() is not supported."); } }