• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.auto.value;
17 
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth8.assertThat;
21 import static java.lang.annotation.ElementType.TYPE_USE;
22 import static org.junit.Assert.assertThrows;
23 import static org.junit.Assert.fail;
24 import static org.junit.Assume.assumeTrue;
25 
26 import com.google.common.base.MoreObjects;
27 import com.google.common.collect.ImmutableList;
28 import com.google.common.collect.ImmutableMap;
29 import com.google.common.collect.ImmutableSet;
30 import java.io.IOException;
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 import java.lang.annotation.Target;
34 import java.math.BigInteger;
35 import java.time.LocalTime;
36 import java.util.AbstractSet;
37 import java.util.Collections;
38 import java.util.Iterator;
39 import java.util.Map;
40 import java.util.NoSuchElementException;
41 import java.util.Objects;
42 import java.util.Optional;
43 import java.util.Set;
44 import javax.lang.model.SourceVersion;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.junit.runners.JUnit4;
48 
49 @RunWith(JUnit4.class)
50 public final class AutoBuilderTest {
51   static class Simple {
52     private final int anInt;
53     private final String aString;
54 
Simple(int anInt, String aString)55     Simple(int anInt, String aString) {
56       this.anInt = anInt;
57       this.aString = aString;
58     }
59 
of(int anInt, String aString)60     static Simple of(int anInt, String aString) {
61       return new Simple(anInt, aString);
62     }
63 
64     @Override
equals(Object x)65     public boolean equals(Object x) {
66       if (x instanceof Simple) {
67         Simple that = (Simple) x;
68         return this.anInt == that.anInt && Objects.equals(this.aString, that.aString);
69       }
70       return false;
71     }
72 
73     @Override
hashCode()74     public int hashCode() {
75       return Objects.hash(anInt, aString);
76     }
77 
78     @Override
toString()79     public String toString() {
80       return MoreObjects.toStringHelper(this)
81           .add("anInt", anInt)
82           .add("aString", aString)
83           .toString();
84     }
85 
builder()86     static Builder builder() {
87       return new AutoBuilder_AutoBuilderTest_Simple_Builder();
88     }
89 
90     @AutoBuilder
91     abstract static class Builder {
setAnInt(int x)92       abstract Builder setAnInt(int x);
93 
setAString(String x)94       abstract Builder setAString(String x);
95 
build()96       abstract Simple build();
97     }
98   }
99 
100   @Test
simple()101   public void simple() {
102     Simple x = Simple.builder().setAnInt(23).setAString("skidoo").build();
103     assertThat(x).isEqualTo(new Simple(23, "skidoo"));
104   }
105 
106   @AutoValue
107   abstract static class SimpleAuto {
getFoo()108     abstract int getFoo();
109 
getBar()110     abstract String getBar();
111 
builder()112     static Builder builder() {
113       return new AutoBuilder_AutoBuilderTest_SimpleAuto_Builder();
114     }
115 
116     // There's no particular reason to do this since @AutoValue.Builder works just as well, but
117     // let's check anyway.
118     @AutoBuilder(ofClass = AutoValue_AutoBuilderTest_SimpleAuto.class)
119     abstract static class Builder {
setFoo(int x)120       abstract Builder setFoo(int x);
121 
setBar(String x)122       abstract Builder setBar(String x);
123 
build()124       abstract AutoValue_AutoBuilderTest_SimpleAuto build();
125     }
126   }
127 
128   @Test
simpleAuto()129   public void simpleAuto() {
130     SimpleAuto x = SimpleAuto.builder().setFoo(23).setBar("skidoo").build();
131     assertThat(x.getFoo()).isEqualTo(23);
132     assertThat(x.getBar()).isEqualTo("skidoo");
133   }
134 
135   enum Truthiness {
136     FALSY,
137     TRUTHY
138   }
139 
140   @Retention(RetentionPolicy.RUNTIME)
141   @interface MyAnnotation {
value()142     String value();
143 
144     int DEFAULT_ID = -1;
145 
id()146     int id() default DEFAULT_ID;
147 
148     Truthiness DEFAULT_TRUTHINESS = Truthiness.FALSY;
149 
truthiness()150     Truthiness truthiness() default Truthiness.FALSY;
151   }
152 
153   // This method has a parameter for `truthiness`, even though that has a default, but it has no
154   // parameter for `id`, which also has a default.
155   @AutoAnnotation
myAnnotation(String value, Truthiness truthiness)156   static MyAnnotation myAnnotation(String value, Truthiness truthiness) {
157     return new AutoAnnotation_AutoBuilderTest_myAnnotation(value, truthiness);
158   }
159 
160   // This method has parameters for all the annotation elements.
161   @AutoAnnotation
myAnnotationAll(String value, int id, Truthiness truthiness)162   static MyAnnotation myAnnotationAll(String value, int id, Truthiness truthiness) {
163     return new AutoAnnotation_AutoBuilderTest_myAnnotationAll(value, id, truthiness);
164   }
165 
166   @AutoBuilder(callMethod = "myAnnotation")
167   interface MyAnnotationBuilder {
value(String x)168     MyAnnotationBuilder value(String x);
169 
truthiness(Truthiness x)170     MyAnnotationBuilder truthiness(Truthiness x);
171 
build()172     MyAnnotation build();
173   }
174 
myAnnotationBuilder()175   static MyAnnotationBuilder myAnnotationBuilder() {
176     return new AutoBuilder_AutoBuilderTest_MyAnnotationBuilder();
177   }
178 
179   @AutoBuilder(callMethod = "myAnnotationAll")
180   interface MyAnnotationAllBuilder {
value(String x)181     MyAnnotationAllBuilder value(String x);
182 
id(int x)183     MyAnnotationAllBuilder id(int x);
184 
truthiness(Truthiness x)185     MyAnnotationAllBuilder truthiness(Truthiness x);
186 
build()187     MyAnnotation build();
188   }
189 
myAnnotationAllBuilder()190   static MyAnnotationAllBuilder myAnnotationAllBuilder() {
191     return new AutoBuilder_AutoBuilderTest_MyAnnotationAllBuilder();
192   }
193 
194   @Test
simpleAutoAnnotation()195   public void simpleAutoAnnotation() {
196     // We haven't supplied a value for `truthiness`, so AutoBuilder should use the default one in
197     // the annotation.
198     MyAnnotation annotation1 = myAnnotationBuilder().value("foo").build();
199     assertThat(annotation1.value()).isEqualTo("foo");
200     assertThat(annotation1.id()).isEqualTo(MyAnnotation.DEFAULT_ID);
201     assertThat(annotation1.truthiness()).isEqualTo(MyAnnotation.DEFAULT_TRUTHINESS);
202     MyAnnotation annotation2 =
203         myAnnotationBuilder().value("bar").truthiness(Truthiness.TRUTHY).build();
204     assertThat(annotation2.value()).isEqualTo("bar");
205     assertThat(annotation2.id()).isEqualTo(MyAnnotation.DEFAULT_ID);
206     assertThat(annotation2.truthiness()).isEqualTo(Truthiness.TRUTHY);
207 
208     MyAnnotation annotation3 = myAnnotationAllBuilder().value("foo").build();
209     MyAnnotation annotation4 =
210         myAnnotationAllBuilder()
211             .value("foo")
212             .id(MyAnnotation.DEFAULT_ID)
213             .truthiness(MyAnnotation.DEFAULT_TRUTHINESS)
214             .build();
215     assertThat(annotation3).isEqualTo(annotation4);
216   }
217 
218   @AutoBuilder(ofClass = MyAnnotation.class)
219   public interface MyAnnotationSimpleBuilder {
value(String x)220     MyAnnotationSimpleBuilder value(String x);
221 
id(int x)222     MyAnnotationSimpleBuilder id(int x);
223 
truthiness(Truthiness x)224     MyAnnotationSimpleBuilder truthiness(Truthiness x);
225 
build()226     MyAnnotation build();
227   }
228 
myAnnotationSimpleBuilder()229   public static MyAnnotationSimpleBuilder myAnnotationSimpleBuilder() {
230     return new AutoBuilder_AutoBuilderTest_MyAnnotationSimpleBuilder();
231   }
232 
233   @Test
buildWithoutAutoAnnotation()234   public void buildWithoutAutoAnnotation() {
235     // We don't set a value for `id` or `truthiness`, so AutoBuilder should use the default ones in
236     // the annotation.
237     MyAnnotation annotation1 = myAnnotationSimpleBuilder().value("foo").build();
238     assertThat(annotation1.value()).isEqualTo("foo");
239     assertThat(annotation1.id()).isEqualTo(MyAnnotation.DEFAULT_ID);
240     assertThat(annotation1.truthiness()).isEqualTo(MyAnnotation.DEFAULT_TRUTHINESS);
241 
242     // Now we set `truthiness` but still not `id`.
243     MyAnnotation annotation2 =
244         myAnnotationSimpleBuilder().value("bar").truthiness(Truthiness.TRUTHY).build();
245     assertThat(annotation2.value()).isEqualTo("bar");
246     assertThat(annotation2.id()).isEqualTo(MyAnnotation.DEFAULT_ID);
247     assertThat(annotation2.truthiness()).isEqualTo(Truthiness.TRUTHY);
248 
249     // All three elements set explicitly.
250     MyAnnotation annotation3 =
251         myAnnotationSimpleBuilder().value("foo").id(23).truthiness(Truthiness.TRUTHY).build();
252     assertThat(annotation3.value()).isEqualTo("foo");
253     assertThat(annotation3.id()).isEqualTo(23);
254     assertThat(annotation3.truthiness()).isEqualTo(Truthiness.TRUTHY);
255   }
256 
257   // This builder doesn't have a setter for the `truthiness` element, so the annotations it builds
258   // should always get the default value.
259   @AutoBuilder(ofClass = MyAnnotation.class)
260   public interface MyAnnotationSimplerBuilder {
value(String x)261     MyAnnotationSimplerBuilder value(String x);
262 
id(int x)263     MyAnnotationSimplerBuilder id(int x);
264 
build()265     MyAnnotation build();
266   }
267 
myAnnotationSimplerBuilder()268   public static MyAnnotationSimplerBuilder myAnnotationSimplerBuilder() {
269     return new AutoBuilder_AutoBuilderTest_MyAnnotationSimplerBuilder();
270   }
271 
272   @Test
buildWithoutAutoAnnotation_noSetterForElement()273   public void buildWithoutAutoAnnotation_noSetterForElement() {
274     MyAnnotation annotation = myAnnotationSimplerBuilder().value("foo").id(23).build();
275     assertThat(annotation.value()).isEqualTo("foo");
276     assertThat(annotation.id()).isEqualTo(23);
277     assertThat(annotation.truthiness()).isEqualTo(MyAnnotation.DEFAULT_TRUTHINESS);
278   }
279 
280   static class Overload {
281     final int anInt;
282     final String aString;
283     final BigInteger aBigInteger;
284 
Overload(int anInt, String aString)285     Overload(int anInt, String aString) {
286       this(anInt, aString, BigInteger.ZERO);
287     }
288 
Overload(int anInt, String aString, BigInteger aBigInteger)289     Overload(int anInt, String aString, BigInteger aBigInteger) {
290       this.anInt = anInt;
291       this.aString = aString;
292       this.aBigInteger = aBigInteger;
293     }
294 
295     @Override
equals(Object x)296     public boolean equals(Object x) {
297       if (x instanceof Overload) {
298         Overload that = (Overload) x;
299         return this.anInt == that.anInt
300             && Objects.equals(this.aString, that.aString)
301             && Objects.equals(this.aBigInteger, that.aBigInteger);
302       }
303       return false;
304     }
305 
306     @Override
hashCode()307     public int hashCode() {
308       return Objects.hash(anInt, aString, aBigInteger);
309     }
310 
311     @Override
toString()312     public String toString() {
313       return MoreObjects.toStringHelper(this)
314           .add("anInt", anInt)
315           .add("aString", aString)
316           .add("aBigInteger", aBigInteger)
317           .toString();
318     }
319 
builder1()320     static Builder1 builder1() {
321       return new AutoBuilder_AutoBuilderTest_Overload_Builder1();
322     }
323 
builder2()324     static Builder2 builder2() {
325       return new AutoBuilder_AutoBuilderTest_Overload_Builder2();
326     }
327 
328     @AutoBuilder
329     interface Builder1 {
setAnInt(int x)330       Builder1 setAnInt(int x);
331 
setAString(String x)332       Builder1 setAString(String x);
333 
build()334       Overload build();
335     }
336 
337     @AutoBuilder
338     interface Builder2 {
setAnInt(int x)339       Builder2 setAnInt(int x);
340 
setAString(String x)341       Builder2 setAString(String x);
342 
setABigInteger(BigInteger x)343       Builder2 setABigInteger(BigInteger x);
344 
build()345       Overload build();
346     }
347   }
348 
349   @Test
overloadedConstructor()350   public void overloadedConstructor() {
351     Overload actual1 = Overload.builder1().setAnInt(23).setAString("skidoo").build();
352     Overload expected1 = new Overload(23, "skidoo");
353     assertThat(actual1).isEqualTo(expected1);
354 
355     BigInteger big17 = BigInteger.valueOf(17);
356     Overload actual2 =
357         Overload.builder2().setAnInt(17).setAString("17").setABigInteger(big17).build();
358     Overload expected2 = new Overload(17, "17", big17);
359     assertThat(actual2).isEqualTo(expected2);
360   }
361 
362   @AutoBuilder(callMethod = "of", ofClass = Simple.class)
363   interface SimpleStaticBuilder {
anInt(int x)364     SimpleStaticBuilder anInt(int x);
365 
aString(String x)366     SimpleStaticBuilder aString(String x);
367 
build()368     Simple build();
369   }
370 
simpleStaticBuilder()371   static SimpleStaticBuilder simpleStaticBuilder() {
372     return new AutoBuilder_AutoBuilderTest_SimpleStaticBuilder();
373   }
374 
375   @Test
staticMethod()376   public void staticMethod() {
377     Simple actual = simpleStaticBuilder().anInt(17).aString("17").build();
378     Simple expected = new Simple(17, "17");
379     assertThat(actual).isEqualTo(expected);
380   }
381 
382   // We can't be sure that the java.time package has parameter names, so we use this intermediary.
383   // Otherwise we could just write @AutoBuilder(callMethod = "of", ofClass = LocalTime.class).
384   // It's still interesting to test this as a realistic example.
localTimeOf(int hour, int minute, int second, int nanoOfSecond)385   static LocalTime localTimeOf(int hour, int minute, int second, int nanoOfSecond) {
386     return LocalTime.of(hour, minute, second, nanoOfSecond);
387   }
388 
localTimeBuilder()389   static LocalTimeBuilder localTimeBuilder() {
390     return new AutoBuilder_AutoBuilderTest_LocalTimeBuilder().nanoOfSecond(0);
391   }
392 
393   @AutoBuilder(callMethod = "localTimeOf")
394   interface LocalTimeBuilder {
hour(int hour)395     LocalTimeBuilder hour(int hour);
396 
minute(int minute)397     LocalTimeBuilder minute(int minute);
398 
second(int second)399     LocalTimeBuilder second(int second);
400 
nanoOfSecond(int nanoOfSecond)401     LocalTimeBuilder nanoOfSecond(int nanoOfSecond);
402 
build()403     LocalTime build();
404   }
405 
406   @Test
staticMethodOfContainingClass()407   public void staticMethodOfContainingClass() {
408     LocalTime actual = localTimeBuilder().hour(12).minute(34).second(56).build();
409     LocalTime expected = LocalTime.of(12, 34, 56);
410     assertThat(actual).isEqualTo(expected);
411   }
412 
413   @Test
missingRequiredProperty()414   public void missingRequiredProperty() {
415     // This test is compiled at source level 7 by CompileWithEclipseTest, so we can't use
416     // assertThrows with a lambda.
417     try {
418       localTimeBuilder().hour(12).minute(34).build();
419       fail();
420     } catch (IllegalStateException e) {
421       assertThat(e).hasMessageThat().isEqualTo("Missing required properties: second");
422     }
423   }
424 
throwException()425   static void throwException() throws IOException {
426     throw new IOException("oops");
427   }
428 
throwExceptionBuilder()429   static ThrowExceptionBuilder throwExceptionBuilder() {
430     return new AutoBuilder_AutoBuilderTest_ThrowExceptionBuilder();
431   }
432 
433   @AutoBuilder(callMethod = "throwException")
434   interface ThrowExceptionBuilder {
build()435     void build() throws IOException;
436   }
437 
438   @Test
emptyBuilderThrowsException()439   public void emptyBuilderThrowsException() {
440     try {
441       throwExceptionBuilder().build();
442       fail();
443     } catch (IOException expected) {
444       assertThat(expected).hasMessageThat().isEqualTo("oops");
445     }
446   }
447 
448   static class ListContainer {
449     private final ImmutableList<String> list;
450 
ListContainer(ImmutableList<String> list)451     ListContainer(ImmutableList<String> list) {
452       this.list = checkNotNull(list);
453     }
454 
455     @Override
equals(Object o)456     public boolean equals(Object o) {
457       return o instanceof ListContainer && list.equals(((ListContainer) o).list);
458     }
459 
460     @Override
hashCode()461     public int hashCode() {
462       return list.hashCode();
463     }
464 
465     @Override
toString()466     public String toString() {
467       return list.toString();
468     }
469 
builder()470     static Builder builder() {
471       return new AutoBuilder_AutoBuilderTest_ListContainer_Builder();
472     }
473 
474     @AutoBuilder
475     interface Builder {
setList(Iterable<String> list)476       Builder setList(Iterable<String> list);
477 
listBuilder()478       ImmutableList.Builder<String> listBuilder();
479 
build()480       ListContainer build();
481     }
482   }
483 
484   @Test
propertyBuilder()485   public void propertyBuilder() {
486     ListContainer expected = new ListContainer(ImmutableList.of("one", "two", "three"));
487     ListContainer actual1 =
488         ListContainer.builder().setList(ImmutableList.of("one", "two", "three")).build();
489     assertThat(actual1).isEqualTo(expected);
490 
491     ListContainer.Builder builder2 = ListContainer.builder();
492     builder2.listBuilder().add("one", "two", "three");
493     assertThat(builder2.build()).isEqualTo(expected);
494 
495     ListContainer.Builder builder3 = ListContainer.builder().setList(ImmutableList.of("one"));
496     builder3.listBuilder().add("two", "three");
497     assertThat(builder3.build()).isEqualTo(expected);
498 
499     ListContainer.Builder builder4 = ListContainer.builder();
500     ImmutableList.Builder<String> unused = builder4.listBuilder();
501     try {
502       builder4.setList(ImmutableList.of("one", "two", "three"));
503       fail();
504     } catch (IllegalStateException e) {
505       assertThat(e).hasMessageThat().isEqualTo("Cannot set list after calling listBuilder()");
506     }
507   }
508 
concatList(ImmutableList<T> list)509   static <T> String concatList(ImmutableList<T> list) {
510     // We're avoiding streams for now since we compile this in Java 7 mode in CompileWithEclipseTest
511     StringBuilder sb = new StringBuilder();
512     for (T element : list) {
513       sb.append(element);
514     }
515     return sb.toString();
516   }
517 
518   @AutoBuilder(callMethod = "concatList")
519   interface ConcatListCaller<T> {
listBuilder()520     ImmutableList.Builder<T> listBuilder();
521 
call()522     String call();
523   }
524 
525   @Test
propertyBuilderWithoutSetter()526   public void propertyBuilderWithoutSetter() {
527     ConcatListCaller<Integer> caller = new AutoBuilder_AutoBuilderTest_ConcatListCaller<>();
528     caller.listBuilder().add(1, 1, 2, 3, 5, 8);
529     String s = caller.call();
530     assertThat(s).isEqualTo("112358");
531   }
532 
singletonMap(K key, V value)533   static <K, V extends Number> Map<K, V> singletonMap(K key, V value) {
534     return Collections.singletonMap(key, value);
535   }
536 
singletonMapBuilder()537   static <K, V extends Number> SingletonMapBuilder<K, V> singletonMapBuilder() {
538     return new AutoBuilder_AutoBuilderTest_SingletonMapBuilder<>();
539   }
540 
541   @AutoBuilder(callMethod = "singletonMap")
542   interface SingletonMapBuilder<K, V extends Number> {
key(K key)543     SingletonMapBuilder<K, V> key(K key);
544 
value(V value)545     SingletonMapBuilder<K, V> value(V value);
546 
build()547     Map<K, V> build();
548   }
549 
550   @Test
genericStaticMethod()551   public void genericStaticMethod() {
552     ImmutableMap<String, Integer> expected = ImmutableMap.of("17", 17);
553     SingletonMapBuilder<String, Integer> builder = singletonMapBuilder();
554     Map<String, Integer> actual = builder.key("17").value(17).build();
555     assertThat(actual).isEqualTo(expected);
556   }
557 
558   static class SingletonSet<E> extends AbstractSet<E> {
559     private final E element;
560 
SingletonSet(E element)561     SingletonSet(E element) {
562       this.element = element;
563     }
564 
565     @Override
size()566     public int size() {
567       return 1;
568     }
569 
570     @Override
iterator()571     public Iterator<E> iterator() {
572       return new Iterator<E>() {
573         private boolean first = true;
574 
575         @Override
576         public boolean hasNext() {
577           return first;
578         }
579 
580         @Override
581         public E next() {
582           if (!first) {
583             throw new NoSuchElementException();
584           }
585           first = false;
586           return element;
587         }
588       };
589     }
590   }
591 
592   @AutoBuilder(ofClass = SingletonSet.class)
593   interface SingletonSetBuilder<E> {
setElement(E element)594     SingletonSetBuilder<E> setElement(E element);
595 
build()596     SingletonSet<E> build();
597   }
598 
singletonSetBuilder()599   static <E> SingletonSetBuilder<E> singletonSetBuilder() {
600     return new AutoBuilder_AutoBuilderTest_SingletonSetBuilder<>();
601   }
602 
603   @Test
genericClass()604   public void genericClass() {
605     ImmutableSet<String> expected = ImmutableSet.of("foo");
606     SingletonSetBuilder<String> builder = singletonSetBuilder();
607     Set<String> actual = builder.setElement("foo").build();
608     assertThat(actual).isEqualTo(expected);
609   }
610 
611   static class TypedSingletonSet<E> extends SingletonSet<E> {
612     private final Class<?> type;
613 
TypedSingletonSet(T element, Class<T> type)614     <T extends E> TypedSingletonSet(T element, Class<T> type) {
615       super(element);
616       this.type = type;
617     }
618 
619     @Override
toString()620     public String toString() {
621       return type.getName() + super.toString();
622     }
623   }
624 
625   @AutoBuilder(ofClass = TypedSingletonSet.class)
626   interface TypedSingletonSetBuilder<E, T extends E> {
setElement(T element)627     TypedSingletonSetBuilder<E, T> setElement(T element);
628 
setType(Class<T> type)629     TypedSingletonSetBuilder<E, T> setType(Class<T> type);
630 
build()631     TypedSingletonSet<E> build();
632   }
633 
typedSingletonSetBuilder()634   static <E, T extends E> TypedSingletonSetBuilder<E, T> typedSingletonSetBuilder() {
635     return new AutoBuilder_AutoBuilderTest_TypedSingletonSetBuilder<>();
636   }
637 
638   @Test
genericClassWithGenericConstructor()639   public void genericClassWithGenericConstructor() {
640     TypedSingletonSetBuilder<CharSequence, String> builder = typedSingletonSetBuilder();
641     TypedSingletonSet<CharSequence> set = builder.setElement("foo").setType(String.class).build();
642     assertThat(set.toString()).isEqualTo("java.lang.String[foo]");
643   }
644 
pair(T first, T second)645   static <T> ImmutableList<T> pair(T first, T second) {
646     return ImmutableList.of(first, second);
647   }
648 
649   @AutoBuilder(callMethod = "pair")
650   interface PairBuilder<T> {
setFirst(T x)651     PairBuilder<T> setFirst(T x);
652 
getFirst()653     T getFirst();
654 
setSecond(T x)655     PairBuilder<T> setSecond(T x);
656 
getSecond()657     Optional<T> getSecond();
658 
build()659     ImmutableList<T> build();
660   }
661 
pairBuilder()662   static <T> PairBuilder<T> pairBuilder() {
663     return new AutoBuilder_AutoBuilderTest_PairBuilder<>();
664   }
665 
666   @Test
genericGetters()667   public void genericGetters() {
668     PairBuilder<Number> builder = pairBuilder();
669     assertThat(builder.getSecond()).isEmpty();
670     builder.setSecond(2);
671     assertThat(builder.getSecond()).hasValue(2);
672     try {
673       builder.getFirst();
674       fail();
675     } catch (IllegalStateException expected) {
676     }
677     builder.setFirst(1.0);
678     assertThat(builder.getFirst()).isEqualTo(1.0);
679     assertThat(builder.build()).containsExactly(1.0, 2).inOrder();
680   }
681 
682   static class NumberHolder<T extends Number> {
683     private final T number;
684 
NumberHolder(T number)685     NumberHolder(T number) {
686       this.number = number;
687     }
688 
getNumber()689     T getNumber() {
690       return number;
691     }
692   }
693 
buildNumberHolder(T number)694   static <T extends Number> NumberHolder<T> buildNumberHolder(T number) {
695     return new NumberHolder<>(number);
696   }
697 
698   @AutoBuilder(callMethod = "buildNumberHolder")
699   interface NumberHolderBuilder<T extends Number> {
setNumber(T number)700     NumberHolderBuilder<T> setNumber(T number);
701 
build()702     NumberHolder<T> build();
703   }
704 
numberHolderBuilder()705   static <T extends Number> NumberHolderBuilder<T> numberHolderBuilder() {
706     return new AutoBuilder_AutoBuilderTest_NumberHolderBuilder<>();
707   }
708 
numberHolderBuilder( NumberHolder<T> numberHolder)709   static <T extends Number> NumberHolderBuilder<T> numberHolderBuilder(
710       NumberHolder<T> numberHolder) {
711     return new AutoBuilder_AutoBuilderTest_NumberHolderBuilder<>(numberHolder);
712   }
713 
714   @Test
builderFromInstance()715   public void builderFromInstance() {
716     NumberHolder<Integer> instance1 =
717         AutoBuilderTest.<Integer>numberHolderBuilder().setNumber(23).build();
718     assertThat(instance1.getNumber()).isEqualTo(23);
719     NumberHolder<Integer> instance2 = numberHolderBuilder(instance1).build();
720     assertThat(instance2.getNumber()).isEqualTo(23);
721     NumberHolder<Integer> instance3 = numberHolderBuilder(instance2).setNumber(17).build();
722     assertThat(instance3.getNumber()).isEqualTo(17);
723   }
724 
725   @AutoBuilder(callMethod = "of", ofClass = Simple.class)
726   @MyAnnotation("thing")
727   interface AnnotatedSimpleStaticBuilder1 {
anInt(int x)728     AnnotatedSimpleStaticBuilder1 anInt(int x);
729 
aString(String x)730     AnnotatedSimpleStaticBuilder1 aString(String x);
731 
build()732     Simple build();
733   }
734 
735   @Test
builderAnnotationsNotCopiedByDefault()736   public void builderAnnotationsNotCopiedByDefault() {
737     assertThat(AutoBuilder_AutoBuilderTest_AnnotatedSimpleStaticBuilder1.class.getAnnotations())
738         .asList()
739         .isEmpty();
740   }
741 
742   @AutoBuilder(callMethod = "of", ofClass = Simple.class)
743   @AutoValue.CopyAnnotations
744   @MyAnnotation("thing")
745   interface AnnotatedSimpleStaticBuilder2 {
anInt(int x)746     AnnotatedSimpleStaticBuilder2 anInt(int x);
747 
aString(String x)748     AnnotatedSimpleStaticBuilder2 aString(String x);
749 
build()750     Simple build();
751   }
752 
753   @Test
builderAnnotationsCopiedIfRequested()754   public void builderAnnotationsCopiedIfRequested() {
755     assertThat(AutoBuilder_AutoBuilderTest_AnnotatedSimpleStaticBuilder2.class.getAnnotations())
756         .asList()
757         .contains(myAnnotationBuilder().value("thing").build());
758   }
759 
760   @Target(TYPE_USE)
761   public @interface Nullable {}
762 
frob(T arg, U notNull)763   public static <T extends @Nullable Object, U> T frob(T arg, U notNull) {
764     return arg;
765   }
766 
767   @AutoBuilder(callMethod = "frob")
768   interface FrobCaller<T extends @Nullable Object, U> {
arg(T arg)769     FrobCaller<T, U> arg(T arg);
770 
notNull(U notNull)771     FrobCaller<T, U> notNull(U notNull);
772 
call()773     T call();
774 
caller()775     static <T extends @Nullable Object, U> FrobCaller<T, U> caller() {
776       return new AutoBuilder_AutoBuilderTest_FrobCaller<>();
777     }
778   }
779 
780   @Test
builderTypeVariableWithNullableBound()781   public void builderTypeVariableWithNullableBound() {
782     // The Annotation Processing API doesn't see the @Nullable Object bound on Java 8.
783     assumeTrue(SourceVersion.latest().ordinal() > SourceVersion.RELEASE_8.ordinal());
784     assertThat(FrobCaller.<@Nullable String, String>caller().arg(null).notNull("foo").call())
785         .isNull();
786     assertThrows(
787         NullPointerException.class,
788         () -> FrobCaller.<@Nullable String, String>caller().arg(null).notNull(null).call());
789   }
790 }
791