aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-10 15:44:26 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-10 15:44:26 +0000
commita54b304d31fecdc2729b4389866f4137f42e6ba0 (patch)
tree20fc4a42f3e1b8f013e6c8e3a0d6b54a66c6bdb1
parentc70dd0ed46f8cd76c73c0812f365151720c1b0fa (diff)
parent4a335f05967d42e34ba9d90179fe505290a241c4 (diff)
downloadtruth-busytown-mac-infra-release.tar.gz
Snap for 11819167 from 4a335f05967d42e34ba9d90179fe505290a241c4 to busytown-mac-infra-releasebusytown-mac-infra-release
Change-Id: Icd5a2e2e56dfa2a2537dd279cebeddab1ef395f6
-rw-r--r--.github/workflows/ci.yml23
-rw-r--r--Android.bp23
-rw-r--r--METADATA4
-rw-r--r--core/pom.xml95
-rw-r--r--core/src/main/java/com/google/common/truth/AbstractArraySubject.java7
-rw-r--r--core/src/main/java/com/google/common/truth/ActualValueInference.java77
-rw-r--r--core/src/main/java/com/google/common/truth/AssertionErrorWithFacts.java4
-rw-r--r--core/src/main/java/com/google/common/truth/BigDecimalSubject.java9
-rw-r--r--core/src/main/java/com/google/common/truth/BooleanSubject.java2
-rw-r--r--core/src/main/java/com/google/common/truth/ClassSubject.java7
-rw-r--r--core/src/main/java/com/google/common/truth/ComparableSubject.java36
-rw-r--r--core/src/main/java/com/google/common/truth/ComparisonFailureWithFacts.java1
-rw-r--r--core/src/main/java/com/google/common/truth/Correspondence.java81
-rw-r--r--core/src/main/java/com/google/common/truth/CustomSubjectBuilder.java3
-rw-r--r--core/src/main/java/com/google/common/truth/DiffUtils.java6
-rw-r--r--core/src/main/java/com/google/common/truth/DoubleSubject.java8
-rw-r--r--core/src/main/java/com/google/common/truth/Expect.java13
-rw-r--r--core/src/main/java/com/google/common/truth/ExpectFailure.java29
-rw-r--r--core/src/main/java/com/google/common/truth/Fact.java2
-rw-r--r--core/src/main/java/com/google/common/truth/FailureMetadata.java21
-rw-r--r--core/src/main/java/com/google/common/truth/FailureStrategy.java1
-rw-r--r--core/src/main/java/com/google/common/truth/FloatSubject.java8
-rw-r--r--core/src/main/java/com/google/common/truth/GraphMatching.java10
-rw-r--r--core/src/main/java/com/google/common/truth/GuavaOptionalSubject.java4
-rw-r--r--core/src/main/java/com/google/common/truth/IntegerSubject.java6
-rw-r--r--core/src/main/java/com/google/common/truth/IterableSubject.java264
-rw-r--r--core/src/main/java/com/google/common/truth/J2ktIncompatible.java30
-rw-r--r--core/src/main/java/com/google/common/truth/LazyMessage.java15
-rw-r--r--core/src/main/java/com/google/common/truth/LongSubject.java6
-rw-r--r--core/src/main/java/com/google/common/truth/MapSubject.java158
-rw-r--r--core/src/main/java/com/google/common/truth/MultimapSubject.java164
-rw-r--r--core/src/main/java/com/google/common/truth/MultisetSubject.java5
-rw-r--r--core/src/main/java/com/google/common/truth/ObjectArraySubject.java10
-rw-r--r--core/src/main/java/com/google/common/truth/Ordered.java1
-rw-r--r--core/src/main/java/com/google/common/truth/Platform.java84
-rw-r--r--core/src/main/java/com/google/common/truth/PrimitiveBooleanArraySubject.java8
-rw-r--r--core/src/main/java/com/google/common/truth/PrimitiveByteArraySubject.java8
-rw-r--r--core/src/main/java/com/google/common/truth/PrimitiveCharArraySubject.java8
-rw-r--r--core/src/main/java/com/google/common/truth/PrimitiveDoubleArraySubject.java14
-rw-r--r--core/src/main/java/com/google/common/truth/PrimitiveFloatArraySubject.java14
-rw-r--r--core/src/main/java/com/google/common/truth/PrimitiveIntArraySubject.java8
-rw-r--r--core/src/main/java/com/google/common/truth/PrimitiveLongArraySubject.java8
-rw-r--r--core/src/main/java/com/google/common/truth/PrimitiveShortArraySubject.java8
-rw-r--r--core/src/main/java/com/google/common/truth/SimpleSubjectBuilder.java1
-rw-r--r--core/src/main/java/com/google/common/truth/StackTraceCleaner.java28
-rw-r--r--core/src/main/java/com/google/common/truth/StandardSubjectBuilder.java25
-rw-r--r--core/src/main/java/com/google/common/truth/StringSubject.java66
-rw-r--r--core/src/main/java/com/google/common/truth/Subject.java190
-rw-r--r--core/src/main/java/com/google/common/truth/SubjectUtils.java57
-rw-r--r--core/src/main/java/com/google/common/truth/TableSubject.java49
-rw-r--r--core/src/main/java/com/google/common/truth/ThrowableSubject.java9
-rw-r--r--core/src/main/java/com/google/common/truth/Truth.gwt.xml33
-rw-r--r--core/src/main/java/com/google/common/truth/Truth.java48
-rw-r--r--core/src/main/java/com/google/common/truth/TruthFailureSubject.java9
-rw-r--r--core/src/main/java/com/google/common/truth/TruthJUnit.java31
-rw-r--r--core/src/main/java/com/google/common/truth/UsedByReflection.java25
-rw-r--r--core/src/main/java/com/google/common/truth/super/com/google/common/truth/Platform.java78
-rw-r--r--core/src/test/java/com/google/common/truth/ActualValueInferenceTest.java37
-rw-r--r--core/src/test/java/com/google/common/truth/ChainingTest.java1
-rw-r--r--core/src/test/java/com/google/common/truth/ComparableSubjectCompileTest.java97
-rw-r--r--core/src/test/java/com/google/common/truth/ComparableSubjectTest.java11
-rw-r--r--core/src/test/java/com/google/common/truth/CorrespondenceExceptionStoreTest.java3
-rw-r--r--core/src/test/java/com/google/common/truth/CorrespondenceTest.java102
-rw-r--r--core/src/test/java/com/google/common/truth/CustomFailureMessageTest.java1
-rw-r--r--core/src/test/java/com/google/common/truth/DoubleSubjectTest.java26
-rw-r--r--core/src/test/java/com/google/common/truth/ExpectFailureNonRuleTest.java4
-rw-r--r--core/src/test/java/com/google/common/truth/ExpectFailureRuleTest.java2
-rw-r--r--core/src/test/java/com/google/common/truth/ExpectFailureWithStackTraceTest.java2
-rw-r--r--core/src/test/java/com/google/common/truth/ExpectTest.java66
-rw-r--r--core/src/test/java/com/google/common/truth/ExpectWithStackTest.java10
-rw-r--r--core/src/test/java/com/google/common/truth/FloatSubjectTest.java22
-rw-r--r--core/src/test/java/com/google/common/truth/IntegerSubjectTest.java4
-rw-r--r--core/src/test/java/com/google/common/truth/IterableSubjectCorrespondenceTest.java319
-rw-r--r--core/src/test/java/com/google/common/truth/IterableSubjectTest.java147
-rw-r--r--core/src/test/java/com/google/common/truth/MapSubjectTest.java12
-rw-r--r--core/src/test/java/com/google/common/truth/MathUtilTest.java2
-rw-r--r--core/src/test/java/com/google/common/truth/ObjectArraySubjectTest.java42
-rw-r--r--core/src/test/java/com/google/common/truth/StackTraceCleanerJUnit3Test.java36
-rw-r--r--core/src/test/java/com/google/common/truth/StackTraceCleanerTest.java5
-rw-r--r--core/src/test/java/com/google/common/truth/StringSubjectTest.java4
-rw-r--r--core/src/test/java/com/google/common/truth/SubjectTest.java69
-rw-r--r--core/src/test/java/com/google/common/truth/TableSubjectTest.java29
-rw-r--r--core/src/test/java/com/google/common/truth/TestCorrespondences.java186
-rw-r--r--core/src/test/java/com/google/common/truth/TruthAssertThatTest.java39
-rw-r--r--core/src/test/java/com/google/common/truth/TruthFailureSubjectTest.java4
-rw-r--r--core/src/test/java/com/google/common/truth/extension/EmployeeSubject.java39
-rw-r--r--core/src/test/java/com/google/common/truth/extension/EmployeeSubjectTest.java3
-rw-r--r--core/src/test/java/com/google/common/truth/gwt/Inventory.java6
-rw-r--r--core/src/test/java/com/google/common/truth/gwt/TruthGwtTest.java5
-rw-r--r--extensions/java8/pom.xml13
-rw-r--r--extensions/java8/src/main/java/com/google/common/truth/IntStreamSubject.java3
-rw-r--r--extensions/java8/src/main/java/com/google/common/truth/LongStreamSubject.java3
-rw-r--r--extensions/java8/src/main/java/com/google/common/truth/OptionalSubject.java4
-rw-r--r--extensions/java8/src/main/java/com/google/common/truth/StreamSubject.java39
-rw-r--r--extensions/java8/src/main/java/com/google/common/truth/Truth8.gwt.xml33
-rw-r--r--extensions/java8/src/main/java/com/google/common/truth/Truth8.java1
-rw-r--r--extensions/java8/src/test/java/com/google/common/truth/IntStreamSubjectTest.java98
-rw-r--r--extensions/java8/src/test/java/com/google/common/truth/LongStreamSubjectTest.java98
-rw-r--r--extensions/java8/src/test/java/com/google/common/truth/StreamSubjectTest.java129
-rw-r--r--extensions/liteproto/pom.xml9
-rw-r--r--extensions/liteproto/src/main/java/com/google/common/truth/extensions/proto/LiteProtoSubject.java31
-rw-r--r--extensions/liteproto/src/test/java/com/google/common/truth/extensions/proto/LiteProtoSubjectTest.java154
-rw-r--r--extensions/proto/pom.xml9
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/DiffResult.java162
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldDescriptorValidator.java6
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldScopeUtil.java29
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FluentEqualityConfig.java10
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosSubject.java41
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosUsingCorrespondence.java8
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesFluentAssertion.java2
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesSubject.java3
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesFluentAssertion.java2
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesSubject.java22
-rw-r--r--extensions/proto/src/main/java/com/google/common/truth/extensions/proto/ProtoTruthMessageDifferencer.java35
-rw-r--r--extensions/proto/src/test/java/com/google/common/truth/extensions/proto/IterableOfProtosSubjectTest.java18
-rw-r--r--extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTest.java101
-rw-r--r--extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTestBase.java6
-rw-r--r--extensions/re2j/pom.xml11
-rw-r--r--extensions/re2j/src/main/java/com/google/common/truth/extensions/re2j/Re2jSubjects.java28
-rw-r--r--pom.xml222
-rw-r--r--refactorings/src/main/java/com/google/common/truth/refactorings/CorrespondenceSubclassToFactoryCall.java32
-rw-r--r--refactorings/src/main/java/com/google/common/truth/refactorings/FailWithFacts.java3
-rw-r--r--refactorings/src/main/java/com/google/common/truth/refactorings/NamedToWithMessage.java268
-rw-r--r--refactorings/src/main/java/com/google/common/truth/refactorings/StoreActualValueInField.java281
-rwxr-xr-xutil/generate-latest-docs.sh4
-rwxr-xr-xutil/mvn-deploy.sh53
126 files changed, 2604 insertions, 2644 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0b3b3e8b..eb5ec20a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,20 +18,20 @@ jobs:
steps:
# Cancel any previous runs for the same branch that are still running.
- name: 'Cancel previous runs'
- uses: styfle/cancel-workflow-action@0.9.0
+ uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5
with:
access_token: ${{ github.token }}
- name: 'Check out repository'
- uses: actions/checkout@v2
+ uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
- name: 'Cache local Maven repository'
- uses: actions/cache@v2.1.5
+ uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
with:
path: ~/.m2/repository
key: maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
maven-
- name: 'Set up JDK ${{ matrix.java }}'
- uses: actions/setup-java@v2
+ uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2
with:
java-version: ${{ matrix.java }}
distribution: 'zulu'
@@ -41,6 +41,9 @@ jobs:
- name: 'Test'
shell: bash
run: mvn -B -P!standard-with-extra-repos verify -U -Dmaven.javadoc.skip=true
+ - name: 'Javadoc Test Run'
+ shell: bash
+ run: mvn -B -P!standard-with-extra-repos javadoc:aggregate -U
publish_snapshot:
name: 'Publish snapshot'
@@ -49,16 +52,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Check out repository'
- uses: actions/checkout@v2
+ uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
- name: 'Cache local Maven repository'
- uses: actions/cache@v2.1.5
+ uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
with:
path: ~/.m2/repository
key: maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
maven-
- name: 'Set up JDK 11'
- uses: actions/setup-java@v2
+ uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2
with:
java-version: 11
distribution: 'zulu'
@@ -78,16 +81,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Check out repository'
- uses: actions/checkout@v2
+ uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
- name: 'Cache local Maven repository'
- uses: actions/cache@v2.1.5
+ uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
with:
path: ~/.m2/repository
key: maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
maven-
- name: 'Set up JDK 11'
- uses: actions/setup-java@v2
+ uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2
with:
java-version: 11
distribution: 'zulu'
diff --git a/Android.bp b/Android.bp
index 79a37634..bccc4fc8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -78,7 +78,6 @@ java_library {
sdk_version: "current",
}
-
java_library {
name: "truth-liteproto-extension",
host_supported: true,
@@ -95,3 +94,25 @@ java_library {
],
sdk_version: "current",
}
+
+java_library_host {
+ name: "truth-proto-extension",
+ srcs: ["extensions/proto/src/main/java/**/*.java"],
+ libs: [
+ "auto_value_annotations",
+ "auto_value_memoized_extension_annotations",
+ "error_prone_annotations",
+ "guava-android-annotation-stubs",
+ "truth",
+ "truth-liteproto-extension",
+ ],
+ plugins: [
+ "auto_oneof_plugin",
+ "auto_value_memoized_extension_plugin",
+ "auto_value_plugin",
+ ],
+ static_libs: [
+ "guava",
+ "libprotobuf-java-full",
+ ],
+}
diff --git a/METADATA b/METADATA
index 483212f2..4f40f8fa 100644
--- a/METADATA
+++ b/METADATA
@@ -11,7 +11,7 @@ third_party {
type: GIT
value: "https://github.com/google/truth.git"
}
- version: "release_1_1_3"
- last_upgrade_date { year: 2022 month: 10 day: 13 }
+ version: "v1.1.5"
+ last_upgrade_date { year: 2023 month: 10 day: 7 }
license_type: NOTICE
}
diff --git a/core/pom.xml b/core/pom.xml
index f600f1c7..2afd00e5 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -43,11 +43,6 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.google.testing.compile</groupId>
- <artifactId>compile-testing</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
</dependency>
@@ -66,6 +61,13 @@
<exclude>**/*.gwt.xml</exclude>
</excludes>
</resource>
+ <resource>
+ <directory>..</directory>
+ <includes>
+ <include>LICENSE</include>
+ </includes>
+ <targetPath>META-INF</targetPath>
+ </resource>
</resources>
<testResources>
<testResource><directory>src/test/java</directory></testResource>
@@ -110,18 +112,7 @@
<goals><goal>jar</goal></goals>
<configuration>
<classifier>gwt</classifier>
- <classesDirectory>src/main/java</classesDirectory>
- <includes>
- <include>**/*.java</include>
- <include>**/*.gwt.xml</include>
- </includes>
- <excludes>
- <exclude>com/google/common/truth/ClassSubject.java</exclude>
- <exclude>com/google/common/truth/Expect.java</exclude>
- <exclude>com/google/common/truth/IteratingVerb.java</exclude>
- <exclude>com/google/common/truth/ReflectionUtil.java</exclude>
- <exclude>com/google/common/truth/codegen/**</exclude>
- </excludes>
+ <classesDirectory>${project.build.directory}/gwt-sources</classesDirectory>
</configuration>
</execution>
</executions>
@@ -161,6 +152,74 @@
</execution>
</executions>
</plugin>
+ <!-- We need to strip "@Nullable" from the sources that we hand to GWT:
+ b/183648616. To do that, we have to make a copy of the original
+ source directory and add that directory as a Maven source root. But
+ the added root comes *after* the original root, so, in order to make
+ GWT choose those sources in preference to the originals, we need to
+ put them in a `super` directory.
+
+ TODO(b/183648616): Once we can use @Nullable from GWT, generate the
+ GWT jar from the original sources instead of these sources that we
+ strip @Nullable from. -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>3.4.0</version>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>${project.build.directory}/gwt-sources</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>3.1.0</version>
+ <executions>
+ <execution>
+ <id>copy-gwt-files</id>
+ <phase>generate-sources</phase>
+ <goals><goal>run</goal></goals>
+ <configuration>
+ <target name="copy-gwt-resources">
+ <copy toDir="${project.build.directory}/gwt-sources">
+ <fileset dir="${project.basedir}/src/main/java">
+ <include name="**/super/**/*.java"/>
+ <include name="**/*.gwt.xml"/>
+ </fileset>
+ </copy>
+ <copy toDir="${project.build.directory}/gwt-sources/com/google/common/truth/super">
+ <fileset dir="${project.basedir}/src/main/java">
+ <!-- Don't put files under .../super/.../super/... -->
+ <exclude name="**/super/**/*.java"/>
+ <!-- Don't put the .gwt.xml under super -->
+ <exclude name="**/*.gwt.xml"/>
+ </fileset>
+ </copy>
+ <replace token="@Nullable" value="">
+ <fileset dir="${project.build.directory}/gwt-sources">
+ <include name="**/super/**/*.java"/>
+ </fileset>
+ </replace>
+ <replace token="@NonNull" value="">
+ <fileset dir="${project.build.directory}/gwt-sources">
+ <include name="**/super/**/*.java"/>
+ </fileset>
+ </replace>
+ </target>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
<reporting>
@@ -168,7 +227,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
- <version>3.1.2</version>
+ <version>3.4.5</version>
</plugin>
</plugins>
</reporting>
diff --git a/core/src/main/java/com/google/common/truth/AbstractArraySubject.java b/core/src/main/java/com/google/common/truth/AbstractArraySubject.java
index a0cd2fdc..8eff47a1 100644
--- a/core/src/main/java/com/google/common/truth/AbstractArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/AbstractArraySubject.java
@@ -16,6 +16,7 @@
package com.google.common.truth;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.truth.Fact.simpleFact;
import java.lang.reflect.Array;
@@ -27,7 +28,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
abstract class AbstractArraySubject extends Subject {
- private final Object actual;
+ private final @Nullable Object actual;
AbstractArraySubject(
FailureMetadata metadata, @Nullable Object actual, @Nullable String typeDescription) {
@@ -55,11 +56,11 @@ abstract class AbstractArraySubject extends Subject {
* @throws IllegalArgumentException if {@code length < 0}
*/
public final void hasLength(int length) {
- checkArgument(length >= 0, "length (%s) must be >= 0");
+ checkArgument(length >= 0, "length (%s) must be >= 0", length);
check("length").that(length()).isEqualTo(length);
}
private int length() {
- return Array.getLength(actual);
+ return Array.getLength(checkNotNull(actual));
}
}
diff --git a/core/src/main/java/com/google/common/truth/ActualValueInference.java b/core/src/main/java/com/google/common/truth/ActualValueInference.java
index 5959bb60..db49c1da 100644
--- a/core/src/main/java/com/google/common/truth/ActualValueInference.java
+++ b/core/src/main/java/com/google/common/truth/ActualValueInference.java
@@ -15,6 +15,7 @@ package com.google.common.truth;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
import static java.lang.Thread.currentThread;
@@ -25,12 +26,14 @@ import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import org.objectweb.asm.Opcodes;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.errorprone.annotations.CheckReturnValue;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Map.Entry;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Handle;
@@ -65,9 +68,10 @@ import org.objectweb.asm.Type;
* this is all best-effort.
*/
@GwtIncompatible
+@J2ktIncompatible
final class ActualValueInference {
/** <b>Call {@link Platform#inferDescription} rather than calling this directly.</b> */
- static String describeActualValue(String className, String methodName, int lineNumber) {
+ static @Nullable String describeActualValue(String className, String methodName, int lineNumber) {
InferenceClassVisitor visitor;
try {
// TODO(cpovirk): Verify that methodName is correct for constructors and static initializers.
@@ -89,7 +93,7 @@ final class ActualValueInference {
try {
stream = loader.getResourceAsStream(className.replace('.', '/') + ".class");
// TODO(cpovirk): Disable inference if the bytecode version is newer than we've tested on?
- new ClassReader(stream).accept(visitor, /*parsingOptions=*/ 0);
+ new ClassReader(stream).accept(visitor, /* parsingOptions= */ 0);
ImmutableSet<StackEntry> actualsAtLine = visitor.actualValueAtLine.build().get(lineNumber);
/*
* It's very unlikely that more than one assertion would happen on the same line _but with
@@ -140,7 +144,7 @@ final class ActualValueInference {
throw new ClassCastException(getClass().getName());
}
- String description() {
+ @Nullable String description() {
return null;
}
}
@@ -149,6 +153,7 @@ final class ActualValueInference {
@AutoValue
@CopyAnnotations
@GwtIncompatible
+ @J2ktIncompatible
abstract static class OpaqueEntry extends StackEntry {
@Override
public final String toString() {
@@ -168,6 +173,7 @@ final class ActualValueInference {
@AutoValue
@CopyAnnotations
@GwtIncompatible
+ @J2ktIncompatible
abstract static class DescribedEntry extends StackEntry {
@Override
abstract String description();
@@ -193,6 +199,7 @@ final class ActualValueInference {
@AutoValue
@CopyAnnotations
@GwtIncompatible
+ @J2ktIncompatible
abstract static class SubjectEntry extends StackEntry {
@Override
abstract StackEntry actualValue();
@@ -266,7 +273,7 @@ final class ActualValueInference {
String name,
String methodDescriptor,
ImmutableSetMultimap.Builder<Integer, StackEntry> actualValueAtLine) {
- super(Opcodes.ASM8);
+ super(Opcodes.ASM9);
localVariableSlots = createInitialLocalVariableSlots(access, owner, name, methodDescriptor);
previousFrame =
FrameInfo.create(
@@ -734,7 +741,7 @@ final class ActualValueInference {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
- if (opcode == Opcodes.INVOKESPECIAL && "<init>".equals(name)) {
+ if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) {
int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2);
InferredType receiverType = getOperandFromTop(argumentSize - 1).type();
if (receiverType.isUninitialized()) {
@@ -958,7 +965,7 @@ final class ActualValueInference {
}
private void pushDescriptor(String desc) {
- pushDescriptorAndMaybeProcessMethodCall(desc, /*invocation=*/ null);
+ pushDescriptorAndMaybeProcessMethodCall(desc, /* invocation= */ null);
}
/**
@@ -973,9 +980,11 @@ final class ActualValueInference {
* @param invocation the method invocation being visited, or {@code null} if a non-method
* descriptor is being visited
*/
- private void pushDescriptorAndMaybeProcessMethodCall(String desc, Invocation invocation) {
+ private void pushDescriptorAndMaybeProcessMethodCall(
+ String desc, @Nullable Invocation invocation) {
if (invocation != null && invocation.isOnSubjectInstance()) {
- actualValueAtLocation.put(labelsSeen.build(), invocation.receiver().actualValue());
+ actualValueAtLocation.put(
+ labelsSeen.build(), checkNotNull(invocation.receiver()).actualValue());
}
boolean hasParams = invocation != null && (Type.getArgumentsAndReturnSizes(desc) >> 2) > 1;
@@ -1010,7 +1019,8 @@ final class ActualValueInference {
}
}
- private void pushMaybeDescribed(InferredType type, Invocation invocation, boolean hasParams) {
+ private void pushMaybeDescribed(
+ InferredType type, @Nullable Invocation invocation, boolean hasParams) {
push(invocation == null ? opaque(type) : invocation.deriveEntry(type, hasParams));
}
@@ -1031,10 +1041,11 @@ final class ActualValueInference {
operandStack,
methodSignature);
int expectedLastIndex = operandStack.size() - count - 1;
- StackEntry lastPopped = null;
- for (int i = operandStack.size() - 1; i > expectedLastIndex; --i) {
- lastPopped = operandStack.remove(i);
- }
+
+ StackEntry lastPopped;
+ do {
+ lastPopped = operandStack.remove(operandStack.size() - 1);
+ } while (operandStack.size() - 1 > expectedLastIndex);
return lastPopped;
}
@@ -1074,7 +1085,7 @@ final class ActualValueInference {
}
private StackEntry top() {
- return operandStack.get(operandStack.size() - 1);
+ return Iterables.getLast(operandStack);
}
/**
@@ -1219,6 +1230,7 @@ final class ActualValueInference {
@AutoValue
@CopyAnnotations
@GwtIncompatible
+ @J2ktIncompatible
abstract static class FrameInfo {
static FrameInfo create(ImmutableList<StackEntry> locals, ImmutableList<StackEntry> stack) {
@@ -1234,24 +1246,22 @@ final class ActualValueInference {
@AutoValue
@CopyAnnotations
@GwtIncompatible
+ @J2ktIncompatible
abstract static class Invocation {
static Builder builder(String name) {
return new AutoValue_ActualValueInference_Invocation.Builder().setName(name);
}
/** The receiver of this call, if it is an instance call. */
- @Nullable
- abstract StackEntry receiver();
+ abstract @Nullable StackEntry receiver();
/** The value being passed to this call if it is an {@code assertThat} or {@code that} call. */
- @Nullable
- abstract StackEntry actualValue();
+ abstract @Nullable StackEntry actualValue();
/**
* The value being passed to this call if it is a boxing call (e.g., {@code Integer.valueOf}).
*/
- @Nullable
- abstract StackEntry boxingInput();
+ abstract @Nullable StackEntry boxingInput();
abstract String name();
@@ -1261,7 +1271,7 @@ final class ActualValueInference {
} else if (actualValue() != null) {
return subjectFor(type, actualValue());
} else if (isOnSubjectInstance()) {
- return subjectFor(type, receiver().actualValue());
+ return subjectFor(type, checkNotNull(receiver()).actualValue());
} else if (BORING_NAMES.contains(name())) {
/*
* TODO(cpovirk): For no-arg instance methods like get(), return "foo.get()," where "foo" is
@@ -1278,7 +1288,6 @@ final class ActualValueInference {
}
@AutoValue.Builder
- @CanIgnoreReturnValue
abstract static class Builder {
abstract Builder setReceiver(StackEntry receiver);
@@ -1288,7 +1297,6 @@ final class ActualValueInference {
abstract Builder setName(String name);
- @CheckReturnValue
abstract Invocation build();
}
}
@@ -1297,6 +1305,7 @@ final class ActualValueInference {
@AutoValue
@CopyAnnotations
@GwtIncompatible
+ @J2ktIncompatible
abstract static class InferredType {
static final String UNINITIALIZED_PREFIX = "UNINIT@";
@@ -1320,7 +1329,7 @@ final class ActualValueInference {
/** Create a type for a value. */
static InferredType create(String descriptor) {
- if (UNINITIALIZED_PREFIX.equals(descriptor)) {
+ if (descriptor.equals(UNINITIALIZED_PREFIX)) {
return UNINITIALIZED;
}
char firstChar = descriptor.charAt(0);
@@ -1395,7 +1404,7 @@ final class ActualValueInference {
private String className;
InferenceClassVisitor(String methodNameToVisit) {
- super(Opcodes.ASM7);
+ super(Opcodes.ASM9);
this.methodNameToVisit = methodNameToVisit;
}
@@ -1411,7 +1420,7 @@ final class ActualValueInference {
}
@Override
- public MethodVisitor visitMethod(
+ public @Nullable MethodVisitor visitMethod(
int access, String name, String desc, String signature, String[] exceptions) {
/*
* Each InferenceMethodVisitor instance may be used only once. Still, it might seem like we
@@ -1455,7 +1464,8 @@ final class ActualValueInference {
*/
return (owner.equals("com/google/common/truth/Truth") && name.equals("assertThat"))
|| (owner.equals("com/google/common/truth/StandardSubjectBuilder") && name.equals("that"))
- || (owner.equals("com/google/common/truth/SimpleSubjectBuilder") && name.equals("that"));
+ || (owner.equals("com/google/common/truth/SimpleSubjectBuilder") && name.equals("that"))
+ || (owner.equals("com/google/common/truth/Expect") && name.equals("that"));
}
private static boolean isBoxing(String owner, String name, String desc) {
@@ -1496,7 +1506,7 @@ final class ActualValueInference {
return (flags & bitmask) == bitmask;
}
- private static void closeQuietly(InputStream stream) {
+ private static void closeQuietly(@Nullable InputStream stream) {
if (stream == null) {
return;
}
@@ -1507,14 +1517,5 @@ final class ActualValueInference {
}
}
- /*
- * TODO(cpovirk): Switch to using Checker Framework @Nullable. The problem I see if I try to
- * switch now is that the AutoValue-generated code is `@Nullable ActualValueInference.StackEntry`
- * rather than `ActualValueInference.@Nullable StackEntry`. AutoValue normally gets this right
- * (b/29530042), so I think the failure here is because we use `-source 7`. That might still be
- * fine, except that j2objc compilation appears to then use `-source 8`.
- */
- @interface Nullable {}
-
private ActualValueInference() {}
}
diff --git a/core/src/main/java/com/google/common/truth/AssertionErrorWithFacts.java b/core/src/main/java/com/google/common/truth/AssertionErrorWithFacts.java
index db465057..cc5d36d9 100644
--- a/core/src/main/java/com/google/common/truth/AssertionErrorWithFacts.java
+++ b/core/src/main/java/com/google/common/truth/AssertionErrorWithFacts.java
@@ -47,13 +47,13 @@ final class AssertionErrorWithFacts extends AssertionError implements ErrorWithF
@Override
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
- public Throwable getCause() {
+ public @Nullable Throwable getCause() {
return cause;
}
@Override
public String toString() {
- return getLocalizedMessage();
+ return checkNotNull(getLocalizedMessage());
}
@Override
diff --git a/core/src/main/java/com/google/common/truth/BigDecimalSubject.java b/core/src/main/java/com/google/common/truth/BigDecimalSubject.java
index 64cf8236..dbba5917 100644
--- a/core/src/main/java/com/google/common/truth/BigDecimalSubject.java
+++ b/core/src/main/java/com/google/common/truth/BigDecimalSubject.java
@@ -15,6 +15,7 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.truth.Fact.fact;
import static com.google.common.truth.Fact.simpleFact;
@@ -27,7 +28,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Kurt Alfred Kluever
*/
public final class BigDecimalSubject extends ComparableSubject<BigDecimal> {
- private final BigDecimal actual;
+ private final @Nullable BigDecimal actual;
BigDecimalSubject(FailureMetadata metadata, @Nullable BigDecimal actual) {
super(metadata, actual);
@@ -88,12 +89,12 @@ public final class BigDecimalSubject extends ComparableSubject<BigDecimal> {
* #isEqualTo(Object)}.
*/
@Override
- public void isEquivalentAccordingToCompareTo(BigDecimal expected) {
+ public void isEquivalentAccordingToCompareTo(@Nullable BigDecimal expected) {
compareValues(expected);
}
- private void compareValues(BigDecimal expected) {
- if (actual.compareTo(expected) != 0) {
+ private void compareValues(@Nullable BigDecimal expected) {
+ if (checkNotNull(actual).compareTo(checkNotNull(expected)) != 0) {
failWithoutActual(fact("expected", expected), butWas(), simpleFact("(scale is ignored)"));
}
}
diff --git a/core/src/main/java/com/google/common/truth/BooleanSubject.java b/core/src/main/java/com/google/common/truth/BooleanSubject.java
index 528cbc62..4e7f3da0 100644
--- a/core/src/main/java/com/google/common/truth/BooleanSubject.java
+++ b/core/src/main/java/com/google/common/truth/BooleanSubject.java
@@ -25,7 +25,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public final class BooleanSubject extends Subject {
- private final Boolean actual;
+ private final @Nullable Boolean actual;
BooleanSubject(FailureMetadata metadata, @Nullable Boolean actual) {
super(metadata, actual);
diff --git a/core/src/main/java/com/google/common/truth/ClassSubject.java b/core/src/main/java/com/google/common/truth/ClassSubject.java
index a2ca5c48..1ef1b950 100644
--- a/core/src/main/java/com/google/common/truth/ClassSubject.java
+++ b/core/src/main/java/com/google/common/truth/ClassSubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.annotations.GwtIncompatible;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,8 +26,9 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Kurt Alfred Kluever
*/
@GwtIncompatible("reflection")
+@J2ktIncompatible
public final class ClassSubject extends Subject {
- private final Class<?> actual;
+ private final @Nullable Class<?> actual;
ClassSubject(FailureMetadata metadata, @Nullable Class<?> o) {
super(metadata, o);
@@ -37,7 +40,7 @@ public final class ClassSubject extends Subject {
* class or interface.
*/
public void isAssignableTo(Class<?> clazz) {
- if (!clazz.isAssignableFrom(actual)) {
+ if (!clazz.isAssignableFrom(checkNotNull(actual))) {
failWithActual("expected to be assignable to", clazz.getName());
}
}
diff --git a/core/src/main/java/com/google/common/truth/ComparableSubject.java b/core/src/main/java/com/google/common/truth/ComparableSubject.java
index ed769734..857f2149 100644
--- a/core/src/main/java/com/google/common/truth/ComparableSubject.java
+++ b/core/src/main/java/com/google/common/truth/ComparableSubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.collect.Range;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,12 +26,13 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Kurt Alfred Kluever
* @param <T> the type of the object being tested by this {@code ComparableSubject}
*/
-public abstract class ComparableSubject<T extends Comparable> extends Subject {
+// TODO(b/136040841): Consider further tightening this to the proper `extends Comparable<? super T>`
+public abstract class ComparableSubject<T extends Comparable<?>> extends Subject {
/**
* Constructor for use by subclasses. If you want to create an instance of this class itself, call
* {@link Subject#check(String, Object...) check(...)}{@code .that(actual)}.
*/
- private final T actual;
+ private final @Nullable T actual;
protected ComparableSubject(FailureMetadata metadata, @Nullable T actual) {
super(metadata, actual);
@@ -38,14 +41,14 @@ public abstract class ComparableSubject<T extends Comparable> extends Subject {
/** Checks that the subject is in {@code range}. */
public final void isIn(Range<T> range) {
- if (!range.contains(actual)) {
+ if (!range.contains(checkNotNull(actual))) {
failWithActual("expected to be in range", range);
}
}
/** Checks that the subject is <i>not</i> in {@code range}. */
public final void isNotIn(Range<T> range) {
- if (range.contains(actual)) {
+ if (range.contains(checkNotNull(actual))) {
failWithActual("expected not to be in range", range);
}
}
@@ -57,8 +60,9 @@ public abstract class ComparableSubject<T extends Comparable> extends Subject {
* <p><b>Note:</b> Do not use this method for checking object equality. Instead, use {@link
* #isEqualTo(Object)}.
*/
- public void isEquivalentAccordingToCompareTo(T expected) {
- if (actual.compareTo(expected) != 0) {
+ @SuppressWarnings("unchecked")
+ public void isEquivalentAccordingToCompareTo(@Nullable T expected) {
+ if (checkNotNull((Comparable<Object>) actual).compareTo(checkNotNull(expected)) != 0) {
failWithActual("expected value that sorts equal to", expected);
}
}
@@ -69,8 +73,9 @@ public abstract class ComparableSubject<T extends Comparable> extends Subject {
* <p>To check that the subject is greater than <i>or equal to</i> {@code other}, use {@link
* #isAtLeast}.
*/
- public final void isGreaterThan(T other) {
- if (actual.compareTo(other) <= 0) {
+ @SuppressWarnings("unchecked")
+ public final void isGreaterThan(@Nullable T other) {
+ if (checkNotNull((Comparable<Object>) actual).compareTo(checkNotNull(other)) <= 0) {
failWithActual("expected to be greater than", other);
}
}
@@ -81,8 +86,9 @@ public abstract class ComparableSubject<T extends Comparable> extends Subject {
* <p>To check that the subject is less than <i>or equal to</i> {@code other}, use {@link
* #isAtMost}.
*/
- public final void isLessThan(T other) {
- if (actual.compareTo(other) >= 0) {
+ @SuppressWarnings("unchecked")
+ public final void isLessThan(@Nullable T other) {
+ if (checkNotNull((Comparable<Object>) actual).compareTo(checkNotNull(other)) >= 0) {
failWithActual("expected to be less than", other);
}
}
@@ -93,8 +99,9 @@ public abstract class ComparableSubject<T extends Comparable> extends Subject {
* <p>To check that the subject is <i>strictly</i> less than {@code other}, use {@link
* #isLessThan}.
*/
- public final void isAtMost(T other) {
- if (actual.compareTo(other) > 0) {
+ @SuppressWarnings("unchecked")
+ public final void isAtMost(@Nullable T other) {
+ if (checkNotNull((Comparable<Object>) actual).compareTo(checkNotNull(other)) > 0) {
failWithActual("expected to be at most", other);
}
}
@@ -105,8 +112,9 @@ public abstract class ComparableSubject<T extends Comparable> extends Subject {
* <p>To check that the subject is <i>strictly</i> greater than {@code other}, use {@link
* #isGreaterThan}.
*/
- public final void isAtLeast(T other) {
- if (actual.compareTo(other) < 0) {
+ @SuppressWarnings("unchecked")
+ public final void isAtLeast(@Nullable T other) {
+ if (checkNotNull((Comparable<Object>) actual).compareTo(checkNotNull(other)) < 0) {
failWithActual("expected to be at least", other);
}
}
diff --git a/core/src/main/java/com/google/common/truth/ComparisonFailureWithFacts.java b/core/src/main/java/com/google/common/truth/ComparisonFailureWithFacts.java
index dcb4477f..47608db2 100644
--- a/core/src/main/java/com/google/common/truth/ComparisonFailureWithFacts.java
+++ b/core/src/main/java/com/google/common/truth/ComparisonFailureWithFacts.java
@@ -30,6 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
final class ComparisonFailureWithFacts extends PlatformComparisonFailure implements ErrorWithFacts {
private final ImmutableList<Fact> facts;
+ @UsedByReflection
ComparisonFailureWithFacts(
ImmutableList<String> messages,
ImmutableList<Fact> facts,
diff --git a/core/src/main/java/com/google/common/truth/Correspondence.java b/core/src/main/java/com/google/common/truth/Correspondence.java
index b4a04b0e..704a9e6c 100644
--- a/core/src/main/java/com/google/common/truth/Correspondence.java
+++ b/core/src/main/java/com/google/common/truth/Correspondence.java
@@ -65,7 +65,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*
* @author Pete Gillin
*/
-public abstract class Correspondence<A, E> {
+public abstract class Correspondence<A extends @Nullable Object, E extends @Nullable Object> {
/**
* Constructs a {@link Correspondence} that compares actual and expected elements using the given
@@ -93,7 +93,7 @@ public abstract class Correspondence<A, E> {
* class MyRecordTestHelper {
* static final Correspondence<MyRecord, MyRecord> EQUIVALENCE =
* Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to");
- * static boolean recordsEquivalent(@Nullable MyRecord actual, @Nullable MyRecord expected) {
+ * static boolean recordsEquivalent(MyRecord actual, MyRecord expected) {
* // code to check whether records should be considered equivalent for testing purposes
* }
* }
@@ -112,7 +112,7 @@ public abstract class Correspondence<A, E> {
* <some actual element> is an element that <description> <some expected element>"}, e.g.
* {@code "contains"}, {@code "is an instance of"}, or {@code "is equivalent to"}
*/
- public static <A, E> Correspondence<A, E> from(
+ public static <A extends @Nullable Object, E extends @Nullable Object> Correspondence<A, E> from(
BinaryPredicate<A, E> predicate, String description) {
return new FromBinaryPredicate<>(predicate, description);
}
@@ -126,16 +126,18 @@ public abstract class Correspondence<A, E> {
* you should almost never see {@code BinaryPredicate} used as the type of a field or variable, or
* a return type.
*/
- public interface BinaryPredicate<A, E> {
+ public interface BinaryPredicate<A extends @Nullable Object, E extends @Nullable Object> {
/**
* Returns whether or not the actual and expected values satisfy the condition defined by this
* predicate.
*/
- boolean apply(@Nullable A actual, @Nullable E expected);
+ boolean apply(A actual, E expected);
}
- private static final class FromBinaryPredicate<A, E> extends Correspondence<A, E> {
+ private static final class FromBinaryPredicate<
+ A extends @Nullable Object, E extends @Nullable Object>
+ extends Correspondence<A, E> {
private final BinaryPredicate<A, E> predicate;
private final String description;
@@ -145,7 +147,7 @@ public abstract class Correspondence<A, E> {
}
@Override
- public boolean compare(@Nullable A actual, @Nullable E expected) {
+ public boolean compare(A actual, E expected) {
return predicate.apply(actual, expected);
}
@@ -191,8 +193,9 @@ public abstract class Correspondence<A, E> {
* <some actual element> is an element that <description> <some expected element>"}, e.g.
* {@code "has an ID of"}
*/
- public static <A, E> Correspondence<A, E> transforming(
- Function<A, ? extends E> actualTransform, String description) {
+ public static <A extends @Nullable Object, E extends @Nullable Object>
+ Correspondence<A, E> transforming(
+ Function<A, ? extends E> actualTransform, String description) {
return new Transforming<>(actualTransform, identity(), description);
}
@@ -238,12 +241,14 @@ public abstract class Correspondence<A, E> {
* <some actual element> is an element that <description> <some expected element>"}, e.g.
* {@code "has the same ID as"}
*/
- public static <A, E> Correspondence<A, E> transforming(
- Function<A, ?> actualTransform, Function<E, ?> expectedTransform, String description) {
+ public static <A extends @Nullable Object, E extends @Nullable Object>
+ Correspondence<A, E> transforming(
+ Function<A, ?> actualTransform, Function<E, ?> expectedTransform, String description) {
return new Transforming<>(actualTransform, expectedTransform, description);
}
- private static final class Transforming<A, E> extends Correspondence<A, E> {
+ private static final class Transforming<A extends @Nullable Object, E extends @Nullable Object>
+ extends Correspondence<A, E> {
private final Function<? super A, ?> actualTransform;
private final Function<? super E, ?> expectedTransform;
@@ -259,7 +264,7 @@ public abstract class Correspondence<A, E> {
}
@Override
- public boolean compare(@Nullable A actual, @Nullable E expected) {
+ public boolean compare(A actual, E expected) {
return Objects.equal(actualTransform.apply(actual), expectedTransform.apply(expected));
}
@@ -373,10 +378,10 @@ public abstract class Correspondence<A, E> {
* static final Correspondence<MyRecord, MyRecord> EQUIVALENCE =
* Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to")
* .formattingDiffsUsing(MyRecordTestHelper::formatRecordDiff);
- * static boolean recordsEquivalent(@Nullable MyRecord actual, @Nullable MyRecord expected) {
+ * static boolean recordsEquivalent(MyRecord actual, MyRecord expected) {
* // code to check whether records should be considered equivalent for testing purposes
* }
- * static String formatRecordDiff(@Nullable MyRecord actual, @Nullable MyRecord expected) {
+ * static String formatRecordDiff(MyRecord actual, MyRecord expected) {
* // code to format the diff between the records
* }
* }
@@ -395,17 +400,18 @@ public abstract class Correspondence<A, E> {
* Correspondence#formattingDiffsUsing}. As a result, you should almost never see {@code
* DiffFormatter} used as the type of a field or variable, or a return type.
*/
- public interface DiffFormatter<A, E> {
+ public interface DiffFormatter<A extends @Nullable Object, E extends @Nullable Object> {
/**
* Returns a {@link String} describing the difference between the {@code actual} and {@code
* expected} values, if possible, or {@code null} if not.
*/
@Nullable
- String formatDiff(@Nullable A actual, @Nullable E expected);
+ String formatDiff(A actual, E expected);
}
- private static class FormattingDiffs<A, E> extends Correspondence<A, E> {
+ private static class FormattingDiffs<A extends @Nullable Object, E extends @Nullable Object>
+ extends Correspondence<A, E> {
private final Correspondence<A, E> delegate;
private final DiffFormatter<? super A, ? super E> formatter;
@@ -416,12 +422,12 @@ public abstract class Correspondence<A, E> {
}
@Override
- public boolean compare(@Nullable A actual, @Nullable E expected) {
+ public boolean compare(A actual, E expected) {
return delegate.compare(actual, expected);
}
@Override
- public @Nullable String formatDiff(@Nullable A actual, @Nullable E expected) {
+ public @Nullable String formatDiff(A actual, E expected) {
return formatter.formatDiff(actual, expected);
}
@@ -517,7 +523,7 @@ public abstract class Correspondence<A, E> {
* returned false. (Note that, in the latter case at least, it is likely that the test author's
* intention was <i>not</i> for the test to pass with these values.)
*/
- public abstract boolean compare(@Nullable A actual, @Nullable E expected);
+ public abstract boolean compare(A actual, E expected);
private static class StoredException {
@@ -525,9 +531,10 @@ public abstract class Correspondence<A, E> {
private final Exception exception;
private final String methodName;
- private final List<Object> methodArguments;
+ private final List<@Nullable Object> methodArguments;
- StoredException(Exception exception, String methodName, List<Object> methodArguments) {
+ StoredException(
+ Exception exception, String methodName, List<@Nullable Object> methodArguments) {
this.exception = checkNotNull(exception);
this.methodName = checkNotNull(methodName);
this.methodArguments = checkNotNull(methodArguments);
@@ -552,9 +559,9 @@ public abstract class Correspondence<A, E> {
static final class ExceptionStore {
private final String argumentLabel;
- private StoredException firstCompareException = null;
- private StoredException firstPairingException = null;
- private StoredException firstFormatDiffException = null;
+ private @Nullable StoredException firstCompareException = null;
+ private @Nullable StoredException firstPairingException = null;
+ private @Nullable StoredException firstFormatDiffException = null;
static ExceptionStore forIterable() {
return new ExceptionStore("elements");
@@ -580,7 +587,10 @@ public abstract class Correspondence<A, E> {
* exception was encountered
*/
void addCompareException(
- Class<?> callingClass, Exception exception, Object actual, Object expected) {
+ Class<?> callingClass,
+ Exception exception,
+ @Nullable Object actual,
+ @Nullable Object expected) {
if (firstCompareException == null) {
truncateStackTrace(exception, callingClass);
firstCompareException = new StoredException(exception, "compare", asList(actual, expected));
@@ -597,7 +607,8 @@ public abstract class Correspondence<A, E> {
* @param actual The {@code actual} argument to the {@code apply} call during which the
* exception was encountered
*/
- void addActualKeyFunctionException(Class<?> callingClass, Exception exception, Object actual) {
+ void addActualKeyFunctionException(
+ Class<?> callingClass, Exception exception, @Nullable Object actual) {
if (firstPairingException == null) {
truncateStackTrace(exception, callingClass);
firstPairingException =
@@ -616,7 +627,7 @@ public abstract class Correspondence<A, E> {
* exception was encountered
*/
void addExpectedKeyFunctionException(
- Class<?> callingClass, Exception exception, Object expected) {
+ Class<?> callingClass, Exception exception, @Nullable Object expected) {
if (firstPairingException == null) {
truncateStackTrace(exception, callingClass);
firstPairingException =
@@ -636,7 +647,10 @@ public abstract class Correspondence<A, E> {
* exception was encountered
*/
void addFormatDiffException(
- Class<?> callingClass, Exception exception, Object actual, Object expected) {
+ Class<?> callingClass,
+ Exception exception,
+ @Nullable Object actual,
+ @Nullable Object expected) {
if (firstFormatDiffException == null) {
truncateStackTrace(exception, callingClass);
firstFormatDiffException =
@@ -718,7 +732,7 @@ public abstract class Correspondence<A, E> {
* returns false. This method can help with implementing the exception-handling policy described
* above, but note that assertions using it <i>must</i> fail later if an exception was stored.
*/
- final boolean safeCompare(@Nullable A actual, @Nullable E expected, ExceptionStore exceptions) {
+ final boolean safeCompare(A actual, E expected, ExceptionStore exceptions) {
try {
return compare(actual, expected);
} catch (RuntimeException e) {
@@ -744,7 +758,7 @@ public abstract class Correspondence<A, E> {
* exception and continue to describe the original failure as if this method had returned null,
* mentioning the failure from this method as additional information.
*/
- public @Nullable String formatDiff(@Nullable A actual, @Nullable E expected) {
+ public @Nullable String formatDiff(A actual, E expected) {
return null;
}
@@ -753,8 +767,7 @@ public abstract class Correspondence<A, E> {
* the result. If it does throw, adds the exception to the given {@link ExceptionStore} and
* returns null.
*/
- final @Nullable String safeFormatDiff(
- @Nullable A actual, @Nullable E expected, ExceptionStore exceptions) {
+ final @Nullable String safeFormatDiff(A actual, E expected, ExceptionStore exceptions) {
try {
return formatDiff(actual, expected);
} catch (RuntimeException e) {
diff --git a/core/src/main/java/com/google/common/truth/CustomSubjectBuilder.java b/core/src/main/java/com/google/common/truth/CustomSubjectBuilder.java
index 3b4f6b11..0b84ef88 100644
--- a/core/src/main/java/com/google/common/truth/CustomSubjectBuilder.java
+++ b/core/src/main/java/com/google/common/truth/CustomSubjectBuilder.java
@@ -18,6 +18,7 @@ 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}.
@@ -69,5 +70,5 @@ public abstract class CustomSubjectBuilder {
return metadata;
}
- // TODO(user): Better enforce that subclasses implement a that() method.
+ // TODO(user,cgruber): Better enforce that subclasses implement a that() method.
}
diff --git a/core/src/main/java/com/google/common/truth/DiffUtils.java b/core/src/main/java/com/google/common/truth/DiffUtils.java
index 43248a72..b8b4122e 100644
--- a/core/src/main/java/com/google/common/truth/DiffUtils.java
+++ b/core/src/main/java/com/google/common/truth/DiffUtils.java
@@ -36,10 +36,10 @@ final class DiffUtils {
private final List<String> stringList = new ArrayList<>();
// A map to record each unique string and its incremental id.
private final Map<String, Integer> stringToId = new HashMap<>();
- private int[] original;
- private int[] revised;
+ private int[] original = new int[0];
+ private int[] revised = new int[0];
// lcs[i][j] is the length of the longest common sequence of original[1..i] and revised[1..j].
- private int[][] lcs;
+ private int[][] lcs = new int[0][0];
private final List<Character> unifiedDiffType = new ArrayList<>();
private final List<Integer> unifiedDiffContentId = new ArrayList<>();
private final List<String> reducedUnifiedDiff = new ArrayList<>();
diff --git a/core/src/main/java/com/google/common/truth/DoubleSubject.java b/core/src/main/java/com/google/common/truth/DoubleSubject.java
index a198bff8..58cd50d6 100644
--- a/core/src/main/java/com/google/common/truth/DoubleSubject.java
+++ b/core/src/main/java/com/google/common/truth/DoubleSubject.java
@@ -36,7 +36,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class DoubleSubject extends ComparableSubject<Double> {
private static final long NEG_ZERO_BITS = doubleToLongBits(-0.0);
- private final Double actual;
+ private final @Nullable Double actual;
DoubleSubject(FailureMetadata metadata, @Nullable Double actual) {
super(metadata, actual);
@@ -104,7 +104,7 @@ public final class DoubleSubject extends ComparableSubject<Double> {
* allowed by the check, which must be a non-negative finite value, i.e. not {@link
* Double#NaN}, {@link Double#POSITIVE_INFINITY}, or negative, including {@code -0.0}
*/
- public TolerantDoubleComparison isWithin(final double tolerance) {
+ public TolerantDoubleComparison isWithin(double tolerance) {
return new TolerantDoubleComparison() {
@Override
public void of(double expected) {
@@ -143,7 +143,7 @@ public final class DoubleSubject extends ComparableSubject<Double> {
* allowed by the check, which must be a non-negative finite value, i.e. not {@code
* Double.NaN}, {@code Double.POSITIVE_INFINITY}, or negative, including {@code -0.0}
*/
- public TolerantDoubleComparison isNotWithin(final double tolerance) {
+ public TolerantDoubleComparison isNotWithin(double tolerance) {
return new TolerantDoubleComparison() {
@Override
public void of(double expected) {
@@ -201,7 +201,7 @@ public final class DoubleSubject extends ComparableSubject<Double> {
*/
@Override
@Deprecated
- public final void isEquivalentAccordingToCompareTo(Double other) {
+ public final void isEquivalentAccordingToCompareTo(@Nullable Double other) {
super.isEquivalentAccordingToCompareTo(other);
}
diff --git a/core/src/main/java/com/google/common/truth/Expect.java b/core/src/main/java/com/google/common/truth/Expect.java
index 5acc31d9..4e7b77d7 100644
--- a/core/src/main/java/com/google/common/truth/Expect.java
+++ b/core/src/main/java/com/google/common/truth/Expect.java
@@ -82,11 +82,12 @@ import org.junit.runners.model.Statement;
* <p>For more on this class, see <a href="https://truth.dev/expect">the documentation page</a>.
*/
@GwtIncompatible("JUnit4")
+@J2ktIncompatible
public final class Expect extends StandardSubjectBuilder implements TestRule {
private static final class ExpectationGatherer implements FailureStrategy {
@GuardedBy("this")
- private final List<AssertionError> failures = new ArrayList<AssertionError>();
+ private final List<AssertionError> failures = new ArrayList<>();
@GuardedBy("this")
private TestPhase inRuleContext = BEFORE;
@@ -136,8 +137,10 @@ public final class Expect extends StandardSubjectBuilder implements TestRule {
}
int numFailures = failures.size();
StringBuilder message =
- new StringBuilder(
- numFailures + (numFailures > 1 ? " expectations" : " expectation") + " failed:\n");
+ new StringBuilder()
+ .append(numFailures)
+ .append(numFailures > 1 ? " expectations" : " expectation")
+ .append(" failed:\n");
int countLength = String.valueOf(failures.size() + 1).length();
int count = 0;
for (AssertionError failure : failures) {
@@ -159,6 +162,8 @@ public final class Expect extends StandardSubjectBuilder implements TestRule {
return message.toString();
}
+ // String.repeat is not available under Java 8 and old versions of Android.
+ @SuppressWarnings({"StringsRepeat", "InlineMeInliner"})
private static void appendIndented(int countLength, StringBuilder builder, String toAppend) {
int indent = countLength + 4; // " " and ". "
builder.append(toAppend.replace("\n", "\n" + repeat(" ", indent)));
@@ -245,7 +250,7 @@ public final class Expect extends StandardSubjectBuilder implements TestRule {
}
@Override
- public Statement apply(final Statement base, Description description) {
+ public Statement apply(Statement base, Description description) {
checkNotNull(base);
checkNotNull(description);
return new Statement() {
diff --git a/core/src/main/java/com/google/common/truth/ExpectFailure.java b/core/src/main/java/com/google/common/truth/ExpectFailure.java
index 970f5261..5b036085 100644
--- a/core/src/main/java/com/google/common/truth/ExpectFailure.java
+++ b/core/src/main/java/com/google/common/truth/ExpectFailure.java
@@ -23,6 +23,7 @@ import static com.google.common.truth.TruthFailureSubject.truthFailures;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.truth.Truth.SimpleAssertionError;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@@ -66,14 +67,6 @@ import org.junit.runners.model.Statement;
* {@link FailureStrategy#fail} only once.
*/
public final class ExpectFailure implements Platform.JUnitTestRule {
- private final FailureStrategy strategy =
- new FailureStrategy() {
- @Override
- public void fail(AssertionError failure) {
- captureFailure(failure);
- }
- };
-
private boolean inRuleContext = false;
private boolean failureExpected = false;
private @Nullable AssertionError failure = null;
@@ -101,7 +94,7 @@ public final class ExpectFailure implements Platform.JUnitTestRule {
"ExpectFailure.whenTesting() called previously, but did not capture a failure.");
}
failureExpected = true;
- return StandardSubjectBuilder.forCustomFailureStrategy(strategy);
+ return StandardSubjectBuilder.forCustomFailureStrategy(this::captureFailure);
}
/**
@@ -161,6 +154,7 @@ public final class ExpectFailure implements Platform.JUnitTestRule {
* <p>{@code AssertionError failure = expectFailure(whenTesting ->
* whenTesting.that(4).isNotEqualTo(4));}
*/
+ @CanIgnoreReturnValue
public static AssertionError expectFailure(StandardSubjectBuilderCallback assertionCallback) {
ExpectFailure expectFailure = new ExpectFailure();
expectFailure.enterRuleContext(); // safe since this instance doesn't leave this method
@@ -175,30 +169,25 @@ public final class ExpectFailure implements Platform.JUnitTestRule {
* <p>{@code AssertionError failure = expectFailureAbout(myTypes(), whenTesting ->
* whenTesting.that(myType).hasProperty());}
*/
+ @CanIgnoreReturnValue
public static <S extends Subject, A> AssertionError expectFailureAbout(
- final Subject.Factory<S, A> factory,
- final SimpleSubjectBuilderCallback<S, A> assertionCallback) {
- // whenTesting -> assertionCallback.invokeAssertion(whenTesting.about(factory))
+ Subject.Factory<S, A> factory, SimpleSubjectBuilderCallback<S, A> assertionCallback) {
return expectFailure(
- new StandardSubjectBuilderCallback() {
- @Override
- public void invokeAssertion(StandardSubjectBuilder whenTesting) {
- assertionCallback.invokeAssertion(whenTesting.about(factory));
- }
- });
+ whenTesting -> assertionCallback.invokeAssertion(whenTesting.about(factory)));
}
/**
* Creates a subject for asserting about the given {@link AssertionError}, usually one produced by
* Truth.
*/
- public static TruthFailureSubject assertThat(AssertionError actual) {
+ public static TruthFailureSubject assertThat(@Nullable AssertionError actual) {
return assertAbout(truthFailures()).that(actual);
}
@Override
@GwtIncompatible("org.junit.rules.TestRule")
- public Statement apply(final Statement base, Description description) {
+ @J2ktIncompatible
+ public Statement apply(Statement base, Description description) {
checkNotNull(base);
checkNotNull(description);
return new Statement() {
diff --git a/core/src/main/java/com/google/common/truth/Fact.java b/core/src/main/java/com/google/common/truth/Fact.java
index 02e2bea4..b2dadad2 100644
--- a/core/src/main/java/com/google/common/truth/Fact.java
+++ b/core/src/main/java/com/google/common/truth/Fact.java
@@ -135,6 +135,6 @@ public final class Fact implements Serializable {
// We don't want to indent with \t because the text would align exactly with the stack trace.
// We don't want to indent with \t\t because it would be very far for people with 8-space tabs.
// Let's compromise and indent by 4 spaces, which is different than both 2- and 8-space tabs.
- return " " + value.replaceAll("\n", "\n ");
+ return " " + value.replace("\n", "\n ");
}
}
diff --git a/core/src/main/java/com/google/common/truth/FailureMetadata.java b/core/src/main/java/com/google/common/truth/FailureMetadata.java
index 00c890cf..e6d86a74 100644
--- a/core/src/main/java/com/google/common/truth/FailureMetadata.java
+++ b/core/src/main/java/com/google/common/truth/FailureMetadata.java
@@ -68,7 +68,7 @@ public final class FailureMetadata {
}
static Step checkCall(
- OldAndNewValuesAreSimilar valuesAreSimilar,
+ @Nullable OldAndNewValuesAreSimilar valuesAreSimilar,
@Nullable Function<String, String> descriptionUpdate) {
return new Step(null, descriptionUpdate, valuesAreSimilar);
}
@@ -161,13 +161,12 @@ public final class FailureMetadata {
* to set a message is {@code check(...).withMessage(...).that(...)} (for calls from within a
* {@code Subject}) or {@link Truth#assertWithMessage} (for most other calls).
*/
- FailureMetadata withMessage(String format, /*@Nullable*/ Object[] args) {
+ FailureMetadata withMessage(String format, @Nullable Object[] args) {
ImmutableList<LazyMessage> messages = append(this.messages, new LazyMessage(format, args));
return derive(messages, steps);
}
void failEqualityCheck(
- ImmutableList<Fact> headFacts,
ImmutableList<Fact> tailFacts,
String expected,
String actual) {
@@ -175,10 +174,7 @@ public final class FailureMetadata {
makeComparisonFailure(
evaluateAll(messages),
makeComparisonFailureFacts(
- concat(description(), headFacts),
- concat(tailFacts, rootUnlessThrowable()),
- expected,
- actual),
+ description(), concat(tailFacts, rootUnlessThrowable()), expected, actual),
expected,
actual,
rootCause()));
@@ -242,7 +238,7 @@ public final class FailureMetadata {
}
if (description == null) {
- description = step.subject.typeDescription();
+ description = checkNotNull(step.subject).typeDescription();
}
}
return descriptionIsInteresting
@@ -291,7 +287,7 @@ public final class FailureMetadata {
}
if (rootSubject == null) {
- if (step.subject.actual() instanceof Throwable) {
+ if (checkNotNull(step.subject).actual() instanceof Throwable) {
/*
* We'll already include the Throwable as a cause of the AssertionError (see rootCause()),
* so we don't need to include it again in the message.
@@ -310,8 +306,9 @@ public final class FailureMetadata {
? ImmutableList.of(
fact(
// TODO(cpovirk): Use inferDescription() here when appropriate? But it can be long.
- rootSubject.subject.typeDescription() + " was",
- rootSubject.subject.actualCustomStringRepresentationForPackageMembersToCall()))
+ checkNotNull(checkNotNull(rootSubject).subject).typeDescription() + " was",
+ checkNotNull(checkNotNull(rootSubject).subject)
+ .actualCustomStringRepresentationForPackageMembersToCall()))
: ImmutableList.<Fact>of();
}
@@ -321,7 +318,7 @@ public final class FailureMetadata {
*/
private @Nullable Throwable rootCause() {
for (Step step : steps) {
- if (!step.isCheckCall() && step.subject.actual() instanceof Throwable) {
+ if (!step.isCheckCall() && checkNotNull(step.subject).actual() instanceof Throwable) {
return (Throwable) step.subject.actual();
}
}
diff --git a/core/src/main/java/com/google/common/truth/FailureStrategy.java b/core/src/main/java/com/google/common/truth/FailureStrategy.java
index 81f1092a..b10d5509 100644
--- a/core/src/main/java/com/google/common/truth/FailureStrategy.java
+++ b/core/src/main/java/com/google/common/truth/FailureStrategy.java
@@ -15,6 +15,7 @@
*/
package com.google.common.truth;
+
/**
* Defines what to do when a check fails.
*
diff --git a/core/src/main/java/com/google/common/truth/FloatSubject.java b/core/src/main/java/com/google/common/truth/FloatSubject.java
index 765b3844..19dff124 100644
--- a/core/src/main/java/com/google/common/truth/FloatSubject.java
+++ b/core/src/main/java/com/google/common/truth/FloatSubject.java
@@ -36,7 +36,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class FloatSubject extends ComparableSubject<Float> {
private static final int NEG_ZERO_BITS = floatToIntBits(-0.0f);
- private final Float actual;
+ private final @Nullable Float actual;
private final DoubleSubject asDouble;
FloatSubject(FailureMetadata metadata, @Nullable Float actual) {
@@ -112,7 +112,7 @@ public final class FloatSubject extends ComparableSubject<Float> {
* allowed by the check, which must be a non-negative finite value, i.e. not {@link
* Float#NaN}, {@link Float#POSITIVE_INFINITY}, or negative, including {@code -0.0f}
*/
- public TolerantFloatComparison isWithin(final float tolerance) {
+ public TolerantFloatComparison isWithin(float tolerance) {
return new TolerantFloatComparison() {
@Override
public void of(float expected) {
@@ -151,7 +151,7 @@ public final class FloatSubject extends ComparableSubject<Float> {
* allowed by the check, which must be a non-negative finite value, i.e. not {@code
* Float.NaN}, {@code Float.POSITIVE_INFINITY}, or negative, including {@code -0.0f}
*/
- public TolerantFloatComparison isNotWithin(final float tolerance) {
+ public TolerantFloatComparison isNotWithin(float tolerance) {
return new TolerantFloatComparison() {
@Override
public void of(float expected) {
@@ -209,7 +209,7 @@ public final class FloatSubject extends ComparableSubject<Float> {
*/
@Override
@Deprecated
- public final void isEquivalentAccordingToCompareTo(Float other) {
+ public final void isEquivalentAccordingToCompareTo(@Nullable Float other) {
super.isEquivalentAccordingToCompareTo(other);
}
diff --git a/core/src/main/java/com/google/common/truth/GraphMatching.java b/core/src/main/java/com/google/common/truth/GraphMatching.java
index 6a266f5d..ef21fef5 100644
--- a/core/src/main/java/com/google/common/truth/GraphMatching.java
+++ b/core/src/main/java/com/google/common/truth/GraphMatching.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.base.Optional;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
@@ -142,7 +144,7 @@ final class GraphMatching {
// Now proceed with the BFS.
while (!queue.isEmpty()) {
U lhs = queue.remove();
- int layer = layers.get(lhs);
+ int layer = checkNotNull(layers.get(lhs));
// If the BFS has proceeded past a layer in which a free RHS vertex was found, stop.
if (freeRhsVertexLayer.isPresent() && layer > freeRhsVertexLayer.get()) {
break;
@@ -164,7 +166,7 @@ final class GraphMatching {
// that new LHS vertex yet, add it to the next layer. (If the edge from the LHS to the
// RHS was matched then the matched edge from the RHS to the LHS will lead back to the
// current LHS vertex, which has definitely been visited, so we correctly do nothing.)
- U nextLhs = matching.inverse().get(rhs);
+ U nextLhs = checkNotNull(matching.inverse().get(rhs));
if (!layers.containsKey(nextLhs)) {
layers.put(nextLhs, layer + 1);
queue.add(nextLhs);
@@ -223,7 +225,7 @@ final class GraphMatching {
// rather than using all the paths at the end of the phase. As explained above, the effect of
// this is that we automatically find only the disjoint set of paths, as required. This is,
// fact, the approach taken in the pseudocode of the wikipedia article (at time of writing).
- int layer = layers.get(lhs);
+ int layer = checkNotNull(layers.get(lhs));
if (layer > freeRhsVertexLayer) {
// We've gone past the target layer, so we're not going to find what we're looking for.
return false;
@@ -240,7 +242,7 @@ final class GraphMatching {
} else {
// We found a non-free RHS vertex. Follow the matched edge from that RHS vertex to find
// the next LHS vertex.
- U nextLhs = matching.inverse().get(rhs);
+ U nextLhs = checkNotNull(matching.inverse().get(rhs));
if (layers.containsKey(nextLhs) && layers.get(nextLhs) == layer + 1) {
// The next LHS vertex is in the next layer of the BFS, so we can use this path for our
// DFS. Recurse into the DFS.
diff --git a/core/src/main/java/com/google/common/truth/GuavaOptionalSubject.java b/core/src/main/java/com/google/common/truth/GuavaOptionalSubject.java
index bbaf8053..d65448d6 100644
--- a/core/src/main/java/com/google/common/truth/GuavaOptionalSubject.java
+++ b/core/src/main/java/com/google/common/truth/GuavaOptionalSubject.java
@@ -30,7 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber
*/
public final class GuavaOptionalSubject extends Subject {
- private final Optional<?> actual;
+ private final @Nullable Optional<?> actual;
GuavaOptionalSubject(
FailureMetadata metadata, @Nullable Optional<?> actual, @Nullable String typeDescription) {
@@ -67,7 +67,7 @@ public final class GuavaOptionalSubject extends Subject {
* assertThat(myOptional.get()).contains("foo");
* }</pre>
*/
- public void hasValue(Object expected) {
+ public void hasValue(@Nullable Object expected) {
if (expected == null) {
throw new NullPointerException("Optional cannot have a null value.");
}
diff --git a/core/src/main/java/com/google/common/truth/IntegerSubject.java b/core/src/main/java/com/google/common/truth/IntegerSubject.java
index 2f892379..bf144640 100644
--- a/core/src/main/java/com/google/common/truth/IntegerSubject.java
+++ b/core/src/main/java/com/google/common/truth/IntegerSubject.java
@@ -33,10 +33,12 @@ public class IntegerSubject extends ComparableSubject<Integer> {
super(metadata, integer);
}
- /** @deprecated Use {@link #isEqualTo} instead. Integer comparison is consistent with equality. */
+ /**
+ * @deprecated Use {@link #isEqualTo} instead. Integer comparison is consistent with equality.
+ */
@Override
@Deprecated
- public final void isEquivalentAccordingToCompareTo(Integer other) {
+ public final void isEquivalentAccordingToCompareTo(@Nullable Integer other) {
super.isEquivalentAccordingToCompareTo(other);
}
}
diff --git a/core/src/main/java/com/google/common/truth/IterableSubject.java b/core/src/main/java/com/google/common/truth/IterableSubject.java
index bfb5dad2..bdafca93 100644
--- a/core/src/main/java/com/google/common/truth/IterableSubject.java
+++ b/core/src/main/java/com/google/common/truth/IterableSubject.java
@@ -58,6 +58,7 @@ import com.google.common.collect.Sets;
import com.google.common.truth.Correspondence.DiffFormatter;
import com.google.common.truth.SubjectUtils.DuplicateGroupedAndTyped;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.DoNotCall;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
@@ -89,7 +90,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
// Can't be final since MultisetSubject and SortedSetSubject extend it
public class IterableSubject extends Subject {
- private final Iterable<?> actual;
+ private final @Nullable Iterable<?> actual;
/**
* Constructor for use by subclasses. If you want to create an instance of this class itself, call
@@ -140,14 +141,14 @@ public class IterableSubject extends Subject {
/** Fails if the subject is not empty. */
public final void isEmpty() {
- if (!Iterables.isEmpty(actual)) {
+ if (!Iterables.isEmpty(checkNotNull(actual))) {
failWithActual(simpleFact("expected to be empty"));
}
}
/** Fails if the subject is empty. */
public final void isNotEmpty() {
- if (Iterables.isEmpty(actual)) {
+ if (Iterables.isEmpty(checkNotNull(actual))) {
failWithoutActual(simpleFact("expected not to be empty"));
}
}
@@ -155,14 +156,14 @@ public class IterableSubject extends Subject {
/** Fails if the subject does not have the given size. */
public final void hasSize(int expectedSize) {
checkArgument(expectedSize >= 0, "expectedSize(%s) must be >= 0", expectedSize);
- int actualSize = size(actual);
+ int actualSize = size(checkNotNull(actual));
check("size()").that(actualSize).isEqualTo(expectedSize);
}
/** Checks (with a side-effect failure) that the subject contains the supplied item. */
public final void contains(@Nullable Object element) {
- if (!Iterables.contains(actual, element)) {
- List<Object> elementList = newArrayList(element);
+ if (!Iterables.contains(checkNotNull(actual), element)) {
+ List<@Nullable Object> elementList = newArrayList(element);
if (hasMatchingToStringPair(actual, elementList)) {
failWithoutActual(
fact("expected to contain", element),
@@ -171,7 +172,7 @@ public class IterableSubject extends Subject {
fact(
"though it did contain",
countDuplicatesAndAddTypeInfo(
- retainMatchingToString(actual, elementList /* itemsToCheck */))),
+ retainMatchingToString(actual, /* itemsToCheck= */ elementList))),
fullContents());
} else {
failWithActual("expected to contain", element);
@@ -181,7 +182,7 @@ public class IterableSubject extends Subject {
/** Checks (with a side-effect failure) that the subject does not contain the supplied item. */
public final void doesNotContain(@Nullable Object element) {
- if (Iterables.contains(actual, element)) {
+ if (Iterables.contains(checkNotNull(actual), element)) {
failWithActual("expected not to contain", element);
}
}
@@ -189,7 +190,7 @@ public class IterableSubject extends Subject {
/** Checks that the subject does not contain duplicate elements. */
public final void containsNoDuplicates() {
List<Multiset.Entry<?>> duplicates = newArrayList();
- for (Multiset.Entry<?> entry : LinkedHashMultiset.create(actual).entrySet()) {
+ for (Multiset.Entry<?> entry : LinkedHashMultiset.create(checkNotNull(actual)).entrySet()) {
if (entry.getCount() > 1) {
duplicates.add(entry);
}
@@ -204,7 +205,7 @@ public class IterableSubject extends Subject {
/** Checks that the subject contains at least one of the provided objects or fails. */
public final void containsAnyOf(
- @Nullable Object first, @Nullable Object second, @Nullable Object /*@Nullable*/... rest) {
+ @Nullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest) {
containsAnyIn(accumulate(first, second, rest));
}
@@ -213,8 +214,9 @@ public class IterableSubject extends Subject {
* collection or fails.
*/
// TODO(cpovirk): Consider using makeElementFacts-style messages here, in contains(), etc.
- public final void containsAnyIn(Iterable<?> expected) {
- Collection<?> actual = iterableToCollection(this.actual);
+ public final void containsAnyIn(@Nullable Iterable<?> expected) {
+ checkNotNull(expected);
+ Collection<?> actual = iterableToCollection(checkNotNull(this.actual));
for (Object item : expected) {
if (actual.contains(item)) {
return;
@@ -227,7 +229,7 @@ public class IterableSubject extends Subject {
fact(
"though it did contain",
countDuplicatesAndAddTypeInfo(
- retainMatchingToString(this.actual, expected /* itemsToCheck */))),
+ retainMatchingToString(checkNotNull(this.actual), /* itemsToCheck= */ expected))),
fullContents());
} else {
failWithActual("expected to contain any of", expected);
@@ -238,6 +240,7 @@ public class IterableSubject extends Subject {
* Checks that the subject contains at least one of the objects contained in the provided array or
* fails.
*/
+ @SuppressWarnings("AvoidObjectArrays")
public final void containsAnyIn(Object[] expected) {
containsAnyIn(asList(expected));
}
@@ -255,7 +258,7 @@ public class IterableSubject extends Subject {
public final Ordered containsAtLeast(
@Nullable Object firstExpected,
@Nullable Object secondExpected,
- @Nullable Object /*@Nullable*/... restOfExpected) {
+ @Nullable Object @Nullable ... restOfExpected) {
return containsAtLeastElementsIn(accumulate(firstExpected, secondExpected, restOfExpected));
}
@@ -270,11 +273,11 @@ public class IterableSubject extends Subject {
*/
@CanIgnoreReturnValue
public final Ordered containsAtLeastElementsIn(Iterable<?> expectedIterable) {
- List<?> actual = Lists.newLinkedList(this.actual);
- final Collection<?> expected = iterableToCollection(expectedIterable);
+ List<?> actual = Lists.newLinkedList(checkNotNull(this.actual));
+ Collection<?> expected = iterableToCollection(expectedIterable);
- List<Object> missing = newArrayList();
- List<Object> actualNotInOrder = newArrayList();
+ List<@Nullable Object> missing = newArrayList();
+ List<@Nullable Object> actualNotInOrder = newArrayList();
boolean ordered = true;
// step through the expected elements...
@@ -298,22 +301,23 @@ public class IterableSubject extends Subject {
return failAtLeast(expected, missing);
}
- /*
- * TODO(cpovirk): In the NotInOrder case, also include a Fact that shows _only_ the required
- * elements (that is, without any extras) but in the order they were actually found. That should
- * make it easier for users to compare the actual order of the required elements to the expected
- * order. Or, if that's too much trouble, at least try to find a better title for the full
- * actual iterable than the default of "but was," which may _sound_ like it should show only the
- * required elements, rather than the full actual iterable.
- */
return ordered
? IN_ORDER
: new Ordered() {
@Override
public void inOrder() {
- failWithActual(
- simpleFact("required elements were all found, but order was wrong"),
- fact("expected order for required elements", expected));
+ ImmutableList.Builder<Fact> facts = ImmutableList.builder();
+ facts.add(simpleFact("required elements were all found, but order was wrong"));
+ facts.add(fact("expected order for required elements", expected));
+ List<Object> actualOrder =
+ Lists.newArrayList(checkNotNull(IterableSubject.this.actual));
+ if (actualOrder.retainAll(expected)) {
+ facts.add(fact("but order was", actualOrder));
+ facts.add(fullContents());
+ failWithoutActual(facts.build());
+ } else {
+ failWithActual(facts.build());
+ }
}
};
}
@@ -328,13 +332,14 @@ public class IterableSubject extends Subject {
* within the actual elements, but they are not required to be consecutive.
*/
@CanIgnoreReturnValue
+ @SuppressWarnings("AvoidObjectArrays")
public final Ordered containsAtLeastElementsIn(Object[] expected) {
return containsAtLeastElementsIn(asList(expected));
}
private Ordered failAtLeast(Collection<?> expected, Collection<?> missingRawObjects) {
- Collection<?> nearMissRawObjects =
- retainMatchingToString(actual, missingRawObjects /* itemsToCheck */);
+ List<?> nearMissRawObjects =
+ retainMatchingToString(checkNotNull(actual), /* itemsToCheck= */ missingRawObjects);
ImmutableList.Builder<Fact> facts = ImmutableList.builder();
facts.addAll(
@@ -359,7 +364,8 @@ public class IterableSubject extends Subject {
* Removes at most the given number of available elements from the input list and adds them to the
* given output collection.
*/
- private static void moveElements(List<?> input, Collection<Object> output, int maxElements) {
+ private static void moveElements(
+ List<?> input, Collection<@Nullable Object> output, int maxElements) {
for (int i = 0; i < maxElements; i++) {
output.add(input.remove(0));
}
@@ -379,8 +385,9 @@ public class IterableSubject extends Subject {
* elements, not an element itself. This helps human readers and avoids a compiler warning.
*/
@CanIgnoreReturnValue
- public final Ordered containsExactly(@Nullable Object /*@Nullable*/... varargs) {
- List<Object> expected = (varargs == null) ? newArrayList((Object) null) : asList(varargs);
+ public final Ordered containsExactly(@Nullable Object @Nullable ... varargs) {
+ List<@Nullable Object> expected =
+ (varargs == null) ? newArrayList((@Nullable Object) null) : asList(varargs);
return containsExactlyElementsIn(
expected, varargs != null && varargs.length == 1 && varargs[0] instanceof Iterable);
}
@@ -396,7 +403,7 @@ public class IterableSubject extends Subject {
* on the object returned by this method.
*/
@CanIgnoreReturnValue
- public final Ordered containsExactlyElementsIn(Iterable<?> expected) {
+ public final Ordered containsExactlyElementsIn(@Nullable Iterable<?> expected) {
return containsExactlyElementsIn(expected, false);
}
@@ -410,13 +417,19 @@ public class IterableSubject extends Subject {
* on the object returned by this method.
*/
@CanIgnoreReturnValue
- public final Ordered containsExactlyElementsIn(Object[] expected) {
- return containsExactlyElementsIn(asList(expected));
+ @SuppressWarnings({
+ "AvoidObjectArrays",
+ "ContainsExactlyElementsInUnnecessaryWrapperAroundArray",
+ "ContainsExactlyElementsInWithVarArgsToExactly"
+ })
+ public final Ordered containsExactlyElementsIn(@Nullable Object @Nullable [] expected) {
+ return containsExactlyElementsIn(asList(checkNotNull(expected)));
}
private Ordered containsExactlyElementsIn(
- final Iterable<?> required, boolean addElementsInWarning) {
- Iterator<?> actualIter = actual.iterator();
+ @Nullable Iterable<?> required, boolean addElementsInWarning) {
+ checkNotNull(required);
+ Iterator<?> actualIter = checkNotNull(actual).iterator();
Iterator<?> requiredIter = required.iterator();
if (!requiredIter.hasNext()) {
@@ -462,12 +475,12 @@ public class IterableSubject extends Subject {
return ALREADY_FAILED;
}
// Missing elements; elements that are not missing will be removed as we iterate.
- Collection<Object> missing = newArrayList();
+ List<@Nullable Object> missing = newArrayList();
missing.add(requiredElement);
Iterators.addAll(missing, requiredIter);
// Extra elements that the subject had but shouldn't have.
- Collection<Object> extra = newArrayList();
+ List<@Nullable Object> extra = newArrayList();
// Remove all actual elements from missing, and add any that weren't in missing
// to extra.
@@ -694,7 +707,7 @@ public class IterableSubject extends Subject {
public final void containsNoneOf(
@Nullable Object firstExcluded,
@Nullable Object secondExcluded,
- @Nullable Object /*@Nullable*/... restOfExcluded) {
+ @Nullable Object @Nullable ... restOfExcluded) {
containsNoneIn(accumulate(firstExcluded, secondExcluded, restOfExcluded));
}
@@ -704,8 +717,8 @@ public class IterableSubject extends Subject {
* elements equal any of the excluded.)
*/
public final void containsNoneIn(Iterable<?> excluded) {
- Collection<?> actual = iterableToCollection(this.actual);
- Collection<Object> present = new ArrayList<>();
+ Collection<?> actual = iterableToCollection(checkNotNull(this.actual));
+ List<@Nullable Object> present = new ArrayList<>();
for (Object item : Sets.newLinkedHashSet(excluded)) {
if (actual.contains(item)) {
present.add(item);
@@ -724,25 +737,16 @@ public class IterableSubject extends Subject {
* or fails. (Duplicates are irrelevant to this test, which fails if any of the actual elements
* equal any of the excluded.)
*/
- public final void containsNoneIn(Object[] excluded) {
+ @SuppressWarnings("AvoidObjectArrays")
+ public final void containsNoneIn(@Nullable Object[] excluded) {
containsNoneIn(asList(excluded));
}
/** Ordered implementation that does nothing because it's already known to be true. */
- @SuppressWarnings("UnnecessaryAnonymousClass") // for Java 7 compatibility
- private static final Ordered IN_ORDER =
- new Ordered() {
- @Override
- public void inOrder() {}
- };
+ private static final Ordered IN_ORDER = () -> {};
/** Ordered implementation that does nothing because an earlier check already caused a failure. */
- @SuppressWarnings("UnnecessaryAnonymousClass") // for Java 7 compatibility
- private static final Ordered ALREADY_FAILED =
- new Ordered() {
- @Override
- public void inOrder() {}
- };
+ private static final Ordered ALREADY_FAILED = () -> {};
/**
* Fails if the iterable is not strictly ordered, according to the natural ordering of its
@@ -774,14 +778,14 @@ public class IterableSubject extends Subject {
* @throws ClassCastException if any pair of elements is not mutually Comparable
*/
@SuppressWarnings({"unchecked"})
- public final void isInStrictOrder(final Comparator<?> comparator) {
+ public final void isInStrictOrder(Comparator<?> comparator) {
checkNotNull(comparator);
pairwiseCheck(
"expected to be in strict order",
new PairwiseChecker() {
@Override
- public boolean check(Object prev, Object next) {
- return ((Comparator<Object>) comparator).compare(prev, next) < 0;
+ public boolean check(@Nullable Object prev, @Nullable Object next) {
+ return ((Comparator<@Nullable Object>) comparator).compare(prev, next) < 0;
}
});
}
@@ -806,24 +810,24 @@ public class IterableSubject extends Subject {
* @throws ClassCastException if any pair of elements is not mutually Comparable
*/
@SuppressWarnings({"unchecked"})
- public final void isInOrder(final Comparator<?> comparator) {
+ public final void isInOrder(Comparator<?> comparator) {
checkNotNull(comparator);
pairwiseCheck(
"expected to be in order",
new PairwiseChecker() {
@Override
- public boolean check(Object prev, Object next) {
- return ((Comparator<Object>) comparator).compare(prev, next) <= 0;
+ public boolean check(@Nullable Object prev, @Nullable Object next) {
+ return ((Comparator<@Nullable Object>) comparator).compare(prev, next) <= 0;
}
});
}
private interface PairwiseChecker {
- boolean check(Object prev, Object next);
+ boolean check(@Nullable Object prev, @Nullable Object next);
}
private void pairwiseCheck(String expectedFact, PairwiseChecker checker) {
- Iterator<?> iterator = actual.iterator();
+ Iterator<?> iterator = checkNotNull(actual).iterator();
if (iterator.hasNext()) {
Object prev = iterator.next();
while (iterator.hasNext()) {
@@ -841,22 +845,27 @@ public class IterableSubject extends Subject {
}
}
- /** @deprecated You probably meant to call {@link #containsNoneOf} instead. */
+ /**
+ * @deprecated You probably meant to call {@link #containsNoneOf} instead.
+ */
@Override
@Deprecated
public void isNoneOf(
- @Nullable Object first, @Nullable Object second, @Nullable Object /*@Nullable*/... rest) {
+ @Nullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest) {
super.isNoneOf(first, second, rest);
}
- /** @deprecated You probably meant to call {@link #containsNoneIn} instead. */
+ /**
+ * @deprecated You probably meant to call {@link #containsNoneIn} instead.
+ */
@Override
@Deprecated
- public void isNotIn(Iterable<?> iterable) {
+ public void isNotIn(@Nullable Iterable<?> iterable) {
+ checkNotNull(iterable);
if (Iterables.contains(iterable, actual)) {
failWithActual("expected not to be any of", iterable);
}
- List<Object> nonIterables = new ArrayList<>();
+ List<@Nullable Object> nonIterables = new ArrayList<>();
for (Object element : iterable) {
if (!(element instanceof Iterable<?>)) {
nonIterables.add(element);
@@ -896,8 +905,9 @@ public class IterableSubject extends Subject {
* <p>Any of the methods on the returned object may throw {@link ClassCastException} if they
* encounter an actual element that is not of type {@code A}.
*/
- public <A, E> UsingCorrespondence<A, E> comparingElementsUsing(
- Correspondence<? super A, ? super E> correspondence) {
+ public <A extends @Nullable Object, E extends @Nullable Object>
+ UsingCorrespondence<A, E> comparingElementsUsing(
+ Correspondence<? super A, ? super E> correspondence) {
return new UsingCorrespondence<>(this, correspondence);
}
@@ -941,7 +951,7 @@ public class IterableSubject extends Subject {
* expected elements are of type {@code E}. Call methods on this object to actually execute the
* check.
*/
- public static class UsingCorrespondence<A, E> {
+ public static class UsingCorrespondence<A extends @Nullable Object, E extends @Nullable Object> {
private final IterableSubject subject;
private final Correspondence<? super A, ? super E> correspondence;
@@ -964,13 +974,54 @@ public class IterableSubject extends Subject {
}
/**
+ * @throws UnsupportedOperationException always
+ * @deprecated {@link Object#equals(Object)} is not supported on Truth subjects or intermediate
+ * classes. If you are writing a test assertion (actual vs. expected), use methods liks
+ * {@link #containsExactlyElementsIn(Iterable)} instead.
+ */
+ @DoNotCall(
+ "UsingCorrespondence.equals() is not supported. Did you mean to call"
+ + " containsExactlyElementsIn(expected) instead of equals(expected)?")
+ @Deprecated
+ @Override
+ public final boolean equals(@Nullable Object o) {
+ throw new UnsupportedOperationException(
+ "UsingCorrespondence.equals() is not supported. Did you mean to call"
+ + " containsExactlyElementsIn(expected) instead of equals(expected)?");
+ }
+
+ /**
+ * @throws UnsupportedOperationException always
+ * @deprecated {@link Object#hashCode()} is not supported on Truth types.
+ */
+ @DoNotCall("UsingCorrespondence.hashCode() is not supported.")
+ @Deprecated
+ @Override
+ public final int hashCode() {
+ throw new UnsupportedOperationException("UsingCorrespondence.hashCode() is not supported.");
+ }
+
+ /**
+ * @throws UnsupportedOperationException always
+ * @deprecated {@link Object#toString()} is not supported on Truth subjects.
+ */
+ @Deprecated
+ @DoNotCall("UsingCorrespondence.toString() is not supported.")
+ @Override
+ public final String toString() {
+ throw new UnsupportedOperationException(
+ "UsingCorrespondence.toString() is not supported. Did you mean to call"
+ + " assertThat(foo.toString()) instead of assertThat(foo).toString()?");
+ }
+
+ /**
* Specifies a way to pair up unexpected and missing elements in the message when an assertion
* fails. For example:
*
* <pre>{@code
* assertThat(actualRecords)
* .comparingElementsUsing(RECORD_CORRESPONDENCE)
- * .displayingDiffsPairedBy(Record::getId)
+ * .displayingDiffsPairedBy(MyRecord::getId)
* .containsExactlyElementsIn(expectedRecords);
* }</pre>
*
@@ -1056,7 +1107,12 @@ public class IterableSubject extends Subject {
* Checks that the subject contains at least one element that corresponds to the given expected
* element.
*/
- public void contains(@Nullable E expected) {
+ /*
+ * TODO(cpovirk): Do we want @Nullable on usages of E? Probably not, since it could throw errors
+ * during comparisons? Or maybe we should take the risk for user convenience? If we make
+ * changes, also make them in MapSubject, MultimapSubject, and possibly others.
+ */
+ public void contains(E expected) {
Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forIterable();
for (A actual : getCastActual()) {
if (correspondence.safeCompare(actual, expected, exceptions)) {
@@ -1106,7 +1162,7 @@ public class IterableSubject extends Subject {
}
/** Checks that none of the actual elements correspond to the given element. */
- public void doesNotContain(@Nullable E excluded) {
+ public void doesNotContain(E excluded) {
Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forIterable();
List<A> matchingElements = new ArrayList<>();
for (A actual : getCastActual()) {
@@ -1153,7 +1209,7 @@ public class IterableSubject extends Subject {
*/
@SafeVarargs
@CanIgnoreReturnValue
- public final Ordered containsExactly(@Nullable E /*@Nullable*/... expected) {
+ public final Ordered containsExactly(@Nullable E @Nullable ... expected) {
return containsExactlyElementsIn(
(expected == null) ? newArrayList((E) null) : asList(expected));
}
@@ -1167,9 +1223,9 @@ public class IterableSubject extends Subject {
* on the object returned by this method.
*/
@CanIgnoreReturnValue
- public Ordered containsExactlyElementsIn(final Iterable<? extends E> expected) {
+ public Ordered containsExactlyElementsIn(@Nullable Iterable<? extends E> expected) {
List<A> actualList = iterableToList(getCastActual());
- List<? extends E> expectedList = iterableToList(expected);
+ List<? extends E> expectedList = iterableToList(checkNotNull(expected));
if (expectedList.isEmpty()) {
if (actualList.isEmpty()) {
@@ -1244,8 +1300,9 @@ public class IterableSubject extends Subject {
* on the object returned by this method.
*/
@CanIgnoreReturnValue
- public Ordered containsExactlyElementsIn(E[] expected) {
- return containsExactlyElementsIn(asList(expected));
+ @SuppressWarnings("AvoidObjectArrays")
+ public Ordered containsExactlyElementsIn(E @Nullable [] expected) {
+ return containsExactlyElementsIn(asList(checkNotNull(expected)));
}
/**
@@ -1330,7 +1387,7 @@ public class IterableSubject extends Subject {
List<? extends A> extra,
Correspondence.ExceptionStore exceptions) {
if (pairer.isPresent()) {
- @Nullable Pairing pairing = pairer.get().pair(missing, extra, exceptions);
+ Pairing pairing = pairer.get().pair(missing, extra, exceptions);
if (pairing != null) {
return describeMissingOrExtraWithPairing(pairing, exceptions);
} else {
@@ -1383,11 +1440,11 @@ public class IterableSubject extends Subject {
E missing,
List<? extends A> extras,
Correspondence.ExceptionStore exceptions) {
- List<String> diffs = new ArrayList<>(extras.size());
+ List<@Nullable String> diffs = new ArrayList<>(extras.size());
boolean hasDiffs = false;
for (int i = 0; i < extras.size(); i++) {
A extra = extras.get(i);
- @Nullable String diff = correspondence.safeFormatDiff(extra, missing, exceptions);
+ String diff = correspondence.safeFormatDiff(extra, missing, exceptions);
diffs.add(diff);
if (diff != null) {
hasDiffs = true;
@@ -1414,7 +1471,8 @@ public class IterableSubject extends Subject {
* Returns all the elements of the given list other than those with the given indexes. Assumes
* that all the given indexes really are valid indexes into the list.
*/
- private <T> List<T> findNotIndexed(List<T> list, Set<Integer> indexes) {
+ private <T extends @Nullable Object> List<T> findNotIndexed(
+ List<T> list, Set<Integer> indexes) {
if (indexes.size() == list.size()) {
// If there are as many distinct valid indexes are there are elements in the list then every
// index must be in there once.
@@ -1503,8 +1561,7 @@ public class IterableSubject extends Subject {
*/
@SafeVarargs
@CanIgnoreReturnValue
- public final Ordered containsAtLeast(
- @Nullable E first, @Nullable E second, @Nullable E /*@Nullable*/... rest) {
+ public final Ordered containsAtLeast(E first, E second, E @Nullable ... rest) {
return containsAtLeastElementsIn(accumulate(first, second, rest));
}
@@ -1518,7 +1575,7 @@ public class IterableSubject extends Subject {
* subject, but they are not required to be consecutive.
*/
@CanIgnoreReturnValue
- public Ordered containsAtLeastElementsIn(final Iterable<? extends E> expected) {
+ public Ordered containsAtLeastElementsIn(Iterable<? extends E> expected) {
List<A> actualList = iterableToList(getCastActual());
List<? extends E> expectedList = iterableToList(expected);
// Check if the expected elements correspond in order to any subset of the actual elements.
@@ -1584,6 +1641,7 @@ public class IterableSubject extends Subject {
* subject, but they are not required to be consecutive.
*/
@CanIgnoreReturnValue
+ @SuppressWarnings("AvoidObjectArrays")
public Ordered containsAtLeastElementsIn(E[] expected) {
return containsAtLeastElementsIn(asList(expected));
}
@@ -1667,7 +1725,7 @@ public class IterableSubject extends Subject {
List<? extends A> extra,
Correspondence.ExceptionStore exceptions) {
if (pairer.isPresent()) {
- @Nullable Pairing pairing = pairer.get().pair(missing, extra, exceptions);
+ Pairing pairing = pairer.get().pair(missing, extra, exceptions);
if (pairing != null) {
return describeMissingWithPairing(pairing, exceptions);
} else {
@@ -1752,8 +1810,7 @@ public class IterableSubject extends Subject {
* expected elements.
*/
@SafeVarargs
- public final void containsAnyOf(
- @Nullable E first, @Nullable E second, @Nullable E /*@Nullable*/... rest) {
+ public final void containsAnyOf(E first, E second, E @Nullable ... rest) {
containsAnyIn(accumulate(first, second, rest));
}
@@ -1834,6 +1891,7 @@ public class IterableSubject extends Subject {
* Checks that the subject contains at least one element that corresponds to at least one of the
* expected elements.
*/
+ @SuppressWarnings("AvoidObjectArrays")
public void containsAnyIn(E[] expected) {
containsAnyIn(asList(expected));
}
@@ -1859,9 +1917,7 @@ public class IterableSubject extends Subject {
*/
@SafeVarargs
public final void containsNoneOf(
- @Nullable E firstExcluded,
- @Nullable E secondExcluded,
- @Nullable E /*@Nullable*/... restOfExcluded) {
+ E firstExcluded, E secondExcluded, E @Nullable ... restOfExcluded) {
containsNoneIn(accumulate(firstExcluded, secondExcluded, restOfExcluded));
}
@@ -1916,13 +1972,14 @@ public class IterableSubject extends Subject {
* (Duplicates are irrelevant to this test, which fails if any of the subject elements
* correspond to any of the given elements.)
*/
+ @SuppressWarnings("AvoidObjectArrays")
public void containsNoneIn(E[] excluded) {
containsNoneIn(asList(excluded));
}
@SuppressWarnings("unchecked") // throwing ClassCastException is the correct behaviour
private Iterable<A> getCastActual() {
- return (Iterable<A>) subject.actual;
+ return (Iterable<A>) checkNotNull(subject.actual);
}
// TODO(b/69154276): Consider commoning up some of the logic between IterableSubject.Pairer,
@@ -1950,8 +2007,7 @@ public class IterableSubject extends Subject {
* Returns a {@link Pairing} of the given expected and actual values, or {@code null} if the
* expected values are not uniquely keyed.
*/
- @Nullable
- Pairing pair(
+ @Nullable Pairing pair(
List<? extends E> expectedValues,
List<? extends A> actualValues,
Correspondence.ExceptionStore exceptions) {
@@ -1959,7 +2015,7 @@ public class IterableSubject extends Subject {
// Populate expectedKeys with the keys of the corresponding elements of expectedValues.
// We do this ahead of time to avoid invoking the key function twice for each element.
- List<Object> expectedKeys = new ArrayList<>(expectedValues.size());
+ List<@Nullable Object> expectedKeys = new ArrayList<>(expectedValues.size());
for (E expected : expectedValues) {
expectedKeys.add(expectedKey(expected, exceptions));
}
@@ -1968,7 +2024,7 @@ public class IterableSubject extends Subject {
// We will remove the unpaired keys later. Return null if we find a duplicate key.
for (int i = 0; i < expectedValues.size(); i++) {
E expected = expectedValues.get(i);
- @Nullable Object key = expectedKeys.get(i);
+ Object key = expectedKeys.get(i);
if (key != null) {
if (pairing.pairedKeysToExpectedValues.containsKey(key)) {
return null;
@@ -1980,9 +2036,9 @@ public class IterableSubject extends Subject {
// Populate pairedKeysToActualValues and unpairedActualValues.
for (A actual : actualValues) {
- @Nullable Object key = actualKey(actual, exceptions);
+ Object key = actualKey(actual, exceptions);
if (pairing.pairedKeysToExpectedValues.containsKey(key)) {
- pairing.pairedKeysToActualValues.put(key, actual);
+ pairing.pairedKeysToActualValues.put(checkNotNull(key), actual);
} else {
pairing.unpairedActualValues.add(actual);
}
@@ -1991,7 +2047,7 @@ public class IterableSubject extends Subject {
// Populate unpairedExpectedValues and remove unpaired keys from pairedKeysToExpectedValues.
for (int i = 0; i < expectedValues.size(); i++) {
E expected = expectedValues.get(i);
- @Nullable Object key = expectedKeys.get(i);
+ Object key = expectedKeys.get(i);
if (!pairing.pairedKeysToActualValues.containsKey(key)) {
pairing.unpairedExpectedValues.add(expected);
pairing.pairedKeysToExpectedValues.remove(key);
@@ -2005,7 +2061,7 @@ public class IterableSubject extends Subject {
E expectedValue,
Iterable<? extends A> actualValues,
Correspondence.ExceptionStore exceptions) {
- @Nullable Object key = expectedKey(expectedValue, exceptions);
+ Object key = expectedKey(expectedValue, exceptions);
List<A> matches = new ArrayList<>();
if (key != null) {
for (A actual : actualValues) {
@@ -2038,7 +2094,7 @@ public class IterableSubject extends Subject {
}
}
- /** An description of a pairing between expected and actual values. N.B. This is mutable. */
+ /** A description of a pairing between expected and actual values. N.B. This is mutable. */
private final class Pairing {
/**
diff --git a/core/src/main/java/com/google/common/truth/J2ktIncompatible.java b/core/src/main/java/com/google/common/truth/J2ktIncompatible.java
new file mode 100644
index 00000000..45e14be0
--- /dev/null
+++ b/core/src/main/java/com/google/common/truth/J2ktIncompatible.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Guava Authors
+ *
+ * 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 com.google.common.annotations.GwtCompatible;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The presence of this annotation on an API indicates that the method may <em>not</em> be used with
+ * J2kt. This can be removed once we can safely depend on a Guava release that contains it.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
+@GwtCompatible
+@interface J2ktIncompatible {}
diff --git a/core/src/main/java/com/google/common/truth/LazyMessage.java b/core/src/main/java/com/google/common/truth/LazyMessage.java
index aa5b3c54..2e6861a7 100644
--- a/core/src/main/java/com/google/common/truth/LazyMessage.java
+++ b/core/src/main/java/com/google/common/truth/LazyMessage.java
@@ -20,19 +20,22 @@ import static com.google.common.base.Strings.lenientFormat;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
+import org.checkerframework.checker.nullness.qual.Nullable;
final class LazyMessage {
- private static final String PLACEHOLDER_ERR =
- "Incorrect number of args (%s) for the given placeholders (%s) in string template:\"%s\"";
-
private final String format;
- private final Object[] args;
+ private final @Nullable Object[] args;
- LazyMessage(String format, /*@Nullable*/ Object... args) {
+ LazyMessage(String format, @Nullable Object... args) {
this.format = format;
this.args = args;
int placeholders = countPlaceholders(format);
- checkArgument(placeholders == args.length, PLACEHOLDER_ERR, args.length, placeholders, format);
+ checkArgument(
+ placeholders == args.length,
+ "Incorrect number of args (%s) for the given placeholders (%s) in string template:\"%s\"",
+ args.length,
+ placeholders,
+ format);
}
@Override
diff --git a/core/src/main/java/com/google/common/truth/LongSubject.java b/core/src/main/java/com/google/common/truth/LongSubject.java
index 27f99f54..d56de24d 100644
--- a/core/src/main/java/com/google/common/truth/LongSubject.java
+++ b/core/src/main/java/com/google/common/truth/LongSubject.java
@@ -33,10 +33,12 @@ public class LongSubject extends ComparableSubject<Long> {
super(metadata, actual);
}
- /** @deprecated Use {@link #isEqualTo} instead. Long comparison is consistent with equality. */
+ /**
+ * @deprecated Use {@link #isEqualTo} instead. Long comparison is consistent with equality.
+ */
@Override
@Deprecated
- public final void isEquivalentAccordingToCompareTo(Long other) {
+ public final void isEquivalentAccordingToCompareTo(@Nullable Long other) {
super.isEquivalentAccordingToCompareTo(other);
}
diff --git a/core/src/main/java/com/google/common/truth/MapSubject.java b/core/src/main/java/com/google/common/truth/MapSubject.java
index 6315a8e8..a74f1752 100644
--- a/core/src/main/java/com/google/common/truth/MapSubject.java
+++ b/core/src/main/java/com/google/common/truth/MapSubject.java
@@ -51,7 +51,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Kurt Alfred Kluever
*/
public class MapSubject extends Subject {
- private final Map<?, ?> actual;
+ private final @Nullable Map<?, ?> actual;
/**
* Constructor for use by subclasses. If you want to create an instance of this class itself, call
@@ -80,14 +80,14 @@ public class MapSubject extends Subject {
/** Fails if the map is not empty. */
public final void isEmpty() {
- if (!actual.isEmpty()) {
+ if (!checkNotNull(actual).isEmpty()) {
failWithActual(simpleFact("expected to be empty"));
}
}
/** Fails if the map is empty. */
public final void isNotEmpty() {
- if (actual.isEmpty()) {
+ if (checkNotNull(actual).isEmpty()) {
failWithoutActual(simpleFact("expected not to be empty"));
}
}
@@ -95,25 +95,26 @@ public class MapSubject extends Subject {
/** Fails if the map does not have the given size. */
public final void hasSize(int expectedSize) {
checkArgument(expectedSize >= 0, "expectedSize (%s) must be >= 0", expectedSize);
- check("size()").that(actual.size()).isEqualTo(expectedSize);
+ check("size()").that(checkNotNull(actual).size()).isEqualTo(expectedSize);
}
/** Fails if the map does not contain the given key. */
public final void containsKey(@Nullable Object key) {
- check("keySet()").that(actual.keySet()).contains(key);
+ check("keySet()").that(checkNotNull(actual).keySet()).contains(key);
}
/** Fails if the map contains the given key. */
public final void doesNotContainKey(@Nullable Object key) {
- check("keySet()").that(actual.keySet()).doesNotContain(key);
+ check("keySet()").that(checkNotNull(actual).keySet()).doesNotContain(key);
}
/** Fails if the map does not contain the given entry. */
public final void containsEntry(@Nullable Object key, @Nullable Object value) {
- Map.Entry<Object, Object> entry = immutableEntry(key, value);
+ Map.Entry<@Nullable Object, @Nullable Object> entry = immutableEntry(key, value);
+ checkNotNull(actual);
if (!actual.entrySet().contains(entry)) {
- List<Object> keyList = singletonList(key);
- List<Object> valueList = singletonList(value);
+ List<@Nullable Object> keyList = singletonList(key);
+ List<@Nullable Object> valueList = singletonList(value);
if (actual.containsKey(key)) {
Object actualValue = actual.get(key);
/*
@@ -138,7 +139,7 @@ public class MapSubject extends Subject {
retainMatchingToString(actual.keySet(), /* itemsToCheck= */ keyList))),
fact("full contents", actualCustomStringRepresentationForPackageMembersToCall()));
} else if (actual.containsValue(value)) {
- Set<Object> keys = new LinkedHashSet<>();
+ Set<@Nullable Object> keys = new LinkedHashSet<>();
for (Map.Entry<?, ?> actualEntry : actual.entrySet()) {
if (Objects.equal(actualEntry.getValue(), value)) {
keys.add(actualEntry.getKey());
@@ -168,7 +169,7 @@ public class MapSubject extends Subject {
/** Fails if the map contains the given entry. */
public final void doesNotContainEntry(@Nullable Object key, @Nullable Object value) {
checkNoNeedToDisplayBothValues("entrySet()")
- .that(actual.entrySet())
+ .that(checkNotNull(actual).entrySet())
.doesNotContain(immutableEntry(key, value));
}
@@ -188,27 +189,27 @@ public class MapSubject extends Subject {
*/
@CanIgnoreReturnValue
public final Ordered containsExactly(
- @Nullable Object k0, @Nullable Object v0, /*@Nullable*/ Object... rest) {
+ @Nullable Object k0, @Nullable Object v0, @Nullable Object... rest) {
return containsExactlyEntriesIn(accumulateMap("containsExactly", k0, v0, rest));
}
@CanIgnoreReturnValue
public final Ordered containsAtLeast(
- @Nullable Object k0, @Nullable Object v0, /*@Nullable*/ Object... rest) {
+ @Nullable Object k0, @Nullable Object v0, @Nullable Object... rest) {
return containsAtLeastEntriesIn(accumulateMap("containsAtLeast", k0, v0, rest));
}
- private static Map<Object, Object> accumulateMap(
- String functionName, @Nullable Object k0, @Nullable Object v0, /*@Nullable*/ Object... rest) {
+ private static Map<@Nullable Object, @Nullable Object> accumulateMap(
+ String functionName, @Nullable Object k0, @Nullable Object v0, @Nullable Object... rest) {
checkArgument(
rest.length % 2 == 0,
"There must be an equal number of key/value pairs "
+ "(i.e., the number of key/value parameters (%s) must be even).",
rest.length + 2);
- Map<Object, Object> expectedMap = Maps.newLinkedHashMap();
+ Map<@Nullable Object, @Nullable Object> expectedMap = Maps.newLinkedHashMap();
expectedMap.put(k0, v0);
- Multiset<Object> keys = LinkedHashMultiset.create();
+ Multiset<@Nullable Object> keys = LinkedHashMultiset.create();
keys.add(k0);
for (int i = 0; i < rest.length; i += 2) {
Object key = rest[i];
@@ -227,7 +228,7 @@ public class MapSubject extends Subject {
@CanIgnoreReturnValue
public final Ordered containsExactlyEntriesIn(Map<?, ?> expectedMap) {
if (expectedMap.isEmpty()) {
- if (actual.isEmpty()) {
+ if (checkNotNull(actual).isEmpty()) {
return IN_ORDER;
} else {
isEmpty(); // fails
@@ -236,8 +237,7 @@ public class MapSubject extends Subject {
}
boolean containsAnyOrder = containsEntriesInAnyOrder(expectedMap, /* allowUnexpected= */ false);
if (containsAnyOrder) {
- return new MapInOrder(
- expectedMap, /* allowUnexpected = */ false, /* correspondence = */ null);
+ return new MapInOrder(expectedMap, /* allowUnexpected= */ false, /* correspondence= */ null);
} else {
return ALREADY_FAILED;
}
@@ -251,7 +251,7 @@ public class MapSubject extends Subject {
}
boolean containsAnyOrder = containsEntriesInAnyOrder(expectedMap, /* allowUnexpected= */ true);
if (containsAnyOrder) {
- return new MapInOrder(expectedMap, /* allowUnexpected = */ true, /* correspondence = */ null);
+ return new MapInOrder(expectedMap, /* allowUnexpected= */ true, /* correspondence= */ null);
} else {
return ALREADY_FAILED;
}
@@ -259,8 +259,8 @@ public class MapSubject extends Subject {
@CanIgnoreReturnValue
private boolean containsEntriesInAnyOrder(Map<?, ?> expectedMap, boolean allowUnexpected) {
- MapDifference<Object, Object, Object> diff =
- MapDifference.create(actual, expectedMap, allowUnexpected, EQUALITY);
+ MapDifference<@Nullable Object, @Nullable Object, @Nullable Object> diff =
+ MapDifference.create(checkNotNull(actual), expectedMap, allowUnexpected, Objects::equal);
if (diff.isEmpty()) {
return true;
}
@@ -276,7 +276,7 @@ public class MapSubject extends Subject {
// present with the wrong value, which may be the closest we currently get to this.)
failWithoutActual(
ImmutableList.<Fact>builder()
- .addAll(diff.describe(/* differ = */ null))
+ .addAll(diff.describe(/* differ= */ null))
.add(simpleFact("---"))
.add(fact(allowUnexpected ? "expected to contain at least" : "expected", expectedMap))
.add(butWas())
@@ -284,37 +284,30 @@ public class MapSubject extends Subject {
return false;
}
- private interface ValueTester<A, E> {
- boolean test(@Nullable A actualValue, @Nullable E expectedValue);
+ private interface ValueTester<A extends @Nullable Object, E extends @Nullable Object> {
+ boolean test(A actualValue, E expectedValue);
}
- @SuppressWarnings("UnnecessaryAnonymousClass") // for Java 7 compatibility
- private static final ValueTester<Object, Object> EQUALITY =
- new ValueTester<Object, Object>() {
- @Override
- public boolean test(@Nullable Object actualValue, @Nullable Object expectedValue) {
- return Objects.equal(actualValue, expectedValue);
- }
- };
-
- private interface Differ<A, E> {
- String diff(A actual, E expected);
+ private interface Differ<A extends @Nullable Object, E extends @Nullable Object> {
+ @Nullable String diff(A actual, E expected);
}
// This is mostly like the MapDifference code in com.google.common.collect, generalized to remove
// the requirement that the values of the two maps are of the same type and are compared with a
// symmetric Equivalence.
- private static class MapDifference<K, A, E> {
+ private static class MapDifference<
+ K extends @Nullable Object, A extends @Nullable Object, E extends @Nullable Object> {
private final Map<K, E> missing;
private final Map<K, A> unexpected;
private final Map<K, ValueDifference<A, E>> wrongValues;
private final Set<K> allKeys;
- static <K, A, E> MapDifference<K, A, E> create(
- Map<? extends K, ? extends A> actual,
- Map<? extends K, ? extends E> expected,
- boolean allowUnexpected,
- ValueTester<? super A, ? super E> valueTester) {
+ static <K extends @Nullable Object, A extends @Nullable Object, E extends @Nullable Object>
+ MapDifference<K, A, E> create(
+ Map<? extends K, ? extends A> actual,
+ Map<? extends K, ? extends E> expected,
+ boolean allowUnexpected,
+ ValueTester<? super A, ? super E> valueTester) {
Map<K, A> unexpected = new LinkedHashMap<>(actual);
Map<K, E> missing = new LinkedHashMap<>();
Map<K, ValueDifference<A, E>> wrongValues = new LinkedHashMap<>();
@@ -322,7 +315,8 @@ public class MapSubject extends Subject {
K expectedKey = expectedEntry.getKey();
E expectedValue = expectedEntry.getValue();
if (actual.containsKey(expectedKey)) {
- A actualValue = unexpected.remove(expectedKey);
+ @SuppressWarnings("UnnecessaryCast") // needed by nullness checker
+ A actualValue = (A) unexpected.remove(expectedKey);
if (!valueTester.test(actualValue, expectedValue)) {
wrongValues.put(expectedKey, new ValueDifference<>(actualValue, expectedValue));
}
@@ -390,11 +384,11 @@ public class MapSubject extends Subject {
}
}
- private static class ValueDifference<A, E> {
+ private static class ValueDifference<A extends @Nullable Object, E extends @Nullable Object> {
private final A actual;
private final E expected;
- ValueDifference(@Nullable A actual, @Nullable E expected) {
+ ValueDifference(A actual, E expected) {
this.actual = actual;
this.expected = expected;
}
@@ -417,7 +411,7 @@ public class MapSubject extends Subject {
}
}
- private static String maybeAddType(Object object, boolean includeTypes) {
+ private static String maybeAddType(@Nullable Object object, boolean includeTypes) {
return includeTypes
? lenientFormat("%s (%s)", object, objectToTypeName(object))
: String.valueOf(object);
@@ -447,6 +441,7 @@ public class MapSubject extends Subject {
@Override
public void inOrder() {
// We're using the fact that Sets.intersection keeps the order of the first set.
+ checkNotNull(actual);
List<?> expectedKeyOrder =
Lists.newArrayList(Sets.intersection(expectedMap.keySet(), actual.keySet()));
List<?> actualKeyOrder =
@@ -472,20 +467,10 @@ public class MapSubject extends Subject {
}
/** Ordered implementation that does nothing because it's already known to be true. */
- @SuppressWarnings("UnnecessaryAnonymousClass") // for Java 7 compatibility
- private static final Ordered IN_ORDER =
- new Ordered() {
- @Override
- public void inOrder() {}
- };
+ private static final Ordered IN_ORDER = () -> {};
/** Ordered implementation that does nothing because an earlier check already caused a failure. */
- @SuppressWarnings("UnnecessaryAnonymousClass") // for Java 7 compatibility
- private static final Ordered ALREADY_FAILED =
- new Ordered() {
- @Override
- public void inOrder() {}
- };
+ private static final Ordered ALREADY_FAILED = () -> {};
/**
* Starts a method chain for a check in which the actual values (i.e. the values of the {@link
@@ -509,8 +494,9 @@ public class MapSubject extends Subject {
* encounter an actual value that is not of type {@code A} or an expected value that is not of
* type {@code E}.
*/
- public final <A, E> UsingCorrespondence<A, E> comparingValuesUsing(
- Correspondence<? super A, ? super E> correspondence) {
+ public final <A extends @Nullable Object, E extends @Nullable Object>
+ UsingCorrespondence<A, E> comparingValuesUsing(
+ Correspondence<? super A, ? super E> correspondence) {
return new UsingCorrespondence<>(correspondence);
}
@@ -552,7 +538,7 @@ public class MapSubject extends Subject {
*
* <p>Note that keys will always be compared with regular object equality ({@link Object#equals}).
*/
- public final class UsingCorrespondence<A, E> {
+ public final class UsingCorrespondence<A extends @Nullable Object, E extends @Nullable Object> {
private final Correspondence<? super A, ? super E> correspondence;
@@ -564,18 +550,19 @@ public class MapSubject extends Subject {
* Fails if the map does not contain an entry with the given key and a value that corresponds to
* the given value.
*/
- public void containsEntry(@Nullable Object expectedKey, @Nullable E expectedValue) {
- if (actual.containsKey(expectedKey)) {
+ @SuppressWarnings("UnnecessaryCast") // needed by nullness checker
+ public void containsEntry(@Nullable Object expectedKey, E expectedValue) {
+ if (checkNotNull(actual).containsKey(expectedKey)) {
// Found matching key.
A actualValue = getCastSubject().get(expectedKey);
Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forMapValues();
- if (correspondence.safeCompare(actualValue, expectedValue, exceptions)) {
+ if (correspondence.safeCompare((A) actualValue, expectedValue, exceptions)) {
// The expected key had the expected value. There's no need to check exceptions here,
// because if Correspondence.compare() threw then safeCompare() would return false.
return;
}
// Found matching key with non-matching value.
- String diff = correspondence.safeFormatDiff(actualValue, expectedValue, exceptions);
+ String diff = correspondence.safeFormatDiff((A) actualValue, expectedValue, exceptions);
if (diff != null) {
failWithoutActual(
ImmutableList.<Fact>builder()
@@ -600,7 +587,7 @@ public class MapSubject extends Subject {
}
} else {
// Did not find matching key. Look for the matching value with a different key.
- Set<Object> keys = new LinkedHashSet<>();
+ Set<@Nullable Object> keys = new LinkedHashSet<>();
Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forMapValues();
for (Map.Entry<?, A> actualEntry : getCastSubject().entrySet()) {
if (correspondence.safeCompare(actualEntry.getValue(), expectedValue, exceptions)) {
@@ -638,12 +625,13 @@ public class MapSubject extends Subject {
* Fails if the map contains an entry with the given key and a value that corresponds to the
* given value.
*/
- public void doesNotContainEntry(@Nullable Object excludedKey, @Nullable E excludedValue) {
- if (actual.containsKey(excludedKey)) {
+ @SuppressWarnings("UnnecessaryCast") // needed by nullness checker
+ public void doesNotContainEntry(@Nullable Object excludedKey, E excludedValue) {
+ if (checkNotNull(actual).containsKey(excludedKey)) {
// Found matching key. Fail if the value matches, too.
A actualValue = getCastSubject().get(excludedKey);
Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forMapValues();
- if (correspondence.safeCompare(actualValue, excludedValue, exceptions)) {
+ if (correspondence.safeCompare((A) actualValue, excludedValue, exceptions)) {
// The matching key had a matching value. There's no need to check exceptions here,
// because if Correspondence.compare() threw then safeCompare() would return false.
failWithoutActual(
@@ -682,8 +670,7 @@ public class MapSubject extends Subject {
// TODO(b/25744307): Can we add an error-prone check that rest.length % 2 == 0?
// For bonus points, checking that the even-numbered values are of type E would be sweet.
@CanIgnoreReturnValue
- public Ordered containsExactly(
- @Nullable Object k0, @Nullable E v0, /*@Nullable*/ Object... rest) {
+ public Ordered containsExactly(@Nullable Object k0, @Nullable E v0, @Nullable Object... rest) {
@SuppressWarnings("unchecked") // throwing ClassCastException is the correct behaviour
Map<Object, E> expectedMap = (Map<Object, E>) accumulateMap("containsExactly", k0, v0, rest);
return containsExactlyEntriesIn(expectedMap);
@@ -702,8 +689,7 @@ public class MapSubject extends Subject {
// TODO(b/25744307): Can we add an error-prone check that rest.length % 2 == 0?
// For bonus points, checking that the even-numbered values are of type E would be sweet.
@CanIgnoreReturnValue
- public Ordered containsAtLeast(
- @Nullable Object k0, @Nullable E v0, /*@Nullable*/ Object... rest) {
+ public Ordered containsAtLeast(@Nullable Object k0, @Nullable E v0, @Nullable Object... rest) {
@SuppressWarnings("unchecked") // throwing ClassCastException is the correct behaviour
Map<Object, E> expectedMap = (Map<Object, E>) accumulateMap("containsAtLeast", k0, v0, rest);
return containsAtLeastEntriesIn(expectedMap);
@@ -716,14 +702,14 @@ public class MapSubject extends Subject {
@CanIgnoreReturnValue
public Ordered containsExactlyEntriesIn(Map<?, ? extends E> expectedMap) {
if (expectedMap.isEmpty()) {
- if (actual.isEmpty()) {
+ if (checkNotNull(actual).isEmpty()) {
return IN_ORDER;
} else {
isEmpty(); // fails
return ALREADY_FAILED;
}
}
- return internalContainsEntriesIn(expectedMap, /* allowUnexpected = */ false);
+ return internalContainsEntriesIn(expectedMap, /* allowUnexpected= */ false);
}
/**
@@ -735,13 +721,13 @@ public class MapSubject extends Subject {
if (expectedMap.isEmpty()) {
return IN_ORDER;
}
- return internalContainsEntriesIn(expectedMap, /* allowUnexpected = */ true);
+ return internalContainsEntriesIn(expectedMap, /* allowUnexpected= */ true);
}
- private <K, V extends E> Ordered internalContainsEntriesIn(
+ private <K extends @Nullable Object, V extends E> Ordered internalContainsEntriesIn(
Map<K, V> expectedMap, boolean allowUnexpected) {
- final Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forMapValues();
- MapDifference<Object, A, V> diff =
+ Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forMapValues();
+ MapDifference<@Nullable Object, A, V> diff =
MapDifference.create(
getCastSubject(),
expectedMap,
@@ -770,19 +756,13 @@ public class MapSubject extends Subject {
return ALREADY_FAILED;
}
- @SuppressWarnings("UnnecessaryAnonymousClass") // for Java 7 compatibility
- private <V extends E> Differ<A, V> differ(final Correspondence.ExceptionStore exceptions) {
- return new Differ<A, V>() {
- @Override
- public String diff(A actual, V expected) {
- return correspondence.safeFormatDiff(actual, expected, exceptions);
- }
- };
+ private <V extends E> Differ<A, V> differ(Correspondence.ExceptionStore exceptions) {
+ return (actual, expected) -> correspondence.safeFormatDiff(actual, expected, exceptions);
}
@SuppressWarnings("unchecked") // throwing ClassCastException is the correct behaviour
private Map<?, A> getCastSubject() {
- return (Map<?, A>) actual;
+ return (Map<?, A>) checkNotNull(actual);
}
}
}
diff --git a/core/src/main/java/com/google/common/truth/MultimapSubject.java b/core/src/main/java/com/google/common/truth/MultimapSubject.java
index 332da4ae..4a02216f 100644
--- a/core/src/main/java/com/google/common/truth/MultimapSubject.java
+++ b/core/src/main/java/com/google/common/truth/MultimapSubject.java
@@ -40,6 +40,7 @@ import com.google.common.collect.Sets;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
@@ -56,14 +57,9 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public class MultimapSubject extends Subject {
/** Ordered implementation that does nothing because an earlier check already caused a failure. */
- @SuppressWarnings("UnnecessaryAnonymousClass") // for Java 7 compatibility
- private static final Ordered ALREADY_FAILED =
- new Ordered() {
- @Override
- public void inOrder() {}
- };
+ private static final Ordered ALREADY_FAILED = () -> {};
- private final Multimap<?, ?> actual;
+ private final @Nullable Multimap<?, ?> actual;
/**
* Constructor for use by subclasses. If you want to create an instance of this class itself, call
@@ -83,14 +79,14 @@ public class MultimapSubject extends Subject {
/** Fails if the multimap is not empty. */
public final void isEmpty() {
- if (!actual.isEmpty()) {
+ if (!checkNotNull(actual).isEmpty()) {
failWithActual(simpleFact("expected to be empty"));
}
}
/** Fails if the multimap is empty. */
public final void isNotEmpty() {
- if (actual.isEmpty()) {
+ if (checkNotNull(actual).isEmpty()) {
failWithoutActual(simpleFact("expected not to be empty"));
}
}
@@ -98,25 +94,27 @@ public class MultimapSubject extends Subject {
/** Fails if the multimap does not have the given size. */
public final void hasSize(int expectedSize) {
checkArgument(expectedSize >= 0, "expectedSize(%s) must be >= 0", expectedSize);
- check("size()").that(actual.size()).isEqualTo(expectedSize);
+ check("size()").that(checkNotNull(actual).size()).isEqualTo(expectedSize);
}
/** Fails if the multimap does not contain the given key. */
public final void containsKey(@Nullable Object key) {
- check("keySet()").that(actual.keySet()).contains(key);
+ check("keySet()").that(checkNotNull(actual).keySet()).contains(key);
}
/** Fails if the multimap contains the given key. */
public final void doesNotContainKey(@Nullable Object key) {
- check("keySet()").that(actual.keySet()).doesNotContain(key);
+ check("keySet()").that(checkNotNull(actual).keySet()).doesNotContain(key);
}
/** Fails if the multimap does not contain the given entry. */
public final void containsEntry(@Nullable Object key, @Nullable Object value) {
// TODO(kak): Can we share any of this logic w/ MapSubject.containsEntry()?
+ checkNotNull(actual);
if (!actual.containsEntry(key, value)) {
- Map.Entry<Object, Object> entry = immutableEntry(key, value);
- List<Map.Entry<Object, Object>> entryList = ImmutableList.of(entry);
+ Map.Entry<@Nullable Object, @Nullable Object> entry = immutableEntry(key, value);
+ ImmutableList<Map.Entry<@Nullable Object, @Nullable Object>> entryList =
+ ImmutableList.of(entry);
// TODO(cpovirk): If the key is present but not with the right value, we could fail using
// something like valuesForKey(key).contains(value). Consider whether this is worthwhile.
if (hasMatchingToStringPair(actual.entries(), entryList)) {
@@ -136,7 +134,7 @@ public class MultimapSubject extends Subject {
fact("though it did contain values with that key", actual.asMap().get(key)),
fact("full contents", actualCustomStringRepresentationForPackageMembersToCall()));
} else if (actual.containsValue(value)) {
- Set<Object> keys = new LinkedHashSet<>();
+ Set<@Nullable Object> keys = new LinkedHashSet<>();
for (Map.Entry<?, ?> actualEntry : actual.entries()) {
if (Objects.equal(actualEntry.getValue(), value)) {
keys.add(actualEntry.getKey());
@@ -156,7 +154,7 @@ public class MultimapSubject extends Subject {
/** Fails if the multimap contains the given entry. */
public final void doesNotContainEntry(@Nullable Object key, @Nullable Object value) {
checkNoNeedToDisplayBothValues("entries()")
- .that(actual.entries())
+ .that(checkNotNull(actual).entries())
.doesNotContain(immutableEntry(key, value));
}
@@ -177,7 +175,8 @@ public class MultimapSubject extends Subject {
* currently they must perform it _after_.
*/
public IterableSubject valuesForKey(@Nullable Object key) {
- return check("valuesForKey(%s)", key).that(((Multimap<Object, Object>) actual).get(key));
+ return check("valuesForKey(%s)", key)
+ .that(((Multimap<@Nullable Object, @Nullable Object>) checkNotNull(actual)).get(key));
}
@Override
@@ -202,9 +201,9 @@ public class MultimapSubject extends Subject {
lenientFormat(
"a %s cannot equal a %s if either is non-empty", actualType, otherType)));
} else if (actual instanceof ListMultimap) {
- containsExactlyEntriesIn((Multimap<?, ?>) other).inOrder();
+ containsExactlyEntriesIn((Multimap<?, ?>) checkNotNull(other)).inOrder();
} else if (actual instanceof SetMultimap) {
- containsExactlyEntriesIn((Multimap<?, ?>) other);
+ containsExactlyEntriesIn((Multimap<?, ?>) checkNotNull(other));
} else {
super.isEqualTo(other);
}
@@ -221,6 +220,7 @@ public class MultimapSubject extends Subject {
@CanIgnoreReturnValue
public final Ordered containsExactlyEntriesIn(Multimap<?, ?> expectedMultimap) {
checkNotNull(expectedMultimap, "expectedMultimap");
+ checkNotNull(actual);
ListMultimap<?, ?> missing = difference(expectedMultimap, actual);
ListMultimap<?, ?> extra = difference(actual, expectedMultimap);
@@ -276,6 +276,7 @@ public class MultimapSubject extends Subject {
@CanIgnoreReturnValue
public final Ordered containsAtLeastEntriesIn(Multimap<?, ?> expectedMultimap) {
checkNotNull(expectedMultimap, "expectedMultimap");
+ checkNotNull(actual);
ListMultimap<?, ?> missing = difference(expectedMultimap, actual);
// TODO(kak): Possible enhancement: Include "[1 copy]" if the element does appear in
@@ -293,8 +294,9 @@ public class MultimapSubject extends Subject {
/** Fails if the multimap is not empty. */
@CanIgnoreReturnValue
+ @SuppressWarnings("deprecation") // TODO(b/134064106): design an alternative to no-arg check()
public final Ordered containsExactly() {
- return check().about(iterableEntries()).that(actual.entries()).containsExactly();
+ return check().about(iterableEntries()).that(checkNotNull(actual).entries()).containsExactly();
}
/**
@@ -305,7 +307,7 @@ public class MultimapSubject extends Subject {
*/
@CanIgnoreReturnValue
public final Ordered containsExactly(
- @Nullable Object k0, @Nullable Object v0, /*@Nullable*/ Object... rest) {
+ @Nullable Object k0, @Nullable Object v0, @Nullable Object... rest) {
return containsExactlyEntriesIn(accumulateMultimap(k0, v0, rest));
}
@@ -317,19 +319,20 @@ public class MultimapSubject extends Subject {
*/
@CanIgnoreReturnValue
public final Ordered containsAtLeast(
- @Nullable Object k0, @Nullable Object v0, /*@Nullable*/ Object... rest) {
+ @Nullable Object k0, @Nullable Object v0, @Nullable Object... rest) {
return containsAtLeastEntriesIn(accumulateMultimap(k0, v0, rest));
}
- private static Multimap<Object, Object> accumulateMultimap(
- @Nullable Object k0, @Nullable Object v0, /*@Nullable*/ Object... rest) {
+ private static ListMultimap<@Nullable Object, @Nullable Object> accumulateMultimap(
+ @Nullable Object k0, @Nullable Object v0, @Nullable Object... rest) {
checkArgument(
rest.length % 2 == 0,
"There must be an equal number of key/value pairs "
+ "(i.e., the number of key/value parameters (%s) must be even).",
rest.length + 2);
- LinkedListMultimap<Object, Object> expectedMultimap = LinkedListMultimap.create();
+ LinkedListMultimap<@Nullable Object, @Nullable Object> expectedMultimap =
+ LinkedListMultimap.create();
expectedMultimap.put(k0, v0);
for (int i = 0; i < rest.length; i += 2) {
expectedMultimap.put(rest[i], rest[i + 1]);
@@ -340,8 +343,8 @@ public class MultimapSubject extends Subject {
private Factory<IterableSubject, Iterable<?>> iterableEntries() {
return new Factory<IterableSubject, Iterable<?>>() {
@Override
- public IterableSubject createSubject(FailureMetadata metadata, Iterable<?> actual) {
- return new IterableEntries(metadata, MultimapSubject.this, actual);
+ public IterableSubject createSubject(FailureMetadata metadata, @Nullable Iterable<?> actual) {
+ return new IterableEntries(metadata, MultimapSubject.this, checkNotNull(actual));
}
};
}
@@ -352,7 +355,7 @@ public class MultimapSubject extends Subject {
IterableEntries(FailureMetadata metadata, MultimapSubject multimapSubject, Iterable<?> actual) {
super(metadata, actual);
// We want to use the multimap's toString() instead of the iterable of entries' toString():
- this.stringRepresentation = multimapSubject.actual.toString();
+ this.stringRepresentation = String.valueOf(multimapSubject.actual);
}
@Override
@@ -379,18 +382,19 @@ public class MultimapSubject extends Subject {
@Override
public void inOrder() {
// We use the fact that Sets.intersection's result has the same order as the first parameter
+ checkNotNull(actual);
boolean keysInOrder =
Lists.newArrayList(Sets.intersection(actual.keySet(), expectedMultimap.keySet()))
.equals(Lists.newArrayList(expectedMultimap.keySet()));
- LinkedHashSet<Object> keysWithValuesOutOfOrder = Sets.newLinkedHashSet();
+ LinkedHashSet<@Nullable Object> keysWithValuesOutOfOrder = Sets.newLinkedHashSet();
for (Object key : expectedMultimap.keySet()) {
List<?> actualVals = Lists.newArrayList(get(actual, key));
List<?> expectedVals = Lists.newArrayList(get(expectedMultimap, key));
Iterator<?> actualIterator = actualVals.iterator();
for (Object value : expectedVals) {
if (!advanceToFind(actualIterator, value)) {
- keysWithValuesOutOfOrder.add(key);
+ boolean unused = keysWithValuesOutOfOrder.add(key);
break;
}
}
@@ -432,7 +436,7 @@ public class MultimapSubject extends Subject {
* where the contract explicitly states that the iterator isn't advanced beyond the value if the
* value is found.
*/
- private static boolean advanceToFind(Iterator<?> iterator, Object value) {
+ private static boolean advanceToFind(Iterator<?> iterator, @Nullable Object value) {
while (iterator.hasNext()) {
if (Objects.equal(iterator.next(), value)) {
return true;
@@ -441,16 +445,18 @@ public class MultimapSubject extends Subject {
return false;
}
- private static <V> Collection<V> get(Multimap<?, V> multimap, @Nullable Object key) {
+ @SuppressWarnings("EmptyList") // ImmutableList doesn't support nullable types
+ private static <V extends @Nullable Object> Collection<V> get(
+ Multimap<?, V> multimap, @Nullable Object key) {
if (multimap.containsKey(key)) {
- return multimap.asMap().get(key);
+ return checkNotNull(multimap.asMap().get(key));
} else {
- return ImmutableList.of();
+ return Collections.emptyList();
}
}
private static ListMultimap<?, ?> difference(Multimap<?, ?> minuend, Multimap<?, ?> subtrahend) {
- ListMultimap<Object, Object> difference = LinkedListMultimap.create();
+ ListMultimap<@Nullable Object, @Nullable Object> difference = LinkedListMultimap.create();
for (Object key : minuend.keySet()) {
List<?> valDifference =
difference(
@@ -461,8 +467,9 @@ public class MultimapSubject extends Subject {
}
private static List<?> difference(List<?> minuend, List<?> subtrahend) {
- LinkedHashMultiset<Object> remaining = LinkedHashMultiset.<Object>create(subtrahend);
- List<Object> difference = Lists.newArrayList();
+ LinkedHashMultiset<@Nullable Object> remaining =
+ LinkedHashMultiset.<@Nullable Object>create(subtrahend);
+ List<@Nullable Object> difference = Lists.newArrayList();
for (Object elem : minuend) {
if (!remaining.remove(elem)) {
difference.add(elem);
@@ -492,11 +499,15 @@ public class MultimapSubject extends Subject {
*/
private static Multimap<?, ?> annotateEmptyStringsMultimap(Multimap<?, ?> multimap) {
if (multimap.containsKey("") || multimap.containsValue("")) {
- ListMultimap<Object, Object> annotatedMultimap = LinkedListMultimap.create();
+ ListMultimap<@Nullable Object, @Nullable Object> annotatedMultimap =
+ LinkedListMultimap.create();
for (Map.Entry<?, ?> entry : multimap.entries()) {
- Object key = "".equals(entry.getKey()) ? HUMAN_UNDERSTANDABLE_EMPTY_STRING : entry.getKey();
+ Object key =
+ Objects.equal(entry.getKey(), "") ? HUMAN_UNDERSTANDABLE_EMPTY_STRING : entry.getKey();
Object value =
- "".equals(entry.getValue()) ? HUMAN_UNDERSTANDABLE_EMPTY_STRING : entry.getValue();
+ Objects.equal(entry.getValue(), "")
+ ? HUMAN_UNDERSTANDABLE_EMPTY_STRING
+ : entry.getValue();
annotatedMultimap.put(key, value);
}
return annotatedMultimap;
@@ -526,8 +537,9 @@ public class MultimapSubject extends Subject {
* <p>Any of the methods on the returned object may throw {@link ClassCastException} if they
* encounter an actual value that is not of type {@code A}.
*/
- public <A, E> UsingCorrespondence<A, E> comparingValuesUsing(
- Correspondence<? super A, ? super E> correspondence) {
+ public <A extends @Nullable Object, E extends @Nullable Object>
+ UsingCorrespondence<A, E> comparingValuesUsing(
+ Correspondence<? super A, ? super E> correspondence) {
return new UsingCorrespondence<>(correspondence);
}
@@ -542,7 +554,7 @@ public class MultimapSubject extends Subject {
*
* <p>Note that keys will always be compared with regular object equality ({@link Object#equals}).
*/
- public final class UsingCorrespondence<A, E> {
+ public final class UsingCorrespondence<A extends @Nullable Object, E extends @Nullable Object> {
private final Correspondence<? super A, ? super E> correspondence;
@@ -554,10 +566,10 @@ public class MultimapSubject extends Subject {
* Fails if the multimap does not contain an entry with the given key and a value that
* corresponds to the given value.
*/
- public void containsEntry(@Nullable Object expectedKey, @Nullable E expectedValue) {
- if (actual.containsKey(expectedKey)) {
+ public void containsEntry(@Nullable Object expectedKey, E expectedValue) {
+ if (checkNotNull(actual).containsKey(expectedKey)) {
// Found matching key.
- Collection<A> actualValues = getCastActual().asMap().get(expectedKey);
+ Collection<A> actualValues = checkNotNull(getCastActual().asMap().get(expectedKey));
Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forMapValues();
for (A actualValue : actualValues) {
if (correspondence.safeCompare(actualValue, expectedValue, exceptions)) {
@@ -647,9 +659,9 @@ public class MultimapSubject extends Subject {
* Fails if the multimap contains an entry with the given key and a value that corresponds to
* the given value.
*/
- public void doesNotContainEntry(@Nullable Object excludedKey, @Nullable E excludedValue) {
- if (actual.containsKey(excludedKey)) {
- Collection<A> actualValues = getCastActual().asMap().get(excludedKey);
+ public void doesNotContainEntry(@Nullable Object excludedKey, E excludedValue) {
+ if (checkNotNull(actual).containsKey(excludedKey)) {
+ Collection<A> actualValues = checkNotNull(getCastActual().asMap().get(excludedKey));
List<A> matchingValues = new ArrayList<>();
Correspondence.ExceptionStore exceptions = Correspondence.ExceptionStore.forMapValues();
for (A actualValue : actualValues) {
@@ -714,7 +726,8 @@ public class MultimapSubject extends Subject {
* public containsExactlyEntriesIn method. This is recommended by Effective Java item 31 (3rd
* edition).
*/
- private <K, V extends E> Ordered internalContainsExactlyEntriesIn(
+ @SuppressWarnings("deprecation") // TODO(b/134064106): design an alternative to no-arg check()
+ private <K extends @Nullable Object, V extends E> Ordered internalContainsExactlyEntriesIn(
Multimap<K, V> expectedMultimap) {
// Note: The non-fuzzy MultimapSubject.containsExactlyEntriesIn has a custom implementation
// and produces somewhat better failure messages simply asserting about the iterables of
@@ -724,8 +737,8 @@ public class MultimapSubject extends Subject {
// complexity for little gain.
return check()
.about(iterableEntries())
- .that(actual.entries())
- .comparingElementsUsing(new EntryCorrespondence<K, A, V>(correspondence))
+ .that(checkNotNull(actual).entries())
+ .comparingElementsUsing(MultimapSubject.<K, A, V>entryCorrespondence(correspondence))
.containsExactlyElementsIn(expectedMultimap.entries());
}
@@ -748,7 +761,8 @@ public class MultimapSubject extends Subject {
* public containsAtLeastEntriesIn method. This is recommended by Effective Java item 31 (3rd
* edition).
*/
- private <K, V extends E> Ordered internalContainsAtLeastEntriesIn(
+ @SuppressWarnings("deprecation") // TODO(b/134064106): design an alternative to no-arg check()
+ private <K extends @Nullable Object, V extends E> Ordered internalContainsAtLeastEntriesIn(
Multimap<K, V> expectedMultimap) {
// Note: The non-fuzzy MultimapSubject.containsAtLeastEntriesIn has a custom implementation
// and produces somewhat better failure messages simply asserting about the iterables of
@@ -758,8 +772,8 @@ public class MultimapSubject extends Subject {
// complexity for little gain.
return check()
.about(iterableEntries())
- .that(actual.entries())
- .comparingElementsUsing(new EntryCorrespondence<K, A, V>(correspondence))
+ .that(checkNotNull(actual).entries())
+ .comparingElementsUsing(MultimapSubject.<K, A, V>entryCorrespondence(correspondence))
.containsAtLeastElementsIn(expectedMultimap.entries());
}
@@ -770,8 +784,7 @@ public class MultimapSubject extends Subject {
* key/value pairs at compile time. Please make sure you provide varargs in key/value pairs!
*/
@CanIgnoreReturnValue
- public Ordered containsExactly(
- @Nullable Object k0, @Nullable E v0, /*@Nullable*/ Object... rest) {
+ public Ordered containsExactly(@Nullable Object k0, @Nullable E v0, @Nullable Object... rest) {
@SuppressWarnings("unchecked")
Multimap<?, E> expectedMultimap = (Multimap<?, E>) accumulateMultimap(k0, v0, rest);
return containsExactlyEntriesIn(expectedMultimap);
@@ -790,8 +803,7 @@ public class MultimapSubject extends Subject {
* key/value pairs at compile time. Please make sure you provide varargs in key/value pairs!
*/
@CanIgnoreReturnValue
- public Ordered containsAtLeast(
- @Nullable Object k0, @Nullable E v0, /*@Nullable*/ Object... rest) {
+ public Ordered containsAtLeast(@Nullable Object k0, @Nullable E v0, @Nullable Object... rest) {
@SuppressWarnings("unchecked")
Multimap<?, E> expectedMultimap = (Multimap<?, E>) accumulateMultimap(k0, v0, rest);
return containsAtLeastEntriesIn(expectedMultimap);
@@ -799,30 +811,20 @@ public class MultimapSubject extends Subject {
@SuppressWarnings("unchecked") // throwing ClassCastException is the correct behaviour
private Multimap<?, A> getCastActual() {
- return (Multimap<?, A>) actual;
+ return (Multimap<?, A>) checkNotNull(actual);
}
}
- private static final class EntryCorrespondence<K, A, E>
- extends Correspondence<Map.Entry<K, A>, Map.Entry<K, E>> {
-
- private final Correspondence<? super A, ? super E> valueCorrespondence;
-
- EntryCorrespondence(Correspondence<? super A, ? super E> valueCorrespondence) {
- this.valueCorrespondence = valueCorrespondence;
- }
-
- @Override
- public boolean compare(Map.Entry<K, A> actual, Map.Entry<K, E> expected) {
- return Objects.equal(actual.getKey(), expected.getKey())
- && valueCorrespondence.compare(actual.getValue(), expected.getValue());
- }
-
- @Override
- public String toString() {
- return lenientFormat(
- "has a key that is equal to and a value that %s the key and value of",
- valueCorrespondence);
- }
+ private static <
+ K extends @Nullable Object, A extends @Nullable Object, E extends @Nullable Object>
+ Correspondence<Map.Entry<K, A>, Map.Entry<K, E>> entryCorrespondence(
+ Correspondence<? super A, ? super E> valueCorrespondence) {
+ return Correspondence.from(
+ (Map.Entry<K, A> actual, Map.Entry<K, E> expected) ->
+ Objects.equal(actual.getKey(), expected.getKey())
+ && valueCorrespondence.compare(actual.getValue(), expected.getValue()),
+ lenientFormat(
+ "has a key that is equal to and a value that %s the key and value of",
+ valueCorrespondence));
}
}
diff --git a/core/src/main/java/com/google/common/truth/MultisetSubject.java b/core/src/main/java/com/google/common/truth/MultisetSubject.java
index 40037fe3..9e8a6315 100644
--- a/core/src/main/java/com/google/common/truth/MultisetSubject.java
+++ b/core/src/main/java/com/google/common/truth/MultisetSubject.java
@@ -16,6 +16,7 @@
package com.google.common.truth;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Multiset;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -27,7 +28,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*/
public final class MultisetSubject extends IterableSubject {
- private final Multiset<?> actual;
+ private final @Nullable Multiset<?> actual;
MultisetSubject(FailureMetadata metadata, @Nullable Multiset<?> multiset) {
super(metadata, multiset);
@@ -37,7 +38,7 @@ public final class MultisetSubject extends IterableSubject {
/** Fails if the element does not have the given count. */
public final void hasCount(@Nullable Object element, int expectedCount) {
checkArgument(expectedCount >= 0, "expectedCount(%s) must be >= 0", expectedCount);
- int actualCount = ((Multiset<?>) actual).count(element);
+ int actualCount = checkNotNull(actual).count(element);
check("count(%s)", element).that(actualCount).isEqualTo(expectedCount);
}
}
diff --git a/core/src/main/java/com/google/common/truth/ObjectArraySubject.java b/core/src/main/java/com/google/common/truth/ObjectArraySubject.java
index cd6b42b5..daa287d2 100644
--- a/core/src/main/java/com/google/common/truth/ObjectArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/ObjectArraySubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.util.Arrays;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -23,16 +25,16 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*
* @author Christian Gruber
*/
-public final class ObjectArraySubject<T> extends AbstractArraySubject {
- private final T[] actual;
+public final class ObjectArraySubject<T extends @Nullable Object> extends AbstractArraySubject {
+ private final @Nullable T @Nullable [] actual;
ObjectArraySubject(
- FailureMetadata metadata, @Nullable T /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, @Nullable T @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
public IterableSubject asList() {
- return checkNoNeedToDisplayBothValues("asList()").that(Arrays.asList(actual));
+ return checkNoNeedToDisplayBothValues("asList()").that(Arrays.asList(checkNotNull(actual)));
}
}
diff --git a/core/src/main/java/com/google/common/truth/Ordered.java b/core/src/main/java/com/google/common/truth/Ordered.java
index 00ed0cc3..2f7efed3 100644
--- a/core/src/main/java/com/google/common/truth/Ordered.java
+++ b/core/src/main/java/com/google/common/truth/Ordered.java
@@ -15,6 +15,7 @@
*/
package com.google.common.truth;
+
/**
* Returned by calls like {@link IterableSubject#containsExactly}, {@code Ordered} lets the caller
* additionally check that the expected elements were present in the order they were passed to the
diff --git a/core/src/main/java/com/google/common/truth/Platform.java b/core/src/main/java/com/google/common/truth/Platform.java
index 698e4bd2..bc4301a2 100644
--- a/core/src/main/java/com/google/common/truth/Platform.java
+++ b/core/src/main/java/com/google/common/truth/Platform.java
@@ -15,12 +15,16 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Suppliers.memoize;
import static com.google.common.base.Throwables.throwIfUnchecked;
import static com.google.common.truth.DiffUtils.generateUnifiedDiff;
import static com.google.common.truth.Fact.fact;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import java.lang.reflect.Constructor;
@@ -59,13 +63,16 @@ final class Platform {
static Throwable[] getSuppressed(Throwable throwable) {
try {
Method getSuppressed = throwable.getClass().getMethod("getSuppressed");
- return (Throwable[]) getSuppressed.invoke(throwable);
+ return (Throwable[]) checkNotNull(getSuppressed.invoke(throwable));
} catch (NoSuchMethodException e) {
return new Throwable[0];
} catch (IllegalAccessException e) {
- throw new RuntimeException(e);
+ // We're calling a public method on a public class.
+ throw newLinkageError(e);
} catch (InvocationTargetException e) {
- throw new RuntimeException(e);
+ throwIfUnchecked(e.getCause());
+ // getSuppressed has no `throws` clause.
+ throw newLinkageError(e);
}
}
@@ -78,7 +85,9 @@ final class Platform {
* the value passed to {@code assertThat} or {@code that}, as distinct from any later actual
* values produced by chaining calls like {@code hasMessageThat}.
*/
- static String inferDescription() {
+ // Checker complains that first invoke argument is null.
+ @SuppressWarnings("argument.type.incompatible")
+ static @Nullable String inferDescription() {
if (isInferDescriptionDisabled()) {
return null;
}
@@ -181,7 +190,7 @@ final class Platform {
@Override
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
- public final Throwable getCause() {
+ public final @Nullable Throwable getCause() {
return cause;
}
@@ -189,7 +198,7 @@ final class Platform {
// TODO(cpovirk): Write a test that fails without this. Ditto for SimpleAssertionError.
@Override
public final String toString() {
- return getLocalizedMessage();
+ return checkNotNull(getLocalizedMessage());
}
}
@@ -201,6 +210,11 @@ final class Platform {
return Float.toString(value);
}
+ /** Turns a non-double, non-float object into a string. */
+ static String stringValueOfNonFloatingPoint(@Nullable Object o) {
+ return String.valueOf(o);
+ }
+
/** Returns a human readable string representation of the throwable's stack trace. */
static String getStackTraceAsString(Throwable throwable) {
return Throwables.getStackTraceAsString(throwable);
@@ -208,7 +222,7 @@ final class Platform {
/** Tests if current platform is Android. */
static boolean isAndroid() {
- return System.getProperty("java.runtime.name").contains("Android");
+ return checkNotNull(System.getProperty("java.runtime.name", "")).contains("Android");
}
/**
@@ -294,4 +308,60 @@ final class Platform {
error.initCause(cause);
return error;
}
+
+ static boolean isKotlinRange(Iterable<?> iterable) {
+ return closedRangeClassIfAvailable.get() != null
+ && closedRangeClassIfAvailable.get().isInstance(iterable);
+ // (If the class isn't available, then nothing could be an instance of ClosedRange.)
+ }
+
+ // Not using lambda here because of wrong nullability type inference in this case.
+ private static final Supplier<@Nullable Class<?>> closedRangeClassIfAvailable =
+ Suppliers.<@Nullable Class<?>>memoize(
+ () -> {
+ try {
+ return Class.forName("kotlin.ranges.ClosedRange");
+ /*
+ * TODO(cpovirk): Consider looking up the Method we'll need here, too: If it's not
+ * present (maybe because Proguard stripped it, similar to cl/462826082), then we
+ * don't want our caller to continue on to call kotlinRangeContains, since it won't
+ * be able to give an answer about what ClosedRange.contains will return.
+ * (Alternatively, we could make kotlinRangeContains contain its own fallback to
+ * Iterables.contains. Conceivably its first fallback could even be to try reading
+ * `start` and `endInclusive` from the ClosedRange instance, but even then, we'd
+ * want to check in advance whether we're able to access those.)
+ */
+ } catch (ClassNotFoundException notAvailable) {
+ return null;
+ }
+ });
+
+ static boolean kotlinRangeContains(Iterable<?> haystack, @Nullable Object needle) {
+ try {
+ return (boolean) closedRangeContainsMethod.get().invoke(haystack, needle);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof ClassCastException) {
+ // icky but no worse than what we normally do for isIn(Iterable)
+ return false;
+ }
+ throwIfUnchecked(e.getCause());
+ // That method has no `throws` clause.
+ throw newLinkageError(e.getCause());
+ } catch (IllegalAccessException e) {
+ // We're calling a public method on a public class.
+ throw newLinkageError(e);
+ }
+ }
+
+ private static final Supplier<Method> closedRangeContainsMethod =
+ memoize(
+ () -> {
+ try {
+ return checkNotNull(closedRangeClassIfAvailable.get())
+ .getMethod("contains", Comparable.class);
+ } catch (NoSuchMethodException e) {
+ // That method exists. (But see the discussion at closedRangeClassIfAvailable above.)
+ throw newLinkageError(e);
+ }
+ });
}
diff --git a/core/src/main/java/com/google/common/truth/PrimitiveBooleanArraySubject.java b/core/src/main/java/com/google/common/truth/PrimitiveBooleanArraySubject.java
index 47605bc6..33ff6d89 100644
--- a/core/src/main/java/com/google/common/truth/PrimitiveBooleanArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/PrimitiveBooleanArraySubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.primitives.Booleans;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,15 +26,15 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public final class PrimitiveBooleanArraySubject extends AbstractArraySubject {
- private final boolean[] actual;
+ private final boolean @Nullable [] actual;
PrimitiveBooleanArraySubject(
- FailureMetadata metadata, boolean /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, boolean @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
public IterableSubject asList() {
- return checkNoNeedToDisplayBothValues("asList()").that(Booleans.asList(actual));
+ return checkNoNeedToDisplayBothValues("asList()").that(Booleans.asList(checkNotNull(actual)));
}
}
diff --git a/core/src/main/java/com/google/common/truth/PrimitiveByteArraySubject.java b/core/src/main/java/com/google/common/truth/PrimitiveByteArraySubject.java
index 59a3c7dd..f8169ca4 100644
--- a/core/src/main/java/com/google/common/truth/PrimitiveByteArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/PrimitiveByteArraySubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.primitives.Bytes;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,15 +26,15 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Kurt Alfred Kluever
*/
public final class PrimitiveByteArraySubject extends AbstractArraySubject {
- private final byte[] actual;
+ private final byte @Nullable [] actual;
PrimitiveByteArraySubject(
- FailureMetadata metadata, byte /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, byte @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
public IterableSubject asList() {
- return checkNoNeedToDisplayBothValues("asList()").that(Bytes.asList(actual));
+ return checkNoNeedToDisplayBothValues("asList()").that(Bytes.asList(checkNotNull(actual)));
}
}
diff --git a/core/src/main/java/com/google/common/truth/PrimitiveCharArraySubject.java b/core/src/main/java/com/google/common/truth/PrimitiveCharArraySubject.java
index 6e94b2cf..79e6f12e 100644
--- a/core/src/main/java/com/google/common/truth/PrimitiveCharArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/PrimitiveCharArraySubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.primitives.Chars;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,15 +26,15 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public final class PrimitiveCharArraySubject extends AbstractArraySubject {
- private final char[] actual;
+ private final char @Nullable [] actual;
PrimitiveCharArraySubject(
- FailureMetadata metadata, char /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, char @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
public IterableSubject asList() {
- return checkNoNeedToDisplayBothValues("asList()").that(Chars.asList(actual));
+ return checkNoNeedToDisplayBothValues("asList()").that(Chars.asList(checkNotNull(actual)));
}
}
diff --git a/core/src/main/java/com/google/common/truth/PrimitiveDoubleArraySubject.java b/core/src/main/java/com/google/common/truth/PrimitiveDoubleArraySubject.java
index dc265105..6fdb2750 100644
--- a/core/src/main/java/com/google/common/truth/PrimitiveDoubleArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/PrimitiveDoubleArraySubject.java
@@ -31,10 +31,10 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public final class PrimitiveDoubleArraySubject extends AbstractArraySubject {
- private final double[] actual;
+ private final double @Nullable [] actual;
PrimitiveDoubleArraySubject(
- FailureMetadata metadata, double /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, double @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
@@ -65,7 +65,7 @@ public final class PrimitiveDoubleArraySubject extends AbstractArraySubject {
*/
// TODO(cpovirk): Move some or all of this Javadoc to the supertype, maybe deleting this override?
@Override
- public void isEqualTo(Object expected) {
+ public void isEqualTo(@Nullable Object expected) {
super.isEqualTo(expected);
}
@@ -84,7 +84,7 @@ public final class PrimitiveDoubleArraySubject extends AbstractArraySubject {
* </ul>
*/
@Override
- public void isNotEqualTo(Object expected) {
+ public void isNotEqualTo(@Nullable Object expected) {
super.isNotEqualTo(expected);
}
@@ -234,7 +234,7 @@ public final class PrimitiveDoubleArraySubject extends AbstractArraySubject {
private IterableSubject iterableSubject() {
return checkNoNeedToDisplayBothValues("asList()")
.about(iterablesWithCustomDoubleToString())
- .that(Doubles.asList(actual));
+ .that(Doubles.asList(checkNotNull(actual)));
}
/*
@@ -248,7 +248,7 @@ public final class PrimitiveDoubleArraySubject extends AbstractArraySubject {
private Factory<IterableSubject, Iterable<?>> iterablesWithCustomDoubleToString() {
return new Factory<IterableSubject, Iterable<?>>() {
@Override
- public IterableSubject createSubject(FailureMetadata metadata, Iterable<?> actual) {
+ public IterableSubject createSubject(FailureMetadata metadata, @Nullable Iterable<?> actual) {
return new IterableSubjectWithInheritedToString(metadata, actual);
}
};
@@ -256,7 +256,7 @@ public final class PrimitiveDoubleArraySubject extends AbstractArraySubject {
private final class IterableSubjectWithInheritedToString extends IterableSubject {
- IterableSubjectWithInheritedToString(FailureMetadata metadata, Iterable<?> actual) {
+ IterableSubjectWithInheritedToString(FailureMetadata metadata, @Nullable Iterable<?> actual) {
super(metadata, actual);
}
diff --git a/core/src/main/java/com/google/common/truth/PrimitiveFloatArraySubject.java b/core/src/main/java/com/google/common/truth/PrimitiveFloatArraySubject.java
index ae106d5f..339a4d5b 100644
--- a/core/src/main/java/com/google/common/truth/PrimitiveFloatArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/PrimitiveFloatArraySubject.java
@@ -31,10 +31,10 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public final class PrimitiveFloatArraySubject extends AbstractArraySubject {
- private final float[] actual;
+ private final float @Nullable [] actual;
PrimitiveFloatArraySubject(
- FailureMetadata metadata, float /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, float @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
@@ -64,7 +64,7 @@ public final class PrimitiveFloatArraySubject extends AbstractArraySubject {
* </ul>
*/
@Override
- public void isEqualTo(Object expected) {
+ public void isEqualTo(@Nullable Object expected) {
super.isEqualTo(expected);
}
@@ -83,7 +83,7 @@ public final class PrimitiveFloatArraySubject extends AbstractArraySubject {
* </ul>
*/
@Override
- public void isNotEqualTo(Object expected) {
+ public void isNotEqualTo(@Nullable Object expected) {
super.isNotEqualTo(expected);
}
@@ -239,7 +239,7 @@ public final class PrimitiveFloatArraySubject extends AbstractArraySubject {
private IterableSubject iterableSubject() {
return checkNoNeedToDisplayBothValues("asList()")
.about(iterablesWithCustomFloatToString())
- .that(Floats.asList(actual));
+ .that(Floats.asList(checkNotNull(actual)));
}
/*
@@ -253,7 +253,7 @@ public final class PrimitiveFloatArraySubject extends AbstractArraySubject {
private Factory<IterableSubject, Iterable<?>> iterablesWithCustomFloatToString() {
return new Factory<IterableSubject, Iterable<?>>() {
@Override
- public IterableSubject createSubject(FailureMetadata metadata, Iterable<?> actual) {
+ public IterableSubject createSubject(FailureMetadata metadata, @Nullable Iterable<?> actual) {
return new IterableSubjectWithInheritedToString(metadata, actual);
}
};
@@ -261,7 +261,7 @@ public final class PrimitiveFloatArraySubject extends AbstractArraySubject {
private final class IterableSubjectWithInheritedToString extends IterableSubject {
- IterableSubjectWithInheritedToString(FailureMetadata metadata, Iterable<?> actual) {
+ IterableSubjectWithInheritedToString(FailureMetadata metadata, @Nullable Iterable<?> actual) {
super(metadata, actual);
}
diff --git a/core/src/main/java/com/google/common/truth/PrimitiveIntArraySubject.java b/core/src/main/java/com/google/common/truth/PrimitiveIntArraySubject.java
index f2c4abb5..b6c64634 100644
--- a/core/src/main/java/com/google/common/truth/PrimitiveIntArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/PrimitiveIntArraySubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.primitives.Ints;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,15 +26,15 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public final class PrimitiveIntArraySubject extends AbstractArraySubject {
- private final int[] actual;
+ private final int @Nullable [] actual;
PrimitiveIntArraySubject(
- FailureMetadata metadata, int /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, int @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
public IterableSubject asList() {
- return checkNoNeedToDisplayBothValues("asList()").that(Ints.asList(actual));
+ return checkNoNeedToDisplayBothValues("asList()").that(Ints.asList(checkNotNull(actual)));
}
}
diff --git a/core/src/main/java/com/google/common/truth/PrimitiveLongArraySubject.java b/core/src/main/java/com/google/common/truth/PrimitiveLongArraySubject.java
index 1d5aec0c..07441086 100644
--- a/core/src/main/java/com/google/common/truth/PrimitiveLongArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/PrimitiveLongArraySubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.primitives.Longs;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,15 +26,15 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public final class PrimitiveLongArraySubject extends AbstractArraySubject {
- private final long[] actual;
+ private final long @Nullable [] actual;
PrimitiveLongArraySubject(
- FailureMetadata metadata, long /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, long @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
public IterableSubject asList() {
- return checkNoNeedToDisplayBothValues("asList()").that(Longs.asList(actual));
+ return checkNoNeedToDisplayBothValues("asList()").that(Longs.asList(checkNotNull(actual)));
}
}
diff --git a/core/src/main/java/com/google/common/truth/PrimitiveShortArraySubject.java b/core/src/main/java/com/google/common/truth/PrimitiveShortArraySubject.java
index cd17c874..dcefab47 100644
--- a/core/src/main/java/com/google/common/truth/PrimitiveShortArraySubject.java
+++ b/core/src/main/java/com/google/common/truth/PrimitiveShortArraySubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.primitives.Shorts;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -24,15 +26,15 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public final class PrimitiveShortArraySubject extends AbstractArraySubject {
- private final short[] actual;
+ private final short @Nullable [] actual;
PrimitiveShortArraySubject(
- FailureMetadata metadata, short /*@Nullable*/[] o, @Nullable String typeDescription) {
+ FailureMetadata metadata, short @Nullable [] o, @Nullable String typeDescription) {
super(metadata, o, typeDescription);
this.actual = o;
}
public IterableSubject asList() {
- return checkNoNeedToDisplayBothValues("asList()").that(Shorts.asList(actual));
+ return checkNoNeedToDisplayBothValues("asList()").that(Shorts.asList(checkNotNull(actual)));
}
}
diff --git a/core/src/main/java/com/google/common/truth/SimpleSubjectBuilder.java b/core/src/main/java/com/google/common/truth/SimpleSubjectBuilder.java
index 4451ee46..80caa364 100644
--- a/core/src/main/java/com/google/common/truth/SimpleSubjectBuilder.java
+++ b/core/src/main/java/com/google/common/truth/SimpleSubjectBuilder.java
@@ -44,4 +44,5 @@ public final class SimpleSubjectBuilder<SubjectT extends Subject, ActualT> {
public SubjectT that(@Nullable ActualT actual) {
return subjectFactory.createSubject(metadata, actual);
}
+
}
diff --git a/core/src/main/java/com/google/common/truth/StackTraceCleaner.java b/core/src/main/java/com/google/common/truth/StackTraceCleaner.java
index 04ac3980..5efc43a0 100644
--- a/core/src/main/java/com/google/common/truth/StackTraceCleaner.java
+++ b/core/src/main/java/com/google/common/truth/StackTraceCleaner.java
@@ -16,6 +16,7 @@
package com.google.common.truth;
import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.Thread.currentThread;
import com.google.common.annotations.GwtIncompatible;
@@ -26,9 +27,11 @@ import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Utility that cleans stack traces to remove noise from common frameworks. */
@GwtIncompatible
+@J2ktIncompatible
final class StackTraceCleaner {
static final String CLEANER_LINK = "https://goo.gl/aH3UyP";
@@ -48,8 +51,8 @@ final class StackTraceCleaner {
private final Throwable throwable;
private final List<StackTraceElementWrapper> cleanedStackTrace = new ArrayList<>();
- private StackTraceElementWrapper lastStackFrameElementWrapper = null;
- private StackFrameType currentStreakType = null;
+ private @Nullable StackTraceElementWrapper lastStackFrameElementWrapper = null;
+ private @Nullable StackFrameType currentStreakType = null;
private int currentStreakLength = 0;
/**
@@ -63,6 +66,7 @@ final class StackTraceCleaner {
// TODO(b/135924708): Add this to the test runners so that we clean all stack traces, not just
// those of exceptions originating in Truth.
/** Cleans the stack trace on {@code throwable}, replacing the trace that was originally on it. */
+ @SuppressWarnings("SetAll") // not available under old versions of Android
private void clean(Set<Throwable> seenThrowables) {
// Stack trace cleaning can be disabled using a system property.
if (isStackTraceCleaningDisabled()) {
@@ -100,7 +104,7 @@ final class StackTraceCleaner {
* frames. Keep those frames around (though much of JUnit itself and related startup frames will
* still be removed by the remainder of this method) so that the user sees a useful stack.
*/
- if (!(stackIndex < endIndex)) {
+ if (stackIndex >= endIndex) {
endIndex = stackFrames.length;
}
@@ -174,10 +178,11 @@ final class StackTraceCleaner {
if (currentStreakLength == 1) {
// A single frame isn't a streak. Just include the frame as-is in the result.
- cleanedStackTrace.add(lastStackFrameElementWrapper);
+ cleanedStackTrace.add(checkNotNull(lastStackFrameElementWrapper));
} else {
// Add a single frame to the result summarizing the streak of framework frames
- cleanedStackTrace.add(createStreakReplacementFrame(currentStreakType, currentStreakLength));
+ cleanedStackTrace.add(
+ createStreakReplacementFrame(checkNotNull(currentStreakType), currentStreakLength));
}
clearStreak();
@@ -190,7 +195,8 @@ final class StackTraceCleaner {
}
private static final ImmutableSet<String> SUBJECT_CLASS =
- ImmutableSet.of(Subject.class.getCanonicalName());
+ ImmutableSet.of(
+ Subject.class.getCanonicalName());
private static final ImmutableSet<String> STANDARD_SUBJECT_BUILDER_CLASS =
ImmutableSet.of(StandardSubjectBuilder.class.getCanonicalName());
@@ -252,8 +258,8 @@ final class StackTraceCleaner {
return false;
}
- private static boolean isSubtypeOf(Class<?> subclass, String superclass) {
- for (; subclass != null; subclass = subclass.getSuperclass()) {
+ private static boolean isSubtypeOf(@Nullable Class<?> subclass, String superclass) {
+ for (; subclass != null; subclass = checkNotNull(subclass).getSuperclass()) {
if (subclass.getCanonicalName() != null && subclass.getCanonicalName().equals(superclass)) {
return true;
}
@@ -352,6 +358,8 @@ final class StackTraceCleaner {
"Testing framework",
"junit",
"org.junit",
+ "androidx.test.internal.runner",
+ "com.github.bazel_contrib.contrib_rules_jvm.junit5",
"com.google.testing.junit",
"com.google.testing.testsize",
"com.google.testing.util"),
@@ -369,7 +377,9 @@ final class StackTraceCleaner {
// TODO(cpovirk): This is really only for tests in Truth itself, so this doesn't matter yet,
// but.... If the Truth tests someday start calling into nested classes, we may want to add:
// || fullyQualifiedClassName.contains("Test$")
- if (fullyQualifiedClassName.endsWith("Test")) {
+ if (fullyQualifiedClassName.endsWith("Test")
+ && !fullyQualifiedClassName.equals(
+ "androidx.test.internal.runner.junit3.NonLeakyTestSuite$NonLeakyTest")) {
return StackFrameType.NEVER_REMOVE;
}
diff --git a/core/src/main/java/com/google/common/truth/StandardSubjectBuilder.java b/core/src/main/java/com/google/common/truth/StandardSubjectBuilder.java
index 512de7e8..f41fb486 100644
--- a/core/src/main/java/com/google/common/truth/StandardSubjectBuilder.java
+++ b/core/src/main/java/com/google/common/truth/StandardSubjectBuilder.java
@@ -61,10 +61,9 @@ public class StandardSubjectBuilder {
this.metadataDoNotReferenceDirectly = checkNotNull(metadata);
}
- @SuppressWarnings({"unchecked", "rawtypes"})
public final <ComparableT extends Comparable<?>> ComparableSubject<ComparableT> that(
@Nullable ComparableT actual) {
- return new ComparableSubject(metadata(), actual) {};
+ return new ComparableSubject<ComparableT>(metadata(), actual) {};
}
public final BigDecimalSubject that(@Nullable BigDecimal actual) {
@@ -76,6 +75,7 @@ public class StandardSubjectBuilder {
}
@GwtIncompatible("ClassSubject.java")
+ @J2ktIncompatible
public final ClassSubject that(@Nullable Class<?> actual) {
return new ClassSubject(metadata(), actual);
}
@@ -112,39 +112,40 @@ public class StandardSubjectBuilder {
return new IterableSubject(metadata(), actual);
}
- public final <T> ObjectArraySubject<T> that(@Nullable T /*@Nullable*/[] actual) {
+ @SuppressWarnings("AvoidObjectArrays")
+ public final <T> ObjectArraySubject<T> that(@Nullable T @Nullable [] actual) {
return new ObjectArraySubject<>(metadata(), actual, "array");
}
- public final PrimitiveBooleanArraySubject that(boolean /*@Nullable*/[] actual) {
+ public final PrimitiveBooleanArraySubject that(boolean @Nullable [] actual) {
return new PrimitiveBooleanArraySubject(metadata(), actual, "array");
}
- public final PrimitiveShortArraySubject that(short /*@Nullable*/[] actual) {
+ public final PrimitiveShortArraySubject that(short @Nullable [] actual) {
return new PrimitiveShortArraySubject(metadata(), actual, "array");
}
- public final PrimitiveIntArraySubject that(int /*@Nullable*/[] actual) {
+ public final PrimitiveIntArraySubject that(int @Nullable [] actual) {
return new PrimitiveIntArraySubject(metadata(), actual, "array");
}
- public final PrimitiveLongArraySubject that(long /*@Nullable*/[] actual) {
+ public final PrimitiveLongArraySubject that(long @Nullable [] actual) {
return new PrimitiveLongArraySubject(metadata(), actual, "array");
}
- public final PrimitiveCharArraySubject that(char /*@Nullable*/[] actual) {
+ public final PrimitiveCharArraySubject that(char @Nullable [] actual) {
return new PrimitiveCharArraySubject(metadata(), actual, "array");
}
- public final PrimitiveByteArraySubject that(byte /*@Nullable*/[] actual) {
+ public final PrimitiveByteArraySubject that(byte @Nullable [] actual) {
return new PrimitiveByteArraySubject(metadata(), actual, "array");
}
- public final PrimitiveFloatArraySubject that(float /*@Nullable*/[] actual) {
+ public final PrimitiveFloatArraySubject that(float @Nullable [] actual) {
return new PrimitiveFloatArraySubject(metadata(), actual, "array");
}
- public final PrimitiveDoubleArraySubject that(double /*@Nullable*/[] actual) {
+ public final PrimitiveDoubleArraySubject that(double @Nullable [] actual) {
return new PrimitiveDoubleArraySubject(metadata(), actual, "array");
}
@@ -189,7 +190,7 @@ public class StandardSubjectBuilder {
* @throws IllegalArgumentException if the number of placeholders in the format string does not
* equal the number of given arguments
*/
- public final StandardSubjectBuilder withMessage(String format, /*@Nullable*/ Object... args) {
+ public final StandardSubjectBuilder withMessage(String format, @Nullable Object... args) {
return new StandardSubjectBuilder(metadata().withMessage(format, args));
}
diff --git a/core/src/main/java/com/google/common/truth/StringSubject.java b/core/src/main/java/com/google/common/truth/StringSubject.java
index d3a10d2f..dc5b12f7 100644
--- a/core/src/main/java/com/google/common/truth/StringSubject.java
+++ b/core/src/main/java/com/google/common/truth/StringSubject.java
@@ -32,7 +32,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber (cgruber@israfil.net)
*/
public class StringSubject extends ComparableSubject<String> {
- private final String actual;
+ private final @Nullable String actual;
/**
* Constructor for use by subclasses. If you want to create an instance of this class itself, call
@@ -43,23 +43,25 @@ public class StringSubject extends ComparableSubject<String> {
this.actual = string;
}
- /** @deprecated Use {@link #isEqualTo} instead. String comparison is consistent with equality. */
+ /**
+ * @deprecated Use {@link #isEqualTo} instead. String comparison is consistent with equality.
+ */
@Override
@Deprecated
- public final void isEquivalentAccordingToCompareTo(String other) {
+ public final void isEquivalentAccordingToCompareTo(@Nullable String other) {
super.isEquivalentAccordingToCompareTo(other);
}
/** Fails if the string does not have the given length. */
public void hasLength(int expectedLength) {
checkArgument(expectedLength >= 0, "expectedLength(%s) must be >= 0", expectedLength);
- check("length()").that(actual.length()).isEqualTo(expectedLength);
+ check("length()").that(checkNotNull(actual).length()).isEqualTo(expectedLength);
}
/** Fails if the string is not equal to the zero-length "empty string." */
public void isEmpty() {
if (actual == null) {
- failWithActual(simpleFact("expected empty string"));
+ failWithActual(simpleFact("expected an empty string"));
} else if (!actual.isEmpty()) {
failWithActual(simpleFact("expected to be empty"));
}
@@ -68,14 +70,14 @@ public class StringSubject extends ComparableSubject<String> {
/** Fails if the string is equal to the zero-length "empty string." */
public void isNotEmpty() {
if (actual == null) {
- failWithActual(simpleFact("expected nonempty string"));
+ failWithActual(simpleFact("expected a non-empty string"));
} else if (actual.isEmpty()) {
failWithoutActual(simpleFact("expected not to be empty"));
}
}
/** Fails if the string does not contain the given sequence. */
- public void contains(CharSequence string) {
+ public void contains(@Nullable CharSequence string) {
checkNotNull(string);
if (actual == null) {
failWithActual("expected a string that contains", string);
@@ -85,7 +87,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string contains the given sequence. */
- public void doesNotContain(CharSequence string) {
+ public void doesNotContain(@Nullable CharSequence string) {
checkNotNull(string);
if (actual == null) {
failWithActual("expected a string that does not contain", string);
@@ -95,7 +97,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string does not start with the given string. */
- public void startsWith(String string) {
+ public void startsWith(@Nullable String string) {
checkNotNull(string);
if (actual == null) {
failWithActual("expected a string that starts with", string);
@@ -105,7 +107,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string does not end with the given string. */
- public void endsWith(String string) {
+ public void endsWith(@Nullable String string) {
checkNotNull(string);
if (actual == null) {
failWithActual("expected a string that ends with", string);
@@ -115,7 +117,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string does not match the given regex. */
- public void matches(String regex) {
+ public void matches(@Nullable String regex) {
checkNotNull(regex);
if (actual == null) {
failWithActual("expected a string that matches", regex);
@@ -133,7 +135,8 @@ public class StringSubject extends ComparableSubject<String> {
/** Fails if the string does not match the given regex. */
@GwtIncompatible("java.util.regex.Pattern")
- public void matches(Pattern regex) {
+ @J2ktIncompatible
+ public void matches(@Nullable Pattern regex) {
checkNotNull(regex);
if (actual == null) {
failWithActual("expected a string that matches", regex);
@@ -152,7 +155,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string matches the given regex. */
- public void doesNotMatch(String regex) {
+ public void doesNotMatch(@Nullable String regex) {
checkNotNull(regex);
if (actual == null) {
failWithActual("expected a string that does not match", regex);
@@ -163,7 +166,8 @@ public class StringSubject extends ComparableSubject<String> {
/** Fails if the string matches the given regex. */
@GwtIncompatible("java.util.regex.Pattern")
- public void doesNotMatch(Pattern regex) {
+ @J2ktIncompatible
+ public void doesNotMatch(@Nullable Pattern regex) {
checkNotNull(regex);
if (actual == null) {
failWithActual("expected a string that does not match", regex);
@@ -174,7 +178,8 @@ public class StringSubject extends ComparableSubject<String> {
/** Fails if the string does not contain a match on the given regex. */
@GwtIncompatible("java.util.regex.Pattern")
- public void containsMatch(Pattern regex) {
+ @J2ktIncompatible
+ public void containsMatch(@Nullable Pattern regex) {
checkNotNull(regex);
if (actual == null) {
failWithActual("expected a string that contains a match for", regex);
@@ -184,7 +189,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string does not contain a match on the given regex. */
- public void containsMatch(String regex) {
+ public void containsMatch(@Nullable String regex) {
checkNotNull(regex);
if (actual == null) {
failWithActual("expected a string that contains a match for", regex);
@@ -195,7 +200,8 @@ public class StringSubject extends ComparableSubject<String> {
/** Fails if the string contains a match on the given regex. */
@GwtIncompatible("java.util.regex.Pattern")
- public void doesNotContainMatch(Pattern regex) {
+ @J2ktIncompatible
+ public void doesNotContainMatch(@Nullable Pattern regex) {
checkNotNull(regex);
if (actual == null) {
failWithActual("expected a string that does not contain a match for", regex);
@@ -211,7 +217,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string contains a match on the given regex. */
- public void doesNotContainMatch(String regex) {
+ public void doesNotContainMatch(@Nullable String regex) {
checkNotNull(regex);
if (actual == null) {
failWithActual("expected a string that does not contain a match for", regex);
@@ -232,6 +238,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Case insensitive propositions for string subjects. */
+ @SuppressWarnings("Casing_StringEqualsIgnoreCase") // intentional choice from API Review
public final class CaseInsensitiveStringComparison {
private CaseInsensitiveStringComparison() {}
@@ -246,7 +253,7 @@ public class StringSubject extends ComparableSubject<String> {
*
* <p>Example: "abc" is equal to "ABC", but not to "abcd".
*/
- public void isEqualTo(String expected) {
+ public void isEqualTo(@Nullable String expected) {
if (actual == null) {
if (expected != null) {
failWithoutActual(
@@ -268,7 +275,7 @@ public class StringSubject extends ComparableSubject<String> {
* Fails if the subject is equal to the given string (while ignoring case). The meaning of
* equality is the same as for the {@link #isEqualTo} method.
*/
- public void isNotEqualTo(String unexpected) {
+ public void isNotEqualTo(@Nullable String unexpected) {
if (actual == null) {
if (unexpected == null) {
failWithoutActual(
@@ -284,7 +291,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string does not contain the given sequence (while ignoring case). */
- public void contains(CharSequence expectedSequence) {
+ public void contains(@Nullable CharSequence expectedSequence) {
checkNotNull(expectedSequence);
String expected = expectedSequence.toString();
if (actual == null) {
@@ -299,7 +306,7 @@ public class StringSubject extends ComparableSubject<String> {
}
/** Fails if the string contains the given sequence (while ignoring case). */
- public void doesNotContain(CharSequence expectedSequence) {
+ public void doesNotContain(@Nullable CharSequence expectedSequence) {
checkNotNull(expectedSequence);
String expected = expectedSequence.toString();
if (actual == null) {
@@ -313,21 +320,22 @@ public class StringSubject extends ComparableSubject<String> {
}
}
- private boolean containsIgnoreCase(String string) {
+ private boolean containsIgnoreCase(@Nullable String string) {
+ checkNotNull(string);
if (string.isEmpty()) {
// TODO(b/79459427): Fix for J2CL discrepancy when string is empty
return true;
}
- String subject = actual;
+ String subject = checkNotNull(actual);
for (int subjectOffset = 0;
subjectOffset <= subject.length() - string.length();
subjectOffset++) {
if (subject.regionMatches(
- /* ignoreCase = */ true,
- /* toffset = */ subjectOffset,
- /* other = */ string,
- /* ooffset = */ 0,
- /* len = */ string.length())) {
+ /* ignoreCase= */ true,
+ /* toffset= */ subjectOffset,
+ /* other= */ string,
+ /* ooffset= */ 0,
+ /* len= */ string.length())) {
return true;
}
}
diff --git a/core/src/main/java/com/google/common/truth/Subject.java b/core/src/main/java/com/google/common/truth/Subject.java
index 0d1436a6..94d9e169 100644
--- a/core/src/main/java/com/google/common/truth/Subject.java
+++ b/core/src/main/java/com/google/common/truth/Subject.java
@@ -19,11 +19,16 @@ import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.CharMatcher.whitespace;
import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.lenientFormat;
import static com.google.common.truth.Fact.fact;
import static com.google.common.truth.Fact.simpleFact;
import static com.google.common.truth.Platform.doubleToString;
import static com.google.common.truth.Platform.floatToString;
+import static com.google.common.truth.Platform.isKotlinRange;
+import static com.google.common.truth.Platform.kotlinRangeContains;
+import static com.google.common.truth.Platform.stringValueOfNonFloatingPoint;
import static com.google.common.truth.Subject.EqualityCheck.SAME_INSTANCE;
import static com.google.common.truth.SubjectUtils.accumulate;
import static com.google.common.truth.SubjectUtils.append;
@@ -31,7 +36,6 @@ import static com.google.common.truth.SubjectUtils.concat;
import static com.google.common.truth.SubjectUtils.sandwich;
import static java.util.Arrays.asList;
-import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@@ -84,18 +88,11 @@ public class Subject {
*/
public interface Factory<SubjectT extends Subject, ActualT> {
/** Creates a new {@link Subject}. */
- SubjectT createSubject(FailureMetadata metadata, ActualT actual);
+ SubjectT createSubject(FailureMetadata metadata, @Nullable ActualT actual);
}
- private static final FailureStrategy IGNORE_STRATEGY =
- new FailureStrategy() {
- @Override
- public void fail(AssertionError failure) {}
- };
-
- private final FailureMetadata metadata;
- private final Object actual;
- private String customName = null;
+ private final @Nullable FailureMetadata metadata;
+ private final @Nullable Object actual;
private final @Nullable String typeDescriptionOverride;
/**
@@ -103,7 +100,7 @@ public class Subject {
* {@link Subject#check(String, Object...) check(...)}{@code .that(actual)}.
*/
protected Subject(FailureMetadata metadata, @Nullable Object actual) {
- this(metadata, actual, /*typeDescriptionOverride=*/ null);
+ this(metadata, actual, /* typeDescriptionOverride= */ null);
}
/**
@@ -118,8 +115,10 @@ public class Subject {
* obfuscated names.
*/
Subject(
- FailureMetadata metadata, @Nullable Object actual, @Nullable String typeDescriptionOverride) {
- this.metadata = metadata.updateForSubject(this);
+ @Nullable FailureMetadata metadata,
+ @Nullable Object actual,
+ @Nullable String typeDescriptionOverride) {
+ this.metadata = metadata == null ? null : metadata.updateForSubject(this);
this.actual = actual;
this.typeDescriptionOverride = typeDescriptionOverride;
}
@@ -299,7 +298,7 @@ public class Subject {
failWithActual("expected instance of", clazz.getName());
return;
}
- if (!Platform.isInstanceOfType(actual, clazz)) {
+ if (!isInstanceOfType(actual, clazz)) {
if (classMetadataUnsupported()) {
throw new UnsupportedOperationException(
actualCustomStringRepresentation()
@@ -328,7 +327,7 @@ public class Subject {
if (actual == null) {
return; // null is not an instance of clazz.
}
- if (Platform.isInstanceOfType(actual, clazz)) {
+ if (isInstanceOfType(actual, clazz)) {
failWithActual("expected not to be an instance of", clazz.getName());
/*
* TODO(cpovirk): Consider including actual.getClass() if it's not clazz itself but only a
@@ -337,21 +336,42 @@ public class Subject {
}
}
+ private static boolean isInstanceOfType(Object instance, Class<?> clazz) {
+ checkArgument(
+ !clazz.isPrimitive(),
+ "Cannot check instanceof for primitive type %s. Pass the wrapper class instead.",
+ clazz.getSimpleName());
+ /*
+ * TODO(cpovirk): Make the message include `Primitives.wrap(clazz).getSimpleName()` once that
+ * method is available in a public guava-gwt release that we depend on.
+ */
+ return Platform.isInstanceOfType(instance, clazz);
+ }
+
/** Fails unless the subject is equal to any element in the given iterable. */
- public void isIn(Iterable<?> iterable) {
- if (!Iterables.contains(iterable, actual)) {
+ public void isIn(@Nullable Iterable<?> iterable) {
+ checkNotNull(iterable);
+ if (!contains(iterable, actual)) {
failWithActual("expected any of", iterable);
}
}
+ private static boolean contains(Iterable<?> haystack, @Nullable Object needle) {
+ if (isKotlinRange(haystack)) {
+ return kotlinRangeContains(haystack, needle);
+ }
+ return Iterables.contains(haystack, needle);
+ }
+
/** Fails unless the subject is equal to any of the given elements. */
public void isAnyOf(
- @Nullable Object first, @Nullable Object second, @Nullable Object /*@Nullable*/... rest) {
+ @Nullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest) {
isIn(accumulate(first, second, rest));
}
/** Fails if the subject is equal to any element in the given iterable. */
- public void isNotIn(Iterable<?> iterable) {
+ public void isNotIn(@Nullable Iterable<?> iterable) {
+ checkNotNull(iterable);
if (Iterables.contains(iterable, actual)) {
failWithActual("expected not to be any of", iterable);
}
@@ -359,12 +379,12 @@ public class Subject {
/** Fails if the subject is equal to any of the given elements. */
public void isNoneOf(
- @Nullable Object first, @Nullable Object second, @Nullable Object /*@Nullable*/... rest) {
+ @Nullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest) {
isNotIn(accumulate(first, second, rest));
}
/** Returns the actual value under test. */
- final Object actual() {
+ final @Nullable Object actual() {
return actual;
}
@@ -401,14 +421,19 @@ public class Subject {
if (o instanceof byte[]) {
return base16((byte[]) o);
} else if (o != null && o.getClass().isArray()) {
- String wrapped = Iterables.toString(stringableIterable(new Object[] {o}));
- return wrapped.substring(1, wrapped.length() - 1);
+ return String.valueOf(arrayAsListRecursively(o));
} else if (o instanceof Double) {
return doubleToString((Double) o);
} else if (o instanceof Float) {
return floatToString((Float) o);
} else {
- return String.valueOf(o);
+ // TODO(cpovirk): Consider renaming the called method to mention "NonArray."
+ /*
+ * TODO(cpovirk): Should the called method and arrayAsListRecursively(...) both call back into
+ * formatActualOrExpected for its handling of byte[] and float/double? Or is there some other
+ * restructuring of this set of methods that we should undertake?
+ */
+ return stringValueOfNonFloatingPoint(o);
}
}
@@ -423,40 +448,30 @@ public class Subject {
private static final char[] hexDigits = "0123456789ABCDEF".toCharArray();
- private static Iterable<?> stringableIterable(Object[] array) {
- return Iterables.transform(asList(array), STRINGIFY);
- }
-
- private static final Function<Object, Object> STRINGIFY =
- new Function<Object, Object>() {
- @Override
- public Object apply(@Nullable Object input) {
- if (input != null && input.getClass().isArray()) {
- Iterable<?> iterable;
- if (input.getClass() == boolean[].class) {
- iterable = Booleans.asList((boolean[]) input);
- } else if (input.getClass() == int[].class) {
- iterable = Ints.asList((int[]) input);
- } else if (input.getClass() == long[].class) {
- iterable = Longs.asList((long[]) input);
- } else if (input.getClass() == short[].class) {
- iterable = Shorts.asList((short[]) input);
- } else if (input.getClass() == byte[].class) {
- iterable = Bytes.asList((byte[]) input);
- } else if (input.getClass() == double[].class) {
- iterable = doubleArrayAsString((double[]) input);
- } else if (input.getClass() == float[].class) {
- iterable = floatArrayAsString((float[]) input);
- } else if (input.getClass() == char[].class) {
- iterable = Chars.asList((char[]) input);
- } else {
- iterable = Arrays.asList((Object[]) input);
- }
- return Iterables.transform(iterable, STRINGIFY);
- }
- return input;
- }
- };
+ private static @Nullable Object arrayAsListRecursively(@Nullable Object input) {
+ if (input instanceof Object[]) {
+ return Lists.<@Nullable Object, @Nullable Object>transform(
+ asList((@Nullable Object[]) input), Subject::arrayAsListRecursively);
+ } else if (input instanceof boolean[]) {
+ return Booleans.asList((boolean[]) input);
+ } else if (input instanceof int[]) {
+ return Ints.asList((int[]) input);
+ } else if (input instanceof long[]) {
+ return Longs.asList((long[]) input);
+ } else if (input instanceof short[]) {
+ return Shorts.asList((short[]) input);
+ } else if (input instanceof byte[]) {
+ return Bytes.asList((byte[]) input);
+ } else if (input instanceof double[]) {
+ return doubleArrayAsString((double[]) input);
+ } else if (input instanceof float[]) {
+ return floatArrayAsString((float[]) input);
+ } else if (input instanceof char[]) {
+ return Chars.asList((char[]) input);
+ } else {
+ return input;
+ }
+ }
/**
* The result of comparing two objects for equality. This includes both the "equal"/"not-equal"
@@ -492,7 +507,7 @@ public class Subject {
private final @Nullable ImmutableList<Fact> facts;
- private ComparisonResult(ImmutableList<Fact> facts) {
+ private ComparisonResult(@Nullable ImmutableList<Fact> facts) {
this.facts = facts;
}
@@ -597,7 +612,7 @@ public class Subject {
}
}
- private static boolean gwtSafeObjectEquals(Object actual, Object expected) {
+ private static boolean gwtSafeObjectEquals(@Nullable Object actual, @Nullable Object expected) {
if (actual instanceof Double && expected instanceof Double) {
return Double.doubleToLongBits((Double) actual) == Double.doubleToLongBits((Double) expected);
} else if (actual instanceof Float && expected instanceof Float) {
@@ -633,7 +648,7 @@ public class Subject {
*/
@Deprecated
final StandardSubjectBuilder check() {
- return new StandardSubjectBuilder(metadata.updateForCheckCall());
+ return new StandardSubjectBuilder(checkNotNull(metadata).updateForCheckCall());
}
/**
@@ -664,28 +679,24 @@ public class Subject {
* @param format a template with {@code %s} placeholders
* @param args the arguments to be inserted into those placeholders
*/
- protected final StandardSubjectBuilder check(String format, Object... args) {
+ protected final StandardSubjectBuilder check(String format, @Nullable Object... args) {
return doCheck(OldAndNewValuesAreSimilar.DIFFERENT, format, args);
}
// TODO(b/134064106): Figure out a public API for this.
- final StandardSubjectBuilder checkNoNeedToDisplayBothValues(String format, Object... args) {
+ final StandardSubjectBuilder checkNoNeedToDisplayBothValues(
+ String format, @Nullable Object... args) {
return doCheck(OldAndNewValuesAreSimilar.SIMILAR, format, args);
}
private StandardSubjectBuilder doCheck(
- OldAndNewValuesAreSimilar valuesAreSimilar, String format, Object[] args) {
- final LazyMessage message = new LazyMessage(format, args);
- Function<String, String> descriptionUpdate =
- new Function<String, String>() {
- @Override
- public String apply(String input) {
- return input + "." + message;
- }
- };
+ OldAndNewValuesAreSimilar valuesAreSimilar, String format, @Nullable Object[] args) {
+ LazyMessage message = new LazyMessage(format, args);
return new StandardSubjectBuilder(
- metadata.updateForCheckCall(valuesAreSimilar, descriptionUpdate));
+ checkNotNull(metadata)
+ .updateForCheckCall(
+ valuesAreSimilar, /* descriptionUpdate= */ input -> input + "." + message));
}
/**
@@ -697,7 +708,7 @@ public class Subject {
* returns {@code ignoreCheck().that(... a dummy exception ...)}.
*/
protected final StandardSubjectBuilder ignoreCheck() {
- return StandardSubjectBuilder.forCustomFailureStrategy(IGNORE_STRATEGY);
+ return StandardSubjectBuilder.forCustomFailureStrategy(failure -> {});
}
/**
@@ -782,7 +793,7 @@ public class Subject {
* message as a migration aid, you can inline this method.
*/
@Deprecated
- final void fail(String verb, Object... messageParts) {
+ final void fail(String verb, @Nullable Object... messageParts) {
StringBuilder message = new StringBuilder("Not true that <");
message.append(actualCustomStringRepresentation()).append("> ").append(verb);
for (Object part : messageParts) {
@@ -806,12 +817,12 @@ public class Subject {
* Special version of {@link #failEqualityCheck} for use from {@link IterableSubject}, documented
* further there.
*/
- final void failEqualityCheckForEqualsWithoutDescription(Object expected) {
+ final void failEqualityCheckForEqualsWithoutDescription(@Nullable Object expected) {
failEqualityCheck(EqualityCheck.EQUAL, expected, ComparisonResult.differentNoDescription());
}
private void failEqualityCheck(
- EqualityCheck equalityCheck, Object expected, ComparisonResult difference) {
+ EqualityCheck equalityCheck, @Nullable Object expected, ComparisonResult difference) {
String actualString = actualCustomStringRepresentation();
String expectedString = formatActualOrExpected(expected);
String actualClass = actual == null ? "(null reference)" : actual.getClass().getName();
@@ -859,8 +870,8 @@ public class Subject {
}
} else {
if (equalityCheck == EqualityCheck.EQUAL && actual != null && expected != null) {
- metadata.failEqualityCheck(
- nameAsFacts(), difference.factsOrEmpty(), expectedString, actualString);
+ checkNotNull(metadata)
+ .failEqualityCheck(difference.factsOrEmpty(), expectedString, actualString);
} else {
failEqualityCheckNoComparisonFailure(
difference,
@@ -874,7 +885,7 @@ public class Subject {
* Checks whether the actual and expected values are strings that match except for trailing
* whitespace. If so, reports a failure and returns true.
*/
- private boolean tryFailForTrailingWhitespaceOnly(Object expected) {
+ private boolean tryFailForTrailingWhitespaceOnly(@Nullable Object expected) {
if (!(actual instanceof String) || !(expected instanceof String)) {
return false;
}
@@ -943,7 +954,7 @@ public class Subject {
* Checks whether the actual and expected values are empty strings. If so, reports a failure and
* returns true.
*/
- private boolean tryFailForEmptyString(Object expected) {
+ private boolean tryFailForEmptyString(@Nullable Object expected) {
if (!(actual instanceof String) || !(expected instanceof String)) {
return false;
}
@@ -1038,8 +1049,7 @@ public class Subject {
*/
@Deprecated
final void failWithoutSubject(String check) {
- String strSubject = this.customName == null ? "the subject" : "\"" + customName + "\"";
- failWithoutActual(simpleFact(lenientFormat("Not true that %s %s", strSubject, check)));
+ failWithoutActual(simpleFact(lenientFormat("Not true that the subject %s", check)));
}
/**
@@ -1183,16 +1193,6 @@ public class Subject {
}
private void doFail(ImmutableList<Fact> facts) {
- metadata.fail(prependNameIfAny(facts));
- }
-
- private ImmutableList<Fact> prependNameIfAny(ImmutableList<Fact> facts) {
- return concat(nameAsFacts(), facts);
- }
-
- private ImmutableList<Fact> nameAsFacts() {
- return customName == null
- ? ImmutableList.<Fact>of()
- : ImmutableList.of(fact("name", customName));
+ checkNotNull(metadata).fail(facts);
}
}
diff --git a/core/src/main/java/com/google/common/truth/SubjectUtils.java b/core/src/main/java/com/google/common/truth/SubjectUtils.java
index 07ef011f..ae55c066 100644
--- a/core/src/main/java/com/google/common/truth/SubjectUtils.java
+++ b/core/src/main/java/com/google/common/truth/SubjectUtils.java
@@ -22,21 +22,21 @@ import static com.google.common.collect.Multisets.immutableEntry;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
-import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultiset;
+import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multiset;
-import com.google.common.collect.SetMultimap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Utility methods used in {@code Subject} implementors.
@@ -49,15 +49,15 @@ final class SubjectUtils {
static final String HUMAN_UNDERSTANDABLE_EMPTY_STRING = "\"\" (empty String)";
- static <T> List<T> accumulate(T first, T second, T... rest) {
+ static <T extends @Nullable Object> List<T> accumulate(T first, T second, T @Nullable ... rest) {
// rest should never be deliberately null, so assume that the caller passed null
// in the third position but intended it to be the third element in the array of values.
// Javac makes the opposite inference, so handle that here.
- List<T> items = new ArrayList<T>(2 + ((rest == null) ? 1 : rest.length));
+ List<T> items = new ArrayList<>(2 + ((rest == null) ? 1 : rest.length));
items.add(first);
items.add(second);
if (rest == null) {
- items.add(null);
+ items.add((T) null);
} else {
items.addAll(Arrays.asList(rest));
}
@@ -89,7 +89,8 @@ final class SubjectUtils {
return (count > 1) ? item + " [" + count + " copies]" : item;
}
- private static <T> NonHashingMultiset<T> countDuplicatesToMultiset(Iterable<T> items) {
+ private static <T extends @Nullable Object> NonHashingMultiset<T> countDuplicatesToMultiset(
+ Iterable<T> items) {
// We use avoid hashing in case the elements don't have a proper
// .hashCode() method (e.g., MessageSet from old versions of protobuf).
NonHashingMultiset<T> multiset = new NonHashingMultiset<>();
@@ -138,26 +139,23 @@ final class SubjectUtils {
}
}
- private static final class NonHashingMultiset<E> {
- // This ought to be static, but the generics are easier when I can refer to <E>.
- private final Function<Multiset.Entry<Wrapper<E>>, Multiset.Entry<?>> unwrapKey =
- new Function<Multiset.Entry<Wrapper<E>>, Multiset.Entry<?>>() {
- @Override
- public Multiset.Entry<?> apply(Multiset.Entry<Wrapper<E>> input) {
- return immutableEntry(input.getElement().get(), input.getCount());
- }
- };
+ private static final class NonHashingMultiset<E extends @Nullable Object> {
+ /*
+ * This ought to be static, but the generics are easier when I can refer to <E>. We still want
+ * an Entry<?> so that entrySet() can return Iterable<Entry<?>> instead of Iterable<Entry<E>>.
+ * That way, it can be returned directly from DuplicateGroupedAndTyped.entrySet() without our
+ * having to generalize *its* return type to Iterable<? extends Entry<?>>.
+ */
+ private Multiset.Entry<?> unwrapKey(Multiset.Entry<Wrapper<E>> input) {
+ return immutableEntry(input.getElement().get(), input.getCount());
+ }
- private final Multiset<Equivalence.Wrapper<E>> contents = LinkedHashMultiset.create();
+ private final Multiset<Wrapper<E>> contents = LinkedHashMultiset.create();
void add(E element) {
contents.add(EQUALITY_WITHOUT_USING_HASH_CODE.wrap(element));
}
- boolean remove(E element) {
- return contents.remove(EQUALITY_WITHOUT_USING_HASH_CODE.wrap(element));
- }
-
int totalCopies() {
return contents.size();
}
@@ -167,7 +165,7 @@ final class SubjectUtils {
}
Iterable<Multiset.Entry<?>> entrySet() {
- return transform(contents.entrySet(), unwrapKey);
+ return transform(contents.entrySet(), this::unwrapKey);
}
String toStringWithBrackets() {
@@ -261,13 +259,14 @@ final class SubjectUtils {
*
* <p>Example: {@code retainMatchingToString([1L, 2L, 2L], [2, 3]) == [2L, 2L]}
*/
- static List<Object> retainMatchingToString(Iterable<?> items, Iterable<?> itemsToCheck) {
- SetMultimap<String, Object> stringValueToItemsToCheck = HashMultimap.create();
+ static List<@Nullable Object> retainMatchingToString(
+ Iterable<?> items, Iterable<?> itemsToCheck) {
+ ListMultimap<String, @Nullable Object> stringValueToItemsToCheck = ArrayListMultimap.create();
for (Object itemToCheck : itemsToCheck) {
stringValueToItemsToCheck.put(String.valueOf(itemToCheck), itemToCheck);
}
- List<Object> result = Lists.newArrayList();
+ List<@Nullable Object> result = Lists.newArrayList();
for (Object item : items) {
for (Object itemToCheck : stringValueToItemsToCheck.get(String.valueOf(item))) {
if (!Objects.equal(itemToCheck, item)) {
@@ -292,7 +291,7 @@ final class SubjectUtils {
return !retainMatchingToString(items1, items2).isEmpty();
}
- static String objectToTypeName(Object item) {
+ static String objectToTypeName(@Nullable Object item) {
// TODO(cpovirk): Merge this with the code in Subject.failEqualityCheck().
if (item == null) {
// The name "null type" comes from the interface javax.lang.model.type.NullType.
@@ -342,7 +341,7 @@ final class SubjectUtils {
return itemsWithTypeInfo;
}
- static <T> Collection<T> iterableToCollection(Iterable<T> iterable) {
+ static <T extends @Nullable Object> Collection<T> iterableToCollection(Iterable<T> iterable) {
if (iterable instanceof Collection) {
// Should be safe to assume that any Iterable implementing Collection isn't a one-shot
// iterable, right? I sure hope so.
@@ -352,7 +351,7 @@ final class SubjectUtils {
}
}
- static <T> List<T> iterableToList(Iterable<T> iterable) {
+ static <T extends @Nullable Object> List<T> iterableToList(Iterable<T> iterable) {
if (iterable instanceof List) {
return (List<T>) iterable;
} else {
@@ -366,7 +365,7 @@ final class SubjectUtils {
*
* <p>Returns the given iterable if it contains no empty strings.
*/
- static <T> Iterable<T> annotateEmptyStrings(Iterable<T> items) {
+ static <T extends @Nullable Object> Iterable<T> annotateEmptyStrings(Iterable<T> items) {
if (Iterables.contains(items, "")) {
List<T> annotatedItems = Lists.newArrayList();
for (T item : items) {
diff --git a/core/src/main/java/com/google/common/truth/TableSubject.java b/core/src/main/java/com/google/common/truth/TableSubject.java
index 87fcd69f..9ab8f5c3 100644
--- a/core/src/main/java/com/google/common/truth/TableSubject.java
+++ b/core/src/main/java/com/google/common/truth/TableSubject.java
@@ -17,6 +17,7 @@ package com.google.common.truth;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.truth.Fact.fact;
import static com.google.common.truth.Fact.simpleFact;
import com.google.common.collect.Table;
@@ -30,7 +31,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Kurt Alfred Kluever
*/
public final class TableSubject extends Subject {
- private final Table<?, ?, ?> actual;
+ private final @Nullable Table<?, ?, ?> actual;
TableSubject(FailureMetadata metadata, @Nullable Table<?, ?, ?> table) {
super(metadata, table);
@@ -39,14 +40,14 @@ public final class TableSubject extends Subject {
/** Fails if the table is not empty. */
public void isEmpty() {
- if (!actual.isEmpty()) {
+ if (!checkNotNull(actual).isEmpty()) {
failWithActual(simpleFact("expected to be empty"));
}
}
/** Fails if the table is empty. */
public void isNotEmpty() {
- if (actual.isEmpty()) {
+ if (checkNotNull(actual).isEmpty()) {
failWithoutActual(simpleFact("expected not to be empty"));
}
}
@@ -54,59 +55,77 @@ public final class TableSubject extends Subject {
/** Fails if the table does not have the given size. */
public final void hasSize(int expectedSize) {
checkArgument(expectedSize >= 0, "expectedSize(%s) must be >= 0", expectedSize);
- check("size()").that(actual.size()).isEqualTo(expectedSize);
+ check("size()").that(checkNotNull(actual).size()).isEqualTo(expectedSize);
}
/** Fails if the table does not contain a mapping for the given row key and column key. */
public void contains(@Nullable Object rowKey, @Nullable Object columnKey) {
- if (!actual.contains(rowKey, columnKey)) {
- fail("contains mapping for row/column", rowKey, columnKey);
+ if (!checkNotNull(actual).contains(rowKey, columnKey)) {
+ /*
+ * TODO(cpovirk): Consider including information about whether any cell with the given row
+ * *or* column was present.
+ */
+ failWithActual(
+ simpleFact("expected to contain mapping for row-column key pair"),
+ fact("row key", rowKey),
+ fact("column key", columnKey));
}
}
/** Fails if the table contains a mapping for the given row key and column key. */
public void doesNotContain(@Nullable Object rowKey, @Nullable Object columnKey) {
- if (actual.contains(rowKey, columnKey)) {
- fail("does not contain mapping for row/column", rowKey, columnKey);
+ if (checkNotNull(actual).contains(rowKey, columnKey)) {
+ failWithoutActual(
+ simpleFact("expected not to contain mapping for row-column key pair"),
+ fact("row key", rowKey),
+ fact("column key", columnKey),
+ fact("but contained value", actual.get(rowKey, columnKey)),
+ fact("full contents", actual));
}
}
/** Fails if the table does not contain the given cell. */
public void containsCell(
@Nullable Object rowKey, @Nullable Object colKey, @Nullable Object value) {
- containsCell(Tables.<Object, Object, Object>immutableCell(rowKey, colKey, value));
+ containsCell(
+ Tables.<@Nullable Object, @Nullable Object, @Nullable Object>immutableCell(
+ rowKey, colKey, value));
}
/** Fails if the table does not contain the given cell. */
public void containsCell(Cell<?, ?, ?> cell) {
checkNotNull(cell);
- checkNoNeedToDisplayBothValues("cellSet()").that(actual.cellSet()).contains(cell);
+ checkNoNeedToDisplayBothValues("cellSet()").that(checkNotNull(actual).cellSet()).contains(cell);
}
/** Fails if the table contains the given cell. */
public void doesNotContainCell(
@Nullable Object rowKey, @Nullable Object colKey, @Nullable Object value) {
- doesNotContainCell(Tables.<Object, Object, Object>immutableCell(rowKey, colKey, value));
+ doesNotContainCell(
+ Tables.<@Nullable Object, @Nullable Object, @Nullable Object>immutableCell(
+ rowKey, colKey, value));
}
/** Fails if the table contains the given cell. */
public void doesNotContainCell(Cell<?, ?, ?> cell) {
checkNotNull(cell);
- checkNoNeedToDisplayBothValues("cellSet()").that(actual.cellSet()).doesNotContain(cell);
+ checkNoNeedToDisplayBothValues("cellSet()")
+ .that(checkNotNull(actual).cellSet())
+ .doesNotContain(cell);
}
/** Fails if the table does not contain the given row key. */
public void containsRow(@Nullable Object rowKey) {
- check("rowKeySet()").that(actual.rowKeySet()).contains(rowKey);
+ check("rowKeySet()").that(checkNotNull(actual).rowKeySet()).contains(rowKey);
}
/** Fails if the table does not contain the given column key. */
public void containsColumn(@Nullable Object columnKey) {
- check("columnKeySet()").that(actual.columnKeySet()).contains(columnKey);
+ check("columnKeySet()").that(checkNotNull(actual).columnKeySet()).contains(columnKey);
}
/** Fails if the table does not contain the given value. */
public void containsValue(@Nullable Object value) {
- check("values()").that(actual.values()).contains(value);
+ check("values()").that(checkNotNull(actual).values()).contains(value);
}
}
diff --git a/core/src/main/java/com/google/common/truth/ThrowableSubject.java b/core/src/main/java/com/google/common/truth/ThrowableSubject.java
index 8e0761da..e85476d2 100644
--- a/core/src/main/java/com/google/common/truth/ThrowableSubject.java
+++ b/core/src/main/java/com/google/common/truth/ThrowableSubject.java
@@ -15,6 +15,8 @@
*/
package com.google.common.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import org.checkerframework.checker.nullness.qual.Nullable;
/**
@@ -23,7 +25,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Kurt Alfred Kluever
*/
public class ThrowableSubject extends Subject {
- private final Throwable actual;
+ private final @Nullable Throwable actual;
/**
* Constructor for use by subclasses. If you want to create an instance of this class itself, call
@@ -53,7 +55,7 @@ public class ThrowableSubject extends Subject {
"(Note from Truth: When possible, instead of asserting on the full message, assert"
+ " about individual facts by using ExpectFailure.assertThat.)");
}
- return check.that(actual.getMessage());
+ return check.that(checkNotNull(actual).getMessage());
}
/**
@@ -61,6 +63,8 @@ public class ThrowableSubject extends Subject {
* cause. This method can be invoked repeatedly (e.g. {@code
* assertThat(e).hasCauseThat().hasCauseThat()....} to assert on a particular indirect cause.
*/
+ // Any Throwable is fine, and we use plain Throwable to emphasize that it's not used "for real."
+ @SuppressWarnings("ShouldNotSubclass")
public final ThrowableSubject hasCauseThat() {
// provides a more helpful error message if hasCauseThat() methods are chained too deep
// e.g. assertThat(new Exception()).hCT().hCT()....
@@ -74,6 +78,7 @@ public class ThrowableSubject extends Subject {
.that(
new Throwable() {
@Override
+ @SuppressWarnings("UnsynchronizedOverridesSynchronized")
public Throwable fillInStackTrace() {
setStackTrace(new StackTraceElement[0]); // for old versions of Android
return this;
diff --git a/core/src/main/java/com/google/common/truth/Truth.gwt.xml b/core/src/main/java/com/google/common/truth/Truth.gwt.xml
index e0be07a6..98e2232f 100644
--- a/core/src/main/java/com/google/common/truth/Truth.gwt.xml
+++ b/core/src/main/java/com/google/common/truth/Truth.gwt.xml
@@ -5,19 +5,26 @@
</source>
<!--
- We used to set this only for packages that had manual supersource.
- That worked everywhere that I know of except for one place:
- when running the GWT util.concurrent tests under Guava.
- The problem is that GWT responds poorly to two .gwt.xml files in the same Java package:
- https://goo.gl/pRV3Yn
- The summary is that it ignores one file in favor of the other.
- util.concurrent, like nearly all our packages, has two .gwt.xml files: one for prod and one for tests.
- util.concurrent, unlike our other packages, has, as of this writing, test supersource but no prod supersource.
- GWT happens to use the prod .gwt.xml, so it looks for no supersource for tests, either.
- This causes it to fail to find AtomicLongMapTest.
- Our workaround is to tell GWT that util.concurrent and all other packages have prod supersource, even if they have none.
- GWT is happy to ignore us when we specify a nonexistent path.
- (I hope that this workaround does not cause its own problems in the future.)
+ We used to set this only for packages that had manual supersource. That
+ worked everywhere that I know of except for one place: when running the GWT
+ util.concurrent tests under Guava.
+
+ The problem is that GWT responds poorly to two .gwt.xml files in the same
+ Java package; see https://goo.gl/pRV3Yn for details.
+
+ The summary is that it ignores one file in favor of the other.
+ util.concurrent, like nearly all our packages, has two .gwt.xml files: one
+ for prod and one for tests. However, unlike our other packages, as of this
+ writing it has test supersource but no prod supersource.
+
+ GWT happens to use the prod .gwt.xml, so it looks for no supersource for
+ tests, either. This causes it to fail to find AtomicLongMapTest.
+
+ Our workaround is to tell GWT that util.concurrent and all other packages
+ have prod supersource, even if they have none. GWT is happy to ignore us
+ when we specify a nonexistent path.
+
+ (I hope that this workaround does not cause its own problems in the future.)
-->
<super-source path="super"/>
diff --git a/core/src/main/java/com/google/common/truth/Truth.java b/core/src/main/java/com/google/common/truth/Truth.java
index fa9b5aee..1afbccaa 100644
--- a/core/src/main/java/com/google/common/truth/Truth.java
+++ b/core/src/main/java/com/google/common/truth/Truth.java
@@ -73,21 +73,18 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class Truth {
private Truth() {}
- private static final FailureStrategy THROW_ASSERTION_ERROR =
- new FailureStrategy() {
- @Override
- public void fail(AssertionError failure) {
- throw failure;
- }
- };
-
+ @SuppressWarnings("ConstantCaseForConstants") // Despite the "Builder" name, it's not mutable.
private static final StandardSubjectBuilder ASSERT =
- StandardSubjectBuilder.forCustomFailureStrategy(THROW_ASSERTION_ERROR);
+ StandardSubjectBuilder.forCustomFailureStrategy(
+ failure -> {
+ throw failure;
+ });
/**
* Begins a call chain with the fluent Truth API. If the check made by the chain fails, it will
* throw {@link AssertionError}.
*/
+ @SuppressWarnings("MemberName") // The underscore is a weird but intentional choice.
public static StandardSubjectBuilder assert_() {
return ASSERT;
}
@@ -101,7 +98,7 @@ public final class Truth {
* StandardSubjectBuilder#about about(...)}, as discussed in <a
* href="https://truth.dev/faq#java8">this FAQ entry</a>.
*/
- public static StandardSubjectBuilder assertWithMessage(String messageToPrepend) {
+ public static StandardSubjectBuilder assertWithMessage(@Nullable String messageToPrepend) {
return assert_().withMessage(messageToPrepend);
}
@@ -121,7 +118,7 @@ public final class Truth {
* @throws IllegalArgumentException if the number of placeholders in the format string does not
* equal the number of given arguments
*/
- public static StandardSubjectBuilder assertWithMessage(String format, Object... args) {
+ public static StandardSubjectBuilder assertWithMessage(String format, @Nullable Object... args) {
return assert_().withMessage(format, args);
}
@@ -144,7 +141,8 @@ public final class Truth {
return assert_().about(factory);
}
- public static <T extends Comparable<?>> ComparableSubject<T> assertThat(@Nullable T actual) {
+ public static <ComparableT extends Comparable<?>> ComparableSubject<ComparableT> assertThat(
+ @Nullable ComparableT actual) {
return assert_().that(actual);
}
@@ -157,6 +155,7 @@ public final class Truth {
}
@GwtIncompatible("ClassSubject.java")
+ @J2ktIncompatible
public static ClassSubject assertThat(@Nullable Class<?> actual) {
return assert_().that(actual);
}
@@ -193,39 +192,40 @@ public final class Truth {
return assert_().that(actual);
}
- public static <T> ObjectArraySubject<T> assertThat(@Nullable T /*@Nullable*/[] actual) {
+ @SuppressWarnings("AvoidObjectArrays")
+ public static <T> ObjectArraySubject<T> assertThat(@Nullable T @Nullable [] actual) {
return assert_().that(actual);
}
- public static PrimitiveBooleanArraySubject assertThat(boolean /*@Nullable*/[] actual) {
+ public static PrimitiveBooleanArraySubject assertThat(boolean @Nullable [] actual) {
return assert_().that(actual);
}
- public static PrimitiveShortArraySubject assertThat(short /*@Nullable*/[] actual) {
+ public static PrimitiveShortArraySubject assertThat(short @Nullable [] actual) {
return assert_().that(actual);
}
- public static PrimitiveIntArraySubject assertThat(int /*@Nullable*/[] actual) {
+ public static PrimitiveIntArraySubject assertThat(int @Nullable [] actual) {
return assert_().that(actual);
}
- public static PrimitiveLongArraySubject assertThat(long /*@Nullable*/[] actual) {
+ public static PrimitiveLongArraySubject assertThat(long @Nullable [] actual) {
return assert_().that(actual);
}
- public static PrimitiveByteArraySubject assertThat(byte /*@Nullable*/[] actual) {
+ public static PrimitiveByteArraySubject assertThat(byte @Nullable [] actual) {
return assert_().that(actual);
}
- public static PrimitiveCharArraySubject assertThat(char /*@Nullable*/[] actual) {
+ public static PrimitiveCharArraySubject assertThat(char @Nullable [] actual) {
return assert_().that(actual);
}
- public static PrimitiveFloatArraySubject assertThat(float /*@Nullable*/[] actual) {
+ public static PrimitiveFloatArraySubject assertThat(float @Nullable [] actual) {
return assert_().that(actual);
}
- public static PrimitiveDoubleArraySubject assertThat(double /*@Nullable*/[] actual) {
+ public static PrimitiveDoubleArraySubject assertThat(double @Nullable [] actual) {
return assert_().that(actual);
}
@@ -296,18 +296,18 @@ public final class Truth {
}
static SimpleAssertionError createWithNoStack(String message) {
- return createWithNoStack(message, /*cause=*/ null);
+ return createWithNoStack(message, /* cause= */ null);
}
@Override
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
- public Throwable getCause() {
+ public @Nullable Throwable getCause() {
return cause;
}
@Override
public String toString() {
- return getLocalizedMessage();
+ return checkNotNull(getLocalizedMessage());
}
}
}
diff --git a/core/src/main/java/com/google/common/truth/TruthFailureSubject.java b/core/src/main/java/com/google/common/truth/TruthFailureSubject.java
index 8724f991..eb9f9387 100644
--- a/core/src/main/java/com/google/common/truth/TruthFailureSubject.java
+++ b/core/src/main/java/com/google/common/truth/TruthFailureSubject.java
@@ -55,12 +55,13 @@ public final class TruthFailureSubject extends ThrowableSubject {
private static final Factory<TruthFailureSubject, AssertionError> FACTORY =
new Factory<TruthFailureSubject, AssertionError>() {
@Override
- public TruthFailureSubject createSubject(FailureMetadata metadata, AssertionError actual) {
+ public TruthFailureSubject createSubject(
+ FailureMetadata metadata, @Nullable AssertionError actual) {
return new TruthFailureSubject(metadata, actual, "failure");
}
};
- private final AssertionError actual;
+ private final @Nullable AssertionError actual;
TruthFailureSubject(
FailureMetadata metadata, @Nullable AssertionError actual, @Nullable String typeDescription) {
@@ -71,7 +72,7 @@ public final class TruthFailureSubject extends ThrowableSubject {
/** Returns a subject for the list of fact keys. */
public IterableSubject factKeys() {
if (!(actual instanceof ErrorWithFacts)) {
- failWithActual(simpleFact("expected a failure thrown by Truth's new failure API"));
+ failWithActual(simpleFact("expected a failure thrown by Truth's failure API"));
return ignoreCheck().that(ImmutableList.of());
}
ErrorWithFacts error = (ErrorWithFacts) actual;
@@ -124,7 +125,7 @@ public final class TruthFailureSubject extends ThrowableSubject {
private StringSubject doFactValue(String key, @Nullable Integer index) {
checkNotNull(key);
if (!(actual instanceof ErrorWithFacts)) {
- failWithActual(simpleFact("expected a failure thrown by Truth's new failure API"));
+ failWithActual(simpleFact("expected a failure thrown by Truth's failure API"));
return ignoreCheck().that("");
}
ErrorWithFacts error = (ErrorWithFacts) actual;
diff --git a/core/src/main/java/com/google/common/truth/TruthJUnit.java b/core/src/main/java/com/google/common/truth/TruthJUnit.java
index 3c70d887..ad82efb2 100644
--- a/core/src/main/java/com/google/common/truth/TruthJUnit.java
+++ b/core/src/main/java/com/google/common/truth/TruthJUnit.java
@@ -16,7 +16,7 @@
package com.google.common.truth;
import com.google.common.annotations.GwtIncompatible;
-import org.junit.internal.AssumptionViolatedException;
+import org.junit.AssumptionViolatedException;
/**
* Provides a way to use Truth to perform JUnit "assumptions." An assumption is a check that, if
@@ -41,20 +41,17 @@ import org.junit.internal.AssumptionViolatedException;
* @author Christian Gruber (cgruber@israfil.net)
*/
@GwtIncompatible("JUnit4")
+@J2ktIncompatible
public final class TruthJUnit {
- private static final FailureStrategy THROW_ASSUMPTION_ERROR =
- new FailureStrategy() {
- @Override
- public void fail(AssertionError failure) {
- ThrowableAssumptionViolatedException assumptionViolated =
- new ThrowableAssumptionViolatedException(failure.getMessage(), failure.getCause());
- assumptionViolated.setStackTrace(failure.getStackTrace());
- throw assumptionViolated;
- }
- };
-
+ @SuppressWarnings("ConstantCaseForConstants") // Despite the "Builder" name, it's not mutable.
private static final StandardSubjectBuilder ASSUME =
- StandardSubjectBuilder.forCustomFailureStrategy(THROW_ASSUMPTION_ERROR);
+ StandardSubjectBuilder.forCustomFailureStrategy(
+ failure -> {
+ AssumptionViolatedException assumptionViolated =
+ new AssumptionViolatedException(failure.getMessage(), failure.getCause());
+ assumptionViolated.setStackTrace(failure.getStackTrace());
+ throw assumptionViolated;
+ });
/**
* Begins a call chain with the fluent Truth API. If the check made by the chain fails, it will
@@ -64,13 +61,5 @@ public final class TruthJUnit {
return ASSUME;
}
- // TODO(diamondm): remove this and use org.junit.AssumptionViolatedException once we're on v4.12
- private static class ThrowableAssumptionViolatedException extends AssumptionViolatedException {
- public ThrowableAssumptionViolatedException(String message, Throwable throwable) {
- super(message);
- if (throwable != null) initCause(throwable);
- }
- }
-
private TruthJUnit() {}
}
diff --git a/core/src/main/java/com/google/common/truth/UsedByReflection.java b/core/src/main/java/com/google/common/truth/UsedByReflection.java
new file mode 100644
index 00000000..ce41dfd8
--- /dev/null
+++ b/core/src/main/java/com/google/common/truth/UsedByReflection.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013 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 java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Target;
+
+@Target({METHOD, FIELD, CONSTRUCTOR})
+@interface UsedByReflection {}
diff --git a/core/src/main/java/com/google/common/truth/super/com/google/common/truth/Platform.java b/core/src/main/java/com/google/common/truth/super/com/google/common/truth/Platform.java
index ed2eb2c4..4642f8ab 100644
--- a/core/src/main/java/com/google/common/truth/super/com/google/common/truth/Platform.java
+++ b/core/src/main/java/com/google/common/truth/super/com/google/common/truth/Platform.java
@@ -20,10 +20,12 @@ import static java.lang.Float.parseFloat;
import static jsinterop.annotations.JsPackage.GLOBAL;
import com.google.common.collect.ImmutableList;
+import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
import org.checkerframework.checker.nullness.qual.Nullable;
+
/**
* Extracted routines that need to be swapped in for GWT, to allow for minimal deltas between the
* GWT and non-GWT version.
@@ -50,21 +52,6 @@ final class Platform {
return false;
}
- abstract static class PlatformComparisonFailure extends AssertionError {
- PlatformComparisonFailure(
- String message,
- String unusedUnderGwtExpected,
- String unusedUnderGwtActual,
- Throwable cause) {
- super(message, cause);
- }
-
- @Override
- public final String toString() {
- return getLocalizedMessage();
- }
- }
-
/** Determines if the given subject contains a match for the given regex. */
static boolean containsMatch(String subject, String regex) {
return compile(regex).test(subject);
@@ -82,7 +69,7 @@ final class Platform {
// Do nothing. See notes in StackTraceCleanerTest.
}
- static String inferDescription() {
+ static @Nullable String inferDescription() {
return null;
}
@@ -97,6 +84,21 @@ final class Platform {
return null;
}
+ abstract static class PlatformComparisonFailure extends AssertionError {
+ PlatformComparisonFailure(
+ String message,
+ String unusedUnderGwtExpected,
+ String unusedUnderGwtActual,
+ @Nullable Throwable cause) {
+ super(message, cause);
+ }
+
+ @Override
+ public final String toString() {
+ return "" + getLocalizedMessage();
+ }
+ }
+
static String doubleToString(double value) {
// This probably doesn't match Java perfectly, but we do our best.
if (value == Double.POSITIVE_INFINITY) {
@@ -136,9 +138,29 @@ final class Platform {
return ((NativeNumber) (Object) value).toLocaleString("en-US", JavaLikeOptions.INSTANCE);
}
- /** Tests if current platform is Android which is always false. */
- static boolean isAndroid() {
- return false;
+ @JsType(isNative = true, namespace = "proto.im")
+ private static class Message {
+ public native String serialize();
+ }
+
+ @JsMethod(namespace = "proto.im.debug")
+ private static native Object dump(Message msg) /*-{
+ // Emtpy stub to make GWT happy. This will never get executed under GWT.
+ throw new Error();
+ }-*/;
+
+ /** Turns a non-double, non-float object into a string. */
+ static String stringValueOfNonFloatingPoint(@Nullable Object o) {
+ // Check if we are in J2CL mode by probing a system property that only exists in GWT.
+ boolean inJ2clMode = "doesntexist".equals(System.getProperty("superdevmode", "doesntexist"));
+ if (inJ2clMode && o instanceof Message) {
+ Message msg = (Message) o;
+ boolean dumpAvailable =
+ "true".equals(System.getProperty("goog.DEBUG", "true"))
+ && !"true".equals(System.getProperty("COMPILED", "false"));
+ return dumpAvailable ? dump(msg).toString() : msg.serialize();
+ }
+ return String.valueOf(o);
}
/** Returns a human readable string representation of the throwable's stack trace. */
@@ -147,6 +169,11 @@ final class Platform {
return throwable.toString();
}
+ /** Tests if current platform is Android which is always false. */
+ static boolean isAndroid() {
+ return false;
+ }
+
/**
* A GWT-swapped version of test rule interface that does nothing. All methods extended from
* {@link org.junit.rules.TestRule} needs to be stripped.
@@ -170,9 +197,9 @@ final class Platform {
@JsType(isNative = true, name = "RegExp", namespace = GLOBAL)
private static class NativeRegExp {
- public NativeRegExp(String pattern) {}
+ public NativeRegExp(@Nullable String pattern) {}
- public native boolean test(String input);
+ public native boolean test(@Nullable String input);
}
@JsType(isNative = true, name = "Number", namespace = GLOBAL)
@@ -233,4 +260,13 @@ final class Platform {
*/
return new ComparisonFailureWithFacts(messages, facts, expected, actual, cause);
}
+
+ static boolean isKotlinRange(Iterable<?> iterable) {
+ return false;
+ }
+
+ static boolean kotlinRangeContains(Iterable<?> haystack, @Nullable Object needle) {
+ throw new AssertionError(); // never called under GWT because isKotlinRange returns false
+ }
}
+
diff --git a/core/src/test/java/com/google/common/truth/ActualValueInferenceTest.java b/core/src/test/java/com/google/common/truth/ActualValueInferenceTest.java
index cc0a441b..9bee28aa 100644
--- a/core/src/test/java/com/google/common/truth/ActualValueInferenceTest.java
+++ b/core/src/test/java/com/google/common/truth/ActualValueInferenceTest.java
@@ -17,17 +17,26 @@ package com.google.common.truth;
import static com.google.common.truth.ExpectFailure.assertThat;
import static com.google.common.truth.ExpectFailure.expectFailure;
+import static org.junit.Assert.assertThrows;
+import static org.junit.runner.Description.createTestDescription;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.ImmutableList;
-import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.junit.runners.model.Statement;
/** Tests for {@link ActualValueInference}. */
@GwtIncompatible // Inference doesn't work under GWT.
@RunWith(JUnit4.class)
+/*
+ * We declare a single `failure` variable in each method, and many methods assign to it multiple
+ * times. We declare it without initializing it so that every assignment to it can look the same as
+ * every other (rather than having an initial combined initialization+assignment that looks slightly
+ * different.
+ */
+@SuppressWarnings("InitializeInline")
public final class ActualValueInferenceTest {
@Test
public void simple() {
@@ -115,9 +124,7 @@ public final class ActualValueInferenceTest {
failure =
expectFailure(
- whenTesting -> {
- whenTesting.that(makeException()).hasMessageThat().isEqualTo("b");
- });
+ whenTesting -> whenTesting.that(makeException()).hasMessageThat().isEqualTo("b"));
assertThat(failure).factValue("value of").isEqualTo("makeException().getMessage()");
}
@@ -180,6 +187,26 @@ public final class ActualValueInferenceTest {
assertThat(failure).factKeys().doesNotContain("value of");
}
+ @Test
+ public void expect() {
+ Expect expect = Expect.create();
+ Statement testMethod =
+ new Statement() {
+ @Override
+ public void evaluate() {
+ expect.that(staticNoArg()).isEqualTo("b");
+ }
+ };
+ Statement wrapped = expect.apply(testMethod, createTestDescription("MyTest", "myMethod"));
+ AssertionError failure = assertThrows(AssertionError.class, wrapped::evaluate);
+ /*
+ * We can't use factValue here because Expect throws a plain wrapper AssertionError, not the
+ * original ErrorWithFacts. We could in theory change that someday, perhaps as part of a
+ * followup to https://github.com/google/truth/issues/543, but it seems unlikely.
+ */
+ assertThat(failure).hasMessageThat().contains("staticNoArg()");
+ }
+
static String staticNoArg() {
return "a";
}
@@ -196,7 +223,7 @@ public final class ActualValueInferenceTest {
return "a";
}
- List<Integer> oneTwoThree() {
+ ImmutableList<Integer> oneTwoThree() {
return ImmutableList.of(1, 2, 3);
}
diff --git a/core/src/test/java/com/google/common/truth/ChainingTest.java b/core/src/test/java/com/google/common/truth/ChainingTest.java
index 7d958fa7..318c6877 100644
--- a/core/src/test/java/com/google/common/truth/ChainingTest.java
+++ b/core/src/test/java/com/google/common/truth/ChainingTest.java
@@ -211,6 +211,7 @@ public final class ChainingTest extends BaseSubjectTestCase {
@Test
public void badFormat() {
try {
+ @SuppressWarnings("LenientFormatStringValidation") // Intentional for testing.
Object unused = assertThat("root").check("%s %s", 1, 2, 3);
assert_().fail();
} catch (IllegalArgumentException expected) {
diff --git a/core/src/test/java/com/google/common/truth/ComparableSubjectCompileTest.java b/core/src/test/java/com/google/common/truth/ComparableSubjectCompileTest.java
deleted file mode 100644
index 767fbd0f..00000000
--- a/core/src/test/java/com/google/common/truth/ComparableSubjectCompileTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2014 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.truth.Truth.assertAbout;
-import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
-
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests for {@link ComparableSubject} calls that should fail to compile.
- *
- * @author Kurt Alfred Kluever
- */
-@RunWith(JUnit4.class)
-public class ComparableSubjectCompileTest {
- @Test
- public void comparableMixedTypesDontCompile() {
- JavaFileObject file =
- JavaFileObjects.forSourceLines(
- "test.MyTest",
- "package test;",
- "import static com.google.common.truth.Truth.assertThat;",
- "class MyTest {",
- " public void testFoo() {",
- " assertThat(new ComparableType(3)).isLessThan(\"kak\");",
- " }",
- " private static final class ComparableType implements Comparable<ComparableType> {",
- " private final int wrapped;",
- " private ComparableType(int toWrap) {",
- " this.wrapped = toWrap;",
- " }",
- " @Override public int compareTo(ComparableType other) {",
- " return wrapped - ((ComparableType) other).wrapped;",
- " }",
- " }",
- "}");
-
- assertAbout(javaSource())
- .that(file)
- // https://github.com/google/compile-testing/issues/149
- .withCompilerOptions("-sourcepath", "")
- .failsToCompile()
- .withErrorContaining("java.lang.String cannot be converted to test.MyTest.ComparableType")
- .in(file)
- .onLine(5);
- }
-
- @Test
- public void rawComparableTypeMixedTypes() {
- JavaFileObject file =
- JavaFileObjects.forSourceLines(
- "test.MyTest",
- "package test;",
- "import static com.google.common.truth.Truth.assertThat;",
- "class MyTest {",
- " public void testFoo() {",
- " assertThat(new RawComparableType(3)).isLessThan(\"kak\");",
- " }",
- " private static final class RawComparableType implements Comparable {",
- " private final int wrapped;",
- " private RawComparableType(int toWrap) {",
- " this.wrapped = toWrap;",
- " }",
- " @Override public int compareTo(Object other) {",
- " return wrapped - ((RawComparableType) other).wrapped;",
- " }",
- " }",
- "}");
- assertAbout(javaSource())
- .that(file)
- // https://github.com/google/compile-testing/issues/149
- .withCompilerOptions("-sourcepath", "")
- .failsToCompile()
- .withErrorContaining(
- "java.lang.String cannot be converted to test.MyTest.RawComparableType")
- .in(file)
- .onLine(5);
- }
-}
diff --git a/core/src/test/java/com/google/common/truth/ComparableSubjectTest.java b/core/src/test/java/com/google/common/truth/ComparableSubjectTest.java
index 86aa41fc..d59bd348 100644
--- a/core/src/test/java/com/google/common/truth/ComparableSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/ComparableSubjectTest.java
@@ -22,7 +22,6 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
import com.google.common.collect.Range;
-import com.google.common.primitives.Ints;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -36,6 +35,8 @@ import org.junit.runners.JUnit4;
public class ComparableSubjectTest extends BaseSubjectTestCase {
@Test
+ // test of a mistaken call and of unnecessary use of isEquivalentAccordingToCompareTo
+ @SuppressWarnings({"deprecation", "IntegerComparison"})
public void testNulls() {
try {
assertThat(6).isEquivalentAccordingToCompareTo(null);
@@ -105,7 +106,11 @@ public class ComparableSubjectTest extends BaseSubjectTestCase {
@Override
public int compareTo(StringComparedByLength other) {
- return Ints.compare(value.length(), other.value.length());
+ /*
+ * Even though Integer.compare was added in Java 7, we use it even under old versions of
+ * Android, as discussed in IterableSubjectTest.
+ */
+ return Integer.compare(value.length(), other.value.length());
}
@Override
@@ -221,7 +226,7 @@ public class ComparableSubjectTest extends BaseSubjectTestCase {
assertThat(new RawComparableType(3)).isLessThan(new RawComparableType(4));
}
- @SuppressWarnings("ComparableType")
+ @SuppressWarnings({"ComparableType", "rawtypes"})
private static final class RawComparableType implements Comparable {
private final int wrapped;
diff --git a/core/src/test/java/com/google/common/truth/CorrespondenceExceptionStoreTest.java b/core/src/test/java/com/google/common/truth/CorrespondenceExceptionStoreTest.java
index d6589216..bdcec87c 100644
--- a/core/src/test/java/com/google/common/truth/CorrespondenceExceptionStoreTest.java
+++ b/core/src/test/java/com/google/common/truth/CorrespondenceExceptionStoreTest.java
@@ -104,7 +104,8 @@ public final class CorrespondenceExceptionStoreTest extends BaseSubjectTestCase
assertThat(second.key).isEqualTo("first exception");
assertThat(second.value)
.matches( // an initial statement of the method that threw and the exception type:
- "compare\\(null, 123\\) threw java.lang.NullPointerException"
+ "compare\\(null, 123\\) threw "
+ + "com.google.common.truth.TestCorrespondences\\$NullPointerExceptionFromWithin10Of"
// some whitespace:
+ "\\s+"
// the start of a stack trace, with the correct class:
diff --git a/core/src/test/java/com/google/common/truth/CorrespondenceTest.java b/core/src/test/java/com/google/common/truth/CorrespondenceTest.java
index ac29057e..781d9cba 100644
--- a/core/src/test/java/com/google/common/truth/CorrespondenceTest.java
+++ b/core/src/test/java/com/google/common/truth/CorrespondenceTest.java
@@ -22,9 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList;
import static org.junit.Assert.fail;
-import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
-import org.checkerframework.checker.nullness.qual.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -39,16 +37,7 @@ public final class CorrespondenceTest extends BaseSubjectTestCase {
// Tests of the abstract base class (just assert that equals and hashCode throw).
private static final Correspondence<Object, Object> INSTANCE =
- Correspondence.from(
- // If we were allowed to use lambdas, this would be:
- // (a, e) -> false,
- new Correspondence.BinaryPredicate<Object, Object>() {
- @Override
- public boolean apply(@Nullable Object actual, @Nullable Object expected) {
- return false;
- }
- },
- "has example property");
+ Correspondence.from((a, e) -> false, "has example property");
@Test
@SuppressWarnings("deprecation") // testing deprecated method
@@ -73,16 +62,7 @@ public final class CorrespondenceTest extends BaseSubjectTestCase {
// Tests of the 'from' factory method.
private static final Correspondence<String, String> STRING_PREFIX_EQUALITY =
- // If we were allowed to use method references here, this would be:
- // Correspondence.from(String::startsWith, "starts with");
- Correspondence.from(
- new Correspondence.BinaryPredicate<String, String>() {
- @Override
- public boolean apply(String actual, String expected) {
- return actual.startsWith(expected);
- }
- },
- "starts with");
+ Correspondence.from(String::startsWith, "starts with");
@Test
public void testFrom_compare() {
@@ -149,33 +129,13 @@ public final class CorrespondenceTest extends BaseSubjectTestCase {
// Tests of the 'transform' factory methods.
private static final Correspondence<String, Integer> LENGTHS =
- // If we were allowed to use method references here, this would be:
- // Correspondence.transforming(String::length, "has a length of");
- Correspondence.transforming(
- new Function<String, Integer>() {
- @Override
- public Integer apply(String str) {
- return str.length();
- }
- },
- "has a length of");
+ Correspondence.transforming(String::length, "has a length of");
private static final Correspondence<String, Integer> HYPHEN_INDEXES =
- // If we were allowed to use lambdas here, this would be:
- // Correspondence.transforming(
- // str -> {
- // int index = str.indexOf('-');
- // return (index >= 0) ? index : null;
- // },
- // "has a hyphen at an index of");
- // (Or else perhaps we'd pull out a method for the lambda body and use a method reference?)
Correspondence.transforming(
- new Function<String, Integer>() {
- @Override
- public @Nullable Integer apply(String str) {
- int index = str.indexOf('-');
- return (index >= 0) ? index : null;
- }
+ str -> {
+ int index = str.indexOf('-');
+ return (index >= 0) ? index : null;
},
"has a hyphen at an index of");
@@ -269,32 +229,14 @@ public final class CorrespondenceTest extends BaseSubjectTestCase {
}
private static final Correspondence<String, String> HYPHENS_MATCH_COLONS =
- // If we were allowed to use lambdas here, this would be:
- // Correspondence.transforming(
- // str -> {
- // int index = str.indexOf('-');
- // return (index >= 0) ? index : null;
- // },
- // str -> {
- // int index = str.indexOf(':');
- // return (index >= 0) ? index : null;
- // },
- // "has a hyphen at the same index as the colon in");
- // (Or else perhaps we'd pull out a method for the lambda bodies?)
Correspondence.transforming(
- new Function<String, Integer>() {
- @Override
- public @Nullable Integer apply(String str) {
- int index = str.indexOf('-');
- return (index >= 0) ? index : null;
- }
+ str -> {
+ int index = str.indexOf('-');
+ return (index >= 0) ? index : null;
},
- new Function<String, Integer>() {
- @Override
- public @Nullable Integer apply(String str) {
- int index = str.indexOf(':');
- return (index >= 0) ? index : null;
- }
+ str -> {
+ int index = str.indexOf(':');
+ return (index >= 0) ? index : null;
},
"has a hyphen at the same index as the colon in");
@@ -567,24 +509,8 @@ public final class CorrespondenceTest extends BaseSubjectTestCase {
// Tests of formattingDiffsUsing.
private static final Correspondence<String, Integer> LENGTHS_WITH_DIFF =
- // If we were allowed to use method references and lambdas here, this would be:
- // Correspondence.transforming(String::length, "has a length of")
- // .formattingDiffsUsing((a, e) -> Integer.toString(a.length() - e));
- Correspondence.transforming(
- new Function<String, Integer>() {
- @Override
- public Integer apply(String str) {
- return str.length();
- }
- },
- "has a length of")
- .formattingDiffsUsing(
- new Correspondence.DiffFormatter<String, Integer>() {
- @Override
- public String formatDiff(String actualString, Integer expectedLength) {
- return Integer.toString(actualString.length() - expectedLength);
- }
- });
+ Correspondence.transforming(String::length, "has a length of")
+ .formattingDiffsUsing((a, e) -> Integer.toString(a.length() - e));
@Test
public void testFormattingDiffsUsing_compare() {
diff --git a/core/src/test/java/com/google/common/truth/CustomFailureMessageTest.java b/core/src/test/java/com/google/common/truth/CustomFailureMessageTest.java
index 39910b32..6a702595 100644
--- a/core/src/test/java/com/google/common/truth/CustomFailureMessageTest.java
+++ b/core/src/test/java/com/google/common/truth/CustomFailureMessageTest.java
@@ -29,6 +29,7 @@ import org.junit.runners.JUnit4;
*
* @author Christian Gruber (cgruber@israfil.net)
*/
+@SuppressWarnings("LenientFormatStringValidation") // Intentional for testing
@RunWith(JUnit4.class)
public class CustomFailureMessageTest extends BaseSubjectTestCase {
diff --git a/core/src/test/java/com/google/common/truth/DoubleSubjectTest.java b/core/src/test/java/com/google/common/truth/DoubleSubjectTest.java
index f96b474e..e6535584 100644
--- a/core/src/test/java/com/google/common/truth/DoubleSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/DoubleSubjectTest.java
@@ -38,8 +38,8 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
private static final double NEARLY_MAX = 1.7976931348623155E308;
private static final double NEGATIVE_NEARLY_MAX = -1.7976931348623155E308;
- private static final double OVER_MIN = 1.0E-323;
- private static final double UNDER_NEGATIVE_MIN = -1.0E-323;
+ private static final double OVER_MIN = 9.9E-324;
+ private static final double UNDER_NEGATIVE_MIN = -9.9E-324;
private static final double GOLDEN = 1.23;
private static final double OVER_GOLDEN = 1.2300000000000002;
@@ -96,8 +96,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThatIsWithinFails(Double.NaN, 1000.0, 2.0);
}
- private static void assertThatIsWithinFails(
- final double actual, final double tolerance, final double expected) {
+ private static void assertThatIsWithinFails(double actual, double tolerance, double expected) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -129,8 +128,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThatIsNotWithinFails(Double.NaN, 1000.0, 2.0);
}
- private static void assertThatIsNotWithinFails(
- final double actual, final double tolerance, final double expected) {
+ private static void assertThatIsNotWithinFails(double actual, double tolerance, double expected) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -371,7 +369,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThat(1.0).isEqualTo(1);
}
- private static void assertThatIsEqualToFails(final double actual, final double expected) {
+ private static void assertThatIsEqualToFails(double actual, double expected) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -394,7 +392,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThat(1.0).isNotEqualTo(2);
}
- private static void assertThatIsNotEqualToFails(final @Nullable Double value) {
+ private static void assertThatIsNotEqualToFails(@Nullable Double value) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -416,7 +414,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThatIsZeroFails(null);
}
- private static void assertThatIsZeroFails(final @Nullable Double value) {
+ private static void assertThatIsZeroFails(@Nullable Double value) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -439,7 +437,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThatIsNonZeroFails(null, "expected a double other than zero");
}
- private static void assertThatIsNonZeroFails(final @Nullable Double value, String factKey) {
+ private static void assertThatIsNonZeroFails(@Nullable Double value, String factKey) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -460,7 +458,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThatIsPositiveInfinityFails(null);
}
- private static void assertThatIsPositiveInfinityFails(final @Nullable Double value) {
+ private static void assertThatIsPositiveInfinityFails(@Nullable Double value) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -480,7 +478,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThatIsNegativeInfinityFails(null);
}
- private static void assertThatIsNegativeInfinityFails(final @Nullable Double value) {
+ private static void assertThatIsNegativeInfinityFails(@Nullable Double value) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -500,7 +498,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThatIsNaNFails(null);
}
- private static void assertThatIsNaNFails(final @Nullable Double value) {
+ private static void assertThatIsNaNFails(@Nullable Double value) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
@@ -522,7 +520,7 @@ public class DoubleSubjectTest extends BaseSubjectTestCase {
assertThatIsFiniteFails(null);
}
- private static void assertThatIsFiniteFails(final @Nullable Double value) {
+ private static void assertThatIsFiniteFails(@Nullable Double value) {
ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<DoubleSubject, Double>() {
@Override
diff --git a/core/src/test/java/com/google/common/truth/ExpectFailureNonRuleTest.java b/core/src/test/java/com/google/common/truth/ExpectFailureNonRuleTest.java
index 1e8f464d..460c35b3 100644
--- a/core/src/test/java/com/google/common/truth/ExpectFailureNonRuleTest.java
+++ b/core/src/test/java/com/google/common/truth/ExpectFailureNonRuleTest.java
@@ -35,7 +35,7 @@ public class ExpectFailureNonRuleTest {
@Test
public void testExpect_userThrowExceptionInSubject_shouldPropagate() throws Exception {
- final List<Failure> reportedFailure = Lists.newArrayList();
+ List<Failure> reportedFailure = Lists.newArrayList();
RunNotifier runNotifier = new RunNotifier();
runNotifier.addListener(
new RunListener() {
@@ -59,7 +59,7 @@ public class ExpectFailureNonRuleTest {
@Test
public void testExpect_userThrowExceptionAfterSubject_shouldPropagate() throws Exception {
- final List<Failure> reportedFailure = Lists.newArrayList();
+ List<Failure> reportedFailure = Lists.newArrayList();
RunNotifier runNotifier = new RunNotifier();
runNotifier.addListener(
new RunListener() {
diff --git a/core/src/test/java/com/google/common/truth/ExpectFailureRuleTest.java b/core/src/test/java/com/google/common/truth/ExpectFailureRuleTest.java
index d79d75b7..5938ce25 100644
--- a/core/src/test/java/com/google/common/truth/ExpectFailureRuleTest.java
+++ b/core/src/test/java/com/google/common/truth/ExpectFailureRuleTest.java
@@ -24,7 +24,7 @@ import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-/** Tests for {@link ExpectFailure} used as JUnit {@link Rule).*/
+/** Tests for {@link ExpectFailure} used as JUnit {@link Rule}. */
@RunWith(JUnit4.class)
@GwtIncompatible("org.junit.Rule")
public class ExpectFailureRuleTest {
diff --git a/core/src/test/java/com/google/common/truth/ExpectFailureWithStackTraceTest.java b/core/src/test/java/com/google/common/truth/ExpectFailureWithStackTraceTest.java
index 3542475c..8ac3e561 100644
--- a/core/src/test/java/com/google/common/truth/ExpectFailureWithStackTraceTest.java
+++ b/core/src/test/java/com/google/common/truth/ExpectFailureWithStackTraceTest.java
@@ -44,7 +44,7 @@ public class ExpectFailureWithStackTraceTest {
@Override
public Statement apply(Statement base, Description description) {
- final Statement s = delegate.apply(base, description);
+ Statement s = delegate.apply(base, description);
return new Statement() {
@Override
public void evaluate() throws Throwable {
diff --git a/core/src/test/java/com/google/common/truth/ExpectTest.java b/core/src/test/java/com/google/common/truth/ExpectTest.java
index e079ee14..f7371c45 100644
--- a/core/src/test/java/com/google/common/truth/ExpectTest.java
+++ b/core/src/test/java/com/google/common/truth/ExpectTest.java
@@ -32,7 +32,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestRule;
-import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.junit.runners.model.Statement;
@@ -44,6 +43,8 @@ import org.junit.runners.model.Statement;
* @author Christian Gruber (cgruber@israfil.net)
*/
@RunWith(JUnit4.class)
+// We use ExpectedException so that we can test our code that runs after the test method completes.
+@SuppressWarnings({"ExpectedExceptionChecker", "deprecation"})
public class ExpectTest {
private final Expect oopsNotARule = Expect.create();
@@ -51,10 +52,8 @@ public class ExpectTest {
private final ExpectedException thrown = ExpectedException.none();
private final TestRule postTestWait =
- new TestRule() {
- @Override
- public Statement apply(final Statement base, Description description) {
- return new Statement() {
+ (base, description) ->
+ new Statement() {
@Override
public void evaluate() throws Throwable {
base.evaluate();
@@ -62,8 +61,6 @@ public class ExpectTest {
taskToAwait.get();
}
};
- }
- };
private final CountDownLatch testMethodComplete = new CountDownLatch(1);
@@ -74,14 +71,11 @@ public class ExpectTest {
@Rule
public final TestRule wrapper =
- new TestRule() {
- @Override
- public Statement apply(Statement statement, Description description) {
- statement = expect.apply(statement, description);
- statement = postTestWait.apply(statement, description);
- statement = thrown.apply(statement, description);
- return statement;
- }
+ (statement, description) -> {
+ statement = expect.apply(statement, description);
+ statement = postTestWait.apply(statement, description);
+ statement = thrown.apply(statement, description);
+ return statement;
};
@Test
@@ -189,13 +183,7 @@ public class ExpectTest {
@Test
public void bash() throws Exception {
- Runnable task =
- new Runnable() {
- @Override
- public void run() {
- expect.that(3).isEqualTo(4);
- }
- };
+ Runnable task = () -> expect.that(3).isEqualTo(4);
List<Future<?>> results = new ArrayList<>();
ExecutorService executor = newFixedThreadPool(10);
for (int i = 0; i < 1000; i++) {
@@ -213,15 +201,12 @@ public class ExpectTest {
ExecutorService executor = newSingleThreadExecutor();
taskToAwait =
executor.submit(
- new Runnable() {
- @Override
- public void run() {
- awaitUninterruptibly(testMethodComplete);
- try {
- expect.that(3);
- fail();
- } catch (IllegalStateException expected) {
- }
+ () -> {
+ awaitUninterruptibly(testMethodComplete);
+ try {
+ expect.that(3);
+ fail();
+ } catch (IllegalStateException expected) {
}
});
executor.shutdown();
@@ -235,19 +220,16 @@ public class ExpectTest {
* expect.that(3).isEqualTo(4), we would always either fail the test or throw an
* IllegalStateException, not record a "failure" that we never read.
*/
- final IntegerSubject expectThat3 = expect.that(3);
+ IntegerSubject expectThat3 = expect.that(3);
taskToAwait =
executor.submit(
- new Runnable() {
- @Override
- public void run() {
- awaitUninterruptibly(testMethodComplete);
- try {
- expectThat3.isEqualTo(4);
- fail();
- } catch (IllegalStateException expected) {
- assertThat(expected).hasCauseThat().isInstanceOf(AssertionError.class);
- }
+ () -> {
+ awaitUninterruptibly(testMethodComplete);
+ try {
+ expectThat3.isEqualTo(4);
+ fail();
+ } catch (IllegalStateException expected) {
+ assertThat(expected).hasCauseThat().isInstanceOf(AssertionError.class);
}
});
executor.shutdown();
diff --git a/core/src/test/java/com/google/common/truth/ExpectWithStackTest.java b/core/src/test/java/com/google/common/truth/ExpectWithStackTest.java
index 528568c8..ae2fcb1a 100644
--- a/core/src/test/java/com/google/common/truth/ExpectWithStackTest.java
+++ b/core/src/test/java/com/google/common/truth/ExpectWithStackTest.java
@@ -123,7 +123,7 @@ public class ExpectWithStackTest {
private static final class TestRuleVerifier implements TestRule {
private final TestRule ruleToVerify;
- private ErrorVerifier errorVerifier = NO_VERIFIER;
+ private ErrorVerifier errorVerifier = error -> {};
TestRuleVerifier(TestRule ruleToVerify) {
this.ruleToVerify = ruleToVerify;
@@ -134,7 +134,7 @@ public class ExpectWithStackTest {
}
@Override
- public Statement apply(final Statement base, final Description description) {
+ public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
@@ -151,10 +151,4 @@ public class ExpectWithStackTest {
interface ErrorVerifier {
void verify(AssertionError error);
}
-
- private static final ErrorVerifier NO_VERIFIER =
- new ErrorVerifier() {
- @Override
- public void verify(AssertionError expected) {}
- };
}
diff --git a/core/src/test/java/com/google/common/truth/FloatSubjectTest.java b/core/src/test/java/com/google/common/truth/FloatSubjectTest.java
index c404a731..b528ab09 100644
--- a/core/src/test/java/com/google/common/truth/FloatSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/FloatSubjectTest.java
@@ -96,8 +96,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThatIsWithinFails(Float.NaN, 1000.0f, 2.0f);
}
- private static void assertThatIsWithinFails(
- final float actual, final float tolerance, final float expected) {
+ private static void assertThatIsWithinFails(float actual, float tolerance, float expected) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -129,8 +128,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThatIsNotWithinFails(Float.NaN, 1000.0f, 2.0f);
}
- private static void assertThatIsNotWithinFails(
- final float actual, final float tolerance, final float expected) {
+ private static void assertThatIsNotWithinFails(float actual, float tolerance, float expected) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -371,7 +369,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThat(1.0f).isEqualTo(1);
}
- private static void assertThatIsEqualToFails(final float actual, final float expected) {
+ private static void assertThatIsEqualToFails(float actual, float expected) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -394,7 +392,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThat(1.0f).isNotEqualTo(2);
}
- private static void assertThatIsNotEqualToFails(final @Nullable Float value) {
+ private static void assertThatIsNotEqualToFails(@Nullable Float value) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -416,7 +414,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThatIsZeroFails(null);
}
- private static void assertThatIsZeroFails(final @Nullable Float value) {
+ private static void assertThatIsZeroFails(@Nullable Float value) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -439,7 +437,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThatIsNonZeroFails(null, "expected a float other than zero");
}
- private static void assertThatIsNonZeroFails(final @Nullable Float value, String factKey) {
+ private static void assertThatIsNonZeroFails(@Nullable Float value, String factKey) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -460,7 +458,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThatIsPositiveInfinityFails(null);
}
- private static void assertThatIsPositiveInfinityFails(final @Nullable Float value) {
+ private static void assertThatIsPositiveInfinityFails(@Nullable Float value) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -480,7 +478,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThatIsNegativeInfinityFails(null);
}
- private static void assertThatIsNegativeInfinityFails(final @Nullable Float value) {
+ private static void assertThatIsNegativeInfinityFails(@Nullable Float value) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -500,7 +498,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThatIsNaNFails(null);
}
- private static void assertThatIsNaNFails(final @Nullable Float value) {
+ private static void assertThatIsNaNFails(@Nullable Float value) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
@@ -522,7 +520,7 @@ public class FloatSubjectTest extends BaseSubjectTestCase {
assertThatIsFiniteFails(null);
}
- private static void assertThatIsFiniteFails(final @Nullable Float value) {
+ private static void assertThatIsFiniteFails(@Nullable Float value) {
ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float> callback =
new ExpectFailure.SimpleSubjectBuilderCallback<FloatSubject, Float>() {
@Override
diff --git a/core/src/test/java/com/google/common/truth/IntegerSubjectTest.java b/core/src/test/java/com/google/common/truth/IntegerSubjectTest.java
index 46103043..bc6a5a02 100644
--- a/core/src/test/java/com/google/common/truth/IntegerSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/IntegerSubjectTest.java
@@ -234,8 +234,8 @@ public class IntegerSubjectTest extends BaseSubjectTestCase {
}
ImmutableSet<Object> fortyTwosNoChar = ImmutableSet.<Object>of(byte42, short42, int42, long42);
- for (final Object actual : fortyTwosNoChar) {
- for (final Object expected : fortyTwosNoChar) {
+ for (Object actual : fortyTwosNoChar) {
+ for (Object expected : fortyTwosNoChar) {
ExpectFailure.SimpleSubjectBuilderCallback<Subject, Object> actualFirst =
new ExpectFailure.SimpleSubjectBuilderCallback<Subject, Object>() {
@Override
diff --git a/core/src/test/java/com/google/common/truth/IterableSubjectCorrespondenceTest.java b/core/src/test/java/com/google/common/truth/IterableSubjectCorrespondenceTest.java
index bb075e2e..f9e3986d 100644
--- a/core/src/test/java/com/google/common/truth/IterableSubjectCorrespondenceTest.java
+++ b/core/src/test/java/com/google/common/truth/IterableSubjectCorrespondenceTest.java
@@ -32,9 +32,10 @@ import static com.google.common.truth.TestCorrespondences.STRING_PARSES_TO_INTEG
import static com.google.common.truth.TestCorrespondences.WITHIN_10_OF;
import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList;
+import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableList;
-import com.google.common.truth.TestCorrespondences.Record;
+import com.google.common.truth.TestCorrespondences.MyRecord;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
@@ -55,6 +56,41 @@ import org.junit.runners.JUnit4;
public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
+ // test of a mistaken call
+ @SuppressWarnings({"EqualsIncompatibleType", "DoNotCall", "deprecation"})
+ public void equalsThrowsUSOE() {
+ try {
+ boolean unused =
+ assertThat(ImmutableList.of(42.0))
+ .comparingElementsUsing(tolerance(10e-5))
+ .equals(ImmutableList.of(0.0));
+ } catch (UnsupportedOperationException expected) {
+ assertThat(expected)
+ .hasMessageThat()
+ .isEqualTo(
+ "UsingCorrespondence.equals() is not supported. Did you mean to call"
+ + " containsExactlyElementsIn(expected) instead of equals(expected)?");
+ return;
+ }
+ fail("Should have thrown.");
+ }
+
+ @Test
+ @SuppressWarnings({"DoNotCall", "deprecation"}) // test of a mistaken call
+ public void hashCodeThrowsUSOE() {
+ try {
+ int unused =
+ assertThat(ImmutableList.of(42.0)).comparingElementsUsing(tolerance(10e-5)).hashCode();
+ } catch (UnsupportedOperationException expected) {
+ assertThat(expected)
+ .hasMessageThat()
+ .isEqualTo("UsingCorrespondence.hashCode() is not supported.");
+ return;
+ }
+ fail("Should have thrown.");
+ }
+
+ @Test
public void contains_success() {
ImmutableList<String> actual = ImmutableList.of("not a number", "+123", "+456", "+789");
assertThat(actual)
@@ -123,14 +159,14 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_1arg_contains() {
- Record expected = Record.create(2, 200);
- ImmutableList<Record> actual =
+ MyRecord expected = MyRecord.create(2, 200);
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 211),
- Record.create(4, 400),
- Record.create(2, 189),
- Record.createWithoutId(999));
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 211),
+ MyRecord.create(4, 400),
+ MyRecord.create(2, 189),
+ MyRecord.createWithoutId(999));
expectFailure
.whenTesting()
.that(actual)
@@ -156,14 +192,14 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_1arg_contains_noDiff() {
- Record expected = Record.create(2, 200);
- ImmutableList<Record> actual =
+ MyRecord expected = MyRecord.create(2, 200);
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 211),
- Record.create(4, 400),
- Record.create(2, 189),
- Record.createWithoutId(999));
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 211),
+ MyRecord.create(4, 400),
+ MyRecord.create(2, 189),
+ MyRecord.createWithoutId(999));
expectFailure
.whenTesting()
.that(actual)
@@ -182,8 +218,8 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_1arg_contains_handlesActualKeyerExceptions() {
- Record expected = Record.create(0, 999);
- List<Record> actual = asList(Record.create(1, 100), null, Record.create(4, 400));
+ MyRecord expected = MyRecord.create(0, 999);
+ List<MyRecord> actual = asList(MyRecord.create(1, 100), null, MyRecord.create(4, 400));
expectFailure
.whenTesting()
.that(actual)
@@ -203,8 +239,8 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_1arg_contains_handlesExpectedKeyerExceptions() {
- List<Record> actual =
- asList(Record.create(1, 100), Record.create(2, 200), Record.create(4, 400));
+ List<MyRecord> actual =
+ asList(MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.create(4, 400));
expectFailure
.whenTesting()
.that(actual)
@@ -224,8 +260,8 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_1arg_contains_handlesFormatDiffExceptions() {
- Record expected = Record.create(0, 999);
- List<Record> actual = asList(Record.create(1, 100), null, Record.create(4, 400));
+ MyRecord expected = MyRecord.create(0, 999);
+ List<MyRecord> actual = asList(MyRecord.create(1, 100), null, MyRecord.create(4, 400));
expectFailure
.whenTesting()
.that(actual)
@@ -622,18 +658,18 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_1arg_containsExactlyElementsIn() {
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(3, 300),
- Record.createWithoutId(900));
- ImmutableList<Record> actual =
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(3, 300),
+ MyRecord.createWithoutId(900));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 211),
- Record.create(4, 400),
- Record.createWithoutId(999));
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 211),
+ MyRecord.create(4, 400),
+ MyRecord.createWithoutId(999));
expectFailure
.whenTesting()
.that(actual)
@@ -666,12 +702,12 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_2arg_containsExactlyElementsIn() {
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(3, 300),
- Record.createWithoutId(900));
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(3, 300),
+ MyRecord.createWithoutId(900));
ImmutableList<String> actual = ImmutableList.of("1/100", "2/211", "4/400", "none/999");
expectFailure
.whenTesting()
@@ -705,18 +741,18 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsExactlyElementsIn_onlyKeyed() {
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(3, 300),
- Record.createWithoutId(999));
- ImmutableList<Record> actual =
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(3, 300),
+ MyRecord.createWithoutId(999));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 211),
- Record.create(3, 303),
- Record.createWithoutId(999));
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 211),
+ MyRecord.create(3, 303),
+ MyRecord.createWithoutId(999));
expectFailure
.whenTesting()
.that(actual)
@@ -741,18 +777,18 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsExactlyElementsIn_noKeyed() {
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(3, 300),
- Record.createWithoutId(900));
- ImmutableList<Record> actual =
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(3, 300),
+ MyRecord.createWithoutId(900));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 201),
- Record.create(4, 400),
- Record.createWithoutId(999));
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 201),
+ MyRecord.create(4, 400),
+ MyRecord.createWithoutId(999));
expectFailure
.whenTesting()
.that(actual)
@@ -773,18 +809,18 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsExactlyElementsIn_noDiffs() {
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(3, 300),
- Record.createWithoutId(999));
- ImmutableList<Record> actual =
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(3, 300),
+ MyRecord.createWithoutId(999));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 211),
- Record.create(3, 303),
- Record.createWithoutId(999));
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 211),
+ MyRecord.create(3, 303),
+ MyRecord.createWithoutId(999));
expectFailure
.whenTesting()
.that(actual)
@@ -816,19 +852,19 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
public void displayingDiffsPairedBy_containsExactlyElementsIn_notUnique() {
// The missing elements here are not uniquely keyed by the key function, so the key function
// should be ignored, but a warning about this should be appended to the failure message.
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(3, 300),
- Record.create(3, 301),
- Record.createWithoutId(900));
- ImmutableList<Record> actual =
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(3, 300),
+ MyRecord.create(3, 301),
+ MyRecord.createWithoutId(900));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 211),
- Record.create(4, 400),
- Record.createWithoutId(999));
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 211),
+ MyRecord.create(4, 400),
+ MyRecord.createWithoutId(999));
expectFailure
.whenTesting()
.that(actual)
@@ -850,9 +886,9 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsExactlyElementsIn_handlesActualKeyerExceptions() {
- ImmutableList<Record> expected =
- ImmutableList.of(Record.create(1, 100), Record.create(2, 200), Record.create(4, 400));
- List<Record> actual = asList(Record.create(1, 101), Record.create(2, 211), null);
+ ImmutableList<MyRecord> expected =
+ ImmutableList.of(MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.create(4, 400));
+ List<MyRecord> actual = asList(MyRecord.create(1, 101), MyRecord.create(2, 211), null);
expectFailure
.whenTesting()
.that(actual)
@@ -882,9 +918,9 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsExactlyElementsIn_handlesExpectedKeyerExceptions() {
- List<Record> expected = asList(Record.create(1, 100), Record.create(2, 200), null);
- List<Record> actual =
- asList(Record.create(1, 101), Record.create(2, 211), Record.create(4, 400));
+ List<MyRecord> expected = asList(MyRecord.create(1, 100), MyRecord.create(2, 200), null);
+ List<MyRecord> actual =
+ asList(MyRecord.create(1, 101), MyRecord.create(2, 211), MyRecord.create(4, 400));
expectFailure
.whenTesting()
.that(actual)
@@ -914,9 +950,9 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsExactlyElementsIn_handlesFormatDiffExceptions() {
- ImmutableList<Record> expected =
- ImmutableList.of(Record.create(1, 100), Record.create(2, 200), Record.create(0, 999));
- List<Record> actual = asList(Record.create(1, 101), Record.create(2, 211), null);
+ ImmutableList<MyRecord> expected =
+ ImmutableList.of(MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.create(0, 999));
+ List<MyRecord> actual = asList(MyRecord.create(1, 101), MyRecord.create(2, 211), null);
expectFailure
.whenTesting()
.that(actual)
@@ -1275,15 +1311,16 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingElementsPairedBy_containsAtLeastElementsIn() {
- ImmutableList<Record> expected =
- ImmutableList.of(Record.create(1, 100), Record.create(2, 200), Record.createWithoutId(999));
- ImmutableList<Record> actual =
+ ImmutableList<MyRecord> expected =
+ ImmutableList.of(
+ MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.createWithoutId(999));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 101),
- Record.create(2, 211),
- Record.create(2, 222),
- Record.create(3, 303),
- Record.createWithoutId(888));
+ MyRecord.create(1, 101),
+ MyRecord.create(2, 211),
+ MyRecord.create(2, 222),
+ MyRecord.create(3, 303),
+ MyRecord.createWithoutId(888));
expectFailure
.whenTesting()
.that(actual)
@@ -1318,14 +1355,15 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingElementsPairedBy_containsAtLeastElementsIn_notUnique() {
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
+ ImmutableList.of(
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(2, 201),
+ MyRecord.createWithoutId(999));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(2, 201),
- Record.createWithoutId(999));
- ImmutableList<Record> actual =
- ImmutableList.of(Record.create(1, 101), Record.create(3, 303), Record.createWithoutId(999));
+ MyRecord.create(1, 101), MyRecord.create(3, 303), MyRecord.createWithoutId(999));
expectFailure
.whenTesting()
.that(actual)
@@ -1345,10 +1383,10 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingElementsPairedBy_containsAtLeastElementsIn_handlesFormatDiffExceptions() {
- ImmutableList<Record> expected =
- ImmutableList.of(Record.create(1, 100), Record.create(2, 200), Record.create(0, 999));
- List<Record> actual =
- asList(Record.create(1, 101), Record.create(2, 211), Record.create(3, 303), null);
+ ImmutableList<MyRecord> expected =
+ ImmutableList.of(MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.create(0, 999));
+ List<MyRecord> actual =
+ asList(MyRecord.create(1, 101), MyRecord.create(2, 211), MyRecord.create(3, 303), null);
expectFailure
.whenTesting()
.that(actual)
@@ -1647,19 +1685,19 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsAnyIn_withKeyMatches() {
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(3, 300),
- Record.createWithoutId(999));
- ImmutableList<Record> actual =
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(3, 300),
+ MyRecord.createWithoutId(999));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(3, 311),
- Record.create(2, 211),
- Record.create(2, 222),
- Record.create(4, 404),
- Record.createWithoutId(888));
+ MyRecord.create(3, 311),
+ MyRecord.create(2, 211),
+ MyRecord.create(2, 222),
+ MyRecord.create(4, 404),
+ MyRecord.createWithoutId(888));
expectFailure
.whenTesting()
.that(actual)
@@ -1700,10 +1738,12 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsAnyIn_withoutKeyMatches() {
- ImmutableList<Record> expected =
- ImmutableList.of(Record.create(1, 100), Record.create(2, 200), Record.createWithoutId(999));
- ImmutableList<Record> actual =
- ImmutableList.of(Record.create(3, 300), Record.create(4, 411), Record.createWithoutId(888));
+ ImmutableList<MyRecord> expected =
+ ImmutableList.of(
+ MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.createWithoutId(999));
+ ImmutableList<MyRecord> actual =
+ ImmutableList.of(
+ MyRecord.create(3, 300), MyRecord.create(4, 411), MyRecord.createWithoutId(888));
expectFailure
.whenTesting()
.that(actual)
@@ -1719,14 +1759,15 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsAnyIn_notUnique() {
- ImmutableList<Record> expected =
+ ImmutableList<MyRecord> expected =
+ ImmutableList.of(
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 200),
+ MyRecord.create(2, 250),
+ MyRecord.createWithoutId(999));
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(1, 100),
- Record.create(2, 200),
- Record.create(2, 250),
- Record.createWithoutId(999));
- ImmutableList<Record> actual =
- ImmutableList.of(Record.create(3, 300), Record.create(2, 211), Record.createWithoutId(888));
+ MyRecord.create(3, 300), MyRecord.create(2, 211), MyRecord.createWithoutId(888));
expectFailure
.whenTesting()
.that(actual)
@@ -1743,9 +1784,9 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void displayingDiffsPairedBy_containsAnyIn_handlesFormatDiffExceptions() {
- ImmutableList<Record> expected =
- ImmutableList.of(Record.create(1, 100), Record.create(2, 200), Record.create(0, 999));
- List<Record> actual = asList(Record.create(3, 311), Record.create(4, 404), null);
+ ImmutableList<MyRecord> expected =
+ ImmutableList.of(MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.create(0, 999));
+ List<MyRecord> actual = asList(MyRecord.create(3, 311), MyRecord.create(4, 404), null);
expectFailure
.whenTesting()
.that(actual)
@@ -1993,28 +2034,28 @@ public class IterableSubjectCorrespondenceTest extends BaseSubjectTestCase {
@Test
public void formattingDiffsUsing_success() {
- ImmutableList<Record> actual =
- ImmutableList.of(Record.create(3, 300), Record.create(2, 200), Record.create(1, 100));
+ ImmutableList<MyRecord> actual =
+ ImmutableList.of(MyRecord.create(3, 300), MyRecord.create(2, 200), MyRecord.create(1, 100));
assertThat(actual)
.formattingDiffsUsing(RECORD_DIFF_FORMATTER)
.displayingDiffsPairedBy(RECORD_ID)
- .containsExactly(Record.create(1, 100), Record.create(2, 200), Record.create(3, 300));
+ .containsExactly(MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.create(3, 300));
}
@Test
public void formattingDiffsUsing_failure() {
- ImmutableList<Record> actual =
+ ImmutableList<MyRecord> actual =
ImmutableList.of(
- Record.create(3, 300),
- Record.create(2, 201),
- Record.create(1, 100),
- Record.create(2, 199));
+ MyRecord.create(3, 300),
+ MyRecord.create(2, 201),
+ MyRecord.create(1, 100),
+ MyRecord.create(2, 199));
expectFailure
.whenTesting()
.that(actual)
.formattingDiffsUsing(RECORD_DIFF_FORMATTER)
.displayingDiffsPairedBy(RECORD_ID)
- .containsExactly(Record.create(1, 100), Record.create(2, 200), Record.create(3, 300));
+ .containsExactly(MyRecord.create(1, 100), MyRecord.create(2, 200), MyRecord.create(3, 300));
assertFailureKeys(
"for key",
"missing",
diff --git a/core/src/test/java/com/google/common/truth/IterableSubjectTest.java b/core/src/test/java/com/google/common/truth/IterableSubjectTest.java
index beab5ff7..aaa20465 100644
--- a/core/src/test/java/com/google/common/truth/IterableSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/IterableSubjectTest.java
@@ -21,9 +21,7 @@ import static java.util.Arrays.asList;
import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
-import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -40,6 +38,8 @@ import org.junit.runners.JUnit4;
* @author Christian Gruber (cgruber@israfil.net)
*/
@RunWith(JUnit4.class)
+// "Iterable" is specific enough to establish that we're testing IterableSubject.
+@SuppressWarnings("PreferredInterfaceType")
public class IterableSubjectTest extends BaseSubjectTestCase {
@Test
@@ -48,6 +48,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings({"TruthIterableIsEmpty", "IsEmptyTruth"})
public void hasSizeZero() {
assertThat(ImmutableList.of()).hasSize(0);
}
@@ -204,16 +205,10 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
@Test
public void iterableContainsAnyOfWithOneShotIterable() {
- final Iterator<Object> iterator = asList((Object) 2, 1, "b").iterator();
- Iterable<Object> iterable =
- new Iterable<Object>() {
- @Override
- public Iterator<Object> iterator() {
- return iterator;
- }
- };
+ List<Object> contents = asList(2, 1, "b");
+ Iterable<Object> oneShot = new OneShotIterable<>(contents.iterator(), "OneShotIterable");
- assertThat(iterable).containsAnyOf(3, "a", 7, "b", 0);
+ assertThat(oneShot).containsAnyOf(3, "a", 7, "b", 0);
}
@Test
@@ -390,50 +385,62 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
"expected order for required elements",
"but was");
assertFailureValue("expected order for required elements", "[null, 1, 3]");
+ assertFailureValue("but was", "[1, null, 3]");
}
@Test
- public void iterableContainsAtLeastInOrderWithOneShotIterable() {
- final Iterable<Object> iterable = Arrays.<Object>asList(2, 1, null, 4, "a", 3, "b");
- final Iterator<Object> iterator = iterable.iterator();
- Iterable<Object> oneShot =
- new Iterable<Object>() {
- @Override
- public Iterator<Object> iterator() {
- return iterator;
- }
+ public void iterableContainsAtLeastInOrderWithFailureWithActualOrder() {
+ expectFailureWhenTestingThat(asList(1, 2, null, 3, 4)).containsAtLeast(null, 1, 3).inOrder();
+ assertFailureKeys(
+ "required elements were all found, but order was wrong",
+ "expected order for required elements",
+ "but order was",
+ "full contents");
+ assertFailureValue("expected order for required elements", "[null, 1, 3]");
+ assertFailureValue("but order was", "[1, null, 3]");
+ assertFailureValue("full contents", "[1, 2, null, 3, 4]");
+ }
- @Override
- public String toString() {
- return Iterables.toString(iterable);
- }
- };
+ @Test
+ public void iterableContainsAtLeastInOrderWithOneShotIterable() {
+ List<Object> contents = asList(2, 1, null, 4, "a", 3, "b");
+ Iterable<Object> oneShot = new OneShotIterable<>(contents.iterator(), contents.toString());
assertThat(oneShot).containsAtLeast(1, null, 3).inOrder();
}
@Test
public void iterableContainsAtLeastInOrderWithOneShotIterableWrongOrder() {
- final Iterator<Object> iterator = asList((Object) 2, 1, null, 4, "a", 3, "b").iterator();
- Iterable<Object> iterable =
- new Iterable<Object>() {
- @Override
- public Iterator<Object> iterator() {
- return iterator;
- }
-
- @Override
- public String toString() {
- return "BadIterable";
- }
- };
+ List<Object> contents = asList(2, 1, null, 4, "a", 3, "b");
+ Iterable<Object> oneShot = new OneShotIterable<>(contents.iterator(), "BadIterable");
- expectFailureWhenTestingThat(iterable).containsAtLeast(1, 3, (Object) null).inOrder();
+ expectFailureWhenTestingThat(oneShot).containsAtLeast(1, 3, (Object) null).inOrder();
assertFailureKeys(
"required elements were all found, but order was wrong",
"expected order for required elements",
"but was");
assertFailureValue("expected order for required elements", "[1, 3, null]");
+ assertFailureValue("but was", "BadIterable"); // TODO(b/231966021): Output its elements.
+ }
+
+ private static final class OneShotIterable<E> implements Iterable<E> {
+ private final Iterator<E> iterator;
+ private final String toString;
+
+ OneShotIterable(Iterator<E> iterator, String toString) {
+ this.iterator = iterator;
+ this.toString = toString;
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return iterator;
+ }
+
+ @Override
+ public String toString() {
+ return toString;
+ }
}
@Test
@@ -442,6 +449,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("ContainsAllElementsInWithVarArgsToContainsAtLeast")
public void iterableContainsAtLeastElementsInIterable() {
assertThat(asList(1, 2, 3)).containsAtLeastElementsIn(asList(1, 2));
@@ -452,6 +460,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("ContainsAllElementsInWithVarArgsToContainsAtLeast")
public void iterableContainsAtLeastElementsInCanUseFactPerElement() {
expectFailureWhenTestingThat(asList("abc"))
.containsAtLeastElementsIn(asList("123\n456", "789"));
@@ -507,6 +516,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("ContainsNoneInWithVarArgsToContainsNoneOf")
public void iterableContainsNoneInIterable() {
assertThat(asList(1, 2, 3)).containsNoneIn(asList(4, 5, 6));
expectFailureWhenTestingThat(asList(1, 2, 3)).containsNoneIn(asList(1, 2, 4));
@@ -531,6 +541,8 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ // We tell people to call containsExactlyElementsIn, but we still test containsExactly.
+ @SuppressWarnings("ContainsExactlyVariadic")
public void arrayContainsExactly() {
ImmutableList<String> iterable = ImmutableList.of("a", "b");
String[] array = {"a", "b"};
@@ -652,6 +664,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("ContainsExactlyElementsInWithVarArgsToExactly")
public void iterableContainsExactlyWithElementsThatThrowWhenYouCallHashCode() {
HashCodeThrower one = new HashCodeThrower();
HashCodeThrower two = new HashCodeThrower();
@@ -660,10 +673,24 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
assertThat(asList(one, two)).containsExactly(one, two).inOrder();
assertThat(asList(one, two)).containsExactlyElementsIn(asList(two, one));
assertThat(asList(one, two)).containsExactlyElementsIn(asList(one, two)).inOrder();
+ }
+
+ @Test
+ public void iterableContainsExactlyWithElementsThatThrowWhenYouCallHashCodeFailureTooMany() {
+ HashCodeThrower one = new HashCodeThrower();
+ HashCodeThrower two = new HashCodeThrower();
expectFailureWhenTestingThat(asList(one, two)).containsExactly(one);
}
+ @Test
+ public void iterableContainsExactlyWithElementsThatThrowWhenYouCallHashCodeOneMismatch() {
+ HashCodeThrower one = new HashCodeThrower();
+ HashCodeThrower two = new HashCodeThrower();
+
+ expectFailureWhenTestingThat(asList(one, one)).containsExactly(one, two);
+ }
+
private static class HashCodeThrower {
@Override
public boolean equals(Object other) {
@@ -682,17 +709,20 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("ContainsExactlyNone")
public void iterableContainsExactlyElementsInInOrderPassesWithEmptyExpectedAndActual() {
assertThat(ImmutableList.of()).containsExactlyElementsIn(ImmutableList.of()).inOrder();
}
@Test
+ @SuppressWarnings("ContainsExactlyNone")
public void iterableContainsExactlyElementsInWithEmptyExpected() {
expectFailureWhenTestingThat(asList("foo")).containsExactlyElementsIn(ImmutableList.of());
assertFailureKeys("expected to be empty", "but was");
}
@Test
+ @SuppressWarnings("ContainsExactlyElementsInWithVarArgsToExactly")
public void iterableContainsExactlyElementsInErrorMessageIsInOrder() {
expectFailureWhenTestingThat(asList("foo OR bar"))
.containsExactlyElementsIn(asList("foo", "bar"));
@@ -842,6 +872,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("ContainsExactlyElementsInWithVarArgsToExactly")
public void iterableContainsExactlyElementsInWithOneIterableDoesNotGiveWarning() {
expectFailureWhenTestingThat(asList(1, 2, 3, 4)).containsExactlyElementsIn(asList(1, 2, 3));
assertFailureValue("unexpected (1)", "4");
@@ -885,7 +916,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
@Test
public void iterableContainsExactlyInOrderWithOneShotIterable() {
- final Iterator<Object> iterator = asList((Object) 1, null, 3).iterator();
+ Iterator<Object> iterator = asList((Object) 1, null, 3).iterator();
Iterable<Object> iterable =
new Iterable<Object>() {
@Override
@@ -898,7 +929,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
@Test
public void iterableContainsExactlyInOrderWithOneShotIterableWrongOrder() {
- final Iterator<Object> iterator = asList((Object) 1, null, 3).iterator();
+ Iterator<Object> iterator = asList((Object) 1, null, 3).iterator();
Iterable<Object> iterable =
new Iterable<Object>() {
@Override
@@ -932,6 +963,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("ContainsExactlyElementsInWithVarArgsToExactly")
public void iterableContainsExactlyElementsInIterable() {
assertThat(asList(1, 2)).containsExactlyElementsIn(asList(1, 2));
@@ -948,6 +980,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("UndefinedEquals") // Iterable equality isn't defined, but null equality is
public void nullEqualToNull() {
assertThat((Iterable<?>) null).isEqualTo(null);
}
@@ -1107,13 +1140,9 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
assertFailureValue("full contents", "[1, 10, 2, 20]");
}
+ @SuppressWarnings("CompareProperty") // avoiding Java 8 API under Android
private static final Comparator<String> COMPARE_AS_DECIMAL =
- new Comparator<String>() {
- @Override
- public int compare(String a, String b) {
- return Integer.valueOf(a).compareTo(Integer.valueOf(b));
- }
- };
+ (a, b) -> Integer.valueOf(a).compareTo(Integer.valueOf(b));
private static class Foo {
private final int x;
@@ -1129,13 +1158,20 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
}
- private static final Comparator<Foo> FOO_COMPARATOR =
- new Comparator<Foo>() {
- @Override
- public int compare(Foo a, Foo b) {
- return (a.x < b.x) ? -1 : ((a.x > b.x) ? 1 : 0);
- }
- };
+ // We can't use Comparators.comparing under old versions of Android.
+ @SuppressWarnings({
+ "CompareProperty",
+ "DoubleProperty_ExtractTernaryHead",
+ "FloatProperty_ExtractTernaryHead",
+ "IntegerProperty_ExtractTernaryHead",
+ "LongProperty_ExtractTernaryHead",
+ })
+ // Even though Integer.compare was added in Java 7, we use it even under old versions of Android,
+ // even without library desugaring on: It and a few other APIs are *always* desguared:
+ // https://r8.googlesource.com/r8/+/a7563f86014d44f961f40fc109ab1c1073f2ee4e/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+ // Now, if this code weren't in Truth's *tests*, then it would cause Animal Sniffer to complain.
+ // In that case, we might fall back to the deprecated Guava Ints.compare.
+ private static final Comparator<Foo> FOO_COMPARATOR = (a, b) -> Integer.compare(a.x, b.x);
@Test
public void iterableOrderedByBaseClassComparator() {
@@ -1155,6 +1191,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("deprecation") // test of a mistaken call
public void isNotIn() {
ImmutableList<String> actual = ImmutableList.of("a");
@@ -1180,7 +1217,7 @@ public class IterableSubjectTest extends BaseSubjectTestCase {
}
@Test
- @SuppressWarnings("IncompatibleArgumentType")
+ @SuppressWarnings({"IncompatibleArgumentType", "deprecation"}) // test of a mistaken call
public void isNoneOf() {
ImmutableList<String> actual = ImmutableList.of("a");
diff --git a/core/src/test/java/com/google/common/truth/MapSubjectTest.java b/core/src/test/java/com/google/common/truth/MapSubjectTest.java
index 6e28fdb8..83382e6f 100644
--- a/core/src/test/java/com/google/common/truth/MapSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/MapSubjectTest.java
@@ -1261,7 +1261,9 @@ public class MapSubjectTest extends BaseSubjectTestCase {
"first exception");
assertThatFailure()
.factValue("first exception", 0)
- .startsWith("compare(null, 60) threw java.lang.NullPointerException");
+ .startsWith(
+ "compare(null, 60) threw"
+ + " com.google.common.truth.TestCorrespondences$NullPointerExceptionFromWithin10Of");
assertThatFailure()
.factValue("first exception", 1)
.startsWith("formatDiff(null, 60) threw java.lang.NullPointerException");
@@ -1710,7 +1712,9 @@ public class MapSubjectTest extends BaseSubjectTestCase {
"first exception");
assertThatFailure()
.factValue("first exception", 0)
- .startsWith("compare(null, 60) threw java.lang.NullPointerException");
+ .startsWith(
+ "compare(null, 60) threw"
+ + " com.google.common.truth.TestCorrespondences$NullPointerExceptionFromWithin10Of");
assertThatFailure()
.factValue("first exception", 1)
.startsWith("formatDiff(null, 60) threw java.lang.NullPointerException");
@@ -2068,7 +2072,9 @@ public class MapSubjectTest extends BaseSubjectTestCase {
"first exception");
assertThatFailure()
.factValue("first exception", 0)
- .startsWith("compare(null, 60) threw java.lang.NullPointerException");
+ .startsWith(
+ "compare(null, 60) threw"
+ + " com.google.common.truth.TestCorrespondences$NullPointerExceptionFromWithin10Of");
assertThatFailure()
.factValue("first exception", 1)
.startsWith("formatDiff(null, 60) threw java.lang.NullPointerException");
diff --git a/core/src/test/java/com/google/common/truth/MathUtilTest.java b/core/src/test/java/com/google/common/truth/MathUtilTest.java
index 292bacd8..1200fafe 100644
--- a/core/src/test/java/com/google/common/truth/MathUtilTest.java
+++ b/core/src/test/java/com/google/common/truth/MathUtilTest.java
@@ -107,6 +107,6 @@ public class MathUtilTest {
assertThat(equalWithinTolerance(1.3f, 1.3d, 0.00000000000001f)).isFalse();
}
- // TODO(user): More complicated ways to break float/double casting to make sure.
+ // TODO(cgruber): More complicated ways to break float/double casting to make sure.
}
diff --git a/core/src/test/java/com/google/common/truth/ObjectArraySubjectTest.java b/core/src/test/java/com/google/common/truth/ObjectArraySubjectTest.java
index d33682a8..b1f7c35f 100644
--- a/core/src/test/java/com/google/common/truth/ObjectArraySubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/ObjectArraySubjectTest.java
@@ -40,7 +40,7 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
@SuppressWarnings("TruthSelfEquals")
@Test
- public void isEqualTo_Same() {
+ public void isEqualTo_same() {
Object[] same = objectArray("A", 5L);
assertThat(same).isEqualTo(same);
}
@@ -104,20 +104,20 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
}
@Test
- public void isEqualTo_Fail_UnequalOrdering() {
+ public void isEqualTo_fail_unequalOrdering() {
expectFailureWhenTestingThat(objectArray("A", 5L)).isEqualTo(objectArray(5L, "A"));
assertFailureValue("differs at index", "[0]");
}
@Test
- public void isEqualTo_Fail_UnequalOrderingMultiDimensional_00() {
+ public void isEqualTo_fail_unequalOrderingMultiDimensional_00() {
expectFailureWhenTestingThat(new Object[][] {{"A"}, {5L}})
.isEqualTo(new Object[][] {{5L}, {"A"}});
assertFailureValue("differs at index", "[0][0]");
}
@Test
- public void isEqualTo_Fail_UnequalOrderingMultiDimensional_01() {
+ public void isEqualTo_fail_unequalOrderingMultiDimensional_01() {
expectFailureWhenTestingThat(new Object[][] {{"A", "B"}, {5L}})
.isEqualTo(new Object[][] {{"A"}, {5L}});
assertFailureValue("wrong length for index", "[0]");
@@ -126,7 +126,7 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
}
@Test
- public void isEqualTo_Fail_UnequalOrderingMultiDimensional_11() {
+ public void isEqualTo_fail_unequalOrderingMultiDimensional_11() {
expectFailureWhenTestingThat(new Object[][] {{"A"}, {5L}})
.isEqualTo(new Object[][] {{"A"}, {5L, 6L}});
assertFailureValue("wrong length for index", "[1]");
@@ -135,35 +135,35 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
}
@Test
- public void isEqualTo_Fail_NotAnArray() {
+ public void isEqualTo_fail_notAnArray() {
expectFailureWhenTestingThat(objectArray("A", 5L)).isEqualTo(new Object());
}
@Test
- public void isNotEqualTo_SameLengths() {
+ public void isNotEqualTo_sameLengths() {
assertThat(objectArray("A", 5L)).isNotEqualTo(objectArray("C", 5L));
assertThat(new Object[][] {{"A"}, {5L}}).isNotEqualTo(new Object[][] {{"C"}, {5L}});
}
@Test
- public void isNotEqualTo_DifferentLengths() {
+ public void isNotEqualTo_differentLengths() {
assertThat(objectArray("A", 5L)).isNotEqualTo(objectArray("A", 5L, "c"));
assertThat(new Object[][] {{"A"}, {5L}}).isNotEqualTo(new Object[][] {{"A", "c"}, {5L}});
assertThat(new Object[][] {{"A"}, {5L}}).isNotEqualTo(new Object[][] {{"A"}, {5L}, {"C"}});
}
@Test
- public void isNotEqualTo_DifferentTypes() {
+ public void isNotEqualTo_differentTypes() {
assertThat(objectArray("A", 5L)).isNotEqualTo(new Object());
}
@Test
- public void isNotEqualTo_FailEquals() {
+ public void isNotEqualTo_failEquals() {
expectFailureWhenTestingThat(objectArray("A", 5L)).isNotEqualTo(objectArray("A", 5L));
}
@Test
- public void isNotEqualTo_FailEqualsMultiDimensional() {
+ public void isNotEqualTo_failEqualsMultiDimensional() {
expectFailureWhenTestingThat(new Object[][] {{"A"}, {5L}})
.isNotEqualTo(new Object[][] {{"A"}, {5L}});
assertFailureValue("expected not to be", "[[A], [5]]");
@@ -171,14 +171,14 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
@SuppressWarnings("TruthSelfEquals")
@Test
- public void isNotEqualTo_FailSame() {
+ public void isNotEqualTo_failSame() {
Object[] same = objectArray("A", 5L);
expectFailureWhenTestingThat(same).isNotEqualTo(same);
}
@SuppressWarnings("TruthSelfEquals")
@Test
- public void isNotEqualTo_FailSameMultiDimensional() {
+ public void isNotEqualTo_failSameMultiDimensional() {
Object[][] same = new Object[][] {{"A"}, {5L}};
expectFailureWhenTestingThat(same).isNotEqualTo(same);
}
@@ -201,7 +201,7 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
}
@Test
- public void stringArrayIsEqualTo_Fail_UnequalLength() {
+ public void stringArrayIsEqualTo_fail_unequalLength() {
expectFailureWhenTestingThat(objectArray("A", "B")).isEqualTo(objectArray("B"));
assertFailureKeys("expected", "but was", "wrong length", "expected", "but was");
assertFailureValueIndexed("expected", 1, "1");
@@ -209,7 +209,7 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
}
@Test
- public void stringArrayIsEqualTo_Fail_UnequalLengthMultiDimensional() {
+ public void stringArrayIsEqualTo_fail_unequalLengthMultiDimensional() {
expectFailureWhenTestingThat(new String[][] {{"A"}, {"B"}}).isEqualTo(new String[][] {{"A"}});
assertFailureKeys("expected", "but was", "wrong length", "expected", "but was");
assertFailureValueIndexed("expected", 1, "1");
@@ -217,20 +217,20 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
}
@Test
- public void stringArrayIsEqualTo_Fail_UnequalOrdering() {
+ public void stringArrayIsEqualTo_fail_unequalOrdering() {
expectFailureWhenTestingThat(objectArray("A", "B")).isEqualTo(objectArray("B", "A"));
assertFailureValue("differs at index", "[0]");
}
@Test
- public void stringArrayIsEqualTo_Fail_UnequalOrderingMultiDimensional() {
+ public void stringArrayIsEqualTo_fail_unequalOrderingMultiDimensional() {
expectFailureWhenTestingThat(new String[][] {{"A"}, {"B"}})
.isEqualTo(new String[][] {{"B"}, {"A"}});
assertFailureValue("differs at index", "[0][0]");
}
@Test
- public void setArrayIsEqualTo_Fail_UnequalOrdering() {
+ public void setArrayIsEqualTo_fail_unequalOrdering() {
expectFailureWhenTestingThat(objectArray(ImmutableSet.of("A"), ImmutableSet.of("B")))
.isEqualTo(objectArray(ImmutableSet.of("B"), ImmutableSet.of("A")));
assertFailureValue("differs at index", "[0]");
@@ -245,7 +245,7 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
}
@Test
- public void primitiveMultiDimensionalArrayIsEqualTo_Fail_UnequalOrdering() {
+ public void primitiveMultiDimensionalArrayIsEqualTo_fail_unequalOrdering() {
expectFailureWhenTestingThat(new int[][] {{1, 2}, {3}, {4, 5, 6}})
.isEqualTo(new int[][] {{1, 2}, {3}, {4, 5, 6, 7}});
assertFailureValue("wrong length for index", "[2]");
@@ -260,7 +260,7 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
}
@Test
- public void primitiveMultiDimensionalArrayIsNotEqualTo_Fail_Equal() {
+ public void primitiveMultiDimensionalArrayIsNotEqualTo_fail_equal() {
expectFailureWhenTestingThat(new int[][] {{1, 2}, {3}, {4, 5, 6}})
.isNotEqualTo(new int[][] {{1, 2}, {3}, {4, 5, 6}});
}
@@ -282,7 +282,7 @@ public class ObjectArraySubjectTest extends BaseSubjectTestCase {
return ts;
}
- private static Set[] objectArray(Set... ts) {
+ private static Set<?>[] objectArray(Set<?>... ts) {
return ts;
}
diff --git a/core/src/test/java/com/google/common/truth/StackTraceCleanerJUnit3Test.java b/core/src/test/java/com/google/common/truth/StackTraceCleanerJUnit3Test.java
new file mode 100644
index 00000000..ab410d9d
--- /dev/null
+++ b/core/src/test/java/com/google/common/truth/StackTraceCleanerJUnit3Test.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 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.truth.Truth.assertThat;
+
+import junit.framework.TestCase;
+
+/**
+ * JUnit3 tests for {@link StackTraceCleaner}.
+ *
+ * <p>The "main" tests are in {@link StackTraceCleanerTest}.
+ */
+public class StackTraceCleanerJUnit3Test extends TestCase {
+ public void testSimple() {
+ try {
+ assertThat(0).isEqualTo(1);
+ throw new Error();
+ } catch (AssertionError failure) {
+ assertThat(failure.getStackTrace()).hasLength(1);
+ }
+ }
+}
diff --git a/core/src/test/java/com/google/common/truth/StackTraceCleanerTest.java b/core/src/test/java/com/google/common/truth/StackTraceCleanerTest.java
index f42eee1f..fc92cec0 100644
--- a/core/src/test/java/com/google/common/truth/StackTraceCleanerTest.java
+++ b/core/src/test/java/com/google/common/truth/StackTraceCleanerTest.java
@@ -97,7 +97,7 @@ public class StackTraceCleanerTest extends BaseSubjectTestCase {
}
@Test
- public void assertionsActuallyUseCleaner_ComparisonFailure() {
+ public void assertionsActuallyUseCleaner_comparisonFailure() {
expectFailure.whenTesting().that("1").isEqualTo("2");
assertThat(expectFailure.getFailure().getStackTrace()[0].getClassName())
.isEqualTo(getClass().getName());
@@ -453,8 +453,7 @@ public class StackTraceCleanerTest extends BaseSubjectTestCase {
0);
}
- private static class SelfReferencingThrowable extends Throwable {
-
+ private static class SelfReferencingThrowable extends Exception {
SelfReferencingThrowable(String... classNames) {
setStackTrace(createStackTrace(classNames));
}
diff --git a/core/src/test/java/com/google/common/truth/StringSubjectTest.java b/core/src/test/java/com/google/common/truth/StringSubjectTest.java
index dbb89112..ec247402 100644
--- a/core/src/test/java/com/google/common/truth/StringSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/StringSubjectTest.java
@@ -73,7 +73,7 @@ public class StringSubjectTest extends BaseSubjectTestCase {
@Test
public void stringIsEmptyFailNull() {
expectFailureWhenTestingThat(null).isEmpty();
- assertFailureKeys("expected empty string", "but was");
+ assertFailureKeys("expected an empty string", "but was");
}
@Test
@@ -90,7 +90,7 @@ public class StringSubjectTest extends BaseSubjectTestCase {
@Test
public void stringIsNotEmptyFailNull() {
expectFailureWhenTestingThat(null).isNotEmpty();
- assertFailureKeys("expected nonempty string", "but was");
+ assertFailureKeys("expected a non-empty string", "but was");
}
@Test
diff --git a/core/src/test/java/com/google/common/truth/SubjectTest.java b/core/src/test/java/com/google/common/truth/SubjectTest.java
index 32919ce4..9544f52f 100644
--- a/core/src/test/java/com/google/common/truth/SubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/SubjectTest.java
@@ -18,9 +18,11 @@ package com.google.common.truth;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.truth.ExpectFailure.assertThat;
import static com.google.common.truth.Fact.simpleFact;
+import static com.google.common.truth.SubjectTest.ForbidsEqualityChecksSubject.objectsForbiddingEqualityCheck;
import static com.google.common.truth.TestPlatform.isGwt;
import static com.google.common.truth.Truth.assertAbout;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.TruthJUnit.assume;
import static org.junit.Assert.fail;
import com.google.common.annotations.GwtIncompatible;
@@ -35,7 +37,6 @@ import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Iterators;
import com.google.common.primitives.UnsignedInteger;
import com.google.common.testing.NullPointerTester;
-import com.google.common.truth.Subject.Factory;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
@@ -58,7 +59,16 @@ public class SubjectTest extends BaseSubjectTestCase {
@Test
@GwtIncompatible("NullPointerTester")
@SuppressWarnings("GoogleInternalApi")
+ /*
+ * TODO(cpovirk): Reenable these tests publicly. Currently, we depend on guava-android, whose
+ * NullPointerTester doesn't yet recognize type-use @Nullable annotations. And we can't mix the
+ * -jre version of guava-testlib with the -android version of guava because the NullPointerTester
+ * feature we need requires a -jre-only API.
+ */
+ @org.junit.Ignore
public void nullPointerTester() {
+ assume().that(isAndroid()).isFalse(); // type-annotation @Nullable is not available
+
NullPointerTester npTester = new NullPointerTester();
npTester.setDefault(Fact.class, simpleFact("fact"));
@@ -88,7 +98,10 @@ public class SubjectTest extends BaseSubjectTestCase {
@Test
@GwtIncompatible("NullPointerTester")
+ @org.junit.Ignore // TODO(cpovirk): Reenable publicly. (See nullPointerTester().)
public void allAssertThatOverloadsAcceptNull() throws Exception {
+ assume().that(isAndroid()).isFalse(); // type-annotation @Nullable is not available
+
NullPointerTester npTester = new NullPointerTester();
npTester.setDefault(Fact.class, simpleFact("fact"));
for (Method method : Truth.class.getDeclaredMethods()) {
@@ -447,6 +460,10 @@ public class SubjectTest extends BaseSubjectTestCase {
assertThat(a).isNotEqualTo(b);
}
+ @SuppressWarnings({
+ "BoxedPrimitiveConstructor",
+ "deprecation"
+ }) // intentional check on non-identity objects
@Test
public void isNotEqualToFailureWithObjects() {
Object o = new Integer(1);
@@ -481,16 +498,19 @@ public class SubjectTest extends BaseSubjectTestCase {
expectFailure.whenTesting().that(o).isNotEqualTo(o);
}
+ @SuppressWarnings("IsInstanceString") // test is an intentional trivially true check
@Test
public void isInstanceOfExactType() {
assertThat("a").isInstanceOf(String.class);
}
+ @SuppressWarnings("IsInstanceInteger") // test is an intentional trivially true check
@Test
public void isInstanceOfSuperclass() {
assertThat(3).isInstanceOf(Number.class);
}
+ @SuppressWarnings("IsInstanceString") // test is an intentional trivially true check
@Test
public void isInstanceOfImplementedInterface() {
if (isGwt()) {
@@ -540,6 +560,17 @@ public class SubjectTest extends BaseSubjectTestCase {
expectFailure.whenTesting().that((Object) null).isInstanceOf(CharSequence.class);
}
+ // false positive; actually an intentional trivially *false* check
+ @SuppressWarnings("IsInstanceInteger")
+ @Test
+ public void isInstanceOfPrimitiveType() {
+ try {
+ assertThat(1).isInstanceOf(int.class);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
@Test
public void isNotInstanceOfUnrelatedClass() {
assertThat("a").isNotInstanceOf(Long.class);
@@ -586,6 +617,15 @@ public class SubjectTest extends BaseSubjectTestCase {
}
@Test
+ public void isNotInstanceOfPrimitiveType() {
+ try {
+ assertThat(1).isNotInstanceOf(int.class);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
public void isIn() {
assertThat("b").isIn(oneShotIterable("a", "b", "c"));
}
@@ -707,7 +747,8 @@ public class SubjectTest extends BaseSubjectTestCase {
}
@Test
- @SuppressWarnings({"EqualsIncompatibleType", "DoNotCall"})
+ // test of a mistaken call
+ @SuppressWarnings({"EqualsIncompatibleType", "DoNotCall", "deprecation"})
public void equalsThrowsUSOE() {
try {
boolean unused = assertThat(5).equals(5);
@@ -724,7 +765,8 @@ public class SubjectTest extends BaseSubjectTestCase {
}
@Test
- @SuppressWarnings("DoNotCall")
+ // test of a mistaken call
+ @SuppressWarnings({"DoNotCall", "deprecation"})
public void hashCodeThrowsUSOE() {
try {
int unused = assertThat(5).hashCode();
@@ -740,8 +782,8 @@ public class SubjectTest extends BaseSubjectTestCase {
assertThat((Object) null).ignoreCheck().that("foo").isNull();
}
- private static <T> Iterable<T> oneShotIterable(final T... values) {
- final Iterator<T> iterator = Iterators.forArray(values);
+ private static <T> Iterable<T> oneShotIterable(T... values) {
+ Iterator<T> iterator = Iterators.forArray(values);
return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
@@ -756,6 +798,7 @@ public class SubjectTest extends BaseSubjectTestCase {
}
@Test
+ @SuppressWarnings("TruthIncompatibleType") // test of a mistaken call
public void disambiguationWithSameToString() {
expectFailure.whenTesting().that(new StringBuilder("foo")).isEqualTo(new StringBuilder("foo"));
assertFailureKeys("expected", "but was");
@@ -784,7 +827,11 @@ public class SubjectTest extends BaseSubjectTestCase {
}
}
- private static final class ForbidsEqualityChecksSubject extends Subject {
+ static final class ForbidsEqualityChecksSubject extends Subject {
+ static Factory<ForbidsEqualityChecksSubject, Object> objectsForbiddingEqualityCheck() {
+ return ForbidsEqualityChecksSubject::new;
+ }
+
ForbidsEqualityChecksSubject(FailureMetadata metadata, @Nullable Object actual) {
super(metadata, actual);
}
@@ -802,13 +849,7 @@ public class SubjectTest extends BaseSubjectTestCase {
}
}
- private static Subject.Factory<ForbidsEqualityChecksSubject, Object>
- objectsForbiddingEqualityCheck() {
- return new Factory<ForbidsEqualityChecksSubject, Object>() {
- @Override
- public ForbidsEqualityChecksSubject createSubject(FailureMetadata metadata, Object actual) {
- return new ForbidsEqualityChecksSubject(metadata, actual);
- }
- };
+ private static boolean isAndroid() {
+ return System.getProperty("java.runtime.name").contains("Android");
}
}
diff --git a/core/src/test/java/com/google/common/truth/TableSubjectTest.java b/core/src/test/java/com/google/common/truth/TableSubjectTest.java
index aea450c2..b96fd6eb 100644
--- a/core/src/test/java/com/google/common/truth/TableSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/TableSubjectTest.java
@@ -15,6 +15,7 @@
*/
package com.google.common.truth;
+import static com.google.common.truth.ExpectFailure.assertThat;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
@@ -88,10 +89,16 @@ public class TableSubjectTest extends BaseSubjectTestCase {
@Test
public void containsFailure() {
ImmutableTable<String, String, String> table = ImmutableTable.of("row", "col", "val");
- expectFailureWhenTestingThat(table).contains("row", "row");
+ expectFailureWhenTestingThat(table).contains("row", "otherCol");
assertThat(expectFailure.getFailure())
- .hasMessageThat()
- .isEqualTo("Not true that <{row={col=val}}> contains mapping for row/column <row> <row>");
+ .factKeys()
+ .containsExactly(
+ "expected to contain mapping for row-column key pair",
+ "row key",
+ "column key",
+ "but was");
+ assertThat(expectFailure.getFailure()).factValue("row key").isEqualTo("row");
+ assertThat(expectFailure.getFailure()).factValue("column key").isEqualTo("otherCol");
}
@Test
@@ -108,10 +115,16 @@ public class TableSubjectTest extends BaseSubjectTestCase {
ImmutableTable<String, String, String> table = ImmutableTable.of("row", "col", "val");
expectFailureWhenTestingThat(table).doesNotContain("row", "col");
assertThat(expectFailure.getFailure())
- .hasMessageThat()
- .isEqualTo(
- "Not true that <{row={col=val}}> does not contain mapping for "
- + "row/column <row> <col>");
+ .factKeys()
+ .containsExactly(
+ "expected not to contain mapping for row-column key pair",
+ "row key",
+ "column key",
+ "but contained value",
+ "full contents");
+ assertThat(expectFailure.getFailure()).factValue("row key").isEqualTo("row");
+ assertThat(expectFailure.getFailure()).factValue("column key").isEqualTo("col");
+ assertThat(expectFailure.getFailure()).factValue("but contained value").isEqualTo("val");
}
@Test
@@ -158,7 +171,7 @@ public class TableSubjectTest extends BaseSubjectTestCase {
return Tables.immutableCell(row, col, val);
}
- private TableSubject expectFailureWhenTestingThat(Table actual) {
+ private TableSubject expectFailureWhenTestingThat(Table<?, ?, ?> actual) {
return expectFailure.whenTesting().that(actual);
}
}
diff --git a/core/src/test/java/com/google/common/truth/TestCorrespondences.java b/core/src/test/java/com/google/common/truth/TestCorrespondences.java
index d9cca3e1..d2488d5c 100644
--- a/core/src/test/java/com/google/common/truth/TestCorrespondences.java
+++ b/core/src/test/java/com/google/common/truth/TestCorrespondences.java
@@ -33,16 +33,7 @@ final class TestCorrespondences {
* correspond to null only.
*/
static final Correspondence<String, Integer> STRING_PARSES_TO_INTEGER_CORRESPONDENCE =
- Correspondence.from(
- // If we were allowed to use method references, this would be:
- // TestCorrespondences::stringParsesToInteger,
- new Correspondence.BinaryPredicate<String, Integer>() {
- @Override
- public boolean apply(@Nullable String actual, @Nullable Integer expected) {
- return stringParsesToInteger(actual, expected);
- }
- },
- "parses to");
+ Correspondence.from(TestCorrespondences::stringParsesToInteger, "parses to");
private static boolean stringParsesToInteger(
@Nullable String actual, @Nullable Integer expected) {
@@ -64,14 +55,7 @@ final class TestCorrespondences {
/** A formatter for the diffs between integers. */
static final Correspondence.DiffFormatter<Integer, Integer> INT_DIFF_FORMATTER =
- // If we were allowed to use lambdas, this would be:
- // (a, e) -> Integer.toString(a - e));
- new Correspondence.DiffFormatter<Integer, Integer>() {
- @Override
- public String formatDiff(Integer actual, Integer expected) {
- return Integer.toString(actual - expected);
- }
- };
+ (a, e) -> Integer.toString(a - e);
/**
* A correspondence between integers which tests whether they are within 10 of each other. Smart
@@ -80,31 +64,23 @@ final class TestCorrespondences {
*/
static final Correspondence<Integer, Integer> WITHIN_10_OF =
Correspondence.from(
- // If we were allowed to use lambdas, this would be:
- // (Integer a, Integer e) -> Math.abs(a - e) <= 10,
- new Correspondence.BinaryPredicate<Integer, Integer>() {
- @Override
- public boolean apply(Integer actual, Integer expected) {
- return Math.abs(actual - expected) <= 10;
+ (Integer actual, Integer expected) -> {
+ if (actual == null || expected == null) {
+ throw new NullPointerExceptionFromWithin10Of();
}
+ return Math.abs(actual - expected) <= 10;
},
"is within 10 of")
.formattingDiffsUsing(INT_DIFF_FORMATTER);
+ private static final class NullPointerExceptionFromWithin10Of extends NullPointerException {}
+
/**
* A correspondence between strings which tests for case-insensitive equality. Supports null
* expected elements, but throws {@link NullPointerException} on null actual elements.
*/
static final Correspondence<String, String> CASE_INSENSITIVE_EQUALITY =
- Correspondence.from(
- // If we were allowed to use method references, this would be String::equalsIgnoreCase.
- new Correspondence.BinaryPredicate<String, String>() {
- @Override
- public boolean apply(String actual, String expected) {
- return actual.equalsIgnoreCase(expected);
- }
- },
- "equals (ignoring case)");
+ Correspondence.from(String::equalsIgnoreCase, "equals (ignoring case)");
/**
* A correspondence between strings which tests for case-insensitive equality, with a broken
@@ -114,16 +90,13 @@ final class TestCorrespondences {
*/
static final Correspondence<String, String> CASE_INSENSITIVE_EQUALITY_HALF_NULL_SAFE =
Correspondence.from(
- // If we were allowed to use method references, this would be:
- // TestCorrespondences::equalsIgnoreCaseHalfNullSafe,
- new Correspondence.BinaryPredicate<String, String>() {
- @Override
- public boolean apply(String actual, String expected) {
- return equalsIgnoreCaseHalfNullSafe(actual, expected);
- }
- },
- "equals (ignoring case)");
+ TestCorrespondences::equalsIgnoreCaseHalfNullSafe, "equals (ignoring case)");
+ /*
+ * This is just an example for a test, and it's a convenient way to demonstrate the specific null
+ * behavior documented below.
+ */
+ @SuppressWarnings("Casing_StringEqualsIgnoreCase")
private static boolean equalsIgnoreCaseHalfNullSafe(String actual, String expected) {
if (actual == null && expected == null) {
return true;
@@ -136,22 +109,22 @@ final class TestCorrespondences {
* An example value object. It has an optional {@code id} field and a required {@code score}
* field, both positive integers.
*/
- static final class Record {
+ static final class MyRecord {
private final int id;
private final int score;
- static Record create(int id, int score) {
+ static MyRecord create(int id, int score) {
checkState(id >= 0);
checkState(score > 0);
- return new Record(id, score);
+ return new MyRecord(id, score);
}
- static Record createWithoutId(int score) {
+ static MyRecord createWithoutId(int score) {
checkState(score >= 0);
- return new Record(-1, score);
+ return new MyRecord(-1, score);
}
- Record(int id, int score) {
+ MyRecord(int id, int score) {
this.id = id;
this.score = score;
}
@@ -169,14 +142,14 @@ final class TestCorrespondences {
return score;
}
- boolean hasSameId(Record that) {
+ boolean hasSameId(MyRecord that) {
return this.id == that.id;
}
@Override
public boolean equals(@Nullable Object o) {
- if (o instanceof Record) {
- Record that = (Record) o;
+ if (o instanceof MyRecord) {
+ MyRecord that = (MyRecord) o;
return this.id == that.id && this.score == that.score;
}
return false;
@@ -200,56 +173,42 @@ final class TestCorrespondences {
* If the argument is the string form of a record, returns that record; otherwise returns {@code
* null}.
*/
- static @Nullable Record parse(String str) {
+ static @Nullable MyRecord parse(String str) {
List<String> parts = Splitter.on('/').splitToList(str);
if (parts.size() != 2) {
return null;
}
- @Nullable Integer id = parts.get(0).equals("none") ? -1 : Ints.tryParse(parts.get(0));
- @Nullable Integer score = Ints.tryParse(parts.get(1));
+ Integer id = parts.get(0).equals("none") ? -1 : Ints.tryParse(parts.get(0));
+ Integer score = Ints.tryParse(parts.get(1));
if (id == null || score == null) {
return null;
}
- return new Record(id, score);
+ return new MyRecord(id, score);
}
}
/**
- * A correspondence between {@link Record} instances which tests whether their {@code id} values
+ * A correspondence between {@link MyRecord} instances which tests whether their {@code id} values
* are equal and their {@code score} values are within 10 of each other. Smart diffing is not
* supported.
*
* <p>The {@link Correspondence#compare} implementation support nulls, such that null corresponds
* to null only. The {@link Correspondence#formatDiff} implementation does not support nulls.
*/
- static final Correspondence<Record, Record> RECORDS_EQUAL_WITH_SCORE_TOLERANCE_10_NO_DIFF =
+ static final Correspondence<MyRecord, MyRecord> RECORDS_EQUAL_WITH_SCORE_TOLERANCE_10_NO_DIFF =
Correspondence.from(
- // If we were allowed to use method references, this would be:
- // TestCorrespondences::recordsAreCloseEnough,
- new Correspondence.BinaryPredicate<Record, Record>() {
- @Override
- public boolean apply(Record actual, Record expected) {
- return recordsAreCloseEnough(actual, expected);
- }
- },
+ TestCorrespondences::recordsAreCloseEnough,
"has the same id as and a score within 10 of");
/**
* A formatter for diffs between records. If the records have the same key, it gives a string of
* the form {@code "score:<score_diff>"}. If they have different keys, it gives null.
*/
- static final Correspondence.DiffFormatter<Record, Record> RECORD_DIFF_FORMATTER =
- // If we were allowed to use method references, this would be:
- // TestCorrespondences::formatRecordDiff);
- new Correspondence.DiffFormatter<Record, Record>() {
- @Override
- public String formatDiff(Record actual, Record expected) {
- return formatRecordDiff(actual, expected);
- }
- };
+ static final Correspondence.DiffFormatter<MyRecord, MyRecord> RECORD_DIFF_FORMATTER =
+ TestCorrespondences::formatRecordDiff;
/**
- * A correspondence between {@link Record} instances which tests whether their {@code id} values
+ * A correspondence between {@link MyRecord} instances which tests whether their {@code id} values
* are equal and their {@code score} values are within 10 of each other. Smart diffing is enabled
* for records with equal {@code id} values, with a formatted diff showing the actual {@code
* score} value less the expected {@code score} value preceded by the literal {@code score:}.
@@ -257,7 +216,7 @@ final class TestCorrespondences {
* <p>The {@link Correspondence#compare} implementation support nulls, such that null corresponds
* to null only. The {@link Correspondence#formatDiff} implementation does not support nulls.
*/
- static final Correspondence<Record, Record> RECORDS_EQUAL_WITH_SCORE_TOLERANCE_10 =
+ static final Correspondence<MyRecord, MyRecord> RECORDS_EQUAL_WITH_SCORE_TOLERANCE_10 =
RECORDS_EQUAL_WITH_SCORE_TOLERANCE_10_NO_DIFF.formattingDiffsUsing(RECORD_DIFF_FORMATTER);
/**
@@ -265,36 +224,21 @@ final class TestCorrespondences {
* values are strings which will be parsed before comparing. If the string does not parse to a
* record then it does not correspond and is not diffed. Does not support null strings or records.
*/
- static final Correspondence<String, Record> PARSED_RECORDS_EQUAL_WITH_SCORE_TOLERANCE_10 =
+ static final Correspondence<String, MyRecord> PARSED_RECORDS_EQUAL_WITH_SCORE_TOLERANCE_10 =
Correspondence.from(
- // If we were allowed to use lambdas, this would be:
- // (String a, Record e) -> {
- // @Nullable Record actualRecord = Record.parse(a);
- // return actualRecord != null && recordsAreCloseEnough(actualRecord, e);
- // },
- new Correspondence.BinaryPredicate<String, Record>() {
- @Override
- public boolean apply(String actual, Record expected) {
- @Nullable Record actualRecord = Record.parse(actual);
- return actualRecord != null && recordsAreCloseEnough(actualRecord, expected);
- }
+ (String a, MyRecord e) -> {
+ MyRecord actualRecord = MyRecord.parse(a);
+ return actualRecord != null && recordsAreCloseEnough(actualRecord, e);
},
"parses to a record that " + RECORDS_EQUAL_WITH_SCORE_TOLERANCE_10)
.formattingDiffsUsing(
- // If we were allowe to use lambdas, this would be:
- // (a, e) -> {
- // @Nullable Record actualRecord = Record.parse(a);
- // return actualRecord != null ? formatRecordDiff(actualRecord, e) : null;
- // });
- new Correspondence.DiffFormatter<String, Record>() {
- @Override
- public String formatDiff(String actual, Record expected) {
- @Nullable Record actualRecord = Record.parse(actual);
- return actualRecord != null ? formatRecordDiff(actualRecord, expected) : null;
- }
+ (a, e) -> {
+ MyRecord actualRecord = MyRecord.parse(a);
+ return actualRecord != null ? formatRecordDiff(actualRecord, e) : null;
});
- private static boolean recordsAreCloseEnough(@Nullable Record actual, @Nullable Record expected) {
+ private static boolean recordsAreCloseEnough(
+ @Nullable MyRecord actual, @Nullable MyRecord expected) {
if (actual == null) {
return expected == null;
}
@@ -304,7 +248,7 @@ final class TestCorrespondences {
return actual.hasSameId(expected) && Math.abs(actual.getScore() - expected.getScore()) <= 10;
}
- private static String formatRecordDiff(Record actual, Record expected) {
+ private static @Nullable String formatRecordDiff(MyRecord actual, MyRecord expected) {
if (actual.hasId() && expected.hasId() && actual.getId() == expected.getId()) {
return "score:" + (actual.getScore() - expected.getScore());
} else {
@@ -313,47 +257,33 @@ final class TestCorrespondences {
}
/**
- * A key function for {@link Record} instances that keys records by their {@code id} values. The
+ * A key function for {@link MyRecord} instances that keys records by their {@code id} values. The
* key is null if the record has no {@code id}. Does not support null records.
*/
- static final Function<Record, Integer> RECORD_ID =
- new Function<Record, Integer>() {
-
- @Override
- public @Nullable Integer apply(Record record) {
- return record.hasId() ? record.getId() : null;
- }
- };
+ static final Function<MyRecord, Integer> RECORD_ID =
+ record -> record.hasId() ? record.getId() : null;
/**
- * A key function for {@link Record} instances that keys records by their {@code id} values. The
+ * A key function for {@link MyRecord} instances that keys records by their {@code id} values. The
* key is null if the record has no {@code id}. Does not support null records.
*/
- static final Function<Record, Integer> NULL_SAFE_RECORD_ID =
- new Function<Record, Integer>() {
-
- @Override
- public @Nullable Integer apply(Record record) {
- if (record == null) {
- return 0;
- }
- return record.hasId() ? record.getId() : null;
+ static final Function<MyRecord, Integer> NULL_SAFE_RECORD_ID =
+ record -> {
+ if (record == null) {
+ return 0;
}
+ return record.hasId() ? record.getId() : null;
};
/**
- * A key function for {@link String} instances that attempts to parse them as {@link Record}
+ * A key function for {@link String} instances that attempts to parse them as {@link MyRecord}
* instances and keys records by their {@code id} values. The key is null if the string does not
* parse or the record has no {@code id}. Does not support null strings.
*/
static final Function<String, Integer> PARSED_RECORD_ID =
- new Function<String, Integer>() {
-
- @Override
- public @Nullable Integer apply(String str) {
- Record record = Record.parse(str);
- return record != null ? RECORD_ID.apply(record) : null;
- }
+ str -> {
+ MyRecord record = MyRecord.parse(str);
+ return record != null ? RECORD_ID.apply(record) : null;
};
private TestCorrespondences() {}
diff --git a/core/src/test/java/com/google/common/truth/TruthAssertThatTest.java b/core/src/test/java/com/google/common/truth/TruthAssertThatTest.java
index 90769484..cb75b934 100644
--- a/core/src/test/java/com/google/common/truth/TruthAssertThatTest.java
+++ b/core/src/test/java/com/google/common/truth/TruthAssertThatTest.java
@@ -18,10 +18,8 @@ package com.google.common.truth;
import static com.google.common.truth.Truth.assert_;
import static java.util.Arrays.asList;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.google.common.reflect.TypeToken;
@@ -38,38 +36,23 @@ import org.junit.runners.JUnit4;
*/
@RunWith(JUnit4.class)
public class TruthAssertThatTest {
- private static final Function<Method, TypeToken<?>> METHOD_TO_RETURN_TYPE_TOKEN =
- new Function<Method, TypeToken<?>>() {
- @Override
- public TypeToken<?> apply(Method input) {
- return TypeToken.of(Iterables.getOnlyElement(asList(input.getParameterTypes())));
- }
- };
+ private static TypeToken<?> methodToReturnTypeToken(Method input) {
+ return TypeToken.of(Iterables.getOnlyElement(asList(input.getParameterTypes())));
+ }
@Test
public void staticAssertThatMethodsMatchStandardSubjectBuilderInstanceMethods() {
- ImmutableSet<TypeToken<?>> verbTypes =
+ ImmutableSortedSet<TypeToken<?>> verbTypes =
FluentIterable.from(asList(StandardSubjectBuilder.class.getMethods()))
- .filter(
- new Predicate<Method>() {
- @Override
- public boolean apply(Method input) {
- return input.getName().equals("that");
- }
- })
- .transform(METHOD_TO_RETURN_TYPE_TOKEN)
+ .filter(input -> input.getName().equals("that"))
+ .transform(TruthAssertThatTest::methodToReturnTypeToken)
.toSortedSet(Ordering.usingToString());
- ImmutableSet<TypeToken<?>> truthTypes =
+ ImmutableSortedSet<TypeToken<?>> truthTypes =
FluentIterable.from(asList(Truth.class.getMethods()))
.filter(
- new Predicate<Method>() {
- @Override
- public boolean apply(Method input) {
- return input.getName().equals("assertThat")
- && Modifier.isStatic(input.getModifiers());
- }
- })
- .transform(METHOD_TO_RETURN_TYPE_TOKEN)
+ input ->
+ input.getName().equals("assertThat") && Modifier.isStatic(input.getModifiers()))
+ .transform(TruthAssertThatTest::methodToReturnTypeToken)
.toSortedSet(Ordering.usingToString());
assert_().that(verbTypes).isNotEmpty();
diff --git a/core/src/test/java/com/google/common/truth/TruthFailureSubjectTest.java b/core/src/test/java/com/google/common/truth/TruthFailureSubjectTest.java
index cb9d7976..d4546cdc 100644
--- a/core/src/test/java/com/google/common/truth/TruthFailureSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/TruthFailureSubjectTest.java
@@ -157,13 +157,13 @@ public class TruthFailureSubjectTest extends BaseSubjectTestCase {
@Test
public void nonTruthErrorFactKeys() {
Object unused = expectFailureWhenTestingThat(new AssertionError()).factKeys();
- assertFailureKeys("expected a failure thrown by Truth's new failure API", "but was");
+ assertFailureKeys("expected a failure thrown by Truth's failure API", "but was");
}
@Test
public void nonTruthErrorFactValue() {
Object unused = expectFailureWhenTestingThat(new AssertionError()).factValue("foo");
- assertFailureKeys("expected a failure thrown by Truth's new failure API", "but was");
+ assertFailureKeys("expected a failure thrown by Truth's failure API", "but was");
}
private TruthFailureSubject assertThat(Fact... facts) {
diff --git a/core/src/test/java/com/google/common/truth/extension/EmployeeSubject.java b/core/src/test/java/com/google/common/truth/extension/EmployeeSubject.java
index 854afb06..224bf653 100644
--- a/core/src/test/java/com/google/common/truth/extension/EmployeeSubject.java
+++ b/core/src/test/java/com/google/common/truth/extension/EmployeeSubject.java
@@ -18,7 +18,10 @@ package com.google.common.truth.extension;
import static com.google.common.truth.Fact.simpleFact;
import static com.google.common.truth.Truth.assertAbout;
+import com.google.common.truth.ComparableSubject;
import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.LongSubject;
+import com.google.common.truth.StringSubject;
import com.google.common.truth.Subject;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -31,18 +34,14 @@ public final class EmployeeSubject extends Subject {
// User-defined entry point
public static EmployeeSubject assertThat(@Nullable Employee employee) {
- return assertAbout(EMPLOYEE_SUBJECT_FACTORY).that(employee);
+ return assertAbout(employees()).that(employee);
}
// Static method for getting the subject factory (for use with assertAbout())
public static Subject.Factory<EmployeeSubject, Employee> employees() {
- return EMPLOYEE_SUBJECT_FACTORY;
+ return EmployeeSubject::new;
}
- // Boiler-plate Subject.Factory for EmployeeSubject
- private static final Subject.Factory<EmployeeSubject, Employee> EMPLOYEE_SUBJECT_FACTORY =
- EmployeeSubject::new;
-
private final Employee actual;
private EmployeeSubject(FailureMetadata failureMetadata, @Nullable Employee subject) {
@@ -53,19 +52,19 @@ public final class EmployeeSubject extends Subject {
// User-defined test assertion SPI below this point
public void hasName(String name) {
- check("name()").that(actual.name()).isEqualTo(name);
+ name().isEqualTo(name);
}
public void hasUsername(String username) {
- check("username()").that(actual.username()).isEqualTo(username);
+ username().isEqualTo(username);
}
public void hasId(long id) {
- check("id()").that(actual.id()).isEqualTo(id);
+ id().isEqualTo(id);
}
public void hasLocation(Employee.Location location) {
- check("location()").that(actual.location()).isEqualTo(location);
+ location().isEqualTo(location);
}
public void isCeo() {
@@ -80,7 +79,21 @@ public final class EmployeeSubject extends Subject {
}
}
- // TODO(kak): Add methods that return other subjects. E.g.,
- // public StringSubject username() {}
- // public IterableSubject languages() {}
+ // Chained subjects methods below this point
+
+ public StringSubject name() {
+ return check("name()").that(actual.name());
+ }
+
+ public StringSubject username() {
+ return check("username()").that(actual.username());
+ }
+
+ public LongSubject id() {
+ return check("id()").that(actual.id());
+ }
+
+ public ComparableSubject<Employee.Location> location() {
+ return check("location()").that(actual.location());
+ }
}
diff --git a/core/src/test/java/com/google/common/truth/extension/EmployeeSubjectTest.java b/core/src/test/java/com/google/common/truth/extension/EmployeeSubjectTest.java
index 8b60963d..36e916cf 100644
--- a/core/src/test/java/com/google/common/truth/extension/EmployeeSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/extension/EmployeeSubjectTest.java
@@ -17,12 +17,12 @@ package com.google.common.truth.extension;
import static com.google.common.truth.ExpectFailure.assertThat;
import static com.google.common.truth.ExpectFailure.expectFailureAbout;
-import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.extension.EmployeeSubject.assertThat;
import static com.google.common.truth.extension.EmployeeSubject.employees;
import com.google.common.truth.ExpectFailure.SimpleSubjectBuilderCallback;
import com.google.common.truth.extension.Employee.Location;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -57,6 +57,7 @@ public final class EmployeeSubjectTest {
assertThat(failure).factValue("value of").isEqualTo("employee.username()");
}
+ @CanIgnoreReturnValue
private static AssertionError expectFailure(
SimpleSubjectBuilderCallback<EmployeeSubject, Employee> callback) {
return expectFailureAbout(employees(), callback);
diff --git a/core/src/test/java/com/google/common/truth/gwt/Inventory.java b/core/src/test/java/com/google/common/truth/gwt/Inventory.java
index 49006f98..63e2fbcc 100644
--- a/core/src/test/java/com/google/common/truth/gwt/Inventory.java
+++ b/core/src/test/java/com/google/common/truth/gwt/Inventory.java
@@ -53,7 +53,7 @@ public class Inventory {
BigDecimalSubject bigDecimalSubject;
BooleanSubject booleanSubject;
ClassSubject classSubject;
- ComparableSubject comparableSubject;
+ ComparableSubject<?> comparableSubject;
DoubleSubject doubleSubject;
FailureStrategy failureStrategy;
FloatSubject floatSubject;
@@ -64,7 +64,7 @@ public class Inventory {
MapSubject mapSubject;
MultimapSubject multimapSubject;
MultisetSubject multisetSubject;
- ObjectArraySubject objectArraySubject;
+ ObjectArraySubject<?> objectArraySubject;
Ordered ordered;
PrimitiveBooleanArraySubject primitiveBooleanArraySubject;
PrimitiveByteArraySubject primitiveByteArraySubject;
@@ -75,7 +75,7 @@ public class Inventory {
PrimitiveLongArraySubject primitiveLongArraySubject;
PrimitiveShortArraySubject primitiveShortArraySubject;
StringSubject stringSubject;
- Subject.Factory subjectFactory;
+ Subject.Factory<?, ?> subjectFactory;
Subject subject;
TableSubject tableSubject;
ThrowableSubject throwableSubject;
diff --git a/core/src/test/java/com/google/common/truth/gwt/TruthGwtTest.java b/core/src/test/java/com/google/common/truth/gwt/TruthGwtTest.java
index 4a10e414..55d4aa91 100644
--- a/core/src/test/java/com/google/common/truth/gwt/TruthGwtTest.java
+++ b/core/src/test/java/com/google/common/truth/gwt/TruthGwtTest.java
@@ -38,7 +38,7 @@ public class TruthGwtTest extends com.google.gwt.junit.client.GWTTestCase {
}
public void testBuildClasses() {
- new Inventory().toString(); // force invocation.
+ String unused = new Inventory().toString(); // force invocation.
}
public void testBoolean() {
@@ -133,10 +133,11 @@ public class TruthGwtTest extends com.google.gwt.junit.client.GWTTestCase {
}
public void testObjectArray() {
- Set[] setOfString = {new HashSet<String>(asList("foo", "bar", "bash"))};
+ Set<?>[] setOfString = {new HashSet<String>(asList("foo", "bar", "bash"))};
assertThat(setOfString).asList().contains(new HashSet<String>(asList("foo", "bar", "bash")));
}
+ @SuppressWarnings("IsInstanceIterable") // test of an intentionally trivially true assertion
public void testDefault() {
assertThat(new Object()).isNotNull();
assertThat(new ArrayList<String>()).isInstanceOf(AbstractList.class);
diff --git a/extensions/java8/pom.xml b/extensions/java8/pom.xml
index f3dfec9f..951dc43a 100644
--- a/extensions/java8/pom.xml
+++ b/extensions/java8/pom.xml
@@ -25,16 +25,21 @@
</dependency>
</dependencies>
<build>
+ <resources>
+ <resource>
+ <directory>../..</directory>
+ <includes>
+ <include>LICENSE</include>
+ </includes>
+ <targetPath>META-INF</targetPath>
+ </resource>
+ </resources>
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- </configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
diff --git a/extensions/java8/src/main/java/com/google/common/truth/IntStreamSubject.java b/extensions/java8/src/main/java/com/google/common/truth/IntStreamSubject.java
index cd898d07..45699bce 100644
--- a/extensions/java8/src/main/java/com/google/common/truth/IntStreamSubject.java
+++ b/extensions/java8/src/main/java/com/google/common/truth/IntStreamSubject.java
@@ -40,6 +40,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*
* @author Kurt Alfred Kluever
*/
+@SuppressWarnings("deprecation") // TODO(b/134064106): design an alternative to no-arg check()
public final class IntStreamSubject extends Subject {
private final List<?> actualList;
@@ -145,7 +146,7 @@ public final class IntStreamSubject extends Subject {
*/
@CanIgnoreReturnValue
public Ordered containsExactly(int... varargs) {
- return check().that(actualList).containsExactly(box(varargs));
+ return check().that(actualList).containsExactlyElementsIn(box(varargs));
}
/**
diff --git a/extensions/java8/src/main/java/com/google/common/truth/LongStreamSubject.java b/extensions/java8/src/main/java/com/google/common/truth/LongStreamSubject.java
index 1e6b5029..0a5c2255 100644
--- a/extensions/java8/src/main/java/com/google/common/truth/LongStreamSubject.java
+++ b/extensions/java8/src/main/java/com/google/common/truth/LongStreamSubject.java
@@ -40,6 +40,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*
* @author Kurt Alfred Kluever
*/
+@SuppressWarnings("deprecation") // TODO(b/134064106): design an alternative to no-arg check()
public final class LongStreamSubject extends Subject {
private final List<?> actualList;
@@ -145,7 +146,7 @@ public final class LongStreamSubject extends Subject {
*/
@CanIgnoreReturnValue
public Ordered containsExactly(long... varargs) {
- return check().that(actualList).containsExactly(box(varargs));
+ return check().that(actualList).containsExactlyElementsIn(box(varargs));
}
/**
diff --git a/extensions/java8/src/main/java/com/google/common/truth/OptionalSubject.java b/extensions/java8/src/main/java/com/google/common/truth/OptionalSubject.java
index 1b9fb5c9..65ca4dae 100644
--- a/extensions/java8/src/main/java/com/google/common/truth/OptionalSubject.java
+++ b/extensions/java8/src/main/java/com/google/common/truth/OptionalSubject.java
@@ -27,7 +27,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Christian Gruber
*/
public final class OptionalSubject extends Subject {
- private final Optional<?> actual;
+ private final @Nullable Optional<?> actual;
OptionalSubject(
FailureMetadata failureMetadata,
@@ -68,7 +68,7 @@ public final class OptionalSubject extends Subject {
* assertThat(myOptional.get()).contains("foo");
* }</pre>
*/
- public void hasValue(Object expected) {
+ public void hasValue(@Nullable Object expected) {
if (expected == null) {
throw new NullPointerException("Optional cannot have a null value.");
}
diff --git a/extensions/java8/src/main/java/com/google/common/truth/StreamSubject.java b/extensions/java8/src/main/java/com/google/common/truth/StreamSubject.java
index 4957686d..f3e90cd6 100644
--- a/extensions/java8/src/main/java/com/google/common/truth/StreamSubject.java
+++ b/extensions/java8/src/main/java/com/google/common/truth/StreamSubject.java
@@ -18,6 +18,7 @@ package com.google.common.truth;
import static java.util.stream.Collectors.toCollection;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.DoNotCall;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -39,6 +40,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*
* @author Kurt Alfred Kluever
*/
+@SuppressWarnings("deprecation") // TODO(b/134064106): design an alternative to no-arg check()
public final class StreamSubject extends Subject {
private final List<?> actualList;
@@ -54,7 +56,7 @@ public final class StreamSubject extends Subject {
}
public static Subject.Factory<StreamSubject, Stream<?>> streams() {
- return (metadata, subject) -> new StreamSubject(metadata, subject);
+ return StreamSubject::new;
}
/** Fails if the subject is not empty. */
@@ -144,6 +146,11 @@ public final class StreamSubject extends Subject {
* on the object returned by this method.
*/
@CanIgnoreReturnValue
+ /*
+ * We need to call containsExactly, not containsExactlyElementsIn, to get the handling we want for
+ * containsExactly(null).
+ */
+ @SuppressWarnings("ContainsExactlyVariadic")
public Ordered containsExactly(@Nullable Object @Nullable ... varargs) {
return check().that(actualList).containsExactly(varargs);
}
@@ -223,7 +230,35 @@ public final class StreamSubject extends Subject {
check().that(actualList).isInOrder(comparator);
}
- // TODO(user): Do we want to override + deprecate isEqualTo/isNotEqualTo?
+ /**
+ * @deprecated {@code streamA.isEqualTo(streamB)} always fails, except when passed the exact same
+ * stream reference
+ */
+ @Override
+ @DoNotCall(
+ "StreamSubject.isEqualTo() is not supported because Streams do not have well-defined"
+ + " equality semantics")
+ @Deprecated
+ public void isEqualTo(@Nullable Object expected) {
+ throw new UnsupportedOperationException(
+ "StreamSubject.isEqualTo() is not supported because Streams do not have well-defined"
+ + " equality semantics");
+ }
+
+ /**
+ * @deprecated {@code streamA.isNotEqualTo(streamB)} always passes, except when passed the exact
+ * same stream reference
+ */
+ @Override
+ @DoNotCall(
+ "StreamSubject.isNotEqualTo() is not supported because Streams do not have well-defined"
+ + " equality semantics")
+ @Deprecated
+ public void isNotEqualTo(@Nullable Object unexpected) {
+ throw new UnsupportedOperationException(
+ "StreamSubject.isNotEqualTo() is not supported because Streams do not have well-defined"
+ + " equality semantics");
+ }
// TODO(user): Do we want to support comparingElementsUsing() on StreamSubject?
}
diff --git a/extensions/java8/src/main/java/com/google/common/truth/Truth8.gwt.xml b/extensions/java8/src/main/java/com/google/common/truth/Truth8.gwt.xml
index a3ac1443..f9aa5adf 100644
--- a/extensions/java8/src/main/java/com/google/common/truth/Truth8.gwt.xml
+++ b/extensions/java8/src/main/java/com/google/common/truth/Truth8.gwt.xml
@@ -5,19 +5,26 @@
</source>
<!--
- We used to set this only for packages that had manual supersource.
- That worked everywhere that I know of except for one place:
- when running the GWT util.concurrent tests under Guava.
- The problem is that GWT responds poorly to two .gwt.xml files in the same Java package:
- https://goo.gl/pRV3Yn
- The summary is that it ignores one file in favor of the other.
- util.concurrent, like nearly all our packages, has two .gwt.xml files: one for prod and one for tests.
- util.concurrent, unlike our other packages, has, as of this writing, test supersource but no prod supersource.
- GWT happens to use the prod .gwt.xml, so it looks for no supersource for tests, either.
- This causes it to fail to find AtomicLongMapTest.
- Our workaround is to tell GWT that util.concurrent and all other packages have prod supersource, even if they have none.
- GWT is happy to ignore us when we specify a nonexistent path.
- (I hope that this workaround does not cause its own problems in the future.)
+ We used to set this only for packages that had manual supersource. That
+ worked everywhere that I know of except for one place: when running the GWT
+ util.concurrent tests under Guava.
+
+ The problem is that GWT responds poorly to two .gwt.xml files in the same
+ Java package; see https://goo.gl/pRV3Yn for details.
+
+ The summary is that it ignores one file in favor of the other.
+ util.concurrent, like nearly all our packages, has two .gwt.xml files: one
+ for prod and one for tests. However, unlike our other packages, as of this
+ writing it has test supersource but no prod supersource.
+
+ GWT happens to use the prod .gwt.xml, so it looks for no supersource for
+ tests, either. This causes it to fail to find AtomicLongMapTest.
+
+ Our workaround is to tell GWT that util.concurrent and all other packages
+ have prod supersource, even if they have none. GWT is happy to ignore us
+ when we specify a nonexistent path.
+
+ (I hope that this workaround does not cause its own problems in the future.)
-->
<super-source path="super"/>
diff --git a/extensions/java8/src/main/java/com/google/common/truth/Truth8.java b/extensions/java8/src/main/java/com/google/common/truth/Truth8.java
index 31f0c6d9..c156c54b 100644
--- a/extensions/java8/src/main/java/com/google/common/truth/Truth8.java
+++ b/extensions/java8/src/main/java/com/google/common/truth/Truth8.java
@@ -44,6 +44,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* behavior/{@code Subject} type?</a> in the Truth FAQ.
*/
public final class Truth8 {
+ @SuppressWarnings("AssertAboutOptionals") // suggests infinite recursion
public static OptionalSubject assertThat(@Nullable Optional<?> target) {
return assertAbout(OptionalSubject.optionals()).that(target);
}
diff --git a/extensions/java8/src/test/java/com/google/common/truth/IntStreamSubjectTest.java b/extensions/java8/src/test/java/com/google/common/truth/IntStreamSubjectTest.java
index bcb11bd9..9fc8ee41 100644
--- a/extensions/java8/src/test/java/com/google/common/truth/IntStreamSubjectTest.java
+++ b/extensions/java8/src/test/java/com/google/common/truth/IntStreamSubjectTest.java
@@ -202,17 +202,16 @@ public final class IntStreamSubjectTest {
@Test
public void testContainsAtLeast_inOrder_fails() throws Exception {
- try {
- assertThat(IntStream.of(42, 43)).containsAtLeast(43, 42).inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(
- expected,
- "required elements were all found, but order was wrong",
- "expected order for required elements",
- "but was");
- assertFailureValue(expected, "expected order for required elements", "[43, 42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(IntStream.of(42, 43)).containsAtLeast(43, 42).inOrder());
+ assertFailureKeys(
+ expected,
+ "required elements were all found, but order was wrong",
+ "expected order for required elements",
+ "but was");
+ assertFailureValue(expected, "expected order for required elements", "[43, 42]");
}
@Test
@@ -237,17 +236,19 @@ public final class IntStreamSubjectTest {
@Test
public void testContainsAtLeastElementsIn_inOrder_fails() throws Exception {
- try {
- assertThat(IntStream.of(42, 43)).containsAtLeastElementsIn(asList(43, 42)).inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(
- expected,
- "required elements were all found, but order was wrong",
- "expected order for required elements",
- "but was");
- assertFailureValue(expected, "expected order for required elements", "[43, 42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(IntStream.of(42, 43))
+ .containsAtLeastElementsIn(asList(43, 42))
+ .inOrder());
+ assertFailureKeys(
+ expected,
+ "required elements were all found, but order was wrong",
+ "expected order for required elements",
+ "but was");
+ assertFailureValue(expected, "expected order for required elements", "[43, 42]");
}
@Test
@@ -257,13 +258,10 @@ public final class IntStreamSubjectTest {
@Test
public void testContainsExactly_fails() throws Exception {
- try {
- assertThat(IntStream.of(42, 43)).containsExactly(42);
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
- assertFailureValue(expected, "expected", "[42]");
- }
+ AssertionError expected =
+ expectFailure(whenTesting -> whenTesting.that(IntStream.of(42, 43)).containsExactly(42));
+ assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
+ assertFailureValue(expected, "expected", "[42]");
}
@Test
@@ -273,13 +271,12 @@ public final class IntStreamSubjectTest {
@Test
public void testContainsExactly_inOrder_fails() throws Exception {
- try {
- assertThat(IntStream.of(42, 43)).containsExactly(43, 42).inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
- assertFailureValue(expected, "expected", "[43, 42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(IntStream.of(42, 43)).containsExactly(43, 42).inOrder());
+ assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
+ assertFailureValue(expected, "expected", "[43, 42]");
}
@Test
@@ -290,13 +287,12 @@ public final class IntStreamSubjectTest {
@Test
public void testContainsExactlyElementsIn_fails() throws Exception {
- try {
- assertThat(IntStream.of(42, 43)).containsExactlyElementsIn(asList(42));
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
- assertFailureValue(expected, "expected", "[42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(IntStream.of(42, 43)).containsExactlyElementsIn(asList(42)));
+ assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
+ assertFailureValue(expected, "expected", "[42]");
}
@Test
@@ -306,13 +302,15 @@ public final class IntStreamSubjectTest {
@Test
public void testContainsExactlyElementsIn_inOrder_fails() throws Exception {
- try {
- assertThat(IntStream.of(42, 43)).containsExactlyElementsIn(asList(43, 42)).inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
- assertFailureValue(expected, "expected", "[43, 42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(IntStream.of(42, 43))
+ .containsExactlyElementsIn(asList(43, 42))
+ .inOrder());
+ assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
+ assertFailureValue(expected, "expected", "[43, 42]");
}
@Test
diff --git a/extensions/java8/src/test/java/com/google/common/truth/LongStreamSubjectTest.java b/extensions/java8/src/test/java/com/google/common/truth/LongStreamSubjectTest.java
index 9908b354..52c36ea0 100644
--- a/extensions/java8/src/test/java/com/google/common/truth/LongStreamSubjectTest.java
+++ b/extensions/java8/src/test/java/com/google/common/truth/LongStreamSubjectTest.java
@@ -203,17 +203,16 @@ public final class LongStreamSubjectTest {
@Test
public void testContainsAtLeast_inOrder_fails() throws Exception {
- try {
- assertThat(LongStream.of(42, 43)).containsAtLeast(43, 42).inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(
- expected,
- "required elements were all found, but order was wrong",
- "expected order for required elements",
- "but was");
- assertFailureValue(expected, "expected order for required elements", "[43, 42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(LongStream.of(42, 43)).containsAtLeast(43, 42).inOrder());
+ assertFailureKeys(
+ expected,
+ "required elements were all found, but order was wrong",
+ "expected order for required elements",
+ "but was");
+ assertFailureValue(expected, "expected order for required elements", "[43, 42]");
}
@Test
@@ -248,17 +247,19 @@ public final class LongStreamSubjectTest {
@Test
public void testContainsAtLeastElementsIn_inOrder_fails() throws Exception {
- try {
- assertThat(LongStream.of(42, 43)).containsAtLeastElementsIn(asList(43L, 42L)).inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(
- expected,
- "required elements were all found, but order was wrong",
- "expected order for required elements",
- "but was");
- assertFailureValue(expected, "expected order for required elements", "[43, 42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(LongStream.of(42, 43))
+ .containsAtLeastElementsIn(asList(43L, 42L))
+ .inOrder());
+ assertFailureKeys(
+ expected,
+ "required elements were all found, but order was wrong",
+ "expected order for required elements",
+ "but was");
+ assertFailureValue(expected, "expected order for required elements", "[43, 42]");
}
@Test
@@ -279,13 +280,10 @@ public final class LongStreamSubjectTest {
@Test
public void testContainsExactly_fails() throws Exception {
- try {
- assertThat(LongStream.of(42, 43)).containsExactly(42);
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
- assertFailureValue(expected, "expected", "[42]");
- }
+ AssertionError expected =
+ expectFailure(whenTesting -> whenTesting.that(LongStream.of(42, 43)).containsExactly(42));
+ assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
+ assertFailureValue(expected, "expected", "[42]");
}
@Test
@@ -295,13 +293,12 @@ public final class LongStreamSubjectTest {
@Test
public void testContainsExactly_inOrder_fails() throws Exception {
- try {
- assertThat(LongStream.of(42, 43)).containsExactly(43, 42).inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
- assertFailureValue(expected, "expected", "[43, 42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(LongStream.of(42, 43)).containsExactly(43, 42).inOrder());
+ assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
+ assertFailureValue(expected, "expected", "[43, 42]");
}
@Test
@@ -312,13 +309,12 @@ public final class LongStreamSubjectTest {
@Test
public void testContainsExactlyElementsIn_fails() throws Exception {
- try {
- assertThat(LongStream.of(42, 43)).containsExactlyElementsIn(asList(42L));
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
- assertFailureValue(expected, "expected", "[42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(LongStream.of(42, 43)).containsExactlyElementsIn(asList(42L)));
+ assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
+ assertFailureValue(expected, "expected", "[42]");
}
@Test
@@ -336,13 +332,15 @@ public final class LongStreamSubjectTest {
@Test
public void testContainsExactlyElementsIn_inOrder_fails() throws Exception {
- try {
- assertThat(LongStream.of(42, 43)).containsExactlyElementsIn(asList(43L, 42L)).inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
- assertFailureValue(expected, "expected", "[43, 42]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(LongStream.of(42, 43))
+ .containsExactlyElementsIn(asList(43L, 42L))
+ .inOrder());
+ assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
+ assertFailureValue(expected, "expected", "[43, 42]");
}
@Test
diff --git a/extensions/java8/src/test/java/com/google/common/truth/StreamSubjectTest.java b/extensions/java8/src/test/java/com/google/common/truth/StreamSubjectTest.java
index b685e71b..3efc4866 100644
--- a/extensions/java8/src/test/java/com/google/common/truth/StreamSubjectTest.java
+++ b/extensions/java8/src/test/java/com/google/common/truth/StreamSubjectTest.java
@@ -20,9 +20,9 @@ import static com.google.common.truth.FailureAssertions.assertFailureValue;
import static com.google.common.truth.StreamSubject.streams;
import static com.google.common.truth.Truth8.assertThat;
import static java.util.Arrays.asList;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
-import java.util.List;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,17 +36,19 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class StreamSubjectTest {
+ @SuppressWarnings({"DoNotCall", "deprecation"}) // test of a mistaken call
@Test
public void testIsEqualTo() throws Exception {
Stream<String> stream = Stream.of("hello");
- assertThat(stream).isEqualTo(stream);
+ assertThrows(UnsupportedOperationException.class, () -> assertThat(stream).isEqualTo(stream));
}
+ @SuppressWarnings({"DoNotCall", "deprecation"}) // test of a mistaken call
@Test
- public void testIsEqualToList() throws Exception {
+ public void testIsNotEqualTo() throws Exception {
Stream<String> stream = Stream.of("hello");
- List<String> list = asList("hello");
- AssertionError unused = expectFailure(whenTesting -> whenTesting.that(stream).isEqualTo(list));
+ assertThrows(
+ UnsupportedOperationException.class, () -> assertThat(stream).isNotEqualTo(stream));
}
@Test
@@ -210,17 +212,19 @@ public final class StreamSubjectTest {
@Test
public void testContainsAtLeast_inOrder_fails() throws Exception {
- try {
- assertThat(Stream.of("hell", "hello")).containsAtLeast("hello", "hell").inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(
- expected,
- "required elements were all found, but order was wrong",
- "expected order for required elements",
- "but was");
- assertFailureValue(expected, "expected order for required elements", "[hello, hell]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(Stream.of("hell", "hello"))
+ .containsAtLeast("hello", "hell")
+ .inOrder());
+ assertFailureKeys(
+ expected,
+ "required elements were all found, but order was wrong",
+ "expected order for required elements",
+ "but was");
+ assertFailureValue(expected, "expected order for required elements", "[hello, hell]");
}
@Test
@@ -247,19 +251,19 @@ public final class StreamSubjectTest {
@Test
public void testContainsAtLeastElementsIn_inOrder_fails() throws Exception {
- try {
- assertThat(Stream.of("hell", "hello"))
- .containsAtLeastElementsIn(asList("hello", "hell"))
- .inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(
- expected,
- "required elements were all found, but order was wrong",
- "expected order for required elements",
- "but was");
- assertFailureValue(expected, "expected order for required elements", "[hello, hell]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(Stream.of("hell", "hello"))
+ .containsAtLeastElementsIn(asList("hello", "hell"))
+ .inOrder());
+ assertFailureKeys(
+ expected,
+ "required elements were all found, but order was wrong",
+ "expected order for required elements",
+ "but was");
+ assertFailureValue(expected, "expected order for required elements", "[hello, hell]");
}
@Test
@@ -269,14 +273,18 @@ public final class StreamSubjectTest {
}
@Test
+ public void testContainsExactly_null() throws Exception {
+ assertThat(Stream.of((Object) null)).containsExactly((Object) null);
+ assertThat(Stream.of((Object) null)).containsExactly((Object[]) null);
+ }
+
+ @Test
public void testContainsExactly_fails() throws Exception {
- try {
- assertThat(Stream.of("hell", "hello")).containsExactly("hell");
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
- assertFailureValue(expected, "expected", "[hell]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting -> whenTesting.that(Stream.of("hell", "hello")).containsExactly("hell"));
+ assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
+ assertFailureValue(expected, "expected", "[hell]");
}
@Test
@@ -286,13 +294,15 @@ public final class StreamSubjectTest {
@Test
public void testContainsExactly_inOrder_fails() throws Exception {
- try {
- assertThat(Stream.of("hell", "hello")).containsExactly("hello", "hell").inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
- assertFailureValue(expected, "expected", "[hello, hell]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(Stream.of("hell", "hello"))
+ .containsExactly("hello", "hell")
+ .inOrder());
+ assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
+ assertFailureValue(expected, "expected", "[hello, hell]");
}
@Test
@@ -303,13 +313,14 @@ public final class StreamSubjectTest {
@Test
public void testContainsExactlyElementsIn_fails() throws Exception {
- try {
- assertThat(Stream.of("hell", "hello")).containsExactlyElementsIn(asList("hell"));
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
- assertFailureValue(expected, "expected", "[hell]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(Stream.of("hell", "hello"))
+ .containsExactlyElementsIn(asList("hell")));
+ assertFailureKeys(expected, "unexpected (1)", "---", "expected", "but was");
+ assertFailureValue(expected, "expected", "[hell]");
}
@Test
@@ -321,15 +332,15 @@ public final class StreamSubjectTest {
@Test
public void testContainsExactlyElementsIn_inOrder_fails() throws Exception {
- try {
- assertThat(Stream.of("hell", "hello"))
- .containsExactlyElementsIn(asList("hello", "hell"))
- .inOrder();
- fail();
- } catch (AssertionError expected) {
- assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
- assertFailureValue(expected, "expected", "[hello, hell]");
- }
+ AssertionError expected =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(Stream.of("hell", "hello"))
+ .containsExactlyElementsIn(asList("hello", "hell"))
+ .inOrder());
+ assertFailureKeys(expected, "contents match, but order was wrong", "expected", "but was");
+ assertFailureValue(expected, "expected", "[hello, hell]");
}
@Test
diff --git a/extensions/liteproto/pom.xml b/extensions/liteproto/pom.xml
index 82bdc46d..7474ee5a 100644
--- a/extensions/liteproto/pom.xml
+++ b/extensions/liteproto/pom.xml
@@ -44,6 +44,15 @@
</dependency>
</dependencies>
<build>
+ <resources>
+ <resource>
+ <directory>../..</directory>
+ <includes>
+ <include>LICENSE</include>
+ </includes>
+ <targetPath>META-INF</targetPath>
+ </resource>
+ </resources>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
diff --git a/extensions/liteproto/src/main/java/com/google/common/truth/extensions/proto/LiteProtoSubject.java b/extensions/liteproto/src/main/java/com/google/common/truth/extensions/proto/LiteProtoSubject.java
index 8bee5946..3a0774ee 100644
--- a/extensions/liteproto/src/main/java/com/google/common/truth/extensions/proto/LiteProtoSubject.java
+++ b/extensions/liteproto/src/main/java/com/google/common/truth/extensions/proto/LiteProtoSubject.java
@@ -139,10 +139,31 @@ public class LiteProtoSubject extends Subject {
/**
* @deprecated A Builder can never compare equal to a MessageLite instance. Use {@code build()},
- * or {@code buildPartial()} on the argument to get a MessageLite for comparison instead.
+ * or {@code buildPartial()} on the argument to get a MessageLite for comparison instead. Or,
+ * if you are passing {@code null}, use {@link #isNull()}.
+ */
+ /*
+ * TODO(cpovirk): Consider @DoNotCall -- or probably some other static analysis, given the problem
+ * discussed in the rest of this comment.
+ *
+ * The problem: isEqualTo(null) resolves to this overload (since this overload is more specific
+ * than isEqualTo(Object)), so @DoNotCall would break all assertions of that form.
+ *
+ * To address that, we could try also adding something like `<NullT extends Impossible &
+ * MessageLite.Builder> void isEqualTo(NullT)` and hoping that isEqualTo(null) would resolve to
+ * that instead. That would also have the benefit of making isEqualTo(null) not produce a
+ * deprecation warning (though of course people "should" use isNull(): b/17294077). But yuck.
+ *
+ * Given the null issue, maybe we should never have added this overload in the first place,
+ * instead adding static analysis specific to MessageLite-MessageLite.Builder comparisons. (Sadly,
+ * we can't remove it now without breaking binary compatibility.)
+ *
+ * Still, we could add static analysis to produce a compile error for isEqualTo(Builder) this even
+ * today, even without using @DoNotCall. And then we could consider removing @Deprecated to stop
+ * spamming the people who call isEqualTo(null).
*/
@Deprecated
- public void isEqualTo(MessageLite./*@Nullable*/ Builder builder) {
+ public void isEqualTo(MessageLite.@Nullable Builder builder) {
isEqualTo((Object) builder);
}
@@ -169,10 +190,12 @@ public class LiteProtoSubject extends Subject {
/**
* @deprecated A Builder will never compare equal to a MessageLite instance. Use {@code build()},
- * or {@code buildPartial()} on the argument to get a MessageLite for comparison instead.
+ * or {@code buildPartial()} on the argument to get a MessageLite for comparison instead. Or,
+ * if you are passing {@code null}, use {@link #isNotNull()}.
*/
+ // TODO(cpovirk): Consider @DoNotCall or other static analysis. (See isEqualTo(Builder).)
@Deprecated
- public void isNotEqualTo(MessageLite./*@Nullable*/ Builder builder) {
+ public void isNotEqualTo(MessageLite.@Nullable Builder builder) {
isNotEqualTo((Object) builder);
}
diff --git a/extensions/liteproto/src/test/java/com/google/common/truth/extensions/proto/LiteProtoSubjectTest.java b/extensions/liteproto/src/test/java/com/google/common/truth/extensions/proto/LiteProtoSubjectTest.java
index c3e0ed2d..372100e4 100644
--- a/extensions/liteproto/src/test/java/com/google/common/truth/extensions/proto/LiteProtoSubjectTest.java
+++ b/extensions/liteproto/src/test/java/com/google/common/truth/extensions/proto/LiteProtoSubjectTest.java
@@ -16,13 +16,15 @@
package com.google.common.truth.extensions.proto;
import static com.google.common.truth.ExpectFailure.assertThat;
+import static com.google.common.truth.ExpectFailure.expectFailureAbout;
import static com.google.common.truth.extensions.proto.LiteProtoTruth.assertThat;
-import static org.junit.Assert.fail;
+import static com.google.common.truth.extensions.proto.LiteProtoTruth.liteProtos;
import com.google.auto.value.AutoValue;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.truth.Expect;
+import com.google.common.truth.ExpectFailure.SimpleSubjectBuilderCallback;
import com.google.common.truth.Subject;
import com.google.protobuf.MessageLite;
import java.util.Arrays;
@@ -174,34 +176,37 @@ public class LiteProtoSubjectTest {
@Test
public void testIsEqualTo_failure() {
- try {
- assertThat(config.nonEmptyMessage()).isEqualTo(config.nonEmptyMessageOfOtherValue());
- fail("Should have failed.");
- } catch (AssertionError e) {
- expectRegex(e, ".*expected:.*\"foo\".*");
- expectNoRegex(e, ".*but was:.*\"foo\".*");
- }
-
- try {
- assertThat(config.nonEmptyMessage()).isEqualTo(config.nonEmptyMessageOfOtherType());
- fail("Should have failed.");
- } catch (AssertionError e) {
- expectRegex(
- e,
- "Not true that \\(.*\\) proto is equal to the expected \\(.*\\) object\\.\\s*"
- + "They are not of the same class\\.");
- }
-
- try {
- assertThat(config.nonEmptyMessage()).isNotEqualTo(config.equivalentNonEmptyMessage());
- fail("Should have failed.");
- } catch (AssertionError e) {
- expectRegex(
- e,
- String.format(
- "Not true that protos are different\\.\\s*Both are \\(%s\\) <.*optional_int: 3.*>\\.",
- Pattern.quote(config.nonEmptyMessage().getClass().getName())));
- }
+ AssertionError e =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(config.nonEmptyMessage())
+ .isEqualTo(config.nonEmptyMessageOfOtherValue()));
+ expectRegex(e, ".*expected:.*\"foo\".*");
+ expectNoRegex(e, ".*but was:.*\"foo\".*");
+
+ e =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(config.nonEmptyMessage())
+ .isEqualTo(config.nonEmptyMessageOfOtherType()));
+ expectRegex(
+ e,
+ "Not true that \\(.*\\) proto is equal to the expected \\(.*\\) object\\.\\s*"
+ + "They are not of the same class\\.");
+
+ e =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(config.nonEmptyMessage())
+ .isNotEqualTo(config.equivalentNonEmptyMessage()));
+ expectRegex(
+ e,
+ String.format(
+ "Not true that protos are different\\.\\s*Both are \\(%s\\) <.*optional_int: 3.*>\\.",
+ Pattern.quote(config.nonEmptyMessage().getClass().getName())));
}
@Test
@@ -215,15 +220,16 @@ public class LiteProtoSubjectTest {
return;
}
- try {
- assertThat(config.messageWithoutRequiredFields().get()).hasAllRequiredFields();
- fail("Should have failed.");
- } catch (AssertionError e) {
- expectRegex(
- e,
- "expected to have all required fields set\\s*but was: .*\\(Lite runtime could not"
- + " determine which fields were missing.\\)");
- }
+ AssertionError e =
+ expectFailure(
+ whenTesting ->
+ whenTesting
+ .that(config.messageWithoutRequiredFields().get())
+ .hasAllRequiredFields());
+ expectRegex(
+ e,
+ "expected to have all required fields set\\s*but was: .*\\(Lite runtime could not"
+ + " determine which fields were missing.\\)");
}
@Test
@@ -238,27 +244,24 @@ public class LiteProtoSubjectTest {
@Test
public void testDefaultInstance_failure() {
- try {
- assertThat(config.nonEmptyMessage()).isEqualToDefaultInstance();
- fail("Should have failed.");
- } catch (AssertionError e) {
- expectRegex(
- e,
- "Not true that <.*optional_int:\\s*3.*> is a default proto instance\\.\\s*"
- + "It has set values\\.");
- }
-
- try {
- assertThat(config.defaultInstance()).isNotEqualToDefaultInstance();
- fail("Should have failed.");
- } catch (AssertionError e) {
- expectRegex(
- e,
- String.format(
- "Not true that \\(%s\\) <.*\\[empty proto\\].*> is not a default "
- + "proto instance\\.\\s*It has no set values\\.",
- Pattern.quote(config.defaultInstance().getClass().getName())));
- }
+ AssertionError e =
+ expectFailure(
+ whenTesting -> whenTesting.that(config.nonEmptyMessage()).isEqualToDefaultInstance());
+ expectRegex(
+ e,
+ "Not true that <.*optional_int:\\s*3.*> is a default proto instance\\.\\s*"
+ + "It has set values\\.");
+
+ e =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(config.defaultInstance()).isNotEqualToDefaultInstance());
+ expectRegex(
+ e,
+ String.format(
+ "Not true that \\(%s\\) <.*\\[empty proto\\].*> is not a default "
+ + "proto instance\\.\\s*It has no set values\\.",
+ Pattern.quote(config.defaultInstance().getClass().getName())));
}
@Test
@@ -272,21 +275,19 @@ public class LiteProtoSubjectTest {
public void testSerializedSize_failure() {
int size = config.nonEmptyMessage().getSerializedSize();
- try {
- assertThat(config.nonEmptyMessage()).serializedSize().isGreaterThan(size);
- fail("Should have failed.");
- } catch (AssertionError e) {
- assertThat(e).factValue("value of").isEqualTo("liteProto.getSerializedSize()");
- assertThat(e).factValue("liteProto was").containsMatch("optional_int:\\s*3");
- }
-
- try {
- assertThat(config.defaultInstance()).serializedSize().isGreaterThan(0);
- fail("Should have failed.");
- } catch (AssertionError e) {
- assertThat(e).factValue("value of").isEqualTo("liteProto.getSerializedSize()");
- assertThat(e).factValue("liteProto was").contains("[empty proto]");
- }
+ AssertionError e =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(config.nonEmptyMessage()).serializedSize().isGreaterThan(size));
+ assertThat(e).factValue("value of").isEqualTo("liteProto.getSerializedSize()");
+ assertThat(e).factValue("liteProto was").containsMatch("optional_int:\\s*3");
+
+ e =
+ expectFailure(
+ whenTesting ->
+ whenTesting.that(config.defaultInstance()).serializedSize().isGreaterThan(0));
+ assertThat(e).factValue("value of").isEqualTo("liteProto.getSerializedSize()");
+ assertThat(e).factValue("liteProto was").contains("[empty proto]");
}
private void expectRegex(AssertionError e, String regex) {
@@ -296,4 +297,9 @@ public class LiteProtoSubjectTest {
private void expectNoRegex(AssertionError e, String regex) {
expect.that(e).hasMessageThat().doesNotMatch(Pattern.compile(regex, Pattern.DOTALL));
}
+
+ private static AssertionError expectFailure(
+ SimpleSubjectBuilderCallback<LiteProtoSubject, MessageLite> assertionCallback) {
+ return expectFailureAbout(liteProtos(), assertionCallback);
+ }
}
diff --git a/extensions/proto/pom.xml b/extensions/proto/pom.xml
index b69b8e24..7c07acc5 100644
--- a/extensions/proto/pom.xml
+++ b/extensions/proto/pom.xml
@@ -46,6 +46,15 @@
</dependency>
</dependencies>
<build>
+ <resources>
+ <resource>
+ <directory>../..</directory>
+ <includes>
+ <include>LICENSE</include>
+ </includes>
+ <targetPath>META-INF</targetPath>
+ </resource>
+ </resources>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/DiffResult.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/DiffResult.java
index a0ec9373..e6c0af64 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/DiffResult.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/DiffResult.java
@@ -24,7 +24,6 @@ import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
-import com.google.common.truth.extensions.proto.RecursableDiffEntity.WithResultCode.Result;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.ForOverride;
import com.google.protobuf.Descriptors.FieldDescriptor;
@@ -45,6 +44,7 @@ import java.util.Set;
*/
@AutoValue
abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
+
/**
* Structural summary of the difference between two singular (non-repeated) fields.
*
@@ -54,7 +54,8 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
* to the default value, and the other did not.
*/
@AutoValue
- abstract static class SingularField extends RecursableDiffEntity.WithResultCode {
+ abstract static class SingularField extends RecursableDiffEntity.WithResultCode
+ implements ProtoPrintable {
/** The type information for this field. May be absent if result code is {@code IGNORED}. */
abstract Optional<SubScopeId> subScopeId();
@@ -108,9 +109,11 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
case ADDED:
sb.append("added: ").append(fieldPrefix).append(": ");
if (actual().get() instanceof Message) {
- sb.append("\n").append(actual().get());
+ sb.append("\n");
+ printMessage((Message) actual().get(), sb);
} else {
- sb.append(valueString(subScopeId().get(), actual().get())).append("\n");
+ printFieldValue(subScopeId().get(), actual().get(), sb);
+ sb.append("\n");
}
return;
case IGNORED:
@@ -122,9 +125,9 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
sb.append("\n");
printChildContents(includeMatches, fieldPrefix, sb);
} else {
- sb.append(": ")
- .append(valueString(subScopeId().get(), actualOrExpected()))
- .append("\n");
+ sb.append(": ");
+ printFieldValue(subScopeId().get(), actualOrExpected(), sb);
+ sb.append("\n");
}
return;
case MODIFIED:
@@ -133,19 +136,21 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
sb.append("\n");
printChildContents(includeMatches, fieldPrefix, sb);
} else {
- sb.append(": ")
- .append(valueString(subScopeId().get(), expected().get()))
- .append(" -> ")
- .append(valueString(subScopeId().get(), actual().get()))
- .append("\n");
+ sb.append(": ");
+ printFieldValue(subScopeId().get(), expected().get(), sb);
+ sb.append(" -> ");
+ printFieldValue(subScopeId().get(), actual().get(), sb);
+ sb.append("\n");
}
return;
case REMOVED:
sb.append("deleted: ").append(fieldPrefix).append(": ");
if (expected().get() instanceof Message) {
- sb.append("\n").append(expected().get());
+ sb.append("\n");
+ printMessage((Message) expected().get(), sb);
} else {
- sb.append(valueString(subScopeId().get(), expected().get())).append("\n");
+ printFieldValue(subScopeId().get(), expected().get(), sb);
+ sb.append("\n");
}
return;
default:
@@ -159,7 +164,12 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
}
static SingularField ignored(String fieldName) {
- return newBuilder().setFieldName(fieldName).setResult(Result.IGNORED).build();
+ return newBuilder()
+ .setFieldName(fieldName)
+ .setResult(Result.IGNORED)
+ // Ignored fields don't need a customized proto printer.
+ .setProtoPrinter(TextFormat.printer())
+ .build();
}
static Builder newBuilder() {
@@ -167,7 +177,6 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
}
/** Builder for {@link SingularField}. */
- @CanIgnoreReturnValue
@AutoValue.Builder
abstract static class Builder {
abstract Builder setResult(Result result);
@@ -184,6 +193,8 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
abstract Builder setUnknownsBreakdown(UnknownFieldSetDiff unknownsBreakdown);
+ abstract Builder setProtoPrinter(TextFormat.Printer value);
+
abstract SingularField build();
}
}
@@ -206,7 +217,8 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
* If both are present but the indexes differ, it represents a 'move'.
*/
@AutoValue
- abstract static class PairResult extends RecursableDiffEntity.WithResultCode {
+ abstract static class PairResult extends RecursableDiffEntity.WithResultCode
+ implements ProtoPrintable {
/** The {@link FieldDescriptor} describing the repeated field for this pair. */
abstract FieldDescriptor fieldDescriptor();
@@ -264,9 +276,11 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
case ADDED:
sb.append("added: ").append(indexed(fieldPrefix, actualFieldIndex())).append(": ");
if (isMessage()) {
- sb.append("\n").append(actual().get());
+ sb.append("\n");
+ printMessage((Message) actual().get(), sb);
} else {
- sb.append(valueString(fieldDescriptor(), actual().get())).append("\n");
+ printFieldValue(fieldDescriptor(), actual().get(), sb);
+ sb.append("\n");
}
return;
case IGNORED:
@@ -286,7 +300,9 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
sb.append("\n");
printChildContents(includeMatches, indexed(fieldPrefix, actualFieldIndex()), sb);
} else {
- sb.append(" ").append(valueString(fieldDescriptor(), actual().get())).append("\n");
+ sb.append(" ");
+ printFieldValue(fieldDescriptor(), actual().get(), sb);
+ sb.append("\n");
}
return;
case MATCHED:
@@ -303,7 +319,9 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
sb.append("\n");
printChildContents(includeMatches, indexed(fieldPrefix, actualFieldIndex()), sb);
} else {
- sb.append(" ").append(valueString(fieldDescriptor(), actual().get())).append("\n");
+ sb.append(" ");
+ printFieldValue(fieldDescriptor(), actual().get(), sb);
+ sb.append("\n");
}
return;
case MOVED_OUT_OF_ORDER:
@@ -316,7 +334,9 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
sb.append("\n");
printChildContents(includeMatches, indexed(fieldPrefix, actualFieldIndex()), sb);
} else {
- sb.append(" ").append(valueString(fieldDescriptor(), actual().get())).append("\n");
+ sb.append(" ");
+ printFieldValue(fieldDescriptor(), actual().get(), sb);
+ sb.append("\n");
}
return;
case MODIFIED:
@@ -333,18 +353,20 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
sb.append("\n");
printChildContents(includeMatches, indexed(fieldPrefix, actualFieldIndex()), sb);
} else {
- sb.append(" ")
- .append(valueString(fieldDescriptor(), expected().get()))
- .append(" -> ")
- .append(valueString(fieldDescriptor(), actual().get()));
+ sb.append(" ");
+ printFieldValue(fieldDescriptor(), expected().get(), sb);
+ sb.append(" -> ");
+ printFieldValue(fieldDescriptor(), actual().get(), sb);
}
return;
case REMOVED:
sb.append("deleted: ").append(indexed(fieldPrefix, expectedFieldIndex())).append(": ");
if (isMessage()) {
- sb.append("\n").append(expected().get());
+ sb.append("\n");
+ printMessage((Message) expected().get(), sb);
} else {
- sb.append(valueString(fieldDescriptor(), expected().get())).append("\n");
+ printFieldValue(fieldDescriptor(), expected().get(), sb);
+ sb.append("\n");
}
return;
}
@@ -362,7 +384,6 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
return new AutoValue_DiffResult_RepeatedField_PairResult.Builder();
}
- @CanIgnoreReturnValue
@AutoValue.Builder
abstract static class Builder {
abstract Builder setResult(Result result);
@@ -377,6 +398,8 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
abstract Builder setExpected(Object expected);
+ abstract Builder setProtoPrinter(TextFormat.Printer value);
+
abstract Builder setBreakdown(DiffResult breakdown);
abstract PairResult build();
@@ -422,7 +445,6 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
return new AutoValue_DiffResult_RepeatedField.Builder();
}
- @CanIgnoreReturnValue
@AutoValue.Builder
abstract static class Builder {
abstract Builder setFieldDescriptor(FieldDescriptor fieldDescriptor);
@@ -434,6 +456,7 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
@ForOverride
abstract ImmutableList.Builder<PairResult> pairResultsBuilder();
+ @CanIgnoreReturnValue
final Builder addPairResult(PairResult pairResult) {
pairResultsBuilder().add(pairResult);
return this;
@@ -489,7 +512,6 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
return new AutoValue_DiffResult_UnknownFieldSetDiff.Builder();
}
- @CanIgnoreReturnValue
@AutoValue.Builder
abstract static class Builder {
abstract Builder setActual(UnknownFieldSet actual);
@@ -499,11 +521,13 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
@ForOverride
abstract ImmutableListMultimap.Builder<Integer, SingularField> singularFieldsBuilder();
+ @CanIgnoreReturnValue
final Builder addSingularField(int fieldNumber, SingularField singularField) {
singularFieldsBuilder().put(fieldNumber, singularField);
return this;
}
+ @CanIgnoreReturnValue
final Builder addAllSingularFields(int fieldNumber, Iterable<SingularField> singularFields) {
singularFieldsBuilder().putAll(fieldNumber, singularFields);
return this;
@@ -513,6 +537,48 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
}
}
+ /** Utilities to support printing messages and proto fields using a {@link TextFormat.Printer}. */
+ interface ProtoPrintable {
+ TextFormat.Printer protoPrinter();
+
+ default void printMessage(Message m, StringBuilder sb) {
+ try {
+ protoPrinter().print(m, sb);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ default void printFieldValue(SubScopeId subScopeId, Object o, StringBuilder sb) {
+ switch (subScopeId.kind()) {
+ case FIELD_DESCRIPTOR:
+ printFieldValue(subScopeId.fieldDescriptor(), o, sb);
+ return;
+ case UNKNOWN_FIELD_DESCRIPTOR:
+ printFieldValue(subScopeId.unknownFieldDescriptor(), o, sb);
+ return;
+ }
+ throw new AssertionError(subScopeId.kind());
+ }
+
+ default void printFieldValue(FieldDescriptor field, Object value, StringBuilder sb) {
+ try {
+ protoPrinter().printFieldValue(field, value, sb);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ default void printFieldValue(
+ UnknownFieldDescriptor unknownField, Object value, StringBuilder sb) {
+ try {
+ TextFormat.printUnknownFieldValue(unknownField.type().wireType(), value, sb);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+ }
+
/** The {@link Message} being tested. */
abstract Message actual();
@@ -599,37 +665,6 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
return rootFieldPrefix.isEmpty() ? toAdd : (rootFieldPrefix + "." + toAdd);
}
- private static String valueString(SubScopeId subScopeId, Object o) {
- switch (subScopeId.kind()) {
- case FIELD_DESCRIPTOR:
- return valueString(subScopeId.fieldDescriptor(), o);
- case UNKNOWN_FIELD_DESCRIPTOR:
- return valueString(subScopeId.unknownFieldDescriptor(), o);
- }
- throw new AssertionError(subScopeId.kind());
- }
-
- private static String valueString(FieldDescriptor fieldDescriptor, Object o) {
- StringBuilder sb = new StringBuilder();
- try {
- TextFormat.printFieldValue(fieldDescriptor, o, sb);
- return sb.toString();
- } catch (IOException impossible) {
- throw new AssertionError(impossible);
- }
- }
-
- private static String valueString(UnknownFieldDescriptor unknownFieldDescriptor, Object o) {
- StringBuilder sb = new StringBuilder();
- try {
- TextFormat.printUnknownFieldValue(unknownFieldDescriptor.type().wireType(), o, sb);
- return sb.toString();
- } catch (IOException impossible) {
- throw new AssertionError(impossible);
- }
- }
-
- @CanIgnoreReturnValue
@AutoValue.Builder
abstract static class Builder {
abstract Builder setActual(Message actual);
@@ -639,11 +674,13 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
@ForOverride
abstract ImmutableListMultimap.Builder<Integer, SingularField> singularFieldsBuilder();
+ @CanIgnoreReturnValue
final Builder addSingularField(int fieldNumber, SingularField singularField) {
singularFieldsBuilder().put(fieldNumber, singularField);
return this;
}
+ @CanIgnoreReturnValue
final Builder addAllSingularFields(int fieldNumber, Iterable<SingularField> singularFields) {
singularFieldsBuilder().putAll(fieldNumber, singularFields);
return this;
@@ -652,6 +689,7 @@ abstract class DiffResult extends RecursableDiffEntity.WithoutResultCode {
@ForOverride
abstract ImmutableListMultimap.Builder<Integer, RepeatedField> repeatedFieldsBuilder();
+ @CanIgnoreReturnValue
final Builder addRepeatedField(int fieldNumber, RepeatedField repeatedField) {
repeatedFieldsBuilder().put(fieldNumber, repeatedField);
return this;
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldDescriptorValidator.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldDescriptorValidator.java
index a0d64ced..8c3c81fb 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldDescriptorValidator.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldDescriptorValidator.java
@@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkArgument;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor.JavaType;
-import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
/** Various validators, to ensure that explicit comparison settings made by the user make sense. */
enum FieldDescriptorValidator {
@@ -37,9 +36,8 @@ enum FieldDescriptorValidator {
fieldDescriptor);
checkArgument(
- fieldDescriptor.getContainingType().getFile().getSyntax() != Syntax.PROTO3
- || fieldDescriptor.getJavaType() == JavaType.MESSAGE,
- "%s is a primitive field in a Proto 3 message; it cannot be absent",
+ fieldDescriptor.hasPresence(),
+ "%s is a field without presence; it cannot be absent",
fieldDescriptor);
}
},
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldScopeUtil.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldScopeUtil.java
index ae0b634c..c45b1c61 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldScopeUtil.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldScopeUtil.java
@@ -34,13 +34,8 @@ final class FieldScopeUtil {
* @param fmt Format string that must contain exactly one '%s' and no other format parameters.
*/
static Function<Optional<Descriptor>, String> fieldNumbersFunction(
- final String fmt, final Iterable<Integer> fieldNumbers) {
- return new Function<Optional<Descriptor>, String>() {
- @Override
- public String apply(Optional<Descriptor> optDescriptor) {
- return resolveFieldNumbers(optDescriptor, fmt, fieldNumbers);
- }
- };
+ String fmt, Iterable<Integer> fieldNumbers) {
+ return optDescriptor -> resolveFieldNumbers(optDescriptor, fmt, fieldNumbers);
}
/**
@@ -50,25 +45,15 @@ final class FieldScopeUtil {
* @param fmt Format string that must contain exactly one '%s' and no other format parameters.
*/
static Function<Optional<Descriptor>, String> fieldScopeFunction(
- final String fmt, final FieldScope fieldScope) {
- return new Function<Optional<Descriptor>, String>() {
- @Override
- public String apply(Optional<Descriptor> optDescriptor) {
- return String.format(fmt, fieldScope.usingCorrespondenceString(optDescriptor));
- }
- };
+ String fmt, FieldScope fieldScope) {
+ return optDescriptor -> String.format(fmt, fieldScope.usingCorrespondenceString(optDescriptor));
}
/** Returns a function which concatenates the outputs of the two input functions. */
static Function<Optional<Descriptor>, String> concat(
- final Function<? super Optional<Descriptor>, String> function1,
- final Function<? super Optional<Descriptor>, String> function2) {
- return new Function<Optional<Descriptor>, String>() {
- @Override
- public String apply(Optional<Descriptor> optDescriptor) {
- return function1.apply(optDescriptor) + function2.apply(optDescriptor);
- }
- };
+ Function<? super Optional<Descriptor>, String> function1,
+ Function<? super Optional<Descriptor>, String> function2) {
+ return optDescriptor -> function1.apply(optDescriptor) + function2.apply(optDescriptor);
}
/**
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FluentEqualityConfig.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FluentEqualityConfig.java
index 1d5fff1d..25efe721 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FluentEqualityConfig.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FluentEqualityConfig.java
@@ -29,7 +29,6 @@ import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.truth.Correspondence;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.errorprone.annotations.CheckReturnValue;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.ExtensionRegistry;
@@ -366,7 +365,7 @@ abstract class FluentEqualityConfig implements FieldScopeLogicContainer<FluentEq
}
final <M extends Message> Correspondence<M, M> toCorrespondence(
- final Optional<Descriptor> optDescriptor) {
+ Optional<Descriptor> optDescriptor) {
checkState(hasExpectedMessages(), "withExpectedMessages() not called");
return Correspondence.from(
// If we were allowed lambdas, this would be:
@@ -409,7 +408,6 @@ abstract class FluentEqualityConfig implements FieldScopeLogicContainer<FluentEq
abstract Builder toBuilder();
- @CanIgnoreReturnValue
@AutoValue.Builder
abstract static class Builder {
abstract Builder setIgnoreFieldAbsenceScope(FieldScopeLogic fieldScopeLogic);
@@ -433,6 +431,7 @@ abstract class FluentEqualityConfig implements FieldScopeLogicContainer<FluentEq
abstract Builder setReportMismatchesOnly(boolean reportMismatchesOnly);
+ @CanIgnoreReturnValue
final Builder setUnpackingAnyUsing(
TypeRegistry typeRegistry, ExtensionRegistry extensionRegistry) {
setUseTypeRegistry(typeRegistry);
@@ -444,7 +443,6 @@ abstract class FluentEqualityConfig implements FieldScopeLogicContainer<FluentEq
abstract Builder setUseExtensionRegistry(ExtensionRegistry extensionRegistry);
- @CheckReturnValue
abstract Function<? super Optional<Descriptor>, String> usingCorrespondenceStringFunction();
abstract Builder setUsingCorrespondenceStringFunction(
@@ -455,11 +453,13 @@ abstract class FluentEqualityConfig implements FieldScopeLogicContainer<FluentEq
// Lazy formatting methods.
// These allow us to print raw integer field numbers with meaningful names.
+ @CanIgnoreReturnValue
final Builder addUsingCorrespondenceString(String string) {
return setUsingCorrespondenceStringFunction(
FieldScopeUtil.concat(usingCorrespondenceStringFunction(), Functions.constant(string)));
}
+ @CanIgnoreReturnValue
final Builder addUsingCorrespondenceFieldNumbersString(
String fmt, Iterable<Integer> fieldNumbers) {
return setUsingCorrespondenceStringFunction(
@@ -468,6 +468,7 @@ abstract class FluentEqualityConfig implements FieldScopeLogicContainer<FluentEq
FieldScopeUtil.fieldNumbersFunction(fmt, fieldNumbers)));
}
+ @CanIgnoreReturnValue
final Builder addUsingCorrespondenceFieldDescriptorsString(
String fmt, Iterable<FieldDescriptor> fieldDescriptors) {
return setUsingCorrespondenceStringFunction(
@@ -476,6 +477,7 @@ abstract class FluentEqualityConfig implements FieldScopeLogicContainer<FluentEq
Functions.constant(String.format(fmt, join(fieldDescriptors)))));
}
+ @CanIgnoreReturnValue
final Builder addUsingCorrespondenceFieldScopeString(String fmt, FieldScope fieldScope) {
return setUsingCorrespondenceStringFunction(
FieldScopeUtil.concat(
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosSubject.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosSubject.java
index 0b9252a7..b5f342bb 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosSubject.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosSubject.java
@@ -29,7 +29,9 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.Message;
+import com.google.protobuf.TextFormat;
import com.google.protobuf.TypeRegistry;
+import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -64,6 +66,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
private final FailureMetadata metadata;
private final Iterable<M> actual;
private final FluentEqualityConfig config;
+ private final TextFormat.Printer protoPrinter;
protected IterableOfProtosSubject(
FailureMetadata failureMetadata, @Nullable Iterable<M> messages) {
@@ -78,6 +81,28 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
this.metadata = failureMetadata;
this.actual = messages;
this.config = config;
+ this.protoPrinter = TextFormat.printer().usingTypeRegistry(config.useTypeRegistry());
+ }
+
+ @Override
+ protected String actualCustomStringRepresentation() {
+ if (actual == null) {
+ return "null";
+ }
+ StringBuilder sb = new StringBuilder().append('[');
+ boolean first = true;
+ for (M element : actual) {
+ if (!first) {
+ sb.append(", ");
+ }
+ first = false;
+ try {
+ protoPrinter.print(element, sb);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+ return sb.append(']').toString();
}
/**
@@ -735,7 +760,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
@Override
@CanIgnoreReturnValue
- public Ordered containsExactly(/*@Nullable*/ M... expected) {
+ public Ordered containsExactly(@Nullable M... expected) {
return delegate(Arrays.asList(expected)).containsExactly(expected);
}
@@ -753,7 +778,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
@Override
@CanIgnoreReturnValue
- public Ordered containsAtLeast(@Nullable M first, @Nullable M second, /*@Nullable*/ M... rest) {
+ public Ordered containsAtLeast(@Nullable M first, @Nullable M second, @Nullable M... rest) {
return delegate(Lists.asList(first, second, rest)).containsAtLeast(first, second, rest);
}
@@ -770,7 +795,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
}
@Override
- public void containsAnyOf(@Nullable M first, @Nullable M second, /*@Nullable*/ M... rest) {
+ public void containsAnyOf(@Nullable M first, @Nullable M second, @Nullable M... rest) {
delegate(Lists.asList(first, second, rest)).containsAnyOf(first, second, rest);
}
@@ -786,7 +811,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
@Override
public void containsNoneOf(
- @Nullable M firstExcluded, @Nullable M secondExcluded, /*@Nullable*/ M... restOfExcluded) {
+ @Nullable M firstExcluded, @Nullable M secondExcluded, @Nullable M... restOfExcluded) {
delegate(Lists.asList(firstExcluded, secondExcluded, restOfExcluded))
.containsNoneOf(firstExcluded, secondExcluded, restOfExcluded);
}
@@ -1029,7 +1054,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
}
@Override
- public Ordered containsExactly(/*@Nullable*/ M... expected) {
+ public Ordered containsExactly(@Nullable M... expected) {
return usingCorrespondence().containsExactly(expected);
}
@@ -1044,7 +1069,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
}
@Override
- public Ordered containsAtLeast(@Nullable M first, @Nullable M second, /*@Nullable*/ M... rest) {
+ public Ordered containsAtLeast(@Nullable M first, @Nullable M second, @Nullable M... rest) {
return usingCorrespondence().containsAtLeast(first, second, rest);
}
@@ -1059,7 +1084,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
}
@Override
- public void containsAnyOf(@Nullable M first, @Nullable M second, /*@Nullable*/ M... rest) {
+ public void containsAnyOf(@Nullable M first, @Nullable M second, @Nullable M... rest) {
usingCorrespondence().containsAnyOf(first, second, rest);
}
@@ -1075,7 +1100,7 @@ public class IterableOfProtosSubject<M extends Message> extends IterableSubject
@Override
public void containsNoneOf(
- @Nullable M firstExcluded, @Nullable M secondExcluded, /*@Nullable*/ M... restOfExcluded) {
+ @Nullable M firstExcluded, @Nullable M secondExcluded, @Nullable M... restOfExcluded) {
usingCorrespondence().containsNoneOf(firstExcluded, secondExcluded, restOfExcluded);
}
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosUsingCorrespondence.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosUsingCorrespondence.java
index 5a49369a..9c366f58 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosUsingCorrespondence.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/IterableOfProtosUsingCorrespondence.java
@@ -83,7 +83,7 @@ public interface IterableOfProtosUsingCorrespondence<M extends Message> {
* elements, not an element itself.
*/
@CanIgnoreReturnValue
- Ordered containsExactly(/*@Nullable*/ M... expected);
+ Ordered containsExactly(@Nullable M... expected);
/**
* Checks that subject contains exactly elements that correspond to the expected elements, i.e.
@@ -117,7 +117,7 @@ public interface IterableOfProtosUsingCorrespondence<M extends Message> {
* subject, but they are not required to be consecutive.
*/
@CanIgnoreReturnValue
- Ordered containsAtLeast(@Nullable M first, @Nullable M second, /*@Nullable*/ M... rest);
+ Ordered containsAtLeast(@Nullable M first, @Nullable M second, @Nullable M... rest);
/**
* Checks that the subject contains elements that corresponds to all of the expected elements,
@@ -147,7 +147,7 @@ public interface IterableOfProtosUsingCorrespondence<M extends Message> {
* Checks that the subject contains at least one element that corresponds to at least one of the
* expected elements.
*/
- void containsAnyOf(@Nullable M first, @Nullable M second, /*@Nullable*/ M... rest);
+ void containsAnyOf(@Nullable M first, @Nullable M second, @Nullable M... rest);
/**
* Checks that the subject contains at least one element that corresponds to at least one of the
@@ -167,7 +167,7 @@ public interface IterableOfProtosUsingCorrespondence<M extends Message> {
* to any of the given elements.)
*/
void containsNoneOf(
- @Nullable M firstExcluded, @Nullable M secondExcluded, /*@Nullable*/ M... restOfExcluded);
+ @Nullable M firstExcluded, @Nullable M secondExcluded, @Nullable M... restOfExcluded);
/**
* Checks that the subject contains no elements that correspond to any of the given elements.
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesFluentAssertion.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesFluentAssertion.java
index fee52423..f1aa7af1 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesFluentAssertion.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesFluentAssertion.java
@@ -524,7 +524,7 @@ public interface MapWithProtoValuesFluentAssertion<M extends Message> {
* key/value pairs at compile time. Please make sure you provide varargs in key/value pairs!
*/
@CanIgnoreReturnValue
- Ordered containsExactly(@Nullable Object k0, @Nullable M v0, /*@Nullable*/ Object... rest);
+ Ordered containsExactly(@Nullable Object k0, @Nullable M v0, @Nullable Object... rest);
/**
* Fails if the map does not contain exactly the keys in the given map, mapping to values that
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesSubject.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesSubject.java
index 2f4fac81..9248843e 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesSubject.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MapWithProtoValuesSubject.java
@@ -870,8 +870,7 @@ public class MapWithProtoValuesSubject<M extends Message> extends MapSubject {
@Override
@CanIgnoreReturnValue
@SuppressWarnings("unchecked") // ClassCastException is fine
- public Ordered containsExactly(
- @Nullable Object k0, @Nullable M v0, /*@Nullable*/ Object... rest) {
+ public Ordered containsExactly(@Nullable Object k0, @Nullable M v0, @Nullable Object... rest) {
List<M> expectedValues = new ArrayList<>();
expectedValues.add(v0);
for (int i = 1; i < rest.length; i += 2) {
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesFluentAssertion.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesFluentAssertion.java
index 224e3302..838389b4 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesFluentAssertion.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesFluentAssertion.java
@@ -536,7 +536,7 @@ public interface MultimapWithProtoValuesFluentAssertion<M extends Message> {
* key/value pairs at compile time. Please make sure you provide varargs in key/value pairs!
*/
@CanIgnoreReturnValue
- public Ordered containsExactly(@Nullable Object k0, @Nullable M v0, /*@Nullable*/ Object... rest);
+ public Ordered containsExactly(@Nullable Object k0, @Nullable M v0, @Nullable Object... rest);
/**
* @deprecated Do not call {@code equals()} on a {@code MultimapWithProtoValuesFluentAssertion}.
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesSubject.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesSubject.java
index 8a1e5c0a..8b37ee95 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesSubject.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/MultimapWithProtoValuesSubject.java
@@ -21,6 +21,7 @@ import static com.google.common.collect.Lists.asList;
import static com.google.common.truth.extensions.proto.FieldScopeUtil.asList;
import static com.google.common.truth.extensions.proto.ProtoTruth.protos;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.MultimapSubject;
@@ -33,7 +34,6 @@ import com.google.protobuf.Message;
import com.google.protobuf.TypeRegistry;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -90,6 +90,12 @@ public class MultimapWithProtoValuesSubject<M extends Message> extends MultimapS
* <p>This method performs no checks on its own and cannot cause test failures. Subsequent
* assertions must be chained onto this method call to test properties of the {@link Multimap}.
*/
+ /*
+ * This is mostly safe because we only read from the map. And if it produces NPE/CCE immediately,
+ * that's no worse than many existing Collection implementations....
+ */
+ @SuppressWarnings("unchecked")
+ @Override
public IterableOfProtosSubject<M> valuesForKey(@Nullable Object key) {
return check("valuesForKey(%s)", key)
.about(protos())
@@ -910,14 +916,13 @@ public class MultimapWithProtoValuesSubject<M extends Message> extends MultimapS
@Override
@CanIgnoreReturnValue
public Ordered containsExactly() {
- return subject.usingCorrespondence(Collections.<M>emptyList()).containsExactly();
+ return subject.usingCorrespondence(ImmutableList.of()).containsExactly();
}
@Override
@CanIgnoreReturnValue
@SuppressWarnings("unchecked") // ClassCastException is fine
- public Ordered containsExactly(
- @Nullable Object k0, @Nullable M v0, /*@Nullable*/ Object... rest) {
+ public Ordered containsExactly(@Nullable Object k0, @Nullable M v0, @Nullable Object... rest) {
List<M> expectedValues = new ArrayList<>();
expectedValues.add(v0);
for (int i = 1; i < rest.length; i += 2) {
@@ -926,14 +931,19 @@ public class MultimapWithProtoValuesSubject<M extends Message> extends MultimapS
return subject.usingCorrespondence(expectedValues).containsExactly(k0, v0, rest);
}
- @SuppressWarnings("DoNotCall")
+ /*
+ * Calling this method is a mistake, so we delegate to a method whose implementation throws an
+ * exception to explain the mistake.
+ */
+ @SuppressWarnings({"DoNotCall", "deprecation"})
@Override
@Deprecated
public boolean equals(Object o) {
return subject.equals(o);
}
- @SuppressWarnings("DoNotCall")
+ // (see equals() just above)
+ @SuppressWarnings({"DoNotCall", "deprecation"})
@Override
@Deprecated
public int hashCode() {
diff --git a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/ProtoTruthMessageDifferencer.java b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/ProtoTruthMessageDifferencer.java
index d843a61d..5ccf6dc1 100644
--- a/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/ProtoTruthMessageDifferencer.java
+++ b/extensions/proto/src/main/java/com/google/common/truth/extensions/proto/ProtoTruthMessageDifferencer.java
@@ -37,7 +37,6 @@ import com.google.protobuf.Any;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor.JavaType;
-import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
import com.google.protobuf.Message;
import com.google.protobuf.TextFormat;
import com.google.protobuf.UnknownFieldSet;
@@ -62,12 +61,14 @@ import org.checkerframework.checker.nullness.qual.Nullable;
final class ProtoTruthMessageDifferencer {
private final FluentEqualityConfig rootConfig;
private final Descriptor rootDescriptor;
+ private final TextFormat.Printer protoPrinter;
private ProtoTruthMessageDifferencer(FluentEqualityConfig rootConfig, Descriptor descriptor) {
rootConfig.validate(descriptor, FieldDescriptorValidator.ALLOW_ALL);
this.rootConfig = rootConfig;
this.rootDescriptor = descriptor;
+ this.protoPrinter = TextFormat.printer().usingTypeRegistry(rootConfig.useTypeRegistry());
}
/** Create a new {@link ProtoTruthMessageDifferencer} for the given config and descriptor. */
@@ -387,6 +388,7 @@ final class ProtoTruthMessageDifferencer {
.setActual(actualList.get(i))
.setActualFieldIndex(i)
.setFieldDescriptor(fieldDescriptor)
+ .setProtoPrinter(protoPrinter)
.build());
} else {
builder.addPairResult(
@@ -481,6 +483,7 @@ final class ProtoTruthMessageDifferencer {
.setFieldDescriptor(fieldDescriptor)
.setExpected(expected)
.setExpectedFieldIndex(expectedIndex)
+ .setProtoPrinter(protoPrinter)
.build());
}
}
@@ -494,6 +497,7 @@ final class ProtoTruthMessageDifferencer {
.setFieldDescriptor(fieldDescriptor)
.setActual(actualList.get(index))
.setActualFieldIndex(index)
+ .setProtoPrinter(protoPrinter)
.build());
}
@@ -505,7 +509,7 @@ final class ProtoTruthMessageDifferencer {
// Also removes the index for the matching value from actualIndicies.
//
// If there is no match, returns null.
- private RepeatedField./*@Nullable*/ PairResult findMatchingPairResult(
+ private RepeatedField.@Nullable PairResult findMatchingPairResult(
Deque<Integer> actualIndices,
List<?> actualValues,
int expectedIndex,
@@ -555,7 +559,8 @@ final class ProtoTruthMessageDifferencer {
RepeatedField.PairResult.Builder pairResultBuilder =
RepeatedField.PairResult.newBuilder()
.setResult(comparison.result())
- .setFieldDescriptor(fieldDescriptor);
+ .setFieldDescriptor(fieldDescriptor)
+ .setProtoPrinter(protoPrinter);
if (actual != null) {
pairResultBuilder.setActual(actual).setActualFieldIndex(actualFieldIndex);
}
@@ -687,7 +692,8 @@ final class ProtoTruthMessageDifferencer {
SingularField.newBuilder()
.setSubScopeId(SubScopeId.of(fieldDescriptor))
.setFieldName(fieldName)
- .setResult(result.build());
+ .setResult(result.build())
+ .setProtoPrinter(protoPrinter);
if (actual != null) {
singularFieldBuilder.setActual(actual);
}
@@ -709,16 +715,12 @@ final class ProtoTruthMessageDifferencer {
FluentEqualityConfig config) {
Result.Builder result = Result.builder();
- // Use the default if it's set and we're ignoring field absence, or if it's a Proto3 primitive
- // for which default is indistinguishable from unset.
+ // Use the default if it's set and we're ignoring field absence or if it's a field without
+ // presence for which default is indistinguishable from unset.
SubScopeId subScopeId = SubScopeId.of(fieldDescriptor);
- boolean isNonRepeatedProto3 =
- !fieldDescriptor.isRepeated()
- && fieldDescriptor.getContainingOneof() == null
- && fieldDescriptor.getFile().getSyntax() == Syntax.PROTO3;
+ boolean hasPresence = fieldDescriptor.isRepeated() || fieldDescriptor.hasPresence();
boolean ignoreFieldAbsence =
- isNonRepeatedProto3
- || config.ignoreFieldAbsenceScope().contains(rootDescriptor, subScopeId);
+ !hasPresence || config.ignoreFieldAbsenceScope().contains(rootDescriptor, subScopeId);
actual = orIfIgnoringFieldAbsence(actual, defaultValue, ignoreFieldAbsence);
expected = orIfIgnoringFieldAbsence(expected, defaultValue, ignoreFieldAbsence);
@@ -750,7 +752,8 @@ final class ProtoTruthMessageDifferencer {
SingularField.newBuilder()
.setSubScopeId(SubScopeId.of(fieldDescriptor))
.setFieldName(fieldName)
- .setResult(result.build());
+ .setResult(result.build())
+ .setProtoPrinter(protoPrinter);
if (actual != null) {
singularFieldBuilder.setActual(actual);
}
@@ -904,7 +907,8 @@ final class ProtoTruthMessageDifferencer {
SingularField.newBuilder()
.setSubScopeId(SubScopeId.of(unknownFieldDescriptor))
.setFieldName(fieldName)
- .setResult(result.build());
+ .setResult(result.build())
+ .setProtoPrinter(protoPrinter);
if (actual != null) {
singularFieldBuilder.setActual(actual);
}
@@ -932,7 +936,8 @@ final class ProtoTruthMessageDifferencer {
SingularField.newBuilder()
.setSubScopeId(SubScopeId.of(unknownFieldDescriptor))
.setFieldName(fieldName)
- .setResult(result.build());
+ .setResult(result.build())
+ .setProtoPrinter(protoPrinter);
if (actual != null) {
singularFieldBuilder.setActual(actual);
}
diff --git a/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/IterableOfProtosSubjectTest.java b/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/IterableOfProtosSubjectTest.java
index 7a06845e..028601bc 100644
--- a/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/IterableOfProtosSubjectTest.java
+++ b/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/IterableOfProtosSubjectTest.java
@@ -16,6 +16,8 @@
package com.google.common.truth.extensions.proto;
+import static java.util.Comparator.comparing;
+
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.protobuf.Message;
@@ -487,12 +489,7 @@ public class IterableOfProtosSubjectTest extends ProtoSubjectTestBase {
Message expectedInt4 = parse("o_int: 4 r_string: 'qux'");
Function<Message, Integer> getInt =
- new Function<Message, Integer>() {
- @Override
- public Integer apply(Message message) {
- return (Integer) message.getField(getFieldDescriptor("o_int"));
- }
- };
+ message -> (Integer) message.getField(getFieldDescriptor("o_int"));
expectFailureWhenTesting()
.that(listOf(actualInt3, actualInt4))
@@ -520,13 +517,6 @@ public class IterableOfProtosSubjectTest extends ProtoSubjectTestBase {
}
private Comparator<Message> compareByOIntAscending() {
- return new Comparator<Message>() {
- @Override
- public int compare(Message message1, Message message2) {
- return Integer.compare(
- (Integer) message1.getField(getFieldDescriptor("o_int")),
- (Integer) message2.getField(getFieldDescriptor("o_int")));
- }
- };
+ return comparing(message -> (Integer) message.getField(getFieldDescriptor("o_int")));
}
}
diff --git a/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTest.java b/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTest.java
index 9b3c0a68..c9eb636b 100644
--- a/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTest.java
+++ b/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTest.java
@@ -208,7 +208,7 @@ public class ProtoSubjectTest extends ProtoSubjectTestBase {
fail("Expected failure.");
} catch (Exception e) {
assertThat(e).hasMessageThat().contains("o_double");
- assertThat(e).hasMessageThat().contains("is a primitive field in a Proto 3 message");
+ assertThat(e).hasMessageThat().contains("is a field without presence");
}
} else {
expectThat(message)
@@ -248,8 +248,8 @@ public class ProtoSubjectTest extends ProtoSubjectTestBase {
Message eqMessage = parse("r_string: \"bar\" r_string: \"foo\"");
Message diffMessage = parse("r_string: \"foo\" r_string: \"foo\" r_string: \"bar\"");
- expectThat(message).isEqualTo(message.toBuilder().build());
- expectThat(message).ignoringRepeatedFieldOrder().isEqualTo(message.toBuilder().build());
+ expectThat(message).isEqualTo(clone(message));
+ expectThat(message).ignoringRepeatedFieldOrder().isEqualTo(clone(message));
expectThat(diffMessage).isNotEqualTo(message);
expectThat(diffMessage).ignoringRepeatedFieldOrder().isNotEqualTo(message);
expectThat(eqMessage).isNotEqualTo(message);
@@ -268,10 +268,8 @@ public class ProtoSubjectTest extends ProtoSubjectTestBase {
"r_test_message: { o_int: 44 r_string: \"qux\" r_string: \"baz\" } "
+ "r_test_message: { o_int: 33 r_string: \"bar\" r_string: \"foo\" } ");
- expectThat(nestedMessage).isEqualTo(nestedMessage.toBuilder().build());
- expectThat(nestedMessage)
- .ignoringRepeatedFieldOrder()
- .isEqualTo(nestedMessage.toBuilder().build());
+ expectThat(nestedMessage).isEqualTo(clone(nestedMessage));
+ expectThat(nestedMessage).ignoringRepeatedFieldOrder().isEqualTo(clone(nestedMessage));
expectThat(diffNestedMessage).isNotEqualTo(nestedMessage);
expectThat(diffNestedMessage).ignoringRepeatedFieldOrder().isNotEqualTo(nestedMessage);
expectThat(eqNestedMessage).isNotEqualTo(nestedMessage);
@@ -786,6 +784,91 @@ public class ProtoSubjectTest extends ProtoSubjectTestBase {
}
@Test
+ public void testAnyMessage_notEqual_diffPrintsExpandedAny() {
+ String typeUrl =
+ isProto3()
+ ? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
+ : "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
+ Message msgWithAny =
+ parse("" + "o_int: 42 " + "o_any_message: { [" + typeUrl + "]: {r_string: \"foo\"} }");
+ Message msgWithoutAny = parse("o_int: 42");
+
+ expectFailureWhenTesting()
+ .that(msgWithAny)
+ .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
+ .isEqualTo(msgWithoutAny);
+ expectThatFailure()
+ .hasMessageThat()
+ .contains(
+ "added: o_any_message: \n" + "[" + typeUrl + "] {\n" + " r_string: \"foo\"\n" + "}\n");
+
+ expectFailureWhenTesting()
+ .that(msgWithoutAny)
+ .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
+ .isEqualTo(msgWithAny);
+ expectThatFailure()
+ .hasMessageThat()
+ .contains(
+ "deleted: o_any_message: \n"
+ + "["
+ + typeUrl
+ + "] {\n"
+ + " r_string: \"foo\"\n"
+ + "}\n");
+ }
+
+ @Test
+ public void testRepeatedAnyMessage_notEqual_diffPrintsExpandedAny() {
+ String typeUrl =
+ isProto3()
+ ? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
+ : "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
+ String fooSubMessage = "{ [" + typeUrl + "]: {r_string: \"foo\"} }";
+ String barSubMessage = "{ [" + typeUrl + "]: {r_string: \"bar\"} }";
+ String bazSubMessage = "{ [" + typeUrl + "]: {r_string: \"baz\"} }";
+ Message msgWithFooBar =
+ parse(
+ ""
+ + "o_int: 42 "
+ + "r_any_message: "
+ + fooSubMessage
+ + "r_any_message: "
+ + barSubMessage);
+ Message msgWithBazFoo =
+ parse(
+ ""
+ + "o_int: 42 "
+ + "r_any_message: "
+ + bazSubMessage
+ + "r_any_message: "
+ + fooSubMessage);
+
+ expectFailureWhenTesting()
+ .that(msgWithFooBar)
+ .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
+ .ignoringRepeatedFieldOrder()
+ .isEqualTo(msgWithBazFoo);
+
+ expectThatFailure()
+ .hasMessageThat()
+ .contains(
+ ""
+ + "moved: r_any_message[1] -> r_any_message[0]:\n"
+ + "added: r_any_message[1]: \n"
+ + "["
+ + typeUrl
+ + "] {\n"
+ + " r_string: \"bar\"\n"
+ + "}\n"
+ + "deleted: r_any_message[0]: \n"
+ + "["
+ + typeUrl
+ + "] {\n"
+ + " r_string: \"baz\"\n"
+ + "}");
+ }
+
+ @Test
public void testAnyMessagesWithDifferentTypes() {
String typeUrl =
isProto3()
@@ -870,8 +953,8 @@ public class ProtoSubjectTest extends ProtoSubjectTestBase {
@Test
public void testMapWithDefaultKeysAndValues() throws InvalidProtocolBufferException {
Descriptor descriptor = getFieldDescriptor("o_int").getContainingType();
- final String defaultString = "";
- final int defaultInt32 = 0;
+ String defaultString = "";
+ int defaultInt32 = 0;
Message message = makeProtoMap(ImmutableMap.of(defaultString, 1, "foo", defaultInt32));
Message dynamicMessage =
DynamicMessage.parseFrom(
diff --git a/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTestBase.java b/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTestBase.java
index a6d4e6b5..cc7fd0a3 100644
--- a/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTestBase.java
+++ b/extensions/proto/src/test/java/com/google/common/truth/extensions/proto/ProtoSubjectTestBase.java
@@ -141,6 +141,10 @@ public class ProtoSubjectTestBase {
return extensionRegistry;
}
+ protected final Message clone(Message in) {
+ return in.toBuilder().build();
+ }
+
protected Message parse(String textProto) {
try {
Message.Builder builder = defaultInstance.toBuilder();
@@ -250,7 +254,7 @@ public class ProtoSubjectTestBase {
for (int i = 0; i < rest.length; i += 2) {
builder.put((K) rest[i], (V) rest[i + 1]);
}
- return builder.build();
+ return builder.buildOrThrow();
}
@SuppressWarnings("unchecked")
diff --git a/extensions/re2j/pom.xml b/extensions/re2j/pom.xml
index d95e4cd1..6ca4180c 100644
--- a/extensions/re2j/pom.xml
+++ b/extensions/re2j/pom.xml
@@ -25,6 +25,15 @@
</dependency>
</dependencies>
<build>
+ <resources>
+ <resource>
+ <directory>../..</directory>
+ <includes>
+ <include>LICENSE</include>
+ </includes>
+ <targetPath>META-INF</targetPath>
+ </resource>
+ </resources>
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
@@ -32,5 +41,3 @@
</plugins>
</build>
</project>
-
-
diff --git a/extensions/re2j/src/main/java/com/google/common/truth/extensions/re2j/Re2jSubjects.java b/extensions/re2j/src/main/java/com/google/common/truth/extensions/re2j/Re2jSubjects.java
index 67b1ed81..1dc387f5 100644
--- a/extensions/re2j/src/main/java/com/google/common/truth/extensions/re2j/Re2jSubjects.java
+++ b/extensions/re2j/src/main/java/com/google/common/truth/extensions/re2j/Re2jSubjects.java
@@ -15,10 +15,13 @@
*/
package com.google.common.truth.extensions.re2j;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.annotations.GwtIncompatible;
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.Subject;
import com.google.re2j.Pattern;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Truth subjects for re2j regular expressions.
@@ -51,26 +54,27 @@ public final class Re2jSubjects {
private static final Subject.Factory<Re2jStringSubject, String> FACTORY =
new Subject.Factory<Re2jStringSubject, String>() {
@Override
- public Re2jStringSubject createSubject(FailureMetadata failureMetadata, String target) {
+ public Re2jStringSubject createSubject(
+ FailureMetadata failureMetadata, @Nullable String target) {
return new Re2jStringSubject(failureMetadata, target);
}
};
- private final String actual;
+ private final @Nullable String actual;
- private Re2jStringSubject(FailureMetadata failureMetadata, String subject) {
+ private Re2jStringSubject(FailureMetadata failureMetadata, @Nullable String subject) {
super(failureMetadata, subject);
this.actual = subject;
}
@Override
protected String actualCustomStringRepresentation() {
- return quote(actual);
+ return quote(checkNotNull(actual));
}
/** Fails if the string does not match the given regex. */
public void matches(String regex) {
- if (!Pattern.matches(regex, actual)) {
+ if (!Pattern.matches(regex, checkNotNull(actual))) {
failWithActual("expected to match ", regex);
}
}
@@ -78,14 +82,14 @@ public final class Re2jSubjects {
/** Fails if the string does not match the given regex. */
@GwtIncompatible("com.google.re2j.Pattern")
public void matches(Pattern regex) {
- if (!regex.matcher(actual).matches()) {
+ if (!regex.matcher(checkNotNull(actual)).matches()) {
failWithActual("expected to match ", regex);
}
}
/** Fails if the string matches the given regex. */
public void doesNotMatch(String regex) {
- if (Pattern.matches(regex, actual)) {
+ if (Pattern.matches(regex, checkNotNull(actual))) {
failWithActual("expected to fail to match", regex);
}
}
@@ -93,7 +97,7 @@ public final class Re2jSubjects {
/** Fails if the string matches the given regex. */
@GwtIncompatible("com.google.re2j.Pattern")
public void doesNotMatch(Pattern regex) {
- if (regex.matcher(actual).matches()) {
+ if (regex.matcher(checkNotNull(actual)).matches()) {
failWithActual("expected to fail to match", regex);
}
}
@@ -101,14 +105,14 @@ public final class Re2jSubjects {
/** Fails if the string does not contain a match on the given regex. */
@GwtIncompatible("com.google.re2j.Pattern")
public void containsMatch(Pattern pattern) {
- if (!pattern.matcher(actual).find()) {
+ if (!pattern.matcher(checkNotNull(actual)).find()) {
failWithActual("expected to contain a match for", pattern);
}
}
/** Fails if the string does not contain a match on the given regex. */
public void containsMatch(String regex) {
- if (!doContainsMatch(actual, regex)) {
+ if (!doContainsMatch(checkNotNull(actual), regex)) {
failWithActual("expected to contain a match for", regex);
}
}
@@ -116,14 +120,14 @@ public final class Re2jSubjects {
/** Fails if the string contains a match on the given regex. */
@GwtIncompatible("com.google.re2j.Pattern")
public void doesNotContainMatch(Pattern pattern) {
- if (pattern.matcher(actual).find()) {
+ if (pattern.matcher(checkNotNull(actual)).find()) {
failWithActual("expected not to contain a match for", pattern);
}
}
/** Fails if the string contains a match on the given regex. */
public void doesNotContainMatch(String regex) {
- if (doContainsMatch(actual, regex)) {
+ if (doContainsMatch(checkNotNull(actual), regex)) {
failWithActual("expected not to contain a match for", regex);
}
}
diff --git a/pom.xml b/pom.xml
index a105364c..ac06274b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,11 +4,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.sonatype.oss</groupId>
- <artifactId>oss-parent</artifactId>
- <version>7</version>
- </parent>
<groupId>com.google.truth</groupId>
<artifactId>truth-parent</artifactId>
<version>HEAD-SNAPSHOT</version>
@@ -18,18 +13,14 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <!-- Properties for plugins for which pluginManagement hasn't been working for us. -->
- <maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
- <maven-enforcer-plugin.version>3.0.0-M3</maven-enforcer-plugin.version>
-
<!-- Properties for multiple-artifact deps. -->
- <auto-value.version>1.8.1</auto-value.version>
+ <auto-value.version>1.10.1</auto-value.version>
<!--
We have a separate property for each flavor of Guava (instead of a shared
version without the -android and -jre suffixes) because that lets
Dependabot update our Guava versions.
-->
- <guava.android.version>30.1.1-android</guava.android.version>
+ <guava.android.version>32.0.1-android</guava.android.version>
<!--
Also, we have this comment in between the 2 flavors of Guava. That's
also to smooth the Dependabot update process: Dependabot generates a
@@ -37,15 +28,18 @@
time, one gets submitted before the other, and
the other ends up with a merge conflict. That requires reapprovals.
-->
- <guava.jre.version>30.1.1-jre</guava.jre.version>
+ <guava.jre.version>32.0.0-jre</guava.jre.version>
<gwt.version>2.9.0</gwt.version>
- <protobuf.version>3.15.8</protobuf.version>
+ <protobuf.version>3.23.2</protobuf.version>
<!-- Property for protobuf-lite protocArtifact, which isn't a "normal" Maven dep. -->
<!-- TODO(cpovirk): Use protobuf.version instead. But that requires finding the new way to request the Lite runtime. -->
<protobuf-lite.protoc.version>3.1.0</protobuf-lite.protoc.version>
<!-- Property for an extension, since Maven doesn't have extensionManagement. -->
- <os-maven-plugin.version>1.7.0</os-maven-plugin.version>
+ <os-maven-plugin.version>1.7.1</os-maven-plugin.version>
+
+ <!-- Default to no additional options (for Java 8). Overridden by a profile. -->
+ <conditionalJavadoc9PlusOptions></conditionalJavadoc9PlusOptions>
</properties>
<dependencyManagement>
<dependencies>
@@ -79,7 +73,7 @@
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
- <version>3.13.0</version>
+ <version>3.35.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -107,20 +101,9 @@
<version>${guava.android.version}</version>
</dependency>
<dependency>
- <groupId>com.google.testing.compile</groupId>
- <artifactId>compile-testing</artifactId>
- <version>0.19</version>
- <exclusions>
- <exclusion>
- <groupId>com.google.truth</groupId>
- <artifactId>truth</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
- <version>2.6.0</version>
+ <version>2.19.1</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
@@ -135,12 +118,12 @@
<dependency>
<groupId>com.google.re2j</groupId>
<artifactId>re2j</artifactId>
- <version>1.6</version>
+ <version>1.7</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
- <version>9.1</version>
+ <version>9.5</version>
</dependency>
<dependency>
<groupId>com.google.jsinterop</groupId>
@@ -217,6 +200,18 @@
<connection>scm:git:git@github.com:google/truth.git</connection>
<url>scm:git:git@github.com:google/truth.git</url>
</scm>
+ <distributionManagement>
+ <snapshotRepository>
+ <id>sonatype-nexus-snapshots</id>
+ <name>Sonatype Nexus Snapshots</name>
+ <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+ </snapshotRepository>
+ <repository>
+ <id>sonatype-nexus-staging</id>
+ <name>Nexus Release Repository</name>
+ <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+ </repository>
+ </distributionManagement>
<build>
<pluginManagement>
<plugins>
@@ -224,24 +219,20 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
- <version>3.9.1</version>
+ <version>3.12.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
- <version>3.1.2</version>
+ <version>3.4.5</version>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
- <version>${maven-javadoc-plugin.version}</version>
+ <version>3.5.0</version>
<configuration>
<additionalOptions>
- <additionalOption>--frames</additionalOption>
- <additionalOption>-Xdoclint:-html</additionalOption>
+ <additionalOption>-Xdoclint:-html ${conditionalJavadoc9PlusOptions}</additionalOption>
</additionalOptions>
- <additionalJOptions>
- <additionalJOption>--no-module-directories</additionalJOption>
- </additionalJOptions>
<doctitle>Truth ${project.version}</doctitle>
<windowtitle>Truth ${project.version}</windowtitle>
<quiet>true</quiet>
@@ -254,11 +245,10 @@
<links>
<!-- TODO(cpovirk): Link to the version that we depend on? -->
<link>https://guava.dev/releases/snapshot-jre/api/docs</link>
- <link>https://developers.google.com/protocol-buffers/docs/reference/java</link>
+ <link>https://protobuf.dev/reference/java/api-docs/</link>
<link>https://junit.org/junit4/javadoc/latest/</link>
<link>https://docs.oracle.com/javase/7/docs/api/</link>
</links>
- <source>8</source>
<sourceFileExcludes>
<sourceFileExclude>**/super/**/*.java</sourceFileExclude>
</sourceFileExcludes>
@@ -266,12 +256,12 @@
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
- <version>3.2.0</version> <!-- work around ubuntu bug -->
+ <version>3.3.0</version> <!-- work around ubuntu bug -->
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
- <version>1.20</version>
+ <version>1.23</version>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
@@ -291,61 +281,32 @@
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.8.1</version>
+ <version>3.11.0</version>
<configuration>
- <source>1.7</source>
- <target>1.7</target>
- <testSource>1.8</testSource>
- <testTarget>1.8</testTarget>
+ <source>1.8</source>
+ <target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
- <version>3.2.1</version>
+ <version>3.3.0</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
- <version>2.22.2</version>
+ <version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
- <version>${maven-enforcer-plugin.version}</version>
+ <version>3.3.0</version>
<executions>
<execution>
<id>enforce</id>
<configuration>
<rules>
- <!--
- Perhaps surprisingly, requireUpperBoundDeps catches problems
- that dependencyConvergence does not: If we use
- dependencyManagement to force Maven to use an *old* version
- of a dependency, that will satisfy dependencyConvergence
- (because the version is now consistent), but it will not
- satisfy requireUpperBoundDeps, which apparently still sees
- the original request for the newer version.
- requireUpperBoundDeps's behavior is probably a good thing.
-
- But, in what seems like a bug, dependencyConvergence catches
- certain upper-bound problems that requireUpperBoundDeps does
- not. To be clear, it's usually *not* a bug for
- dependencyConvergence to give an error when
- requireUpperBoundDeps does not: dependencyConvergence is in
- some ways a stricter test than requireUpperBoundDeps. What
- I'm seeing here is weirder: When I changed liteproto to
- request checker-compat-qual 2.1.0 and
- error_prone_annotations 2.0.9, both older versions than
- those inherited through core Truth, dependencyConvergence
- flagged both as expected, but requireUpperBoundDeps flagged
- only error_prone_annotations. The reason for this may have
- something to do with guava-25.1-android's dependency on the
- even older checker-compat-qual 2.0.0: When I updated Truth
- to depend on guava-26.0, which depends on
- checker-compat-qual 2.5.3, then requireUpperBoundDeps
- detected the problem.
-
- I filed a bug against Maven:
- https://issues.apache.org/jira/browse/MENFORCER-316
- -->
<requireUpperBoundDeps>
<excludes>
<!-- We have some deps on guava-android and others on guava-jre. -->
@@ -353,19 +314,9 @@
</excludes>
</requireUpperBoundDeps>
<!--
- This should be a no-op for us, since we try to list
- everything in dependencyManagement. But it should at least
- make sure that we do remember to put new deps into
- dependencyManagement. It might also flag conflicts that
- exist only in transitive dependencies. If that becomes too
- much of a pain, we can back this check out.
- -->
- <dependencyConvergence />
- <!--
- Note that neither of these rules would catch a conflict
- between, say, java8 and liteproto, since no Truth module
- depends on both of those. If we wanted, we could create
- such a module.
+ Note that this rule would not catch a conflict between, say,
+ java8 and liteproto, since no Truth module depends on both
+ of those. If we wanted, we could create such a module.
-->
</rules>
</configuration>
@@ -387,26 +338,69 @@
</plugin>
</plugins>
</pluginManagement>
- <plugins>
- <!--
- Force a version >2.7 for this parent project. If we use the current
- default of 2.7, Maven ignores this parent project's configuration when
- running maven-javadoc-plugin in children during releases.
- -->
- <plugin>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>${maven-javadoc-plugin.version}</version>
- </plugin>
- <!--
- Similar. Without this, Maven tries to run maven-enforcer-plugin 1.0,
- and it fails to construct an instance of the rule class, apparently
- because of a mismatch between the new Maven APIs and the old Enforcer
- APIs.
- -->
- <plugin>
- <artifactId>maven-enforcer-plugin</artifactId>
- <version>${maven-enforcer-plugin.version}</version>
- </plugin>
- </plugins>
</build>
+ <profiles>
+ <profile>
+ <id>sonatype-oss-release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals><goal>sign</goal></goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals><goal>jar</goal></goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-docs</id>
+ <goals><goal>jar</goal></goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <!--
+ Passes JDK 11-12-specific `no-module-directories` flag to Javadoc tool,
+ which is required to make symbol search work correctly in the generated
+ pages.
+
+ This flag does not exist on 9-10 and 13+ (https://bugs.openjdk.java.net/browse/JDK-8215582).
+
+ Consider removing it once our release and test scripts are migrated to a recent JDK (17+).
+ -->
+ <id>javadocs-jdk11-12</id>
+ <activation>
+ <jdk>[11,13)</jdk>
+ </activation>
+ <properties>
+ <maven-javadoc-plugin.additionalJOptions>--no-module-directories</maven-javadoc-plugin.additionalJOptions>
+ </properties>
+ </profile>
+ <profile>
+ <id>javadocs-jdk9plus</id>
+ <activation>
+ <jdk>[9,)</jdk>
+ </activation>
+ <properties>
+ <conditionalJavadocOptions>--frames</conditionalJavadocOptions>
+ </properties>
+ </profile>
+ </profiles>
</project>
diff --git a/refactorings/src/main/java/com/google/common/truth/refactorings/CorrespondenceSubclassToFactoryCall.java b/refactorings/src/main/java/com/google/common/truth/refactorings/CorrespondenceSubclassToFactoryCall.java
index 76a85502..c10b24ea 100644
--- a/refactorings/src/main/java/com/google/common/truth/refactorings/CorrespondenceSubclassToFactoryCall.java
+++ b/refactorings/src/main/java/com/google/common/truth/refactorings/CorrespondenceSubclassToFactoryCall.java
@@ -58,6 +58,7 @@ import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
+import com.google.errorprone.suppliers.Supplier;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionStatementTree;
@@ -80,8 +81,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
-import javax.annotation.Nullable;
import javax.lang.model.element.Modifier;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Refactors some subclasses of {@code Correspondence} to instead call {@code Correspondence.from}.
@@ -94,6 +95,12 @@ import javax.lang.model.element.Modifier;
severity = SUGGESTION)
public final class CorrespondenceSubclassToFactoryCall extends BugChecker
implements ClassTreeMatcher {
+
+ private static final String CORRESPONDENCE_CLASS = "com.google.common.truth.Correspondence";
+
+ private static final Supplier<Type> COM_GOOGLE_COMMON_TRUTH_CORRESPONDENCE =
+ VisitorState.memoize(state -> state.getTypeFromString(CORRESPONDENCE_CLASS));
+
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
if (!isCorrespondence(tree.getExtendsClause(), state)) {
@@ -285,7 +292,7 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
private ParentType parentType = ParentType.OTHER;
@Override
- public Void visitMethodInvocation(MethodInvocationTree node, Void unused) {
+ public @Nullable Void visitMethodInvocation(MethodInvocationTree node, Void unused) {
boolean isComparingElementsUsing =
Optional.of(node.getMethodSelect())
.filter(t -> t.getKind() == MEMBER_SELECT)
@@ -304,7 +311,7 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
}
@Override
- public Void visitNewClass(NewClassTree node, Void unused) {
+ public @Nullable Void visitNewClass(NewClassTree node, Void unused) {
if (getSymbol(node.getIdentifier()).equals(classSymbol)) {
calls.put(parentType, node);
}
@@ -324,7 +331,7 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
Set<Tree> references = new HashSet<>();
new TreeScanner<Void, Void>() {
@Override
- public Void scan(Tree node, Void unused) {
+ public @Nullable Void scan(Tree node, Void unused) {
if (equal(getSymbol(node), classSymbol)
&& getDeclaredSymbol(node) == null // Don't touch the ClassTree that we're replacing.
) {
@@ -334,7 +341,7 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
}
@Override
- public Void visitNewClass(NewClassTree node, Void aVoid) {
+ public @Nullable Void visitNewClass(NewClassTree node, Void aVoid) {
scan(node.getEnclosingExpression(), null);
// Do NOT scan node.getIdentifier().
scan(node.getTypeArguments(), null);
@@ -445,7 +452,7 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
* Converts the given method into a lambda, either expression or block, if "appropriate." For
* details about the various cases, see implementation comments.
*/
- private static Tree maybeMakeLambdaBody(MethodTree compareMethod, VisitorState state) {
+ private static @Nullable Tree maybeMakeLambdaBody(MethodTree compareMethod, VisitorState state) {
ExpressionTree comparison = returnExpression(compareMethod);
if (comparison != null) {
// compare() is defined as simply `return something;`. Create a lambda.
@@ -472,7 +479,7 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
boolean[] referenceFound = new boolean[1];
new TreeScanner<Void, Void>() {
@Override
- public Void scan(Tree node, Void aVoid) {
+ public @Nullable Void scan(Tree node, Void aVoid) {
if (paramsOfEnclosingMethod.contains(getSymbol(node))) {
referenceFound[0] = true;
}
@@ -498,7 +505,8 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
}
/** Like {@link VisitorState#findEnclosing} but doesn't consider the leaf to enclose itself. */
- private static <T extends Tree> T findStrictlyEnclosing(VisitorState state, Class<T> clazz) {
+ private static <T extends Tree> @Nullable T findStrictlyEnclosing(
+ VisitorState state, Class<T> clazz) {
return stream(state.getPath().getParentPath())
.filter(clazz::isInstance)
.map(clazz::cast)
@@ -511,7 +519,7 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
* path. For example, if called with {@code ClassTree}, it might return a {@code MethodTree}
* inside the class.
*/
- private static Tree findChildOfStrictlyEnclosing(
+ private static @Nullable Tree findChildOfStrictlyEnclosing(
VisitorState state, Class<? extends Tree> clazz) {
Tree previous = state.getPath().getLeaf();
for (Tree t : state.getPath().getParentPath()) {
@@ -570,7 +578,7 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
abstract Optional<String> supportingMethodDefinition();
}
- private static ExpressionTree returnExpression(MethodTree method) {
+ private static @Nullable ExpressionTree returnExpression(MethodTree method) {
List<? extends StatementTree> statements = method.getBody().getStatements();
if (statements.size() != 1) {
return null;
@@ -646,13 +654,11 @@ public final class CorrespondenceSubclassToFactoryCall extends BugChecker
}
private static boolean isCorrespondence(Tree supertypeTree, VisitorState state) {
- Type correspondenceType = state.getTypeFromString(CORRESPONDENCE_CLASS);
+ Type correspondenceType = COM_GOOGLE_COMMON_TRUTH_CORRESPONDENCE.get(state);
if (correspondenceType == null) {
return false;
}
return supertypeTree != null
&& state.getTypes().isSameType(getSymbol(supertypeTree).type, correspondenceType);
}
-
- private static final String CORRESPONDENCE_CLASS = "com.google.common.truth.Correspondence";
}
diff --git a/refactorings/src/main/java/com/google/common/truth/refactorings/FailWithFacts.java b/refactorings/src/main/java/com/google/common/truth/refactorings/FailWithFacts.java
index d47b35cb..30cb5207 100644
--- a/refactorings/src/main/java/com/google/common/truth/refactorings/FailWithFacts.java
+++ b/refactorings/src/main/java/com/google/common/truth/refactorings/FailWithFacts.java
@@ -40,6 +40,7 @@ import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import java.util.List;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Migrates Truth subjects from the old {@code fail(String, Object)} to the new {@code
@@ -96,7 +97,7 @@ public final class FailWithFacts extends BugChecker implements MethodInvocationT
return describeMatch(tree, fix.build());
}
- private static String newVerb(String oldVerb) {
+ private static @Nullable String newVerb(String oldVerb) {
List<String> old = Splitter.on(whitespace()).splitToList(oldVerb);
String first = old.get(0);
if (CAPITAL_LETTER.matchesAnyOf(first)) {
diff --git a/refactorings/src/main/java/com/google/common/truth/refactorings/NamedToWithMessage.java b/refactorings/src/main/java/com/google/common/truth/refactorings/NamedToWithMessage.java
deleted file mode 100644
index 411ce6dd..00000000
--- a/refactorings/src/main/java/com/google/common/truth/refactorings/NamedToWithMessage.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (c) 2019 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.refactorings;
-
-import static com.google.common.collect.ImmutableSet.toImmutableSet;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
-import static com.google.errorprone.matchers.Description.NO_MATCH;
-import static com.google.errorprone.matchers.Matchers.anyOf;
-import static com.google.errorprone.matchers.Matchers.instanceMethod;
-import static com.google.errorprone.matchers.Matchers.staticMethod;
-import static com.google.errorprone.util.ASTHelpers.getReceiver;
-import static com.google.errorprone.util.ASTHelpers.getSymbol;
-import static com.google.errorprone.util.ASTHelpers.isSubtype;
-import static com.sun.source.tree.Tree.Kind.MEMBER_SELECT;
-import static com.sun.source.tree.Tree.Kind.METHOD_INVOCATION;
-import static java.lang.String.format;
-import static java.util.stream.Stream.concat;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.BugPattern;
-import com.google.errorprone.VisitorState;
-import com.google.errorprone.bugpatterns.BugChecker;
-import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
-import com.google.errorprone.fixes.SuggestedFix;
-import com.google.errorprone.matchers.Description;
-import com.google.errorprone.matchers.Matcher;
-import com.sun.source.tree.ExpressionTree;
-import com.sun.source.tree.MemberSelectTree;
-import com.sun.source.tree.MethodInvocationTree;
-import com.sun.tools.javac.code.Symbol.MethodSymbol;
-import javax.annotation.Nullable;
-
-/**
- * Migrates assertions from {@code assertThat(...).named(...)} to {@code
- * assertWithMessage(...).that(...)} (sometimes with an {@code about} call in there, and sometimes
- * with {@code withMessage} if using a {@code FailureStrategy} other than assert).
- *
- * <p>Alternatively, if setting up the infrastructure to run this migration tool is too costly,
- * consider running a Perl-compatible regex search-and-replace like: {@code
- * s/assertThat[(](.*)[)]\s*[.]named[(]((?:[^"\n)]|"(?:[^\\\n]|\\.)*")*)[)]/assertWithMessage($2).that($1)/g}.
- * Such a search will not handle as many cases as this tool, and it is more likely to produce code
- * that does not compile (or that no longer uses custom {@code Subject} classes), but it will handle
- * many simple cases.
- */
-@BugPattern(
- name = "NamedToWithMessage",
- summary = "Use assertWithMessage(...)/withMessage(...) instead of the deprecated named(...).",
- severity = SUGGESTION)
-public final class NamedToWithMessage extends BugChecker implements MethodInvocationTreeMatcher {
- @Override
- public Description matchMethodInvocation(MethodInvocationTree namedCall, VisitorState state) {
- if (!NAMED_METHOD.matches(namedCall, state)) {
- return NO_MATCH;
- }
- MethodInvocationTree thatCall = findThatCall(namedCall, state);
- if (thatCall == null) {
- return NO_MATCH;
- }
- ExpressionTree namedReceiver = getReceiver(namedCall);
- if (namedReceiver == null) {
- return NO_MATCH;
- }
- String parensAndNamedArgs =
- state
- .getSourceCode()
- .subSequence(
- state.getEndPosition(namedCall.getMethodSelect()), state.getEndPosition(namedCall))
- .toString();
-
- SuggestedFix.Builder fix = SuggestedFix.builder();
- // We want to do something like the following, but it overlaps with some other changes we make:
- // fix.replace(namedCall, state.getSourceForNode(namedReceiver));
- fix.replace(state.getEndPosition(namedReceiver), state.getEndPosition(namedCall), "");
-
- if (STANDARD_ASSERT_THAT.matches(thatCall, state)) {
- fix.addStaticImport("com.google.common.truth.Truth.assertWithMessage");
- fix.replace(
- thatCall.getMethodSelect(), format("assertWithMessage%s.that", parensAndNamedArgs));
- return describeMatch(namedCall, fix.build());
- }
-
- if (ANY_ASSERT_THAT.matches(thatCall, state)) {
- FactoryMethodName factory = tryFindFactory(thatCall, state);
- if (factory == null) {
- if (ONLY_GENERATE_REFERENCES_TO_FACTORIES_THAT_ALREADY_EXIST) {
- return NO_MATCH;
- }
-
- // Guess at a good name for a factory, and rely on the user to create the factory later.
- MethodSymbol assertThatSymbol = getSymbol(thatCall);
- if (assertThatSymbol == null) {
- return NO_MATCH;
- }
- String factoryMethodEnclosingClass = assertThatSymbol.owner.getQualifiedName().toString();
- // FooSubject -> Foos:
- String factoryMethodName =
- assertThatSymbol.owner.getSimpleName().toString().replaceFirst("Subject$", "s");
- // Foos -> foos:
- factoryMethodName =
- factoryMethodName.substring(0, 1).toLowerCase() + factoryMethodName.substring(1);
- factory = FactoryMethodName.create(factoryMethodEnclosingClass, factoryMethodName);
- }
- fix.addStaticImport("com.google.common.truth.Truth.assertWithMessage");
- fix.addStaticImport(factory.clazz() + "." + factory.method());
- fix.replace(
- thatCall.getMethodSelect(),
- format("assertWithMessage%s.about(%s()).that", parensAndNamedArgs, factory.method()));
- return describeMatch(namedCall, fix.build());
- }
-
- ExpressionTree thatReceiver = getReceiver(thatCall);
- if (thatReceiver == null) {
- return NO_MATCH;
- }
-
- if (STANDARD_SUBJECT_BUILDER_THAT.matches(thatCall, state)) {
- fix.postfixWith(thatReceiver, format(".withMessage%s", parensAndNamedArgs));
- return describeMatch(namedCall, fix.build());
- }
-
- if (OTHER_SUBJECT_BUILDER_THAT.matches(thatCall, state)) {
- if (ASSERT_ABOUT.matches(thatReceiver, state)) {
- if (thatReceiver.getKind() != METHOD_INVOCATION) {
- return NO_MATCH;
- }
- ExpressionTree assertAboutSelect = ((MethodInvocationTree) thatReceiver).getMethodSelect();
-
- fix.addStaticImport("com.google.common.truth.Truth.assertWithMessage");
- fix.replace(assertAboutSelect, format("assertWithMessage%s.about", parensAndNamedArgs));
- return describeMatch(namedCall, fix.build());
- }
-
- if (STANDARD_SUBJECT_BUILDER_ABOUT.matches(thatReceiver, state)) {
- ExpressionTree aboutReceiver = getReceiver(thatReceiver);
- if (aboutReceiver == null) {
- return NO_MATCH;
- }
-
- fix.postfixWith(aboutReceiver, format(".withMessage%s", parensAndNamedArgs));
- return describeMatch(namedCall, fix.build());
- }
- }
-
- return NO_MATCH;
- }
-
- @AutoValue
- abstract static class FactoryMethodName {
- static FactoryMethodName create(String clazz, String method) {
- return new AutoValue_NamedToWithMessage_FactoryMethodName(clazz, method);
- }
-
- static FactoryMethodName tryCreate(MethodSymbol symbol) {
- return symbol.params.isEmpty()
- ? create(symbol.owner.getQualifiedName().toString(), symbol.getSimpleName().toString())
- : null;
- }
-
- abstract String clazz();
-
- abstract String method();
- }
-
- @Nullable
- private static FactoryMethodName tryFindFactory(
- MethodInvocationTree assertThatCall, VisitorState state) {
- MethodSymbol assertThatSymbol = getSymbol(assertThatCall);
- if (assertThatSymbol == null) {
- return null;
- }
- /*
- * First, a special case for ProtoTruth.protos(). Usually the main case below finds it OK, but
- * sometimes it misses it, I believe because it can't decide between that and
- * IterableOfProtosSubject.iterableOfMessages.
- */
- if (assertThatSymbol.owner.getQualifiedName().contentEquals(PROTO_TRUTH_CLASS)) {
- return FactoryMethodName.create(PROTO_TRUTH_CLASS, "protos");
- }
- ImmutableSet<MethodSymbol> factories =
- concat(
- // The class that assertThat is declared in:
- assertThatSymbol.owner.getEnclosedElements().stream(),
- // The Subject class (possibly the same; if so, toImmutableSet() will deduplicate):
- assertThatSymbol.getReturnType().asElement().getEnclosedElements().stream())
- .filter(s -> s instanceof MethodSymbol)
- .map(s -> (MethodSymbol) s)
- .filter(
- s ->
- returns(s, SUBJECT_FACTORY_CLASS, state)
- || returns(s, CUSTOM_SUBJECT_BUILDER_FACTORY_CLASS, state))
- .collect(toImmutableSet());
- return factories.size() == 1 ? FactoryMethodName.tryCreate(getOnlyElement(factories)) : null;
- // TODO(cpovirk): If multiple factories exist, try filtering to visible ones only.
- }
-
- private static boolean returns(MethodSymbol symbol, String returnType, VisitorState state) {
- return isSubtype(symbol.getReturnType(), state.getTypeFromString(returnType), state);
- }
-
- private static MethodInvocationTree findThatCall(MethodInvocationTree tree, VisitorState state) {
- while (true) {
- if (tree.getMethodSelect().getKind() != MEMBER_SELECT) {
- return null;
- }
- MemberSelectTree methodSelect = (MemberSelectTree) tree.getMethodSelect();
- if (methodSelect.getExpression().getKind() != METHOD_INVOCATION) {
- return null;
- }
- tree = (MethodInvocationTree) methodSelect.getExpression();
- if (ANY_ASSERT_THAT.matches(tree, state)
- || STANDARD_SUBJECT_BUILDER_THAT.matches(tree, state)
- || OTHER_SUBJECT_BUILDER_THAT.matches(tree, state)) {
- return tree;
- }
- }
- }
-
- private static final String TRUTH_CLASS = "com.google.common.truth.Truth";
- private static final String PROTO_TRUTH_CLASS =
- "com.google.common.truth.extensions.proto.ProtoTruth";
- private static final String SUBJECT_CLASS = "com.google.common.truth.Subject";
- private static final String SUBJECT_FACTORY_CLASS = "com.google.common.truth.Subject.Factory";
- private static final String CUSTOM_SUBJECT_BUILDER_FACTORY_CLASS =
- "com.google.common.truth.CustomSubjectBuilder.Factory";
- private static final String STANDARD_SUBJECT_BUILDER_CLASS =
- "com.google.common.truth.StandardSubjectBuilder";
- private static final String CUSTOM_SUBJECT_BUILDER_CLASS =
- "com.google.common.truth.CustomSubjectBuilder";
- private static final String SIMPLE_SUBJECT_BUILDER_CLASS =
- "com.google.common.truth.SimpleSubjectBuilder";
-
- private static final Matcher<ExpressionTree> STANDARD_ASSERT_THAT =
- staticMethod().onClass(TRUTH_CLASS).named("assertThat");
- private static final Matcher<ExpressionTree> ANY_ASSERT_THAT =
- staticMethod().anyClass().named("assertThat");
- private static final Matcher<ExpressionTree> ASSERT_ABOUT =
- staticMethod().onClass(TRUTH_CLASS).named("assertAbout");
-
- private static final Matcher<ExpressionTree> STANDARD_SUBJECT_BUILDER_THAT =
- instanceMethod().onDescendantOf(STANDARD_SUBJECT_BUILDER_CLASS).named("that");
- private static final Matcher<ExpressionTree> STANDARD_SUBJECT_BUILDER_ABOUT =
- instanceMethod().onDescendantOf(STANDARD_SUBJECT_BUILDER_CLASS).named("about");
- private static final Matcher<ExpressionTree> OTHER_SUBJECT_BUILDER_THAT =
- anyOf(
- instanceMethod().onDescendantOf(CUSTOM_SUBJECT_BUILDER_CLASS).named("that"),
- instanceMethod().onDescendantOf(SIMPLE_SUBJECT_BUILDER_CLASS).named("that"));
- private static final Matcher<ExpressionTree> NAMED_METHOD =
- instanceMethod().onDescendantOf(SUBJECT_CLASS).named("named");
-
- // TODO(cpovirk): Provide a flag for this.
- private static final boolean ONLY_GENERATE_REFERENCES_TO_FACTORIES_THAT_ALREADY_EXIST = true;
-}
diff --git a/refactorings/src/main/java/com/google/common/truth/refactorings/StoreActualValueInField.java b/refactorings/src/main/java/com/google/common/truth/refactorings/StoreActualValueInField.java
deleted file mode 100644
index ea2e7e21..00000000
--- a/refactorings/src/main/java/com/google/common/truth/refactorings/StoreActualValueInField.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (c) 2019 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.refactorings;
-
-import static com.google.common.collect.ImmutableSet.toImmutableSet;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
-import static com.google.errorprone.fixes.SuggestedFix.replace;
-import static com.google.errorprone.matchers.Description.NO_MATCH;
-import static com.google.errorprone.matchers.Matchers.anyOf;
-import static com.google.errorprone.matchers.Matchers.constructor;
-import static com.google.errorprone.matchers.Matchers.instanceMethod;
-import static com.google.errorprone.matchers.Matchers.staticMethod;
-import static com.google.errorprone.util.ASTHelpers.getType;
-import static com.google.errorprone.util.ASTHelpers.isSameType;
-import static com.google.errorprone.util.ASTHelpers.isSubtype;
-import static com.sun.source.tree.Tree.Kind.CLASS;
-import static com.sun.source.tree.Tree.Kind.IDENTIFIER;
-import static com.sun.source.tree.Tree.Kind.MEMBER_SELECT;
-import static com.sun.source.tree.Tree.Kind.METHOD_INVOCATION;
-import static com.sun.source.tree.Tree.Kind.VARIABLE;
-import static java.lang.String.format;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.BugPattern;
-import com.google.errorprone.VisitorState;
-import com.google.errorprone.bugpatterns.BugChecker;
-import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
-import com.google.errorprone.fixes.SuggestedFix;
-import com.google.errorprone.matchers.Description;
-import com.google.errorprone.matchers.Matcher;
-import com.sun.source.tree.ClassTree;
-import com.sun.source.tree.ExpressionTree;
-import com.sun.source.tree.IdentifierTree;
-import com.sun.source.tree.MemberSelectTree;
-import com.sun.source.tree.MethodInvocationTree;
-import com.sun.source.tree.MethodTree;
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.VariableTree;
-import com.sun.source.util.TreePath;
-import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.tree.JCTree;
-import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
-import com.sun.tools.javac.tree.TreeScanner;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.stream.Stream;
-import javax.lang.model.element.Name;
-
-/**
- * Refactors callers of {@code Subject.actual()} and {@code Subject.getSubject()} to store their own
- * copy of the actual value in a variable and use that instead.
- */
-@BugPattern(
- name = "StoreActualValueInField",
- summary =
- "Store the actual value locally instead of using the deprecated actual() and getSubject().",
- severity = SUGGESTION)
-public final class StoreActualValueInField extends BugChecker
- implements MethodInvocationTreeMatcher {
- @Override
- public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
- ClassTree enclosingClass = state.findEnclosing(ClassTree.class);
- if (enclosingClass == null) {
- return NO_MATCH;
- }
- if (enclosingClass.getMembers().stream()
- .filter(t -> t.getKind() == VARIABLE)
- .map(t -> (VariableTree) t)
- .anyMatch(t -> t.getName().contentEquals("actual"))) {
- return NO_MATCH;
- }
-
- if (ACTUAL_METHOD.matches(tree, state)) {
- if (tree.getMethodSelect().getKind() == IDENTIFIER) {
- if (varNamedActualInScope(state)) {
- return describeMatch(tree, replace(tree, qualifierForThis(state) + "this.actual"));
- } else {
- return describeMatch(tree, replace(tree, "actual"));
- }
- } else if (tree.getMethodSelect().getKind() == MEMBER_SELECT) {
- MemberSelectTree methodSelect = (MemberSelectTree) tree.getMethodSelect();
- return describeMatch(
- tree,
- replace(
- tree, format("%s.actual", state.getSourceForNode(methodSelect.getExpression()))));
- } else {
- return NO_MATCH;
- }
- }
-
- if (!SUBJECT_CONSTRUCTOR_CALL.matches(tree, state)) {
- return NO_MATCH;
- }
- if (tree.getMethodSelect().getKind() != IDENTIFIER
- || !((IdentifierTree) tree.getMethodSelect()).getName().contentEquals("super")) {
- return NO_MATCH;
- }
- IdentifierTree value = findActualArg(tree.getArguments(), state);
- if (value == null) {
- return NO_MATCH;
- }
- /*
- * TODO(cpovirk): Before adding the field, scan the compilation unit for any usages of
- * ThisType.actual(). (But this is moderately rare and usually easy to detect after the fact.
- * Plus, adding the field in all cases is harmless enough.)
- */
- SuggestedFix.Builder fix = SuggestedFix.builder();
- fix.postfixWith(
- state.getPath().getParentPath().getLeaf(),
- format("this.actual = %s;", state.getSourceForNode(value)));
-
- Tree type = findActualFormalType(value.getName(), state);
- Tree putFieldBefore =
- enclosingClass.getMembers().stream()
- .map((Tree t) -> t) // Stream<? extends Tree> -> Stream<Tree>
- .filter(
- t ->
- t.getKind() == VARIABLE
- && !((VariableTree) t).getModifiers().getFlags().contains(STATIC))
- .findFirst()
- .orElse(state.findEnclosing(MethodTree.class));
- fix.prefixWith(
- putFieldBefore, format("private final %s actual;", state.getSourceForNode(type)));
-
- return describeMatch(tree, fix.build());
- }
-
- private static String qualifierForThis(VisitorState state) {
- Type subjectBaseType = state.getTypeFromString("com.google.common.truth.Subject");
-
- boolean seenClassInBetween = false;
- for (Tree t : state.getPath()) {
- if (t.getKind() != CLASS) {
- continue;
- }
- Type enclosingType = getType(t);
- if (isSubtype(enclosingType, subjectBaseType, state)) {
- if (seenClassInBetween) {
- return enclosingType.asElement().getSimpleName() + ".";
- } else {
- return "";
- }
- }
- seenClassInBetween = true;
- }
- return ""; // not sure what's going on, so let's try this
- }
-
- // from an old copy of RenameField (Similar code now lives in FieldRenamer.)
- private static boolean varNamedActualInScope(VisitorState state) {
- final AtomicBoolean local = new AtomicBoolean(false);
-
- MethodTree outerMostMethod = null;
- for (TreePath path = state.getPath(); path != null; path = path.getParentPath()) {
- if (path.getLeaf() instanceof MethodTree) {
- outerMostMethod = (MethodTree) path.getLeaf();
- }
- }
- if (outerMostMethod != null && outerMostMethod.getBody() != null) {
- ((JCTree) outerMostMethod.getBody())
- .accept(
- new TreeScanner() {
- @Override
- public void visitVarDef(JCVariableDecl tree) {
- if (tree.getName().contentEquals("actual")) {
- local.set(true);
- }
- super.visitVarDef(tree);
- }
- });
- }
- return local.get();
- }
-
- // from AbstractCollectionIncompatibleTypeMatcher
- private static Type extractTypeArgAsMemberOfSupertype(
- Type type, Symbol superTypeSym, int typeArgIndex, Types types) {
- Type collectionType = types.asSuper(type, superTypeSym);
- if (collectionType == null) {
- return null;
- }
- com.sun.tools.javac.util.List<Type> tyargs = collectionType.getTypeArguments();
- if (tyargs.size() <= typeArgIndex) {
- // Collection is raw, nothing we can do.
- return null;
- }
-
- return tyargs.get(typeArgIndex);
- }
-
- private static IdentifierTree findActualArg(
- List<? extends ExpressionTree> args, VisitorState state) {
- Type actualType =
- extractTypeArgAsMemberOfSupertype(
- getType(state.findEnclosing(ClassTree.class)),
- state.getSymbolFromString("com.google.common.truth.Subject"),
- 1,
- state.getTypes());
- Type failureMetadataType = state.getTypeFromString("com.google.common.truth.FailureMetadata");
- ImmutableSet<IdentifierTree> candidates =
- args.stream()
- .flatMap(a -> maybeToIdentifier(a, state))
- .filter(a -> !isSameType(getType(a), failureMetadataType, state))
- .filter(a -> isSubtype(getType(a), actualType, state))
- .collect(toImmutableSet());
- if (candidates.size() == 1) {
- return getOnlyElement(candidates);
- }
-
- if (args.size() == 2
- && isSameType(getType(args.get(0)), failureMetadataType, state)
- && args.get(1).getKind() == IDENTIFIER) {
- return (IdentifierTree) args.get(1);
- }
- return null;
- }
-
- private static Stream<IdentifierTree> maybeToIdentifier(ExpressionTree tree, VisitorState state) {
- if (tree.getKind() == IDENTIFIER) {
- return Stream.of((IdentifierTree) tree);
- } else if (tree.getKind() == METHOD_INVOCATION && CHECK_NOT_NULL.matches(tree, state)) {
- /*
- * checkNotNull() is inadvisable (since it makes assertThat(foo) throw NPE for that type, even
- * if the assertion is going to be something like isNull()). But people do it, albeit rarely.
- */
- MethodInvocationTree invocation = (MethodInvocationTree) tree;
- return maybeToIdentifier(invocation.getArguments().get(0), state);
- } else {
- return Stream.empty();
- }
- }
-
- private static Tree findActualFormalType(Name name, VisitorState state) {
- MethodTree method = state.findEnclosing(MethodTree.class);
- if (method == null) {
- return null;
- }
- return method.getParameters().stream()
- .filter(p -> p.getName().equals(name))
- .findFirst()
- .map(p -> p.getType())
- .orElse(null);
- }
-
- private static final Matcher<ExpressionTree> SUBJECT_CONSTRUCTOR_CALL =
- constructor()
- .forClass(
- (type, state) ->
- isSubtype(
- type, state.getTypeFromString("com.google.common.truth.Subject"), state));
- private static final Matcher<ExpressionTree> ACTUAL_METHOD =
- anyOf(
- instanceMethod()
- .onDescendantOf("com.google.common.truth.Subject")
- .named("actual")
- .withParameters(),
- instanceMethod()
- .onDescendantOf("com.google.common.truth.Subject")
- .named("getSubject")
- .withParameters());
- private static final Matcher<ExpressionTree> CHECK_NOT_NULL =
- staticMethod().onClass("com.google.common.base.Preconditions").named("checkNotNull");
-}
diff --git a/util/generate-latest-docs.sh b/util/generate-latest-docs.sh
index 6fc96f36..3e6cfcd5 100755
--- a/util/generate-latest-docs.sh
+++ b/util/generate-latest-docs.sh
@@ -20,10 +20,12 @@ if [ -n "${RELEASE_VERSION:-}" ]; then
# Release
version_subdir=api/${RELEASE_VERSION}
commit_message="Release $RELEASE_VERSION javadoc pushed to gh-pages."
+ github_url="git@github.com:google/truth.git"
else
# CI
version_subdir=api/latest
commit_message="Latest javadoc on successful CI build auto-pushed to gh-pages."
+ github_url="https://x-access-token:${GITHUB_TOKEN}@github.com/google/truth.git"
fi
mvn javadoc:aggregate
@@ -32,7 +34,7 @@ find target/site/apidocs -name '*.html' | xargs perl -077pi -e 's#<li class="blo
target_dir="$(pwd)/target"
cd ${target_dir}
rm -rf gh-pages
-git clone --quiet --branch=gh-pages "https://x-access-token:${GITHUB_TOKEN}@github.com/google/truth.git" gh-pages > /dev/null
+git clone --quiet --branch=gh-pages "${github_url}" gh-pages > /dev/null
cd gh-pages
if [[ -z "${RELEASE_VERSION:-}" ]]; then
diff --git a/util/mvn-deploy.sh b/util/mvn-deploy.sh
deleted file mode 100755
index 30f93cb8..00000000
--- a/util/mvn-deploy.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/bash
-keys="$(gpg --list-keys | grep ^pub | sed 's#/# #' | awk '{ print $3 }')"
-key_count="$(echo ${keys} | wc -w)"
-
-seen=""
-while [[ $# > 0 ]] ; do
- param="$1"
- if [[ $param == "--signing-key" ]]; then
- # disambiguating or overriding key
- key="$2"
- shift
- else
- seen="${seen} ${param}"
- fi
- shift
-done
-params=${seen}
-
-if [[ ${key_count} -lt 1 ]]; then
- echo ""
- echo "You are attempting to deploy a maven release without a GPG signing key."
- echo "You need to generate a signing key in accordance with the instructions"
- echo "found at http://blog.sonatype.com/2010/01/how-to-generate-pgp-signatures-with-maven"
- exit 1
-fi
-
-# if a key is specified, use that, else use the default, unless there are many
-if [[ -n "${key}" ]]; then
- #validate key
- keystatus=$(gpg --list-keys | grep ${key} | awk '{print $1}')
- if [ "${keystatus}" != "pub" ]; then
- echo ""
- echo "Could not find public key with label \"${key}\""
- echo ""
- echo "Available keys from: "
- gpg --list-keys | grep --invert-match '^sub'
- exit 1
- fi
-
- key_param="-Dgpg.keyname=${key}"
-elif [ ${key_count} -gt 1 ]; then
- echo ""
- echo "You are attempting to deploy a maven release but have more than one GPG"
- echo "signing key and did not specify which one you wish to sign with."
- echo ""
- echo "usage $0 [--signing-key <ssl-key>] [<maven params> ...]"
- echo ""
- echo -n "Available keys from: "
- gpg --list-keys | grep --invert-match '^sub'
- exit 1;
-fi
-
-mvn ${params} clean site:jar -P sonatype-oss-release ${key_param} deploy