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 androidx.room.compiler.processing.util.Source; 20 import com.google.common.collect.ImmutableMap; 21 import dagger.testing.compile.CompilerTests; 22 import dagger.testing.golden.GoldenFileRule; 23 import org.junit.Rule; 24 import org.junit.Test; 25 import org.junit.runner.RunWith; 26 import org.junit.runners.JUnit4; 27 28 @RunWith(JUnit4.class) 29 // TODO(gak): add tests for generation in the default package. 30 public final class InjectConstructorFactoryGeneratorTest { 31 private static final Source QUALIFIER_A = 32 CompilerTests.javaSource("test.QualifierA", 33 "package test;", 34 "", 35 "import javax.inject.Qualifier;", 36 "", 37 "@Qualifier @interface QualifierA {}"); 38 private static final Source QUALIFIER_B = 39 CompilerTests.javaSource("test.QualifierB", 40 "package test;", 41 "", 42 "import javax.inject.Qualifier;", 43 "", 44 "@Qualifier @interface QualifierB {}"); 45 private static final Source SCOPE_A = 46 CompilerTests.javaSource("test.ScopeA", 47 "package test;", 48 "", 49 "import javax.inject.Scope;", 50 "", 51 "@Scope @interface ScopeA {}"); 52 private static final Source SCOPE_B = 53 CompilerTests.javaSource("test.ScopeB", 54 "package test;", 55 "", 56 "import javax.inject.Scope;", 57 "", 58 "@Scope @interface ScopeB {}"); 59 60 @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); 61 injectOnPrivateConstructor()62 @Test public void injectOnPrivateConstructor() { 63 Source file = 64 CompilerTests.javaSource( 65 "test.PrivateConstructor", 66 "package test;", 67 "", 68 "import javax.inject.Inject;", 69 "", 70 "class PrivateConstructor {", 71 " @Inject private PrivateConstructor() {}", 72 "}"); 73 CompilerTests.daggerCompiler(file) 74 .compile( 75 subject -> { 76 subject.hasErrorCount(1); 77 subject.hasErrorContaining( 78 "Dagger does not support injection into private constructors") 79 .onSource(file) 80 .onLine(6); 81 }); 82 } 83 injectConstructorOnInnerClass()84 @Test public void injectConstructorOnInnerClass() { 85 Source file = 86 CompilerTests.javaSource( 87 "test.OuterClass", 88 "package test;", 89 "", 90 "import javax.inject.Inject;", 91 "", 92 "class OuterClass {", 93 " class InnerClass {", 94 " @Inject InnerClass() {}", 95 " }", 96 "}"); 97 CompilerTests.daggerCompiler(file) 98 .compile( 99 subject -> { 100 subject.hasErrorCount(1); 101 subject.hasErrorContaining( 102 "@Inject constructors are invalid on inner classes. " 103 + "Did you mean to make the class static?") 104 .onSource(file) 105 .onLine(7); 106 }); 107 } 108 injectConstructorOnAbstractClass()109 @Test public void injectConstructorOnAbstractClass() { 110 Source file = 111 CompilerTests.javaSource( 112 "test.AbstractClass", 113 "package test;", 114 "", 115 "import javax.inject.Inject;", 116 "", 117 "abstract class AbstractClass {", 118 " @Inject AbstractClass() {}", 119 "}"); 120 CompilerTests.daggerCompiler(file) 121 .compile( 122 subject -> { 123 subject.hasErrorCount(1); 124 subject.hasErrorContaining( 125 "@Inject is nonsense on the constructor of an abstract class") 126 .onSource(file) 127 .onLine(6); 128 }); 129 } 130 injectConstructorOnGenericClass()131 @Test public void injectConstructorOnGenericClass() { 132 Source file = 133 CompilerTests.javaSource( 134 "test.GenericClass", 135 "package test;", 136 "", 137 "import javax.inject.Inject;", 138 "", 139 "class GenericClass<T> {", 140 " @Inject GenericClass(T t) {}", 141 "}"); 142 CompilerTests.daggerCompiler(file) 143 .compile( 144 subject -> { 145 subject.hasErrorCount(0); 146 subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); 147 }); 148 } 149 fieldAndMethodGenerics()150 @Test public void fieldAndMethodGenerics() { 151 Source file = 152 CompilerTests.javaSource( 153 "test.GenericClass", 154 "package test;", 155 "", 156 "import javax.inject.Inject;", 157 "", 158 "class GenericClass<A, B> {", 159 " @Inject A a;", 160 "", 161 " @Inject GenericClass() {}", 162 "", 163 " @Inject void register(B b) {}", 164 "}"); 165 CompilerTests.daggerCompiler(file) 166 .compile( 167 subject -> { 168 subject.hasErrorCount(0); 169 subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); 170 }); 171 } 172 genericClassWithNoDependencies()173 @Test public void genericClassWithNoDependencies() { 174 Source file = 175 CompilerTests.javaSource( 176 "test.GenericClass", 177 "package test;", 178 "", 179 "import javax.inject.Inject;", 180 "", 181 "class GenericClass<T> {", 182 " @Inject GenericClass() {}", 183 "}"); 184 CompilerTests.daggerCompiler(file) 185 .compile( 186 subject -> { 187 subject.hasErrorCount(0); 188 subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); 189 }); 190 } 191 twoGenericTypes()192 @Test public void twoGenericTypes() { 193 Source file = 194 CompilerTests.javaSource( 195 "test.GenericClass", 196 "package test;", 197 "", 198 "import javax.inject.Inject;", 199 "", 200 "class GenericClass<A, B> {", 201 " @Inject GenericClass(A a, B b) {}", 202 "}"); 203 CompilerTests.daggerCompiler(file) 204 .compile( 205 subject -> { 206 subject.hasErrorCount(0); 207 subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); 208 }); 209 } 210 boundedGenerics()211 @Test public void boundedGenerics() { 212 Source file = 213 CompilerTests.javaSource( 214 "test.GenericClass", 215 "package test;", 216 "", 217 "import javax.inject.Inject;", 218 "import java.util.List;", 219 "", 220 "class GenericClass<A extends Number & Comparable<A>,", 221 " B extends List<? extends String>,", 222 " C extends List<? super String>> {", 223 " @Inject GenericClass(A a, B b, C c) {}", 224 "}"); 225 CompilerTests.daggerCompiler(file) 226 .compile( 227 subject -> { 228 subject.hasErrorCount(0); 229 subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); 230 }); 231 } 232 multipleSameTypesWithGenericsAndQualifiersAndLazies()233 @Test public void multipleSameTypesWithGenericsAndQualifiersAndLazies() { 234 Source file = 235 CompilerTests.javaSource( 236 "test.GenericClass", 237 "package test;", 238 "", 239 "import javax.inject.Inject;", 240 "import javax.inject.Provider;", 241 "import dagger.Lazy;", 242 "", 243 "class GenericClass<A, B> {", 244 " @Inject GenericClass(A a, A a2, Provider<A> pa, @QualifierA A qa, Lazy<A> la, ", 245 " String s, String s2, Provider<String> ps, ", 246 " @QualifierA String qs, Lazy<String> ls,", 247 " B b, B b2, Provider<B> pb, @QualifierA B qb, Lazy<B> lb) {}", 248 "}"); 249 CompilerTests.daggerCompiler(file, QUALIFIER_A) 250 .compile( 251 subject -> { 252 subject.hasErrorCount(0); 253 subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); 254 }); 255 } 256 multipleInjectConstructors()257 @Test public void multipleInjectConstructors() { 258 Source file = 259 CompilerTests.javaSource( 260 "test.TooManyInjectConstructors", 261 "package test;", 262 "", 263 "import javax.inject.Inject;", 264 "", 265 "class TooManyInjectConstructors {", 266 " @Inject TooManyInjectConstructors() {}", 267 " TooManyInjectConstructors(int i) {}", 268 " @Inject TooManyInjectConstructors(String s) {}", 269 "}"); 270 CompilerTests.daggerCompiler(file) 271 .compile( 272 subject -> { 273 subject.hasErrorCount(1); 274 subject.hasErrorContaining( 275 "Type test.TooManyInjectConstructors may only contain one injected " 276 + "constructor. Found: [" 277 + "@Inject test.TooManyInjectConstructors(), " 278 + "@Inject test.TooManyInjectConstructors(String)" 279 + "]") 280 .onSource(file) 281 .onLine(5); 282 }); 283 } 284 multipleQualifiersOnInjectConstructorParameter()285 @Test public void multipleQualifiersOnInjectConstructorParameter() { 286 Source file = 287 CompilerTests.javaSource( 288 "test.MultipleQualifierConstructorParam", 289 "package test;", 290 "", 291 "import javax.inject.Inject;", 292 "", 293 "class MultipleQualifierConstructorParam {", 294 " @Inject MultipleQualifierConstructorParam(", 295 " @QualifierA", 296 " @QualifierB", 297 " String s) {}", 298 "}"); 299 CompilerTests.daggerCompiler(file, QUALIFIER_A, QUALIFIER_B) 300 .compile( 301 subject -> { 302 subject.hasErrorCount(2); 303 subject.hasErrorContaining( 304 "A single dependency request may not use more than one @Qualifier") 305 .onSource(file) 306 .onLine(7); 307 subject.hasErrorContaining( 308 "A single dependency request may not use more than one @Qualifier") 309 .onSource(file) 310 .onLine(8); 311 }); 312 } 313 injectConstructorOnClassWithMultipleScopes()314 @Test public void injectConstructorOnClassWithMultipleScopes() { 315 Source file = 316 CompilerTests.javaSource( 317 "test.MultipleScopeClass", 318 "package test;", 319 "", 320 "import javax.inject.Inject;", 321 "", 322 "@ScopeA", 323 "@ScopeB", 324 "class MultipleScopeClass {", 325 " @Inject MultipleScopeClass() {}", 326 "}"); 327 CompilerTests.daggerCompiler(file, SCOPE_A, SCOPE_B) 328 .compile( 329 subject -> { 330 subject.hasErrorCount(2); 331 subject.hasErrorContaining("A single binding may not declare more than one @Scope") 332 .onSource(file) 333 .onLine(5); 334 subject.hasErrorContaining("A single binding may not declare more than one @Scope") 335 .onSource(file) 336 .onLine(6); 337 }); 338 } 339 injectConstructorWithQualifier()340 @Test public void injectConstructorWithQualifier() { 341 Source file = 342 CompilerTests.javaSource( 343 "test.MultipleScopeClass", 344 "package test;", 345 "", 346 "import javax.inject.Inject;", 347 "", 348 "class MultipleScopeClass {", 349 " @Inject", 350 " @QualifierA", 351 " @QualifierB", 352 " MultipleScopeClass() {}", 353 "}"); 354 CompilerTests.daggerCompiler(file, QUALIFIER_A, QUALIFIER_B) 355 .compile( 356 subject -> { 357 subject.hasErrorCount(2); 358 subject.hasErrorContaining( 359 "@Qualifier annotations are not allowed on @Inject constructors") 360 .onSource(file) 361 .onLine(7); 362 subject.hasErrorContaining( 363 "@Qualifier annotations are not allowed on @Inject constructors") 364 .onSource(file) 365 .onLine(8); 366 }); 367 } 368 injectConstructorWithCheckedExceptionsError()369 @Test public void injectConstructorWithCheckedExceptionsError() { 370 Source file = 371 CompilerTests.javaSource( 372 "test.CheckedExceptionClass", 373 "package test;", 374 "", 375 "import javax.inject.Inject;", 376 "", 377 "class CheckedExceptionClass {", 378 " @Inject CheckedExceptionClass() throws Exception {}", 379 "}"); 380 CompilerTests.daggerCompiler(file) 381 .compile( 382 subject -> { 383 subject.hasErrorCount(1); 384 subject.hasErrorContaining( 385 "Dagger does not support checked exceptions on @Inject constructors") 386 .onSource(file) 387 .onLine(6); 388 }); 389 } 390 injectConstructorWithCheckedExceptionsWarning()391 @Test public void injectConstructorWithCheckedExceptionsWarning() { 392 Source file = 393 CompilerTests.javaSource( 394 "test.CheckedExceptionClass", 395 "package test;", 396 "", 397 "import javax.inject.Inject;", 398 "", 399 "class CheckedExceptionClass {", 400 " @Inject CheckedExceptionClass() throws Exception {}", 401 "}"); 402 CompilerTests.daggerCompiler(file) 403 .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) 404 .compile( 405 subject -> { 406 subject.hasErrorCount(0); 407 subject.hasWarningCount(1); 408 subject.hasWarningContaining( 409 "Dagger does not support checked exceptions on @Inject constructors") 410 .onSource(file) 411 .onLine(6); 412 }); 413 } 414 privateInjectClassError()415 @Test public void privateInjectClassError() { 416 Source file = 417 CompilerTests.javaSource( 418 "test.OuterClass", 419 "package test;", 420 "", 421 "import javax.inject.Inject;", 422 "", 423 "final class OuterClass {", 424 " private static final class InnerClass {", 425 " @Inject InnerClass() {}", 426 " }", 427 "}"); 428 CompilerTests.daggerCompiler(file) 429 .compile( 430 subject -> { 431 subject.hasErrorCount(1); 432 subject.hasErrorContaining("Dagger does not support injection into private classes") 433 .onSource(file) 434 .onLine(7); 435 }); 436 } 437 privateInjectClassWarning()438 @Test public void privateInjectClassWarning() { 439 Source file = 440 CompilerTests.javaSource( 441 "test.OuterClass", 442 "package test;", 443 "", 444 "import javax.inject.Inject;", 445 "", 446 "final class OuterClass {", 447 " private static final class InnerClass {", 448 " @Inject InnerClass() {}", 449 " }", 450 "}"); 451 CompilerTests.daggerCompiler(file) 452 .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) 453 .compile( 454 subject -> { 455 subject.hasErrorCount(0); 456 subject.hasWarningCount(1); 457 subject.hasWarningContaining("Dagger does not support injection into private classes") 458 .onSource(file) 459 .onLine(7); 460 }); 461 } 462 nestedInPrivateInjectClassError()463 @Test public void nestedInPrivateInjectClassError() { 464 Source file = 465 CompilerTests.javaSource( 466 "test.OuterClass", 467 "package test;", 468 "", 469 "import javax.inject.Inject;", 470 "", 471 "final class OuterClass {", 472 " private static final class MiddleClass {", 473 " static final class InnerClass {", 474 " @Inject InnerClass() {}", 475 " }", 476 " }", 477 "}"); 478 CompilerTests.daggerCompiler(file) 479 .compile( 480 subject -> { 481 subject.hasErrorCount(1); 482 subject.hasErrorContaining("Dagger does not support injection into private classes") 483 .onSource(file) 484 .onLine(8); 485 }); 486 } 487 nestedInPrivateInjectClassWarning()488 @Test public void nestedInPrivateInjectClassWarning() { 489 Source file = 490 CompilerTests.javaSource( 491 "test.OuterClass", 492 "package test;", 493 "", 494 "import javax.inject.Inject;", 495 "", 496 "final class OuterClass {", 497 " private static final class MiddleClass {", 498 " static final class InnerClass {", 499 " @Inject InnerClass() {}", 500 " }", 501 " }", 502 "}"); 503 CompilerTests.daggerCompiler(file) 504 .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) 505 .compile( 506 subject -> { 507 subject.hasErrorCount(0); 508 subject.hasWarningCount(1); 509 subject.hasWarningContaining("Dagger does not support injection into private classes") 510 .onSource(file) 511 .onLine(8); 512 }); 513 } 514 finalInjectField()515 @Test public void finalInjectField() { 516 Source file = 517 CompilerTests.javaSource( 518 "test.FinalInjectField", 519 "package test;", 520 "", 521 "import javax.inject.Inject;", 522 "", 523 "class FinalInjectField {", 524 " @Inject final String s;", 525 "}"); 526 CompilerTests.daggerCompiler(file) 527 .compile( 528 subject -> { 529 subject.hasErrorCount(1); 530 subject.hasErrorContaining("@Inject fields may not be final") 531 .onSource(file) 532 .onLine(6); 533 }); 534 } 535 privateInjectFieldError()536 @Test public void privateInjectFieldError() { 537 Source file = 538 CompilerTests.javaSource( 539 "test.PrivateInjectField", 540 "package test;", 541 "", 542 "import javax.inject.Inject;", 543 "", 544 "class PrivateInjectField {", 545 " @Inject private String s;", 546 "}"); 547 CompilerTests.daggerCompiler(file) 548 .compile( 549 subject -> { 550 subject.hasErrorCount(1); 551 subject.hasErrorContaining("Dagger does not support injection into private fields") 552 .onSource(file) 553 .onLine(6); 554 }); 555 } 556 privateInjectFieldWarning()557 @Test public void privateInjectFieldWarning() { 558 Source file = 559 CompilerTests.javaSource( 560 "test.PrivateInjectField", 561 "package test;", 562 "", 563 "import javax.inject.Inject;", 564 "", 565 "class PrivateInjectField {", 566 " @Inject private String s;", 567 "}"); 568 CompilerTests.daggerCompiler(file) 569 .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) 570 .compile( 571 subject -> { 572 subject.hasErrorCount(0); 573 // TODO: Verify warning message when supported 574 // subject.hasWarningCount(1); 575 }); 576 } 577 staticInjectFieldError()578 @Test public void staticInjectFieldError() { 579 Source file = 580 CompilerTests.javaSource( 581 "test.StaticInjectField", 582 "package test;", 583 "", 584 "import javax.inject.Inject;", 585 "", 586 "class StaticInjectField {", 587 " @Inject static String s;", 588 "}"); 589 CompilerTests.daggerCompiler(file) 590 .compile( 591 subject -> { 592 subject.hasErrorCount(1); 593 subject.hasErrorContaining("Dagger does not support injection into static fields") 594 .onSource(file) 595 .onLine(6); 596 }); 597 } 598 staticInjectFieldWarning()599 @Test public void staticInjectFieldWarning() { 600 Source file = 601 CompilerTests.javaSource( 602 "test.StaticInjectField", 603 "package test;", 604 "", 605 "import javax.inject.Inject;", 606 "", 607 "class StaticInjectField {", 608 " @Inject static String s;", 609 "}"); 610 CompilerTests.daggerCompiler(file) 611 .withProcessingOptions(ImmutableMap.of("dagger.staticMemberValidation", "WARNING")) 612 .compile( 613 subject -> { 614 subject.hasErrorCount(0); 615 // TODO: Verify warning message when supported 616 // subject.hasWarningCount(1); 617 }); 618 } 619 multipleQualifiersOnField()620 @Test public void multipleQualifiersOnField() { 621 Source file = 622 CompilerTests.javaSource( 623 "test.MultipleQualifierInjectField", 624 "package test;", 625 "", 626 "import javax.inject.Inject;", 627 "", 628 "class MultipleQualifierInjectField {", 629 " @Inject", 630 " @QualifierA", 631 " @QualifierB", 632 " String s;", 633 "}"); 634 CompilerTests.daggerCompiler(file, QUALIFIER_A, QUALIFIER_B) 635 .compile( 636 subject -> { 637 subject.hasErrorCount(2); 638 subject.hasErrorContaining( 639 "A single dependency request may not use more than one @Qualifier") 640 .onSource(file) 641 .onLine(7); 642 subject.hasErrorContaining( 643 "A single dependency request may not use more than one @Qualifier") 644 .onSource(file) 645 .onLine(8); 646 }); 647 } 648 abstractInjectMethod()649 @Test public void abstractInjectMethod() { 650 Source file = 651 CompilerTests.javaSource( 652 "test.AbstractInjectMethod", 653 "package test;", 654 "", 655 "import javax.inject.Inject;", 656 "", 657 "abstract class AbstractInjectMethod {", 658 " @Inject abstract void method();", 659 "}"); 660 CompilerTests.daggerCompiler(file) 661 .compile( 662 subject -> { 663 subject.hasErrorCount(1); 664 subject.hasErrorContaining("Methods with @Inject may not be abstract") 665 .onSource(file) 666 .onLine(6); 667 }); 668 } 669 privateInjectMethodError()670 @Test public void privateInjectMethodError() { 671 Source file = 672 CompilerTests.javaSource( 673 "test.PrivateInjectMethod", 674 "package test;", 675 "", 676 "import javax.inject.Inject;", 677 "", 678 "class PrivateInjectMethod {", 679 " @Inject private void method(){}", 680 "}"); 681 CompilerTests.daggerCompiler(file) 682 .compile( 683 subject -> { 684 subject.hasErrorCount(1); 685 subject.hasErrorContaining("Dagger does not support injection into private methods") 686 .onSource(file) 687 .onLine(6); 688 }); 689 } 690 privateInjectMethodWarning()691 @Test public void privateInjectMethodWarning() { 692 Source file = 693 CompilerTests.javaSource( 694 "test.PrivateInjectMethod", 695 "package test;", 696 "", 697 "import javax.inject.Inject;", 698 "", 699 "class PrivateInjectMethod {", 700 " @Inject private void method(){}", 701 "}"); 702 CompilerTests.daggerCompiler(file) 703 .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) 704 .compile( 705 subject -> { 706 subject.hasErrorCount(0); 707 // TODO: Verify warning message when supported 708 // subject.hasWarningCount(1); 709 }); 710 } 711 staticInjectMethodError()712 @Test public void staticInjectMethodError() { 713 Source file = 714 CompilerTests.javaSource( 715 "test.StaticInjectMethod", 716 "package test;", 717 "", 718 "import javax.inject.Inject;", 719 "", 720 "class StaticInjectMethod {", 721 " @Inject static void method(){}", 722 "}"); 723 CompilerTests.daggerCompiler(file) 724 .compile( 725 subject -> { 726 subject.hasErrorCount(1); 727 subject.hasErrorContaining("Dagger does not support injection into static methods") 728 .onSource(file) 729 .onLine(6); 730 }); 731 } 732 staticInjectMethodWarning()733 @Test public void staticInjectMethodWarning() { 734 Source file = 735 CompilerTests.javaSource( 736 "test.StaticInjectMethod", 737 "package test;", 738 "", 739 "import javax.inject.Inject;", 740 "", 741 "class StaticInjectMethod {", 742 " @Inject static void method(){}", 743 "}"); 744 CompilerTests.daggerCompiler(file) 745 .withProcessingOptions(ImmutableMap.of("dagger.staticMemberValidation", "WARNING")) 746 .compile( 747 subject -> { 748 subject.hasErrorCount(0); 749 // TODO: Verify warning message when supported 750 // subject.hasWarningCount(1); 751 }); 752 } 753 genericInjectMethod()754 @Test public void genericInjectMethod() { 755 Source file = 756 CompilerTests.javaSource( 757 "test.GenericInjectMethod", 758 "package test;", 759 "", 760 "import javax.inject.Inject;", 761 "", 762 "class AbstractInjectMethod {", 763 " @Inject <T> void method();", 764 "}"); 765 CompilerTests.daggerCompiler(file) 766 .compile( 767 subject -> { 768 subject.hasErrorCount(1); 769 subject.hasErrorContaining("Methods with @Inject may not declare type parameters") 770 .onSource(file) 771 .onLine(6); 772 }); 773 } 774 multipleQualifiersOnInjectMethodParameter()775 @Test public void multipleQualifiersOnInjectMethodParameter() { 776 Source file = 777 CompilerTests.javaSource( 778 "test.MultipleQualifierMethodParam", 779 "package test;", 780 "", 781 "import javax.inject.Inject;", 782 "", 783 "class MultipleQualifierMethodParam {", 784 " @Inject void method(", 785 " @QualifierA", 786 " @QualifierB", 787 " String s) {}", 788 "}"); 789 CompilerTests.daggerCompiler(file, QUALIFIER_A, QUALIFIER_B) 790 .compile( 791 subject -> { 792 subject.hasErrorCount(2); 793 subject.hasErrorContaining( 794 "A single dependency request may not use more than one @Qualifier") 795 .onSource(file) 796 .onLine(7); 797 subject.hasErrorContaining( 798 "A single dependency request may not use more than one @Qualifier") 799 .onSource(file) 800 .onLine(8); 801 }); 802 } 803 injectConstructorDependsOnProduced()804 @Test public void injectConstructorDependsOnProduced() { 805 Source file = 806 CompilerTests.javaSource( 807 "test.A", 808 "package test;", 809 "", 810 "import dagger.producers.Produced;", 811 "import javax.inject.Inject;", 812 "", 813 "final class A {", 814 " @Inject A(Produced<String> str) {}", 815 "}"); 816 CompilerTests.daggerCompiler(file) 817 .compile( 818 subject -> { 819 subject.hasErrorCount(1); 820 subject.hasErrorContaining("Produced may only be injected in @Produces methods"); 821 }); 822 } 823 injectConstructorDependsOnProducer()824 @Test public void injectConstructorDependsOnProducer() { 825 Source file = 826 CompilerTests.javaSource( 827 "test.A", 828 "package test;", 829 "", 830 "import dagger.producers.Producer;", 831 "import javax.inject.Inject;", 832 "", 833 "final class A {", 834 " @Inject A(Producer<String> str) {}", 835 "}"); 836 CompilerTests.daggerCompiler(file) 837 .compile( 838 subject -> { 839 subject.hasErrorCount(1); 840 subject.hasErrorContaining("Producer may only be injected in @Produces methods"); 841 }); 842 } 843 injectFieldDependsOnProduced()844 @Test public void injectFieldDependsOnProduced() { 845 Source file = 846 CompilerTests.javaSource( 847 "test.A", 848 "package test;", 849 "", 850 "import dagger.producers.Produced;", 851 "import javax.inject.Inject;", 852 "", 853 "final class A {", 854 " @Inject Produced<String> str;", 855 "}"); 856 CompilerTests.daggerCompiler(file) 857 .compile( 858 subject -> { 859 subject.hasErrorCount(1); 860 subject.hasErrorContaining("Produced may only be injected in @Produces methods"); 861 }); 862 } 863 injectFieldDependsOnProducer()864 @Test public void injectFieldDependsOnProducer() { 865 Source file = 866 CompilerTests.javaSource( 867 "test.A", 868 "package test;", 869 "", 870 "import dagger.producers.Producer;", 871 "import javax.inject.Inject;", 872 "", 873 "final class A {", 874 " @Inject Producer<String> str;", 875 "}"); 876 CompilerTests.daggerCompiler(file) 877 .compile( 878 subject -> { 879 subject.hasErrorCount(1); 880 subject.hasErrorContaining("Producer may only be injected in @Produces methods"); 881 }); 882 } 883 injectMethodDependsOnProduced()884 @Test public void injectMethodDependsOnProduced() { 885 Source file = 886 CompilerTests.javaSource( 887 "test.A", 888 "package test;", 889 "", 890 "import dagger.producers.Produced;", 891 "import javax.inject.Inject;", 892 "", 893 "final class A {", 894 " @Inject void inject(Produced<String> str) {}", 895 "}"); 896 CompilerTests.daggerCompiler(file) 897 .compile( 898 subject -> { 899 subject.hasErrorCount(1); 900 subject.hasErrorContaining("Produced may only be injected in @Produces methods"); 901 }); 902 } 903 injectMethodDependsOnProducer()904 @Test public void injectMethodDependsOnProducer() { 905 Source file = 906 CompilerTests.javaSource( 907 "test.A", 908 "package test;", 909 "", 910 "import dagger.producers.Producer;", 911 "import javax.inject.Inject;", 912 "", 913 "final class A {", 914 " @Inject void inject(Producer<String> str) {}", 915 "}"); 916 CompilerTests.daggerCompiler(file) 917 .compile( 918 subject -> { 919 subject.hasErrorCount(1); 920 subject.hasErrorContaining("Producer may only be injected in @Produces methods"); 921 }); 922 } 923 924 injectConstructor()925 @Test public void injectConstructor() { 926 Source file = 927 CompilerTests.javaSource("test.InjectConstructor", 928 "package test;", 929 "", 930 "import javax.inject.Inject;", 931 "", 932 "class InjectConstructor {", 933 " @Inject InjectConstructor(String s) {}", 934 "}"); 935 CompilerTests.daggerCompiler(file) 936 .compile( 937 subject -> { 938 subject.hasErrorCount(0); 939 subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); 940 }); 941 } 942 injectConstructorAndMembersInjection()943 @Test public void injectConstructorAndMembersInjection() { 944 Source file = 945 CompilerTests.javaSource("test.AllInjections", 946 "package test;", 947 "", 948 "import javax.inject.Inject;", 949 "", 950 "class AllInjections {", 951 " @Inject String s;", 952 " @Inject AllInjections(String s) {}", 953 " @Inject void s(String s) {}", 954 "}"); 955 CompilerTests.daggerCompiler(file) 956 .compile( 957 subject -> { 958 subject.hasErrorCount(0); 959 subject.generatedSource(goldenFileRule.goldenSource("test/AllInjections_Factory")); 960 }); 961 } 962 963 @Test wildcardDependency()964 public void wildcardDependency() { 965 Source file = 966 CompilerTests.javaSource("test.InjectConstructor", 967 "package test;", 968 "", 969 "import java.util.List;", 970 "import javax.inject.Inject;", 971 "", 972 "class InjectConstructor {", 973 " @Inject InjectConstructor(List<?> objects) {}", 974 "}"); 975 CompilerTests.daggerCompiler(file) 976 .compile( 977 subject -> { 978 subject.hasErrorCount(0); 979 subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); 980 }); 981 } 982 983 @Test basicNameCollision()984 public void basicNameCollision() { 985 Source factoryFile = 986 CompilerTests.javaSource("other.pkg.Factory", 987 "package other.pkg;", 988 "", 989 "public class Factory {}"); 990 Source file = 991 CompilerTests.javaSource("test.InjectConstructor", 992 "package test;", 993 "", 994 "import javax.inject.Inject;", 995 "import other.pkg.Factory;", 996 "", 997 "class InjectConstructor {", 998 " @Inject InjectConstructor(Factory factory) {}", 999 "}"); 1000 CompilerTests.daggerCompiler(factoryFile, file) 1001 .compile( 1002 subject -> { 1003 subject.hasErrorCount(0); 1004 subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); 1005 }); 1006 } 1007 1008 @Test nestedNameCollision()1009 public void nestedNameCollision() { 1010 Source factoryFile = 1011 CompilerTests.javaSource("other.pkg.Outer", 1012 "package other.pkg;", 1013 "", 1014 "public class Outer {", 1015 " public class Factory {}", 1016 "}"); 1017 Source file = 1018 CompilerTests.javaSource("test.InjectConstructor", 1019 "package test;", 1020 "", 1021 "import javax.inject.Inject;", 1022 "import other.pkg.Outer;", 1023 "", 1024 "class InjectConstructor {", 1025 " @Inject InjectConstructor(Outer.Factory factory) {}", 1026 "}"); 1027 CompilerTests.daggerCompiler(factoryFile, file) 1028 .compile( 1029 subject -> { 1030 subject.hasErrorCount(0); 1031 subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); 1032 }); 1033 } 1034 1035 @Test samePackageNameCollision()1036 public void samePackageNameCollision() { 1037 Source samePackageInterface = 1038 CompilerTests.javaSource( 1039 "test.CommonName", 1040 "package test;", 1041 "", 1042 "public interface CommonName {}"); 1043 Source differentPackageInterface = 1044 CompilerTests.javaSource( 1045 "other.pkg.CommonName", 1046 "package other.pkg;", 1047 "", 1048 "public interface CommonName {}"); 1049 Source file = 1050 CompilerTests.javaSource( 1051 "test.InjectConstructor", 1052 "package test;", 1053 "", 1054 "import javax.inject.Inject;", 1055 "", 1056 "class InjectConstructor implements CommonName {", 1057 " @Inject InjectConstructor(" 1058 + "other.pkg.CommonName otherPackage, CommonName samePackage) {}", 1059 "}"); 1060 CompilerTests.daggerCompiler(samePackageInterface, differentPackageInterface, file) 1061 .compile( 1062 subject -> { 1063 subject.hasErrorCount(0); 1064 subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); 1065 }); 1066 } 1067 1068 @Test noDeps()1069 public void noDeps() { 1070 Source file = 1071 CompilerTests.javaSource( 1072 "test.SimpleType", 1073 "package test;", 1074 "", 1075 "import javax.inject.Inject;", 1076 "", 1077 "final class SimpleType {", 1078 " @Inject SimpleType() {}", 1079 "}"); 1080 CompilerTests.daggerCompiler(file) 1081 .compile( 1082 subject -> { 1083 subject.hasErrorCount(0); 1084 subject.generatedSource(goldenFileRule.goldenSource("test/SimpleType_Factory")); 1085 }); 1086 } 1087 simpleComponentWithNesting()1088 @Test public void simpleComponentWithNesting() { 1089 Source file = 1090 CompilerTests.javaSource( 1091 "test.OuterType", 1092 "package test;", 1093 "", 1094 "import dagger.Component;", 1095 "import javax.inject.Inject;", 1096 "", 1097 "final class OuterType {", 1098 " static class A {", 1099 " @Inject A() {}", 1100 " }", 1101 " static class B {", 1102 " @Inject A a;", 1103 " }", 1104 "}"); 1105 CompilerTests.daggerCompiler(file) 1106 .compile( 1107 subject -> { 1108 subject.hasErrorCount(0); 1109 subject.generatedSource(goldenFileRule.goldenSource("test/OuterType_A_Factory")); 1110 }); 1111 } 1112 1113 @Test testScopedMetadata()1114 public void testScopedMetadata() throws Exception { 1115 Source file = 1116 CompilerTests.javaSource( 1117 "test.ScopedBinding", 1118 "package test;", 1119 "", 1120 "import javax.inject.Inject;", 1121 "import javax.inject.Singleton;", 1122 "", 1123 "@Singleton", 1124 "class ScopedBinding {", 1125 " @Inject", 1126 " ScopedBinding() {}", 1127 "}"); 1128 CompilerTests.daggerCompiler(file) 1129 .compile( 1130 subject -> { 1131 subject.hasErrorCount(0); 1132 subject.generatedSource(goldenFileRule.goldenSource("test/ScopedBinding_Factory")); 1133 }); 1134 } 1135 1136 @Test testScopedMetadataWithCustomScope()1137 public void testScopedMetadataWithCustomScope() throws Exception { 1138 Source customScope = 1139 CompilerTests.javaSource( 1140 "test.CustomScope", 1141 "package test;", 1142 "", 1143 "import javax.inject.Scope;", 1144 "", 1145 "@Scope", 1146 "@interface CustomScope {", 1147 " String value();", 1148 "}"); 1149 1150 Source customAnnotation = 1151 CompilerTests.javaSource( 1152 "test.CustomAnnotation", 1153 "package test;", 1154 "", 1155 "@interface CustomAnnotation {", 1156 " String value();", 1157 "}"); 1158 1159 Source scopedBinding = 1160 CompilerTests.javaSource( 1161 "test.ScopedBinding", 1162 "package test;", 1163 "", 1164 "import javax.inject.Inject;", 1165 "import javax.inject.Singleton;", 1166 "", 1167 "@CustomAnnotation(\"someValue\")", 1168 "@CustomScope(\"someOtherValue\")", 1169 "class ScopedBinding {", 1170 " @Inject", 1171 " ScopedBinding() {}", 1172 "}"); 1173 CompilerTests.daggerCompiler(scopedBinding, customScope, customAnnotation) 1174 .compile( 1175 subject -> { 1176 subject.hasErrorCount(0); 1177 subject.generatedSource(goldenFileRule.goldenSource("test/ScopedBinding_Factory")); 1178 }); 1179 } 1180 1181 @Test testQualifierMetadata()1182 public void testQualifierMetadata() throws Exception { 1183 Source someBinding = 1184 CompilerTests.javaSource( 1185 "test.SomeBinding", 1186 "package test;", 1187 "", 1188 "import javax.inject.Inject;", 1189 "import javax.inject.Singleton;", 1190 "", 1191 "@NonQualifier", 1192 "@MisplacedQualifier", 1193 "class SomeBinding {", 1194 " @NonQualifier @FieldQualifier @Inject String injectField;", 1195 " @NonQualifier @MisplacedQualifier String nonDaggerField;", 1196 "", 1197 " @NonQualifier", 1198 " @Inject", 1199 " SomeBinding(@NonQualifier @ConstructorParameterQualifier Double d) {}", 1200 "", 1201 " @NonQualifier", 1202 " @MisplacedQualifier", 1203 " SomeBinding(@NonQualifier @MisplacedQualifier Double d, int i) {}", 1204 "", 1205 " @NonQualifier", 1206 " @MisplacedQualifier", 1207 " @Inject", 1208 " void injectMethod(@NonQualifier @MethodParameterQualifier Float f) {}", 1209 "", 1210 " @NonQualifier", 1211 " @MisplacedQualifier", 1212 " void nonDaggerMethod(@NonQualifier @MisplacedQualifier Float f) {}", 1213 "}"); 1214 Source fieldQualifier = 1215 CompilerTests.javaSource( 1216 "test.FieldQualifier", 1217 "package test;", 1218 "", 1219 "import javax.inject.Qualifier;", 1220 "", 1221 "@Qualifier", 1222 "@interface FieldQualifier {}"); 1223 Source constructorParameterQualifier = 1224 CompilerTests.javaSource( 1225 "test.ConstructorParameterQualifier", 1226 "package test;", 1227 "", 1228 "import javax.inject.Qualifier;", 1229 "", 1230 "@Qualifier", 1231 "@interface ConstructorParameterQualifier {}"); 1232 Source methodParameterQualifier = 1233 CompilerTests.javaSource( 1234 "test.MethodParameterQualifier", 1235 "package test;", 1236 "", 1237 "import javax.inject.Qualifier;", 1238 "", 1239 "@Qualifier", 1240 "@interface MethodParameterQualifier {}"); 1241 Source misplacedQualifier = 1242 CompilerTests.javaSource( 1243 "test.MisplacedQualifier", 1244 "package test;", 1245 "", 1246 "import javax.inject.Qualifier;", 1247 "", 1248 "@Qualifier", 1249 "@interface MisplacedQualifier {}"); 1250 Source nonQualifier = 1251 CompilerTests.javaSource( 1252 "test.NonQualifier", 1253 "package test;", 1254 "", 1255 "@interface NonQualifier {}"); 1256 CompilerTests.daggerCompiler( 1257 someBinding, 1258 fieldQualifier, 1259 constructorParameterQualifier, 1260 methodParameterQualifier, 1261 misplacedQualifier, 1262 nonQualifier) 1263 .compile( 1264 subject -> { 1265 subject.hasErrorCount(0); 1266 subject.generatedSource(goldenFileRule.goldenSource("test/SomeBinding_Factory")); 1267 subject.generatedSource( 1268 goldenFileRule.goldenSource("test/SomeBinding_MembersInjector")); 1269 }); 1270 } 1271 1272 @Test testComplexQualifierMetadata()1273 public void testComplexQualifierMetadata() throws Exception { 1274 Source someBinding = 1275 CompilerTests.javaSource( 1276 "test.SomeBinding", 1277 "package test;", 1278 "", 1279 "import javax.inject.Inject;", 1280 "import javax.inject.Inject;", 1281 "", 1282 "class SomeBinding {", 1283 " @QualifierWithValue(1) @Inject String injectField;", 1284 "", 1285 " @Inject", 1286 " SomeBinding(", 1287 " @pkg1.SameNameQualifier String str1,", 1288 " @pkg2.SameNameQualifier String str2) {}", 1289 "", 1290 " @Inject", 1291 " void injectMethod(@test.Outer.NestedQualifier Float f) {}", 1292 "}"); 1293 Source qualifierWithValue = 1294 CompilerTests.javaSource( 1295 "test.QualifierWithValue", 1296 "package test;", 1297 "", 1298 "import javax.inject.Qualifier;", 1299 "", 1300 "@Qualifier", 1301 "@interface QualifierWithValue {", 1302 " int value();", 1303 "}"); 1304 Source pkg1SameNameQualifier = 1305 CompilerTests.javaSource( 1306 "pkg1.SameNameQualifier", 1307 "package pkg1;", 1308 "", 1309 "import javax.inject.Qualifier;", 1310 "", 1311 "@Qualifier", 1312 "public @interface SameNameQualifier {}"); 1313 Source pkg2SameNameQualifier = 1314 CompilerTests.javaSource( 1315 "pkg2.SameNameQualifier", 1316 "package pkg2;", 1317 "", 1318 "import javax.inject.Qualifier;", 1319 "", 1320 "@Qualifier", 1321 "public @interface SameNameQualifier {}"); 1322 Source nestedQualifier = 1323 CompilerTests.javaSource( 1324 "test.Outer", 1325 "package test;", 1326 "", 1327 "import javax.inject.Qualifier;", 1328 "", 1329 "interface Outer {", 1330 " @Qualifier", 1331 " @interface NestedQualifier {}", 1332 "}"); 1333 CompilerTests.daggerCompiler( 1334 someBinding, 1335 qualifierWithValue, 1336 pkg1SameNameQualifier, 1337 pkg2SameNameQualifier, 1338 nestedQualifier) 1339 .compile( 1340 subject -> { 1341 subject.hasErrorCount(0); 1342 subject.generatedSource(goldenFileRule.goldenSource("test/SomeBinding_Factory")); 1343 subject.generatedSource( 1344 goldenFileRule.goldenSource("test/SomeBinding_MembersInjector")); 1345 }); 1346 } 1347 1348 @Test testBaseClassQualifierMetadata()1349 public void testBaseClassQualifierMetadata() throws Exception { 1350 Source foo = 1351 CompilerTests.javaSource( 1352 "test.Foo", 1353 "package test;", 1354 "", 1355 "import javax.inject.Inject;", 1356 "import javax.inject.Singleton;", 1357 "", 1358 "class Foo extends FooBase {", 1359 " @FooFieldQualifier @Inject String injectField;", 1360 "", 1361 " @Inject", 1362 " Foo(@FooConstructorQualifier int i) { super(i); }", 1363 "", 1364 " @Inject", 1365 " void injectMethod(@FooMethodQualifier float f) {}", 1366 "}"); 1367 Source fooFieldQualifier = 1368 CompilerTests.javaSource( 1369 "test.FooFieldQualifier", 1370 "package test;", 1371 "", 1372 "import javax.inject.Qualifier;", 1373 "", 1374 "@Qualifier", 1375 "@interface FooFieldQualifier {}"); 1376 Source fooConstructorQualifier = 1377 CompilerTests.javaSource( 1378 "test.FooConstructorQualifier", 1379 "package test;", 1380 "", 1381 "import javax.inject.Qualifier;", 1382 "", 1383 "@Qualifier", 1384 "@interface FooConstructorQualifier {}"); 1385 Source fooMethodQualifier = 1386 CompilerTests.javaSource( 1387 "test.FooMethodQualifier", 1388 "package test;", 1389 "", 1390 "import javax.inject.Qualifier;", 1391 "", 1392 "@Qualifier", 1393 "@interface FooMethodQualifier {}"); 1394 Source fooBase = 1395 CompilerTests.javaSource( 1396 "test.FooBase", 1397 "package test;", 1398 "", 1399 "import javax.inject.Inject;", 1400 "import javax.inject.Singleton;", 1401 "", 1402 "class FooBase {", 1403 " @FooBaseFieldQualifier @Inject String injectField;", 1404 "", 1405 " @Inject", 1406 " FooBase(@FooBaseConstructorQualifier int i) {}", 1407 "", 1408 " @Inject", 1409 " void injectMethod(@FooBaseMethodQualifier float f) {}", 1410 "}"); 1411 Source fooBaseFieldQualifier = 1412 CompilerTests.javaSource( 1413 "test.FooBaseFieldQualifier", 1414 "package test;", 1415 "", 1416 "import javax.inject.Qualifier;", 1417 "", 1418 "@Qualifier", 1419 "@interface FooBaseFieldQualifier {}"); 1420 Source fooBaseConstructorQualifier = 1421 CompilerTests.javaSource( 1422 "test.FooBaseConstructorQualifier", 1423 "package test;", 1424 "", 1425 "import javax.inject.Qualifier;", 1426 "", 1427 "@Qualifier", 1428 "@interface FooBaseConstructorQualifier {}"); 1429 Source fooBaseMethodQualifier = 1430 CompilerTests.javaSource( 1431 "test.FooBaseMethodQualifier", 1432 "package test;", 1433 "", 1434 "import javax.inject.Qualifier;", 1435 "", 1436 "@Qualifier", 1437 "@interface FooBaseMethodQualifier {}"); 1438 CompilerTests.daggerCompiler( 1439 foo, 1440 fooBase, 1441 fooFieldQualifier, 1442 fooConstructorQualifier, 1443 fooMethodQualifier, 1444 fooBaseFieldQualifier, 1445 fooBaseConstructorQualifier, 1446 fooBaseMethodQualifier) 1447 .compile( 1448 subject -> { 1449 subject.hasErrorCount(0); 1450 subject.generatedSource(goldenFileRule.goldenSource("test/Foo_Factory")); 1451 subject.generatedSource(goldenFileRule.goldenSource("test/Foo_MembersInjector")); 1452 subject.generatedSource(goldenFileRule.goldenSource("test/FooBase_Factory")); 1453 subject.generatedSource(goldenFileRule.goldenSource("test/FooBase_MembersInjector")); 1454 }); 1455 } 1456 } 1457