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