aboutsummaryrefslogtreecommitdiff
path: root/value/src/it/functional
diff options
context:
space:
mode:
Diffstat (limited to 'value/src/it/functional')
-rw-r--r--value/src/it/functional/pom.xml98
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/AutoAnnotationTest.java93
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderKotlinTest.java99
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderTest.java580
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/AutoOneOfTest.java10
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java60
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java224
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java44
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/GradleTest.java187
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/KotlinData.kt22
-rw-r--r--value/src/it/functional/src/test/java/com/google/auto/value/gwt/EmptyExtension.java3
11 files changed, 1360 insertions, 60 deletions
diff --git a/value/src/it/functional/pom.xml b/value/src/it/functional/pom.xml
index 750b9c43..d4ae1386 100644
--- a/value/src/it/functional/pom.xml
+++ b/value/src/it/functional/pom.xml
@@ -32,6 +32,7 @@
<version>1.7.4</version>
<name>Auto-Value Functional Integration Test</name>
<properties>
+ <kotlin.version>1.5.21</kotlin.version>
<exclude.tests>this-matches-nothing</exclude.tests>
</properties>
<dependencies>
@@ -48,7 +49,7 @@
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
- <version>1.0-rc6</version>
+ <version>1.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
@@ -62,7 +63,7 @@
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
- <version>2.8.2</version>
+ <version>2.9.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -90,21 +91,32 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>dev.gradleplugins</groupId>
+ <artifactId>gradle-test-kit</artifactId>
+ <version>6.8.3</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
- <version>3.1.0</version>
+ <version>3.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>ecj</artifactId>
- <version>3.20.0</version>
+ <version>3.25.0</version>
</dependency>
<dependency>
<groupId>com.google.escapevelocity</groupId>
<artifactId>escapevelocity</artifactId>
<version>0.9.1</version>
</dependency>
+ <dependency>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-stdlib</artifactId>
+ <version>${kotlin.version}</version>
+ </dependency>
</dependencies>
<build>
@@ -112,17 +124,49 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>3.0.2</version>
+ <version>3.2.0</version>
+ </plugin>
+ <plugin>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-maven-plugin</artifactId>
+ <version>${kotlin.version}</version>
+ <executions>
+ <!--
+ The Kotlin configuration here is a bit unusual. JetBrains recommends
+ <https://kotlinlang.org/docs/maven.html#compile-kotlin-and-java-sources>
+ a fairly invasive reconfiguration of the maven-compiler-plugin (which compiles Java)
+ in order to ensure that the Kotlin compiler can run first. In our case, we have just
+ one Kotlin file that a test in Java accesses. So, even though it is in src/test/java,
+ we compile it in the `compile` goal, which means it is available to the Java test sources
+ when they are compiled in the `default-testCompile` goal.
+
+ Currently if you want to use JDK ≥ 16 then you must set
+ JAVA_TOOL_OPTIONS=__illegal-access=permit
+ except the two underscores should be dashes (which XML comments won't allow us to write).
+ This is a bug that will presumably be fixed in a forthcoming version.
+ -->
+ <execution>
+ <id>compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <sourceDirs>
+ <sourceDir>${project.basedir}/src/test/java</sourceDir>
+ </sourceDirs>
+ </configuration>
+ </execution>
+ </executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.7.0</version>
+ <version>3.8.1</version>
<dependencies>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-java</artifactId>
- <version>0.9.4</version>
+ <version>1.0.7</version>
</dependency>
</dependencies>
<configuration>
@@ -132,6 +176,7 @@
<arg>-Xlint:all</arg>
<arg>-encoding</arg>
<arg>utf8</arg>
+ <arg>-Acom.google.auto.value.AutoBuilderIsUnstable</arg>
</compilerArgs>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
@@ -143,12 +188,23 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
- <version>2.7</version>
+ <version>2.8.2</version>
<configuration>
<!-- Build/test, but don't deploy -->
<skip>true</skip>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.22.2</version>
+ <configuration>
+ <argLine>${test.jvm.flags}</argLine>
+ <systemPropertyVariables>
+ <autoValueVersion>${project.version}</autoValueVersion>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
</plugins>
</build>
@@ -160,12 +216,12 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.7.0</version>
+ <version>3.8.1</version>
<dependencies>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-java</artifactId>
- <version>0.9.4</version>
+ <version>1.0.7</version>
</dependency>
</dependencies>
<configuration>
@@ -195,5 +251,27 @@
<exclude.tests>**/AutoValueJava8Test.java</exclude.tests>
</properties>
</profile>
+ <profile>
+ <id>open-modules</id>
+ <activation>
+ <jdk>[9,)</jdk>
+ </activation>
+ <properties>
+ <test.jvm.flags>--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</test.jvm.flags>
+ </properties>
+ </profile>
+ <profile>
+ <!-- Before JDK 11, parameter names from already-compiled classes are not reliably available
+ to the compiler even when they are present in class files. Since our Kotlin test file
+ obviously has to be compiled separately from the Java test that uses it,
+ AutoBuilderKotlinTest doesn't pass on earlier JDK versions. -->
+ <id>exclude-separate-compilation-parameter-names</id>
+ <activation>
+ <jdk>(,11)</jdk>
+ </activation>
+ <properties>
+ <exclude.tests>**/AutoBuilderKotlinTest.java</exclude.tests>
+ </properties>
+ </profile>
</profiles>
</project>
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoAnnotationTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoAnnotationTest.java
index ca1ef6b9..a04d41f3 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/AutoAnnotationTest.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoAnnotationTest.java
@@ -15,20 +15,24 @@
*/
package com.google.auto.value;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.TruthJUnit.assume;
import com.google.auto.value.annotations.Empty;
import com.google.auto.value.annotations.GwtArrays;
import com.google.auto.value.annotations.StringValues;
+import com.google.common.base.StandardSystemProperty;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.primitives.Ints;
import com.google.common.testing.EqualsTester;
+import com.google.common.testing.SerializableTester;
+import java.io.ObjectStreamClass;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -38,6 +42,7 @@ import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import org.junit.AssumptionViolatedException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -66,13 +71,41 @@ public class AutoAnnotationTest {
}
@Test
+ public void testEqualsParameterAnnotation() throws ReflectiveOperationException {
+ assume()
+ .that(Double.parseDouble(StandardSystemProperty.JAVA_SPECIFICATION_VERSION.value()))
+ .isAtLeast(8.0);
+ Class<? extends Annotation> jspecifyNullable;
+ try {
+ // We write this using .concat in order to hide it from rewriting rules.
+ jspecifyNullable =
+ Class.forName("org".concat(".jspecify.nullness.Nullable")).asSubclass(Annotation.class);
+ } catch (ClassNotFoundException e) {
+ throw new AssumptionViolatedException("No JSpecify @Nullable available", e);
+ }
+ @SuppressWarnings("GetClassOnAnnotation") // yes, I really want the implementation class
+ Class<? extends StringValues> autoAnnotationImpl = newStringValues(new String[0]).getClass();
+ Method equals = autoAnnotationImpl.getDeclaredMethod("equals", Object.class);
+ // The remaining faffing around with reflection is there because we have a Google-internal test
+ // that runs this code with -source 7 -target 7. We're really just doing this:
+ // assertThat(equals.getAnnotatedParameterTypes()[0].isAnnotationPresent(jspecifyNullable))
+ // .isTrue();
+ Method getAnnotatedParameterTypes = Method.class.getMethod("getAnnotatedParameterTypes");
+ Object[] annotatedParameterTypes = (Object[]) getAnnotatedParameterTypes.invoke(equals);
+ Method isAnnotationPresent =
+ annotatedParameterTypes[0].getClass().getMethod("isAnnotationPresent", Class.class);
+ assertThat(isAnnotationPresent.invoke(annotatedParameterTypes[0], jspecifyNullable))
+ .isEqualTo(true);
+ }
+
+ @Test
public void testArraysAreCloned() {
String[] array = {"Jekyll"};
StringValues stringValues = newStringValues(array);
array[0] = "Hyde";
- assertEquals("Jekyll", stringValues.value()[0]);
+ assertThat(stringValues.value()).asList().containsExactly("Jekyll");
stringValues.value()[0] = "Hyde";
- assertEquals("Jekyll", stringValues.value()[0]);
+ assertThat(stringValues.value()[0]).isEqualTo("Jekyll");
}
@Test
@@ -80,12 +113,12 @@ public class AutoAnnotationTest {
String[] strings = {"Jekyll"};
int[] ints = {2, 3, 5};
GwtArrays arrays = newGwtArrays(strings, ints);
- assertEquals(ImmutableList.of("Jekyll"), ImmutableList.copyOf(arrays.strings()));
- assertEquals(ImmutableList.of(2, 3, 5), Ints.asList(arrays.ints()));
+ assertThat(arrays.strings()).asList().containsExactly("Jekyll");
+ assertThat(arrays.ints()).asList().containsExactly(2, 3, 5).inOrder();
strings[0] = "Hyde";
ints[0] = -1;
- assertEquals(ImmutableList.of("Jekyll"), ImmutableList.copyOf(arrays.strings()));
- assertEquals(ImmutableList.of(2, 3, 5), Ints.asList(arrays.ints()));
+ assertThat(arrays.strings()).asList().containsExactly("Jekyll");
+ assertThat(arrays.ints()).asList().containsExactly(2, 3, 5).inOrder();
}
@AutoAnnotation
@@ -406,7 +439,39 @@ public class AutoAnnotationTest {
.testEquals();
}
+ @Test
+ public void testSerialization() {
+ Annotation[] instances = {EVERYTHING_FROM_AUTO, EVERYTHING_FROM_AUTO_COLLECTIONS};
+ for (Annotation instance : instances) {
+ SerializableTester.reserializeAndAssert(instance);
+ }
+ }
+
+ @Test
+ @SuppressWarnings("GetClassOnAnnotation") // yes, we really do want the implementation classes
+ public void testSerialVersionUid() {
+ Class<? extends Everything> everythingImpl = EVERYTHING_FROM_AUTO.getClass();
+ Class<? extends Everything> everythingFromCollectionsImpl =
+ EVERYTHING_FROM_AUTO_COLLECTIONS.getClass();
+ assertThat(everythingImpl).isNotEqualTo(everythingFromCollectionsImpl);
+ long everythingUid = ObjectStreamClass.lookup(everythingImpl).getSerialVersionUID();
+ long everythingFromCollectionsUid =
+ ObjectStreamClass.lookup(everythingFromCollectionsImpl).getSerialVersionUID();
+ // Two different implementations of the same annotation with the same members being provided
+ // (not defaulted) should have the same serialVersionUID. They won't be serial-compatible, of
+ // course, because their classes are different. So we're really just checking that the
+ // serialVersionUID depends only on the names and types of those members.
+ assertThat(everythingFromCollectionsUid).isEqualTo(everythingUid);
+ Class<? extends StringValues> stringValuesImpl = newStringValues(new String[0]).getClass();
+ long stringValuesUid = ObjectStreamClass.lookup(stringValuesImpl).getSerialVersionUID();
+ // The previous assertion would be vacuously true if every implementation had the same
+ // serialVersionUID, so check that that's not true.
+ assertThat(stringValuesUid).isNotEqualTo(everythingUid);
+ }
+
public static class IntList extends ArrayList<Integer> {
+ private static final long serialVersionUID = 1L;
+
IntList(Collection<Integer> c) {
super(c);
}
@@ -440,7 +505,7 @@ public class AutoAnnotationTest {
IntList intList = new IntList(ImmutableList.of(1, 2, 3));
IntArray actual = newIntArray(intList);
IntArray expected = AnnotatedWithIntArray.class.getAnnotation(IntArray.class);
- assertEquals(expected, actual);
+ assertThat(actual).isEqualTo(expected);
}
@Test
@@ -461,8 +526,8 @@ public class AutoAnnotationTest {
+ "@com.google.auto.value.annotations.StringValues([\"foo\", \"bar\"])"
+ "]"
+ ")";
- assertEquals(expected, EVERYTHING_FROM_AUTO.toString());
- assertEquals(expected, EVERYTHING_FROM_AUTO_COLLECTIONS.toString());
+ assertThat(EVERYTHING_FROM_AUTO.toString()).isEqualTo(expected);
+ assertThat(EVERYTHING_FROM_AUTO_COLLECTIONS.toString()).isEqualTo(expected);
}
@Test
@@ -475,7 +540,7 @@ public class AutoAnnotationTest {
String expected =
"@com.google.auto.value.annotations.StringValues("
+ "[\"\", \"\\r\\n\", \"hello, world\", \"Éamonn\", \"\\007\\uffef\"])";
- assertEquals(expected, instance.toString());
+ assertThat(instance.toString()).isEqualTo(expected);
}
@Retention(RetentionPolicy.RUNTIME)
@@ -498,7 +563,7 @@ public class AutoAnnotationTest {
ImmutableList.<Class<? extends Annotation>>of(AnnotationsAnnotation.class));
AnnotationsAnnotation fromReflect =
AnnotatedWithAnnotationsAnnotation.class.getAnnotation(AnnotationsAnnotation.class);
- assertEquals(fromReflect, generated);
+ assertThat(generated).isEqualTo(fromReflect);
}
@Retention(RetentionPolicy.RUNTIME)
@@ -520,7 +585,7 @@ public class AutoAnnotationTest {
newClassesAnnotation(Arrays.<Class<?>>asList(AnnotationsAnnotation.class));
ClassesAnnotation fromReflect =
AnnotatedWithClassesAnnotation.class.getAnnotation(ClassesAnnotation.class);
- assertEquals(fromReflect, generated);
+ assertThat(generated).isEqualTo(fromReflect);
}
@Retention(RetentionPolicy.RUNTIME)
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderKotlinTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderKotlinTest.java
new file mode 100644
index 00000000..1dc346c9
--- /dev/null
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderKotlinTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AutoBuilderKotlinTest {
+ @AutoBuilder(ofClass = KotlinData.class)
+ abstract static class KotlinDataBuilder {
+ static KotlinDataBuilder builder() {
+ return new AutoBuilder_AutoBuilderKotlinTest_KotlinDataBuilder();
+ }
+
+ abstract KotlinDataBuilder setInt(int x);
+
+ abstract KotlinDataBuilder setString(String x);
+
+ abstract KotlinData build();
+ }
+
+ @Test
+ public void simpleKotlin() {
+ KotlinData x = KotlinDataBuilder.builder().setInt(23).setString("skidoo").build();
+ assertThat(x.getInt()).isEqualTo(23);
+ assertThat(x.getString()).isEqualTo("skidoo");
+ }
+
+ @AutoBuilder(ofClass = KotlinDataWithNullable.class)
+ abstract static class KotlinDataWithNullableBuilder {
+ static KotlinDataWithNullableBuilder builder() {
+ return new AutoBuilder_AutoBuilderKotlinTest_KotlinDataWithNullableBuilder();
+ }
+
+ abstract KotlinDataWithNullableBuilder setAnInt(int x);
+
+ abstract KotlinDataWithNullableBuilder setAString(String x);
+
+ abstract KotlinDataWithNullable build();
+ }
+
+ @Test
+ public void kotlinWithNullable() {
+ KotlinDataWithNullable empty = KotlinDataWithNullableBuilder.builder().build();
+ assertThat(empty.getAnInt()).isNull();
+ assertThat(empty.getAString()).isNull();
+
+ KotlinDataWithNullable notEmpty =
+ KotlinDataWithNullableBuilder.builder().setAString("answer").setAnInt(42).build();
+ assertThat(notEmpty.getAString()).isEqualTo("answer");
+ assertThat(notEmpty.getAnInt()).isEqualTo(42);
+ }
+
+ @AutoBuilder(ofClass = KotlinDataWithDefaults.class)
+ abstract static class KotlinDataWithDefaultsBuilder {
+ static KotlinDataWithDefaultsBuilder builder() {
+ return new AutoBuilder_AutoBuilderKotlinTest_KotlinDataWithDefaultsBuilder();
+ }
+
+ abstract KotlinDataWithDefaultsBuilder setAnInt(int x);
+
+ abstract KotlinDataWithDefaultsBuilder setAString(String x);
+
+ abstract KotlinDataWithDefaults build();
+ }
+
+ @Test
+ public void kotlinWithDefaults() {
+ // AutoBuilder doesn't currently try to give the builder the same defaults as the Kotlin class,
+ // but we do at least check that the presence of defaults doesn't throw AutoBuilder off.
+ // When a constructor has default parameters, the Kotlin compiler generates an extra constructor
+ // with two extra parameters: an int bitmask saying which parameters were defaulted, and a
+ // DefaultConstructorMarker parameter to avoid clashing with another constructor that might have
+ // an extra int parameter for some other reason. If AutoBuilder found this constructor it might
+ // be confused, but fortunately the constructor is marked synthetic, and javax.lang.model
+ // doesn't show synthetic elements.
+ KotlinDataWithDefaults x =
+ KotlinDataWithDefaultsBuilder.builder().setAString("answer").setAnInt(42).build();
+ assertThat(x.getAString()).isEqualTo("answer");
+ assertThat(x.getAnInt()).isEqualTo(42);
+ }
+}
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderTest.java
new file mode 100644
index 00000000..952edaac
--- /dev/null
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderTest.java
@@ -0,0 +1,580 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth8.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.time.LocalTime;
+import java.util.AbstractSet;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AutoBuilderTest {
+ static class Simple {
+ private final int anInt;
+ private final String aString;
+
+ Simple(int anInt, String aString) {
+ this.anInt = anInt;
+ this.aString = aString;
+ }
+
+ static Simple of(int anInt, String aString) {
+ return new Simple(anInt, aString);
+ }
+
+ @Override
+ public boolean equals(Object x) {
+ if (x instanceof Simple) {
+ Simple that = (Simple) x;
+ return this.anInt == that.anInt && Objects.equals(this.aString, that.aString);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(anInt, aString);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("anInt", anInt)
+ .add("aString", aString)
+ .toString();
+ }
+
+ static Builder builder() {
+ return new AutoBuilder_AutoBuilderTest_Simple_Builder();
+ }
+
+ @AutoBuilder
+ abstract static class Builder {
+ abstract Builder setAnInt(int x);
+
+ abstract Builder setAString(String x);
+
+ abstract Simple build();
+ }
+ }
+
+ @Test
+ public void simple() {
+ Simple x = Simple.builder().setAnInt(23).setAString("skidoo").build();
+ assertThat(x).isEqualTo(new Simple(23, "skidoo"));
+ }
+
+ @AutoValue
+ abstract static class SimpleAuto {
+ abstract int getFoo();
+
+ abstract String getBar();
+
+ static Builder builder() {
+ return new AutoBuilder_AutoBuilderTest_SimpleAuto_Builder();
+ }
+
+ // There's no particular reason to do this since @AutoValue.Builder works just as well, but
+ // let's check anyway.
+ @AutoBuilder(ofClass = AutoValue_AutoBuilderTest_SimpleAuto.class)
+ abstract static class Builder {
+ abstract Builder setFoo(int x);
+
+ abstract Builder setBar(String x);
+
+ abstract AutoValue_AutoBuilderTest_SimpleAuto build();
+ }
+ }
+
+ @Test
+ public void simpleAuto() {
+ SimpleAuto x = SimpleAuto.builder().setFoo(23).setBar("skidoo").build();
+ assertThat(x.getFoo()).isEqualTo(23);
+ assertThat(x.getBar()).isEqualTo("skidoo");
+ }
+
+ enum Truthiness {
+ FALSY,
+ TRUTHY
+ }
+
+ @interface MyAnnotation {
+ String value();
+
+ int DEFAULT_ID = -1;
+
+ int id() default DEFAULT_ID;
+
+ Truthiness DEFAULT_TRUTHINESS = Truthiness.FALSY;
+
+ Truthiness truthiness() default Truthiness.FALSY;
+ }
+
+ // This method has a parameter for `truthiness`, even though that has a default, but it has no
+ // parameter for `id`, which also has a default.
+ @AutoAnnotation
+ static MyAnnotation myAnnotation(String value, Truthiness truthiness) {
+ return new AutoAnnotation_AutoBuilderTest_myAnnotation(value, truthiness);
+ }
+
+ @AutoBuilder(callMethod = "myAnnotation")
+ interface MyAnnotationBuilder {
+ MyAnnotationBuilder value(String x);
+
+ MyAnnotationBuilder truthiness(Truthiness x);
+
+ MyAnnotation build();
+ }
+
+ static MyAnnotationBuilder myAnnotationBuilder() {
+ return new AutoBuilder_AutoBuilderTest_MyAnnotationBuilder()
+ .truthiness(MyAnnotation.DEFAULT_TRUTHINESS);
+ }
+
+ @Test
+ public void simpleAutoAnnotation() {
+ MyAnnotation annotation1 = myAnnotationBuilder().value("foo").build();
+ assertThat(annotation1.value()).isEqualTo("foo");
+ assertThat(annotation1.id()).isEqualTo(MyAnnotation.DEFAULT_ID);
+ assertThat(annotation1.truthiness()).isEqualTo(MyAnnotation.DEFAULT_TRUTHINESS);
+ MyAnnotation annotation2 =
+ myAnnotationBuilder().value("bar").truthiness(Truthiness.TRUTHY).build();
+ assertThat(annotation2.value()).isEqualTo("bar");
+ assertThat(annotation2.id()).isEqualTo(MyAnnotation.DEFAULT_ID);
+ assertThat(annotation2.truthiness()).isEqualTo(Truthiness.TRUTHY);
+ }
+
+ static class Overload {
+ final int anInt;
+ final String aString;
+ final BigInteger aBigInteger;
+
+ Overload(int anInt, String aString) {
+ this(anInt, aString, BigInteger.ZERO);
+ }
+
+ Overload(int anInt, String aString, BigInteger aBigInteger) {
+ this.anInt = anInt;
+ this.aString = aString;
+ this.aBigInteger = aBigInteger;
+ }
+
+ @Override
+ public boolean equals(Object x) {
+ if (x instanceof Overload) {
+ Overload that = (Overload) x;
+ return this.anInt == that.anInt
+ && Objects.equals(this.aString, that.aString)
+ && Objects.equals(this.aBigInteger, that.aBigInteger);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(anInt, aString, aBigInteger);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("anInt", anInt)
+ .add("aString", aString)
+ .add("aBigInteger", aBigInteger)
+ .toString();
+ }
+
+ static Builder1 builder1() {
+ return new AutoBuilder_AutoBuilderTest_Overload_Builder1();
+ }
+
+ static Builder2 builder2() {
+ return new AutoBuilder_AutoBuilderTest_Overload_Builder2();
+ }
+
+ @AutoBuilder
+ interface Builder1 {
+ Builder1 setAnInt(int x);
+
+ Builder1 setAString(String x);
+
+ Overload build();
+ }
+
+ @AutoBuilder
+ interface Builder2 {
+ Builder2 setAnInt(int x);
+
+ Builder2 setAString(String x);
+
+ Builder2 setABigInteger(BigInteger x);
+
+ Overload build();
+ }
+ }
+
+ @Test
+ public void overloadedConstructor() {
+ Overload actual1 = Overload.builder1().setAnInt(23).setAString("skidoo").build();
+ Overload expected1 = new Overload(23, "skidoo");
+ assertThat(actual1).isEqualTo(expected1);
+
+ BigInteger big17 = BigInteger.valueOf(17);
+ Overload actual2 =
+ Overload.builder2().setAnInt(17).setAString("17").setABigInteger(big17).build();
+ Overload expected2 = new Overload(17, "17", big17);
+ assertThat(actual2).isEqualTo(expected2);
+ }
+
+ @AutoBuilder(callMethod = "of", ofClass = Simple.class)
+ interface SimpleStaticBuilder {
+ SimpleStaticBuilder anInt(int x);
+
+ SimpleStaticBuilder aString(String x);
+
+ Simple build();
+ }
+
+ static SimpleStaticBuilder simpleStaticBuilder() {
+ return new AutoBuilder_AutoBuilderTest_SimpleStaticBuilder();
+ }
+
+ @Test
+ public void staticMethod() {
+ Simple actual = simpleStaticBuilder().anInt(17).aString("17").build();
+ Simple expected = new Simple(17, "17");
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ // We can't be sure that the java.time package has parameter names, so we use this intermediary.
+ // Otherwise we could just write @AutoBuilder(callMethod = "of", ofClass = LocalTime.class).
+ // It's still interesting to test this as a realistic example.
+ static LocalTime localTimeOf(int hour, int minute, int second, int nanoOfSecond) {
+ return LocalTime.of(hour, minute, second, nanoOfSecond);
+ }
+
+ static LocalTimeBuilder localTimeBuilder() {
+ return new AutoBuilder_AutoBuilderTest_LocalTimeBuilder().nanoOfSecond(0);
+ }
+
+ @AutoBuilder(callMethod = "localTimeOf")
+ interface LocalTimeBuilder {
+ LocalTimeBuilder hour(int hour);
+
+ LocalTimeBuilder minute(int minute);
+
+ LocalTimeBuilder second(int second);
+
+ LocalTimeBuilder nanoOfSecond(int nanoOfSecond);
+
+ LocalTime build();
+ }
+
+ @Test
+ public void staticMethodOfContainingClass() {
+ LocalTime actual = localTimeBuilder().hour(12).minute(34).second(56).build();
+ LocalTime expected = LocalTime.of(12, 34, 56);
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void missingRequiredProperty() {
+ // This test is compiled at source level 7 by CompileWithEclipseTest, so we can't use
+ // assertThrows with a lambda.
+ try {
+ localTimeBuilder().hour(12).minute(34).build();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessageThat().isEqualTo("Missing required properties: second");
+ }
+ }
+
+ static void throwException() throws IOException {
+ throw new IOException("oops");
+ }
+
+ static ThrowExceptionBuilder throwExceptionBuilder() {
+ return new AutoBuilder_AutoBuilderTest_ThrowExceptionBuilder();
+ }
+
+ @AutoBuilder(callMethod = "throwException")
+ interface ThrowExceptionBuilder {
+ void build() throws IOException;
+ }
+
+ @Test
+ public void emptyBuilderThrowsException() {
+ try {
+ throwExceptionBuilder().build();
+ fail();
+ } catch (IOException expected) {
+ assertThat(expected).hasMessageThat().isEqualTo("oops");
+ }
+ }
+
+ static class ListContainer {
+ private final ImmutableList<String> list;
+
+ ListContainer(ImmutableList<String> list) {
+ this.list = checkNotNull(list);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof ListContainer && list.equals(((ListContainer) o).list);
+ }
+
+ @Override
+ public int hashCode() {
+ return list.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return list.toString();
+ }
+
+ static Builder builder() {
+ return new AutoBuilder_AutoBuilderTest_ListContainer_Builder();
+ }
+
+ @AutoBuilder
+ interface Builder {
+ Builder setList(Iterable<String> list);
+
+ ImmutableList.Builder<String> listBuilder();
+
+ ListContainer build();
+ }
+ }
+
+ @Test
+ public void propertyBuilder() {
+ ListContainer expected = new ListContainer(ImmutableList.of("one", "two", "three"));
+ ListContainer actual1 =
+ ListContainer.builder().setList(ImmutableList.of("one", "two", "three")).build();
+ assertThat(actual1).isEqualTo(expected);
+
+ ListContainer.Builder builder2 = ListContainer.builder();
+ builder2.listBuilder().add("one", "two", "three");
+ assertThat(builder2.build()).isEqualTo(expected);
+
+ ListContainer.Builder builder3 = ListContainer.builder().setList(ImmutableList.of("one"));
+ builder3.listBuilder().add("two", "three");
+ assertThat(builder3.build()).isEqualTo(expected);
+
+ ListContainer.Builder builder4 = ListContainer.builder();
+ builder4.listBuilder();
+ try {
+ builder4.setList(ImmutableList.of("one", "two", "three"));
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessageThat().isEqualTo("Cannot set list after calling listBuilder()");
+ }
+ }
+
+ static <T> String concatList(ImmutableList<T> list) {
+ // We're avoiding streams for now so we compile this in Java 7 mode in CompileWithEclipseTest.
+ StringBuilder sb = new StringBuilder();
+ for (T element : list) {
+ sb.append(element);
+ }
+ return sb.toString();
+ }
+
+ @AutoBuilder(callMethod = "concatList")
+ interface ConcatListCaller<T> {
+ ImmutableList.Builder<T> listBuilder();
+
+ String call();
+ }
+
+ @Test
+ public void propertyBuilderWithoutSetter() {
+ ConcatListCaller<Integer> caller = new AutoBuilder_AutoBuilderTest_ConcatListCaller<>();
+ caller.listBuilder().add(1, 1, 2, 3, 5, 8);
+ String s = caller.call();
+ assertThat(s).isEqualTo("112358");
+ }
+
+ static <K, V extends Number> Map<K, V> singletonMap(K key, V value) {
+ return Collections.singletonMap(key, value);
+ }
+
+ static <K, V extends Number> SingletonMapBuilder<K, V> singletonMapBuilder() {
+ return new AutoBuilder_AutoBuilderTest_SingletonMapBuilder<>();
+ }
+
+ @AutoBuilder(callMethod = "singletonMap")
+ interface SingletonMapBuilder<K, V extends Number> {
+ SingletonMapBuilder<K, V> key(K key);
+
+ SingletonMapBuilder<K, V> value(V value);
+
+ Map<K, V> build();
+ }
+
+ @Test
+ public void genericStaticMethod() {
+ ImmutableMap<String, Integer> expected = ImmutableMap.of("17", 17);
+ SingletonMapBuilder<String, Integer> builder = singletonMapBuilder();
+ Map<String, Integer> actual = builder.key("17").value(17).build();
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ static class SingletonSet<E> extends AbstractSet<E> {
+ private final E element;
+
+ SingletonSet(E element) {
+ this.element = element;
+ }
+
+ @Override
+ public int size() {
+ return 1;
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return new Iterator<E>() {
+ private boolean first = true;
+
+ @Override
+ public boolean hasNext() {
+ return first;
+ }
+
+ @Override
+ public E next() {
+ if (!first) {
+ throw new NoSuchElementException();
+ }
+ first = false;
+ return element;
+ }
+ };
+ }
+ }
+
+ @AutoBuilder(ofClass = SingletonSet.class)
+ interface SingletonSetBuilder<E> {
+ SingletonSetBuilder<E> setElement(E element);
+
+ SingletonSet<E> build();
+ }
+
+ static <E> SingletonSetBuilder<E> singletonSetBuilder() {
+ return new AutoBuilder_AutoBuilderTest_SingletonSetBuilder<>();
+ }
+
+ @Test
+ public void genericClass() {
+ ImmutableSet<String> expected = ImmutableSet.of("foo");
+ SingletonSetBuilder<String> builder = singletonSetBuilder();
+ Set<String> actual = builder.setElement("foo").build();
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ static class TypedSingletonSet<E> extends SingletonSet<E> {
+ private final Class<?> type;
+
+ <T extends E> TypedSingletonSet(T element, Class<T> type) {
+ super(element);
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return type.getName() + super.toString();
+ }
+ }
+
+ @AutoBuilder(ofClass = TypedSingletonSet.class)
+ interface TypedSingletonSetBuilder<E, T extends E> {
+ TypedSingletonSetBuilder<E, T> setElement(T element);
+
+ TypedSingletonSetBuilder<E, T> setType(Class<T> type);
+
+ TypedSingletonSet<E> build();
+ }
+
+ static <E, T extends E> TypedSingletonSetBuilder<E, T> typedSingletonSetBuilder() {
+ return new AutoBuilder_AutoBuilderTest_TypedSingletonSetBuilder<>();
+ }
+
+ @Test
+ public void genericClassWithGenericConstructor() {
+ TypedSingletonSetBuilder<CharSequence, String> builder = typedSingletonSetBuilder();
+ TypedSingletonSet<CharSequence> set = builder.setElement("foo").setType(String.class).build();
+ assertThat(set.toString()).isEqualTo("java.lang.String[foo]");
+ }
+
+ static <T> ImmutableList<T> pair(T first, T second) {
+ return ImmutableList.of(first, second);
+ }
+
+ @AutoBuilder(callMethod = "pair")
+ interface PairBuilder<T> {
+ PairBuilder<T> setFirst(T x);
+
+ T getFirst();
+
+ PairBuilder<T> setSecond(T x);
+
+ Optional<T> getSecond();
+
+ ImmutableList<T> build();
+ }
+
+ static <T> PairBuilder<T> pairBuilder() {
+ return new AutoBuilder_AutoBuilderTest_PairBuilder<>();
+ }
+
+ @Test
+ public void genericGetters() {
+ PairBuilder<Number> builder = pairBuilder();
+ assertThat(builder.getSecond()).isEmpty();
+ builder.setSecond(2);
+ assertThat(builder.getSecond()).hasValue(2);
+ try {
+ builder.getFirst();
+ fail();
+ } catch (IllegalStateException expected) {
+ }
+ builder.setFirst(1.0);
+ assertThat(builder.getFirst()).isEqualTo(1.0);
+ assertThat(builder.build()).containsExactly(1.0, 2).inOrder();
+ }
+}
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoOneOfTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoOneOfTest.java
index 1b587282..ee337409 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/AutoOneOfTest.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoOneOfTest.java
@@ -499,10 +499,7 @@ public class AutoOneOfTest {
ArrayValue string = ArrayValue.ofString("foo");
ArrayValue ints1 = ArrayValue.ofInts(new int[] {17, 23});
ArrayValue ints2 = ArrayValue.ofInts(new int[] {17, 23});
- new EqualsTester()
- .addEqualityGroup(string)
- .addEqualityGroup(ints1, ints2)
- .testEquals();
+ new EqualsTester().addEqualityGroup(string).addEqualityGroup(ints1, ints2).testEquals();
}
@Retention(RetentionPolicy.RUNTIME)
@@ -560,8 +557,11 @@ public class AutoOneOfTest {
@AutoOneOf(MaybeEmpty.Kind.class)
public abstract static class MaybeEmpty implements Serializable {
+ private static final long serialVersionUID = 1L;
+
public enum Kind {
- EMPTY, STRING,
+ EMPTY,
+ STRING,
}
public abstract Kind getKind();
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java
index 10812f8d..3f4e9bf5 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java
@@ -15,9 +15,11 @@
*/
package com.google.auto.value;
+import static com.google.common.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.Truth8.assertThat;
+import static com.google.common.truth.TruthJUnit.assume;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeTrue;
@@ -53,6 +55,7 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
+import org.junit.AssumptionViolatedException;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -153,6 +156,19 @@ public class AutoValueJava8Test {
.isEqualTo("NullableProperties{nullableString=null, randomInt=23}");
}
+ @Test
+ public void testEqualsParameterIsAnnotated() throws NoSuchMethodException {
+ // 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);
+ Method equals =
+ NullableProperties.create(null, 23).getClass().getMethod("equals", Object.class);
+ AnnotatedType[] parameterTypes = equals.getAnnotatedParameterTypes();
+ assertThat(parameterTypes).hasLength(1);
+ assertThat(parameterTypes[0].getAnnotation(Nullable.class)).isNotNull();
+ }
+
@AutoAnnotation
static Nullable nullable() {
return new AutoAnnotation_AutoValueJava8Test_nullable();
@@ -162,9 +178,7 @@ public class AutoValueJava8Test {
public void testNullablePropertyImplementationIsNullable() throws NoSuchMethodException {
Method method =
AutoValue_AutoValueJava8Test_NullableProperties.class.getDeclaredMethod("nullableString");
- assertThat(method.getAnnotatedReturnType().getAnnotations())
- .asList()
- .contains(nullable());
+ assertThat(method.getAnnotatedReturnType().getAnnotations()).asList().contains(nullable());
}
@Test
@@ -198,8 +212,9 @@ public class AutoValueJava8Test {
@Test
public void testExcludedNullablePropertyImplementation() throws NoSuchMethodException {
- Method method = AutoValue_AutoValueJava8Test_NullablePropertiesNotCopied.class
- .getDeclaredMethod("nullableString");
+ Method method =
+ AutoValue_AutoValueJava8Test_NullablePropertiesNotCopied.class.getDeclaredMethod(
+ "nullableString");
assertThat(method.getAnnotatedReturnType().getAnnotations())
.asList()
.doesNotContain(nullable());
@@ -536,6 +551,35 @@ public class AutoValueJava8Test {
}
}
+ @AutoValue
+ abstract static class NoNullableRef {
+ abstract String foo();
+
+ static NoNullableRef of(String foo) {
+ return new AutoValue_AutoValueJava8Test_NoNullableRef(foo);
+ }
+ }
+
+ // Tests that we generate equals(@Nullable x) using JSpecify @Nullable if that annotation is
+ // available and there is no other @Nullable type annotation mentioned in the @AutoValue class.
+ // If there *are* other @Nullable type annotations, other test methods here will check that they
+ // are used instead.
+ @Test
+ public void testDefaultToJSpecifyNullable() throws ReflectiveOperationException {
+ Class<? extends Annotation> jspecifyNullable;
+ try {
+ // We write this using .concat in order to hide it from rewriting rules.
+ jspecifyNullable =
+ Class.forName("org".concat(".jspecify.nullness.Nullable")).asSubclass(Annotation.class);
+ } catch (ClassNotFoundException e) {
+ throw new AssumptionViolatedException("No JSpecify @Nullable available", e);
+ }
+ Class<? extends NoNullableRef> autoValueImpl = NoNullableRef.of("foo").getClass();
+ Method equals = autoValueImpl.getDeclaredMethod("equals", Object.class);
+ assertThat(equals.getAnnotatedParameterTypes()[0].isAnnotationPresent(jspecifyNullable))
+ .isTrue();
+ }
+
@Test
public void testBuilderWithUnprefixedGetter() {
assumeTrue(javacHandlesTypeAnnotationsCorrectly);
@@ -571,7 +615,7 @@ public class AutoValueJava8Test {
public abstract static class BuilderWithPrefixedGetters<T extends Comparable<T>> {
public abstract ImmutableList<T> getList();
- public abstract T getT();
+ public abstract @Nullable T getT();
@SuppressWarnings("mutable")
public abstract int @Nullable [] getInts();
@@ -586,7 +630,7 @@ public class AutoValueJava8Test {
public abstract static class Builder<T extends Comparable<T>> {
public abstract Builder<T> setList(ImmutableList<T> list);
- public abstract Builder<T> setT(T t);
+ public abstract Builder<T> setT(@Nullable T t);
public abstract Builder<T> setInts(int[] ints);
@@ -761,6 +805,7 @@ public class AutoValueJava8Test {
@AutoValue.Builder
abstract static class Builder {
abstract Builder maybeJustMaybe(Optional<String> maybe);
+
abstract OptionalOptional build();
}
}
@@ -795,6 +840,7 @@ public class AutoValueJava8Test {
@AutoValue.Builder
abstract static class Builder {
abstract Builder setPredicate(Predicate<? super Integer> predicate);
+
abstract OptionalExtends build();
}
}
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java
index 346bc53a..3a7e7bc4 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java
@@ -34,6 +34,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Ordering;
import com.google.common.testing.EqualsTester;
import com.google.common.testing.SerializableTester;
import java.io.ObjectStreamClass;
@@ -52,6 +53,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -60,6 +62,7 @@ import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.SortedMap;
+import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.annotation.Nullable;
@@ -70,6 +73,7 @@ import org.junit.runners.JUnit4;
/** @author emcmanus@google.com (Éamonn McManus) */
@RunWith(JUnit4.class)
+@SuppressWarnings({"AutoValueImmutableFields", "AutoValueFinalMethods", "TypeNameShadowing"})
public class AutoValueTest {
private static boolean omitIdentifiers;
@@ -180,12 +184,15 @@ public class AutoValueTest {
@AutoValue
abstract static class StrangeGetters {
abstract int get1st();
+
abstract int get_1st(); // by default we'll use _1st where identifiers are needed, so foil that.
@AutoValue.Builder
abstract static class Builder {
abstract Builder set1st(int x);
+
abstract Builder set_1st(int x);
+
abstract StrangeGetters build();
}
@@ -284,6 +291,8 @@ public class AutoValueTest {
@AutoValue
public abstract static class Serialize implements Serializable {
+ private static final long serialVersionUID = 1L;
+
public abstract int integer();
public abstract String string();
@@ -845,6 +854,8 @@ public class AutoValueTest {
@Test
public void testGenericClassWithHairyBounds() throws Exception {
class ComparableList<E> extends ArrayList<E> implements Comparable<ComparableList<E>> {
+ private static final long serialVersionUID = 1L;
+
@Override
public int compareTo(ComparableList<E> list) {
throw new UnsupportedOperationException();
@@ -1262,7 +1273,7 @@ public class AutoValueTest {
}
@AutoValue
- public abstract static class ComplexInheritance extends AbstractBase implements A, B {
+ public abstract static class ComplexInheritance extends AbstractBase implements IntfA, IntfB {
public static ComplexInheritance create(String name) {
return new AutoValue_AutoValueTest_ComplexInheritance(name);
}
@@ -1277,9 +1288,9 @@ public class AutoValueTest {
}
}
- interface A extends Base {}
+ interface IntfA extends Base {}
- interface B extends Base {}
+ interface IntfB extends Base {}
interface Base {
int answer();
@@ -1352,7 +1363,7 @@ public class AutoValueTest {
}
@AutoValue
- public abstract static class InheritTwice implements A, B {
+ public abstract static class InheritTwice implements IntfA, IntfB {
public static InheritTwice create(int answer) {
return new AutoValue_AutoValueTest_InheritTwice(answer);
}
@@ -1664,6 +1675,13 @@ public class AutoValueTest {
.build();
assertThat(suppliedDirectly.optionalString()).hasValue("foo");
assertThat(suppliedDirectly.optionalInteger()).hasValue(23);
+
+ try {
+ // The parameter is not marked @Nullable so this should fail.
+ OptionalPropertiesWithBuilder.builder().setOptionalString((String) null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
}
@AutoValue
@@ -1874,6 +1892,40 @@ public class AutoValueTest {
assertEquals((Integer) 17, instance3.u());
}
+ public interface ToBuilder<BuilderT> {
+ BuilderT toBuilder();
+ }
+
+ @AutoValue
+ public abstract static class InheritedToBuilder<T, U>
+ implements ToBuilder<InheritedToBuilder.Builder<T, U>> {
+
+ public abstract T t();
+
+ public abstract U u();
+
+ public static <T, U> Builder<T, U> builder() {
+ return new AutoValue_AutoValueTest_InheritedToBuilder.Builder<T, U>();
+ }
+
+ @AutoValue.Builder
+ public abstract static class Builder<T, U> {
+ public abstract Builder<T, U> setT(T t);
+
+ public abstract Builder<T, U> setU(U u);
+
+ public abstract InheritedToBuilder<T, U> build();
+ }
+ }
+
+ @Test
+ public void testInheritedToBuilder() {
+ InheritedToBuilder<Integer, String> x =
+ InheritedToBuilder.<Integer, String>builder().setT(17).setU("wibble").build();
+ InheritedToBuilder<Integer, String> y = x.toBuilder().setT(23).build();
+ assertThat(y.u()).isEqualTo("wibble");
+ }
+
@AutoValue
public abstract static class BuilderWithSet<T extends Comparable<T>> {
public abstract List<T> list();
@@ -2115,6 +2167,37 @@ public class AutoValueTest {
}
@AutoValue
+ public abstract static class BuilderWithPrefixedGettersAndUnprefixedSetters {
+ public abstract String getOAuth();
+
+ public abstract String getOBrien();
+
+ public static Builder builder() {
+ return new AutoValue_AutoValueTest_BuilderWithPrefixedGettersAndUnprefixedSetters.Builder();
+ }
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract Builder oAuth(String x);
+
+ public abstract Builder OBrien(String x);
+
+ public abstract BuilderWithPrefixedGettersAndUnprefixedSetters build();
+ }
+ }
+
+ @Test
+ public void testBuilderWithPrefixedGetterAndUnprefixedSetter() {
+ BuilderWithPrefixedGettersAndUnprefixedSetters x =
+ BuilderWithPrefixedGettersAndUnprefixedSetters.builder()
+ .oAuth("OAuth")
+ .OBrien("Flann")
+ .build();
+ assertThat(x.getOAuth()).isEqualTo("OAuth");
+ assertThat(x.getOBrien()).isEqualTo("Flann");
+ }
+
+ @AutoValue
public abstract static class BuilderWithPropertyBuilders<FooT extends Comparable<FooT>> {
public abstract ImmutableList<FooT> getFoos();
@@ -2223,6 +2306,7 @@ public class AutoValueTest {
@AutoValue.Builder
abstract static class Builder {
abstract ImmutableList.Builder<String> listBuilder();
+
abstract PropertyBuilderInheritsType build();
}
}
@@ -2820,6 +2904,8 @@ public class AutoValueTest {
}
public static class MyMap<K, V> extends HashMap<K, V> {
+ private static final long serialVersionUID = 1L;
+
public MyMap() {}
public MyMap(Map<K, V> map) {
@@ -2828,6 +2914,8 @@ public class AutoValueTest {
}
public static class MyMapBuilder<K, V> extends LinkedHashMap<K, V> {
+ private static final long serialVersionUID = 1L;
+
public MyMapBuilder() {}
public MyMapBuilder(Map<K, V> map) {
@@ -2873,6 +2961,8 @@ public class AutoValueTest {
}
public static class MyStringMap<V> extends MyMap<String, V> {
+ private static final long serialVersionUID = 1L;
+
public MyStringMap() {}
public MyStringMap(Map<String, V> map) {
@@ -2885,6 +2975,8 @@ public class AutoValueTest {
}
public static class MyStringMapBuilder<V> extends MyMapBuilder<String, V> {
+ private static final long serialVersionUID = 1L;
+
public MyStringMapBuilder() {}
public MyStringMapBuilder(Map<String, V> map) {
@@ -3258,6 +3350,7 @@ public class AutoValueTest {
@AutoValue.Builder
abstract static class Builder {
abstract Builder setMetrics(ImmutableSet<? extends Number> metrics);
+
abstract GenericExtends build();
}
}
@@ -3282,6 +3375,7 @@ public class AutoValueTest {
@AutoValue.Builder
abstract static class Builder {
abstract Builder setList(List<String> list);
+
abstract Child build();
}
}
@@ -3325,14 +3419,18 @@ public class AutoValueTest {
@SuppressWarnings("ClassCanBeStatic")
static class OuterWithTypeParam<T extends Number> {
class InnerWithTypeParam<U> {}
+
class InnerWithoutTypeParam {}
+
static class Nested {}
}
@AutoValue
abstract static class Nesty {
abstract OuterWithTypeParam<Double>.InnerWithTypeParam<String> innerWithTypeParam();
+
abstract OuterWithTypeParam<Double>.InnerWithoutTypeParam innerWithoutTypeParam();
+
abstract OuterWithTypeParam.Nested nested();
static Builder builder() {
@@ -3343,8 +3441,11 @@ public class AutoValueTest {
abstract static class Builder {
abstract Builder setInnerWithTypeParam(
OuterWithTypeParam<Double>.InnerWithTypeParam<String> x);
+
abstract Builder setInnerWithoutTypeParam(OuterWithTypeParam<Double>.InnerWithoutTypeParam x);
+
abstract Builder setNested(OuterWithTypeParam.Nested x);
+
abstract Nesty build();
}
}
@@ -3353,11 +3454,12 @@ public class AutoValueTest {
public void outerWithTypeParam() throws ReflectiveOperationException {
@SuppressWarnings("UseDiamond") // Currently we compile this with -source 6 in the Eclipse test.
OuterWithTypeParam<Double> outer = new OuterWithTypeParam<Double>();
- Nesty nesty = Nesty.builder()
- .setInnerWithTypeParam(outer.new InnerWithTypeParam<String>())
- .setInnerWithoutTypeParam(outer.new InnerWithoutTypeParam())
- .setNested(new OuterWithTypeParam.Nested())
- .build();
+ Nesty nesty =
+ Nesty.builder()
+ .setInnerWithTypeParam(outer.new InnerWithTypeParam<String>())
+ .setInnerWithoutTypeParam(outer.new InnerWithoutTypeParam())
+ .setNested(new OuterWithTypeParam.Nested())
+ .build();
Type originalReturnType =
Nesty.class.getDeclaredMethod("innerWithTypeParam").getGenericReturnType();
Type generatedReturnType =
@@ -3383,6 +3485,7 @@ public class AutoValueTest {
@MyAnnotation("thing")
abstract static class Builder {
abstract Builder setFoo(String x);
+
abstract BuilderAnnotationsNotCopied build();
}
}
@@ -3407,6 +3510,7 @@ public class AutoValueTest {
@MyAnnotation("thing")
abstract static class Builder {
abstract Builder setFoo(String x);
+
abstract BuilderAnnotationsCopied build();
}
}
@@ -3417,4 +3521,106 @@ public class AutoValueTest {
assertThat(builder.getClass().getAnnotations()).asList().containsExactly(myAnnotation("thing"));
assertThat(builder.setFoo("foo").build().foo()).isEqualTo("foo");
}
+
+ @AutoValue
+ @AutoValue.CopyAnnotations
+ @SuppressWarnings({"rawtypes", "unchecked"}) // deliberately checking handling of raw types
+ abstract static class DataWithSortedCollectionBuilders<K, V> {
+ abstract ImmutableSortedMap<K, V> anImmutableSortedMap();
+
+ abstract ImmutableSortedSet<V> anImmutableSortedSet();
+
+ abstract ImmutableSortedMap<Integer, V> nonGenericImmutableSortedMap();
+
+ abstract ImmutableSortedSet rawImmutableSortedSet();
+
+ abstract DataWithSortedCollectionBuilders.Builder<K, V> toBuilder();
+
+ static <K, V> DataWithSortedCollectionBuilders.Builder<K, V> builder() {
+ return new AutoValue_AutoValueTest_DataWithSortedCollectionBuilders.Builder<K, V>();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder<K, V> {
+ abstract DataWithSortedCollectionBuilders.Builder<K, V> anImmutableSortedMap(
+ SortedMap<K, V> anImmutableSortedMap);
+
+ abstract ImmutableSortedMap.Builder<K, V> anImmutableSortedMapBuilder(
+ Comparator<K> keyComparator);
+
+ abstract DataWithSortedCollectionBuilders.Builder<K, V> anImmutableSortedSet(
+ SortedSet<V> anImmutableSortedSet);
+
+ abstract ImmutableSortedSet.Builder<V> anImmutableSortedSetBuilder(Comparator<V> comparator);
+
+ abstract ImmutableSortedMap.Builder<Integer, V> nonGenericImmutableSortedMapBuilder(
+ Comparator<Integer> keyComparator);
+
+ abstract ImmutableSortedSet.Builder rawImmutableSortedSetBuilder(Comparator comparator);
+
+ abstract DataWithSortedCollectionBuilders<K, V> build();
+ }
+ }
+
+ @Test
+ @SuppressWarnings({"rawtypes", "unchecked"}) // deliberately checking handling of raw types
+ public void shouldGenerateBuildersWithComparators() {
+ Comparator<String> stringComparator =
+ new Comparator<String>() {
+ @Override
+ public int compare(String left, String right) {
+ return left.compareTo(right);
+ }
+ };
+
+ Comparator<Integer> intComparator =
+ new Comparator<Integer>() {
+ @Override
+ public int compare(Integer o1, Integer o2) {
+ return o1 - o2;
+ }
+ };
+
+ Comparator comparator =
+ new Comparator() {
+ @Override
+ public int compare(Object left, Object right) {
+ return String.valueOf(left).compareTo(String.valueOf(right));
+ }
+ };
+
+ AutoValueTest.DataWithSortedCollectionBuilders.Builder<String, Integer> builder =
+ AutoValueTest.DataWithSortedCollectionBuilders.builder();
+
+ builder
+ .anImmutableSortedMapBuilder(stringComparator)
+ .put("Charlie", 1)
+ .put("Alfa", 2)
+ .put("Bravo", 3);
+ builder.anImmutableSortedSetBuilder(intComparator).add(1, 5, 9, 3);
+ builder.nonGenericImmutableSortedMapBuilder(intComparator).put(9, 99).put(1, 11).put(3, 33);
+ builder.rawImmutableSortedSetBuilder(comparator).add("Bravo", "Charlie", "Alfa");
+
+ AutoValueTest.DataWithSortedCollectionBuilders<String, Integer> data = builder.build();
+
+ AutoValueTest.DataWithSortedCollectionBuilders.Builder<String, Integer> copiedBuilder =
+ data.toBuilder();
+ AutoValueTest.DataWithSortedCollectionBuilders<String, Integer> copiedData =
+ copiedBuilder.build();
+
+ assertThat(data.anImmutableSortedMap().keySet())
+ .containsExactly("Alfa", "Bravo", "Charlie")
+ .inOrder();
+ assertThat(data.anImmutableSortedSet()).containsExactly(1, 3, 5, 9).inOrder();
+ assertThat(data.nonGenericImmutableSortedMap().keySet()).containsExactly(1, 3, 9).inOrder();
+ assertThat(data.rawImmutableSortedSet()).containsExactly("Alfa", "Bravo", "Charlie").inOrder();
+
+ assertThat(copiedData).isEqualTo(data);
+
+ try {
+ builder.anImmutableSortedMapBuilder(Ordering.from(stringComparator).reverse());
+ fail("Calling property builder method a second time should have failed");
+ } catch (IllegalStateException expected) {
+ }
+ }
}
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java
index 15188274..ca10fb45 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import com.google.auto.value.processor.AutoAnnotationProcessor;
+import com.google.auto.value.processor.AutoBuilderProcessor;
import com.google.auto.value.processor.AutoOneOfProcessor;
import com.google.auto.value.processor.AutoValueProcessor;
import com.google.common.collect.ImmutableList;
@@ -58,25 +59,28 @@ public class CompileWithEclipseTest {
@BeforeClass
public static void setSourceRoot() {
assertWithMessage("basedir property must be set - test must be run from Maven")
- .that(SOURCE_ROOT).isNotNull();
+ .that(SOURCE_ROOT)
+ .isNotNull();
}
public @Rule TemporaryFolder tmp = new TemporaryFolder();
private static final ImmutableSet<String> IGNORED_TEST_FILES =
- ImmutableSet.of("AutoValueNotEclipseTest.java", "CompileWithEclipseTest.java");
+ ImmutableSet.of(
+ "AutoValueNotEclipseTest.java", "CompileWithEclipseTest.java", "GradleTest.java");
private static final Predicate<File> JAVA_FILE =
f -> f.getName().endsWith(".java") && !IGNORED_TEST_FILES.contains(f.getName());
private static final Predicate<File> JAVA8_TEST =
- f -> f.getName().equals("AutoValueJava8Test.java")
- || f.getName().equals("AutoOneOfJava8Test.java")
- || f.getName().equals("EmptyExtension.java");
+ f ->
+ f.getName().equals("AutoValueJava8Test.java")
+ || f.getName().equals("AutoOneOfJava8Test.java")
+ || f.getName().equals("EmptyExtension.java");
@Test
- public void compileWithEclipseJava6() throws Exception {
- compileWithEclipse("6", JAVA_FILE.and(JAVA8_TEST.negate()));
+ public void compileWithEclipseJava7() throws Exception {
+ compileWithEclipse("7", JAVA_FILE.and(JAVA8_TEST.negate()));
}
@Test
@@ -103,17 +107,28 @@ public class CompileWithEclipseTest {
// fileManager.getLocation(SYSTEM_MODULES).
File rtJar = new File(JAVA_HOME.value() + "/lib/rt.jar");
if (rtJar.exists()) {
- List<File> bootClassPath = ImmutableList.<File>builder()
- .add(rtJar)
- .addAll(fileManager.getLocation(StandardLocation.PLATFORM_CLASS_PATH))
- .build();
+ List<File> bootClassPath =
+ ImmutableList.<File>builder()
+ .add(rtJar)
+ .addAll(fileManager.getLocation(StandardLocation.PLATFORM_CLASS_PATH))
+ .build();
fileManager.setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootClassPath);
}
Iterable<? extends JavaFileObject> sourceFileObjects =
fileManager.getJavaFileObjectsFromFiles(sources);
String outputDir = tmp.getRoot().toString();
ImmutableList<String> options =
- ImmutableList.of("-d", outputDir, "-s", outputDir, "-source", version, "-target", version);
+ ImmutableList.of(
+ "-d",
+ outputDir,
+ "-s",
+ outputDir,
+ "-source",
+ version,
+ "-target",
+ version,
+ "-warn:-warningToken,-intfAnnotation",
+ "-Acom.google.auto.value.AutoBuilderIsUnstable");
JavaCompiler.CompilationTask task =
compiler.getTask(null, fileManager, null, options, null, sourceFileObjects);
// Explicitly supply an empty list of extensions for AutoValueProcessor, because otherwise this
@@ -121,7 +136,10 @@ public class CompileWithEclipseTest {
AutoValueProcessor autoValueProcessor = new AutoValueProcessor(ImmutableList.of());
ImmutableList<? extends Processor> processors =
ImmutableList.of(
- autoValueProcessor, new AutoOneOfProcessor(), new AutoAnnotationProcessor());
+ autoValueProcessor,
+ new AutoOneOfProcessor(),
+ new AutoAnnotationProcessor(),
+ new AutoBuilderProcessor());
task.setProcessors(processors);
assertWithMessage("Compilation should succeed").that(task.call()).isTrue();
}
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/GradleTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/GradleTest.java
new file mode 100644
index 00000000..f4eb5388
--- /dev/null
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/GradleTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableList;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.gradle.util.GradleVersion;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class GradleTest {
+ @Rule public TemporaryFolder fakeProject = new TemporaryFolder();
+
+ private static final String BUILD_GRADLE_TEXT =
+ String.join(
+ "\n",
+ "plugins {",
+ " id 'java-library'",
+ "}",
+ "repositories {",
+ " maven { url = uri('${localRepository}') }",
+ "}",
+ "dependencies {",
+ " compileOnlyApi "
+ + " 'com.google.auto.value:auto-value-annotations:${autoValueVersion}'",
+ " annotationProcessor 'com.google.auto.value:auto-value:${autoValueVersion}'",
+ "}");
+
+ private static final String FOO_TEXT =
+ String.join(
+ "\n",
+ "package com.example;",
+ "",
+ "import com.google.auto.value.AutoValue;",
+ "",
+ "@AutoValue",
+ "abstract class Foo {",
+ " abstract String bar();",
+ "",
+ " static Foo of(String bar) {",
+ " return new AutoValue_Foo(bar);",
+ " }",
+ "}");
+
+ private static final Optional<File> GRADLE_INSTALLATION = getGradleInstallation();
+
+ @Test
+ public void basic() throws IOException {
+ String autoValueVersion = System.getProperty("autoValueVersion");
+ assertThat(autoValueVersion).isNotNull();
+ String localRepository = System.getProperty("localRepository");
+ assertThat(localRepository).isNotNull();
+
+ // Set up the fake Gradle project.
+ String buildGradleText = expandSystemProperties(BUILD_GRADLE_TEXT);
+ writeFile(fakeProject.newFile("build.gradle").toPath(), buildGradleText);
+ Path srcDir = fakeProject.newFolder("src", "main", "java", "com", "example").toPath();
+ writeFile(srcDir.resolve("Foo.java"), FOO_TEXT);
+
+ // Build it the first time.
+ BuildResult result1 = buildFakeProject();
+ assertThat(result1.getOutput())
+ .contains(
+ "Full recompilation is required because no incremental change information is"
+ + " available");
+ Path output =
+ fakeProject
+ .getRoot()
+ .toPath()
+ .resolve("build/classes/java/main/com/example/AutoValue_Foo.class");
+ assertThat(Files.exists(output)).isTrue();
+
+ // Add a source file to the project.
+ String barText = FOO_TEXT.replace("Foo", "Bar");
+ Path barFile = srcDir.resolve("Bar.java");
+ writeFile(barFile, barText);
+
+ // Build it a second time.
+ BuildResult result2 = buildFakeProject();
+ assertThat(result2.getOutput()).doesNotContain("Full recompilation is required");
+
+ // Remove the second source file and build a third time. If incremental annotation processing
+ // is not working, this will produce a message like this:
+ // Full recompilation is required because com.google.auto.value.processor.AutoValueProcessor
+ // is not incremental
+ Files.delete(barFile);
+ BuildResult result3 = buildFakeProject();
+ assertThat(result3.getOutput()).doesNotContain("Full recompilation is required");
+ }
+
+ private BuildResult buildFakeProject() throws IOException {
+ GradleRunner runner =
+ GradleRunner.create()
+ .withProjectDir(fakeProject.getRoot())
+ .withArguments("--info", "compileJava");
+ if (GRADLE_INSTALLATION.isPresent()) {
+ runner.withGradleInstallation(GRADLE_INSTALLATION.get());
+ } else {
+ runner.withGradleVersion(GradleVersion.current().getVersion());
+ }
+ return runner.build();
+ }
+
+ private static Optional<File> getGradleInstallation() {
+ String gradleHome = System.getenv("GRADLE_HOME");
+ if (gradleHome != null) {
+ File gradleHomeFile = new File(gradleHome);
+ if (gradleHomeFile.isDirectory()) {
+ return Optional.of(new File(gradleHome));
+ }
+ }
+ try {
+ Path gradleExecutable = Paths.get("/usr/bin/gradle");
+ Path gradleLink = gradleExecutable.resolveSibling(Files.readSymbolicLink(gradleExecutable));
+ if (!gradleLink.endsWith("bin/gradle")) {
+ return Optional.empty();
+ }
+ Path installationPath = gradleLink.getParent().getParent();
+ if (!Files.isDirectory(installationPath)) {
+ return Optional.empty();
+ }
+ Optional<Path> coreJar;
+ Pattern corePattern = Pattern.compile("gradle-core-([0-9]+)\\..*\\.jar");
+ try (Stream<Path> files = Files.walk(installationPath.resolve("lib"))) {
+ coreJar =
+ files
+ .filter(
+ p -> {
+ Matcher matcher = corePattern.matcher(p.getFileName().toString());
+ if (matcher.matches()) {
+ int version = Integer.parseInt(matcher.group(1));
+ if (version >= 5) {
+ return true;
+ }
+ }
+ return false;
+ })
+ .findFirst();
+ }
+ return coreJar.map(unused -> installationPath.toFile());
+ } catch (IOException e) {
+ return Optional.empty();
+ }
+ }
+
+ private static String expandSystemProperties(String s) {
+ for (String name : System.getProperties().stringPropertyNames()) {
+ String value = System.getProperty(name);
+ s = s.replace("${" + name + "}", value);
+ }
+ return s;
+ }
+
+ private static void writeFile(Path file, String text) throws IOException {
+ Files.write(file, ImmutableList.of(text), UTF_8);
+ }
+}
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/KotlinData.kt b/value/src/it/functional/src/test/java/com/google/auto/value/KotlinData.kt
new file mode 100644
index 00000000..f3318890
--- /dev/null
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/KotlinData.kt
@@ -0,0 +1,22 @@
+/*
+ * 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
+
+data class KotlinData(val int: Int, val string: String)
+
+data class KotlinDataWithNullable(val anInt: Int?, val aString: String?)
+
+data class KotlinDataWithDefaults(val anInt: Int = 23, val aString: String = "skidoo")
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/gwt/EmptyExtension.java b/value/src/it/functional/src/test/java/com/google/auto/value/gwt/EmptyExtension.java
index 0476906c..e6f7abf7 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/gwt/EmptyExtension.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/gwt/EmptyExtension.java
@@ -99,8 +99,7 @@ public class EmptyExtension extends AutoValueExtension {
if (typeParameters.isEmpty()) {
return "";
}
- return typeParameters
- .stream()
+ return typeParameters.stream()
.map(e -> e.getSimpleName().toString())
.collect(joining(", ", "<", ">"));
}