1 /* 2 * Copyright (C) 2014 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.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import androidx.room.compiler.processing.util.CompilationResultSubject; 23 import androidx.room.compiler.processing.util.Source; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableMap; 26 import com.squareup.javapoet.AnnotationSpec; 27 import com.squareup.javapoet.MethodSpec; 28 import com.squareup.javapoet.TypeSpec; 29 import dagger.MembersInjector; 30 import dagger.internal.codegen.javapoet.TypeNames; 31 import dagger.testing.compile.CompilerTests; 32 import dagger.testing.golden.GoldenFileRule; 33 import java.util.Collection; 34 import javax.inject.Inject; 35 import javax.tools.Diagnostic; 36 import org.junit.Rule; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 import org.junit.runners.Parameterized; 40 import org.junit.runners.Parameterized.Parameters; 41 42 @RunWith(Parameterized.class) 43 public class ComponentProcessorTest { 44 @Parameters(name = "{0}") parameters()45 public static Collection<Object[]> parameters() { 46 return CompilerMode.TEST_PARAMETERS; 47 } 48 49 private static final TypeSpec GENERATED_INJECT_TYPE = 50 TypeSpec.classBuilder("GeneratedInjectType") 51 .addMethod( 52 MethodSpec.constructorBuilder() 53 .addAnnotation(TypeNames.INJECT_JAVAX) 54 .build()) 55 .build(); 56 57 private static final TypeSpec GENERATED_QUALIFIER = 58 TypeSpec.annotationBuilder("GeneratedQualifier") 59 .addAnnotation(AnnotationSpec.builder(TypeNames.QUALIFIER_JAVAX).build()) 60 .build(); 61 62 private static final TypeSpec GENERATED_MODULE = 63 TypeSpec.classBuilder("GeneratedModule").addAnnotation(TypeNames.MODULE).build(); 64 65 66 @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); 67 68 private final CompilerMode compilerMode; 69 ComponentProcessorTest(CompilerMode compilerMode)70 public ComponentProcessorTest(CompilerMode compilerMode) { 71 this.compilerMode = compilerMode; 72 } 73 74 @Test doubleBindingFromResolvedModules()75 public void doubleBindingFromResolvedModules() { 76 Source parent = CompilerTests.javaSource("test.ParentModule", 77 "package test;", 78 "", 79 "import dagger.Module;", 80 "import dagger.Provides;", 81 "import java.util.List;", 82 "", 83 "@Module", 84 "abstract class ParentModule<A> {", 85 " @Provides List<A> provideListB(A a) { return null; }", 86 "}"); 87 Source child = CompilerTests.javaSource("test.ChildNumberModule", 88 "package test;", 89 "", 90 "import dagger.Module;", 91 "import dagger.Provides;", 92 "", 93 "@Module", 94 "class ChildNumberModule extends ParentModule<Integer> {", 95 " @Provides Integer provideInteger() { return null; }", 96 "}"); 97 Source another = CompilerTests.javaSource("test.AnotherModule", 98 "package test;", 99 "", 100 "import dagger.Module;", 101 "import dagger.Provides;", 102 "import java.util.List;", 103 "", 104 "@Module", 105 "class AnotherModule {", 106 " @Provides List<Integer> provideListOfInteger() { return null; }", 107 "}"); 108 Source componentFile = CompilerTests.javaSource("test.BadComponent", 109 "package test;", 110 "", 111 "import dagger.Component;", 112 "import java.util.List;", 113 "", 114 "@Component(modules = {ChildNumberModule.class, AnotherModule.class})", 115 "interface BadComponent {", 116 " List<Integer> listOfInteger();", 117 "}"); 118 119 CompilerTests.daggerCompiler(parent, child, another, componentFile) 120 .withProcessingOptions(compilerMode.processorOptions()) 121 .compile( 122 subject -> { 123 subject.hasErrorCount(1); 124 subject.hasErrorContaining("List<Integer> is bound multiple times"); 125 subject.hasErrorContaining( 126 "@Provides List<Integer> ChildNumberModule.provideListB(Integer)"); 127 subject.hasErrorContaining( 128 "@Provides List<Integer> AnotherModule.provideListOfInteger()"); 129 }); 130 } 131 132 @Test privateNestedClassWithWarningThatIsAnErrorInComponent()133 public void privateNestedClassWithWarningThatIsAnErrorInComponent() { 134 Source outerClass = CompilerTests.javaSource("test.OuterClass", 135 "package test;", 136 "", 137 "import javax.inject.Inject;", 138 "", 139 "final class OuterClass {", 140 " @Inject OuterClass(InnerClass innerClass) {}", 141 "", 142 " private static final class InnerClass {", 143 " @Inject InnerClass() {}", 144 " }", 145 "}"); 146 Source componentFile = CompilerTests.javaSource("test.BadComponent", 147 "package test;", 148 "", 149 "import dagger.Component;", 150 "", 151 "@Component", 152 "interface BadComponent {", 153 " OuterClass outerClass();", 154 "}"); 155 CompilerTests.daggerCompiler(outerClass, componentFile) 156 .withProcessingOptions( 157 ImmutableMap.<String, String>builder() 158 .putAll(compilerMode.processorOptions()) 159 .put("dagger.privateMemberValidation", "WARNING") 160 .buildOrThrow()) 161 .compile( 162 subject -> 163 // Because it is just a warning until it is used, the factory still gets generated 164 // which has errors from referencing the private class, so there are extra errors. 165 // Hence we don't assert on the number of errors. 166 subject.hasErrorContaining( 167 "Dagger does not support injection into private classes")); 168 } 169 170 @Test simpleComponent()171 public void simpleComponent() throws Exception { 172 Source injectableTypeFile = CompilerTests.javaSource("test/SomeInjectableType", 173 "package test;", 174 "", 175 "import javax.inject.Inject;", 176 "", 177 "final class SomeInjectableType {", 178 " @Inject SomeInjectableType() {}", 179 "}"); 180 Source componentFile = CompilerTests.javaSource("test/SimpleComponent", 181 "package test;", 182 "", 183 "import dagger.Component;", 184 "import dagger.Lazy;", 185 "import javax.inject.Provider;", 186 "", 187 "@Component", 188 "interface SimpleComponent {", 189 " SomeInjectableType someInjectableType();", 190 " Lazy<SomeInjectableType> lazySomeInjectableType();", 191 " Provider<SomeInjectableType> someInjectableTypeProvider();", 192 "}"); 193 194 CompilerTests.daggerCompiler(injectableTypeFile, componentFile) 195 .withProcessingOptions(compilerMode.processorOptions()) 196 .compile( 197 subject -> { 198 subject.hasErrorCount(0); 199 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 200 }); 201 } 202 203 @Test componentWithScope()204 public void componentWithScope() throws Exception { 205 Source injectableTypeFile = CompilerTests.javaSource("test.SomeInjectableType", 206 "package test;", 207 "", 208 "import javax.inject.Inject;", 209 "import javax.inject.Singleton;", 210 "", 211 "@Singleton", 212 "final class SomeInjectableType {", 213 " @Inject SomeInjectableType() {}", 214 "}"); 215 Source componentFile = CompilerTests.javaSource("test.SimpleComponent", 216 "package test;", 217 "", 218 "import dagger.Component;", 219 "import dagger.Lazy;", 220 "import javax.inject.Provider;", 221 "import javax.inject.Singleton;", 222 "", 223 "@Singleton", 224 "@Component", 225 "interface SimpleComponent {", 226 " SomeInjectableType someInjectableType();", 227 " Lazy<SomeInjectableType> lazySomeInjectableType();", 228 " Provider<SomeInjectableType> someInjectableTypeProvider();", 229 "}"); 230 231 CompilerTests.daggerCompiler(injectableTypeFile, componentFile) 232 .withProcessingOptions(compilerMode.processorOptions()) 233 .compile( 234 subject -> { 235 subject.hasErrorCount(0); 236 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 237 }); 238 } 239 240 @Test simpleComponentWithNesting()241 public void simpleComponentWithNesting() throws Exception { 242 Source nestedTypesFile = CompilerTests.javaSource("test.OuterType", 243 "package test;", 244 "", 245 "import dagger.Component;", 246 "import javax.inject.Inject;", 247 "", 248 "final class OuterType {", 249 " static class A {", 250 " @Inject A() {}", 251 " }", 252 " static class B {", 253 " @Inject A a;", 254 " }", 255 " @Component interface SimpleComponent {", 256 " A a();", 257 " void inject(B b);", 258 " }", 259 "}"); 260 261 CompilerTests.daggerCompiler(nestedTypesFile) 262 .withProcessingOptions(compilerMode.processorOptions()) 263 .compile( 264 subject -> { 265 subject.hasErrorCount(0); 266 subject.generatedSource( 267 goldenFileRule.goldenSource("test/DaggerOuterType_SimpleComponent")); 268 }); 269 } 270 271 @Test componentWithModule()272 public void componentWithModule() throws Exception { 273 Source aFile = CompilerTests.javaSource("test.A", 274 "package test;", 275 "", 276 "import javax.inject.Inject;", 277 "", 278 "final class A {", 279 " @Inject A(B b) {}", 280 "}"); 281 Source bFile = CompilerTests.javaSource("test.B", 282 "package test;", 283 "", 284 "interface B {}"); 285 Source cFile = CompilerTests.javaSource("test.C", 286 "package test;", 287 "", 288 "import javax.inject.Inject;", 289 "", 290 "final class C {", 291 " @Inject C() {}", 292 "}"); 293 294 Source moduleFile = CompilerTests.javaSource("test.TestModule", 295 "package test;", 296 "", 297 "import dagger.Module;", 298 "import dagger.Provides;", 299 "", 300 "@Module", 301 "final class TestModule {", 302 " @Provides B b(C c) { return null; }", 303 "}"); 304 305 Source componentFile = CompilerTests.javaSource("test.TestComponent", 306 "package test;", 307 "", 308 "import dagger.Component;", 309 "import javax.inject.Provider;", 310 "", 311 "@Component(modules = TestModule.class)", 312 "interface TestComponent {", 313 " A a();", 314 "}"); 315 316 CompilerTests.daggerCompiler(aFile, bFile, cFile, moduleFile, componentFile) 317 .withProcessingOptions(compilerMode.processorOptions()) 318 .compile( 319 subject -> { 320 subject.hasErrorCount(0); 321 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 322 }); 323 } 324 325 @Test componentWithAbstractModule()326 public void componentWithAbstractModule() throws Exception { 327 Source aFile = CompilerTests.javaSource( 328 "test.A", 329 "package test;", 330 "", 331 "import javax.inject.Inject;", 332 "", 333 "final class A {", 334 " @Inject A(B b) {}", 335 "}"); 336 Source bFile = CompilerTests.javaSource("test.B", 337 "package test;", 338 "", 339 "interface B {}"); 340 Source cFile = CompilerTests.javaSource( 341 "test.C", 342 "package test;", 343 "", 344 "import javax.inject.Inject;", 345 "", 346 "final class C {", 347 " @Inject C() {}", 348 "}"); 349 350 Source moduleFile = CompilerTests.javaSource( 351 "test.TestModule", 352 "package test;", 353 "", 354 "import dagger.Module;", 355 "import dagger.Provides;", 356 "", 357 "@Module", 358 "abstract class TestModule {", 359 " @Provides static B b(C c) { return null; }", 360 "}"); 361 362 Source componentFile = CompilerTests.javaSource( 363 "test.TestComponent", 364 "package test;", 365 "", 366 "import dagger.Component;", 367 "", 368 "@Component(modules = TestModule.class)", 369 "interface TestComponent {", 370 " A a();", 371 "}"); 372 373 CompilerTests.daggerCompiler(aFile, bFile, cFile, moduleFile, componentFile) 374 .withProcessingOptions(compilerMode.processorOptions()) 375 .compile( 376 subject -> { 377 subject.hasErrorCount(0); 378 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 379 }); 380 } 381 382 @Test transitiveModuleDeps()383 public void transitiveModuleDeps() throws Exception { 384 Source always = CompilerTests.javaSource("test.AlwaysIncluded", 385 "package test;", 386 "", 387 "import dagger.Module;", 388 "", 389 "@Module", 390 "final class AlwaysIncluded {}"); 391 Source testModule = CompilerTests.javaSource("test.TestModule", 392 "package test;", 393 "", 394 "import dagger.Module;", 395 "", 396 "@Module(includes = {DepModule.class, AlwaysIncluded.class})", 397 "final class TestModule extends ParentTestModule {}"); 398 Source parentTest = CompilerTests.javaSource("test.ParentTestModule", 399 "package test;", 400 "", 401 "import dagger.Module;", 402 "", 403 "@Module(includes = {ParentTestIncluded.class, AlwaysIncluded.class})", 404 "class ParentTestModule {}"); 405 Source parentTestIncluded = CompilerTests.javaSource("test.ParentTestIncluded", 406 "package test;", 407 "", 408 "import dagger.Module;", 409 "", 410 "@Module(includes = AlwaysIncluded.class)", 411 "final class ParentTestIncluded {}"); 412 Source depModule = CompilerTests.javaSource("test.DepModule", 413 "package test;", 414 "", 415 "import dagger.Module;", 416 "", 417 "@Module(includes = {RefByDep.class, AlwaysIncluded.class})", 418 "final class DepModule extends ParentDepModule {}"); 419 Source refByDep = CompilerTests.javaSource("test.RefByDep", 420 "package test;", 421 "", 422 "import dagger.Module;", 423 "", 424 "@Module(includes = AlwaysIncluded.class)", 425 "final class RefByDep extends ParentDepModule {}"); 426 Source parentDep = CompilerTests.javaSource("test.ParentDepModule", 427 "package test;", 428 "", 429 "import dagger.Module;", 430 "", 431 "@Module(includes = {ParentDepIncluded.class, AlwaysIncluded.class})", 432 "class ParentDepModule {}"); 433 Source parentDepIncluded = CompilerTests.javaSource("test.ParentDepIncluded", 434 "package test;", 435 "", 436 "import dagger.Module;", 437 "", 438 "@Module(includes = AlwaysIncluded.class)", 439 "final class ParentDepIncluded {}"); 440 441 Source componentFile = CompilerTests.javaSource("test.TestComponent", 442 "package test;", 443 "", 444 "import dagger.Component;", 445 "", 446 "@Component(modules = TestModule.class)", 447 "interface TestComponent {", 448 "}"); 449 450 CompilerTests.daggerCompiler( 451 always, 452 testModule, 453 parentTest, 454 parentTestIncluded, 455 depModule, 456 refByDep, 457 parentDep, 458 parentDepIncluded, 459 componentFile) 460 .withProcessingOptions(compilerMode.processorOptions()) 461 .compile( 462 subject -> { 463 subject.hasErrorCount(0); 464 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 465 }); 466 } 467 468 @Test generatedTransitiveModule()469 public void generatedTransitiveModule() { 470 Source rootModule = 471 CompilerTests.javaSource( 472 "test.RootModule", 473 "package test;", 474 "", 475 "import dagger.Module;", 476 "", 477 "@Module(includes = GeneratedModule.class)", 478 "final class RootModule {}"); 479 Source component = 480 CompilerTests.javaSource( 481 "test.TestComponent", 482 "package test;", 483 "", 484 "import dagger.Component;", 485 "", 486 "@Component(modules = RootModule.class)", 487 "interface TestComponent {}"); 488 489 CompilerTests.daggerCompiler(rootModule, component) 490 .withProcessingOptions(compilerMode.processorOptions()) 491 .compile(subject -> subject.hasError()); 492 493 CompilerTests.daggerCompiler(rootModule, component) 494 .withProcessingOptions(compilerMode.processorOptions()) 495 .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_MODULE)) 496 .compile(subject -> subject.hasErrorCount(0)); 497 } 498 499 @Test generatedModuleInSubcomponent()500 public void generatedModuleInSubcomponent() { 501 Source subcomponent = 502 CompilerTests.javaSource( 503 "test.ChildComponent", 504 "package test;", 505 "", 506 "import dagger.Subcomponent;", 507 "", 508 "@Subcomponent(modules = GeneratedModule.class)", 509 "interface ChildComponent {}"); 510 Source component = 511 CompilerTests.javaSource( 512 "test.TestComponent", 513 "package test;", 514 "", 515 "import dagger.Component;", 516 "", 517 "@Component", 518 "interface TestComponent {", 519 " ChildComponent childComponent();", 520 "}"); 521 CompilerTests.daggerCompiler(subcomponent, component) 522 .withProcessingOptions(compilerMode.processorOptions()) 523 .compile(subject -> subject.hasError()); 524 525 CompilerTests.daggerCompiler(subcomponent, component) 526 .withProcessingOptions(compilerMode.processorOptions()) 527 .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_MODULE)) 528 .compile(subject -> subject.hasErrorCount(0)); 529 } 530 531 @Test subcomponentNotGeneratedIfNotUsedInGraph()532 public void subcomponentNotGeneratedIfNotUsedInGraph() throws Exception { 533 Source component = 534 CompilerTests.javaSource( 535 "test.Parent", 536 "package test;", 537 "", 538 "import dagger.Component;", 539 "", 540 "@Component(modules = ParentModule.class)", 541 "interface Parent {", 542 " String notSubcomponent();", 543 "}"); 544 Source module = 545 CompilerTests.javaSource( 546 "test.ParentModule", 547 "package test;", 548 "", 549 "import dagger.Module;", 550 "import dagger.Provides;", 551 "", 552 "@Module(subcomponents = Child.class)", 553 "class ParentModule {", 554 " @Provides static String notSubcomponent() { return new String(); }", 555 "}"); 556 557 Source subcomponent = 558 CompilerTests.javaSource( 559 "test.Child", 560 "package test;", 561 "", 562 "import dagger.Subcomponent;", 563 "", 564 "@Subcomponent", 565 "interface Child {", 566 " @Subcomponent.Builder", 567 " interface Builder {", 568 " Child build();", 569 " }", 570 "}"); 571 572 CompilerTests.daggerCompiler(component, module, subcomponent) 573 .withProcessingOptions(compilerMode.processorOptions()) 574 .compile( 575 subject -> { 576 subject.hasErrorCount(0); 577 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent")); 578 }); 579 } 580 581 @Test testDefaultPackage()582 public void testDefaultPackage() { 583 Source aClass = CompilerTests.javaSource("AClass", "class AClass {}"); 584 Source bClass = CompilerTests.javaSource("BClass", 585 "import javax.inject.Inject;", 586 "", 587 "class BClass {", 588 " @Inject BClass(AClass a) {}", 589 "}"); 590 Source aModule = CompilerTests.javaSource("AModule", 591 "import dagger.Module;", 592 "import dagger.Provides;", 593 "", 594 "@Module class AModule {", 595 " @Provides AClass aClass() {", 596 " return new AClass();", 597 " }", 598 "}"); 599 Source component = CompilerTests.javaSource("SomeComponent", 600 "import dagger.Component;", 601 "", 602 "@Component(modules = AModule.class)", 603 "interface SomeComponent {", 604 " BClass bClass();", 605 "}"); 606 607 CompilerTests.daggerCompiler(aModule, aClass, bClass, component) 608 .withProcessingOptions(compilerMode.processorOptions()) 609 .compile(subject -> subject.hasErrorCount(0)); 610 } 611 612 @Test membersInjection()613 public void membersInjection() throws Exception { 614 Source injectableTypeFile = CompilerTests.javaSource("test.SomeInjectableType", 615 "package test;", 616 "", 617 "import javax.inject.Inject;", 618 "", 619 "final class SomeInjectableType {", 620 " @Inject SomeInjectableType() {}", 621 "}"); 622 Source injectedTypeFile = CompilerTests.javaSource("test.SomeInjectedType", 623 "package test;", 624 "", 625 "import javax.inject.Inject;", 626 "", 627 "final class SomeInjectedType {", 628 " @Inject SomeInjectableType injectedField;", 629 " SomeInjectedType() {}", 630 "}"); 631 Source componentFile = CompilerTests.javaSource("test.SimpleComponent", 632 "package test;", 633 "", 634 "import dagger.Component;", 635 "import dagger.Lazy;", 636 "import javax.inject.Provider;", 637 "", 638 "@Component", 639 "interface SimpleComponent {", 640 " void inject(SomeInjectedType instance);", 641 " SomeInjectedType injectAndReturn(SomeInjectedType instance);", 642 "}"); 643 644 CompilerTests.daggerCompiler(injectableTypeFile, injectedTypeFile, componentFile) 645 .withProcessingOptions(compilerMode.processorOptions()) 646 .compile( 647 subject -> { 648 subject.hasErrorCount(0); 649 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 650 }); 651 } 652 653 @Test componentInjection()654 public void componentInjection() throws Exception { 655 Source injectableTypeFile = 656 CompilerTests.javaSource( 657 "test.SomeInjectableType", 658 "package test;", 659 "", 660 "import javax.inject.Inject;", 661 "", 662 "final class SomeInjectableType {", 663 " @Inject SomeInjectableType(SimpleComponent component) {}", 664 "}"); 665 Source componentFile = 666 CompilerTests.javaSource( 667 "test.SimpleComponent", 668 "package test;", 669 "", 670 "import dagger.Component;", 671 "import dagger.Lazy;", 672 "import javax.inject.Provider;", 673 "", 674 "@Component", 675 "interface SimpleComponent {", 676 " SomeInjectableType someInjectableType();", 677 " Provider<SimpleComponent> selfProvider();", 678 "}"); 679 680 CompilerTests.daggerCompiler(injectableTypeFile, componentFile) 681 .withProcessingOptions(compilerMode.processorOptions()) 682 .compile( 683 subject -> { 684 subject.hasErrorCount(0); 685 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 686 }); 687 } 688 689 @Test membersInjectionInsideProvision()690 public void membersInjectionInsideProvision() throws Exception { 691 Source injectableTypeFile = 692 CompilerTests.javaSource( 693 "test.SomeInjectableType", 694 "package test;", 695 "", 696 "import javax.inject.Inject;", 697 "", 698 "final class SomeInjectableType {", 699 " @Inject SomeInjectableType() {}", 700 "}"); 701 Source injectedTypeFile = 702 CompilerTests.javaSource( 703 "test.SomeInjectedType", 704 "package test;", 705 "", 706 "import javax.inject.Inject;", 707 "", 708 "final class SomeInjectedType {", 709 " @Inject SomeInjectableType injectedField;", 710 " @Inject SomeInjectedType() {}", 711 "}"); 712 Source componentFile = 713 CompilerTests.javaSource( 714 "test.SimpleComponent", 715 "package test;", 716 "", 717 "import dagger.Component;", 718 "", 719 "@Component", 720 "interface SimpleComponent {", 721 " SomeInjectedType createAndInject();", 722 "}"); 723 CompilerTests.daggerCompiler(injectableTypeFile, injectedTypeFile, componentFile) 724 .withProcessingOptions(compilerMode.processorOptions()) 725 .compile( 726 subject -> { 727 subject.hasErrorCount(0); 728 subject.generatedSourceFileWithPath("test/DaggerSimpleComponent.java"); 729 }); 730 } 731 732 @Test componentDependency()733 public void componentDependency() throws Exception { 734 Source aFile = CompilerTests.javaSource("test.A", 735 "package test;", 736 "", 737 "import javax.inject.Inject;", 738 "", 739 "final class A {", 740 " @Inject A() {}", 741 "}"); 742 Source bFile = CompilerTests.javaSource("test.B", 743 "package test;", 744 "", 745 "import javax.inject.Inject;", 746 "import javax.inject.Provider;", 747 "", 748 "final class B {", 749 " @Inject B(Provider<A> a) {}", 750 "}"); 751 Source aComponentFile = CompilerTests.javaSource("test.AComponent", 752 "package test;", 753 "", 754 "import dagger.Component;", 755 "", 756 "@Component", 757 "interface AComponent {", 758 " A a();", 759 "}"); 760 Source bComponentFile = CompilerTests.javaSource("test.BComponent", 761 "package test;", 762 "", 763 "import dagger.Component;", 764 "", 765 "@Component(dependencies = AComponent.class)", 766 "interface BComponent {", 767 " B b();", 768 "}"); 769 770 CompilerTests.daggerCompiler(aFile, bFile, aComponentFile, bComponentFile) 771 .withProcessingOptions(compilerMode.processorOptions()) 772 .compile( 773 subject -> { 774 subject.hasErrorCount(0); 775 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent")); 776 }); 777 } 778 779 @Test primitiveComponentDependency()780 public void primitiveComponentDependency() throws Exception { 781 Source bFile = CompilerTests.javaSource("test.B", 782 "package test;", 783 "", 784 "import javax.inject.Inject;", 785 "import javax.inject.Provider;", 786 "", 787 "final class B {", 788 " @Inject B(Provider<Integer> i) {}", 789 "}"); 790 Source intComponentFile = CompilerTests.javaSource("test.IntComponent", 791 "package test;", 792 "", 793 "interface IntComponent {", 794 " int i();", 795 "}"); 796 Source bComponentFile = CompilerTests.javaSource("test.BComponent", 797 "package test;", 798 "", 799 "import dagger.Component;", 800 "", 801 "@Component(dependencies = IntComponent.class)", 802 "interface BComponent {", 803 " B b();", 804 "}"); 805 806 CompilerTests.daggerCompiler(bFile, intComponentFile, bComponentFile) 807 .withProcessingOptions(compilerMode.processorOptions()) 808 .compile( 809 subject -> { 810 subject.hasErrorCount(0); 811 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent")); 812 }); 813 } 814 815 @Test arrayComponentDependency()816 public void arrayComponentDependency() throws Exception { 817 Source bFile = CompilerTests.javaSource("test.B", 818 "package test;", 819 "", 820 "import javax.inject.Inject;", 821 "import javax.inject.Provider;", 822 "", 823 "final class B {", 824 " @Inject B(Provider<String[]> i) {}", 825 "}"); 826 Source arrayComponentFile = CompilerTests.javaSource("test.ArrayComponent", 827 "package test;", 828 "", 829 "interface ArrayComponent {", 830 " String[] strings();", 831 "}"); 832 Source bComponentFile = CompilerTests.javaSource("test.BComponent", 833 "package test;", 834 "", 835 "import dagger.Component;", 836 "", 837 "@Component(dependencies = ArrayComponent.class)", 838 "interface BComponent {", 839 " B b();", 840 "}"); 841 842 CompilerTests.daggerCompiler(bFile, arrayComponentFile, bComponentFile) 843 .withProcessingOptions(compilerMode.processorOptions()) 844 .compile( 845 subject -> { 846 subject.hasErrorCount(0); 847 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent")); 848 }); 849 } 850 851 @Test dependencyNameCollision()852 public void dependencyNameCollision() throws Exception { 853 Source a1 = CompilerTests.javaSource("pkg1.A", 854 "package pkg1;", 855 "", 856 "import javax.inject.Inject;", 857 "", 858 "public final class A {", 859 " @Inject A() {}", 860 "}"); 861 Source a2 = CompilerTests.javaSource("pkg2.A", 862 "package pkg2;", 863 "", 864 "import javax.inject.Inject;", 865 "", 866 "public final class A {", 867 " @Inject A() {}", 868 "}"); 869 Source a1Component = CompilerTests.javaSource("pkg1.AComponent", 870 "package pkg1;", 871 "", 872 "import dagger.Component;", 873 "", 874 "@Component", 875 "public interface AComponent {", 876 " A a();", 877 "}"); 878 Source a2Component = CompilerTests.javaSource("pkg2.AComponent", 879 "package pkg2;", 880 "", 881 "import dagger.Component;", 882 "", 883 "@Component", 884 "public interface AComponent {", 885 " A a();", 886 "}"); 887 Source bComponent = CompilerTests.javaSource("test.BComponent", 888 "package test;", 889 "", 890 "import dagger.Component;", 891 "", 892 "@Component(dependencies = {pkg1.AComponent.class, pkg2.AComponent.class})", 893 "interface BComponent {", 894 " B b();", 895 "}"); 896 Source b = CompilerTests.javaSource("test.B", 897 "package test;", 898 "", 899 "import javax.inject.Inject;", 900 "import javax.inject.Provider;", 901 "", 902 "final class B {", 903 " @Inject B(Provider<pkg1.A> a1, Provider<pkg2.A> a2) {}", 904 "}"); 905 906 CompilerTests.daggerCompiler(a1, a2, b, a1Component, a2Component, bComponent) 907 .withProcessingOptions(compilerMode.processorOptions()) 908 .compile( 909 subject -> { 910 subject.hasErrorCount(0); 911 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent")); 912 }); 913 } 914 915 @Test moduleNameCollision()916 public void moduleNameCollision() throws Exception { 917 Source aFile = 918 CompilerTests.javaSource( 919 "test.A", 920 "package test;", 921 "", 922 "public final class A {}"); 923 Source otherAFile = 924 CompilerTests.javaSource( 925 "other.test.A", 926 "package other.test;", 927 "", 928 "public final class A {}"); 929 Source moduleFile = 930 CompilerTests.javaSource( 931 "test.TestModule", 932 "package test;", 933 "", 934 "import dagger.Module;", 935 "import dagger.Provides;", 936 "", 937 "@Module", 938 "public final class TestModule {", 939 " @Provides A a() { return null; }", 940 "}"); 941 Source otherModuleFile = 942 CompilerTests.javaSource( 943 "other.test.TestModule", 944 "package other.test;", 945 "", 946 "import dagger.Module;", 947 "import dagger.Provides;", 948 "", 949 "@Module", 950 "public final class TestModule {", 951 " @Provides A a() { return null; }", 952 "}"); 953 Source componentFile = 954 CompilerTests.javaSource( 955 "test.TestComponent", 956 "package test;", 957 "", 958 "import dagger.Component;", 959 "import javax.inject.Provider;", 960 "", 961 "@Component(modules = {TestModule.class, other.test.TestModule.class})", 962 "interface TestComponent {", 963 " A a();", 964 " other.test.A otherA();", 965 "}"); 966 CompilerTests.daggerCompiler(aFile, otherAFile, moduleFile, otherModuleFile, componentFile) 967 .withProcessingOptions(compilerMode.processorOptions()) 968 .compile( 969 subject -> { 970 subject.hasErrorCount(0); 971 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 972 }); 973 } 974 975 @Test ignoresDependencyMethodsFromObject()976 public void ignoresDependencyMethodsFromObject() throws Exception { 977 Source injectedTypeFile = 978 CompilerTests.javaSource( 979 "test.InjectedType", 980 "package test;", 981 "", 982 "import javax.inject.Inject;", 983 "import javax.inject.Provider;", 984 "", 985 "final class InjectedType {", 986 " @Inject InjectedType(", 987 " String stringInjection,", 988 " int intInjection,", 989 " AComponent aComponent,", 990 " Class<AComponent> aClass) {}", 991 "}"); 992 Source aComponentFile = 993 CompilerTests.javaSource( 994 "test.AComponent", 995 "package test;", 996 "", 997 "class AComponent {", 998 " String someStringInjection() {", 999 " return \"injectedString\";", 1000 " }", 1001 "", 1002 " int someIntInjection() {", 1003 " return 123;", 1004 " }", 1005 "", 1006 " Class<AComponent> someClassInjection() {", 1007 " return AComponent.class;", 1008 " }", 1009 "", 1010 " @Override", 1011 " public String toString() {", 1012 " return null;", 1013 " }", 1014 "", 1015 " @Override", 1016 " public int hashCode() {", 1017 " return 456;", 1018 " }", 1019 "", 1020 " @Override", 1021 " public AComponent clone() {", 1022 " return null;", 1023 " }", 1024 "}"); 1025 Source bComponentFile = 1026 CompilerTests.javaSource( 1027 "test.BComponent", 1028 "package test;", 1029 "", 1030 "import dagger.Component;", 1031 "", 1032 "@Component(dependencies = AComponent.class)", 1033 "interface BComponent {", 1034 " InjectedType injectedType();", 1035 "}"); 1036 1037 CompilerTests.daggerCompiler(injectedTypeFile, aComponentFile, bComponentFile) 1038 .withProcessingOptions(compilerMode.processorOptions()) 1039 .compile( 1040 subject -> { 1041 subject.hasErrorCount(0); 1042 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent")); 1043 }); 1044 } 1045 1046 @Test resolutionOrder()1047 public void resolutionOrder() throws Exception { 1048 Source aFile = CompilerTests.javaSource("test.A", 1049 "package test;", 1050 "", 1051 "import javax.inject.Inject;", 1052 "", 1053 "final class A {", 1054 " @Inject A(B b) {}", 1055 "}"); 1056 Source bFile = CompilerTests.javaSource("test.B", 1057 "package test;", 1058 "", 1059 "import javax.inject.Inject;", 1060 "", 1061 "final class B {", 1062 " @Inject B(C c) {}", 1063 "}"); 1064 Source cFile = CompilerTests.javaSource("test.C", 1065 "package test;", 1066 "", 1067 "import javax.inject.Inject;", 1068 "", 1069 "final class C {", 1070 " @Inject C() {}", 1071 "}"); 1072 Source xFile = CompilerTests.javaSource("test.X", 1073 "package test;", 1074 "", 1075 "import javax.inject.Inject;", 1076 "", 1077 "final class X {", 1078 " @Inject X(C c) {}", 1079 "}"); 1080 1081 Source componentFile = CompilerTests.javaSource("test.TestComponent", 1082 "package test;", 1083 "", 1084 "import dagger.Component;", 1085 "import javax.inject.Provider;", 1086 "", 1087 "@Component", 1088 "interface TestComponent {", 1089 " A a();", 1090 " C c();", 1091 " X x();", 1092 "}"); 1093 CompilerTests.daggerCompiler(aFile, bFile, cFile, xFile, componentFile) 1094 .withProcessingOptions(compilerMode.processorOptions()) 1095 .compile( 1096 subject -> { 1097 subject.hasErrorCount(0); 1098 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 1099 }); 1100 } 1101 1102 @Test simpleComponent_redundantComponentMethod()1103 public void simpleComponent_redundantComponentMethod() throws Exception { 1104 Source injectableTypeFile = 1105 CompilerTests.javaSource( 1106 "test.SomeInjectableType", 1107 "package test;", 1108 "", 1109 "import javax.inject.Inject;", 1110 "", 1111 "final class SomeInjectableType {", 1112 " @Inject SomeInjectableType() {}", 1113 "}"); 1114 Source componentSupertypeAFile = 1115 CompilerTests.javaSource( 1116 "test.SupertypeA", 1117 "package test;", 1118 "", 1119 "import dagger.Component;", 1120 "import dagger.Lazy;", 1121 "import javax.inject.Provider;", 1122 "", 1123 "@Component", 1124 "interface SupertypeA {", 1125 " SomeInjectableType someInjectableType();", 1126 "}"); 1127 Source componentSupertypeBFile = 1128 CompilerTests.javaSource( 1129 "test.SupertypeB", 1130 "package test;", 1131 "", 1132 "import dagger.Component;", 1133 "import dagger.Lazy;", 1134 "import javax.inject.Provider;", 1135 "", 1136 "@Component", 1137 "interface SupertypeB {", 1138 " SomeInjectableType someInjectableType();", 1139 "}"); 1140 Source componentFile = 1141 CompilerTests.javaSource( 1142 "test.SimpleComponent", 1143 "package test;", 1144 "", 1145 "import dagger.Component;", 1146 "import dagger.Lazy;", 1147 "import javax.inject.Provider;", 1148 "", 1149 "@Component", 1150 "interface SimpleComponent extends SupertypeA, SupertypeB {", 1151 "}"); 1152 CompilerTests.daggerCompiler( 1153 injectableTypeFile, componentSupertypeAFile, componentSupertypeBFile, componentFile) 1154 .withProcessingOptions(compilerMode.processorOptions()) 1155 .compile( 1156 subject -> { 1157 subject.hasErrorCount(0); 1158 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 1159 }); 1160 } 1161 1162 @Test simpleComponent_inheritedComponentMethodDep()1163 public void simpleComponent_inheritedComponentMethodDep() throws Exception { 1164 Source injectableTypeFile = CompilerTests.javaSource("test.SomeInjectableType", 1165 "package test;", 1166 "", 1167 "import javax.inject.Inject;", 1168 "", 1169 "final class SomeInjectableType {", 1170 " @Inject SomeInjectableType() {}", 1171 "}"); 1172 Source componentSupertype = CompilerTests.javaSource("test.Supertype", 1173 "package test;", 1174 "", 1175 "import dagger.Component;", 1176 "", 1177 "@Component", 1178 "interface Supertype {", 1179 " SomeInjectableType someInjectableType();", 1180 "}"); 1181 Source depComponentFile = CompilerTests.javaSource("test.SimpleComponent", 1182 "package test;", 1183 "", 1184 "import dagger.Component;", 1185 "", 1186 "@Component", 1187 "interface SimpleComponent extends Supertype {", 1188 "}"); 1189 1190 CompilerTests.daggerCompiler(injectableTypeFile, componentSupertype, depComponentFile) 1191 .withProcessingOptions(compilerMode.processorOptions()) 1192 .compile( 1193 subject -> { 1194 subject.hasErrorCount(0); 1195 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent")); 1196 }); 1197 } 1198 1199 @Test wildcardGenericsRequiresAtProvides()1200 public void wildcardGenericsRequiresAtProvides() { 1201 Source aFile = CompilerTests.javaSource("test.A", 1202 "package test;", 1203 "", 1204 "import javax.inject.Inject;", 1205 "", 1206 "final class A {", 1207 " @Inject A() {}", 1208 "}"); 1209 Source bFile = CompilerTests.javaSource("test.B", 1210 "package test;", 1211 "", 1212 "import javax.inject.Inject;", 1213 "import javax.inject.Provider;", 1214 "", 1215 "final class B<T> {", 1216 " @Inject B(T t) {}", 1217 "}"); 1218 Source cFile = CompilerTests.javaSource("test.C", 1219 "package test;", 1220 "", 1221 "import javax.inject.Inject;", 1222 "import javax.inject.Provider;", 1223 "", 1224 "final class C {", 1225 " @Inject C(B<? extends A> bA) {}", 1226 "}"); 1227 Source componentFile = CompilerTests.javaSource("test.SimpleComponent", 1228 "package test;", 1229 "", 1230 "import dagger.Component;", 1231 "import dagger.Lazy;", 1232 "import javax.inject.Provider;", 1233 "", 1234 "@Component", 1235 "interface SimpleComponent {", 1236 " C c();", 1237 "}"); 1238 1239 CompilerTests.daggerCompiler(aFile, bFile, cFile, componentFile) 1240 .withProcessingOptions(compilerMode.processorOptions()) 1241 .compile( 1242 subject -> { 1243 subject.hasErrorCount(1); 1244 subject.hasErrorContaining( 1245 "test.B<? extends test.A> cannot be provided without an @Provides-annotated " 1246 + "method"); 1247 }); 1248 } 1249 1250 // https://github.com/google/dagger/issues/630 1251 @Test arrayKeyRequiresAtProvides()1252 public void arrayKeyRequiresAtProvides() { 1253 Source component = 1254 CompilerTests.javaSource( 1255 "test.TestComponent", 1256 "package test;", 1257 "", 1258 "import dagger.Component;", 1259 "", 1260 "@Component", 1261 "interface TestComponent {", 1262 " String[] array();", 1263 "}"); 1264 1265 CompilerTests.daggerCompiler(component) 1266 .withProcessingOptions(compilerMode.processorOptions()) 1267 .compile( 1268 subject -> { 1269 subject.hasErrorCount(1); 1270 subject.hasErrorContaining( 1271 "String[] cannot be provided without an @Provides-annotated method"); 1272 }); 1273 } 1274 1275 @Test componentImplicitlyDependsOnGeneratedType()1276 public void componentImplicitlyDependsOnGeneratedType() { 1277 Source injectableTypeFile = 1278 CompilerTests.javaSource( 1279 "test.SomeInjectableType", 1280 "package test;", 1281 "", 1282 "import javax.inject.Inject;", 1283 "", 1284 "final class SomeInjectableType {", 1285 " @Inject SomeInjectableType(GeneratedInjectType generatedInjectType) {}", 1286 "}"); 1287 Source componentFile = 1288 CompilerTests.javaSource( 1289 "test.SimpleComponent", 1290 "package test;", 1291 "", 1292 "import dagger.Component;", 1293 "", 1294 "@Component", 1295 "interface SimpleComponent {", 1296 " SomeInjectableType someInjectableType();", 1297 "}"); 1298 CompilerTests.daggerCompiler(injectableTypeFile, componentFile) 1299 .withProcessingOptions(compilerMode.processorOptions()) 1300 .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_INJECT_TYPE)) 1301 .compile( 1302 subject -> { 1303 subject.hasErrorCount(0); 1304 subject.generatedSourceFileWithPath("test/DaggerSimpleComponent.java"); 1305 }); 1306 } 1307 1308 @Test componentSupertypeDependsOnGeneratedType()1309 public void componentSupertypeDependsOnGeneratedType() { 1310 Source componentFile = 1311 CompilerTests.javaSource( 1312 "test.SimpleComponent", 1313 "package test;", 1314 "", 1315 "import dagger.Component;", 1316 "", 1317 "@Component", 1318 "interface SimpleComponent extends SimpleComponentInterface {}"); 1319 Source interfaceFile = 1320 CompilerTests.javaSource( 1321 "test.SimpleComponentInterface", 1322 "package test;", 1323 "", 1324 "interface SimpleComponentInterface {", 1325 " GeneratedInjectType generatedInjectType();", 1326 "}"); 1327 CompilerTests.daggerCompiler(componentFile, interfaceFile) 1328 .withProcessingOptions(compilerMode.processorOptions()) 1329 .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_INJECT_TYPE)) 1330 .compile( 1331 subject -> { 1332 subject.hasErrorCount(0); 1333 subject.generatedSourceFileWithPath("test/DaggerSimpleComponent.java"); 1334 }); 1335 } 1336 1337 /** 1338 * We warn when generating a {@link MembersInjector} for a type post-hoc (i.e., if Dagger wasn't 1339 * invoked when compiling the type). But Dagger only generates {@link MembersInjector}s for types 1340 * with {@link Inject @Inject} constructors if they have any injection sites, and it only 1341 * generates them for types without {@link Inject @Inject} constructors if they have local 1342 * (non-inherited) injection sites. So make sure we warn in only those cases where running the 1343 * Dagger processor actually generates a {@link MembersInjector}. 1344 */ 1345 @Test unprocessedMembersInjectorNotes()1346 public void unprocessedMembersInjectorNotes() { 1347 Source component = 1348 CompilerTests.javaSource( 1349 "test.TestComponent", 1350 "package test;", 1351 "", 1352 "import dagger.Component;", 1353 "import dagger.internal.codegen.ComponentProcessorTestClasses;", 1354 "", 1355 "@Component(modules = TestModule.class)", 1356 "interface TestComponent {", 1357 " void inject(ComponentProcessorTestClasses.NoInjectMemberNoConstructor object);", 1358 " void inject(ComponentProcessorTestClasses.NoInjectMemberWithConstructor object);", 1359 " void inject(ComponentProcessorTestClasses.LocalInjectMemberNoConstructor object);", 1360 " void inject(ComponentProcessorTestClasses.LocalInjectMemberWithConstructor object);", 1361 " void inject(ComponentProcessorTestClasses.ParentInjectMemberNoConstructor object);", 1362 " void inject(", 1363 " ComponentProcessorTestClasses.ParentInjectMemberWithConstructor object);", 1364 "}"); 1365 Source module = 1366 CompilerTests.javaSource( 1367 "test.TestModule", 1368 "package test;", 1369 "", 1370 "import dagger.Module;", 1371 "import dagger.Provides;", 1372 "", 1373 "@Module", 1374 "class TestModule {", 1375 " @Provides static Object object() {", 1376 " return \"object\";", 1377 " }", 1378 "}"); 1379 CompilerTests.daggerCompiler(module, component) 1380 .withProcessingOptions( 1381 ImmutableMap.<String, String>builder() 1382 .putAll(compilerMode.processorOptions()) 1383 .put("dagger.warnIfInjectionFactoryNotGeneratedUpstream", "enabled") 1384 .buildOrThrow()) 1385 .compile( 1386 subject -> { 1387 subject.hasErrorCount(0); 1388 subject.hasWarningCount(0); 1389 1390 String generatedFileTemplate = 1391 "dagger/internal/codegen/ComponentProcessorTestClasses_%s_MembersInjector.java"; 1392 String noteTemplate = 1393 "Generating a MembersInjector for " 1394 + "dagger.internal.codegen.ComponentProcessorTestClasses.%s."; 1395 1396 // Assert that we generate sources and notes for the following classes. 1397 ImmutableList.of( 1398 "LocalInjectMemberNoConstructor", 1399 "LocalInjectMemberWithConstructor", 1400 "ParentInjectMemberWithConstructor") 1401 .forEach( 1402 className -> { 1403 subject.generatedSourceFileWithPath( 1404 String.format(generatedFileTemplate, className)); 1405 subject.hasNoteContaining(String.format(noteTemplate, className)); 1406 }); 1407 1408 // Assert that we **do not** generate sources and notes for the following classes. 1409 ImmutableList.of( 1410 "ParentInjectMemberNoConstructor", 1411 "NoInjectMemberNoConstructor", 1412 "NoInjectMemberWithConstructor") 1413 .forEach( 1414 className -> { 1415 assertFileNotGenerated( 1416 subject, String.format(generatedFileTemplate, className)); 1417 assertDoesNotHaveNoteContaining( 1418 subject, String.format(noteTemplate, className)); 1419 }); 1420 }); 1421 } 1422 assertFileNotGenerated(CompilationResultSubject subject, String filePath)1423 private void assertFileNotGenerated(CompilationResultSubject subject, String filePath) { 1424 // TODO(b/303653163): replace this with better XProcessing API once we have the ability to get a 1425 // list of all generated sources. 1426 AssertionError error = 1427 assertThrows( 1428 AssertionError.class, 1429 () -> subject.generatedSourceFileWithPath(filePath)); 1430 assertThat(error).hasMessageThat().contains("Didn't generate file"); 1431 } 1432 assertDoesNotHaveNoteContaining(CompilationResultSubject subject, String content)1433 private void assertDoesNotHaveNoteContaining(CompilationResultSubject subject, String content) { 1434 assertThat( 1435 subject.getCompilationResult().getDiagnostics().get(Diagnostic.Kind.NOTE).stream() 1436 .filter(diagnostic -> diagnostic.getMsg().contains(content))) 1437 .isEmpty(); 1438 } 1439 1440 @Test scopeAnnotationOnInjectConstructorNotValid()1441 public void scopeAnnotationOnInjectConstructorNotValid() { 1442 Source aScope = 1443 CompilerTests.javaSource( 1444 "test.AScope", 1445 "package test;", 1446 "", 1447 "import javax.inject.Scope;", 1448 "", 1449 "@Scope", 1450 "@interface AScope {}"); 1451 Source aClass = 1452 CompilerTests.javaSource( 1453 "test.AClass", 1454 "package test;", 1455 "", 1456 "import javax.inject.Inject;", 1457 "", 1458 "final class AClass {", 1459 " @Inject @AScope AClass() {}", 1460 "}"); 1461 CompilerTests.daggerCompiler(aScope, aClass) 1462 .withProcessingOptions(compilerMode.processorOptions()) 1463 .compile( 1464 subject -> { 1465 subject.hasErrorCount(1); 1466 subject 1467 .hasErrorContaining("@Scope annotations are not allowed on @Inject constructors") 1468 .onSource(aClass) 1469 .onLine(6); 1470 }); 1471 } 1472 1473 @Test unusedSubcomponents_dontResolveExtraBindingsInParentComponents()1474 public void unusedSubcomponents_dontResolveExtraBindingsInParentComponents() throws Exception { 1475 Source foo = 1476 CompilerTests.javaSource( 1477 "test.Foo", 1478 "package test;", 1479 "", 1480 "import javax.inject.Inject;", 1481 "import javax.inject.Singleton;", 1482 "", 1483 "@Singleton", 1484 "class Foo {", 1485 " @Inject Foo() {}", 1486 "}"); 1487 1488 Source module = 1489 CompilerTests.javaSource( 1490 "test.TestModule", 1491 "package test;", 1492 "", 1493 "import dagger.Module;", 1494 "", 1495 "@Module(subcomponents = Pruned.class)", 1496 "class TestModule {}"); 1497 1498 Source component = 1499 CompilerTests.javaSource( 1500 "test.Parent", 1501 "package test;", 1502 "", 1503 "import dagger.Component;", 1504 "import javax.inject.Singleton;", 1505 "", 1506 "@Singleton", 1507 "@Component(modules = TestModule.class)", 1508 "interface Parent {}"); 1509 1510 Source prunedSubcomponent = 1511 CompilerTests.javaSource( 1512 "test.Pruned", 1513 "package test;", 1514 "", 1515 "import dagger.Subcomponent;", 1516 "", 1517 "@Subcomponent", 1518 "interface Pruned {", 1519 " @Subcomponent.Builder", 1520 " interface Builder {", 1521 " Pruned build();", 1522 " }", 1523 "", 1524 " Foo foo();", 1525 "}"); 1526 1527 CompilerTests.daggerCompiler(foo, module, component, prunedSubcomponent) 1528 .withProcessingOptions(compilerMode.processorOptions()) 1529 .compile( 1530 subject -> { 1531 subject.hasErrorCount(0); 1532 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent")); 1533 }); 1534 } 1535 1536 @Test bindsToDuplicateBinding_bindsKeyIsNotDuplicated()1537 public void bindsToDuplicateBinding_bindsKeyIsNotDuplicated() { 1538 Source firstModule = 1539 CompilerTests.javaSource( 1540 "test.FirstModule", 1541 "package test;", 1542 "", 1543 "import dagger.Module;", 1544 "import dagger.Provides;", 1545 "", 1546 "@Module", 1547 "abstract class FirstModule {", 1548 " @Provides static String first() { return \"first\"; }", 1549 "}"); 1550 Source secondModule = 1551 CompilerTests.javaSource( 1552 "test.SecondModule", 1553 "package test;", 1554 "", 1555 "import dagger.Module;", 1556 "import dagger.Provides;", 1557 "", 1558 "@Module", 1559 "abstract class SecondModule {", 1560 " @Provides static String second() { return \"second\"; }", 1561 "}"); 1562 Source bindsModule = 1563 CompilerTests.javaSource( 1564 "test.BindsModule", 1565 "package test;", 1566 "", 1567 "import dagger.Binds;", 1568 "import dagger.Module;", 1569 "", 1570 "@Module", 1571 "abstract class BindsModule {", 1572 " @Binds abstract Object bindToDuplicateBinding(String duplicate);", 1573 "}"); 1574 Source component = 1575 CompilerTests.javaSource( 1576 "test.TestComponent", 1577 "package test;", 1578 "", 1579 "import dagger.Component;", 1580 "", 1581 "@Component(modules = {FirstModule.class, SecondModule.class, BindsModule.class})", 1582 "interface TestComponent {", 1583 " Object notDuplicated();", 1584 "}"); 1585 1586 CompilerTests.daggerCompiler(firstModule, secondModule, bindsModule, component) 1587 .withProcessingOptions(compilerMode.processorOptions()) 1588 .compile( 1589 subject -> { 1590 subject.hasErrorCount(1); 1591 subject.hasErrorContaining("String is bound multiple times") 1592 .onSource(component) 1593 .onLineContaining("interface TestComponent"); 1594 }); 1595 } 1596 1597 @Test nullIncorrectlyReturnedFromNonNullableInlinedProvider()1598 public void nullIncorrectlyReturnedFromNonNullableInlinedProvider() throws Exception { 1599 CompilerTests.daggerCompiler( 1600 CompilerTests.javaSource( 1601 "test.TestModule", 1602 "package test;", 1603 "", 1604 "import dagger.Module;", 1605 "import dagger.Provides;", 1606 "", 1607 "@Module", 1608 "public abstract class TestModule {", 1609 " @Provides static String nonNullableString() { return \"string\"; }", 1610 "}"), 1611 CompilerTests.javaSource( 1612 "test.InjectsMember", 1613 "package test;", 1614 "", 1615 "import javax.inject.Inject;", 1616 "", 1617 "public class InjectsMember {", 1618 " @Inject String member;", 1619 "}"), 1620 CompilerTests.javaSource( 1621 "test.TestComponent", 1622 "package test;", 1623 "", 1624 "import dagger.Component;", 1625 "", 1626 "@Component(modules = TestModule.class)", 1627 "interface TestComponent {", 1628 " String nonNullableString();", 1629 " void inject(InjectsMember member);", 1630 "}")) 1631 .withProcessingOptions(compilerMode.processorOptions()) 1632 .compile( 1633 subject -> { 1634 // TODO(bcorso): Replace with subject.succeededWithoutWarnings() 1635 subject.hasErrorCount(0); 1636 subject.hasWarningCount(0); 1637 subject.generatedSource( 1638 goldenFileRule.goldenSource("test/TestModule_NonNullableStringFactory")); 1639 subject.generatedSource( 1640 goldenFileRule.goldenSource("test/DaggerTestComponent")); 1641 }); 1642 } 1643 1644 @Test nullCheckingIgnoredWhenProviderReturnsPrimitive()1645 public void nullCheckingIgnoredWhenProviderReturnsPrimitive() throws Exception { 1646 CompilerTests.daggerCompiler( 1647 CompilerTests.javaSource( 1648 "test.TestModule", 1649 "package test;", 1650 "", 1651 "import dagger.Module;", 1652 "import dagger.Provides;", 1653 "", 1654 "@Module", 1655 "public abstract class TestModule {", 1656 " @Provides static int primitiveInteger() { return 1; }", 1657 "}"), 1658 CompilerTests.javaSource( 1659 "test.InjectsMember", 1660 "package test;", 1661 "", 1662 "import javax.inject.Inject;", 1663 "", 1664 "public class InjectsMember {", 1665 " @Inject Integer member;", 1666 "}"), 1667 CompilerTests.javaSource( 1668 "test.TestComponent", 1669 "package test;", 1670 "", 1671 "import dagger.Component;", 1672 "", 1673 "@Component(modules = TestModule.class)", 1674 "interface TestComponent {", 1675 " Integer nonNullableInteger();", 1676 " void inject(InjectsMember member);", 1677 "}")) 1678 .withProcessingOptions(compilerMode.processorOptions()) 1679 .compile( 1680 subject -> { 1681 // TODO(bcorso): Replace with subject.succeededWithoutWarnings() 1682 subject.hasErrorCount(0); 1683 subject.hasWarningCount(0); 1684 subject.generatedSource( 1685 goldenFileRule.goldenSource("test/TestModule_PrimitiveIntegerFactory")); 1686 subject.generatedSource( 1687 goldenFileRule.goldenSource("test/DaggerTestComponent")); 1688 }); 1689 } 1690 1691 @Test privateMethodUsedOnlyInChildDoesNotUseQualifiedThis()1692 public void privateMethodUsedOnlyInChildDoesNotUseQualifiedThis() throws Exception { 1693 Source parent = 1694 CompilerTests.javaSource( 1695 "test.Parent", 1696 "package test;", 1697 "", 1698 "import dagger.Component;", 1699 "import javax.inject.Singleton;", 1700 "", 1701 "@Singleton", 1702 "@Component(modules=TestModule.class)", 1703 "interface Parent {", 1704 " Child child();", 1705 "}"); 1706 Source testModule = 1707 CompilerTests.javaSource( 1708 "test.TestModule", 1709 "package test;", 1710 "", 1711 "import dagger.Module;", 1712 "import dagger.Provides;", 1713 "import javax.inject.Singleton;", 1714 "", 1715 "@Module", 1716 "abstract class TestModule {", 1717 " @Provides @Singleton static Number number() {", 1718 " return 3;", 1719 " }", 1720 "", 1721 " @Provides static String string(Number number) {", 1722 " return number.toString();", 1723 " }", 1724 "}"); 1725 Source child = 1726 CompilerTests.javaSource( 1727 "test.Child", 1728 "package test;", 1729 "", 1730 "import dagger.Subcomponent;", 1731 "", 1732 "@Subcomponent", 1733 "interface Child {", 1734 " String string();", 1735 "}"); 1736 1737 CompilerTests.daggerCompiler(parent, testModule, child) 1738 .withProcessingOptions(compilerMode.processorOptions()) 1739 .compile( 1740 subject -> { 1741 // TODO(bcorso): Replace with subject.succeededWithoutWarnings() 1742 subject.hasErrorCount(0); 1743 subject.hasWarningCount(0); 1744 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent")); 1745 }); 1746 } 1747 1748 @Test componentMethodInChildCallsComponentMethodInParent()1749 public void componentMethodInChildCallsComponentMethodInParent() throws Exception { 1750 Source supertype = 1751 CompilerTests.javaSource( 1752 "test.Supertype", 1753 "package test;", 1754 "", 1755 "interface Supertype {", 1756 " String string();", 1757 "}"); 1758 Source parent = 1759 CompilerTests.javaSource( 1760 "test.Parent", 1761 "package test;", 1762 "", 1763 "import dagger.Component;", 1764 "import javax.inject.Singleton;", 1765 "", 1766 "@Singleton", 1767 "@Component(modules=TestModule.class)", 1768 "interface Parent extends Supertype {", 1769 " Child child();", 1770 "}"); 1771 Source testModule = 1772 CompilerTests.javaSource( 1773 "test.TestModule", 1774 "package test;", 1775 "", 1776 "import dagger.Module;", 1777 "import dagger.Provides;", 1778 "import javax.inject.Singleton;", 1779 "", 1780 "@Module", 1781 "abstract class TestModule {", 1782 " @Provides @Singleton static Number number() {", 1783 " return 3;", 1784 " }", 1785 "", 1786 " @Provides static String string(Number number) {", 1787 " return number.toString();", 1788 " }", 1789 "}"); 1790 Source child = 1791 CompilerTests.javaSource( 1792 "test.Child", 1793 "package test;", 1794 "", 1795 "import dagger.Subcomponent;", 1796 "", 1797 "@Subcomponent", 1798 "interface Child extends Supertype {}"); 1799 1800 CompilerTests.daggerCompiler(supertype, parent, testModule, child) 1801 .withProcessingOptions(compilerMode.processorOptions()) 1802 .compile( 1803 subject -> { 1804 // TODO(bcorso): Replace with subject.succeededWithoutWarnings() 1805 subject.hasErrorCount(0); 1806 subject.hasWarningCount(0); 1807 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerParent")); 1808 }); 1809 } 1810 1811 @Test justInTimeAtInjectConstructor_hasGeneratedQualifier()1812 public void justInTimeAtInjectConstructor_hasGeneratedQualifier() throws Exception { 1813 Source injected = 1814 CompilerTests.javaSource( 1815 "test.Injected", 1816 "package test;", 1817 "", 1818 "import javax.inject.Inject;", 1819 "", 1820 "class Injected {", 1821 " @Inject Injected(@GeneratedQualifier String string) {}", 1822 "}"); 1823 Source module = 1824 CompilerTests.javaSource( 1825 "test.TestModule", 1826 "package test;", 1827 "", 1828 "import dagger.Module;", 1829 "import dagger.Provides;", 1830 "", 1831 "@Module", 1832 "interface TestModule {", 1833 " @Provides", 1834 " static String unqualified() {", 1835 " return new String();", 1836 " }", 1837 "", 1838 " @Provides", 1839 " @GeneratedQualifier", 1840 " static String qualified() {", 1841 " return new String();", 1842 " }", 1843 "}"); 1844 Source component = 1845 CompilerTests.javaSource( 1846 "test.TestComponent", 1847 "package test;", 1848 "", 1849 "import dagger.Component;", 1850 "", 1851 "@Component(modules = TestModule.class)", 1852 "interface TestComponent {", 1853 " Injected injected();", 1854 "}"); 1855 CompilerTests.daggerCompiler(injected, module, component) 1856 .withProcessingOptions(compilerMode.processorOptions()) 1857 .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_QUALIFIER)) 1858 .compile( 1859 subject -> { 1860 subject.hasErrorCount(0); 1861 subject.hasWarningCount(0); 1862 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 1863 }); 1864 } 1865 1866 @Test moduleHasGeneratedQualifier()1867 public void moduleHasGeneratedQualifier() throws Exception { 1868 Source module = 1869 CompilerTests.javaSource( 1870 "test.TestModule", 1871 "package test;", 1872 "", 1873 "import dagger.Module;", 1874 "import dagger.Provides;", 1875 "", 1876 "@Module", 1877 "interface TestModule {", 1878 " @Provides", 1879 " static String unqualified() {", 1880 " return new String();", 1881 " }", 1882 "", 1883 " @Provides", 1884 " @GeneratedQualifier", 1885 " static String qualified() {", 1886 " return new String();", 1887 " }", 1888 "}"); 1889 Source component = 1890 CompilerTests.javaSource( 1891 "test.TestComponent", 1892 "package test;", 1893 "", 1894 "import dagger.Component;", 1895 "", 1896 "@Component(modules = TestModule.class)", 1897 "interface TestComponent {", 1898 " String unqualified();", 1899 "}"); 1900 1901 CompilerTests.daggerCompiler(module, component) 1902 .withProcessingOptions(compilerMode.processorOptions()) 1903 .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_QUALIFIER)) 1904 .compile( 1905 subject -> { 1906 subject.hasErrorCount(0); 1907 subject.hasWarningCount(0); 1908 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 1909 }); 1910 } 1911 1912 @Test publicComponentType()1913 public void publicComponentType() throws Exception { 1914 Source publicComponent = 1915 CompilerTests.javaSource( 1916 "test.PublicComponent", 1917 "package test;", 1918 "", 1919 "import dagger.Component;", 1920 "", 1921 "@Component", 1922 "public interface PublicComponent {}"); 1923 CompilerTests.daggerCompiler(publicComponent) 1924 .withProcessingOptions(compilerMode.processorOptions()) 1925 .compile( 1926 subject -> { 1927 subject.hasErrorCount(0); 1928 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerPublicComponent")); 1929 }); 1930 } 1931 1932 @Test componentFactoryInterfaceTest()1933 public void componentFactoryInterfaceTest() { 1934 Source parentInterface = 1935 CompilerTests.javaSource( 1936 "test.ParentInterface", 1937 "package test;", 1938 "", 1939 "interface ParentInterface extends ChildInterface.Factory {}"); 1940 1941 Source childInterface = 1942 CompilerTests.javaSource( 1943 "test.ChildInterface", 1944 "package test;", 1945 "", 1946 "interface ChildInterface {", 1947 " interface Factory {", 1948 " ChildInterface child(ChildModule childModule);", 1949 " }", 1950 "}"); 1951 1952 Source parent = 1953 CompilerTests.javaSource( 1954 "test.Parent", 1955 "package test;", 1956 "", 1957 "import dagger.Component;", 1958 "", 1959 "@Component", 1960 "interface Parent extends ParentInterface, Child.Factory {}"); 1961 1962 Source child = 1963 CompilerTests.javaSource( 1964 "test.Child", 1965 "package test;", 1966 "", 1967 "import dagger.Subcomponent;", 1968 "", 1969 "@Subcomponent(modules = ChildModule.class)", 1970 "interface Child extends ChildInterface {", 1971 " interface Factory extends ChildInterface.Factory {", 1972 " @Override Child child(ChildModule childModule);", 1973 " }", 1974 "}"); 1975 1976 Source childModule = 1977 CompilerTests.javaSource( 1978 "test.ChildModule", 1979 "package test;", 1980 "", 1981 "import dagger.Module;", 1982 "import dagger.Provides;", 1983 "", 1984 "@Module", 1985 "class ChildModule {", 1986 " @Provides", 1987 " int provideInt() {", 1988 " return 0;", 1989 " }", 1990 "}"); 1991 1992 CompilerTests.daggerCompiler(parentInterface, childInterface, parent, child, childModule) 1993 .withProcessingOptions(compilerMode.processorOptions()) 1994 .compile(subject -> subject.hasErrorCount(0)); 1995 } 1996 1997 @Test providerComponentType()1998 public void providerComponentType() throws Exception { 1999 Source entryPoint = 2000 CompilerTests.javaSource( 2001 "test.SomeEntryPoint", 2002 "package test;", 2003 "", 2004 "import javax.inject.Inject;", 2005 "import javax.inject.Provider;", 2006 "", 2007 "public class SomeEntryPoint {", 2008 " @Inject SomeEntryPoint(Foo foo, Provider<Foo> fooProvider) {}", 2009 "}"); 2010 Source foo = 2011 CompilerTests.javaSource( 2012 "test.Foo", 2013 "package test;", 2014 "", 2015 "import javax.inject.Inject;", 2016 "", 2017 "public class Foo {", 2018 " @Inject Foo(Bar bar) {}", 2019 "}"); 2020 Source bar = 2021 CompilerTests.javaSource( 2022 "test.Bar", 2023 "package test;", 2024 "", 2025 "import javax.inject.Inject;", 2026 "", 2027 "public class Bar {", 2028 " @Inject Bar() {}", 2029 "}"); 2030 Source component = 2031 CompilerTests.javaSource( 2032 "test.TestComponent", 2033 "package test;", 2034 "", 2035 "import dagger.Component;", 2036 "import javax.inject.Provider;", 2037 "", 2038 "@Component", 2039 "public interface TestComponent {", 2040 " SomeEntryPoint someEntryPoint();", 2041 "}"); 2042 CompilerTests.daggerCompiler(component, foo, bar, entryPoint) 2043 .withProcessingOptions(compilerMode.processorOptions()) 2044 .compile( 2045 subject -> { 2046 subject.hasErrorCount(0); 2047 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 2048 }); 2049 } 2050 2051 @Test injectedTypeHasGeneratedParam()2052 public void injectedTypeHasGeneratedParam() { 2053 Source foo = 2054 CompilerTests.javaSource( 2055 "test.Foo", 2056 "package test;", 2057 "", 2058 "import javax.inject.Inject;", 2059 "", 2060 "public final class Foo {", 2061 "", 2062 " @Inject", 2063 " public Foo(GeneratedInjectType param) {}", 2064 "", 2065 " @Inject", 2066 " public void init() {}", 2067 "}"); 2068 Source component = 2069 CompilerTests.javaSource( 2070 "test.TestComponent", 2071 "package test;", 2072 "", 2073 "import dagger.Component;", 2074 "import java.util.Set;", 2075 "", 2076 "@Component", 2077 "interface TestComponent {", 2078 " Foo foo();", 2079 "}"); 2080 2081 CompilerTests.daggerCompiler(foo, component) 2082 .withProcessingOptions(compilerMode.processorOptions()) 2083 .withProcessingSteps(() -> new GeneratingProcessingStep("test", GENERATED_INJECT_TYPE)) 2084 .compile( 2085 subject -> { 2086 subject.hasErrorCount(0); 2087 subject.hasWarningCount(0); 2088 }); 2089 } 2090 2091 @Test abstractVarFieldInComponent_failsValidation()2092 public void abstractVarFieldInComponent_failsValidation() { 2093 Source component = 2094 CompilerTests.kotlinSource( 2095 "test.TestComponent.kt", 2096 "package test", 2097 "", 2098 "import dagger.Component", 2099 "", 2100 "@Component(modules = [TestModule::class])", 2101 "interface TestComponent {", 2102 " var foo: String", 2103 "}"); 2104 2105 Source module = 2106 CompilerTests.javaSource( 2107 "test.TestModule", 2108 "package test;", 2109 "", 2110 "import dagger.Module;", 2111 "import dagger.Provides;", 2112 "", 2113 "@Module", 2114 "abstract class TestModule {", 2115 " @Provides", 2116 " static String provideString() { return \"hello\"; }", 2117 "}"); 2118 2119 CompilerTests.daggerCompiler(component, module) 2120 .withProcessingOptions(compilerMode.processorOptions()) 2121 .compile( 2122 subject -> { 2123 subject.hasErrorCount(1); 2124 subject.hasErrorContaining( 2125 "Cannot use 'abstract var' property in a component declaration to get a binding." 2126 + " Use 'val' or 'fun' instead: foo"); 2127 }); 2128 } 2129 2130 @Test nonAbstractVarFieldInComponent_passesValidation()2131 public void nonAbstractVarFieldInComponent_passesValidation() { 2132 Source component = 2133 CompilerTests.kotlinSource( 2134 "test.TestComponent.kt", 2135 "package test", 2136 "", 2137 "import dagger.Component", 2138 "", 2139 "@Component(modules = [TestModule::class])", 2140 "abstract class TestComponent {", 2141 " var foo: String = \"hello\"", 2142 "}"); 2143 2144 Source module = 2145 CompilerTests.javaSource( 2146 "test.TestModule", 2147 "package test;", 2148 "", 2149 "import dagger.Module;", 2150 "import dagger.Provides;", 2151 "", 2152 "@Module", 2153 "abstract class TestModule {", 2154 " @Provides", 2155 " static String provideString() { return \"hello\"; }", 2156 "}"); 2157 2158 CompilerTests.daggerCompiler(component, module) 2159 .withProcessingOptions(compilerMode.processorOptions()) 2160 .compile(subject -> subject.hasErrorCount(0)); 2161 } 2162 } 2163