1 /* 2 * Copyright (C) 2015 The Dagger Authors. 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 17 package dagger.internal.codegen; 18 19 import static com.google.common.truth.TruthJUnit.assume; 20 import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE; 21 import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE; 22 import static dagger.internal.codegen.ComponentCreatorTest.CompilerType.JAVAC; 23 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.COMPONENT_BUILDER; 24 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.COMPONENT_FACTORY; 25 import static dagger.internal.codegen.base.ComponentCreatorKind.BUILDER; 26 import static dagger.internal.codegen.base.ComponentCreatorKind.FACTORY; 27 import static dagger.internal.codegen.base.ComponentKind.COMPONENT; 28 import static dagger.internal.codegen.binding.ErrorMessages.componentMessagesFor; 29 30 import androidx.room.compiler.processing.util.Source; 31 import com.google.common.collect.ImmutableList; 32 import com.google.common.collect.ImmutableMap; 33 import dagger.internal.codegen.base.ComponentCreatorAnnotation; 34 import dagger.testing.compile.CompilerTests; 35 import dagger.testing.golden.GoldenFileRule; 36 import java.util.Collection; 37 import org.junit.Rule; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 import org.junit.runners.Parameterized; 41 import org.junit.runners.Parameterized.Parameters; 42 43 /** Tests for properties of component creators shared by both builders and factories. */ 44 @RunWith(Parameterized.class) 45 public class ComponentCreatorTest extends ComponentCreatorTestHelper { 46 enum CompilerType { 47 JAVAC 48 } 49 50 private final CompilerType compilerType; 51 private final ImmutableMap<String, String> compilerOptions; 52 53 @Parameters(name = "compilerMode={0}, creatorKind={1}") parameters()54 public static Collection<Object[]> parameters() { 55 return ImmutableList.of( 56 new Object[]{DEFAULT_MODE, COMPONENT_BUILDER, JAVAC}, 57 new Object[]{DEFAULT_MODE, COMPONENT_FACTORY, JAVAC}, 58 new Object[]{FAST_INIT_MODE, COMPONENT_BUILDER, JAVAC}, 59 new Object[]{FAST_INIT_MODE, COMPONENT_FACTORY, JAVAC}); 60 } 61 62 @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); 63 ComponentCreatorTest( CompilerMode compilerMode, ComponentCreatorAnnotation componentCreatorAnnotation, CompilerType compilerType)64 public ComponentCreatorTest( 65 CompilerMode compilerMode, 66 ComponentCreatorAnnotation componentCreatorAnnotation, 67 CompilerType compilerType) { 68 super(compilerMode, componentCreatorAnnotation); 69 this.compilerType = compilerType; 70 this.compilerOptions = 71 ImmutableMap.<String, String>builder() 72 .putAll(compilerMode.processorOptions()) 73 .build(); 74 } 75 76 @Test testEmptyCreator()77 public void testEmptyCreator() throws Exception { 78 assume().that(compilerType).isEqualTo(JAVAC); 79 Source injectableTypeFile = 80 CompilerTests.javaSource( 81 "test.SomeInjectableType", 82 "package test;", 83 "", 84 "import javax.inject.Inject;", 85 "", 86 "final class SomeInjectableType {", 87 " @Inject SomeInjectableType() {}", 88 "}"); 89 Source componentFile = 90 preprocessedJavaSource( 91 "test.SimpleComponent", 92 "package test;", 93 "", 94 "import dagger.Component;", 95 "import javax.inject.Provider;", 96 "", 97 "@Component", 98 "interface SimpleComponent {", 99 " SomeInjectableType someInjectableType();", 100 "", 101 " @Component.Builder", 102 " static interface Builder {", 103 " SimpleComponent build();", 104 " }", 105 "}"); 106 107 CompilerTests.daggerCompiler(injectableTypeFile, componentFile) 108 .withProcessingOptions(compilerOptions) 109 .compile( 110 subject -> { 111 subject.hasErrorCount(0); 112 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 113 }); 114 } 115 116 @Test testCanInstantiateModulesUserCannotSet()117 public void testCanInstantiateModulesUserCannotSet() throws Exception { 118 assume().that(compilerType).isEqualTo(JAVAC); 119 Source module = 120 CompilerTests.javaSource( 121 "test.TestModule", 122 "package test;", 123 "", 124 "import dagger.Module;", 125 "import dagger.Provides;", 126 "", 127 "@Module", 128 "final class TestModule {", 129 " @Provides String string() { return null; }", 130 "}"); 131 132 Source componentFile = 133 preprocessedJavaSource( 134 "test.TestComponent", 135 "package test;", 136 "", 137 "import dagger.Component;", 138 "", 139 "@Component(modules = TestModule.class)", 140 "interface TestComponent {", 141 " String string();", 142 "", 143 " @Component.Builder", 144 " interface Builder {", 145 " TestComponent build();", 146 " }", 147 "}"); 148 149 CompilerTests.daggerCompiler(module, componentFile) 150 .withProcessingOptions(compilerOptions) 151 .compile( 152 subject -> { 153 subject.hasErrorCount(0); 154 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 155 }); 156 } 157 158 @Test testMoreThanOneCreatorOfSameTypeFails()159 public void testMoreThanOneCreatorOfSameTypeFails() { 160 Source componentFile = 161 preprocessedJavaSource( 162 "test.SimpleComponent", 163 "package test;", 164 "", 165 "import dagger.Component;", 166 "import javax.inject.Provider;", 167 "", 168 "@Component", 169 "interface SimpleComponent {", 170 " @Component.Builder", 171 " static interface Builder {", 172 " SimpleComponent build();", 173 " }", 174 "", 175 " @Component.Builder", 176 " interface Builder2 {", 177 " SimpleComponent build();", 178 " }", 179 "}"); 180 181 CompilerTests.daggerCompiler(componentFile) 182 .withProcessingOptions(compilerOptions) 183 .compile( 184 subject -> { 185 subject.hasErrorCount(1); 186 subject.hasErrorContaining( 187 String.format( 188 componentMessagesFor(COMPONENT).moreThanOne(), 189 process("[test.SimpleComponent.Builder, test.SimpleComponent.Builder2]"))) 190 .onSource(componentFile); 191 }); 192 } 193 194 @Test testBothBuilderAndFactoryFails()195 public void testBothBuilderAndFactoryFails() { 196 Source componentFile = 197 CompilerTests.javaSource( 198 "test.SimpleComponent", 199 "package test;", 200 "", 201 "import dagger.Component;", 202 "import javax.inject.Provider;", 203 "", 204 "@Component", 205 "interface SimpleComponent {", 206 " @Component.Builder", 207 " static interface Builder {", 208 " SimpleComponent build();", 209 " }", 210 "", 211 " @Component.Factory", 212 " interface Factory {", 213 " SimpleComponent create();", 214 " }", 215 "}"); 216 CompilerTests.daggerCompiler(componentFile) 217 .withProcessingOptions(compilerOptions) 218 .compile( 219 subject -> { 220 subject.hasErrorCount(1); 221 subject.hasErrorContaining( 222 String.format( 223 componentMessagesFor(COMPONENT).moreThanOne(), 224 "[test.SimpleComponent.Builder, test.SimpleComponent.Factory]")) 225 .onSource(componentFile); 226 }); 227 } 228 229 @Test testGenericCreatorTypeFails()230 public void testGenericCreatorTypeFails() { 231 Source componentFile = 232 preprocessedJavaSource( 233 "test.SimpleComponent", 234 "package test;", 235 "", 236 "import dagger.Component;", 237 "import javax.inject.Provider;", 238 "", 239 "@Component", 240 "interface SimpleComponent {", 241 " @Component.Builder", 242 " interface Builder<T> {", 243 " SimpleComponent build();", 244 " }", 245 "}"); 246 CompilerTests.daggerCompiler(componentFile) 247 .withProcessingOptions(compilerOptions) 248 .compile( 249 subject -> { 250 subject.hasErrorCount(1); 251 subject.hasErrorContaining(messages.generics()).onSource(componentFile); 252 }); 253 } 254 255 @Test testCreatorNotInComponentFails()256 public void testCreatorNotInComponentFails() { 257 Source builder = 258 preprocessedJavaSource( 259 "test.Builder", 260 "package test;", 261 "", 262 "import dagger.Component;", 263 "", 264 "@Component.Builder", 265 "interface Builder {}"); 266 CompilerTests.daggerCompiler(builder) 267 .withProcessingOptions(compilerOptions) 268 .compile( 269 subject -> { 270 subject.hasErrorCount(1); 271 subject.hasErrorContaining(messages.mustBeInComponent()).onSource(builder); 272 }); 273 } 274 275 @Test testCreatorMissingFactoryMethodFails()276 public void testCreatorMissingFactoryMethodFails() { 277 Source componentFile = 278 preprocessedJavaSource( 279 "test.SimpleComponent", 280 "package test;", 281 "", 282 "import dagger.Component;", 283 "import javax.inject.Provider;", 284 "", 285 "@Component", 286 "interface SimpleComponent {", 287 " @Component.Builder", 288 " interface Builder {}", 289 "}"); 290 CompilerTests.daggerCompiler(componentFile) 291 .withProcessingOptions(compilerOptions) 292 .compile( 293 subject -> { 294 subject.hasErrorCount(1); 295 subject.hasErrorContaining(messages.missingFactoryMethod()) 296 .onSource(componentFile); 297 }); 298 } 299 300 @Test testCreatorWithBindsInstanceNoStaticCreateGenerated()301 public void testCreatorWithBindsInstanceNoStaticCreateGenerated() throws Exception { 302 assume().that(compilerType).isEqualTo(JAVAC); 303 Source componentFile = 304 javaFileBuilder("test.SimpleComponent") 305 .addLines( 306 "package test;", 307 "", 308 "import dagger.BindsInstance;", 309 "import dagger.Component;", 310 "import javax.inject.Provider;", 311 "", 312 "@Component", 313 "interface SimpleComponent {", 314 " Object object();", 315 "") 316 .addLinesIf( 317 BUILDER, 318 " @Component.Builder", 319 " interface Builder {", 320 " @BindsInstance Builder object(Object object);", 321 " SimpleComponent build();", 322 " }") 323 .addLinesIf( 324 FACTORY, 325 " @Component.Factory", 326 " interface Factory {", 327 " SimpleComponent create(@BindsInstance Object object);", 328 " }") 329 .addLines("}") 330 .buildSource(); 331 332 CompilerTests.daggerCompiler(componentFile) 333 .withProcessingOptions(compilerOptions) 334 .compile( 335 subject -> { 336 subject.hasErrorCount(0); 337 subject.hasWarningCount(0); 338 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 339 }); 340 } 341 342 @Test testCreatorWithPrimitiveBindsInstance()343 public void testCreatorWithPrimitiveBindsInstance() throws Exception { 344 assume().that(compilerType).isEqualTo(JAVAC); 345 Source componentFile = 346 javaFileBuilder("test.SimpleComponent") 347 .addLines( 348 "package test;", 349 "", 350 "import dagger.BindsInstance;", 351 "import dagger.Component;", 352 "import javax.inject.Provider;", 353 "", 354 "@Component", 355 "interface SimpleComponent {", 356 " int anInt();", 357 "") 358 .addLinesIf( 359 BUILDER, 360 " @Component.Builder", 361 " interface Builder {", 362 " @BindsInstance Builder i(int i);", 363 " SimpleComponent build();", 364 " }") 365 .addLinesIf( 366 FACTORY, 367 " @Component.Factory", 368 " interface Factory {", 369 " SimpleComponent create(@BindsInstance int i);", 370 " }") 371 .addLines( 372 "}") 373 .buildSource(); 374 375 CompilerTests.daggerCompiler(componentFile) 376 .withProcessingOptions(compilerOptions) 377 .compile( 378 subject -> { 379 subject.hasErrorCount(0); 380 subject.hasWarningCount(0); 381 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 382 }); 383 } 384 385 @Test testPrivateCreatorFails()386 public void testPrivateCreatorFails() { 387 Source componentFile = 388 preprocessedJavaSource( 389 "test.SimpleComponent", 390 "package test;", 391 "", 392 "import dagger.Component;", 393 "import javax.inject.Provider;", 394 "", 395 "@Component", 396 "abstract class SimpleComponent {", 397 " @Component.Builder", 398 " private interface Builder {}", 399 "}"); 400 CompilerTests.daggerCompiler(componentFile) 401 .withProcessingOptions(compilerOptions) 402 .compile( 403 subject -> { 404 subject.hasErrorCount(1); 405 subject.hasErrorContaining(messages.isPrivate()).onSource(componentFile); 406 }); 407 } 408 409 @Test testNonStaticCreatorFails()410 public void testNonStaticCreatorFails() { 411 Source componentFile = 412 preprocessedJavaSource( 413 "test.SimpleComponent", 414 "package test;", 415 "", 416 "import dagger.Component;", 417 "import javax.inject.Provider;", 418 "", 419 "@Component", 420 "abstract class SimpleComponent {", 421 " @Component.Builder", 422 " abstract class Builder {}", 423 "}"); 424 CompilerTests.daggerCompiler(componentFile) 425 .withProcessingOptions(compilerOptions) 426 .compile( 427 subject -> { 428 subject.hasErrorCount(1); 429 subject.hasErrorContaining(messages.mustBeStatic()).onSource(componentFile); 430 }); 431 } 432 433 @Test testNonAbstractCreatorFails()434 public void testNonAbstractCreatorFails() { 435 Source componentFile = 436 preprocessedJavaSource( 437 "test.SimpleComponent", 438 "package test;", 439 "", 440 "import dagger.Component;", 441 "import javax.inject.Provider;", 442 "", 443 "@Component", 444 "abstract class SimpleComponent {", 445 " @Component.Builder", 446 " static class Builder {}", 447 "}"); 448 CompilerTests.daggerCompiler(componentFile) 449 .withProcessingOptions(compilerOptions) 450 .compile( 451 subject -> { 452 subject.hasErrorCount(1); 453 subject.hasErrorContaining(messages.mustBeAbstract()).onSource(componentFile); 454 }); 455 } 456 457 @Test testCreatorOneConstructorWithArgsFails()458 public void testCreatorOneConstructorWithArgsFails() { 459 Source componentFile = 460 preprocessedJavaSource( 461 "test.SimpleComponent", 462 "package test;", 463 "", 464 "import dagger.Component;", 465 "import javax.inject.Provider;", 466 "", 467 "@Component", 468 "abstract class SimpleComponent {", 469 " @Component.Builder", 470 " static abstract class Builder {", 471 " Builder(String unused) {}", 472 " }", 473 "}"); 474 CompilerTests.daggerCompiler(componentFile) 475 .withProcessingOptions(compilerOptions) 476 .compile( 477 subject -> { 478 subject.hasErrorCount(2); 479 subject.hasErrorContaining(messages.invalidConstructor()) 480 .onSource(componentFile); 481 }); 482 } 483 484 @Test testCreatorMoreThanOneConstructorFails()485 public void testCreatorMoreThanOneConstructorFails() { 486 Source componentFile = 487 preprocessedJavaSource( 488 "test.SimpleComponent", 489 "package test;", 490 "", 491 "import dagger.Component;", 492 "import javax.inject.Provider;", 493 "", 494 "@Component", 495 "abstract class SimpleComponent {", 496 " @Component.Builder", 497 " static abstract class Builder {", 498 " Builder() {}", 499 " Builder(String unused) {}", 500 " }", 501 "}"); 502 CompilerTests.daggerCompiler(componentFile) 503 .withProcessingOptions(compilerOptions) 504 .compile( 505 subject -> { 506 subject.hasErrorCount(2); 507 subject.hasErrorContaining(messages.invalidConstructor()) 508 .onSource(componentFile); 509 }); 510 } 511 512 @Test testCreatorEnumFails()513 public void testCreatorEnumFails() { 514 Source componentFile = 515 preprocessedJavaSource( 516 "test.SimpleComponent", 517 "package test;", 518 "", 519 "import dagger.Component;", 520 "import javax.inject.Provider;", 521 "", 522 "@Component", 523 "abstract class SimpleComponent {", 524 " @Component.Builder", 525 " enum Builder {}", 526 "}"); 527 CompilerTests.daggerCompiler(componentFile) 528 .withProcessingOptions(compilerOptions) 529 .compile( 530 subject -> { 531 subject.hasErrorCount(1); 532 subject.hasErrorContaining(messages.mustBeClassOrInterface()) 533 .onSource(componentFile); 534 }); 535 } 536 537 @Test testCreatorFactoryMethodReturnsWrongTypeFails()538 public void testCreatorFactoryMethodReturnsWrongTypeFails() { 539 Source componentFile = 540 preprocessedJavaSource( 541 "test.SimpleComponent", 542 "package test;", 543 "", 544 "import dagger.Component;", 545 "import javax.inject.Provider;", 546 "", 547 "@Component", 548 "abstract class SimpleComponent {", 549 " @Component.Builder", 550 " interface Builder {", 551 " String build();", 552 " }", 553 "}"); 554 CompilerTests.daggerCompiler(componentFile) 555 .withProcessingOptions(compilerOptions) 556 .compile( 557 subject -> { 558 subject.hasErrorCount(1); 559 subject.hasErrorContaining(messages.factoryMethodMustReturnComponentType()) 560 .onSource(componentFile) 561 .onLineContaining(process("String build();")); 562 }); 563 } 564 565 @Test testCreatorSetterForNonBindsInstancePrimitiveFails()566 public void testCreatorSetterForNonBindsInstancePrimitiveFails() { 567 Source component = 568 javaFileBuilder("test.TestComponent") 569 .addLines( 570 "package test;", 571 "", 572 "import dagger.Component;", 573 "", 574 "@Component", 575 "interface TestComponent {", 576 " Object object();", 577 "") 578 .addLinesIf( 579 BUILDER, 580 " @Component.Builder", 581 " interface Builder {", 582 " Builder primitive(long l);", 583 " TestComponent build();", 584 " }") 585 .addLinesIf( 586 FACTORY, 587 " @Component.Factory", 588 " interface Factory {", 589 " TestComponent create(long l);", 590 " }") 591 .addLines( // 592 "}") 593 .buildSource(); 594 CompilerTests.daggerCompiler(component) 595 .withProcessingOptions(compilerOptions) 596 .compile( 597 subject -> { 598 subject.hasErrorCount(1); 599 subject.hasErrorContaining(messages.nonBindsInstanceParametersMayNotBePrimitives()) 600 .onSource(component) 601 .onLineContaining("(long l)"); 602 }); 603 } 604 605 @Test testInheritedBuilderBuildReturnsWrongTypeFails()606 public void testInheritedBuilderBuildReturnsWrongTypeFails() { 607 Source componentFile = 608 preprocessedJavaSource( 609 "test.SimpleComponent", 610 "package test;", 611 "", 612 "import dagger.Component;", 613 "import javax.inject.Provider;", 614 "", 615 "@Component", 616 "abstract class SimpleComponent {", 617 " interface Parent {", 618 " String build();", 619 " }", 620 "", 621 " @Component.Builder", 622 " interface Builder extends Parent {}", 623 "}"); 624 CompilerTests.daggerCompiler(componentFile) 625 .withProcessingOptions(compilerOptions) 626 .compile( 627 subject -> { 628 subject.hasErrorCount(1); 629 subject.hasErrorContaining( 630 String.format( 631 messages.inheritedFactoryMethodMustReturnComponentType(), 632 process("String test.SimpleComponent.Parent.build()"))) 633 .onSource(componentFile) 634 .onLineContaining(process("interface Builder")); 635 }); 636 } 637 638 @Test testTwoFactoryMethodsFails()639 public void testTwoFactoryMethodsFails() { 640 Source componentFile = 641 preprocessedJavaSource( 642 "test.SimpleComponent", 643 "package test;", 644 "", 645 "import dagger.Component;", 646 "import javax.inject.Provider;", 647 "", 648 "@Component", 649 "abstract class SimpleComponent {", 650 " @Component.Builder", 651 " interface Builder {", 652 " SimpleComponent build();", 653 " SimpleComponent newSimpleComponent();", 654 " }", 655 "}"); 656 CompilerTests.daggerCompiler(componentFile) 657 .withProcessingOptions(compilerOptions) 658 .compile( 659 subject -> { 660 subject.hasErrorCount(1); 661 subject.hasErrorContaining( 662 String.format( 663 messages.twoFactoryMethods(), 664 process("test.SimpleComponent test.SimpleComponent.Builder.build()"))) 665 .onSource(componentFile) 666 .onLineContaining("SimpleComponent newSimpleComponent();"); 667 }); 668 } 669 670 @Test testInheritedTwoFactoryMethodsFails()671 public void testInheritedTwoFactoryMethodsFails() { 672 Source componentFile = 673 preprocessedJavaSource( 674 "test.SimpleComponent", 675 "package test;", 676 "", 677 "import dagger.Component;", 678 "import javax.inject.Provider;", 679 "", 680 "@Component", 681 "abstract class SimpleComponent {", 682 " interface Parent {", 683 " SimpleComponent build();", 684 " SimpleComponent newSimpleComponent();", 685 " }", 686 "", 687 " @Component.Builder", 688 " interface Builder extends Parent {}", 689 "}"); 690 CompilerTests.daggerCompiler(componentFile) 691 .withProcessingOptions(compilerOptions) 692 .compile( 693 subject -> { 694 subject.hasErrorCount(1); 695 subject.hasErrorContaining( 696 String.format( 697 messages.inheritedTwoFactoryMethods(), 698 process("test.SimpleComponent test.SimpleComponent.Parent.build()"), 699 "test.SimpleComponent test.SimpleComponent.Parent.newSimpleComponent()")) 700 .onSource(componentFile) 701 .onLineContaining(process("interface Builder")); 702 }); 703 } 704 705 @Test testMultipleSettersPerTypeFails()706 public void testMultipleSettersPerTypeFails() { 707 assume().that(compilerType).isEqualTo(JAVAC); 708 Source moduleFile = 709 CompilerTests.javaSource( 710 "test.TestModule", 711 "package test;", 712 "", 713 "import dagger.Module;", 714 "import dagger.Provides;", 715 "", 716 "@Module", 717 "final class TestModule {", 718 " @Provides String s() { return \"\"; }", 719 "}"); 720 Source componentFile = 721 javaFileBuilder("test.SimpleComponent") 722 .addLines( 723 "package test;", 724 "", 725 "import dagger.Component;", 726 "import javax.inject.Provider;", 727 "", 728 "@Component(modules = TestModule.class)", 729 "abstract class SimpleComponent {", 730 " abstract String s();", 731 "") 732 .addLinesIf( 733 BUILDER, 734 " @Component.Builder", 735 " interface Builder {", 736 " SimpleComponent build();", 737 " void set1(TestModule s);", 738 " void set2(TestModule s);", 739 " }") 740 .addLinesIf( 741 FACTORY, 742 " @Component.Factory", 743 " interface Factory {", 744 " SimpleComponent create(TestModule m1, TestModule m2);", 745 " }") 746 .addLines( // 747 "}") 748 .buildSource(); 749 CompilerTests.daggerCompiler(moduleFile, componentFile) 750 .withProcessingOptions(compilerOptions) 751 .compile( 752 subject -> { 753 subject.hasErrorCount(1); 754 String elements = 755 creatorKind.equals(BUILDER) 756 ? "[void test.SimpleComponent.Builder.set1(test.TestModule), " 757 + "void test.SimpleComponent.Builder.set2(test.TestModule)]" 758 : "[test.TestModule m1, test.TestModule m2]"; 759 subject.hasErrorContaining( 760 String.format( 761 messages.multipleSettersForModuleOrDependencyType(), 762 "test.TestModule", 763 elements)) 764 .onSource(componentFile) 765 .onLineContaining(process("interface Builder")); 766 }); 767 } 768 769 @Test testMultipleSettersPerTypeIncludingResolvedGenericsFails()770 public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() { 771 assume().that(compilerType).isEqualTo(JAVAC); 772 Source moduleFile = 773 CompilerTests.javaSource( 774 "test.TestModule", 775 "package test;", 776 "", 777 "import dagger.Module;", 778 "import dagger.Provides;", 779 "", 780 "@Module", 781 "final class TestModule {", 782 " @Provides String s() { return \"\"; }", 783 "}"); 784 Source componentFile = 785 javaFileBuilder("test.SimpleComponent") 786 .addLines( 787 "package test;", 788 "", 789 "import dagger.Component;", 790 "import javax.inject.Provider;", 791 "", 792 "@Component(modules = TestModule.class)", 793 "abstract class SimpleComponent {", 794 " abstract String s();", 795 "") 796 .addLinesIf( 797 BUILDER, 798 " interface Parent<T> {", 799 " void set1(T t);", 800 " }", 801 "", 802 " @Component.Builder", 803 " interface Builder extends Parent<TestModule> {", 804 " SimpleComponent build();", 805 " void set2(TestModule s);", 806 " }") 807 .addLinesIf( 808 FACTORY, 809 " interface Parent<C, T> {", 810 " C create(TestModule m1, T t);", 811 " }", 812 "", 813 " @Component.Factory", 814 " interface Factory extends Parent<SimpleComponent, TestModule> {}") 815 .addLines( // 816 "}") 817 .buildSource(); 818 CompilerTests.daggerCompiler(moduleFile, componentFile) 819 .withProcessingOptions(compilerOptions) 820 .compile( 821 subject -> { 822 subject.hasErrorCount(1); 823 String elements = 824 creatorKind.equals(BUILDER) 825 ? "[void test.SimpleComponent.Builder.set1(test.TestModule), " 826 + "void test.SimpleComponent.Builder.set2(test.TestModule)]" 827 : "[test.TestModule m1, test.TestModule t]"; 828 subject.hasErrorContaining( 829 String.format( 830 messages.multipleSettersForModuleOrDependencyType(), 831 "test.TestModule", 832 elements)) 833 .onSource(componentFile) 834 .onLineContaining(process("interface Builder")); 835 }); 836 } 837 838 @Test testExtraSettersFails()839 public void testExtraSettersFails() { 840 assume().that(compilerType).isEqualTo(JAVAC); 841 Source componentFile = 842 javaFileBuilder("test.SimpleComponent") 843 .addLines( 844 "package test;", 845 "", 846 "import dagger.Component;", 847 "import javax.inject.Provider;", 848 "", 849 "@Component(modules = AbstractModule.class)", 850 "abstract class SimpleComponent {") 851 .addLinesIf( 852 BUILDER, 853 " @Component.Builder", 854 " interface Builder {", 855 " SimpleComponent build();", 856 " void abstractModule(AbstractModule abstractModule);", 857 " void other(String s);", 858 " }") 859 .addLinesIf( 860 FACTORY, 861 " @Component.Factory", 862 " interface Factory {", 863 " SimpleComponent create(AbstractModule abstractModule, String s);", 864 " }") 865 .addLines("}") 866 .buildSource(); 867 Source abstractModule = 868 CompilerTests.javaSource( 869 "test.AbstractModule", 870 "package test;", 871 "", 872 "import dagger.Module;", 873 "", 874 "@Module", 875 "abstract class AbstractModule {}"); 876 CompilerTests.daggerCompiler(componentFile, abstractModule) 877 .withProcessingOptions(compilerOptions) 878 .compile( 879 subject -> { 880 subject.hasErrorCount(1); 881 String elements = 882 creatorKind.equals(BUILDER) 883 ? "[void test.SimpleComponent.Builder.abstractModule(test.AbstractModule), " 884 + "void test.SimpleComponent.Builder.other(String)]" 885 : "[test.AbstractModule abstractModule, String s]"; 886 subject.hasErrorContaining(String.format(messages.extraSetters(), elements)) 887 .onSource(componentFile) 888 .onLineContaining(process("interface Builder")); 889 }); 890 } 891 892 @Test testMissingSettersFail()893 public void testMissingSettersFail() { 894 assume().that(compilerType).isEqualTo(JAVAC); 895 Source moduleFile = 896 CompilerTests.javaSource( 897 "test.TestModule", 898 "package test;", 899 "", 900 "import dagger.Module;", 901 "import dagger.Provides;", 902 "", 903 "@Module", 904 "final class TestModule {", 905 " TestModule(String unused) {}", 906 " @Provides String s() { return null; }", 907 "}"); 908 Source module2File = 909 CompilerTests.javaSource( 910 "test.Test2Module", 911 "package test;", 912 "", 913 "import dagger.Module;", 914 "import dagger.Provides;", 915 "", 916 "@Module", 917 "final class Test2Module {", 918 " @Provides Integer i() { return null; }", 919 "}"); 920 Source module3File = 921 CompilerTests.javaSource( 922 "test.Test3Module", 923 "package test;", 924 "", 925 "import dagger.Module;", 926 "import dagger.Provides;", 927 "", 928 "@Module", 929 "final class Test3Module {", 930 " Test3Module(String unused) {}", 931 " @Provides Double d() { return null; }", 932 "}"); 933 Source componentFile = 934 preprocessedJavaSource( 935 "test.TestComponent", 936 "package test;", 937 "", 938 "import dagger.Component;", 939 "", 940 "@Component(", 941 " modules = {TestModule.class, Test2Module.class, Test3Module.class},", 942 " dependencies = OtherComponent.class", 943 ")", 944 "interface TestComponent {", 945 " String string();", 946 " Integer integer();", 947 "", 948 " @Component.Builder", 949 " interface Builder {", 950 " TestComponent create();", 951 " }", 952 "}"); 953 Source otherComponent = 954 CompilerTests.javaSource( 955 "test.OtherComponent", 956 "package test;", 957 "", 958 "import dagger.Component;", 959 "", 960 "@Component", 961 "interface OtherComponent {}"); 962 CompilerTests.daggerCompiler( 963 moduleFile, module2File, module3File, componentFile, otherComponent) 964 .withProcessingOptions(compilerOptions) 965 .compile( 966 subject -> { 967 subject.hasErrorCount(1); 968 subject.hasErrorContaining( 969 // Ignores Test2Module because we can construct it ourselves. 970 // TODO(sameb): Ignore Test3Module because it's not used within transitive 971 // dependencies. 972 String.format( 973 messages.missingSetters(), 974 "[test.TestModule, test.Test3Module, test.OtherComponent]")) 975 .onSource(componentFile) 976 .onLineContaining(process("interface Builder")); 977 }); 978 } 979 980 @Test covariantFactoryMethodReturnType()981 public void covariantFactoryMethodReturnType() { 982 assume().that(compilerType).isEqualTo(JAVAC); 983 Source foo = 984 CompilerTests.javaSource( 985 "test.Foo", 986 "package test;", 987 "", 988 "import javax.inject.Inject;", 989 "", 990 "class Foo {", 991 " @Inject Foo() {}", 992 "}"); 993 Source supertype = 994 CompilerTests.javaSource( 995 "test.Supertype", 996 "package test;", 997 "", 998 "interface Supertype {", 999 " Foo foo();", 1000 "}"); 1001 1002 Source component = 1003 preprocessedJavaSource( 1004 "test.HasSupertype", 1005 "package test;", 1006 "", 1007 "import dagger.Component;", 1008 "", 1009 "@Component", 1010 "interface HasSupertype extends Supertype {", 1011 " @Component.Builder", 1012 " interface Builder {", 1013 " Supertype build();", 1014 " }", 1015 "}"); 1016 1017 CompilerTests.daggerCompiler(foo, supertype, component) 1018 .withProcessingOptions(compilerOptions) 1019 .compile( 1020 subject -> { 1021 subject.hasErrorCount(0); 1022 subject.hasWarningCount(0); 1023 }); 1024 } 1025 1026 @Test covariantFactoryMethodReturnType_hasNewMethod()1027 public void covariantFactoryMethodReturnType_hasNewMethod() { 1028 assume().that(compilerType).isEqualTo(JAVAC); 1029 Source foo = 1030 CompilerTests.javaSource( 1031 "test.Foo", 1032 "package test;", 1033 "", 1034 "import javax.inject.Inject;", 1035 "", 1036 "class Foo {", 1037 " @Inject Foo() {}", 1038 "}"); 1039 Source bar = 1040 CompilerTests.javaSource( 1041 "test.Bar", 1042 "package test;", 1043 "", 1044 "import javax.inject.Inject;", 1045 "", 1046 "class Bar {", 1047 " @Inject Bar() {}", 1048 "}"); 1049 Source supertype = 1050 CompilerTests.javaSource( 1051 "test.Supertype", 1052 "package test;", 1053 "", 1054 "interface Supertype {", 1055 " Foo foo();", 1056 "}"); 1057 1058 Source component = 1059 preprocessedJavaSource( 1060 "test.HasSupertype", 1061 "package test;", 1062 "", 1063 "import dagger.Component;", 1064 "", 1065 "@Component", 1066 "interface HasSupertype extends Supertype {", 1067 " Bar bar();", 1068 "", 1069 " @Component.Builder", 1070 " interface Builder {", 1071 " Supertype build();", 1072 " }", 1073 "}"); 1074 1075 CompilerTests.daggerCompiler(foo, bar, supertype, component) 1076 .withProcessingOptions(compilerOptions) 1077 .compile( 1078 subject -> { 1079 subject.hasErrorCount(0); 1080 subject.hasWarningContaining( 1081 process( 1082 "test.HasSupertype.Builder.build() returns test.Supertype, but " 1083 + "test.HasSupertype declares additional component method(s): bar(). " 1084 + "In order to provide type-safe access to these methods, override " 1085 + "build() to return test.HasSupertype")) 1086 .onSource(component) 1087 .onLine(11); 1088 }); 1089 } 1090 1091 @Test covariantFactoryMethodReturnType_hasNewMethod_factoryMethodInherited()1092 public void covariantFactoryMethodReturnType_hasNewMethod_factoryMethodInherited() { 1093 assume().that(compilerType).isEqualTo(JAVAC); 1094 Source foo = 1095 CompilerTests.javaSource( 1096 "test.Foo", 1097 "package test;", 1098 "", 1099 "import javax.inject.Inject;", 1100 "", 1101 "class Foo {", 1102 " @Inject Foo() {}", 1103 "}"); 1104 Source bar = 1105 CompilerTests.javaSource( 1106 "test.Bar", 1107 "package test;", 1108 "", 1109 "import javax.inject.Inject;", 1110 "", 1111 "class Bar {", 1112 " @Inject Bar() {}", 1113 "}"); 1114 Source supertype = 1115 CompilerTests.javaSource( 1116 "test.Supertype", 1117 "package test;", 1118 "", 1119 "interface Supertype {", 1120 " Foo foo();", 1121 "}"); 1122 1123 Source creatorSupertype = 1124 preprocessedJavaSource( 1125 "test.CreatorSupertype", 1126 "package test;", 1127 "", 1128 "interface CreatorSupertype {", 1129 " Supertype build();", 1130 "}"); 1131 1132 Source component = 1133 preprocessedJavaSource( 1134 "test.HasSupertype", 1135 "package test;", 1136 "", 1137 "import dagger.Component;", 1138 "", 1139 "@Component", 1140 "interface HasSupertype extends Supertype {", 1141 " Bar bar();", 1142 "", 1143 " @Component.Builder", 1144 " interface Builder extends CreatorSupertype {}", 1145 "}"); 1146 1147 CompilerTests.daggerCompiler(foo, bar, supertype, creatorSupertype, component) 1148 .withProcessingOptions(compilerOptions) 1149 .compile( 1150 subject -> { 1151 subject.hasErrorCount(0); 1152 subject.hasWarningContaining( 1153 process( 1154 "test.HasSupertype.Builder.build() returns test.Supertype, but " 1155 + "test.HasSupertype declares additional component method(s): bar(). " 1156 + "In order to provide type-safe access to these methods, override " 1157 + "build() to return test.HasSupertype")); 1158 }); 1159 } 1160 1161 @Test testGenericsOnFactoryMethodFails()1162 public void testGenericsOnFactoryMethodFails() { 1163 Source componentFile = 1164 preprocessedJavaSource( 1165 "test.SimpleComponent", 1166 "package test;", 1167 "", 1168 "import dagger.Component;", 1169 "import javax.inject.Provider;", 1170 "", 1171 "@Component", 1172 "abstract class SimpleComponent {", 1173 " @Component.Builder", 1174 " interface Builder {", 1175 " <T> SimpleComponent build();", 1176 " }", 1177 "}"); 1178 CompilerTests.daggerCompiler(componentFile) 1179 .withProcessingOptions(compilerOptions) 1180 .compile( 1181 subject -> { 1182 subject.hasErrorCount(1); 1183 subject.hasErrorContaining(messages.methodsMayNotHaveTypeParameters()) 1184 .onSource(componentFile) 1185 .onLineContaining(process("<T> SimpleComponent build();")); 1186 }); 1187 } 1188 1189 @Test testGenericsOnInheritedFactoryMethodFails()1190 public void testGenericsOnInheritedFactoryMethodFails() { 1191 Source componentFile = 1192 preprocessedJavaSource( 1193 "test.SimpleComponent", 1194 "package test;", 1195 "", 1196 "import dagger.Component;", 1197 "import javax.inject.Provider;", 1198 "", 1199 "@Component", 1200 "abstract class SimpleComponent {", 1201 " interface Parent {", 1202 " <T> SimpleComponent build();", 1203 " }", 1204 "", 1205 " @Component.Builder", 1206 " interface Builder extends Parent {}", 1207 "}"); 1208 CompilerTests.daggerCompiler(componentFile) 1209 .withProcessingOptions(compilerOptions) 1210 .compile( 1211 subject -> { 1212 subject.hasErrorCount(1); 1213 subject.hasErrorContaining( 1214 String.format( 1215 messages.inheritedMethodsMayNotHaveTypeParameters(), 1216 process("test.SimpleComponent test.SimpleComponent.Parent.build()"))) 1217 .onSource(componentFile) 1218 .onLineContaining(process("interface Builder")); 1219 }); 1220 } 1221 } 1222