aboutsummaryrefslogtreecommitdiff
path: root/value/src/test/java/com/google
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-08 02:01:35 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-08 02:01:35 +0000
commit529fadac881c901379b71de78522c45d78b1b292 (patch)
treee7dfe5daeab98b225bb9f472e43ea319259f4e73 /value/src/test/java/com/google
parent65a3186e65e87308d442222838c4bc5f1a0deb77 (diff)
parent02fc1d59868bdded8cd1605983d579b2bf75e3e0 (diff)
downloadauto-529fadac881c901379b71de78522c45d78b1b292.tar.gz
Change-Id: Ia497db4441b97eacdee6c8ff77ab0d0ac6bdd96e
Diffstat (limited to 'value/src/test/java/com/google')
-rw-r--r--value/src/test/java/com/google/auto/value/extension/memoized/MemoizedMethodSubject.java5
-rw-r--r--value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java56
-rw-r--r--value/src/test/java/com/google/auto/value/extension/serializable/processor/SerializableAutoValueExtensionTest.java34
-rw-r--r--value/src/test/java/com/google/auto/value/extension/serializable/serializer/utils/FakeSerializerFactory.java9
-rw-r--r--value/src/test/java/com/google/auto/value/extension/toprettystring/ToPrettyStringTest.java961
-rw-r--r--value/src/test/java/com/google/auto/value/extension/toprettystring/ToPrettyStringValidatorTest.java240
-rw-r--r--value/src/test/java/com/google/auto/value/processor/AutoAnnotationCompilationTest.java28
-rw-r--r--value/src/test/java/com/google/auto/value/processor/AutoAnnotationErrorsTest.java47
-rw-r--r--value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java875
-rw-r--r--value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java22
-rw-r--r--value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java187
-rw-r--r--value/src/test/java/com/google/auto/value/processor/ExtensionTest.java320
-rw-r--r--value/src/test/java/com/google/auto/value/processor/GeneratedDoesNotExistTest.java16
-rw-r--r--value/src/test/java/com/google/auto/value/processor/IncrementalExtensionTest.java26
-rw-r--r--value/src/test/java/com/google/auto/value/processor/NullablesTest.java179
-rw-r--r--value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java63
-rw-r--r--value/src/test/java/com/google/auto/value/processor/PropertyNamesTest.java18
-rw-r--r--value/src/test/java/com/google/auto/value/processor/ReformatterTest.java69
-rw-r--r--value/src/test/java/com/google/auto/value/processor/SimpleServiceLoaderTest.java31
-rw-r--r--value/src/test/java/com/google/auto/value/processor/SimplifyWithAnnotationsTest.java3
-rw-r--r--value/src/test/java/com/google/auto/value/processor/TypeEncoderTest.java3
-rw-r--r--value/src/test/java/com/google/auto/value/processor/TypeVariablesTest.java20
22 files changed, 2905 insertions, 307 deletions
diff --git a/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedMethodSubject.java b/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedMethodSubject.java
index 18c77368..5d1462d0 100644
--- a/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedMethodSubject.java
+++ b/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedMethodSubject.java
@@ -51,9 +51,6 @@ final class MemoizedMethodSubject extends Subject {
javac()
.withProcessors(new AutoValueProcessor(ImmutableList.of(new MemoizeExtension())))
.compile(file);
- assertThat(compilation)
- .hadErrorContaining(error)
- .inFile(file)
- .onLineContaining(actual);
+ assertThat(compilation).hadErrorContaining(error).inFile(file).onLineContaining(actual);
}
}
diff --git a/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java b/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java
index 7bd61ac7..5beb686b 100644
--- a/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java
+++ b/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java
@@ -22,6 +22,8 @@ import com.google.auto.value.AutoValue;
import com.google.auto.value.AutoValue.CopyAnnotations;
import com.google.auto.value.extension.memoized.MemoizedTest.HashCodeEqualsOptimization.EqualsCounter;
import com.google.common.collect.ImmutableList;
+import com.google.errorprone.annotations.Immutable;
+import com.google.errorprone.annotations.ImmutableTypeParameter;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@@ -123,7 +125,9 @@ public class MemoizedTest {
@org.checkerframework.checker.nullness.qual.Nullable
String nullableWithTypeAnnotation() {
nullableWithTypeAnnotationCount++;
- return "nullable derived " + stringWithTypeAnnotation() + " "
+ return "nullable derived "
+ + stringWithTypeAnnotation()
+ + " "
+ nullableWithTypeAnnotationCount;
}
@@ -234,8 +238,9 @@ public class MemoizedTest {
@Before
public void setUp() {
- value = new AutoValue_MemoizedTest_Value(
- "string", "stringWithTypeAnnotation", new HashCodeAndToStringCounter());
+ value =
+ new AutoValue_MemoizedTest_Value(
+ "string", "stringWithTypeAnnotation", new HashCodeAndToStringCounter());
listValue = new AutoValue_MemoizedTest_ListValue<Integer, String>(0, "hello");
}
@@ -375,8 +380,9 @@ public class MemoizedTest {
Method nullable =
AutoValue_MemoizedTest_Value.class.getDeclaredMethod("nullableWithTypeAnnotation");
AnnotatedType returnType = nullable.getAnnotatedReturnType();
- assertThat(returnType.isAnnotationPresent(
- org.checkerframework.checker.nullness.qual.Nullable.class))
+ assertThat(
+ returnType.isAnnotationPresent(
+ org.checkerframework.checker.nullness.qual.Nullable.class))
.isTrue();
}
@@ -387,11 +393,13 @@ public class MemoizedTest {
// [1] @org.checkerframework.checker.nullness.qual.Nullable String stringWithTypeAnnotation,
// [2] HashCodeAndToStringCounter counter
// We don't currently copy @javax.annotation.Nullable because it is not a TYPE_USE annotation.
- Constructor<?> constructor = AutoValue_MemoizedTest_Value.class.getDeclaredConstructor(
- String.class, String.class, HashCodeAndToStringCounter.class);
+ Constructor<?> constructor =
+ AutoValue_MemoizedTest_Value.class.getDeclaredConstructor(
+ String.class, String.class, HashCodeAndToStringCounter.class);
AnnotatedType paramType = constructor.getAnnotatedParameterTypes()[1];
- assertThat(paramType.isAnnotationPresent(
- org.checkerframework.checker.nullness.qual.Nullable.class))
+ assertThat(
+ paramType.isAnnotationPresent(
+ org.checkerframework.checker.nullness.qual.Nullable.class))
.isTrue();
}
@@ -448,8 +456,8 @@ public class MemoizedTest {
assertThat(memoizedHashCodeAndFinalEqualsMethod.equals(second)).isTrue();
assertThat(memoizedHashCodeAndFinalEqualsMethod.hashCodeCount).isEqualTo(0);
- memoizedHashCodeAndFinalEqualsMethod.hashCode();
- memoizedHashCodeAndFinalEqualsMethod.hashCode();
+ int unused1 = memoizedHashCodeAndFinalEqualsMethod.hashCode();
+ int unused2 = memoizedHashCodeAndFinalEqualsMethod.hashCode();
assertThat(memoizedHashCodeAndFinalEqualsMethod.hashCodeCount).isEqualTo(1);
}
@@ -465,8 +473,7 @@ public class MemoizedTest {
@AutoValue
abstract static class ResourceUriPath<InputT> extends AbstractTypePath<InputT, ResourceUri> {
- static <InputT> ResourceUriPath<InputT> create(
- TypeEdgeIterable<InputT, ResourceUri> edges) {
+ static <InputT> ResourceUriPath<InputT> create(TypeEdgeIterable<InputT, ResourceUri> edges) {
return new AutoValue_MemoizedTest_ResourceUriPath<>(edges);
}
@@ -482,4 +489,27 @@ public class MemoizedTest {
ResourceUriPath.create(new TypeEdgeIterable<String, ResourceUri>() {});
assertThat(path.edges()).isNotNull();
}
+
+ @Immutable
+ @AutoValue
+ abstract static class Unchanging<@ImmutableTypeParameter T> {
+ abstract T value();
+
+ @Override
+ @Memoized
+ public abstract int hashCode();
+
+ static <@ImmutableTypeParameter T> Unchanging<T> of(T value) {
+ return new AutoValue_MemoizedTest_Unchanging<T>(value);
+ }
+ }
+
+ @Test
+ public void copiedTypeAnnotations() {
+ for (Class<?> c = Unchanging.of("foo").getClass(); c != Object.class; c = c.getSuperclass()) {
+ assertThat(c.getTypeParameters()).hasLength(1);
+ assertThat(c.getTypeParameters()[0].isAnnotationPresent(ImmutableTypeParameter.class))
+ .isTrue();
+ }
+ }
}
diff --git a/value/src/test/java/com/google/auto/value/extension/serializable/processor/SerializableAutoValueExtensionTest.java b/value/src/test/java/com/google/auto/value/extension/serializable/processor/SerializableAutoValueExtensionTest.java
index 1879d1e5..064406da 100644
--- a/value/src/test/java/com/google/auto/value/extension/serializable/processor/SerializableAutoValueExtensionTest.java
+++ b/value/src/test/java/com/google/auto/value/extension/serializable/processor/SerializableAutoValueExtensionTest.java
@@ -415,4 +415,38 @@ public final class SerializableAutoValueExtensionTest {
assertThat(actualAutoValue).isEqualTo(autoValue);
}
+
+ /**
+ * Type that may result in nested lambdas in the generated code. Including this allows us to
+ * verify that we handle those correctly, in particular not reusing a lambda parameter name in
+ * another lambda nested inside the first one.
+ */
+ @SerializableAutoValue
+ @AutoValue
+ abstract static class ComplexType implements Serializable {
+ abstract ImmutableMap<String, ImmutableMap<String, Optional<String>>> a();
+
+ static ComplexType.Builder builder() {
+ return new AutoValue_SerializableAutoValueExtensionTest_ComplexType.Builder();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract ComplexType.Builder setA(
+ ImmutableMap<String, ImmutableMap<String, Optional<String>>> a);
+
+ abstract ComplexType build();
+ }
+ }
+
+ @Test
+ public void complexType() {
+ ImmutableMap<String, ImmutableMap<String, Optional<String>>> map =
+ ImmutableMap.of("foo", ImmutableMap.of("bar", Optional.of("baz")));
+ ComplexType complexType = ComplexType.builder().setA(map).build();
+
+ ComplexType reserialized = SerializableTester.reserialize(complexType);
+
+ assertThat(reserialized).isEqualTo(complexType);
+ }
}
diff --git a/value/src/test/java/com/google/auto/value/extension/serializable/serializer/utils/FakeSerializerFactory.java b/value/src/test/java/com/google/auto/value/extension/serializable/serializer/utils/FakeSerializerFactory.java
index 388977fb..162d7cf6 100644
--- a/value/src/test/java/com/google/auto/value/extension/serializable/serializer/utils/FakeSerializerFactory.java
+++ b/value/src/test/java/com/google/auto/value/extension/serializable/serializer/utils/FakeSerializerFactory.java
@@ -42,6 +42,15 @@ public final class FakeSerializerFactory implements SerializerFactory {
return new FakeIdentitySerializer(type, isIdentity);
}
+ // This doesn't follow the contract, and always returns the same string for a given prefix.
+ // That means it will be wrong if two identifiers with the same prefix are in the same scope in
+ // the generated code, but for our purposes in this fake it is OK, and means we don't have to
+ // hardwire knowledge of the uniqueness algorithm into golden text in tests.
+ @Override
+ public CodeBlock newIdentifier(String prefix) {
+ return CodeBlock.of("$L$$", prefix);
+ }
+
private static class FakeIdentitySerializer implements Serializer {
private final TypeMirror typeMirror;
diff --git a/value/src/test/java/com/google/auto/value/extension/toprettystring/ToPrettyStringTest.java b/value/src/test/java/com/google/auto/value/extension/toprettystring/ToPrettyStringTest.java
new file mode 100644
index 00000000..f5197472
--- /dev/null
+++ b/value/src/test/java/com/google/auto/value/extension/toprettystring/ToPrettyStringTest.java
@@ -0,0 +1,961 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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.auto.value.extension.toprettystring;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.toprettystring.ToPrettyStringTest.CollectionSubtypesWithFixedTypeParameters.StringList;
+import com.google.auto.value.extension.toprettystring.ToPrettyStringTest.CollectionSubtypesWithFixedTypeParameters.StringMap;
+import com.google.auto.value.extension.toprettystring.ToPrettyStringTest.PropertyHasToPrettyString.HasToPrettyString;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.primitives.ImmutableIntArray;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SuppressWarnings("AutoValueImmutableFields")
+@RunWith(JUnit4.class)
+public class ToPrettyStringTest {
+ @AutoValue
+ abstract static class Primitives {
+ abstract int i();
+
+ abstract long l();
+
+ abstract byte b();
+
+ abstract short s();
+
+ abstract char c();
+
+ abstract float f();
+
+ abstract double d();
+
+ abstract boolean bool();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void primitives() {
+ Primitives valueType =
+ new AutoValue_ToPrettyStringTest_Primitives(
+ 1, 2L, (byte) 3, (short) 4, 'C', 6.6f, 7.7, false);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "Primitives {"
+ + "\n i = 1,"
+ + "\n l = 2,"
+ + "\n b = 3,"
+ + "\n s = 4,"
+ + "\n c = C,"
+ + "\n f = 6.6,"
+ + "\n d = 7.7,"
+ + "\n bool = false,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class PrimitiveArray {
+ @Nullable
+ @SuppressWarnings("mutable")
+ abstract long[] longs();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void primitiveArray() {
+ PrimitiveArray valueType =
+ new AutoValue_ToPrettyStringTest_PrimitiveArray(new long[] {1L, 2L, 10L, 200L});
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrimitiveArray {"
+ + "\n longs = ["
+ + "\n 1,"
+ + "\n 2,"
+ + "\n 10,"
+ + "\n 200,"
+ + "\n ],"
+ + "\n}");
+ }
+
+ @Test
+ public void primitiveArray_empty() {
+ PrimitiveArray valueType = new AutoValue_ToPrettyStringTest_PrimitiveArray(new long[0]);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrimitiveArray {" // force newline
+ + "\n longs = [],"
+ + "\n}");
+ }
+
+ @Test
+ public void primitiveArray_null() {
+ PrimitiveArray valueType = new AutoValue_ToPrettyStringTest_PrimitiveArray(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrimitiveArray {" // force newline
+ + "\n longs = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class PrettyCollection {
+ @Nullable
+ abstract Collection<Object> collection();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void prettyCollection() {
+ PrettyCollection valueType =
+ new AutoValue_ToPrettyStringTest_PrettyCollection(ImmutableList.of("hello", "world"));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyCollection {"
+ + "\n collection = ["
+ + "\n hello,"
+ + "\n world,"
+ + "\n ],"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyCollection_elementsWithNewlines() {
+ PrettyCollection valueType =
+ new AutoValue_ToPrettyStringTest_PrettyCollection(
+ ImmutableList.of("hello\nworld\nnewline"));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyCollection {"
+ + "\n collection = ["
+ + "\n hello"
+ + "\n world"
+ + "\n newline,"
+ + "\n ],"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyCollection_empty() {
+ PrettyCollection valueType =
+ new AutoValue_ToPrettyStringTest_PrettyCollection(ImmutableList.of());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyCollection {" // force newline
+ + "\n collection = [],"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyCollection_null() {
+ PrettyCollection valueType = new AutoValue_ToPrettyStringTest_PrettyCollection(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyCollection {" // force newline
+ + "\n collection = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class NestedCollection {
+ @Nullable
+ abstract Collection<Collection<Object>> nestedCollection();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void nestedCollection() {
+ NestedCollection valueType =
+ new AutoValue_ToPrettyStringTest_NestedCollection(
+ Arrays.asList(
+ ImmutableList.of("hello", "world"),
+ ImmutableList.of("hello2", "world2"),
+ null,
+ Arrays.asList("not null", null)));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "NestedCollection {"
+ + "\n nestedCollection = ["
+ + "\n ["
+ + "\n hello,"
+ + "\n world,"
+ + "\n ],"
+ + "\n ["
+ + "\n hello2,"
+ + "\n world2,"
+ + "\n ],"
+ + "\n null,"
+ + "\n ["
+ + "\n not null,"
+ + "\n null,"
+ + "\n ],"
+ + "\n ],"
+ + "\n}");
+ }
+
+ @Test
+ public void nestedCollection_elementsWithNewlines() {
+ NestedCollection valueType =
+ new AutoValue_ToPrettyStringTest_NestedCollection(
+ ImmutableList.of(
+ ImmutableList.of((Object) "hello\nworld\nnewline", "hello2\nworld2\nnewline2")));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "NestedCollection {"
+ + "\n nestedCollection = ["
+ + "\n ["
+ + "\n hello"
+ + "\n world"
+ + "\n newline,"
+ + "\n hello2"
+ + "\n world2"
+ + "\n newline2,"
+ + "\n ],"
+ + "\n ],"
+ + "\n}");
+ }
+
+ @Test
+ public void nestedCollection_empty() {
+ NestedCollection valueType =
+ new AutoValue_ToPrettyStringTest_NestedCollection(ImmutableList.of());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "NestedCollection {" // force newline
+ + "\n nestedCollection = [],"
+ + "\n}");
+ }
+
+ @Test
+ public void nestedCollection_nestedEmpty() {
+ NestedCollection valueType =
+ new AutoValue_ToPrettyStringTest_NestedCollection(
+ ImmutableList.of(ImmutableList.of(), ImmutableList.of()));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "NestedCollection {"
+ + "\n nestedCollection = ["
+ + "\n [],"
+ + "\n [],"
+ + "\n ],"
+ + "\n}");
+ }
+
+ @Test
+ public void nestedCollection_null() {
+ NestedCollection valueType = new AutoValue_ToPrettyStringTest_NestedCollection(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "NestedCollection {" // force newline
+ + "\n nestedCollection = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class ImmutablePrimitiveArray {
+ @Nullable
+ abstract ImmutableIntArray immutableIntArray();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void immutablePrimitiveArray() {
+ ImmutablePrimitiveArray valueType =
+ new AutoValue_ToPrettyStringTest_ImmutablePrimitiveArray(ImmutableIntArray.of(1, 2));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "ImmutablePrimitiveArray {"
+ + "\n immutableIntArray = ["
+ + "\n 1,"
+ + "\n 2,"
+ + "\n ],"
+ + "\n}");
+ }
+
+ @Test
+ public void immutablePrimitiveArray_empty() {
+ ImmutablePrimitiveArray valueType =
+ new AutoValue_ToPrettyStringTest_ImmutablePrimitiveArray(ImmutableIntArray.of());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "ImmutablePrimitiveArray {" // force newline
+ + "\n immutableIntArray = [],"
+ + "\n}");
+ }
+
+ @Test
+ public void immutablePrimitiveArray_null() {
+ ImmutablePrimitiveArray valueType =
+ new AutoValue_ToPrettyStringTest_ImmutablePrimitiveArray(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "ImmutablePrimitiveArray {" // force newline
+ + "\n immutableIntArray = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class PrettyMap {
+ @Nullable
+ abstract Map<Object, Object> map();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void prettyMap() {
+ PrettyMap valueType = new AutoValue_ToPrettyStringTest_PrettyMap(ImmutableMap.of(1, 2));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyMap {" // force newline
+ + "\n map = {"
+ + "\n 1: 2,"
+ + "\n },"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyMap_keysAndValuesWithNewlines() {
+ PrettyMap valueType =
+ new AutoValue_ToPrettyStringTest_PrettyMap(
+ ImmutableMap.of(
+ "key1\nnewline", "value1\nnewline", "key2\nnewline", "value2\nnewline"));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyMap {"
+ + "\n map = {"
+ + "\n key1"
+ + "\n newline: value1"
+ + "\n newline,"
+ + "\n key2"
+ + "\n newline: value2"
+ + "\n newline,"
+ + "\n },"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyMap_empty() {
+ PrettyMap valueType = new AutoValue_ToPrettyStringTest_PrettyMap(ImmutableMap.of());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyMap {" // force newline
+ + "\n map = {},"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyMap_null() {
+ PrettyMap valueType = new AutoValue_ToPrettyStringTest_PrettyMap(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyMap {" // force newline
+ + "\n map = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class MapOfMaps {
+ @Nullable
+ abstract Map<Map<Object, Object>, Map<Object, Object>> mapOfMaps();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ private static <K, V> Map<K, V> mapWithNulls(K k, V v) {
+ Map<K, V> map = new LinkedHashMap<>();
+ map.put(k, v);
+ return map;
+ }
+
+ @Test
+ public void mapOfMaps() {
+ Map<Map<Object, Object>, Map<Object, Object>> mapOfMaps = new LinkedHashMap<>();
+ mapOfMaps.put(ImmutableMap.of("k1_k", "k1_v"), ImmutableMap.of("v1_k", "v1_v"));
+ mapOfMaps.put(ImmutableMap.of("k2_k", "k2_v"), ImmutableMap.of("v2_k", "v2_v"));
+ mapOfMaps.put(mapWithNulls("keyForNullValue", null), mapWithNulls(null, "valueForNullKey"));
+ mapOfMaps.put(null, ImmutableMap.of("nullKeyKey", "nullKeyValue"));
+ mapOfMaps.put(ImmutableMap.of("nullValueKey", "nullValueValue"), null);
+ mapOfMaps.put(
+ ImmutableMap.of("keyForMapOfNullsKey", "keyForMapOfNullsValue"), mapWithNulls(null, null));
+ MapOfMaps valueType = new AutoValue_ToPrettyStringTest_MapOfMaps(mapOfMaps);
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "MapOfMaps {"
+ + "\n mapOfMaps = {"
+ + "\n {"
+ + "\n k1_k: k1_v,"
+ + "\n }: {"
+ + "\n v1_k: v1_v,"
+ + "\n },"
+ + "\n {"
+ + "\n k2_k: k2_v,"
+ + "\n }: {"
+ + "\n v2_k: v2_v,"
+ + "\n },"
+ + "\n {"
+ + "\n keyForNullValue: null,"
+ + "\n }: {"
+ + "\n null: valueForNullKey,"
+ + "\n },"
+ + "\n null: {"
+ + "\n nullKeyKey: nullKeyValue,"
+ + "\n },"
+ + "\n {"
+ + "\n nullValueKey: nullValueValue,"
+ + "\n }: null,"
+ + "\n {"
+ + "\n keyForMapOfNullsKey: keyForMapOfNullsValue,"
+ + "\n }: {"
+ + "\n null: null,"
+ + "\n },"
+ + "\n },"
+ + "\n}");
+ }
+
+ @Test
+ public void mapOfMaps_elementsWithNewlines() {
+ MapOfMaps valueType =
+ new AutoValue_ToPrettyStringTest_MapOfMaps(
+ ImmutableMap.of(
+ ImmutableMap.of((Object) "k_k\nnewline", (Object) "k_v\nnewline"),
+ ImmutableMap.of((Object) "v_k\nnewline", (Object) "v_v\nnewline")));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "MapOfMaps {"
+ + "\n mapOfMaps = {"
+ + "\n {"
+ + "\n k_k"
+ + "\n newline: k_v"
+ + "\n newline,"
+ + "\n }: {"
+ + "\n v_k"
+ + "\n newline: v_v"
+ + "\n newline,"
+ + "\n },"
+ + "\n },"
+ + "\n}");
+ }
+
+ @Test
+ public void mapOfMaps_empty() {
+ MapOfMaps valueType = new AutoValue_ToPrettyStringTest_MapOfMaps(ImmutableMap.of());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "MapOfMaps {" // force newline
+ + "\n mapOfMaps = {},"
+ + "\n}");
+ }
+
+ @Test
+ public void mapOfMaps_nestedEmpty() {
+ MapOfMaps valueType =
+ new AutoValue_ToPrettyStringTest_MapOfMaps(
+ ImmutableMap.of(ImmutableMap.of(), ImmutableMap.of()));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "MapOfMaps {" // force newline
+ + "\n mapOfMaps = {"
+ + "\n {}: {},"
+ + "\n },"
+ + "\n}");
+ }
+
+ @Test
+ public void mapOfMaps_null() {
+ MapOfMaps valueType = new AutoValue_ToPrettyStringTest_MapOfMaps(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "MapOfMaps {" // force newline
+ + "\n mapOfMaps = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class PrettyMultimap {
+ @Nullable
+ abstract Multimap<Object, Object> multimap();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void prettyMultimap() {
+ PrettyMultimap valueType =
+ new AutoValue_ToPrettyStringTest_PrettyMultimap(
+ ImmutableMultimap.builder().putAll("k", "v1", "v2").build());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyMultimap {" // force newline
+ + "\n multimap = {"
+ + "\n k: ["
+ + "\n v1,"
+ + "\n v2,"
+ + "\n ],"
+ + "\n },"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyMultimap_keysAndValuesWithNewlines() {
+ PrettyMultimap valueType =
+ new AutoValue_ToPrettyStringTest_PrettyMultimap(
+ ImmutableMultimap.builder()
+ .putAll("key\nnewline", "value1\nnewline", "value2\nnewline")
+ .build());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyMultimap {"
+ + "\n multimap = {"
+ + "\n key"
+ + "\n newline: ["
+ + "\n value1"
+ + "\n newline,"
+ + "\n value2"
+ + "\n newline,"
+ + "\n ],"
+ + "\n },"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyMultimap_empty() {
+ PrettyMultimap valueType =
+ new AutoValue_ToPrettyStringTest_PrettyMultimap(ImmutableMultimap.of());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyMultimap {" // force newline
+ + "\n multimap = {},"
+ + "\n}");
+ }
+
+ @Test
+ public void prettyMultimap_null() {
+ PrettyMultimap valueType = new AutoValue_ToPrettyStringTest_PrettyMultimap(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PrettyMultimap {" // force newline
+ + "\n multimap = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class JavaOptional {
+ @Nullable
+ abstract java.util.Optional<Object> optional();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void javaOptional_present() {
+ JavaOptional valueType =
+ new AutoValue_ToPrettyStringTest_JavaOptional(java.util.Optional.of("hello, world"));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "JavaOptional {" // force newline
+ + "\n optional = hello, world,"
+ + "\n}");
+ }
+
+ @Test
+ public void javaOptional_empty() {
+ JavaOptional valueType =
+ new AutoValue_ToPrettyStringTest_JavaOptional(java.util.Optional.empty());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "JavaOptional {" // force newline
+ + "\n optional = <empty>,"
+ + "\n}");
+ }
+
+ @Test
+ public void javaOptional_valueWithNewlines() {
+ JavaOptional valueType =
+ new AutoValue_ToPrettyStringTest_JavaOptional(
+ java.util.Optional.of("optional\nwith\nnewline"));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "JavaOptional {" // force newline
+ + "\n optional = optional"
+ + "\n with"
+ + "\n newline,"
+ + "\n}");
+ }
+
+ @Test
+ public void javaOptional_null() {
+ @SuppressWarnings("NullOptional")
+ JavaOptional valueType = new AutoValue_ToPrettyStringTest_JavaOptional(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "JavaOptional {" // force newline
+ + "\n optional = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class GuavaOptional {
+ @Nullable
+ abstract com.google.common.base.Optional<Object> optional();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void guavaOptional_present() {
+ GuavaOptional valueType =
+ new AutoValue_ToPrettyStringTest_GuavaOptional(
+ com.google.common.base.Optional.of("hello, world"));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "GuavaOptional {" // force newline
+ + "\n optional = hello, world,"
+ + "\n}");
+ }
+
+ @Test
+ public void guavaOptional_absent() {
+ GuavaOptional valueType =
+ new AutoValue_ToPrettyStringTest_GuavaOptional(com.google.common.base.Optional.absent());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "GuavaOptional {" // force newline
+ + "\n optional = <absent>,"
+ + "\n}");
+ }
+
+ @Test
+ public void guavaOptional_valueWithNewlines() {
+ GuavaOptional valueType =
+ new AutoValue_ToPrettyStringTest_GuavaOptional(
+ com.google.common.base.Optional.of("optional\nwith\nnewline"));
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "GuavaOptional {" // force newline
+ + "\n optional = optional"
+ + "\n with"
+ + "\n newline,"
+ + "\n}");
+ }
+
+ @Test
+ public void guavaOptional_null() {
+ @SuppressWarnings("NullOptional")
+ GuavaOptional valueType = new AutoValue_ToPrettyStringTest_GuavaOptional(null);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "GuavaOptional {" // force newline
+ + "\n optional = null,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class NestAllTheThings {
+ @Nullable
+ abstract com.google.common.base.Optional<
+ java.util.Optional<
+ List< // open list
+ Map<ImmutableIntArray, Multimap<int[][], Object>>
+ // close list
+ >>>
+ value();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void nestAllTheThings() {
+ NestAllTheThings valueType =
+ new AutoValue_ToPrettyStringTest_NestAllTheThings(
+ com.google.common.base.Optional.of(
+ java.util.Optional.of(
+ ImmutableList.of(
+ ImmutableMap.of(
+ ImmutableIntArray.of(-1, -2, -3),
+ ImmutableMultimap.of(
+ new int[][] {{1, 2}, {3, 4, 5}, {}}, "value\nwith\nnewline"))))));
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "NestAllTheThings {"
+ + "\n value = ["
+ + "\n {"
+ + "\n ["
+ + "\n -1,"
+ + "\n -2,"
+ + "\n -3,"
+ + "\n ]: {"
+ + "\n ["
+ + "\n ["
+ + "\n 1,"
+ + "\n 2,"
+ + "\n ],"
+ + "\n ["
+ + "\n 3,"
+ + "\n 4,"
+ + "\n 5,"
+ + "\n ],"
+ + "\n [],"
+ + "\n ]: ["
+ + "\n value"
+ + "\n with"
+ + "\n newline,"
+ + "\n ],"
+ + "\n },"
+ + "\n },"
+ + "\n ],"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class WithCustomName {
+ abstract int i();
+
+ @ToPrettyString
+ abstract String customName();
+ }
+
+ @Test
+ public void withCustomName() {
+ WithCustomName valueType = new AutoValue_ToPrettyStringTest_WithCustomName(1);
+
+ assertThat(valueType.customName())
+ .isEqualTo(
+ "WithCustomName {" // force newline
+ + "\n i = 1,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class OverridesToString {
+ abstract int i();
+
+ @ToPrettyString
+ @Override
+ public abstract String toString();
+ }
+
+ @Test
+ public void overridesToString() {
+ OverridesToString valueType = new AutoValue_ToPrettyStringTest_OverridesToString(1);
+
+ assertThat(valueType.toString())
+ .isEqualTo(
+ "OverridesToString {" // force newline
+ + "\n i = 1,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class PropertyHasToPrettyString {
+ static class HasToPrettyString<A> {
+ @Override
+ public String toString() {
+ throw new AssertionError();
+ }
+
+ @ToPrettyString
+ String toPrettyString() {
+ return "custom\n@ToPrettyString\nmethod";
+ }
+ }
+
+ static class HasInheritedToPrettyString extends HasToPrettyString<String> {}
+
+ interface HasToPrettyStringInInterface {
+ @ToPrettyString
+ default String toPrettyString() {
+ return "custom\n@ToPrettyString\nmethod\ninterface";
+ }
+ }
+
+ static class HasToPrettyStringFromSuperInterface implements HasToPrettyStringInInterface {}
+
+ abstract HasToPrettyString<String> parameterizedWithString();
+
+ abstract HasToPrettyString<Void> parameterizedWithVoid();
+
+ abstract HasInheritedToPrettyString superclass();
+
+ abstract HasToPrettyStringFromSuperInterface superinterface();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void propertyHasToPrettyString() {
+ PropertyHasToPrettyString valueType =
+ new AutoValue_ToPrettyStringTest_PropertyHasToPrettyString(
+ new PropertyHasToPrettyString.HasToPrettyString<>(),
+ new PropertyHasToPrettyString.HasToPrettyString<>(),
+ new PropertyHasToPrettyString.HasInheritedToPrettyString(),
+ new PropertyHasToPrettyString.HasToPrettyStringFromSuperInterface());
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "PropertyHasToPrettyString {"
+ + "\n parameterizedWithString = custom"
+ + "\n @ToPrettyString"
+ + "\n method,"
+ + "\n parameterizedWithVoid = custom"
+ + "\n @ToPrettyString"
+ + "\n method,"
+ + "\n superclass = custom"
+ + "\n @ToPrettyString"
+ + "\n method,"
+ + "\n superinterface = custom"
+ + "\n @ToPrettyString"
+ + "\n method"
+ + "\n interface,"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class CollectionSubtypesWithFixedTypeParameters {
+ static class StringList extends ArrayList<String> {}
+
+ static class StringMap extends LinkedHashMap<String, String> {}
+
+ abstract StringList list();
+
+ abstract StringMap map();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void fixedTypeParameters() {
+ StringList stringList = new StringList();
+ stringList.addAll(ImmutableList.of("a", "b", "c"));
+ StringMap stringMap = new StringMap();
+ stringMap.putAll(ImmutableMap.of("A", "a", "B", "b"));
+ CollectionSubtypesWithFixedTypeParameters valueType =
+ new AutoValue_ToPrettyStringTest_CollectionSubtypesWithFixedTypeParameters(
+ stringList, stringMap);
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "CollectionSubtypesWithFixedTypeParameters {"
+ + "\n list = ["
+ + "\n a,"
+ + "\n b,"
+ + "\n c,"
+ + "\n ],"
+ + "\n map = {"
+ + "\n A: a,"
+ + "\n B: b,"
+ + "\n },"
+ + "\n}");
+ }
+
+ @AutoValue
+ abstract static class JavaBeans {
+ abstract int getInt();
+
+ abstract boolean isBoolean();
+
+ abstract String getNotAJavaIdentifier();
+
+ @ToPrettyString
+ abstract String toPrettyString();
+ }
+
+ @Test
+ public void javaBeans() {
+ JavaBeans valueType = new AutoValue_ToPrettyStringTest_JavaBeans(4, false, "not");
+
+ assertThat(valueType.toPrettyString())
+ .isEqualTo(
+ "JavaBeans {"
+ + "\n int = 4,"
+ + "\n boolean = false,"
+ + "\n notAJavaIdentifier = not,"
+ + "\n}");
+
+ // Check to make sure that we use the same property names that AutoValue does. This is mostly
+ // defensive, since in some scenarios AutoValue considers the property names of a java bean as
+ // having the prefix removed.
+ assertThat(valueType.toString())
+ .isEqualTo("JavaBeans{int=4, boolean=false, notAJavaIdentifier=not}");
+ }
+}
diff --git a/value/src/test/java/com/google/auto/value/extension/toprettystring/ToPrettyStringValidatorTest.java b/value/src/test/java/com/google/auto/value/extension/toprettystring/ToPrettyStringValidatorTest.java
new file mode 100644
index 00000000..6c51be1d
--- /dev/null
+++ b/value/src/test/java/com/google/auto/value/extension/toprettystring/ToPrettyStringValidatorTest.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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.auto.value.extension.toprettystring;
+
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static com.google.testing.compile.Compiler.javac;
+
+import com.google.auto.value.extension.toprettystring.processor.ToPrettyStringValidator;
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ToPrettyStringValidatorTest {
+ @Test
+ public void cannotBeStatic() {
+ JavaFileObject file =
+ JavaFileObjects.forSourceLines(
+ "test.Test",
+ "package test;",
+ "",
+ "import com.google.auto.value.extension.toprettystring.ToPrettyString;",
+ "",
+ "class Test {",
+ " @ToPrettyString",
+ " static String toPretty() {",
+ " return new String();",
+ " }",
+ "}",
+ "");
+ Compilation compilation = compile(file);
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation)
+ .hadErrorContaining("must be instance methods")
+ .inFile(file)
+ .onLineContaining("static String toPretty()");
+ }
+
+ @Test
+ public void mustReturnString() {
+ JavaFileObject file =
+ JavaFileObjects.forSourceLines(
+ "test.Test",
+ "package test;",
+ "",
+ "import com.google.auto.value.extension.toprettystring.ToPrettyString;",
+ "",
+ "class Test {",
+ " @ToPrettyString",
+ " CharSequence toPretty() {",
+ " return new String();",
+ " }",
+ "}",
+ "");
+ Compilation compilation = compile(file);
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation)
+ .hadErrorContaining("must return String")
+ .inFile(file)
+ .onLineContaining("CharSequence toPretty()");
+ }
+
+ @Test
+ public void noParameters() {
+ JavaFileObject file =
+ JavaFileObjects.forSourceLines(
+ "test.Test",
+ "package test;",
+ "",
+ "import com.google.auto.value.extension.toprettystring.ToPrettyString;",
+ "",
+ "class Test {",
+ " @ToPrettyString",
+ " String toPretty(String value) {",
+ " return value;",
+ " }",
+ "}",
+ "");
+ Compilation compilation = compile(file);
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation)
+ .hadErrorContaining("cannot have parameters")
+ .inFile(file)
+ .onLineContaining("String toPretty(String value)");
+ }
+
+ @Test
+ public void onlyOneToPrettyStringMethod_sameClass() {
+ JavaFileObject file =
+ JavaFileObjects.forSourceLines(
+ "test.Test",
+ "package test;",
+ "",
+ "import com.google.auto.value.extension.toprettystring.ToPrettyString;",
+ "",
+ "class Test {",
+ " @ToPrettyString",
+ " String toPretty1() {",
+ " return new String();",
+ " }",
+ "",
+ " @ToPrettyString",
+ " String toPretty2() {",
+ " return new String();",
+ " }",
+ "}",
+ "");
+ Compilation compilation = compile(file);
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation)
+ .hadErrorContaining(
+ error(
+ "test.Test has multiple @ToPrettyString methods:",
+ " - test.Test.toPretty1()",
+ " - test.Test.toPretty2()"))
+ .inFile(file)
+ .onLineContaining("class Test");
+ }
+
+ @Test
+ public void onlyOneToPrettyStringMethod_superclass() {
+ JavaFileObject superclass =
+ JavaFileObjects.forSourceLines(
+ "test.Superclass",
+ "package test;",
+ "",
+ "import com.google.auto.value.extension.toprettystring.ToPrettyString;",
+ "",
+ "class Superclass {",
+ " @ToPrettyString",
+ " String toPretty1() {",
+ " return new String();",
+ " }",
+ "}",
+ "");
+ JavaFileObject subclass =
+ JavaFileObjects.forSourceLines(
+ "test.Subclass",
+ "package test;",
+ "",
+ "import com.google.auto.value.extension.toprettystring.ToPrettyString;",
+ "",
+ "class Subclass extends Superclass {",
+ " @ToPrettyString",
+ " String toPretty2() {",
+ " return new String();",
+ " }",
+ "}",
+ "");
+ Compilation compilation = compile(superclass, subclass);
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation)
+ .hadErrorContaining(
+ error(
+ "test.Subclass has multiple @ToPrettyString methods:",
+ " - test.Superclass.toPretty1()",
+ " - test.Subclass.toPretty2()"))
+ .inFile(subclass)
+ .onLineContaining("class Subclass");
+ }
+
+ @Test
+ public void onlyOneToPrettyStringMethod_superinterface() {
+ JavaFileObject superinterface =
+ JavaFileObjects.forSourceLines(
+ "test.Superinterface",
+ "package test;",
+ "",
+ "import com.google.auto.value.extension.toprettystring.ToPrettyString;",
+ "",
+ "interface Superinterface {",
+ " @ToPrettyString",
+ " default String toPretty1() {",
+ " return new String();",
+ " }",
+ "}",
+ "");
+ JavaFileObject subclass =
+ JavaFileObjects.forSourceLines(
+ "test.Subclass",
+ "package test;",
+ "",
+ "import com.google.auto.value.extension.toprettystring.ToPrettyString;",
+ "",
+ "class Subclass implements Superinterface {",
+ " @ToPrettyString",
+ " String toPretty2() {",
+ " return new String();",
+ " }",
+ "}",
+ "");
+ Compilation compilation = compile(superinterface, subclass);
+
+ assertThat(compilation).failed();
+ assertThat(compilation).hadErrorCount(1);
+ assertThat(compilation)
+ .hadErrorContaining(
+ error(
+ "test.Subclass has multiple @ToPrettyString methods:",
+ " - test.Superinterface.toPretty1()",
+ " - test.Subclass.toPretty2()"))
+ .inFile(subclass)
+ .onLineContaining("class Subclass");
+ }
+
+ private static Compilation compile(JavaFileObject... javaFileObjects) {
+ return javac().withProcessors(new ToPrettyStringValidator()).compile(javaFileObjects);
+ }
+
+ private static String error(String... lines) {
+ return String.join("\n ", lines);
+ }
+}
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoAnnotationCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoAnnotationCompilationTest.java
index b8a36eac..1f79a074 100644
--- a/value/src/test/java/com/google/auto/value/processor/AutoAnnotationCompilationTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/AutoAnnotationCompilationTest.java
@@ -74,11 +74,13 @@ public class AutoAnnotationCompilationTest {
"",
"import com.example.annotations.MyAnnotation;",
"import com.example.enums.MyEnum;",
+ "import java.io.Serializable;",
GeneratedImport.importGeneratedAnnotationType(),
"",
"@Generated(\"" + AutoAnnotationProcessor.class.getName() + "\")",
"final class AutoAnnotation_AnnotationFactory_newMyAnnotation",
- " implements MyAnnotation {",
+ " implements MyAnnotation, Serializable {",
+ " private static final long serialVersionUID = -7473814294717163169L;",
" private final MyEnum value;",
" private static final int defaultedValue = 23;",
"",
@@ -129,6 +131,7 @@ public class AutoAnnotationCompilationTest {
Compilation compilation =
javac()
.withProcessors(new AutoAnnotationProcessor())
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
.compile(annotationFactoryJavaFile, myAnnotationJavaFile, myEnumJavaFile);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
@@ -157,11 +160,13 @@ public class AutoAnnotationCompilationTest {
JavaFileObject expectedOutput =
JavaFileObjects.forSourceLines(
"AutoAnnotation_AnnotationFactory_newMyAnnotation",
+ "import java.io.Serializable;",
GeneratedImport.importGeneratedAnnotationType(),
"",
"@Generated(\"" + AutoAnnotationProcessor.class.getName() + "\")",
"final class AutoAnnotation_AnnotationFactory_newMyAnnotation",
- " implements MyAnnotation {",
+ " implements MyAnnotation, Serializable {",
+ " private static final long serialVersionUID = 0L;",
" AutoAnnotation_AnnotationFactory_newMyAnnotation() {",
" }",
"",
@@ -191,6 +196,7 @@ public class AutoAnnotationCompilationTest {
Compilation compilation =
javac()
.withProcessors(new AutoAnnotationProcessor())
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
.compile(annotationFactoryJavaFile, myAnnotationJavaFile);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
@@ -237,12 +243,14 @@ public class AutoAnnotationCompilationTest {
"package com.example.factories;",
"",
"import com.example.annotations.MyAnnotation;",
+ "import java.io.Serializable",
"import java.util.Arrays;",
GeneratedImport.importGeneratedAnnotationType(),
"",
"@Generated(\"" + AutoAnnotationProcessor.class.getName() + "\")",
- "final class AutoAnnotation_AnnotationFactory_newMyAnnotation implements MyAnnotation"
- + " {",
+ "final class AutoAnnotation_AnnotationFactory_newMyAnnotation implements MyAnnotation,"
+ + " Serializable {",
+ " private static final long serialVersionUID = -8116050813861599066L;",
" private final int[] value;",
"",
" AutoAnnotation_AnnotationFactory_newMyAnnotation(int[] value) {",
@@ -288,6 +296,7 @@ public class AutoAnnotationCompilationTest {
Compilation compilation =
javac()
.withProcessors(new AutoAnnotationProcessor())
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
.compile(annotationFactoryJavaFile, myAnnotationJavaFile, gwtCompatibleJavaFile);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
@@ -343,6 +352,7 @@ public class AutoAnnotationCompilationTest {
"",
"import com.example.annotations.MyAnnotation;",
"import com.example.enums.MyEnum;",
+ "import java.io.Serializable;",
"import java.util.Arrays;",
"import java.util.Collection;",
"import java.util.List;",
@@ -350,8 +360,9 @@ public class AutoAnnotationCompilationTest {
GeneratedImport.importGeneratedAnnotationType(),
"",
"@Generated(\"" + AutoAnnotationProcessor.class.getName() + "\")",
- "final class AutoAnnotation_AnnotationFactory_newMyAnnotation implements MyAnnotation"
- + " {",
+ "final class AutoAnnotation_AnnotationFactory_newMyAnnotation implements MyAnnotation,"
+ + " Serializable {",
+ " private static final long serialVersionUID = -2102364343628921304L;",
" private final int[] value;",
" private final MyEnum[] enums;",
"",
@@ -426,6 +437,7 @@ public class AutoAnnotationCompilationTest {
Compilation compilation =
javac()
.withProcessors(new AutoAnnotationProcessor())
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
.compile(annotationFactoryJavaFile, myEnumJavaFile, myAnnotationJavaFile);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
@@ -457,9 +469,7 @@ public class AutoAnnotationCompilationTest {
" @NotAutoAnnotation Empty notNewEmpty() {}",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(erroneousJavaFileObject);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(erroneousJavaFileObject);
assertThat(compilation)
.hadErrorContaining("NotAutoAnnotation")
.inFile(erroneousJavaFileObject)
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoAnnotationErrorsTest.java b/value/src/test/java/com/google/auto/value/processor/AutoAnnotationErrorsTest.java
index 55a4c5db..094b570d 100644
--- a/value/src/test/java/com/google/auto/value/processor/AutoAnnotationErrorsTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/AutoAnnotationErrorsTest.java
@@ -57,9 +57,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(TEST_ANNOTATION, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(TEST_ANNOTATION, testSource);
assertThat(compilation).succeededWithoutWarnings();
}
@@ -79,9 +77,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(TEST_ANNOTATION, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(TEST_ANNOTATION, testSource);
assertThat(compilation)
.hadErrorContaining("must be static")
.inFile(testSource)
@@ -103,9 +99,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(TEST_ANNOTATION, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(TEST_ANNOTATION, testSource);
assertThat(compilation)
.hadErrorContaining("must be an annotation type, not java.lang.String")
.inFile(testSource)
@@ -132,9 +126,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(TEST_ANNOTATION, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(TEST_ANNOTATION, testSource);
assertThat(compilation)
.hadErrorContaining("@AutoAnnotation methods cannot be overloaded")
.inFile(testSource)
@@ -196,9 +188,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(TEST_ANNOTATION, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(TEST_ANNOTATION, testSource);
assertThat(compilation)
.hadErrorContaining("method parameter 'fred' must have the same name")
.inFile(testSource)
@@ -221,9 +211,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(TEST_ANNOTATION, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(TEST_ANNOTATION, testSource);
assertThat(compilation)
.hadErrorContaining(
"method parameter 'value' has type java.lang.String "
@@ -267,9 +255,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(testSource, testAnnotation);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(testSource, testAnnotation);
assertThat(compilation)
.hadErrorContaining(
"method parameter 'value' has type "
@@ -296,9 +282,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(TEST_ANNOTATION, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(TEST_ANNOTATION, testSource);
assertThat(compilation)
.hadErrorContaining(
"method parameter 'other' must have the same name as a member of "
@@ -323,9 +307,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(TEST_ANNOTATION, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(TEST_ANNOTATION, testSource);
assertThat(compilation)
.hadErrorContaining("method needs a parameter with name 'value' and type int")
.inFile(testSource)
@@ -357,9 +339,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(annotationSource, testSource);
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(annotationSource, testSource);
assertThat(compilation)
.hadErrorContaining(
"@AutoAnnotation cannot yet supply a default value for annotation-valued member "
@@ -399,10 +379,7 @@ public class AutoAnnotationErrorsTest {
" }",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoAnnotationProcessor())
- .compile(annotationSource, testSource);
- assertThat(compilation)
- .hadErrorContaining("variable value$ is already defined in constructor");
+ javac().withProcessors(new AutoAnnotationProcessor()).compile(annotationSource, testSource);
+ assertThat(compilation).hadErrorContaining("variable value$ is already defined in constructor");
}
}
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java
new file mode 100644
index 00000000..50b6b271
--- /dev/null
+++ b/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java
@@ -0,0 +1,875 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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.auto.value.processor;
+
+import static com.google.common.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION;
+import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static com.google.testing.compile.Compiler.javac;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AutoBuilderCompilationTest {
+ private static final JavaFileObject EXPECTED_SIMPLE_OUTPUT =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.AutoBuilder_Baz_Builder",
+ "package foo.bar;",
+ "",
+ GeneratedImport.importGeneratedAnnotationType(),
+ "",
+ "@Generated(\"" + AutoBuilderProcessor.class.getName() + "\")",
+ "class AutoBuilder_Baz_Builder implements Baz.Builder {",
+ " private Integer anInt;",
+ " private String aString;",
+ "",
+ " AutoBuilder_Baz_Builder() {}",
+ "",
+ " @Override public Baz.Builder setAnInt(int anInt) {",
+ " this.anInt = anInt;",
+ " return this;",
+ " }",
+ "",
+ " @Override public Baz.Builder setAString(String aString) {",
+ " if (aString == null) {",
+ " throw new NullPointerException(\"Null aString\");",
+ " }",
+ " this.aString = aString;",
+ " return this;",
+ " }",
+ "",
+ " @Override",
+ " public Baz build() {",
+ " if (this.anInt == null",
+ " || this.aString == null) {",
+ " StringBuilder missing = new StringBuilder();",
+ " if (this.anInt == null) {",
+ " missing.append(\" anInt\");",
+ " }",
+ " if (this.aString == null) {",
+ " missing.append(\" aString\");",
+ " }",
+ " throw new IllegalStateException(\"Missing required properties:\" + missing);",
+ " }",
+ " return new Baz(",
+ " this.anInt,",
+ " this.aString);",
+ " }",
+ "}");
+
+ @Test
+ public void simpleSuccess() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " private final int anInt;",
+ " private final String aString;",
+ "",
+ " public Baz(int anInt, String aString) {",
+ " this.anInt = anInt;",
+ " this.aString = aString;",
+ " }",
+ "",
+ " public int anInt() {",
+ " return anInt;",
+ " }",
+ "",
+ " public String aString() {",
+ " return aString;",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new AutoBuilder_Baz_Builder();",
+ " }",
+ "",
+ " @AutoBuilder",
+ " public interface Builder {",
+ " Builder setAnInt(int x);",
+ " Builder setAString(String x);",
+ " Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation)
+ .generatedSourceFile("foo.bar.AutoBuilder_Baz_Builder")
+ .hasSourceEquivalentTo(EXPECTED_SIMPLE_OUTPUT);
+ }
+
+ @Test
+ public void simpleRecord() {
+ double version = Double.parseDouble(JAVA_SPECIFICATION_VERSION.value());
+ assume().that(version).isAtLeast(16.0);
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public record Baz(int anInt, String aString) {",
+ " public static Builder builder() {",
+ " return new AutoBuilder_Baz_Builder();",
+ " }",
+ "",
+ " @AutoBuilder",
+ " public interface Builder {",
+ " Builder setAnInt(int x);",
+ " Builder setAString(String x);",
+ " Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation)
+ .generatedSourceFile("foo.bar.AutoBuilder_Baz_Builder")
+ .hasSourceEquivalentTo(EXPECTED_SIMPLE_OUTPUT);
+ }
+
+ @Test
+ public void buildOtherPackage() {
+ JavaFileObject built =
+ JavaFileObjects.forSourceLines(
+ "com.example.Built",
+ "package com.example;",
+ "",
+ "public class Built {",
+ " private final int anInt;",
+ " private final String aString;",
+ "",
+ " public Built(int anInt, String aString) {",
+ " this.anInt = anInt;",
+ " this.aString = aString;",
+ " }",
+ "}");
+ JavaFileObject builder =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Builder",
+ "package foo.bar;",
+ "",
+ "import com.example.Built;",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "@AutoBuilder(ofClass = Built.class)",
+ "public interface Builder {",
+ " public static Builder builder() {",
+ " return new AutoBuilder_Builder();",
+ " }",
+ "",
+ " Builder setAnInt(int x);",
+ " Builder setAString(String x);",
+ " Built build();",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(built, builder);
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation).generatedSourceFile("foo.bar.AutoBuilder_Builder");
+ }
+
+ @Test
+ public void autoBuilderOnEnum() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "@AutoBuilder",
+ "public enum Baz {",
+ " ZIG, ZAG, DUSTIN,",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderWrongType] @AutoBuilder only applies to classes and interfaces")
+ .inFile(javaFileObject)
+ .onLineContaining("enum Baz");
+ }
+
+ @Test
+ public void autoBuilderPrivate() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " @AutoBuilder",
+ " private interface Builder {",
+ " Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("[AutoBuilderPrivate] @AutoBuilder class must not be private")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void autoBuilderNestedInPrivate() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " private static class Private {",
+ " @AutoBuilder",
+ " public interface Builder {",
+ " Baz build();",
+ " }",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderInPrivate] @AutoBuilder class must not be nested in a private class")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void autoBuilderInner() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " @AutoBuilder",
+ " abstract class Builder {",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("[AutoBuilderInner] Nested @AutoBuilder class must be static")
+ .inFile(javaFileObject)
+ .onLineContaining("class Builder");
+ }
+
+ @Test
+ public void innerConstructor() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " class Inner {}",
+ "",
+ " @AutoBuilder(ofClass = Inner.class)",
+ " interface Builder {",
+ " abstract Inner build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("[AutoBuilderInner] Nested @AutoBuilder ofClass class must be static")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void noVisibleConstructor() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " @AutoBuilder(ofClass = System.class)",
+ " interface Builder {",
+ " abstract System build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("[AutoBuilderNoVisible] No visible constructor for java.lang.System")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void noVisibleMethod() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " private static Baz of() {",
+ " return new Baz();",
+ " }",
+ "",
+ " @AutoBuilder(callMethod = \"of\")",
+ " interface Builder {",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderNoVisible] No visible static method named \"of\" for foo.bar.Baz")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void methodNotStatic() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " Baz of() {",
+ " return this;",
+ " }",
+ "",
+ " @AutoBuilder(callMethod = \"of\")",
+ " interface Builder {",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderNoVisible] No visible static method named \"of\" for foo.bar.Baz")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void noMatchingConstructor() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " public Baz(int notMe) {}",
+ "",
+ " public Baz(String notMeEither) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " Builder setBuh(String x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderNoMatch] Property names do not correspond to the parameter names of any"
+ + " constructor:\n"
+ + " Baz(int notMe)\n"
+ + " Baz(java.lang.String notMeEither)")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void twoMatchingConstructors() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public class Baz {",
+ " public Baz() {}",
+ "",
+ " public Baz(int buh) {}",
+ "",
+ " public Baz(String buh) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " Builder setBuh(String x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderAmbiguous] Property names correspond to more than one constructor:\n"
+ + " Baz(int buh)\n"
+ + " Baz(java.lang.String buh)")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void constructInterface() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "public interface Baz {",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderEnclosing] @AutoBuilder must specify ofClass=Something.class or it must"
+ + " be nested inside the class to be built; actually nested inside interface"
+ + " foo.bar.Baz")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void inconsistentSetPrefix() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "class Baz {",
+ " Baz(int one, int two) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder one(int x);",
+ " abstract Builder setTwo(int x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderSetNotSet] If any setter methods use the setFoo convention then all must")
+ .inFile(javaFileObject)
+ .onLineContaining("Builder one(int x)");
+ }
+
+ @Test
+ public void missingSetter() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "class Baz {",
+ " Baz(int one, int two) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder one(int x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderBuilderMissingMethod] Expected a method with this signature:"
+ + " foo.bar.Baz.Builder two(int), or a twoBuilder() method")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder");
+ }
+
+ @Test
+ public void tooManyArgs() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "class Baz {",
+ " Baz(int one, int two) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder one(int x);",
+ " abstract Builder two(int x);",
+ " abstract Builder many(int x, int y);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining("[AutoBuilderBuilderArgs] Builder methods must have 0 or 1 parameters")
+ .inFile(javaFileObject)
+ .onLineContaining("many(int x, int y)");
+ }
+
+ @Test
+ public void alienNoArgMethod() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "class Baz {",
+ " Baz(int one, int two) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder one(int x);",
+ " abstract Builder two(int x);",
+ " abstract String alien();",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderBuilderNoArg] Method without arguments should be a build method returning"
+ + " foo.bar.Baz, or a getter method with the same name and type as a parameter of"
+ + " Baz(int one, int two), or fooBuilder() where foo is a parameter of Baz(int"
+ + " one, int two)")
+ .inFile(javaFileObject)
+ .onLineContaining("String alien()");
+ }
+
+ @Test
+ public void alienOneArgMethod() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "class Baz {",
+ " Baz(int one, int two) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder one(int x);",
+ " abstract Builder two(int x);",
+ " abstract Builder three(int x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderBuilderWhatProp] Method three does not correspond to "
+ + "a parameter of Baz(int one, int two)")
+ .inFile(javaFileObject)
+ .onLineContaining("three(int x)");
+ }
+
+ @Test
+ public void setterReturnType() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "class Baz {",
+ " Baz(int one, int two) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder one(int x);",
+ " abstract void two(int x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderBuilderRet] Setter methods must return foo.bar.Baz.Builder")
+ .inFile(javaFileObject)
+ .onLineContaining("two(int x)");
+ }
+
+ @Test
+ public void nullableSetterForNonNullableParameter() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "import org.checkerframework.checker.nullness.qual.Nullable;",
+ "",
+ "class Baz {",
+ " Baz(String thing) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder thing(@Nullable String x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ JavaFileObject nullableFileObject =
+ JavaFileObjects.forSourceLines(
+ "org.checkerframework.checker.nullness.qual.Nullable",
+ "package org.jspecify.nullness;",
+ "",
+ "import java.lang.annotation.ElementType;",
+ "import java.lang.annotation.Target;",
+ "",
+ "@Target(ElementType.TYPE_USE)",
+ "public @interface Nullable {}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject, nullableFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderNullNotNull] Parameter of setter method is @Nullable but parameter"
+ + " \"thing\" of Baz(java.lang.String thing) is not")
+ .inFile(javaFileObject)
+ .onLineContaining("thing(@Nullable String x)");
+ }
+
+ @Test
+ public void setterWrongType() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "",
+ "class Baz {",
+ " Baz(int up, int down) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder up(int x);",
+ " abstract Builder down(String x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderGetVsSet] Parameter type java.lang.String of setter method should be int"
+ + " to match parameter \"down\" of Baz(int up, int down)")
+ .inFile(javaFileObject)
+ .onLineContaining("down(String x)");
+ }
+
+ @Test
+ public void setterWrongTypeEvenWithConversion() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "import java.util.Optional;",
+ "",
+ "class Baz {",
+ " Baz(Optional<String> maybe) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder {",
+ " abstract Builder maybe(int x);",
+ " abstract Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderGetVsSetOrConvert] Parameter type int of setter method should be"
+ + " java.util.Optional<java.lang.String> to match parameter \"maybe\" of"
+ + " Baz(java.util.Optional<java.lang.String> maybe), or it should be a type that"
+ + " can be passed to Optional.of to produce java.util.Optional<java.lang.String>")
+ .inFile(javaFileObject)
+ .onLineContaining("maybe(int x)");
+ }
+
+ @Test
+ public void typeParamMismatch() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoBuilder;",
+ "import java.util.Optional;",
+ "",
+ "class Baz<T> {",
+ " Baz(T param) {}",
+ "",
+ " @AutoBuilder",
+ " interface Builder<E> {",
+ " abstract Builder<E> param(E param);",
+ " abstract Baz<E> build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoBuilderProcessor())
+ .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+ .compile(javaFileObject);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ "[AutoBuilderTypeParams] Builder type parameters <E> must match type parameters <T> of"
+ + " Baz(T param)")
+ .inFile(javaFileObject)
+ .onLineContaining("interface Builder<E>");
+ }
+}
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java
index 63e84199..788b543a 100644
--- a/value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java
@@ -43,7 +43,9 @@ public class AutoOneOfCompilationTest {
"import java.io.Serializable;",
"",
"@AutoOneOf(TaskResult.Kind.class)",
- "public abstract class TaskResult<V, T extends Throwable> {",
+ "public abstract class TaskResult<V, T extends Throwable> implements Serializable {",
+ " private static final long serialVersionUID = 1234L;",
+ "",
" public enum Kind {VALUE, EXCEPTION, EMPTY}",
" public abstract Kind getKind();",
"",
@@ -92,6 +94,8 @@ public class AutoOneOfCompilationTest {
" // Parent class that each implementation will inherit from.",
" private abstract static class Parent_<V, T extends Throwable> "
+ "extends TaskResult<V, T> {",
+ " private static final long serialVersionUID = 1234L;",
+ "",
" @Override",
" public V value() {",
" throw new UnsupportedOperationException(getKind().toString());",
@@ -111,6 +115,8 @@ public class AutoOneOfCompilationTest {
" // Implementation when the contained property is \"value\".",
" private static final class Impl_value<V, T extends Throwable> "
+ "extends Parent_<V, T> {",
+ " private static final long serialVersionUID = 1234L;",
+ "",
" private final V value;",
"",
" Impl_value(V value) {",
@@ -152,6 +158,8 @@ public class AutoOneOfCompilationTest {
" // Implementation when the contained property is \"exception\".",
" private static final class Impl_exception<V, T extends Throwable> "
+ "extends Parent_<V, T> {",
+ " private static final long serialVersionUID = 1234L;",
+ "",
" private final Throwable exception;",
"",
" Impl_exception(Throwable exception) {",
@@ -193,6 +201,8 @@ public class AutoOneOfCompilationTest {
" // Implementation when the contained property is \"empty\".",
" private static final class Impl_empty<V, T extends Throwable> "
+ "extends Parent_<V, T> {",
+ " private static final long serialVersionUID = 1234L;",
+ "",
" static final Impl_empty<?, ?> INSTANCE = new Impl_empty<>();",
"",
" private Impl_empty() {}",
@@ -200,6 +210,10 @@ public class AutoOneOfCompilationTest {
" @Override",
" public void empty() {}",
"",
+ " private Object readResolve() {",
+ " return INSTANCE;",
+ " }",
+ "",
" @Override",
" public String toString() {",
" return \"TaskResult{empty}\";",
@@ -223,7 +237,8 @@ public class AutoOneOfCompilationTest {
Compilation compilation =
javac()
.withProcessors(new AutoOneOfProcessor())
- .withOptions("-Xlint:-processing", "-implicit:none")
+ .withOptions(
+ "-Xlint:-processing", "-implicit:none", "-A" + Nullables.NULLABLE_OPTION + "=")
.compile(javaFileObject);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
@@ -307,7 +322,8 @@ public class AutoOneOfCompilationTest {
Compilation compilation =
javac()
.withProcessors(new AutoOneOfProcessor())
- .withOptions("-Xlint:-processing", "-implicit:none")
+ .withOptions(
+ "-Xlint:-processing", "-implicit:none", "-A" + Nullables.NULLABLE_OPTION + "=")
.compile(javaFileObject);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
index e46c9f51..ab6690fd 100644
--- a/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
@@ -57,8 +57,8 @@ public class AutoValueCompilationTest {
public void simpleSuccess() {
// Positive test case that ensures we generate the expected code for at least one case.
// Most AutoValue code-generation tests are functional, meaning that we check that the generated
- // code does the right thing rather than checking what it looks like, but this test is a sanity
- // check that we are not generating correct but weird code.
+ // code does the right thing rather than checking what it looks like, but this test checks that
+ // we are not generating correct but weird code.
JavaFileObject javaFileObject =
JavaFileObjects.forSourceLines(
"foo.bar.Baz",
@@ -118,7 +118,10 @@ public class AutoValueCompilationTest {
" }",
"}");
Compilation compilation =
- javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject);
+ javac()
+ .withProcessors(new AutoValueProcessor())
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
+ .compile(javaFileObject);
assertThat(compilation)
.generatedSourceFile("foo.bar.AutoValue_Baz")
.hasSourceEquivalentTo(expectedOutput);
@@ -216,7 +219,10 @@ public class AutoValueCompilationTest {
" }",
"}");
Compilation compilation =
- javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject);
+ javac()
+ .withProcessors(new AutoValueProcessor())
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
+ .compile(javaFileObject);
assertThat(compilation)
.generatedSourceFile("foo.bar.AutoValue_Baz")
.hasSourceEquivalentTo(expectedOutput);
@@ -335,7 +341,6 @@ public class AutoValueCompilationTest {
" return false;",
" }",
"",
-
" @Override",
" public int hashCode() {",
" int h$ = 1;",
@@ -348,7 +353,8 @@ public class AutoValueCompilationTest {
Compilation compilation =
javac()
.withProcessors(new AutoValueProcessor())
- .withOptions("-Xlint:-processing", "-implicit:none")
+ .withOptions(
+ "-Xlint:-processing", "-implicit:none", "-A" + Nullables.NULLABLE_OPTION + "=")
.compile(annotFileObject, outerFileObject, nestyFileObject);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
@@ -1129,10 +1135,10 @@ public class AutoValueCompilationTest {
" return this.anInt == that.anInt()",
" && Arrays.equals(this.aByteArray, "
+ "(that instanceof AutoValue_Baz) "
- + "? ((AutoValue_Baz) that).aByteArray : that.aByteArray())",
+ + "? ((AutoValue_Baz<?>) that).aByteArray : that.aByteArray())",
" && Arrays.equals(this.aNullableIntArray, "
+ "(that instanceof AutoValue_Baz) "
- + "? ((AutoValue_Baz) that).aNullableIntArray : that.aNullableIntArray())",
+ + "? ((AutoValue_Baz<?>) that).aNullableIntArray : that.aNullableIntArray())",
" && this.aList.equals(that.aList())",
" && this.anImmutableList.equals(that.anImmutableList())",
" && this.anOptionalString.equals(that.anOptionalString())",
@@ -1312,17 +1318,19 @@ public class AutoValueCompilationTest {
+ "NestedAutoValue.builder();",
" this.aNestedAutoValue = aNestedAutoValue$builder.build();",
" }",
- " String missing = \"\";",
- " if (this.anInt == null) {",
- " missing += \" anInt\";",
- " }",
- " if (this.aByteArray == null) {",
- " missing += \" aByteArray\";",
- " }",
- " if (this.aList == null) {",
- " missing += \" aList\";",
- " }",
- " if (!missing.isEmpty()) {",
+ " if (this.anInt == null",
+ " || this.aByteArray == null",
+ " || this.aList == null) {",
+ " StringBuilder missing = new StringBuilder();",
+ " if (this.anInt == null) {",
+ " missing.append(\" anInt\");",
+ " }",
+ " if (this.aByteArray == null) {",
+ " missing.append(\" aByteArray\");",
+ " }",
+ " if (this.aList == null) {",
+ " missing.append(\" aList\");",
+ " }",
" throw new IllegalStateException(\"Missing required properties:\" + missing);",
" }",
" return new AutoValue_Baz<T>(",
@@ -1339,7 +1347,8 @@ public class AutoValueCompilationTest {
Compilation compilation =
javac()
.withProcessors(new AutoValueProcessor())
- .withOptions("-Xlint:-processing", "-implicit:none")
+ .withOptions(
+ "-Xlint:-processing", "-implicit:none", "-A" + Nullables.NULLABLE_OPTION + "=")
.compile(javaFileObject, nestedJavaFileObject);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
@@ -1587,7 +1596,7 @@ public class AutoValueCompilationTest {
assertThat(compilation)
.hadErrorContaining(
"Parameter type java.lang.String of setter method should be int "
- + "to match getter foo.bar.Baz.blim")
+ + "to match property method foo.bar.Baz.blim()")
.inFile(javaFileObject)
.onLineContaining("Builder blim(String x)");
}
@@ -1620,10 +1629,10 @@ public class AutoValueCompilationTest {
.compile(javaFileObject);
assertThat(compilation)
.hadErrorContaining(
- "Parameter type java.lang.String of setter method should be "
- + "com.google.common.collect.ImmutableList<java.lang.String> to match getter "
- + "foo.bar.Baz.blam, or it should be a type that can be passed to "
- + "ImmutableList.copyOf")
+ "Parameter type java.lang.String of setter method should be"
+ + " com.google.common.collect.ImmutableList<java.lang.String> to match property"
+ + " method foo.bar.Baz.blam(), or it should be a type that can be passed to"
+ + " ImmutableList.copyOf")
.inFile(javaFileObject)
.onLineContaining("Builder blam(String x)");
}
@@ -1657,11 +1666,11 @@ public class AutoValueCompilationTest {
.compile(javaFileObject);
assertThat(compilation)
.hadErrorContaining(
- "Parameter type java.util.Collection<java.lang.Integer> of setter method should be "
- + "com.google.common.collect.ImmutableList<java.lang.String> to match getter "
- + "foo.bar.Baz.blam, or it should be a type that can be passed to "
- + "ImmutableList.copyOf to produce "
- + "com.google.common.collect.ImmutableList<java.lang.String>")
+ "Parameter type java.util.Collection<java.lang.Integer> of setter method should be"
+ + " com.google.common.collect.ImmutableList<java.lang.String> to match property"
+ + " method foo.bar.Baz.blam(), or it should be a type that can be passed to"
+ + " ImmutableList.copyOf to produce"
+ + " com.google.common.collect.ImmutableList<java.lang.String>")
.inFile(javaFileObject)
.onLineContaining("Builder blam(Collection<Integer> x)");
}
@@ -1694,7 +1703,7 @@ public class AutoValueCompilationTest {
assertThat(compilation)
.hadErrorContaining(
"Parameter type java.lang.String of setter method should be int "
- + "to match getter foo.bar.Baz.getBlim")
+ + "to match property method foo.bar.Baz.getBlim()")
.inFile(javaFileObject)
.onLineContaining("Builder blim(String x)");
}
@@ -1768,7 +1777,8 @@ public class AutoValueCompilationTest {
.withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
.compile(javaFileObject);
assertThat(compilation)
- .hadErrorContaining("Method does not correspond to a property of foo.bar.Item")
+ .hadErrorContaining(
+ "Method setTitle does not correspond to a property method of foo.bar.Item")
.inFile(javaFileObject)
.onLineContaining("Builder setTitle(String title)");
assertThat(compilation)
@@ -1802,7 +1812,7 @@ public class AutoValueCompilationTest {
.withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
.compile(javaFileObject);
assertThat(compilation)
- .hadErrorContaining("Method does not correspond to a property of foo.bar.Baz")
+ .hadErrorContaining("Method blim does not correspond to a property method of foo.bar.Baz")
.inFile(javaFileObject)
.onLineContaining("Builder blim(int x)");
}
@@ -1839,6 +1849,35 @@ public class AutoValueCompilationTest {
}
@Test
+ public void autoValueBuilderSetterReturnType() {
+ JavaFileObject javaFileObject =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "",
+ "@AutoValue",
+ "public abstract class Baz {",
+ " abstract int blim();",
+ "",
+ " @AutoValue.Builder",
+ " public interface Builder {",
+ " void blim(int x);",
+ " Baz build();",
+ " }",
+ "}");
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
+ .compile(javaFileObject);
+ assertThat(compilation)
+ .hadErrorContaining("Setter methods must return foo.bar.Baz.Builder")
+ .inFile(javaFileObject)
+ .onLineContaining("void blim(int x)");
+ }
+
+ @Test
public void autoValueBuilderWrongTypeGetter() {
JavaFileObject javaFileObject =
JavaFileObjects.forSourceLines(
@@ -1866,10 +1905,15 @@ public class AutoValueCompilationTest {
.withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
.compile(javaFileObject);
assertThat(compilation)
- .hadErrorContaining(
- "Method matches a property of foo.bar.Baz but has return type T instead of U")
+ .hadErrorContainingMatch(
+ "Method matches a property of foo\\.bar\\.Baz<T, ?U> but has return type T instead of"
+ + " U")
.inFile(javaFileObject)
.onLineContaining("T blam()");
+ // The <T, ?U> is because we're depending on TypeMirror.toString(), and the JDK actually spells
+ // this as <T,U> with no space. While it's not completely sound to expect a given string from
+ // TypeMirror.toString(), in practice it's hard to imagine that it would be anything other
+ // than "foo.bar.Baz<T,U>" or "foo.bar.Baz<T, U>" given the specification.
}
@Test
@@ -1929,9 +1973,9 @@ public class AutoValueCompilationTest {
.withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
.compile(javaFileObject);
assertThat(compilation)
- .hadErrorContaining("Property strings has a property builder so it cannot be @Nullable")
+ .hadErrorContaining("Property strings is @Nullable so it cannot have a property builder")
.inFile(javaFileObject)
- .onLineContaining("@Nullable ImmutableList<String> strings()");
+ .onLineContaining("stringsBuilder()");
}
@Test
@@ -1963,9 +2007,9 @@ public class AutoValueCompilationTest {
.withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
.compile(javaFileObject);
assertThat(compilation)
- .hadErrorContaining("Property strings has a property builder so it cannot be @Nullable")
+ .hadErrorContaining("Property strings is @Nullable so it cannot have a property builder")
.inFile(javaFileObject)
- .onLineContaining("@Nullable ImmutableList<String> strings()");
+ .onLineContaining("stringsBuilder()");
}
@Test
@@ -2451,8 +2495,8 @@ public class AutoValueCompilationTest {
assertThat(compilation)
.hadErrorContaining(
"Method without arguments should be a build method returning foo.bar.Baz, or a getter"
- + " method with the same name and type as a getter method of foo.bar.Baz, or"
- + " fooBuilder() where foo() or getFoo() is a getter method of foo.bar.Baz")
+ + " method with the same name and type as a property method of foo.bar.Baz, or"
+ + " fooBuilder() where foo() or getFoo() is a property method of foo.bar.Baz")
.inFile(javaFileObject)
.onLineContaining("Builder whut()");
}
@@ -2481,7 +2525,7 @@ public class AutoValueCompilationTest {
.withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
.compile(javaFileObject);
assertThat(compilation)
- .hadErrorContaining("Method does not correspond to a property of foo.bar.Baz")
+ .hadErrorContaining("Method whut does not correspond to a property method of foo.bar.Baz")
.inFile(javaFileObject)
.onLineContaining("void whut(String x)");
}
@@ -2539,7 +2583,8 @@ public class AutoValueCompilationTest {
.compile(javaFileObject);
assertThat(compilation)
.hadErrorContaining(
- "Builder must have a single no-argument method returning foo.bar.Baz<T>")
+ "Builder must have a single no-argument method, typically called build(), that returns"
+ + " foo.bar.Baz<T>")
.inFile(javaFileObject)
.onLineContaining("public interface Builder<T>");
}
@@ -2569,11 +2614,15 @@ public class AutoValueCompilationTest {
.withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
.compile(javaFileObject);
assertThat(compilation)
- .hadErrorContaining("Builder must have a single no-argument method returning foo.bar.Baz")
+ .hadErrorContaining(
+ "Builder must have a single no-argument method, typically called build(), that returns"
+ + " foo.bar.Baz")
.inFile(javaFileObject)
.onLineContaining("Baz build()");
assertThat(compilation)
- .hadErrorContaining("Builder must have a single no-argument method returning foo.bar.Baz")
+ .hadErrorContaining(
+ "Builder must have a single no-argument method, typically called build(), that returns"
+ + " foo.bar.Baz")
.inFile(javaFileObject)
.onLineContaining("Baz create()");
}
@@ -3286,7 +3335,7 @@ public class AutoValueCompilationTest {
"}");
private static final String GENERATED_PROPERTY_TYPE =
String.join(
- "\n",
+ "\n", //
"package foo.baz;",
"",
"public class GeneratedPropertyType {}");
@@ -3315,18 +3364,14 @@ public class AutoValueCompilationTest {
GENERATED_TYPES.forEach(
(typeName, source) -> {
try {
- JavaFileObject generated =
- processingEnv
- .getFiler()
- .createSourceFile(typeName);
+ JavaFileObject generated = processingEnv.getFiler().createSourceFile(typeName);
try (Writer writer = generated.openWriter()) {
writer.write(source);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
- }
- );
+ });
}
return false;
}
@@ -3337,7 +3382,41 @@ public class AutoValueCompilationTest {
}
}
+ // This is a regression test for the problem described in
+ // https://github.com/google/auto/issues/1087.
+ @Test
+ public void kotlinMetadataAnnotationsAreImplicitlyExcludedFromCopying() {
+ JavaFileObject metadata =
+ JavaFileObjects.forSourceLines(
+ "kotlin.Metadata", "package kotlin;", "", "public @interface Metadata {", "}");
+ JavaFileObject test =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Test",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "import kotlin.Metadata;",
+ "",
+ "@AutoValue.CopyAnnotations",
+ "@Metadata",
+ "@AutoValue",
+ "public abstract class Test {",
+ " public abstract String string();",
+ "}");
+ AutoValueProcessor autoValueProcessor = new AutoValueProcessor();
+ Compilation compilation =
+ javac()
+ .withProcessors(autoValueProcessor)
+ .withOptions("-Xlint:-processing", "-implicit:none")
+ .compile(test, metadata);
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("foo.bar.AutoValue_Test")
+ .contentsAsUtf8String()
+ .doesNotContain("kotlin.Metadata");
+ }
+
private String sorted(String... imports) {
- return Arrays.stream(imports).sorted().collect(joining("\n"));
- }
+ return Arrays.stream(imports).sorted().collect(joining("\n"));
+ }
}
diff --git a/value/src/test/java/com/google/auto/value/processor/ExtensionTest.java b/value/src/test/java/com/google/auto/value/processor/ExtensionTest.java
index ce9eeed0..56eaad25 100644
--- a/value/src/test/java/com/google/auto/value/processor/ExtensionTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/ExtensionTest.java
@@ -172,6 +172,7 @@ public class ExtensionTest {
Compilation compilation =
javac()
.withProcessors(new AutoValueProcessor(ImmutableList.of(new FooExtension())))
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
.compile(javaFileObject);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
@@ -250,9 +251,7 @@ public class ExtensionTest {
" abstract String dizzle();",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoValueProcessor(ImmutableList.of(ext1, ext2)))
- .compile(impl);
+ javac().withProcessors(new AutoValueProcessor(ImmutableList.of(ext1, ext2))).compile(impl);
assertThat(compilation)
.hadErrorContaining("wants to consume a method that was already consumed")
.inFile(impl)
@@ -596,10 +595,9 @@ public class ExtensionTest {
"}");
Compilation compilation =
javac()
- .withProcessors(new AutoValueProcessor(ImmutableList.of(new FooExtension())))
- .compile(javaFileObject);
- assertThat(compilation)
- .hadErrorContaining("writeToParcel");
+ .withProcessors(new AutoValueProcessor(ImmutableList.of(new FooExtension())))
+ .compile(javaFileObject);
+ assertThat(compilation).hadErrorContaining("writeToParcel");
assertThat(compilation)
.hadWarningContaining(
"Abstract method is neither a property getter nor a Builder converter, "
@@ -647,13 +645,12 @@ public class ExtensionTest {
"public abstract class Baz {",
"}");
Compilation compilation =
- javac()
- .withProcessors(new AutoValueProcessor(badJarLoader))
- .compile(javaFileObject);
+ javac().withProcessors(new AutoValueProcessor(badJarLoader)).compile(javaFileObject);
assertThat(compilation).succeeded();
- assertThat(compilation).hadWarningContaining(
- "This may be due to a corrupt jar file in the compiler's classpath.\n "
- + ServiceConfigurationError.class.getName());
+ assertThat(compilation)
+ .hadWarningContaining(
+ "This may be due to a corrupt jar file in the compiler's classpath.\n "
+ + ServiceConfigurationError.class.getName());
assertThat(compilation).generatedSourceFile("foo.bar.AutoValue_Baz");
}
@@ -857,8 +854,12 @@ public class ExtensionTest {
String sideClassName = "Side_" + context.autoValueClass().getSimpleName();
String sideClass =
"" //
- + "package " + context.packageName() + ";\n"
- + "class " + sideClassName + " {}\n";
+ + "package "
+ + context.packageName()
+ + ";\n"
+ + "class "
+ + sideClassName
+ + " {}\n";
Filer filer = context.processingEnvironment().getFiler();
try {
String sideClassFqName = context.packageName() + "." + sideClassName;
@@ -912,25 +913,27 @@ public class ExtensionTest {
@Test
public void propertyTypes() {
- JavaFileObject parent = JavaFileObjects.forSourceLines(
- "foo.bar.Parent",
- "package foo.bar;",
- "",
- "import java.util.List;",
- "",
- "interface Parent<T> {",
- " T thing();",
- " List<T> list();",
- "}");
- JavaFileObject autoValueClass = JavaFileObjects.forSourceLines(
- "foo.bar.Baz",
- "package foo.bar;",
- "",
- "import com.google.auto.value.AutoValue;",
- "",
- "@AutoValue",
- "abstract class Baz implements Parent<String> {",
- "}");
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Parent",
+ "package foo.bar;",
+ "",
+ "import java.util.List;",
+ "",
+ "interface Parent<T> {",
+ " T thing();",
+ " List<T> list();",
+ "}");
+ JavaFileObject autoValueClass =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "",
+ "@AutoValue",
+ "abstract class Baz implements Parent<String> {",
+ "}");
ContextChecker checker =
context -> {
assertThat(context.builder()).isEmpty();
@@ -955,15 +958,16 @@ public class ExtensionTest {
@Test
public void finalAutoValueClassName() {
- JavaFileObject autoValueClass = JavaFileObjects.forSourceLines(
- "foo.bar.Baz",
- "package foo.bar;",
- "",
- "import com.google.auto.value.AutoValue;",
- "",
- "@AutoValue",
- "abstract class Baz {",
- "}");
+ JavaFileObject autoValueClass =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "",
+ "@AutoValue",
+ "abstract class Baz {",
+ "}");
ContextChecker checker =
context -> {
assertThat(context.finalAutoValueClassName()).isEqualTo("foo.bar.AutoValue_Baz");
@@ -982,43 +986,45 @@ public class ExtensionTest {
@Test
public void builderContext() {
- JavaFileObject parent = JavaFileObjects.forSourceLines(
- "foo.bar.Parent",
- "package foo.bar;",
- "",
- "import com.google.common.collect.ImmutableList;",
- "",
- "interface Parent<T> {",
- " T thing();",
- " ImmutableList<T> list();",
- "}");
- JavaFileObject autoValueClass = JavaFileObjects.forSourceLines(
- "foo.bar.Baz",
- "package foo.bar;",
- "",
- "import com.google.auto.value.AutoValue;",
- "import com.google.common.collect.ImmutableList;",
- "",
- "@AutoValue",
- "abstract class Baz implements Parent<String> {",
- " static Builder builder() {",
- " return new AutoValue_Baz.Builder();",
- " }",
- "",
- " abstract Builder toBuilder();",
- "",
- " @AutoValue.Builder",
- " abstract static class Builder {",
- " abstract Builder setThing(String x);",
- " abstract Builder setList(Iterable<String> x);",
- " abstract Builder setList(ImmutableList<String> x);",
- " abstract ImmutableList.Builder<String> listBuilder();",
- " abstract Baz autoBuild();",
- " Baz build() {",
- " return autoBuild();",
- " }",
- " }",
- "}");
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Parent",
+ "package foo.bar;",
+ "",
+ "import com.google.common.collect.ImmutableList;",
+ "",
+ "interface Parent<T> {",
+ " T thing();",
+ " ImmutableList<T> list();",
+ "}");
+ JavaFileObject autoValueClass =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "import com.google.common.collect.ImmutableList;",
+ "",
+ "@AutoValue",
+ "abstract class Baz implements Parent<String> {",
+ " static Builder builder() {",
+ " return new AutoValue_Baz.Builder();",
+ " }",
+ "",
+ " abstract Builder toBuilder();",
+ "",
+ " @AutoValue.Builder",
+ " abstract static class Builder {",
+ " abstract Builder setThing(String x);",
+ " abstract Builder setList(Iterable<String> x);",
+ " abstract Builder setList(ImmutableList<String> x);",
+ " abstract ImmutableList.Builder<String> listBuilder();",
+ " abstract Baz autoBuild();",
+ " Baz build() {",
+ " return autoBuild();",
+ " }",
+ " }",
+ "}");
ContextChecker checker =
context -> {
assertThat(context.builder()).isPresent();
@@ -1075,27 +1081,102 @@ public class ExtensionTest {
}
@Test
+ public void builderContextWithInheritance() {
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Parent",
+ "package foo.bar;",
+ "",
+ "interface Parent<BuilderT> {",
+ " BuilderT toBuilder();",
+ " interface Builder<T, BuilderT, BuiltT> {",
+ " BuilderT setThing(T x);",
+ " BuiltT build();",
+ " }",
+ "}");
+ JavaFileObject autoValueClass =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "",
+ "@AutoValue",
+ "abstract class Baz<T> implements Parent<Baz.Builder<T>> {",
+ " abstract T thing();",
+ " static <T> Builder<T> builder() {",
+ " return new AutoValue_Baz.Builder<>();",
+ " }",
+ "",
+ " @AutoValue.Builder",
+ " abstract static class Builder<T> implements Parent.Builder<T, Builder<T>, Baz<T>> {",
+ " }",
+ "}");
+ ContextChecker checker =
+ context -> {
+ assertThat(context.builder()).isPresent();
+ BuilderContext builderContext = context.builder().get();
+
+ assertThat(builderContext.builderType().getQualifiedName().toString())
+ .isEqualTo("foo.bar.Baz.Builder");
+
+ Set<ExecutableElement> builderMethods = builderContext.builderMethods();
+ assertThat(builderMethods).hasSize(1);
+ ExecutableElement builderMethod = Iterables.getOnlyElement(builderMethods);
+ assertThat(builderMethod.getSimpleName().toString()).isEqualTo("builder");
+
+ Set<ExecutableElement> toBuilderMethods = builderContext.toBuilderMethods();
+ assertThat(toBuilderMethods).hasSize(1);
+ ExecutableElement toBuilderMethod = Iterables.getOnlyElement(toBuilderMethods);
+ assertThat(toBuilderMethod.getSimpleName().toString()).isEqualTo("toBuilder");
+
+ Optional<ExecutableElement> buildMethod = builderContext.buildMethod();
+ assertThat(buildMethod).isPresent();
+ assertThat(buildMethod.get().getSimpleName().toString()).isEqualTo("build");
+ assertThat(buildMethod.get().getParameters()).isEmpty();
+ assertThat(buildMethod.get().getReturnType().toString()).isEqualTo("BuiltT");
+
+ ExecutableElement autoBuildMethod = builderContext.autoBuildMethod();
+ assertThat(autoBuildMethod).isEqualTo(buildMethod.get());
+
+ Map<String, Set<ExecutableElement>> setters = builderContext.setters();
+ assertThat(setters.keySet()).containsExactly("thing");
+ Set<ExecutableElement> thingSetters = setters.get("thing");
+ assertThat(thingSetters).hasSize(1);
+ ExecutableElement thingSetter = Iterables.getOnlyElement(thingSetters);
+ assertThat(thingSetter.getSimpleName().toString()).isEqualTo("setThing");
+ };
+ ContextCheckingExtension extension = new ContextCheckingExtension(checker);
+ Compilation compilation =
+ javac()
+ .withProcessors(new AutoValueProcessor(ImmutableList.of(extension)))
+ .compile(autoValueClass, parent);
+ assertThat(compilation).succeededWithoutWarnings();
+ }
+
+ @Test
public void oddBuilderContext() {
- JavaFileObject autoValueClass = JavaFileObjects.forSourceLines(
- "foo.bar.Baz",
- "package foo.bar;",
- "",
- "import com.google.auto.value.AutoValue;",
- "import com.google.common.collect.ImmutableList;",
- "",
- "@AutoValue",
- "abstract class Baz {",
- " abstract String string();",
- "",
- " @AutoValue.Builder",
- " abstract static class Builder {",
- " abstract Builder setString(String x);",
- " abstract Baz oddBuild();",
- " Baz build(int butNotReallyBecauseOfThisParameter) {",
- " return null;",
- " }",
- " }",
- "}");
+ JavaFileObject autoValueClass =
+ JavaFileObjects.forSourceLines(
+ "foo.bar.Baz",
+ "package foo.bar;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "import com.google.common.collect.ImmutableList;",
+ "",
+ "@AutoValue",
+ "abstract class Baz {",
+ " abstract String string();",
+ "",
+ " @AutoValue.Builder",
+ " abstract static class Builder {",
+ " abstract Builder setString(String x);",
+ " abstract Baz oddBuild();",
+ " Baz build(int butNotReallyBecauseOfThisParameter) {",
+ " return null;",
+ " }",
+ " }",
+ "}");
ContextChecker checker =
context -> {
assertThat(context.builder()).isPresent();
@@ -1126,25 +1207,26 @@ public class ExtensionTest {
// https://github.com/google/auto/issues/809
@Test
public void propertyErrorShouldNotCrash() {
- JavaFileObject autoValueClass = JavaFileObjects.forSourceLines(
- "test.Test",
- "package test;",
- "import com.google.auto.value.AutoValue;",
- "import java.util.List;",
- "",
- "@AutoValue",
- "public abstract class Test {",
- " abstract Integer property();",
- " abstract List<String> listProperty();",
- "",
- " @AutoValue.Builder",
- " public interface Builder {",
- " Builder property(Integer property);",
- " Builder listProperty(List<String> listProperty);",
- " Builder listProperty(Integer listPropertyValues);",
- " Test build();",
- " }",
- "}");
+ JavaFileObject autoValueClass =
+ JavaFileObjects.forSourceLines(
+ "test.Test",
+ "package test;",
+ "import com.google.auto.value.AutoValue;",
+ "import java.util.List;",
+ "",
+ "@AutoValue",
+ "public abstract class Test {",
+ " abstract Integer property();",
+ " abstract List<String> listProperty();",
+ "",
+ " @AutoValue.Builder",
+ " public interface Builder {",
+ " Builder property(Integer property);",
+ " Builder listProperty(List<String> listProperty);",
+ " Builder listProperty(Integer listPropertyValues);",
+ " Test build();",
+ " }",
+ "}");
// We don't actually expect the extension to be invoked. Previously it was, and that led to a
// NullPointerException when calling .setters() in the checker.
ContextChecker checker =
diff --git a/value/src/test/java/com/google/auto/value/processor/GeneratedDoesNotExistTest.java b/value/src/test/java/com/google/auto/value/processor/GeneratedDoesNotExistTest.java
index f3d3d611..18cca5e4 100644
--- a/value/src/test/java/com/google/auto/value/processor/GeneratedDoesNotExistTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/GeneratedDoesNotExistTest.java
@@ -48,6 +48,8 @@ import org.junit.runners.Parameterized.Parameters;
*/
@RunWith(Parameterized.class)
public class GeneratedDoesNotExistTest {
+ private static final ImmutableList<String> STANDARD_OPTIONS =
+ ImmutableList.of("-A" + Nullables.NULLABLE_OPTION + "=");
@Parameters(name = "{0}")
public static Collection<Object[]> data() {
@@ -57,12 +59,16 @@ public class GeneratedDoesNotExistTest {
// TODO(b/72513371): use --release 8 once compile-testing supports that
params.add(
new Object[] {
- ImmutableList.of(), "javax.annotation.processing.Generated",
+ STANDARD_OPTIONS, "javax.annotation.processing.Generated",
});
}
params.add(
new Object[] {
- ImmutableList.of("-source", "8", "-target", "8"), "javax.annotation.Generated",
+ ImmutableList.<String>builder()
+ .addAll(STANDARD_OPTIONS)
+ .add("-source", "8", "-target", "8")
+ .build(),
+ "javax.annotation.Generated",
});
return params.build();
}
@@ -223,9 +229,9 @@ public class GeneratedDoesNotExistTest {
Processor noGeneratedProcessor = partialProxy(Processor.class, handler);
Compilation compilation =
javac()
- .withOptions(javacOptions)
- .withProcessors(noGeneratedProcessor)
- .compile(javaFileObject);
+ .withOptions(javacOptions)
+ .withProcessors(noGeneratedProcessor)
+ .compile(javaFileObject);
assertThat(compilation).succeededWithoutWarnings();
assertThat(compilation)
.generatedSourceFile("foo.bar.AutoValue_Baz")
diff --git a/value/src/test/java/com/google/auto/value/processor/IncrementalExtensionTest.java b/value/src/test/java/com/google/auto/value/processor/IncrementalExtensionTest.java
index 27cb0936..472f62db 100644
--- a/value/src/test/java/com/google/auto/value/processor/IncrementalExtensionTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/IncrementalExtensionTest.java
@@ -22,6 +22,7 @@ import com.google.auto.value.extension.AutoValueExtension;
import com.google.auto.value.extension.AutoValueExtension.IncrementalExtensionType;
import com.google.auto.value.extension.memoized.processor.MemoizeExtension;
import com.google.auto.value.extension.serializable.processor.SerializableAutoValueExtension;
+import com.google.auto.value.extension.toprettystring.processor.ToPrettyStringExtension;
import com.google.common.collect.ImmutableList;
import javax.annotation.processing.ProcessingEnvironment;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType;
@@ -46,7 +47,10 @@ public class IncrementalExtensionTest {
// different <?>.
assertThat(builtInExtensions)
.comparingElementsUsing(transforming(e -> (Object) e.getClass(), "is class"))
- .containsExactly(MemoizeExtension.class, SerializableAutoValueExtension.class);
+ .containsExactly(
+ MemoizeExtension.class,
+ SerializableAutoValueExtension.class,
+ ToPrettyStringExtension.class);
AutoValueProcessor processor = new AutoValueProcessor(builtInExtensions);
assertThat(processor.getSupportedOptions())
@@ -58,10 +62,12 @@ public class IncrementalExtensionTest {
AutoValueExtension nonIsolatingExtension = new NonIsolatingExtension();
assertThat(nonIsolatingExtension.incrementalType((ProcessingEnvironment) null))
.isEqualTo(IncrementalExtensionType.UNKNOWN);
- ImmutableList<AutoValueExtension> extensions = ImmutableList.<AutoValueExtension>builder()
- .addAll(AutoValueProcessor.extensionsFromLoader(AutoValueProcessor.class.getClassLoader()))
- .add(nonIsolatingExtension)
- .build();
+ ImmutableList<AutoValueExtension> extensions =
+ ImmutableList.<AutoValueExtension>builder()
+ .addAll(
+ AutoValueProcessor.extensionsFromLoader(AutoValueProcessor.class.getClassLoader()))
+ .add(nonIsolatingExtension)
+ .build();
AutoValueProcessor processor = new AutoValueProcessor(extensions);
assertThat(processor.getSupportedOptions())
@@ -73,10 +79,12 @@ public class IncrementalExtensionTest {
AutoValueExtension isolatingExtension = new IsolatingExtension();
assertThat(isolatingExtension.incrementalType((ProcessingEnvironment) null))
.isEqualTo(IncrementalExtensionType.ISOLATING);
- ImmutableList<AutoValueExtension> extensions = ImmutableList.<AutoValueExtension>builder()
- .addAll(AutoValueProcessor.extensionsFromLoader(AutoValueProcessor.class.getClassLoader()))
- .add(isolatingExtension)
- .build();
+ ImmutableList<AutoValueExtension> extensions =
+ ImmutableList.<AutoValueExtension>builder()
+ .addAll(
+ AutoValueProcessor.extensionsFromLoader(AutoValueProcessor.class.getClassLoader()))
+ .add(isolatingExtension)
+ .build();
AutoValueProcessor processor = new AutoValueProcessor(extensions);
assertThat(processor.getSupportedOptions())
diff --git a/value/src/test/java/com/google/auto/value/processor/NullablesTest.java b/value/src/test/java/com/google/auto/value/processor/NullablesTest.java
new file mode 100644
index 00000000..9e345f53
--- /dev/null
+++ b/value/src/test/java/com/google/auto/value/processor/NullablesTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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.auto.value.processor;
+
+import static com.google.common.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION;
+import static com.google.common.truth.OptionalSubject.optionals;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static java.util.stream.Collectors.partitioningBy;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.google.common.truth.Expect;
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.Compiler;
+import com.google.testing.compile.JavaFileObjects;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.util.ElementFilter;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class NullablesTest {
+ @Rule public Expect expect = Expect.create();
+
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Nullable {}
+
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Irrelevant {}
+
+ // The class here has various methods that we will examine with
+ // Nullables.nullableMentionedInMethods to ensure that we do indeed detect @Nullable annotations
+ // in various contexts.
+ // This test is a lot more complicated than it should be. Ideally we would just have this Methods
+ // class be an actual class nested inside this test, and we would use CompilationRule to get
+ // the corresponding TypeElement so we could check the various methods. Unfortunately, if we
+ // do that then we get a TypeElement where all type annotations have disappeared because of
+ // https://bugs.openjdk.java.net/browse/JDK-8225377. So instead we have to use Compiler to compile
+ // the code here with a special annotation processor that will check the annotations of the
+ // just-compiled class. Since the processor is running as part of the same compilation, we don't
+ // lose the type annotations.
+
+ private static final ImmutableList<String> METHOD_LINES =
+ ImmutableList.of(
+ // Methods in this class whose names begin with "no" do not mention @Nullable anywhere.",
+ // All other methods do.",
+ "package foo.bar;",
+ "",
+ "import " + Irrelevant.class.getCanonicalName() + ";",
+ "import " + Nullable.class.getCanonicalName() + ";",
+ "import java.util.List;",
+ "",
+ "abstract class Methods {",
+ " void noAnnotations() {}",
+ " abstract int noAnnotationsEither(int x);",
+ " abstract @Irrelevant String noRelevantAnnotations(@Irrelevant int x);",
+ " abstract @Nullable String nullableString();",
+ " abstract String @Nullable [] nullableArrayOfString();",
+ " abstract @Nullable String[] arrayOfNullableString();",
+ " abstract @Nullable String @Nullable [] nullableArrayOfNullableString();",
+ " abstract List<@Nullable String> listOfNullableString();",
+ " abstract List<? extends @Nullable Object> listOfExtendsNullable();",
+ " abstract List<? super @Nullable Number> listOfSuperNullable();",
+ " abstract <T extends @Nullable Object> T nullableTypeParamBound();",
+ " abstract <T> @Nullable T nullableTypeParamRef();",
+ " void nullableParam(@Nullable String x) {}",
+ " void nullableParamBound(List<? extends @Nullable String> x) {}",
+ "}");
+
+ @Test
+ public void nullableMentionedInMethods() {
+ // Sadly we can't rely on JDK 8 to handle type annotations correctly.
+ // Some versions do, some don't. So skip the test unless we are on at least JDK 9.
+ double javaVersion = Double.parseDouble(JAVA_SPECIFICATION_VERSION.value());
+ assume().that(javaVersion).isAtLeast(9.0);
+ NullableProcessor processor = new NullableProcessor(expect);
+ Compilation compilation =
+ Compiler.javac()
+ .withProcessors(processor)
+ .compile(JavaFileObjects.forSourceLines("foo.bar.Methods", METHOD_LINES));
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(processor.ran).isTrue();
+ // If any `expect` calls failed then the test will fail now because of the Expect rule.
+ }
+
+ @SupportedAnnotationTypes("*")
+ private static class NullableProcessor extends AbstractProcessor {
+
+ private final Expect expect;
+ boolean ran;
+
+ NullableProcessor(Expect expect) {
+ this.expect = expect;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver()) {
+ TypeElement methodsElement =
+ processingEnv.getElementUtils().getTypeElement("foo.bar.Methods");
+ expect.that(methodsElement).isNotNull();
+
+ List<ExecutableElement> methods =
+ ElementFilter.methodsIn(methodsElement.getEnclosedElements());
+ Map<Boolean, List<ExecutableElement>> partitionedMethods =
+ methods.stream()
+ .collect(partitioningBy(p -> !p.getSimpleName().toString().startsWith("no")));
+ List<ExecutableElement> nullableMethods = partitionedMethods.get(true);
+ List<ExecutableElement> notNullableMethods = partitionedMethods.get(false);
+
+ expect
+ .about(optionals())
+ .that(Nullables.nullableMentionedInMethods(notNullableMethods))
+ .isEmpty();
+
+ TypeElement nullableElement =
+ processingEnv.getElementUtils().getTypeElement(Nullable.class.getCanonicalName());
+ expect.that(nullableElement).isNotNull();
+ DeclaredType nullableType = MoreTypes.asDeclared(nullableElement.asType());
+
+ for (ExecutableElement nullableMethod : nullableMethods) {
+ // Make a list with all the methods that don't have @Nullable plus one method that does.
+ ImmutableList<ExecutableElement> notNullablePlusNullable =
+ ImmutableList.<ExecutableElement>builder()
+ .addAll(notNullableMethods)
+ .add(nullableMethod)
+ .build();
+ expect
+ .withMessage("method %s should have @Nullable", nullableMethod)
+ .about(optionals())
+ .that(
+ Nullables.nullableMentionedInMethods(notNullablePlusNullable)
+ .map(AnnotationMirror::getAnnotationType))
+ .hasValue(nullableType);
+ }
+ ran = true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java b/value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java
index 2c3bea0d..48d8cd6e 100644
--- a/value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java
@@ -15,12 +15,13 @@
*/
package com.google.auto.value.processor;
-import static com.google.common.truth.Truth.assertAbout;
-import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static com.google.testing.compile.Compiler.javac;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
+import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@@ -40,8 +41,7 @@ import org.junit.runners.JUnit4;
*/
@RunWith(JUnit4.class)
public class PropertyAnnotationsTest {
- private static final String TEST_ANNOTATION =
- "@PropertyAnnotationsTest.TestAnnotation";
+ private static final String TEST_ANNOTATION = "@PropertyAnnotationsTest.TestAnnotation";
private static final String TEST_ARRAY_ANNOTATION =
"@PropertyAnnotationsTest.TestArrayAnnotation";
@@ -272,12 +272,15 @@ public class PropertyAnnotationsTest {
.addMethodAnnotations(expectedMethodAnnotations)
.build();
- assertAbout(javaSource())
- .that(javaFileObject)
- .processedWith(new AutoValueProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expectedOutput);
+ Compilation compilation =
+ javac()
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
+ .withProcessors(new AutoValueProcessor())
+ .compile(javaFileObject);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("foo.bar.AutoValue_Baz")
+ .hasSourceEquivalentTo(expectedOutput);
}
@Test
@@ -445,10 +448,12 @@ public class PropertyAnnotationsTest {
assertGeneratedMatches(
getImports(PropertyAnnotationsTest.class),
ImmutableList.of(
- TEST_ARRAY_ANNOTATION + "(testEnums = {PropertyAnnotationsTest.TestEnum.A,"
+ TEST_ARRAY_ANNOTATION
+ + "(testEnums = {PropertyAnnotationsTest.TestEnum.A,"
+ " PropertyAnnotationsTest.TestEnum.B})"),
ImmutableList.of(
- TEST_ARRAY_ANNOTATION + "(testEnums = {PropertyAnnotationsTest.TestEnum.A,"
+ TEST_ARRAY_ANNOTATION
+ + "(testEnums = {PropertyAnnotationsTest.TestEnum.A,"
+ " PropertyAnnotationsTest.TestEnum.B})"));
}
@@ -512,12 +517,15 @@ public class PropertyAnnotationsTest {
.addFieldAnnotations("@Deprecated", "@PropertyAnnotationsTest.InheritedAnnotation")
.build();
- assertAbout(javaSource())
- .that(inputFile)
- .processedWith(new AutoValueProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(outputFile);
+ Compilation compilation =
+ javac()
+ .withOptions("-A" + Nullables.NULLABLE_OPTION)
+ .withProcessors(new AutoValueProcessor())
+ .compile(inputFile);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("foo.bar.AutoValue_Baz")
+ .hasSourceEquivalentTo(outputFile);
}
/**
@@ -545,16 +553,17 @@ public class PropertyAnnotationsTest {
.setImports(getImports(PropertyAnnotationsTest.class))
.addFieldAnnotations("@Deprecated", "@PropertyAnnotationsTest.InheritedAnnotation")
.addMethodAnnotations(
- "@Deprecated",
- "@PropertyAnnotationsTest.InheritedAnnotation",
- "@Baz.MethodsOnly")
+ "@Deprecated", "@PropertyAnnotationsTest.InheritedAnnotation", "@Baz.MethodsOnly")
.build();
- assertAbout(javaSource())
- .that(inputFile)
- .processedWith(new AutoValueProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(outputFile);
+ Compilation compilation =
+ javac()
+ .withOptions("-A" + Nullables.NULLABLE_OPTION + "=")
+ .withProcessors(new AutoValueProcessor())
+ .compile(inputFile);
+ assertThat(compilation).succeeded();
+ assertThat(compilation)
+ .generatedSourceFile("foo.bar.AutoValue_Baz")
+ .hasSourceEquivalentTo(outputFile);
}
}
diff --git a/value/src/test/java/com/google/auto/value/processor/PropertyNamesTest.java b/value/src/test/java/com/google/auto/value/processor/PropertyNamesTest.java
index 7af240c6..d488e599 100644
--- a/value/src/test/java/com/google/auto/value/processor/PropertyNamesTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/PropertyNamesTest.java
@@ -34,14 +34,12 @@ public class PropertyNamesTest {
.put("x", "x")
.put("", "")
.build();
-
+
@Test
public void decapitalizeLikeJavaBeans() {
- NORMAL_CASES
- .forEach(
- (input, output) -> {
- expect.that(PropertyNames.decapitalizeLikeJavaBeans(input)).isEqualTo(output);
- });
+ NORMAL_CASES.forEach(
+ (input, output) ->
+ expect.that(PropertyNames.decapitalizeLikeJavaBeans(input)).isEqualTo(output));
expect.that(PropertyNames.decapitalizeLikeJavaBeans(null)).isNull();
expect.that(PropertyNames.decapitalizeLikeJavaBeans("HTMLPage")).isEqualTo("HTMLPage");
expect.that(PropertyNames.decapitalizeLikeJavaBeans("OAuth")).isEqualTo("OAuth");
@@ -49,11 +47,9 @@ public class PropertyNamesTest {
@Test
public void decapitalizeNormally() {
- NORMAL_CASES
- .forEach(
- (input, output) -> {
- expect.that(PropertyNames.decapitalizeNormally(input)).isEqualTo(output);
- });
+ NORMAL_CASES.forEach(
+ (input, output) ->
+ expect.that(PropertyNames.decapitalizeNormally(input)).isEqualTo(output));
expect.that(PropertyNames.decapitalizeNormally(null)).isNull();
expect.that(PropertyNames.decapitalizeNormally("HTMLPage")).isEqualTo("hTMLPage");
expect.that(PropertyNames.decapitalizeNormally("OAuth")).isEqualTo("oAuth");
diff --git a/value/src/test/java/com/google/auto/value/processor/ReformatterTest.java b/value/src/test/java/com/google/auto/value/processor/ReformatterTest.java
index 98d31b48..48ecf5be 100644
--- a/value/src/test/java/com/google/auto/value/processor/ReformatterTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/ReformatterTest.java
@@ -15,7 +15,7 @@
*/
package com.google.auto.value.processor;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,7 +29,7 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class ReformatterTest {
@Test
- public void testSimple() {
+ public void simple() {
String input =
"\n"
+ "package com.latin.declension; \n"
@@ -50,7 +50,7 @@ public class ReformatterTest {
+ "\n"
+ " Eodem ( Eadem eodem ) { }\n";
String output =
- "package com.latin.declension;\n"
+ "package com.latin.declension;\n"
+ "\n"
+ "public class Idem {\n"
+ "\n"
@@ -62,11 +62,11 @@ public class ReformatterTest {
+ " }\n"
+ "\n"
+ " Eodem (Eadem eodem) { }\n";
- assertEquals(output, Reformatter.fixup(input));
+ assertThat(Reformatter.fixup(input)).isEqualTo(output);
}
@Test
- public void testSpecialSpaces() {
+ public void specialSpaces() {
String input =
"\n"
+ "package com.example.whatever;\n"
@@ -79,7 +79,7 @@ public class ReformatterTest {
+ " static final char QUOTE2 = '\\\"' ;\n"
+ "}\n";
String output =
- "package com.example.whatever;\n"
+ "package com.example.whatever;\n"
+ "\n"
+ "public class SomeClass {\n"
+ " static final String STRING = \" hello world \\n\";\n"
@@ -88,13 +88,66 @@ public class ReformatterTest {
+ " static final char QUOTE = '\"';\n"
+ " static final char QUOTE2 = '\\\"';\n"
+ "}\n";
- assertEquals(output, Reformatter.fixup(input));
+ assertThat(Reformatter.fixup(input)).isEqualTo(output);
}
@Test
public void noTrailingNewline() {
String input = "package com.example.whatever;\n\npublic class SomeClass {}";
String output = input + "\n";
- assertEquals(output, Reformatter.fixup(input));
+ assertThat(Reformatter.fixup(input)).isEqualTo(output);
+ }
+
+ @Test
+ public void indent() {
+ String input =
+ " class Test {\n"
+ + "private final int field;\n"
+ + "\n"
+ + "Test(\n"
+ + "@Interesting Integer field,\n"
+ + "boolean ignored) {\n"
+ + "this.field = field;\n"
+ + "}\n"
+ + "\n"
+ + "@Override\n"
+ + "public boolean equals(Object x) {\n"
+ + "return x instanceof Test\n"
+ + "&& ((Test) x).field == field;\n"
+ + "// interesting\n"
+ + "}\n"
+ + "\n"
+ + "@Override\n"
+ + "public String toString() {\n"
+ + "return \"Test{\"\n"
+ + "+ \"field=\" + field\n"
+ + "+ \"}\";\n"
+ + "}\n"
+ + "}\n";
+ String output =
+ "class Test {\n"
+ + " private final int field;\n"
+ + "\n"
+ + " Test(\n"
+ + " @Interesting Integer field,\n"
+ + " boolean ignored) {\n"
+ + " this.field = field;\n"
+ + " }\n"
+ + "\n"
+ + " @Override\n"
+ + " public boolean equals(Object x) {\n"
+ + " return x instanceof Test\n"
+ + " && ((Test) x).field == field;\n"
+ + " // interesting\n"
+ + " }\n"
+ + "\n"
+ + " @Override\n"
+ + " public String toString() {\n"
+ + " return \"Test{\"\n"
+ + " + \"field=\" + field\n"
+ + " + \"}\";\n"
+ + " }\n"
+ + "}\n";
+ assertThat(Reformatter.fixup(input)).isEqualTo(output);
}
}
diff --git a/value/src/test/java/com/google/auto/value/processor/SimpleServiceLoaderTest.java b/value/src/test/java/com/google/auto/value/processor/SimpleServiceLoaderTest.java
index fab18056..5e2d230d 100644
--- a/value/src/test/java/com/google/auto/value/processor/SimpleServiceLoaderTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/SimpleServiceLoaderTest.java
@@ -28,6 +28,8 @@ import java.io.PrintWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.ServiceConfigurationError;
@@ -54,6 +56,35 @@ public final class SimpleServiceLoaderTest {
assertThat(classes).containsExactly(String.class, StringBuilder.class).inOrder();
}
+ // Sometimes you can have the same jar appear more than once in the classpath, perhaps in
+ // different versions. In that case we don't want to instantiate the same class more than once.
+ // This test checks that we don't.
+ @Test
+ public void loadWithDuplicates() throws Exception {
+ ClassLoader loader1 =
+ loaderForJarWithEntries(
+ CharSequence.class.getName(), String.class.getName(), StringBuilder.class.getName());
+ ClassLoader loader2 =
+ loaderForJarWithEntries(
+ CharSequence.class.getName(), String.class.getName(), StringBuilder.class.getName());
+ ClassLoader combinedLoader =
+ new ClassLoader() {
+ @Override
+ public Enumeration<URL> getResources(String name) throws IOException {
+ List<URL> urls = new ArrayList<>(Collections.list(loader1.getResources(name)));
+ urls.addAll(Collections.list(loader2.getResources(name)));
+ return Collections.enumeration(urls);
+ }
+ };
+
+ ImmutableList<CharSequence> providers =
+ SimpleServiceLoader.load(CharSequence.class, combinedLoader);
+
+ assertThat(providers).contains("");
+ List<Class<?>> classes = providers.stream().map(Object::getClass).collect(toList());
+ assertThat(classes).containsExactly(String.class, StringBuilder.class).inOrder();
+ }
+
@Test
public void blankLinesAndComments() throws Exception {
ClassLoader loader =
diff --git a/value/src/test/java/com/google/auto/value/processor/SimplifyWithAnnotationsTest.java b/value/src/test/java/com/google/auto/value/processor/SimplifyWithAnnotationsTest.java
index 39e2dc0e..7bc67790 100644
--- a/value/src/test/java/com/google/auto/value/processor/SimplifyWithAnnotationsTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/SimplifyWithAnnotationsTest.java
@@ -157,8 +157,7 @@ public class SimplifyWithAnnotationsTest {
void testTypeSpellings(TypeElement testClass) {
ExecutableElement witness =
- ElementFilter.methodsIn(testClass.getEnclosedElements())
- .stream()
+ ElementFilter.methodsIn(testClass.getEnclosedElements()).stream()
.filter(m -> m.getSimpleName().contentEquals("witness"))
.collect(onlyElement());
if (witness.getReturnType().getAnnotationMirrors().isEmpty()) {
diff --git a/value/src/test/java/com/google/auto/value/processor/TypeEncoderTest.java b/value/src/test/java/com/google/auto/value/processor/TypeEncoderTest.java
index c31f711e..83951e0a 100644
--- a/value/src/test/java/com/google/auto/value/processor/TypeEncoderTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/TypeEncoderTest.java
@@ -292,7 +292,7 @@ public class TypeEncoderTest {
TypeMirror multipleBoundsMirror = multipleBoundsElement.asType();
String text = "`import`\n";
text += "{" + TypeEncoder.encode(multipleBoundsMirror) + "}";
- text += "{" + TypeEncoder.formalTypeParametersString(multipleBoundsElement) + "}";
+ text += "{" + TypeEncoder.typeParametersString(multipleBoundsElement.getTypeParameters()) + "}";
String myPackage = getClass().getPackage().getName();
String decoded =
TypeEncoder.decode(text, elementUtils, typeUtils, myPackage, baseWithoutContainedTypes());
@@ -306,6 +306,7 @@ public class TypeEncoderTest {
@SuppressWarnings("ClassCanBeStatic")
static class Outer<T extends Number> {
class InnerWithoutTypeParam {}
+
class Middle<U> {
class InnerWithTypeParam<V> {}
}
diff --git a/value/src/test/java/com/google/auto/value/processor/TypeVariablesTest.java b/value/src/test/java/com/google/auto/value/processor/TypeVariablesTest.java
index 078ef513..895bed25 100644
--- a/value/src/test/java/com/google/auto/value/processor/TypeVariablesTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/TypeVariablesTest.java
@@ -115,10 +115,12 @@ public class TypeVariablesTest {
abstract static class Outer<T, U extends T> {
abstract Map<T, U> getFoo();
+
abstract List<? extends T> getBar();
abstract static class Inner<T, U extends T> {
abstract void setFoo(Map<T, U> foo);
+
abstract void setBar(List<? extends T> bar);
}
}
@@ -165,13 +167,15 @@ public class TypeVariablesTest {
List<ExecutableElement> immutableMapMethods =
ElementFilter.methodsIn(immutableMap.getEnclosedElements());
ExecutableElement copyOf = methodNamed(immutableMapMethods, "copyOf", erasedMap);
- expect.that(
- TypeVariables.canAssignStaticMethodResult(
- copyOf, immutableMapStringInteger, immutableMapStringNumber, typeUtils))
+ expect
+ .that(
+ TypeVariables.canAssignStaticMethodResult(
+ copyOf, immutableMapStringInteger, immutableMapStringNumber, typeUtils))
.isTrue();
- expect.that(
- TypeVariables.canAssignStaticMethodResult(
- copyOf, immutableMapStringNumber, immutableMapStringInteger, typeUtils))
+ expect
+ .that(
+ TypeVariables.canAssignStaticMethodResult(
+ copyOf, immutableMapStringNumber, immutableMapStringInteger, typeUtils))
.isFalse();
}
@@ -184,7 +188,9 @@ public class TypeVariablesTest {
return methods.stream()
.filter(m -> m.getSimpleName().contentEquals(name))
.filter(m -> m.getParameters().size() == 1)
- .filter(m -> typeUtils.isSameType(
+ .filter(
+ m ->
+ typeUtils.isSameType(
erasedParameterType, typeUtils.erasure(m.getParameters().get(0).asType())))
.findFirst()
.get();