• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2011 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.CaseFormat.LOWER_CAMEL;
19 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
20 import static com.google.common.base.CharMatcher.whitespace;
21 import static com.google.common.base.MoreObjects.firstNonNull;
22 import static com.google.common.base.Preconditions.checkArgument;
23 import static com.google.common.base.Preconditions.checkNotNull;
24 import static com.google.common.base.Strings.lenientFormat;
25 import static com.google.common.truth.Fact.fact;
26 import static com.google.common.truth.Fact.simpleFact;
27 import static com.google.common.truth.Platform.doubleToString;
28 import static com.google.common.truth.Platform.floatToString;
29 import static com.google.common.truth.Platform.isKotlinRange;
30 import static com.google.common.truth.Platform.kotlinRangeContains;
31 import static com.google.common.truth.Platform.stringValueOfNonFloatingPoint;
32 import static com.google.common.truth.Subject.EqualityCheck.SAME_INSTANCE;
33 import static com.google.common.truth.SubjectUtils.accumulate;
34 import static com.google.common.truth.SubjectUtils.append;
35 import static com.google.common.truth.SubjectUtils.concat;
36 import static com.google.common.truth.SubjectUtils.sandwich;
37 import static java.util.Arrays.asList;
38 
39 import com.google.common.base.Objects;
40 import com.google.common.collect.ImmutableList;
41 import com.google.common.collect.Iterables;
42 import com.google.common.collect.Lists;
43 import com.google.common.primitives.Booleans;
44 import com.google.common.primitives.Bytes;
45 import com.google.common.primitives.Chars;
46 import com.google.common.primitives.Ints;
47 import com.google.common.primitives.Longs;
48 import com.google.common.primitives.Shorts;
49 import com.google.common.truth.FailureMetadata.OldAndNewValuesAreSimilar;
50 import com.google.errorprone.annotations.DoNotCall;
51 import com.google.errorprone.annotations.ForOverride;
52 import java.lang.reflect.Array;
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.List;
56 import org.jspecify.annotations.Nullable;
57 
58 /**
59  * An object that lets you perform checks on the value under test. For example, {@code Subject}
60  * contains {@link #isEqualTo(Object)} and {@link #isInstanceOf(Class)}, and {@link StringSubject}
61  * contains {@link StringSubject#startsWith startsWith(String)}.
62  *
63  * <p>To create a {@code Subject} instance, most users will call an {@link Truth#assertThat
64  * assertThat} method. For information about other ways to create an instance, see <a
65  * href="https://truth.dev/faq#full-chain">this FAQ entry</a>.
66  *
67  * <h3>For people extending Truth</h3>
68  *
69  * <p>For information about writing a custom {@link Subject}, see <a
70  * href="https://truth.dev/extension">our doc on extensions</a>.
71  *
72  * @author David Saff
73  * @author Christian Gruber
74  */
75 public class Subject {
76   /**
77    * In a fluent assertion chain, the argument to the common overload of {@link
78    * StandardSubjectBuilder#about(Subject.Factory) about}, the method that specifies what kind of
79    * {@link Subject} to create.
80    *
81    * <p>For more information about the fluent chain, see <a
82    * href="https://truth.dev/faq#full-chain">this FAQ entry</a>.
83    *
84    * <h3>For people extending Truth</h3>
85    *
86    * <p>When you write a custom subject, see <a href="https://truth.dev/extension">our doc on
87    * extensions</a>. It explains where {@code Subject.Factory} fits into the process.
88    */
89   public interface Factory<SubjectT extends Subject, ActualT> {
90     /** Creates a new {@link Subject}. */
createSubject(FailureMetadata metadata, @Nullable ActualT actual)91     SubjectT createSubject(FailureMetadata metadata, @Nullable ActualT actual);
92   }
93 
94   private final @Nullable FailureMetadata metadata;
95   private final @Nullable Object actual;
96   private final @Nullable String typeDescriptionOverride;
97 
98   /**
99    * Constructor for use by subclasses. If you want to create an instance of this class itself, call
100    * {@link Subject#check(String, Object...) check(...)}{@code .that(actual)}.
101    */
Subject(FailureMetadata metadata, @Nullable Object actual)102   protected Subject(FailureMetadata metadata, @Nullable Object actual) {
103     this(metadata, actual, /* typeDescriptionOverride= */ null);
104   }
105 
106   /**
107    * Special constructor that lets subclasses provide a description of the type they're testing. For
108    * example, {@link ThrowableSubject} passes the description "throwable." Normally, Truth is able
109    * to infer this name from the class name. However, if we lack runtime type information (notably,
110    * under j2cl with class metadata off), we might not have access to the original class name.
111    *
112    * <p>We don't expect to make this a public API: Class names are nearly always available. It's
113    * just that we want to be able to run Truth's own tests run with class metadata off, and it's
114    * easier to tweak the subjects to know their own names rather than generalize the tests to accept
115    * obfuscated names.
116    */
Subject( @ullable FailureMetadata metadata, @Nullable Object actual, @Nullable String typeDescriptionOverride)117   Subject(
118       @Nullable FailureMetadata metadata,
119       @Nullable Object actual,
120       @Nullable String typeDescriptionOverride) {
121     this.metadata = metadata == null ? null : metadata.updateForSubject(this);
122     this.actual = actual;
123     this.typeDescriptionOverride = typeDescriptionOverride;
124   }
125 
126   /** Fails if the subject is not null. */
isNull()127   public void isNull() {
128     standardIsEqualTo(null);
129   }
130 
131   /** Fails if the subject is null. */
isNotNull()132   public void isNotNull() {
133     standardIsNotEqualTo(null);
134   }
135 
136   /**
137    * Fails if the subject is not equal to the given object. For the purposes of this comparison, two
138    * objects are equal if any of the following is true:
139    *
140    * <ul>
141    *   <li>they are equal according to {@link Objects#equal}
142    *   <li>they are arrays and are considered equal by the appropriate {@link Arrays#equals}
143    *       overload
144    *   <li>they are boxed integer types ({@code Byte}, {@code Short}, {@code Character}, {@code
145    *       Integer}, or {@code Long}) and they are numerically equal when converted to {@code Long}.
146    *   <li>the actual value is a boxed floating-point type ({@code Double} or {@code Float}), the
147    *       expected value is an {@code Integer}, and the two are numerically equal when converted to
148    *       {@code Double}. (This allows {@code assertThat(someDouble).isEqualTo(0)} to pass.)
149    * </ul>
150    *
151    * <p><b>Note:</b> This method does not test the {@link Object#equals} implementation itself; it
152    * <i>assumes</i> that method is functioning correctly according to its contract. Testing an
153    * {@code equals} implementation requires a utility such as <a
154    * href="https://mvnrepository.com/artifact/com.google.guava/guava-testlib">guava-testlib</a>'s <a
155    * href="https://static.javadoc.io/com.google.guava/guava-testlib/23.0/com/google/common/testing/EqualsTester.html">EqualsTester</a>.
156    *
157    * <p>In some cases, this method might not even call {@code equals}. It may instead perform other
158    * tests that will return the same result as long as {@code equals} is implemented according to
159    * the contract for its type.
160    */
161   /*
162    * TODO(cpovirk): Possibly ban overriding isEqualTo+isNotEqualTo in favor of a
163    * compareForEquality(Object, Object) method. That way, people would need to override only one
164    * method, they would get a ComparisonFailure and other message niceties, and they'd have less to
165    * test.
166    */
isEqualTo(@ullable Object expected)167   public void isEqualTo(@Nullable Object expected) {
168     standardIsEqualTo(expected);
169   }
170 
standardIsEqualTo(@ullable Object expected)171   private void standardIsEqualTo(@Nullable Object expected) {
172     ComparisonResult difference = compareForEquality(expected);
173     if (!difference.valuesAreEqual()) {
174       failEqualityCheck(EqualityCheck.EQUAL, expected, difference);
175     }
176   }
177 
178   /**
179    * Fails if the subject is equal to the given object. The meaning of equality is the same as for
180    * the {@link #isEqualTo} method.
181    */
isNotEqualTo(@ullable Object unexpected)182   public void isNotEqualTo(@Nullable Object unexpected) {
183     standardIsNotEqualTo(unexpected);
184   }
185 
standardIsNotEqualTo(@ullable Object unexpected)186   private void standardIsNotEqualTo(@Nullable Object unexpected) {
187     ComparisonResult difference = compareForEquality(unexpected);
188     if (difference.valuesAreEqual()) {
189       String unexpectedAsString = formatActualOrExpected(unexpected);
190       if (actualCustomStringRepresentation().equals(unexpectedAsString)) {
191         failWithoutActual(fact("expected not to be", unexpectedAsString));
192       } else {
193         failWithoutActual(
194             fact("expected not to be", unexpectedAsString),
195             fact(
196                 "but was; string representation of actual value",
197                 actualCustomStringRepresentation()));
198       }
199     }
200   }
201 
202   /**
203    * Returns whether {@code actual} equals {@code expected} differ and, in some cases, a description
204    * of how they differ.
205    *
206    * <p>The equality check follows the rules described on {@link #isEqualTo}.
207    */
compareForEquality(@ullable Object expected)208   private ComparisonResult compareForEquality(@Nullable Object expected) {
209     if (actual == null && expected == null) {
210       return ComparisonResult.equal();
211     } else if (actual == null || expected == null) {
212       return ComparisonResult.differentNoDescription();
213     } else if (actual instanceof byte[] && expected instanceof byte[]) {
214       /*
215        * For a special error message and to use faster Arrays.equals to avoid at least one timeout.
216        *
217        * TODO(cpovirk): For performance, use Arrays.equals for other array types (here and/or in
218        * checkArrayEqualsRecursive)? Exception: double[] and float[], whose GWT implementations I
219        * think may have both false positives and false negatives (so we can't even use Arrays.equals
220        * as a fast path for them, nor deepEquals for an Object[] that might contain them). We would
221        * still fall back to the slower checkArrayEqualsRecursive to produce a nicer failure message
222        * -- but naturally only for tests that are about to fail, when performance matters less.
223        */
224       return checkByteArrayEquals((byte[]) expected, (byte[]) actual);
225     } else if (actual.getClass().isArray() && expected.getClass().isArray()) {
226       return checkArrayEqualsRecursive(expected, actual, "");
227     } else if (isIntegralBoxedPrimitive(actual) && isIntegralBoxedPrimitive(expected)) {
228       return ComparisonResult.fromEqualsResult(integralValue(actual) == integralValue(expected));
229     } else if (actual instanceof Double && expected instanceof Double) {
230       return ComparisonResult.fromEqualsResult(
231           Double.compare((Double) actual, (Double) expected) == 0);
232     } else if (actual instanceof Float && expected instanceof Float) {
233       return ComparisonResult.fromEqualsResult(
234           Float.compare((Float) actual, (Float) expected) == 0);
235     } else if (actual instanceof Double && expected instanceof Integer) {
236       return ComparisonResult.fromEqualsResult(
237           Double.compare((Double) actual, (Integer) expected) == 0);
238     } else if (actual instanceof Float && expected instanceof Integer) {
239       return ComparisonResult.fromEqualsResult(
240           Double.compare((Float) actual, (Integer) expected) == 0);
241     } else {
242       return ComparisonResult.fromEqualsResult(actual == expected || actual.equals(expected));
243     }
244   }
245 
isIntegralBoxedPrimitive(@ullable Object o)246   private static boolean isIntegralBoxedPrimitive(@Nullable Object o) {
247     return o instanceof Byte
248         || o instanceof Short
249         || o instanceof Character
250         || o instanceof Integer
251         || o instanceof Long;
252   }
253 
integralValue(Object o)254   private static long integralValue(Object o) {
255     if (o instanceof Character) {
256       return (long) ((Character) o).charValue();
257     } else if (o instanceof Number) {
258       return ((Number) o).longValue();
259     } else {
260       throw new AssertionError(o + " must be either a Character or a Number.");
261     }
262   }
263 
264   /** Fails if the subject is not the same instance as the given object. */
isSameInstanceAs(@ullable Object expected)265   public final void isSameInstanceAs(@Nullable Object expected) {
266     if (actual != expected) {
267       failEqualityCheck(
268           SAME_INSTANCE,
269           expected,
270           /*
271            * Pass through *whether* the values are equal so that failEqualityCheck() can print that
272            * information. But remove the description of the difference, which is always about
273            * content, since people calling isSameInstanceAs() are explicitly not interested in
274            * content, only object identity.
275            */
276           compareForEquality(expected).withoutDescription());
277     }
278   }
279 
280   /** Fails if the subject is the same instance as the given object. */
isNotSameInstanceAs(@ullable Object unexpected)281   public final void isNotSameInstanceAs(@Nullable Object unexpected) {
282     if (actual == unexpected) {
283       /*
284        * We use actualCustomStringRepresentation() because it might be overridden to be better than
285        * actual.toString()/unexpected.toString().
286        */
287       failWithoutActual(
288           fact("expected not to be specific instance", actualCustomStringRepresentation()));
289     }
290   }
291 
292   /** Fails if the subject is not an instance of the given class. */
isInstanceOf(Class<?> clazz)293   public void isInstanceOf(Class<?> clazz) {
294     if (clazz == null) {
295       throw new NullPointerException("clazz");
296     }
297     if (actual == null) {
298       failWithActual("expected instance of", clazz.getName());
299       return;
300     }
301     if (!isInstanceOfType(actual, clazz)) {
302       if (Platform.classMetadataUnsupported()) {
303         throw new UnsupportedOperationException(
304             actualCustomStringRepresentation()
305                 + ", an instance of "
306                 + actual.getClass().getName()
307                 + ", may or may not be an instance of "
308                 + clazz.getName()
309                 + ". Under -XdisableClassMetadata, we do not have enough information to tell.");
310       }
311       failWithoutActual(
312           fact("expected instance of", clazz.getName()),
313           fact("but was instance of", actual.getClass().getName()),
314           fact("with value", actualCustomStringRepresentation()));
315     }
316   }
317 
318   /** Fails if the subject is an instance of the given class. */
isNotInstanceOf(Class<?> clazz)319   public void isNotInstanceOf(Class<?> clazz) {
320     if (clazz == null) {
321       throw new NullPointerException("clazz");
322     }
323     if (Platform.classMetadataUnsupported()) {
324       throw new UnsupportedOperationException(
325           "isNotInstanceOf is not supported under -XdisableClassMetadata");
326     }
327     if (actual == null) {
328       return; // null is not an instance of clazz.
329     }
330     if (isInstanceOfType(actual, clazz)) {
331       failWithActual("expected not to be an instance of", clazz.getName());
332       /*
333        * TODO(cpovirk): Consider including actual.getClass() if it's not clazz itself but only a
334        * subtype.
335        */
336     }
337   }
338 
isInstanceOfType(Object instance, Class<?> clazz)339   private static boolean isInstanceOfType(Object instance, Class<?> clazz) {
340     checkArgument(
341         !clazz.isPrimitive(),
342         "Cannot check instanceof for primitive type %s. Pass the wrapper class instead.",
343         clazz.getSimpleName());
344     /*
345      * TODO(cpovirk): Make the message include `Primitives.wrap(clazz).getSimpleName()` once that
346      * method is available in a public guava-gwt release that we depend on.
347      */
348     return Platform.isInstanceOfType(instance, clazz);
349   }
350 
351   /** Fails unless the subject is equal to any element in the given iterable. */
isIn(@ullable Iterable<?> iterable)352   public void isIn(@Nullable Iterable<?> iterable) {
353     checkNotNull(iterable);
354     if (!contains(iterable, actual)) {
355       failWithActual("expected any of", iterable);
356     }
357   }
358 
contains(Iterable<?> haystack, @Nullable Object needle)359   private static boolean contains(Iterable<?> haystack, @Nullable Object needle) {
360     if (isKotlinRange(haystack)) {
361       return kotlinRangeContains(haystack, needle);
362     }
363     return Iterables.contains(haystack, needle);
364   }
365 
366   /** Fails unless the subject is equal to any of the given elements. */
isAnyOf( @ullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest)367   public void isAnyOf(
368       @Nullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest) {
369     isIn(accumulate(first, second, rest));
370   }
371 
372   /** Fails if the subject is equal to any element in the given iterable. */
isNotIn(@ullable Iterable<?> iterable)373   public void isNotIn(@Nullable Iterable<?> iterable) {
374     checkNotNull(iterable);
375     if (Iterables.contains(iterable, actual)) {
376       failWithActual("expected not to be any of", iterable);
377     }
378   }
379 
380   /** Fails if the subject is equal to any of the given elements. */
isNoneOf( @ullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest)381   public void isNoneOf(
382       @Nullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest) {
383     isNotIn(accumulate(first, second, rest));
384   }
385 
386   /** Returns the actual value under test. */
actual()387   final @Nullable Object actual() {
388     return actual;
389   }
390 
391   /**
392    * Supplies the direct string representation of the actual value to other methods which may prefix
393    * or otherwise position it in an error message. This should only be overridden to provide an
394    * improved string representation of the value under test, as it would appear in any given error
395    * message, and should not be used for additional prefixing.
396    *
397    * <p>Subjects should override this with care.
398    *
399    * <p>By default, this returns {@code String.ValueOf(getActualValue())}.
400    */
401   /*
402    * TODO(cpovirk): Consider whether this API pulls its weight. If users want to format the actual
403    * value, maybe they should do so themselves? Of course, they won't have a chance to use a custom
404    * format for inherited implementations like isEqualTo(). But if they want to format the actual
405    * value specially, then it seems likely that they'll want to format the expected value specially,
406    * too. And that applies just as well to APIs like isIn(). Maybe we'll want an API that supports
407    * formatting those values, too (like formatActualOrExpected below)? See also the related
408    * b/70930431. But note that we are likely to use this from FailureMetadata, at least in the short
409    * term, for better or for worse.
410    */
411   @ForOverride
actualCustomStringRepresentation()412   protected String actualCustomStringRepresentation() {
413     return formatActualOrExpected(actual);
414   }
415 
actualCustomStringRepresentationForPackageMembersToCall()416   final String actualCustomStringRepresentationForPackageMembersToCall() {
417     return actualCustomStringRepresentation();
418   }
419 
formatActualOrExpected(@ullable Object o)420   private String formatActualOrExpected(@Nullable Object o) {
421     if (o instanceof byte[]) {
422       return base16((byte[]) o);
423     } else if (o != null && o.getClass().isArray()) {
424       return String.valueOf(arrayAsListRecursively(o));
425     } else if (o instanceof Double) {
426       return doubleToString((Double) o);
427     } else if (o instanceof Float) {
428       return floatToString((Float) o);
429     } else {
430       // TODO(cpovirk): Consider renaming the called method to mention "NonArray."
431       /*
432        * TODO(cpovirk): Should the called method and arrayAsListRecursively(...) both call back into
433        * formatActualOrExpected for its handling of byte[] and float/double? Or is there some other
434        * restructuring of this set of methods that we should undertake?
435        */
436       return stringValueOfNonFloatingPoint(o);
437     }
438   }
439 
440   // We could add a dep on com.google.common.io, but that seems overkill for base16 encoding
base16(byte[] bytes)441   private static String base16(byte[] bytes) {
442     StringBuilder sb = new StringBuilder(2 * bytes.length);
443     for (byte b : bytes) {
444       sb.append(hexDigits[(b >> 4) & 0xf]).append(hexDigits[b & 0xf]);
445     }
446     return sb.toString();
447   }
448 
449   private static final char[] hexDigits = "0123456789ABCDEF".toCharArray();
450 
arrayAsListRecursively(@ullable Object input)451   private static @Nullable Object arrayAsListRecursively(@Nullable Object input) {
452     if (input instanceof Object[]) {
453       return Lists.<@Nullable Object, @Nullable Object>transform(
454           asList((@Nullable Object[]) input), Subject::arrayAsListRecursively);
455     } else if (input instanceof boolean[]) {
456       return Booleans.asList((boolean[]) input);
457     } else if (input instanceof int[]) {
458       return Ints.asList((int[]) input);
459     } else if (input instanceof long[]) {
460       return Longs.asList((long[]) input);
461     } else if (input instanceof short[]) {
462       return Shorts.asList((short[]) input);
463     } else if (input instanceof byte[]) {
464       return Bytes.asList((byte[]) input);
465     } else if (input instanceof double[]) {
466       return doubleArrayAsString((double[]) input);
467     } else if (input instanceof float[]) {
468       return floatArrayAsString((float[]) input);
469     } else if (input instanceof char[]) {
470       return Chars.asList((char[]) input);
471     } else {
472       return input;
473     }
474   }
475 
476   /**
477    * The result of comparing two objects for equality. This includes both the "equal"/"not-equal"
478    * bit and, in the case of "not equal," optional facts describing the difference.
479    */
480   private static final class ComparisonResult {
481     /**
482      * If {@code equal} is true, returns an equal result; if false, a non-equal result with no
483      * description.
484      */
fromEqualsResult(boolean equal)485     static ComparisonResult fromEqualsResult(boolean equal) {
486       return equal ? EQUAL : DIFFERENT_NO_DESCRIPTION;
487     }
488 
489     /** Returns a non-equal result with the given description. */
differentWithDescription(Fact... facts)490     static ComparisonResult differentWithDescription(Fact... facts) {
491       return new ComparisonResult(ImmutableList.copyOf(facts));
492     }
493 
494     /** Returns an equal result. */
equal()495     static ComparisonResult equal() {
496       return EQUAL;
497     }
498 
499     /** Returns a non-equal result with no description. */
differentNoDescription()500     static ComparisonResult differentNoDescription() {
501       return DIFFERENT_NO_DESCRIPTION;
502     }
503 
504     private static final ComparisonResult EQUAL = new ComparisonResult(null);
505     private static final ComparisonResult DIFFERENT_NO_DESCRIPTION =
506         new ComparisonResult(ImmutableList.<Fact>of());
507 
508     private final @Nullable ImmutableList<Fact> facts;
509 
ComparisonResult(@ullable ImmutableList<Fact> facts)510     private ComparisonResult(@Nullable ImmutableList<Fact> facts) {
511       this.facts = facts;
512     }
513 
valuesAreEqual()514     boolean valuesAreEqual() {
515       return facts == null;
516     }
517 
factsOrEmpty()518     ImmutableList<Fact> factsOrEmpty() {
519       return firstNonNull(facts, ImmutableList.<Fact>of());
520     }
521 
522     /** Returns an instance with the same "equal"/"not-equal" bit but with no description. */
withoutDescription()523     ComparisonResult withoutDescription() {
524       return fromEqualsResult(valuesAreEqual());
525     }
526   }
527 
528   /**
529    * Returns null if the arrays are equal. If not equal, returns a string comparing the two arrays,
530    * displaying them in the style "[1, 2, 3]" to supplement the main failure message, which uses the
531    * style "010203."
532    */
checkByteArrayEquals(byte[] expected, byte[] actual)533   private static ComparisonResult checkByteArrayEquals(byte[] expected, byte[] actual) {
534     if (Arrays.equals(expected, actual)) {
535       return ComparisonResult.equal();
536     }
537     return ComparisonResult.differentWithDescription(
538         fact("expected", Arrays.toString(expected)), fact("but was", Arrays.toString(actual)));
539   }
540 
541   /**
542    * Returns null if the arrays are equal, recursively. If not equal, returns the string of the
543    * index at which they're different.
544    */
545   /*
546    * TODO(cpovirk): Decide whether it's worthwhile to go to this trouble to display the index at
547    * which the arrays differ. If we were to stop doing that, we could mostly delegate to
548    * Arrays.equals() and our float/double arrayEquals methods. (We'd use deepEquals, but it doesn't
549    * have our special double/float handling for GWT.)
550    */
checkArrayEqualsRecursive( Object expectedArray, Object actualArray, String lastIndex)551   private static ComparisonResult checkArrayEqualsRecursive(
552       Object expectedArray, Object actualArray, String lastIndex) {
553     if (expectedArray == actualArray) {
554       return ComparisonResult.equal();
555     }
556     String expectedType = arrayType(expectedArray);
557     String actualType = arrayType(actualArray);
558     if (!expectedType.equals(actualType)) {
559       Fact indexFact =
560           lastIndex.isEmpty() ? simpleFact("wrong type") : fact("wrong type for index", lastIndex);
561       return ComparisonResult.differentWithDescription(
562           indexFact, fact("expected", expectedType), fact("but was", actualType));
563     }
564     int actualLength = Array.getLength(actualArray);
565     int expectedLength = Array.getLength(expectedArray);
566     if (expectedLength != actualLength) {
567       Fact indexFact =
568           lastIndex.isEmpty()
569               ? simpleFact("wrong length")
570               : fact("wrong length for index", lastIndex);
571       return ComparisonResult.differentWithDescription(
572           indexFact, fact("expected", expectedLength), fact("but was", actualLength));
573     }
574     for (int i = 0; i < actualLength; i++) {
575       String index = lastIndex + "[" + i + "]";
576       Object expected = Array.get(expectedArray, i);
577       Object actual = Array.get(actualArray, i);
578       if (actual != null
579           && actual.getClass().isArray()
580           && expected != null
581           && expected.getClass().isArray()) {
582         ComparisonResult result = checkArrayEqualsRecursive(expected, actual, index);
583         if (!result.valuesAreEqual()) {
584           return result;
585         }
586       } else if (!gwtSafeObjectEquals(actual, expected)) {
587         return ComparisonResult.differentWithDescription(fact("differs at index", index));
588       }
589     }
590     return ComparisonResult.equal();
591   }
592 
arrayType(Object array)593   private static String arrayType(Object array) {
594     if (array.getClass() == boolean[].class) {
595       return "boolean[]";
596     } else if (array.getClass() == int[].class) {
597       return "int[]";
598     } else if (array.getClass() == long[].class) {
599       return "long[]";
600     } else if (array.getClass() == short[].class) {
601       return "short[]";
602     } else if (array.getClass() == byte[].class) {
603       return "byte[]";
604     } else if (array.getClass() == double[].class) {
605       return "double[]";
606     } else if (array.getClass() == float[].class) {
607       return "float[]";
608     } else if (array.getClass() == char[].class) {
609       return "char[]";
610     } else {
611       return "Object[]";
612     }
613   }
614 
gwtSafeObjectEquals(@ullable Object actual, @Nullable Object expected)615   private static boolean gwtSafeObjectEquals(@Nullable Object actual, @Nullable Object expected) {
616     if (actual instanceof Double && expected instanceof Double) {
617       return Double.doubleToLongBits((Double) actual) == Double.doubleToLongBits((Double) expected);
618     } else if (actual instanceof Float && expected instanceof Float) {
619       return Float.floatToIntBits((Float) actual) == Float.floatToIntBits((Float) expected);
620     } else {
621       return Objects.equal(actual, expected);
622     }
623   }
624 
doubleArrayAsString(double[] items)625   private static List<String> doubleArrayAsString(double[] items) {
626     List<String> itemAsStrings = new ArrayList<>(items.length);
627     for (double item : items) {
628       itemAsStrings.add(doubleToString(item));
629     }
630     return itemAsStrings;
631   }
632 
floatArrayAsString(float[] items)633   private static List<String> floatArrayAsString(float[] items) {
634     List<String> itemAsStrings = new ArrayList<>(items.length);
635     for (float item : items) {
636       itemAsStrings.add(floatToString(item));
637     }
638     return itemAsStrings;
639   }
640 
641   /**
642    * Returns a builder for creating a derived subject but without providing information about how
643    * the derived subject will relate to the current subject. In most cases, you should provide such
644    * information by using {@linkplain #check(String, Object...) the other overload}.
645    *
646    * @deprecated Use {@linkplain #check(String, Object...) the other overload}, which requires you
647    *     to supply more information to include in any failure messages.
648    */
649   @Deprecated
check()650   final StandardSubjectBuilder check() {
651     return new StandardSubjectBuilder(checkNotNull(metadata).updateForCheckCall());
652   }
653 
654   /**
655    * Returns a builder for creating a derived subject.
656    *
657    * <p>Derived subjects retain the {@link FailureStrategy} and {@linkplain
658    * StandardSubjectBuilder#withMessage messages} of the current subject, and in some cases, they
659    * automatically supplement their failure message with information about the original subject.
660    *
661    * <p>For example, {@link ThrowableSubject#hasMessageThat}, which returns a {@link StringSubject},
662    * is implemented with {@code check("getMessage()").that(actual.getMessage())}.
663    *
664    * <p>The arguments to {@code check} describe how the new subject was derived from the old,
665    * formatted like a chained method call. This allows Truth to include that information in its
666    * failure messages. For example, {@code assertThat(caught).hasCauseThat().hasMessageThat()} will
667    * produce a failure message that includes the string "throwable.getCause().getMessage()," thanks
668    * to internal {@code check} calls that supplied "getCause()" and "getMessage()" as arguments.
669    *
670    * <p>If the method you're delegating to accepts parameters, you can pass {@code check} a format
671    * string. For example, {@link MultimapSubject#valuesForKey} calls {@code
672    * check("valuesForKey(%s)", key)}.
673    *
674    * <p>If you aren't really delegating to an instance method on the actual value -- maybe you're
675    * calling a static method, or you're calling a chain of several methods -- you can supply
676    * whatever string will be most useful to users. For example, if you're delegating to {@code
677    * getOnlyElement(actual.colors())}, you might call {@code check("onlyColor()")}.
678    *
679    * @param format a template with {@code %s} placeholders
680    * @param args the arguments to be inserted into those placeholders
681    */
check(String format, @Nullable Object... args)682   protected final StandardSubjectBuilder check(String format, @Nullable Object... args) {
683     return doCheck(OldAndNewValuesAreSimilar.DIFFERENT, format, args);
684   }
685 
686   // TODO(b/134064106): Figure out a public API for this.
687 
checkNoNeedToDisplayBothValues( String format, @Nullable Object... args)688   final StandardSubjectBuilder checkNoNeedToDisplayBothValues(
689       String format, @Nullable Object... args) {
690     return doCheck(OldAndNewValuesAreSimilar.SIMILAR, format, args);
691   }
692 
doCheck( OldAndNewValuesAreSimilar valuesAreSimilar, String format, @Nullable Object[] args)693   private StandardSubjectBuilder doCheck(
694       OldAndNewValuesAreSimilar valuesAreSimilar, String format, @Nullable Object[] args) {
695     LazyMessage message = new LazyMessage(format, args);
696     return new StandardSubjectBuilder(
697         checkNotNull(metadata)
698             .updateForCheckCall(
699                 valuesAreSimilar, /* descriptionUpdate= */ input -> input + "." + message));
700   }
701 
702   /**
703    * Begins a new call chain that ignores any failures. This is useful for subjects that normally
704    * delegate with to other subjects by using {@link #check} but have already reported a failure. In
705    * such cases it may still be necessary to return a {@code Subject} instance even though any
706    * subsequent assertions are meaningless. For example, if a user chains together more {@link
707    * ThrowableSubject#hasCauseThat} calls than the actual exception has causes, {@code hasCauseThat}
708    * returns {@code ignoreCheck().that(... a dummy exception ...)}.
709    */
ignoreCheck()710   protected final StandardSubjectBuilder ignoreCheck() {
711     return StandardSubjectBuilder.forCustomFailureStrategy(failure -> {});
712   }
713 
714   /**
715    * Fails, reporting a message with two "{@linkplain Fact facts}":
716    *
717    * <ul>
718    *   <li><i>key</i>: <i>value</i>
719    *   <li>but was: <i>actual value</i>.
720    * </ul>
721    *
722    * <p>This is the simplest failure API. For more advanced needs, see {@linkplain
723    * #failWithActual(Fact, Fact...) the other overload} and {@link #failWithoutActual(Fact, Fact...)
724    * failWithoutActual}.
725    *
726    * <p>Example usage: The check {@code contains(String)} calls {@code failWithActual("expected to
727    * contain", string)}.
728    */
failWithActual(String key, @Nullable Object value)729   protected final void failWithActual(String key, @Nullable Object value) {
730     failWithActual(fact(key, value));
731   }
732 
733   /**
734    * Fails, reporting a message with the given facts, followed by an automatically added fact of the
735    * form:
736    *
737    * <ul>
738    *   <li>but was: <i>actual value</i>.
739    * </ul>
740    *
741    * <p>If you have only one fact to report (and it's a {@linkplain Fact#fact key-value fact}),
742    * prefer {@linkplain #failWithActual(String, Object) the simpler overload}.
743    *
744    * <p>Example usage: The check {@code isEmpty()} calls {@code failWithActual(simpleFact("expected
745    * to be empty"))}.
746    */
failWithActual(Fact first, Fact... rest)747   protected final void failWithActual(Fact first, Fact... rest) {
748     doFail(sandwich(first, rest, butWas()));
749   }
750 
751   // TODO(cpovirk): Consider making this protected if there's a need for it.
failWithActual(Iterable<Fact> facts)752   final void failWithActual(Iterable<Fact> facts) {
753     doFail(append(ImmutableList.copyOf(facts), butWas()));
754   }
755 
756   /**
757    * Reports a failure constructing a message from a simple verb.
758    *
759    * @param check the check being asserted
760    * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link
761    *     #failWithActual(Fact, Fact...) failWithActual}{@code (}{@link Fact#simpleFact
762    *     simpleFact(...)}{@code )}. However, if you want to preserve your exact failure message as a
763    *     migration aid, you can inline this method (and then inline the resulting method call, as
764    *     well).
765    */
766   @Deprecated
fail(String check)767   final void fail(String check) {
768     fail(check, new Object[0]);
769   }
770 
771   /**
772    * Assembles a failure message and passes such to the FailureStrategy
773    *
774    * @param verb the check being asserted
775    * @param other the value against which the subject is compared
776    * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link
777    *     #failWithActual(String, Object)}. However, if you want to preserve your exact failure
778    *     message as a migration aid, you can inline this method (and then inline the resulting
779    *     method call, as well).
780    */
781   @Deprecated
fail(String verb, Object other)782   final void fail(String verb, Object other) {
783     fail(verb, new Object[] {other});
784   }
785 
786   /**
787    * Assembles a failure message and passes such to the FailureStrategy
788    *
789    * @param verb the check being asserted
790    * @param messageParts the expectations against which the subject is compared
791    * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link
792    *     #failWithActual(Fact, Fact...)}. However, if you want to preserve your exact failure
793    *     message as a migration aid, you can inline this method.
794    */
795   @Deprecated
fail(String verb, @Nullable Object... messageParts)796   final void fail(String verb, @Nullable Object... messageParts) {
797     StringBuilder message = new StringBuilder("Not true that <");
798     message.append(actualCustomStringRepresentation()).append("> ").append(verb);
799     for (Object part : messageParts) {
800       message.append(" <").append(part).append(">");
801     }
802     failWithoutActual(simpleFact(message.toString()));
803   }
804 
805   enum EqualityCheck {
806     EQUAL("expected"),
807     SAME_INSTANCE("expected specific instance");
808 
809     final String keyForExpected;
810 
EqualityCheck(String keyForExpected)811     EqualityCheck(String keyForExpected) {
812       this.keyForExpected = keyForExpected;
813     }
814   }
815 
816   /**
817    * Special version of {@link #failEqualityCheck} for use from {@link IterableSubject}, documented
818    * further there.
819    */
failEqualityCheckForEqualsWithoutDescription(@ullable Object expected)820   final void failEqualityCheckForEqualsWithoutDescription(@Nullable Object expected) {
821     failEqualityCheck(EqualityCheck.EQUAL, expected, ComparisonResult.differentNoDescription());
822   }
823 
failEqualityCheck( EqualityCheck equalityCheck, @Nullable Object expected, ComparisonResult difference)824   private void failEqualityCheck(
825       EqualityCheck equalityCheck, @Nullable Object expected, ComparisonResult difference) {
826     String actualString = actualCustomStringRepresentation();
827     String expectedString = formatActualOrExpected(expected);
828     String actualClass = actual == null ? "(null reference)" : actual.getClass().getName();
829     String expectedClass = expected == null ? "(null reference)" : expected.getClass().getName();
830 
831     /*
832      * It's a little odd for expectedString to be formatActualOrExpected(expected) but actualString
833      * *not* to be formatActualOrExpected(actual), since we're going to compare the two. Instead,
834      * actualString is actualCustomStringRepresentation() -- as it is for other assertions, since
835      * users may have overridden that method. While actualCustomStringRepresentation() defaults to
836      * formatActualOrExpected(actual), it's only a default.
837      *
838      * What we really want here is probably to delete actualCustomStringRepresentation() and migrate
839      * users to formatActualOrExpected(actual).
840      */
841     boolean sameToStrings = actualString.equals(expectedString);
842     boolean sameClassNames = actualClass.equals(expectedClass);
843     // TODO(cpovirk): Handle "same class name, different class loader."
844     // `equal` is always false for isEqualTo, but it varies for isSameInstanceAs:
845     boolean equal = difference.valuesAreEqual();
846 
847     if (equalityCheck == EqualityCheck.EQUAL
848         && (tryFailForTrailingWhitespaceOnly(expected) || tryFailForEmptyString(expected))) {
849       // tryFailForTrailingWhitespaceOnly or tryFailForEmptyString reported a failure, so we're done
850       return;
851     }
852 
853     if (sameToStrings) {
854       if (sameClassNames) {
855         String doppelgangerDescription =
856             equal
857                 ? "(different but equal instance of same class with same string representation)"
858                 : "(non-equal instance of same class with same string representation)";
859         failEqualityCheckNoComparisonFailure(
860             difference,
861             fact(equalityCheck.keyForExpected, expectedString),
862             fact("but was", doppelgangerDescription));
863       } else {
864         failEqualityCheckNoComparisonFailure(
865             difference,
866             fact(equalityCheck.keyForExpected, expectedString),
867             fact("an instance of", expectedClass),
868             fact("but was", "(non-equal value with same string representation)"),
869             fact("an instance of", actualClass));
870       }
871     } else {
872       if (equalityCheck == EqualityCheck.EQUAL && actual != null && expected != null) {
873         checkNotNull(metadata)
874             .failEqualityCheck(difference.factsOrEmpty(), expectedString, actualString);
875       } else {
876         failEqualityCheckNoComparisonFailure(
877             difference,
878             fact(equalityCheck.keyForExpected, expectedString),
879             fact("but was", actualString));
880       }
881     }
882   }
883 
884   /**
885    * Checks whether the actual and expected values are strings that match except for trailing
886    * whitespace. If so, reports a failure and returns true.
887    */
tryFailForTrailingWhitespaceOnly(@ullable Object expected)888   private boolean tryFailForTrailingWhitespaceOnly(@Nullable Object expected) {
889     if (!(actual instanceof String) || !(expected instanceof String)) {
890       return false;
891     }
892 
893     /*
894      * TODO(cpovirk): Consider applying this for non-String types. The danger there is that we don't
895      * know whether toString() (or actualCustomStringRepresentation/formatActualOrExpected) and
896      * equals() are consistent for those types.
897      */
898     String actualString = (String) actual;
899     String expectedString = (String) expected;
900     String actualNoTrailing = whitespace().trimTrailingFrom(actualString);
901     String expectedNoTrailing = whitespace().trimTrailingFrom(expectedString);
902     String expectedTrailing =
903         escapeWhitespace(expectedString.substring(expectedNoTrailing.length()));
904     String actualTrailing = escapeWhitespace(actualString.substring(actualNoTrailing.length()));
905 
906     if (!actualNoTrailing.equals(expectedNoTrailing)) {
907       return false;
908     }
909 
910     if (actualString.startsWith(expectedString)) {
911       failWithoutActual(
912           fact("expected", expectedString),
913           fact("but contained extra trailing whitespace", actualTrailing));
914     } else if (expectedString.startsWith(actualString)) {
915       failWithoutActual(
916           fact("expected", expectedString),
917           fact("but was missing trailing whitespace", expectedTrailing));
918     } else {
919       failWithoutActual(
920           fact("expected", expectedString),
921           fact("with trailing whitespace", expectedTrailing),
922           fact("but trailing whitespace was", actualTrailing));
923     }
924 
925     return true;
926   }
927 
escapeWhitespace(String in)928   private static String escapeWhitespace(String in) {
929     StringBuilder out = new StringBuilder();
930     for (char c : in.toCharArray()) {
931       out.append(escapeWhitespace(c));
932     }
933     return out.toString();
934   }
935 
escapeWhitespace(char c)936   private static String escapeWhitespace(char c) {
937     switch (c) {
938       case '\t':
939         return "\\t";
940       case '\n':
941         return "\\n";
942       case '\f':
943         return "\\f";
944       case '\r':
945         return "\\r";
946       case ' ':
947         return "␣";
948       default:
949         return new String(asUnicodeHexEscape(c));
950     }
951   }
952 
953   /**
954    * Checks whether the actual and expected values are empty strings. If so, reports a failure and
955    * returns true.
956    */
tryFailForEmptyString(@ullable Object expected)957   private boolean tryFailForEmptyString(@Nullable Object expected) {
958     if (!(actual instanceof String) || !(expected instanceof String)) {
959       return false;
960     }
961 
962     String actualString = (String) actual;
963     String expectedString = (String) expected;
964     if (actualString.isEmpty()) {
965       failWithoutActual(fact("expected", expectedString), simpleFact("but was an empty string"));
966       return true;
967     } else if (expectedString.isEmpty()) {
968       failWithoutActual(simpleFact("expected an empty string"), fact("but was", actualString));
969       return true;
970     }
971 
972     // Neither string was empty
973     return false;
974   }
975 
976   // From SourceCodeEscapers:
977 
978   private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
979 
asUnicodeHexEscape(char c)980   private static char[] asUnicodeHexEscape(char c) {
981     // Equivalent to String.format("\\u%04x", (int) c);
982     char[] r = new char[6];
983     r[0] = '\\';
984     r[1] = 'u';
985     r[5] = HEX_DIGITS[c & 0xF];
986     c = (char) (c >>> 4);
987     r[4] = HEX_DIGITS[c & 0xF];
988     c = (char) (c >>> 4);
989     r[3] = HEX_DIGITS[c & 0xF];
990     c = (char) (c >>> 4);
991     r[2] = HEX_DIGITS[c & 0xF];
992     return r;
993   }
994 
failEqualityCheckNoComparisonFailure(ComparisonResult difference, Fact... facts)995   private void failEqualityCheckNoComparisonFailure(ComparisonResult difference, Fact... facts) {
996     // TODO(cpovirk): Is it possible for difference.factsOrEmpty() to be nonempty? If not, remove.
997     doFail(concat(asList(facts), difference.factsOrEmpty()));
998   }
999 
1000   /**
1001    * Assembles a failure message and passes it to the FailureStrategy
1002    *
1003    * @param verb the check being asserted
1004    * @param expected the expectations against which the subject is compared
1005    * @param failVerb the failure of the check being asserted
1006    * @param actual the actual value the subject was compared against
1007    * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link
1008    *     #failWithActual(Fact, Fact...)}. However, if you want to preserve your exact failure
1009    *     message as a migration aid, you can inline this method.
1010    */
1011   @Deprecated
failWithBadResults(String verb, Object expected, String failVerb, Object actual)1012   final void failWithBadResults(String verb, Object expected, String failVerb, Object actual) {
1013     String message =
1014         lenientFormat(
1015             "Not true that <%s> %s <%s>. It %s <%s>",
1016             actualCustomStringRepresentation(),
1017             verb,
1018             expected,
1019             failVerb,
1020             (actual == null) ? "null reference" : actual);
1021     failWithoutActual(simpleFact(message));
1022   }
1023 
1024   /**
1025    * Assembles a failure message with an alternative representation of the wrapped subject and
1026    * passes it to the FailureStrategy
1027    *
1028    * @param verb the check being asserted
1029    * @param expected the expected value of the check
1030    * @param actual the custom representation of the subject to be reported in the failure.
1031    * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link
1032    *     #failWithoutActual(Fact, Fact...)}. However, if you want to preserve your exact failure
1033    *     message as a migration aid, you can inline this method.
1034    */
1035   @Deprecated
failWithCustomSubject(String verb, Object expected, Object actual)1036   final void failWithCustomSubject(String verb, Object expected, Object actual) {
1037     String message =
1038         lenientFormat(
1039             "Not true that <%s> %s <%s>",
1040             (actual == null) ? "null reference" : actual, verb, expected);
1041     failWithoutActual(simpleFact(message));
1042   }
1043 
1044   /**
1045    * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link
1046    *     #failWithoutActual(Fact, Fact...) failWithoutActual}{@code (}{@link Fact#simpleFact
1047    *     simpleFact(...)}{@code )}. However, if you want to preserve your exact failure message as a
1048    *     migration aid, you can inline this method.
1049    */
1050   @Deprecated
failWithoutSubject(String check)1051   final void failWithoutSubject(String check) {
1052     failWithoutActual(simpleFact(lenientFormat("Not true that the subject %s", check)));
1053   }
1054 
1055   /**
1056    * Fails, reporting a message with the given facts, <i>without automatically adding the actual
1057    * value.</i>
1058    *
1059    * <p>Most failure messages should report the actual value, so most checks should call {@link
1060    * #failWithActual(Fact, Fact...) failWithActual} instead. However, {@code failWithoutActual} is
1061    * useful in some cases:
1062    *
1063    * <ul>
1064    *   <li>when the actual value is obvious from the rest of the message. For example, {@code
1065    *       isNotEmpty()} calls {@code failWithoutActual(simpleFact("expected not to be empty")}.
1066    *   <li>when the actual value shouldn't come last or should have a different key than the default
1067    *       of "but was." For example, {@code isNotWithin(...).of(...)} calls {@code
1068    *       failWithoutActual} so that it can put the expected and actual values together, followed
1069    *       by the tolerance.
1070    * </ul>
1071    *
1072    * <p>Example usage: The check {@code isEmpty()} calls {@code failWithActual(simpleFact("expected
1073    * to be empty"))}.
1074    */
failWithoutActual(Fact first, Fact... rest)1075   protected final void failWithoutActual(Fact first, Fact... rest) {
1076     doFail(ImmutableList.copyOf(Lists.asList(first, rest)));
1077   }
1078 
1079   // TODO(cpovirk): Consider making this protected if there's a need for it.
failWithoutActual(Iterable<Fact> facts)1080   final void failWithoutActual(Iterable<Fact> facts) {
1081     doFail(ImmutableList.copyOf(facts));
1082   }
1083 
1084   /**
1085    * Assembles a failure message without a given subject and passes it to the FailureStrategy
1086    *
1087    * @param check the check being asserted
1088    * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link
1089    *     #failWithoutActual(Fact, Fact...) failWithoutActual}{@code (}{@link Fact#simpleFact
1090    *     simpleFact(...)}{@code )}. However, if you want to preserve your exact failure message as a
1091    *     migration aid, you can inline this method (and then inline the resulting method call, as
1092    *     well).
1093    */
1094   @Deprecated
failWithoutActual(String check)1095   final void failWithoutActual(String check) {
1096     failWithoutSubject(check);
1097   }
1098 
1099   /**
1100    * @throws UnsupportedOperationException always
1101    * @deprecated {@link Object#equals(Object)} is not supported on Truth subjects. If you are
1102    *     writing a test assertion (actual vs. expected), use {@link #isEqualTo(Object)} instead.
1103    */
1104   @DoNotCall(
1105       "Subject.equals() is not supported. Did you mean to call"
1106           + " assertThat(actual).isEqualTo(expected) instead of"
1107           + " assertThat(actual).equals(expected)?")
1108   @Deprecated
1109   @Override
equals(@ullable Object o)1110   public final boolean equals(@Nullable Object o) {
1111     throw new UnsupportedOperationException(
1112         "Subject.equals() is not supported. Did you mean to call"
1113             + " assertThat(actual).isEqualTo(expected) instead of"
1114             + " assertThat(actual).equals(expected)?");
1115   }
1116 
1117   /**
1118    * @throws UnsupportedOperationException always
1119    * @deprecated {@link Object#hashCode()} is not supported on Truth subjects.
1120    */
1121   @DoNotCall("Subject.hashCode() is not supported.")
1122   @Deprecated
1123   @Override
hashCode()1124   public final int hashCode() {
1125     throw new UnsupportedOperationException("Subject.hashCode() is not supported.");
1126   }
1127 
1128   /**
1129    * @throws UnsupportedOperationException always
1130    * @deprecated {@link Object#toString()} is not supported on Truth subjects.
1131    */
1132   @Deprecated
1133   @Override
1134   public
toString()1135   String toString() {
1136     throw new UnsupportedOperationException(
1137         "Subject.toString() is not supported. Did you mean to call assertThat(foo.toString())"
1138             + " instead of assertThat(foo).toString()?");
1139   }
1140 
1141   /**
1142    * Returns a "but was: <actual value>" string. This method should be rarely needed, since Truth
1143    * inserts a "but was" fact by default for assertions. However, it's occasionally useful for calls
1144    * to {@code failWithoutActual} that want a "but was" fact but don't want it to come last, where
1145    * Truth inserts it by default.
1146    */
1147   /*
1148    * TODO(cpovirk): Consider giving this protected access.
1149    *
1150    * It is likely better than what users would otherwise do -- `fact("but was", actual)`, which
1151    * ignores actualCustomStringRepresentation() (which is inaccessible outside the package).
1152    *
1153    * But I want to think more about this. In particular, if people use this to reimplement
1154    * isEqualTo(), I would be sad that they're missing out on its normal special handling. That's
1155    * probably not enough reason to avoid adding this, but we can hold it back for now.
1156    */
butWas()1157   final Fact butWas() {
1158     return fact("but was", actualCustomStringRepresentation());
1159   }
1160 
1161   /*
1162    * Computed lazily so that we're not doing expensive string operations during every assertion,
1163    * only during every failure.
1164    */
typeDescription()1165   final String typeDescription() {
1166     return typeDescriptionOrGuess(getClass(), typeDescriptionOverride);
1167   }
1168 
typeDescriptionOrGuess( Class<? extends Subject> clazz, @Nullable String typeDescriptionOverride)1169   private static String typeDescriptionOrGuess(
1170       Class<? extends Subject> clazz, @Nullable String typeDescriptionOverride) {
1171     if (typeDescriptionOverride != null) {
1172       return typeDescriptionOverride;
1173     }
1174     /*
1175      * j2cl doesn't store enough metadata to know whether "Foo$BarSubject" is a nested class, so it
1176      * can't tell whether the simple name is "Foo$BarSubject" or just "BarSubject": b/71808768. It
1177      * returns "Foo$BarSubject" to err on the side of preserving information. We want just
1178      * "BarSubject," so we strip any likely enclosing type ourselves.
1179      */
1180     String subjectClass = clazz.getSimpleName().replaceFirst(".*[$]", "");
1181     String actualClass =
1182         (subjectClass.endsWith("Subject") && !subjectClass.equals("Subject"))
1183             ? subjectClass.substring(0, subjectClass.length() - "Subject".length())
1184             : "Object";
1185     return UPPER_CAMEL.to(LOWER_CAMEL, actualClass);
1186   }
1187 
doFail(ImmutableList<Fact> facts)1188   private void doFail(ImmutableList<Fact> facts) {
1189     checkNotNull(metadata).fail(facts);
1190   }
1191 }
1192