• 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.Preconditions.checkNotNull;
19 import static com.google.common.base.Preconditions.checkState;
20 import static com.google.common.base.Verify.verifyNotNull;
21 import static com.google.common.truth.ComparisonFailures.makeComparisonFailureFacts;
22 import static com.google.common.truth.Fact.fact;
23 import static com.google.common.truth.LazyMessage.evaluateAll;
24 import static com.google.common.truth.Platform.cleanStackTrace;
25 import static com.google.common.truth.Platform.inferDescription;
26 import static com.google.common.truth.Platform.makeComparisonFailure;
27 import static com.google.common.truth.SubjectUtils.append;
28 import static com.google.common.truth.SubjectUtils.concat;
29 
30 import com.google.common.base.Function;
31 import com.google.common.collect.ImmutableList;
32 import org.checkerframework.checker.nullness.qual.Nullable;
33 
34 /**
35  * An opaque, immutable object containing state from the previous calls in the fluent assertion
36  * chain. It appears primarily as a parameter to {@link Subject} constructors (and {@link
37  * Subject.Factory} methods), which should pass it to the superclass constructor and not otherwise
38  * use or store it. In particular, users should not attempt to call {@code Subject} constructors or
39  * {@code Subject.Factory} methods directly. Instead, they should use the appropriate factory
40  * method:
41  *
42  * <ul>
43  *   <li>If you're writing a test: {@link Truth#assertAbout(Subject.Factory)}{@code .that(...)}
44  *   <li>If you're creating a derived subject from within another subject: {@code
45  *       check(...).about(...).that(...)}
46  *   <li>If you're testing your subject to verify that assertions fail when they should: {@link
47  *       ExpectFailure}
48  * </ul>
49  *
50  * <p>(One exception: Implementations of {@link CustomSubjectBuilder} do directly call constructors,
51  * using their {@link CustomSubjectBuilder#metadata()} method to get an instance to pass to the
52  * constructor.)
53  */
54 public final class FailureMetadata {
forFailureStrategy(FailureStrategy failureStrategy)55   static FailureMetadata forFailureStrategy(FailureStrategy failureStrategy) {
56     return new FailureMetadata(
57         failureStrategy, ImmutableList.<LazyMessage>of(), ImmutableList.<Step>of());
58   }
59 
60   private final FailureStrategy strategy;
61 
62   /**
63    * The data from a call to either (a) a {@link Subject} constructor or (b) {@link Subject#check}.
64    */
65   private static final class Step {
subjectCreation(Subject subject)66     static Step subjectCreation(Subject subject) {
67       return new Step(checkNotNull(subject), null, null);
68     }
69 
checkCall( OldAndNewValuesAreSimilar valuesAreSimilar, @Nullable Function<String, String> descriptionUpdate)70     static Step checkCall(
71         OldAndNewValuesAreSimilar valuesAreSimilar,
72         @Nullable Function<String, String> descriptionUpdate) {
73       return new Step(null, descriptionUpdate, valuesAreSimilar);
74     }
75 
76     /*
77      * We store Subject, rather than the actual value itself, so that we can call
78      * actualCustomStringRepresentation(). Why not call actualCustomStringRepresentation()
79      * immediately? First, it might be expensive, and second, the Subject isn't initialized at the
80      * time we receive it. We *might* be able to make it safe to call if it looks only at actual(),
81      * but it might try to look at facts initialized by a subclass, which aren't ready yet.
82      */
83     final @Nullable Subject subject;
84 
85     final @Nullable Function<String, String> descriptionUpdate;
86 
87     // Present only when descriptionUpdate is.
88     final @Nullable OldAndNewValuesAreSimilar valuesAreSimilar;
89 
Step( @ullable Subject subject, @Nullable Function<String, String> descriptionUpdate, @Nullable OldAndNewValuesAreSimilar valuesAreSimilar)90     private Step(
91         @Nullable Subject subject,
92         @Nullable Function<String, String> descriptionUpdate,
93         @Nullable OldAndNewValuesAreSimilar valuesAreSimilar) {
94       this.subject = subject;
95       this.descriptionUpdate = descriptionUpdate;
96       this.valuesAreSimilar = valuesAreSimilar;
97     }
98 
isCheckCall()99     boolean isCheckCall() {
100       return subject == null;
101     }
102   }
103 
104   /*
105    * TODO(cpovirk): This implementation is wasteful, especially because `steps` is used even by
106    * non-chaining assertions. If it ever does matter, we could use an immutable cactus stack -- or
107    * probably even avoid storing most of the chain entirely (unless we end up wanting more of the
108    * chain to show "telescoping context," as in "the int value of this optional in this list in this
109    * multimap").
110    */
111 
112   private final ImmutableList<LazyMessage> messages;
113 
114   private final ImmutableList<Step> steps;
115 
FailureMetadata( FailureStrategy strategy, ImmutableList<LazyMessage> messages, ImmutableList<Step> steps)116   FailureMetadata(
117       FailureStrategy strategy, ImmutableList<LazyMessage> messages, ImmutableList<Step> steps) {
118     this.strategy = checkNotNull(strategy);
119     this.messages = checkNotNull(messages);
120     this.steps = checkNotNull(steps);
121   }
122 
123   /**
124    * Returns a new instance that includes the given subject in its chain of values. Truth users do
125    * not need to call this method directly; Truth automatically accumulates context, starting from
126    * the initial that(...) call and continuing into any chained calls, like {@link
127    * ThrowableSubject#hasMessageThat}.
128    */
updateForSubject(Subject subject)129   FailureMetadata updateForSubject(Subject subject) {
130     ImmutableList<Step> steps = append(this.steps, Step.subjectCreation(subject));
131     return derive(messages, steps);
132   }
133 
updateForCheckCall()134   FailureMetadata updateForCheckCall() {
135     ImmutableList<Step> steps = append(this.steps, Step.checkCall(null, null));
136     return derive(messages, steps);
137   }
138 
updateForCheckCall( OldAndNewValuesAreSimilar valuesAreSimilar, Function<String, String> descriptionUpdate)139   FailureMetadata updateForCheckCall(
140       OldAndNewValuesAreSimilar valuesAreSimilar, Function<String, String> descriptionUpdate) {
141     checkNotNull(descriptionUpdate);
142     ImmutableList<Step> steps =
143         append(this.steps, Step.checkCall(valuesAreSimilar, descriptionUpdate));
144     return derive(messages, steps);
145   }
146 
147   /**
148    * Whether the value of the original subject and the value of the derived subject are "similar
149    * enough" that we don't need to display both. For example, if we're printing a message about the
150    * value of optional.get(), there's no need to print the optional itself because it adds no
151    * information. Similarly, if we're printing a message about the asList() view of an array,
152    * there's no need to also print the array.
153    */
154   enum OldAndNewValuesAreSimilar {
155     SIMILAR,
156     DIFFERENT;
157   }
158 
159   /**
160    * Returns a new instance whose failures will contain the given message. The way for Truth users
161    * to set a message is {@code check(...).withMessage(...).that(...)} (for calls from within a
162    * {@code Subject}) or {@link Truth#assertWithMessage} (for most other calls).
163    */
withMessage(String format, Object[] args)164   FailureMetadata withMessage(String format, /*@Nullable*/ Object[] args) {
165     ImmutableList<LazyMessage> messages = append(this.messages, new LazyMessage(format, args));
166     return derive(messages, steps);
167   }
168 
failEqualityCheck( ImmutableList<Fact> headFacts, ImmutableList<Fact> tailFacts, String expected, String actual)169   void failEqualityCheck(
170       ImmutableList<Fact> headFacts,
171       ImmutableList<Fact> tailFacts,
172       String expected,
173       String actual) {
174     doFail(
175         makeComparisonFailure(
176             evaluateAll(messages),
177             makeComparisonFailureFacts(
178                 concat(description(), headFacts),
179                 concat(tailFacts, rootUnlessThrowable()),
180                 expected,
181                 actual),
182             expected,
183             actual,
184             rootCause()));
185   }
186 
fail(ImmutableList<Fact> facts)187   void fail(ImmutableList<Fact> facts) {
188     doFail(
189         new AssertionErrorWithFacts(
190             evaluateAll(messages),
191             concat(description(), facts, rootUnlessThrowable()),
192             rootCause()));
193   }
194 
doFail(AssertionError failure)195   private void doFail(AssertionError failure) {
196     cleanStackTrace(failure);
197     strategy.fail(failure);
198   }
199 
derive(ImmutableList<LazyMessage> messages, ImmutableList<Step> steps)200   private FailureMetadata derive(ImmutableList<LazyMessage> messages, ImmutableList<Step> steps) {
201     return new FailureMetadata(strategy, messages, steps);
202   }
203 
204   /**
205    * Returns a description of the final actual value, if it appears "interesting" enough to show.
206    * The description is considered interesting if the chain of derived subjects ends with at least
207    * one derivation that we have a name for. It's also considered interesting in the absence of
208    * derived subjects if we inferred a name for the root actual value from the bytecode.
209    *
210    * <p>We don't want to say: "value of string: expected [foo] but was [bar]" (OK, we might still
211    * decide to say this, but for now, we don't.)
212    *
213    * <p>We do want to say: "value of throwable.getMessage(): expected [foo] but was [bar]"
214    *
215    * <p>We also want to say: "value of getLogMessages(): expected not to be empty"
216    *
217    * <p>To support that, {@code descriptionIsInteresting} tracks whether we've been given context
218    * through {@code check} calls <i>that include names</i> or, initially, whether we inferred a name
219    * for the root actual value from the bytecode.
220    *
221    * <p>If we're missing a naming function halfway through, we have to reset: We don't want to claim
222    * that the value is "foo.bar.baz" when it's "foo.bar.somethingelse.baz." We have to go back to
223    * "object.baz." (But note that {@link #rootUnlessThrowable} will still provide the value of the
224    * root foo to the user as long as we had at least one naming function: We might not know the
225    * root's exact relationship to the final object, but we know it's some object "different enough"
226    * to be worth displaying.)
227    */
description()228   private ImmutableList<Fact> description() {
229     String description = inferDescription();
230     boolean descriptionIsInteresting = description != null;
231     for (Step step : steps) {
232       if (step.isCheckCall()) {
233         checkState(description != null);
234         if (step.descriptionUpdate == null) {
235           description = null;
236           descriptionIsInteresting = false;
237         } else {
238           description = verifyNotNull(step.descriptionUpdate.apply(description));
239           descriptionIsInteresting = true;
240         }
241         continue;
242       }
243 
244       if (description == null) {
245         description = step.subject.typeDescription();
246       }
247     }
248     return descriptionIsInteresting
249         ? ImmutableList.of(fact("value of", description))
250         : ImmutableList.<Fact>of();
251   }
252 
253   /**
254    * Returns the root actual value, if we know it's "different enough" from the final actual value.
255    *
256    * <p>We don't want to say: "expected [foo] but was [bar]. string: [bar]"
257    *
258    * <p>We do want to say: "expected [foo] but was [bar]. myObject: MyObject[string=bar, i=0]"
259    *
260    * <p>To support that, {@code seenDerivation} tracks whether we've seen multiple actual values,
261    * which is equivalent to whether we've seen multiple Subject instances or, more informally,
262    * whether the user is making a chained assertion.
263    *
264    * <p>There's one wrinkle: Sometimes chaining doesn't add information. This is often true with
265    * "internal" chaining, like when StreamSubject internally creates an IterableSubject to delegate
266    * to. The two subjects' string representations will be identical (or, in some cases, _almost_
267    * identical), so there is no value in showing both. In such cases, implementations can call the
268    * no-arg {@code checkNoNeedToDisplayBothValues()}, which sets {@code valuesAreSimilar},
269    * instructing this method that that particular chain link "doesn't count." (Note also that there
270    * are some edge cases that we're not sure how to handle yet, for which we might introduce
271    * additional {@code check}-like methods someday.)
272    */
273   // TODO(b/134505914): Consider returning multiple facts in some cases.
rootUnlessThrowable()274   private ImmutableList<Fact> rootUnlessThrowable() {
275     Step rootSubject = null;
276     boolean seenDerivation = false;
277     for (Step step : steps) {
278       if (step.isCheckCall()) {
279         /*
280          * If we don't have a description update, don't trigger display of a root object. (If we
281          * did, we'd change the messages of a bunch of existing subjects, and we don't want to bite
282          * that off yet.)
283          *
284          * If we do have a description update, then trigger display of a root object but only if the
285          * old and new values are "different enough" to be worth both displaying.
286          */
287         seenDerivation |=
288             step.descriptionUpdate != null
289                 && step.valuesAreSimilar == OldAndNewValuesAreSimilar.DIFFERENT;
290         continue;
291       }
292 
293       if (rootSubject == null) {
294         if (step.subject.actual() instanceof Throwable) {
295           /*
296            * We'll already include the Throwable as a cause of the AssertionError (see rootCause()),
297            * so we don't need to include it again in the message.
298            */
299           return ImmutableList.of();
300         }
301         rootSubject = step;
302       }
303     }
304     /*
305      * TODO(cpovirk): Maybe say "root foo was: ..." instead of just "foo was: ..." if there's more
306      * than one foo in the chain, if the description string doesn't start with "foo," and/or if the
307      * name we have is just "object?"
308      */
309     return seenDerivation
310         ? ImmutableList.of(
311             fact(
312                 // TODO(cpovirk): Use inferDescription() here when appropriate? But it can be long.
313                 rootSubject.subject.typeDescription() + " was",
314                 rootSubject.subject.actualCustomStringRepresentationForPackageMembersToCall()))
315         : ImmutableList.<Fact>of();
316   }
317 
318   /**
319    * Returns the first {@link Throwable} in the chain of actual values. Typically, we'll have a root
320    * cause only if the assertion chain contains a {@link ThrowableSubject}.
321    */
rootCause()322   private @Nullable Throwable rootCause() {
323     for (Step step : steps) {
324       if (!step.isCheckCall() && step.subject.actual() instanceof Throwable) {
325         return (Throwable) step.subject.actual();
326       }
327     }
328     return null;
329   }
330 }
331