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