Skip to content

Commit

Permalink
Copy the *Verb* types to *SubjectBuilder*, and deprecate the old types.
Browse files Browse the repository at this point in the history
Additionally, make TestVerb (now StandardSubjectBuilder) and its supertypes non-extensible.
Finally, add a bunch of docs.
This CL leaves SubjectFactory as a top-level type (and introduces CustomSubjectBuilderFactory as a top-level type). This is so that I can introduce the nested types with a different parameter type ("FailureBuilder" or something like that) as part of a later step.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=166715211
  • Loading branch information
cpovirk committed Aug 28, 2017
1 parent d0f6c5c commit f82a6b7
Show file tree
Hide file tree
Showing 23 changed files with 973 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
* {@link AbstractDelegatedVerb}.
*
* <p>For an example implementation and usage, see {@link DelegatedVerbFactoryTest}.
*
* @deprecated This class is being renamed to {@link CustomSubjectBuilder}.
*/
@Deprecated
public abstract class AbstractDelegatedVerb {
protected AbstractDelegatedVerb() {}

Expand Down
39 changes: 31 additions & 8 deletions core/src/main/java/com/google/common/truth/AbstractVerb.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@
import javax.annotation.Nullable;

/*>>>import org.checkerframework.checker.nullness.compatqual.NullableType;*/
/** A parent type for some infrastructure used in the Verb. */
/**
* A parent type for some infrastructure used in the Verb.
*
* @deprecated Instead of subclassing {@code AbstractVerb}, subclass {@link CustomSubjectBuilder}.
* {@code CustomSubjectBuilder} is the new way of defining custom {@code that()} methods, and it
* doesn't require you to write boilerplate to store and propagate the failure message.
*/
// TODO(cgruber) Remove the FailureMessageHolder inheritance and restructure to simplify verbs.
@Deprecated
public abstract class AbstractVerb<T extends AbstractVerb<T>> extends FailureContext {
private final FailureStrategy failureStrategy;

Expand All @@ -48,12 +55,12 @@ protected FailureStrategy getFailureStrategy() {
}

/** Triggers the failure strategy with an empty failure message */
public final void fail() {
public void fail() {
getFailureStrategy().fail("");
}

/** Triggers the failure strategy with the given failure message */
public final void fail(@Nullable String format, Object /*@NullableType*/... args) {
public void fail(@Nullable String format, Object /*@NullableType*/... args) {
getFailureStrategy().fail(format(format, args));
}

Expand Down Expand Up @@ -87,8 +94,8 @@ public final void fail(@Nullable String format, Object /*@NullableType*/... args
* @param factory a {@code SubjectFactory<S, D>} implementation
* @return A custom verb for the type returned by the SubjectFactory
*/
public final <S extends Subject<S, D>, D, SF extends SubjectFactory<S, D>>
DelegatedVerb<S, D> about(SF factory) {
public <S extends Subject<S, D>, D, SF extends SubjectFactory<S, D>> DelegatedVerb<S, D> about(
SF factory) {
return new DelegatedVerb<S, D>(getFailureStrategy(), factory);
}

Expand All @@ -99,14 +106,23 @@ DelegatedVerb<S, D> about(SF factory) {
* @param <V> the type of {@link AbstractDelegatedVerb} to return
* @param factory a {@code DelegatedVerbFactory<V>} implementation
* @return A custom verb of type {@code <V>}
* @deprecated When you switch from implementing {@link DelegatedVerbFactory} to implementing
* {@link CustomSubjectBuilderFactory}, you'll switch from this overload to {@linkplain
* #about(CustomSubjectBuilderFactory) the overload} that accepts a {@code
* CustomSubjectBuilderFactory}.
*/
@Deprecated
public final <V extends AbstractDelegatedVerb> V about(DelegatedVerbFactory<V> factory) {
return factory.createVerb(getFailureStrategy());
}

/** A special Verb implementation which wraps a SubjectFactory */
public static final class DelegatedVerb<S extends Subject<S, T>, T>
extends AbstractDelegatedVerb {
/**
* A special Verb implementation which wraps a SubjectFactory.
*
* @deprecated This class is being renamed to {@link SimpleSubjectBuilder}.
*/
@Deprecated
public static class DelegatedVerb<S extends Subject<S, T>, T> extends AbstractDelegatedVerb {
private final FailureStrategy failureStrategy;
private final SubjectFactory<S, T> subjectFactory;

Expand Down Expand Up @@ -134,6 +150,13 @@ public S that(@Nullable T target) {
}
}

/**
* @deprecated To prepend a message, use {@link StandardSubjectBuilder#withMessage}. If you are
* using {@code MessagePrependingFailureStrategy} to store and propagate the failure message
* as part of subclassing {@link AbstractVerb} or {@link TestVerb}, you will no longer need it
* when you migrate off those classes, as described in their deprecation text.
*/
@Deprecated
protected static final class MessagePrependingFailureStrategy extends FailureStrategy {
private final FailureStrategy delegate;
private final FailureContext messageHolder;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2016 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.common.truth;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* In a fluent assertion chain, exposes one or more "custom" {@code that} methods, which accept a
* value under test and return a {@link Subject}.
*
* <p>(Note that the "custom" {@code that} methods are not defined on {@code CustomSubjectBuilder}
* itself, only on its subtypes, which are the types users actually interact with.)
*
* <p>TODO(cpovirk): Link to a doc about the full assertion chain.
*
* <h2>For people extending Truth</h2>
*
* <p>TODO(cpovirk): Link to a doc about custom subjects.
*/
public abstract class CustomSubjectBuilder {
private final FailureStrategy failureStrategy;

protected CustomSubjectBuilder(FailureStrategy failureStrategy) {
this.failureStrategy = checkNotNull(failureStrategy);
}

protected final FailureStrategy failureStrategy() {
return failureStrategy;
}

// TODO(user,cgruber): Better enforce that subclasses implement a that() method.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2016 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.common.truth;

/**
* In a fluent assertion chain, the argument to the "custom" overload of {@link
* StandardSubjectBuilder#about(CustomSubjectBuilderFactory) about}, the method that specifies what
* kind of {@link Subject} to create.
*
* <p>TODO(cpovirk): Link to a doc about the full assertion chain.
*
* <h2>For people extending Truth</h2>
*
* <p>TODO(cpovirk): Link to a doc about custom subjects.
*/
// TODO(cpovirk): Convert to a nested type when changing FailureStrategy parameter to another type.
public interface CustomSubjectBuilderFactory<CustomSubjectBuilderT extends CustomSubjectBuilder> {
/** Creates a new {@link CustomSubjectBuilder} of the appropriate type. */
CustomSubjectBuilderT createSubjectBuilder(FailureStrategy failureStrategy);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
* are too strict - for example, if your custom {@link Subject} is parameterized, and you want to
* infer the parameter type from the test object. See {@link DelegatedVerbFactoryTest} for an
* example implementation.
*
* @deprecated This class is being renamed to {@link CustomSubjectBuilderFactory}.
*/
@Deprecated
public interface DelegatedVerbFactory<V extends AbstractDelegatedVerb> {
/** Instantiates a new V with {@code failureStrategy} and itself. */
V createVerb(FailureStrategy failureStrategy);
Expand Down
46 changes: 31 additions & 15 deletions core/src/main/java/com/google/common/truth/Expect.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.google.common.truth;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Throwables.getStackTraceAsString;
import static com.google.common.truth.StringUtil.messageFor;

Expand All @@ -29,14 +30,32 @@
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

/**
* A {@link TestRule} that batches up all failures encountered during a test, and reports them all
* together at the end.
*
* <p>Usage:
*
* <pre>
* {@code @Rule public final Expect expect = Expect.create();}
*
* {@code ...}
*
* {@code expect.that(results).containsExactly(...);}
* {@code expect.that(errors).isEmpty();}
* </pre>
*
* If both of the assertions above fail, the test will fail with an exception that contains
* information about both.
*/
@GwtIncompatible("JUnit4")
public final class Expect extends TestVerb implements TestRule {
public final class Expect extends StandardSubjectBuilder implements TestRule {
/**
* @deprecated To provide your own failure handling, use {@code new TestVerb(new
* AbstractFailureStrategy() { ... })} instead of {@code Expect.create(new
* ExpectationGatherer() { ... })}. Or, if you're testing that assertions on a custom {@code
* Subject} fail (using {@code ExpectationGatherer} to capture the failures), use {@link
* ExpectFailure}.
* @deprecated To provide your own failure handling, use {@code
* StandardSubjectBuilder.forCustomFailureStrategy(new AbstractFailureStrategy() { ... })}
* instead of {@code Expect.create(new ExpectationGatherer() { ... })}. Or, if you're testing
* that assertions on a custom {@code Subject} fail (using {@code ExpectationGatherer} to
* capture the failures), use {@link ExpectFailure}.
*/
@Deprecated
public static class ExpectationGatherer extends AbstractFailureStrategy {
Expand Down Expand Up @@ -132,9 +151,9 @@ public static Expect create() {
}

/**
* @deprecated To provide your own failure handling, use {@code new TestVerb(new
* AbstractFailureStrategy() { ... })} instead of {@code Expect.create(new
* ExpectationGatherer() { ... })}.
* @deprecated To provide your own failure handling, use {@code
* StandardSubjectBuilder.forCustomFailureStrategy(new AbstractFailureStrategy() { ... })}
* instead of {@code Expect.create(new ExpectationGatherer() { ... })}.
*/
@Deprecated
public static Expect create(ExpectationGatherer gatherer) {
Expand All @@ -155,12 +174,9 @@ public boolean hasFailures() {
}

@Override
protected FailureStrategy getFailureStrategy() {
if (!inRuleContext) {
String message = "assertion made on Expect instance, but it's not enabled as a @Rule.";
throw new IllegalStateException(message);
}
return super.getFailureStrategy();
void checkStatePreconditions() {
checkState(
inRuleContext, "assertion made on Expect instance, but it's not enabled as a @Rule.");
}

@Override
Expand Down
Loading

0 comments on commit f82a6b7

Please sign in to comment.