• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.common.truth;
17 
18 import static com.google.common.base.Functions.identity;
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.base.Preconditions.checkState;
21 import static com.google.common.truth.DoubleSubject.checkTolerance;
22 import static com.google.common.truth.Fact.fact;
23 import static com.google.common.truth.Fact.simpleFact;
24 import static com.google.common.truth.Platform.getStackTraceAsString;
25 import static java.util.Arrays.asList;
26 
27 import com.google.common.base.Function;
28 import com.google.common.base.Joiner;
29 import com.google.common.base.Objects;
30 import com.google.common.base.Strings;
31 import com.google.common.collect.ImmutableList;
32 import java.util.Arrays;
33 import java.util.List;
34 import org.checkerframework.checker.nullness.qual.Nullable;
35 
36 /**
37  * Determines whether an instance of type {@code A} corresponds in some way to an instance of type
38  * {@code E} for the purposes of a test assertion. For example, the implementation returned by the
39  * {@link #tolerance(double)} factory method implements approximate equality between numeric values,
40  * with values being said to correspond if the difference between them does not exceed the given
41  * fixed tolerance. The instances of type {@code A} are typically actual values from a collection
42  * returned by the code under test; the instances of type {@code E} are typically expected values
43  * with which the actual values are compared by the test.
44  *
45  * <p>The correspondence is required to be consistent: for any given values {@code actual} and
46  * {@code expected}, multiple invocations of {@code compare(actual, expected)} must consistently
47  * return {@code true} or consistently return {@code false} (provided that neither value is
48  * modified). Although {@code A} and {@code E} will often be the same types, they are <i>not</i>
49  * required to be the same, and even if they are it is <i>not</i> required that the correspondence
50  * should have any of the other properties of an equivalence relation (reflexivity, symmetry, or
51  * transitivity).
52  *
53  * <p>Optionally, instances of this class can also provide functionality to format the difference
54  * between values which do not correspond. This results in failure messages including formatted
55  * diffs between expected and actual value, where possible.
56  *
57  * <p>The recommended approach for creating an instance of this class is to use one of the static
58  * factory methods. The most general of these is {@link #from}; the other methods are more
59  * convenient in specific cases. The optional diff-formatting functionality can be added using
60  * {@link #formattingDiffsUsing}. (Alternatively, you can subclass this class yourself, but that is
61  * generally not recommended.)
62  *
63  * <p>Instances of this are typically used via {@link IterableSubject#comparingElementsUsing},
64  * {@link MapSubject#comparingValuesUsing}, or {@link MultimapSubject#comparingValuesUsing}.
65  *
66  * @author Pete Gillin
67  */
68 public abstract class Correspondence<A, E> {
69 
70   /**
71    * Constructs a {@link Correspondence} that compares actual and expected elements using the given
72    * binary predicate.
73    *
74    * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can
75    * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}.
76    *
77    * <p>Note that, if the data you are asserting about contains nulls, your predicate may be invoked
78    * with null arguments. If this causes it to throw a {@link NullPointerException}, then your test
79    * will fail. (See {@link Correspondence#compare} for more detail on how exceptions are handled.)
80    * In particular, if your predicate is an instance method reference on the actual value (as in the
81    * {@code String::contains} example below), your test will fail if it sees null actual values.
82    *
83    * <p>Example using an instance method reference:
84    *
85    * <pre>{@code
86    * static final Correspondence<String, String> CONTAINS_SUBSTRING =
87    *     Correspondence.from(String::contains, "contains");
88    * }</pre>
89    *
90    * <p>Example using a static method reference:
91    *
92    * <pre>{@code
93    * class MyRecordTestHelper {
94    *   static final Correspondence<MyRecord, MyRecord> EQUIVALENCE =
95    *       Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to");
96    *   static boolean recordsEquivalent(@Nullable MyRecord actual, @Nullable MyRecord expected) {
97    *     // code to check whether records should be considered equivalent for testing purposes
98    *   }
99    * }
100    * }</pre>
101    *
102    * <p>Example using a lambda:
103    *
104    * <pre>{@code
105    * static final Correspondence<Object, Class<?>> INSTANCE_OF =
106    *     Correspondence.from((obj, clazz) -> clazz.isInstance(obj), "is an instance of");
107    * }</pre>
108    *
109    * @param predicate a {@link BinaryPredicate} taking an actual and expected value (in that order)
110    *     and returning whether the actual value corresponds to the expected value in some way
111    * @param description should fill the gap in a failure message of the form {@code "not true that
112    *     <some actual element> is an element that <description> <some expected element>"}, e.g.
113    *     {@code "contains"}, {@code "is an instance of"}, or {@code "is equivalent to"}
114    */
from( BinaryPredicate<A, E> predicate, String description)115   public static <A, E> Correspondence<A, E> from(
116       BinaryPredicate<A, E> predicate, String description) {
117     return new FromBinaryPredicate<>(predicate, description);
118   }
119 
120   /**
121    * A functional interface for a binary predicate, to be used to test whether a pair of objects of
122    * types {@code A} and {@code E} satisfy some condition.
123    *
124    * <p>This interface will normally be implemented using a lambda or a method reference, and the
125    * resulting object will normally be passed directly to {@link Correspondence#from}. As a result,
126    * you should almost never see {@code BinaryPredicate} used as the type of a field or variable, or
127    * a return type.
128    */
129   public interface BinaryPredicate<A, E> {
130 
131     /**
132      * Returns whether or not the actual and expected values satisfy the condition defined by this
133      * predicate.
134      */
apply(@ullable A actual, @Nullable E expected)135     boolean apply(@Nullable A actual, @Nullable E expected);
136   }
137 
138   private static final class FromBinaryPredicate<A, E> extends Correspondence<A, E> {
139     private final BinaryPredicate<A, E> predicate;
140     private final String description;
141 
FromBinaryPredicate(BinaryPredicate<A, E> correspondencePredicate, String description)142     private FromBinaryPredicate(BinaryPredicate<A, E> correspondencePredicate, String description) {
143       this.predicate = checkNotNull(correspondencePredicate);
144       this.description = checkNotNull(description);
145     }
146 
147     @Override
compare(@ullable A actual, @Nullable E expected)148     public boolean compare(@Nullable A actual, @Nullable E expected) {
149       return predicate.apply(actual, expected);
150     }
151 
152     @Override
toString()153     public String toString() {
154       return description;
155     }
156   }
157 
158   /**
159    * Constructs a {@link Correspondence} that compares elements by transforming the actual elements
160    * using the given function and testing for equality with the expected elements. If the
161    * transformed actual element (i.e. the output of the given function) is null, it will correspond
162    * to a null expected element.
163    *
164    * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can
165    * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}.
166    *
167    * <p>Note that, if you the data you are asserting about contains null actual values, your
168    * function may be invoked with a null argument. If this causes it to throw a {@link
169    * NullPointerException}, then your test will fail. (See {@link Correspondence#compare} for more
170    * detail on how exceptions are handled.) In particular, this applies if your function is an
171    * instance method reference on the actual value (as in the example below). If you want a null
172    * actual element to correspond to a null expected element, you must ensure that your function
173    * transforms a null input to a null output.
174    *
175    * <p>Example:
176    *
177    * <pre>{@code
178    * static final Correspondence<MyRecord, Integer> HAS_ID =
179    *     Correspondence.transforming(MyRecord::getId, "has an ID of");
180    * }</pre>
181    *
182    * This can be used as follows:
183    *
184    * <pre>{@code
185    * assertThat(myRecords).comparingElementsUsing(HAS_ID).containsExactly(123, 456, 789);
186    * }</pre>
187    *
188    * @param actualTransform a {@link Function} taking an actual value and returning a new value
189    *     which will be compared with an expected value to determine whether they correspond
190    * @param description should fill the gap in a failure message of the form {@code "not true that
191    *     <some actual element> is an element that <description> <some expected element>"}, e.g.
192    *     {@code "has an ID of"}
193    */
transforming( Function<A, ? extends E> actualTransform, String description)194   public static <A, E> Correspondence<A, E> transforming(
195       Function<A, ? extends E> actualTransform, String description) {
196     return new Transforming<>(actualTransform, identity(), description);
197   }
198 
199   /**
200    * Constructs a {@link Correspondence} that compares elements by transforming the actual and the
201    * expected elements using the given functions and testing the transformed values for equality. If
202    * an actual element is transformed to null, it will correspond to an expected element that is
203    * also transformed to null.
204    *
205    * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can
206    * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}.
207    *
208    * <p>Note that, if you the data you are asserting about contains null actual or expected values,
209    * the appropriate function may be invoked with a null argument. If this causes it to throw a
210    * {@link NullPointerException}, then your test will fail. (See {@link Correspondence#compare} for
211    * more detail on how exceptions are handled.) In particular, this applies if your function is an
212    * instance method reference on the actual or expected value (as in the example below). If you
213    * want a null actual element to correspond to a null expected element, you must ensure that your
214    * functions both transform a null input to a null output.
215    *
216    * <p>If you want to apply the same function to both the actual and expected elements, just
217    * provide the same argument twice.
218    *
219    * <p>Example:
220    *
221    * <pre>{@code
222    * static final Correspondence<MyRequest, MyResponse> SAME_IDS =
223    *     Correspondence.transforming(MyRequest::getId, MyResponse::getId, "has the same ID as");
224    * }</pre>
225    *
226    * This can be used as follows:
227    *
228    * <pre>{@code
229    * assertThat(myResponses).comparingElementsUsing(SAME_IDS).containsExactlyElementsIn(myRequests);
230    * }</pre>
231    *
232    * @param actualTransform a {@link Function} taking an actual value and returning a new value
233    *     which will be compared with a transformed expected value to determine whether they
234    *     correspond
235    * @param expectedTransform a {@link Function} taking an expected value and returning a new value
236    *     which will be compared with a transformed actual value
237    * @param description should fill the gap in a failure message of the form {@code "not true that
238    *     <some actual element> is an element that <description> <some expected element>"}, e.g.
239    *     {@code "has the same ID as"}
240    */
transforming( Function<A, ?> actualTransform, Function<E, ?> expectedTransform, String description)241   public static <A, E> Correspondence<A, E> transforming(
242       Function<A, ?> actualTransform, Function<E, ?> expectedTransform, String description) {
243     return new Transforming<>(actualTransform, expectedTransform, description);
244   }
245 
246   private static final class Transforming<A, E> extends Correspondence<A, E> {
247 
248     private final Function<? super A, ?> actualTransform;
249     private final Function<? super E, ?> expectedTransform;
250     private final String description;
251 
Transforming( Function<? super A, ?> actualTransform, Function<? super E, ?> expectedTransform, String description)252     private Transforming(
253         Function<? super A, ?> actualTransform,
254         Function<? super E, ?> expectedTransform,
255         String description) {
256       this.actualTransform = actualTransform;
257       this.expectedTransform = expectedTransform;
258       this.description = description;
259     }
260 
261     @Override
compare(@ullable A actual, @Nullable E expected)262     public boolean compare(@Nullable A actual, @Nullable E expected) {
263       return Objects.equal(actualTransform.apply(actual), expectedTransform.apply(expected));
264     }
265 
266     @Override
toString()267     public String toString() {
268       return description;
269     }
270   }
271 
272   /**
273    * Returns a {@link Correspondence} between {@link Number} instances that considers instances to
274    * correspond (i.e. {@link Correspondence#compare(Object, Object)} returns {@code true}) if the
275    * double values of each instance (i.e. the result of calling {@link Number#doubleValue()} on
276    * them) are finite values within {@code tolerance} of each other.
277    *
278    * <ul>
279    *   <li>It does not consider instances to correspond if either value is infinite or NaN.
280    *   <li>The conversion to double may result in a loss of precision for some numeric types.
281    *   <li>The {@link Correspondence#compare(Object, Object)} method throws a {@link
282    *       NullPointerException} if either {@link Number} instance is null.
283    * </ul>
284    *
285    * @param tolerance an inclusive upper bound on the difference between the double values of the
286    *     two {@link Number} instances, which must be a non-negative finite value, i.e. not {@link
287    *     Double#NaN}, {@link Double#POSITIVE_INFINITY}, or negative, including {@code -0.0}
288    */
tolerance(double tolerance)289   public static Correspondence<Number, Number> tolerance(double tolerance) {
290     return new TolerantNumericEquality(tolerance);
291   }
292 
293   private static final class TolerantNumericEquality extends Correspondence<Number, Number> {
294 
295     private final double tolerance;
296 
TolerantNumericEquality(double tolerance)297     private TolerantNumericEquality(double tolerance) {
298       checkTolerance(tolerance);
299       this.tolerance = tolerance;
300     }
301 
302     @Override
compare(Number actual, Number expected)303     public boolean compare(Number actual, Number expected) {
304       double actualDouble = checkNotNull(actual).doubleValue();
305       double expectedDouble = checkNotNull(expected).doubleValue();
306       return MathUtil.equalWithinTolerance(actualDouble, expectedDouble, tolerance);
307     }
308 
309     @Override
toString()310     public String toString() {
311       return "is a finite number within " + tolerance + " of";
312     }
313   }
314 
315   /**
316    * Returns a correspondence which compares elements using object equality, i.e. giving the same
317    * assertions as you would get without a correspondence. This exists so that we can add a
318    * diff-formatting functionality to it. See e.g. {@link IterableSubject#formattingDiffsUsing}.
319    */
320   @SuppressWarnings("unchecked") // safe covariant cast
equality()321   static <T> Correspondence<T, T> equality() {
322     return (Equality<T>) Equality.INSTANCE;
323   }
324 
325   private static final class Equality<T> extends Correspondence<T, T> {
326 
327     private static final Equality<Object> INSTANCE = new Equality<>();
328 
329     @Override
compare(T actual, T expected)330     public boolean compare(T actual, T expected) {
331       return Objects.equal(actual, expected);
332     }
333 
334     @Override
toString()335     public String toString() {
336       // This should normally not be used, since isEquality() returns true, but it should do
337       // something sensible anyway:
338       return "is equal to";
339     }
340 
341     @Override
isEquality()342     boolean isEquality() {
343       return true;
344     }
345   }
346 
347   /**
348    * Constructor. Creating subclasses (anonymous or otherwise) of this class is <i>not
349    * recommended</i>, but is possible via this constructor. The recommended approach is to use the
350    * factory methods instead (see {@linkplain Correspondence class-level documentation}).
351    *
352    * @deprecated Construct an instance with the static factory methods instead. The most mechanical
353    *     migration is usually to {@link #from}.
354    */
355   @Deprecated
Correspondence()356   Correspondence() {}
357 
358   /**
359    * Returns a new correspondence which is like this one, except that the given formatter may be
360    * used to format the difference between a pair of elements that do not correspond.
361    *
362    * <p>Note that, if you the data you are asserting about contains null actual or expected values,
363    * the formatter may be invoked with a null argument. If this causes it to throw a {@link
364    * NullPointerException}, that will be taken to indicate that the values cannot be diffed. (See
365    * {@link Correspondence#formatDiff} for more detail on how exceptions are handled.) If you think
366    * null values are likely, it is slightly cleaner to have the formatter return null in that case
367    * instead of throwing.
368    *
369    * <p>Example:
370    *
371    * <pre>{@code
372    * class MyRecordTestHelper {
373    *   static final Correspondence<MyRecord, MyRecord> EQUIVALENCE =
374    *       Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to")
375    *           .formattingDiffsUsing(MyRecordTestHelper::formatRecordDiff);
376    *   static boolean recordsEquivalent(@Nullable MyRecord actual, @Nullable MyRecord expected) {
377    *     // code to check whether records should be considered equivalent for testing purposes
378    *   }
379    *   static String formatRecordDiff(@Nullable MyRecord actual, @Nullable MyRecord expected) {
380    *     // code to format the diff between the records
381    *   }
382    * }
383    * }</pre>
384    */
formattingDiffsUsing(DiffFormatter<? super A, ? super E> formatter)385   public Correspondence<A, E> formattingDiffsUsing(DiffFormatter<? super A, ? super E> formatter) {
386     return new FormattingDiffs<>(this, formatter);
387   }
388 
389   /**
390    * A functional interface to be used format the diff between a pair of objects of types {@code A}
391    * and {@code E}.
392    *
393    * <p>This interface will normally be implemented using a lambda or a method reference, and the
394    * resulting object will normally be passed directly to {@link
395    * Correspondence#formattingDiffsUsing}. As a result, you should almost never see {@code
396    * DiffFormatter} used as the type of a field or variable, or a return type.
397    */
398   public interface DiffFormatter<A, E> {
399 
400     /**
401      * Returns a {@link String} describing the difference between the {@code actual} and {@code
402      * expected} values, if possible, or {@code null} if not.
403      */
404     @Nullable
formatDiff(@ullable A actual, @Nullable E expected)405     String formatDiff(@Nullable A actual, @Nullable E expected);
406   }
407 
408   private static class FormattingDiffs<A, E> extends Correspondence<A, E> {
409 
410     private final Correspondence<A, E> delegate;
411     private final DiffFormatter<? super A, ? super E> formatter;
412 
FormattingDiffs(Correspondence<A, E> delegate, DiffFormatter<? super A, ? super E> formatter)413     FormattingDiffs(Correspondence<A, E> delegate, DiffFormatter<? super A, ? super E> formatter) {
414       this.delegate = checkNotNull(delegate);
415       this.formatter = checkNotNull(formatter);
416     }
417 
418     @Override
compare(@ullable A actual, @Nullable E expected)419     public boolean compare(@Nullable A actual, @Nullable E expected) {
420       return delegate.compare(actual, expected);
421     }
422 
423     @Override
formatDiff(@ullable A actual, @Nullable E expected)424     public @Nullable String formatDiff(@Nullable A actual, @Nullable E expected) {
425       return formatter.formatDiff(actual, expected);
426     }
427 
428     @Override
toString()429     public String toString() {
430       return delegate.toString();
431     }
432 
433     @Override
isEquality()434     boolean isEquality() {
435       return delegate.isEquality();
436     }
437   }
438 
439   /**
440    * Returns whether or not the {@code actual} value is said to correspond to the {@code expected}
441    * value for the purposes of this test.
442    *
443    * <h3>Exception handling</h3>
444    *
445    * <p>Throwing a {@link RuntimeException} from this method indicates that this {@link
446    * Correspondence} cannot compare the given values. Any assertion which encounters such an
447    * exception during the course of evaluating its condition must not pass. However, an assertion is
448    * not required to invoke this method for every pair of values in its input just in order to check
449    * for exceptions, if it is able to evaluate its condition without doing so.
450    *
451    * <h4>Conventions for handling exceptions</h4>
452    *
453    * <p>(N.B. This section is only really of interest when implementing assertion methods that call
454    * {@link Correspondence#compare}, not to users making such assertions in their tests.)
455    *
456    * <p>The only requirement on an assertion is that, if it encounters an exception from this
457    * method, it must not pass. The simplest implementation choice is simply to allow the exception
458    * to propagate. However, it is normally more helpful to catch the exception and instead fail with
459    * a message which includes more information about the assertion in progress and the nature of the
460    * failure.
461    *
462    * <p>By convention, an assertion may catch and store the exception and continue evaluating the
463    * condition as if the method had returned false instead of throwing. If the assertion's condition
464    * does not hold with this alternative behaviour, it may choose to fail with a message that gives
465    * details about how the condition does not hold, additionally mentioning that assertions were
466    * encountered and giving details about one of the stored exceptions. (See the first example
467    * below.) If the assertion's condition does hold with this alternative behaviour, the requirement
468    * that the assertion must not pass still applies, so it should fail with a message giving details
469    * about one of the stored exceptions. (See the second and third examples below.)
470    *
471    * <p>This behaviour is only a convention and should only be implemented when it makes sense to do
472    * so. In particular, in an assertion that has multiple stages, it may be better to only continue
473    * evaluation to the end of the current stage, and fail citing a stored exception at the end of
474    * the stage, rather than accumulating exceptions through the multiple stages.
475    *
476    * <h4>Examples of exception handling</h4>
477    *
478    * <p>Suppose that we have the correspondence
479    *
480    * <pre>{@code
481    * static final Correspondence<String, String> CASE_INSENSITIVE_EQUALITY =
482    *     Correspondence.from(String::equalsIgnoreCase, "equals ignoring case"}
483    * }</pre>
484    *
485    * whose {@code compare} method throws {@link NullPointerException} if the actual value is null.
486    * The assertion
487    *
488    * <pre>{@code
489    * assertThat(asList(null, "xyz", "abc", "def"))
490    *     .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
491    *     .containsExactly("ABC", "DEF", "GHI", "JKL");
492    * }</pre>
493    *
494    * may fail saying that the actual iterable contains unexpected values {@code null} and {@code
495    * xyz} and is missing values corresponding to {@code GHI} and {@code JKL}, which is what it would
496    * do if the {@code compare} method returned false instead of throwing, and additionally mention
497    * the exception. (This is more helpful than allowing the {@link NullPointerException} to
498    * propagate to the caller, or than failing with only a description of the exception.)
499    *
500    * <p>However, the assertions
501    *
502    * <pre>{@code
503    * assertThat(asList(null, "xyz", "abc", "def"))
504    *     .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
505    *     .doesNotContain("MNO");
506    * }</pre>
507    *
508    * and
509    *
510    * <pre>{@code
511    * assertThat(asList(null, "xyz", "abc", "def"))
512    *     .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
513    *     .doesNotContain(null);
514    * }</pre>
515    *
516    * must both fail citing the exception, even though they would pass if the {@code compare} method
517    * returned false. (Note that, in the latter case at least, it is likely that the test author's
518    * intention was <i>not</i> for the test to pass with these values.)
519    */
compare(@ullable A actual, @Nullable E expected)520   public abstract boolean compare(@Nullable A actual, @Nullable E expected);
521 
522   private static class StoredException {
523 
524     private static final Joiner ARGUMENT_JOINER = Joiner.on(", ").useForNull("null");
525 
526     private final Exception exception;
527     private final String methodName;
528     private final List<Object> methodArguments;
529 
StoredException(Exception exception, String methodName, List<Object> methodArguments)530     StoredException(Exception exception, String methodName, List<Object> methodArguments) {
531       this.exception = checkNotNull(exception);
532       this.methodName = checkNotNull(methodName);
533       this.methodArguments = checkNotNull(methodArguments);
534     }
535 
536     /**
537      * Returns a String describing the exception stored. This includes a stack trace (except under
538      * j2cl, where this is not available). It also has a separator at the end, so that when this
539      * appears at the end of an {@code AssertionError} message, the stack trace of the stored
540      * exception is distinguishable from the stack trace of the {@code AssertionError}.
541      */
describe()542     private String describe() {
543       return Strings.lenientFormat(
544           "%s(%s) threw %s\n---",
545           methodName, ARGUMENT_JOINER.join(methodArguments), getStackTraceAsString(exception));
546     }
547   }
548 
549   /**
550    * Helper object to store exceptions encountered while executing a {@link Correspondence} method.
551    */
552   static final class ExceptionStore {
553 
554     private final String argumentLabel;
555     private StoredException firstCompareException = null;
556     private StoredException firstPairingException = null;
557     private StoredException firstFormatDiffException = null;
558 
forIterable()559     static ExceptionStore forIterable() {
560       return new ExceptionStore("elements");
561     }
562 
forMapValues()563     static ExceptionStore forMapValues() {
564       return new ExceptionStore("values");
565     }
566 
ExceptionStore(String argumentLabel)567     private ExceptionStore(String argumentLabel) {
568       this.argumentLabel = argumentLabel;
569     }
570 
571     /**
572      * Adds an exception that was thrown during a {@code compare} call.
573      *
574      * @param callingClass The class from which the {@code compare} method was called. When
575      *     reporting failures, stack traces will be truncated above elements in this class.
576      * @param exception The exception encountered
577      * @param actual The {@code actual} argument to the {@code compare} call during which the
578      *     exception was encountered
579      * @param expected The {@code expected} argument to the {@code compare} call during which the
580      *     exception was encountered
581      */
addCompareException( Class<?> callingClass, Exception exception, Object actual, Object expected)582     void addCompareException(
583         Class<?> callingClass, Exception exception, Object actual, Object expected) {
584       if (firstCompareException == null) {
585         truncateStackTrace(exception, callingClass);
586         firstCompareException = new StoredException(exception, "compare", asList(actual, expected));
587       }
588     }
589 
590     /**
591      * Adds an exception that was thrown during an {@code apply} call on the function used to key
592      * actual elements.
593      *
594      * @param callingClass The class from which the {@code apply} method was called. When reporting
595      *     failures, stack traces will be truncated above elements in this class.
596      * @param exception The exception encountered
597      * @param actual The {@code actual} argument to the {@code apply} call during which the
598      *     exception was encountered
599      */
addActualKeyFunctionException(Class<?> callingClass, Exception exception, Object actual)600     void addActualKeyFunctionException(Class<?> callingClass, Exception exception, Object actual) {
601       if (firstPairingException == null) {
602         truncateStackTrace(exception, callingClass);
603         firstPairingException =
604             new StoredException(exception, "actualKeyFunction.apply", asList(actual));
605       }
606     }
607 
608     /**
609      * Adds an exception that was thrown during an {@code apply} call on the function used to key
610      * expected elements.
611      *
612      * @param callingClass The class from which the {@code apply} method was called. When reporting
613      *     failures, stack traces will be truncated above elements in this class.
614      * @param exception The exception encountered
615      * @param expected The {@code expected} argument to the {@code apply} call during which the
616      *     exception was encountered
617      */
addExpectedKeyFunctionException( Class<?> callingClass, Exception exception, Object expected)618     void addExpectedKeyFunctionException(
619         Class<?> callingClass, Exception exception, Object expected) {
620       if (firstPairingException == null) {
621         truncateStackTrace(exception, callingClass);
622         firstPairingException =
623             new StoredException(exception, "expectedKeyFunction.apply", asList(expected));
624       }
625     }
626 
627     /**
628      * Adds an exception that was thrown during a {@code formatDiff} call.
629      *
630      * @param callingClass The class from which the {@code formatDiff} method was called. When
631      *     reporting failures, stack traces will be truncated above elements in this class.
632      * @param exception The exception encountered
633      * @param actual The {@code actual} argument to the {@code formatDiff} call during which the
634      *     exception was encountered
635      * @param expected The {@code expected} argument to the {@code formatDiff} call during which the
636      *     exception was encountered
637      */
addFormatDiffException( Class<?> callingClass, Exception exception, Object actual, Object expected)638     void addFormatDiffException(
639         Class<?> callingClass, Exception exception, Object actual, Object expected) {
640       if (firstFormatDiffException == null) {
641         truncateStackTrace(exception, callingClass);
642         firstFormatDiffException =
643             new StoredException(exception, "formatDiff", asList(actual, expected));
644       }
645     }
646 
647     /** Returns whether any exceptions thrown during {@code compare} calls were stored. */
hasCompareException()648     boolean hasCompareException() {
649       return firstCompareException != null;
650     }
651 
652     /**
653      * Returns facts to use in a failure message when the exceptions from {@code compare} calls are
654      * the main cause of the failure. At least one exception thrown during a {@code compare} call
655      * must have been stored, and no exceptions from a {@code formatDiff} call. Assertions should
656      * use this when exceptions were thrown while comparing elements and no more meaningful failure
657      * was discovered by assuming a false return and continuing (see the javadoc for {@link
658      * Correspondence#compare}). C.f. {@link #describeAsAdditionalInfo}.
659      */
describeAsMainCause()660     ImmutableList<Fact> describeAsMainCause() {
661       checkState(firstCompareException != null);
662       // We won't do pairing or diff formatting unless a more meaningful failure was found, and if a
663       // more meaningful failure was found then we shouldn't be using this method:
664       checkState(firstPairingException == null);
665       checkState(firstFormatDiffException == null);
666       return ImmutableList.of(
667           simpleFact("one or more exceptions were thrown while comparing " + argumentLabel),
668           fact("first exception", firstCompareException.describe()));
669     }
670 
671     /**
672      * If any exceptions are stored, returns facts to use in a failure message when the exceptions
673      * should be noted as additional info; if empty, returns an empty list. Assertions should use
674      * this when exceptions were thrown while comparing elements but more meaningful failures were
675      * discovered by assuming a false return and continuing (see the javadoc for {@link
676      * Correspondence#compare}), or when exceptions were thrown by other methods while generating
677      * the failure message. C.f. {@link #describeAsMainCause}.
678      */
describeAsAdditionalInfo()679     ImmutableList<Fact> describeAsAdditionalInfo() {
680       ImmutableList.Builder<Fact> builder = ImmutableList.builder();
681       if (firstCompareException != null) {
682         builder.add(
683             simpleFact(
684                 "additionally, one or more exceptions were thrown while comparing "
685                     + argumentLabel));
686         builder.add(fact("first exception", firstCompareException.describe()));
687       }
688       if (firstPairingException != null) {
689         builder.add(
690             simpleFact(
691                 "additionally, one or more exceptions were thrown while keying "
692                     + argumentLabel
693                     + " for pairing"));
694         builder.add(fact("first exception", firstPairingException.describe()));
695       }
696       if (firstFormatDiffException != null) {
697         builder.add(
698             simpleFact("additionally, one or more exceptions were thrown while formatting diffs"));
699         builder.add(fact("first exception", firstFormatDiffException.describe()));
700       }
701       return builder.build();
702     }
703 
truncateStackTrace(Exception exception, Class<?> callingClass)704     private static void truncateStackTrace(Exception exception, Class<?> callingClass) {
705       StackTraceElement[] original = exception.getStackTrace();
706       int keep = 0;
707       while (keep < original.length
708           && !original[keep].getClassName().equals(callingClass.getName())) {
709         keep++;
710       }
711       exception.setStackTrace(Arrays.copyOf(original, keep));
712     }
713   }
714 
715   /**
716    * Invokes {@link #compare}, catching any exceptions. If the comparison does not throw, returns
717    * the result. If it does throw, adds the exception to the given {@link ExceptionStore} and
718    * returns false. This method can help with implementing the exception-handling policy described
719    * above, but note that assertions using it <i>must</i> fail later if an exception was stored.
720    */
safeCompare(@ullable A actual, @Nullable E expected, ExceptionStore exceptions)721   final boolean safeCompare(@Nullable A actual, @Nullable E expected, ExceptionStore exceptions) {
722     try {
723       return compare(actual, expected);
724     } catch (RuntimeException e) {
725       exceptions.addCompareException(Correspondence.class, e, actual, expected);
726       return false;
727     }
728   }
729 
730   /**
731    * Returns a {@link String} describing the difference between the {@code actual} and {@code
732    * expected} values, if possible, or {@code null} if not.
733    *
734    * <p>The implementation on the {@link Correspondence} base class always returns {@code null}. To
735    * enable diffing, use {@link #formattingDiffsUsing} (or override this method in a subclass, but
736    * factory methods are recommended over subclassing).
737    *
738    * <p>Assertions should only invoke this with parameters for which {@link #compare} returns {@code
739    * false}.
740    *
741    * <p>If this throws an exception, that implies that it is not possible to describe the diffs. An
742    * assertion will normally only call this method if it has established that its condition does not
743    * hold: good practice dictates that, if this method throws, the assertion should catch the
744    * exception and continue to describe the original failure as if this method had returned null,
745    * mentioning the failure from this method as additional information.
746    */
formatDiff(@ullable A actual, @Nullable E expected)747   public @Nullable String formatDiff(@Nullable A actual, @Nullable E expected) {
748     return null;
749   }
750 
751   /**
752    * Invokes {@link #formatDiff}, catching any exceptions. If the comparison does not throw, returns
753    * the result. If it does throw, adds the exception to the given {@link ExceptionStore} and
754    * returns null.
755    */
safeFormatDiff( @ullable A actual, @Nullable E expected, ExceptionStore exceptions)756   final @Nullable String safeFormatDiff(
757       @Nullable A actual, @Nullable E expected, ExceptionStore exceptions) {
758     try {
759       return formatDiff(actual, expected);
760     } catch (RuntimeException e) {
761       exceptions.addFormatDiffException(Correspondence.class, e, actual, expected);
762       return null;
763     }
764   }
765 
766   /**
767    * Returns a description of the correspondence, suitable to fill the gap in a failure message of
768    * the form {@code "<some actual element> is an element that ... <some expected element>"}. Note
769    * that this is a fragment of a verb phrase which takes a singular subject.
770    *
771    * <p>Example 1: For a {@code Correspondence<String, Integer>} that tests whether the actual
772    * string parses to the expected integer, this would return {@code "parses to"} to result in a
773    * failure message of the form {@code "<some actual string> is an element that parses to <some
774    * expected integer>"}.
775    *
776    * <p>Example 2: For the {@code Correspondence<Number, Number>} returns by {@link #tolerance} this
777    * returns {@code "is a finite number within " + tolerance + " of"} to result in a failure message
778    * of the form {@code "<some actual number> is an element that is a finite number within 0.0001 of
779    * <some expected number>"}.
780    */
781   @Override
toString()782   public abstract String toString();
783 
784   /**
785    * Returns whether this is an equality correspondence, i.e. one returned by {@link #equality} or
786    * one whose {@link #compare} delegates to one returned by {@link #equality}.
787    */
isEquality()788   boolean isEquality() {
789     return false;
790   }
791 
792   /**
793    * Returns a list of {@link Fact} instance describing how this correspondence compares elements of
794    * an iterable. There will be one "testing whether" fact, unless this {@link #isEquality is an
795    * equality correspondence}, in which case the list will be empty.
796    */
describeForIterable()797   final ImmutableList<Fact> describeForIterable() {
798     if (!isEquality()) {
799       return ImmutableList.of(
800           fact("testing whether", "actual element " + this + " expected element"));
801     } else {
802       return ImmutableList.of();
803     }
804   }
805 
806   /**
807    * Returns a list of {@link Fact} instance describing how this correspondence compares values in a
808    * map (or multimap). There will be one "testing whether" fact, unless this {@link #isEquality is
809    * an equality correspondence}, in which case the list will be empty.
810    */
describeForMapValues()811   final ImmutableList<Fact> describeForMapValues() {
812     if (!isEquality()) {
813       return ImmutableList.of(fact("testing whether", "actual value " + this + " expected value"));
814     } else {
815       return ImmutableList.of();
816     }
817   }
818 
819   /**
820    * @throws UnsupportedOperationException always
821    * @deprecated {@link Object#equals(Object)} is not supported. If you meant to compare objects
822    *     using this {@link Correspondence}, use {@link #compare}.
823    */
824   @Deprecated
825   @Override
equals(@ullable Object o)826   public final boolean equals(@Nullable Object o) {
827     throw new UnsupportedOperationException(
828         "Correspondence.equals(object) is not supported. If you meant to compare objects, use"
829             + " .compare(actual, expected) instead.");
830   }
831 
832   /**
833    * @throws UnsupportedOperationException always
834    * @deprecated {@link Object#hashCode()} is not supported.
835    */
836   @Deprecated
837   @Override
hashCode()838   public final int hashCode() {
839     throw new UnsupportedOperationException("Correspondence.hashCode() is not supported.");
840   }
841 }
842