1 /* 2 * Copyright (C) 2022 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.kotlin; 18 19 import androidx.room.compiler.processing.util.Source; 20 import dagger.testing.compile.CompilerTests; 21 import org.junit.Test; 22 import org.junit.runner.RunWith; 23 import org.junit.runners.JUnit4; 24 25 @RunWith(JUnit4.class) 26 public final class KspComponentProcessorTest { 27 @Test emptyComponentTest()28 public void emptyComponentTest() throws Exception { 29 Source componentSrc = 30 CompilerTests.kotlinSource( 31 "MyComponent.kt", 32 "package test", 33 "", 34 "import dagger.Component", 35 "", 36 "@Component", 37 "interface MyComponent {}"); 38 39 CompilerTests.daggerCompiler(componentSrc) 40 .compile( 41 subject -> { 42 subject.hasErrorCount(0); 43 subject.generatedSource( 44 CompilerTests.javaSource( 45 "test/DaggerMyComponent", 46 "package test;", 47 "", 48 "import dagger.internal.DaggerGenerated;", 49 "import javax.annotation.processing.Generated;", 50 "", 51 "@DaggerGenerated", 52 "@Generated(", 53 " value = \"dagger.internal.codegen.ComponentProcessor\",", 54 " comments = \"https://dagger.dev\"", 55 ")", 56 "@SuppressWarnings({", 57 " \"unchecked\",", 58 " \"rawtypes\",", 59 " \"KotlinInternal\",", 60 " \"KotlinInternalInJava\",", 61 " \"cast\"", 62 "})", 63 "public final class DaggerMyComponent {", 64 " private DaggerMyComponent() {", 65 " }", 66 "", 67 " public static Builder builder() {", 68 " return new Builder();", 69 " }", 70 "", 71 " public static MyComponent create() {", 72 " return new Builder().build();", 73 " }", 74 "", 75 " public static final class Builder {", 76 " private Builder() {", 77 " }", 78 "", 79 " public MyComponent build() {", 80 " return new MyComponentImpl();", 81 " }", 82 " }", 83 "", 84 " private static final class MyComponentImpl implements MyComponent {", 85 " private final MyComponentImpl myComponentImpl = this;", 86 "", 87 " private MyComponentImpl() {", 88 "", 89 "", 90 " }", 91 " }", 92 "}")); 93 }); 94 } 95 96 @Test 97 public void testComponentReferencingGeneratedTypeInCompanionObject_successfullyGeneratedComponent()98 testComponentReferencingGeneratedTypeInCompanionObject_successfullyGeneratedComponent() 99 throws Exception { 100 Source componentSrc = 101 CompilerTests.kotlinSource( 102 "MyComponent.kt", 103 "package test", 104 "", 105 "import dagger.BindsInstance", 106 "import dagger.Component", 107 "", 108 "@Component", 109 "interface MyComponent {", 110 " @Component.Builder", 111 " interface Builder {", 112 " @BindsInstance fun text(text: String): Builder", 113 " fun build(): MyComponent", 114 " }", 115 "", 116 " companion object {", 117 " fun getComponent(text: String) = DaggerMyComponent.builder().text(text).build()", 118 " }", 119 "}"); 120 121 CompilerTests.daggerCompiler(componentSrc).compile(subject -> subject.hasErrorCount(0)); 122 } 123 124 @Test injectBindingComponentTest()125 public void injectBindingComponentTest() throws Exception { 126 Source componentSrc = 127 CompilerTests.kotlinSource( 128 "MyComponent.kt", 129 "package test", 130 "", 131 "import dagger.Component", 132 "import javax.inject.Inject", 133 "", 134 "@Component", 135 "interface MyComponent {", 136 " fun foo(): Foo", 137 "}", 138 "", 139 "class Foo @Inject constructor(bar: Bar)", 140 "", 141 "class Bar @Inject constructor()"); 142 143 CompilerTests.daggerCompiler(componentSrc) 144 .compile( 145 subject -> { 146 subject.hasErrorCount(0); 147 subject.generatedSource( 148 CompilerTests.javaSource( 149 "test/DaggerMyComponent", 150 "package test;", 151 "", 152 "import dagger.internal.DaggerGenerated;", 153 "import javax.annotation.processing.Generated;", 154 "", 155 "@DaggerGenerated", 156 "@Generated(", 157 " value = \"dagger.internal.codegen.ComponentProcessor\",", 158 " comments = \"https://dagger.dev\"", 159 ")", 160 "@SuppressWarnings({", 161 " \"unchecked\",", 162 " \"rawtypes\",", 163 " \"KotlinInternal\",", 164 " \"KotlinInternalInJava\",", 165 " \"cast\"", 166 "})", 167 "public final class DaggerMyComponent {", 168 " private DaggerMyComponent() {", 169 " }", 170 "", 171 " public static Builder builder() {", 172 " return new Builder();", 173 " }", 174 "", 175 " public static MyComponent create() {", 176 " return new Builder().build();", 177 " }", 178 "", 179 " public static final class Builder {", 180 " private Builder() {", 181 " }", 182 "", 183 " public MyComponent build() {", 184 " return new MyComponentImpl();", 185 " }", 186 " }", 187 "", 188 " private static final class MyComponentImpl implements MyComponent {", 189 " private final MyComponentImpl myComponentImpl = this;", 190 "", 191 " private MyComponentImpl() {", 192 "", 193 "", 194 " }", 195 "", 196 " @Override", 197 " public Foo foo() {", 198 " return new Foo(new Bar());", 199 " }", 200 " }", 201 "}")); 202 }); 203 } 204 205 @Test injectBindingWithProvidersComponentTest()206 public void injectBindingWithProvidersComponentTest() throws Exception { 207 Source componentSrc = 208 CompilerTests.kotlinSource( 209 "MyComponent.kt", 210 "package test", 211 "", 212 "import dagger.Component", 213 "import javax.inject.Inject", 214 "import javax.inject.Provider", 215 "", 216 "@Component", 217 "interface MyComponent {", 218 " fun foo(): Provider<Foo>", 219 "}", 220 "", 221 "class Foo @Inject constructor(bar: Bar, barProvider: Provider<Bar>)", 222 "", 223 "class Bar @Inject constructor()"); 224 225 CompilerTests.daggerCompiler(componentSrc) 226 .compile( 227 subject -> { 228 subject.hasErrorCount(0); 229 subject.generatedSource( 230 CompilerTests.javaSource( 231 "test/DaggerMyComponent", 232 "package test;", 233 "", 234 "import dagger.internal.DaggerGenerated;", 235 "import dagger.internal.Provider;", 236 "import javax.annotation.processing.Generated;", 237 "", 238 "@DaggerGenerated", 239 "@Generated(", 240 " value = \"dagger.internal.codegen.ComponentProcessor\",", 241 " comments = \"https://dagger.dev\"", 242 ")", 243 "@SuppressWarnings({", 244 " \"unchecked\",", 245 " \"rawtypes\",", 246 " \"KotlinInternal\",", 247 " \"KotlinInternalInJava\",", 248 " \"cast\"", 249 "})", 250 "public final class DaggerMyComponent {", 251 " private DaggerMyComponent() {", 252 " }", 253 "", 254 " public static Builder builder() {", 255 " return new Builder();", 256 " }", 257 "", 258 " public static MyComponent create() {", 259 " return new Builder().build();", 260 " }", 261 "", 262 " public static final class Builder {", 263 " private Builder() {", 264 " }", 265 "", 266 " public MyComponent build() {", 267 " return new MyComponentImpl();", 268 " }", 269 " }", 270 "", 271 " private static final class MyComponentImpl implements MyComponent {", 272 " private final MyComponentImpl myComponentImpl = this;", 273 "", 274 " private Provider<Foo> fooProvider;", 275 "", 276 " private MyComponentImpl() {", 277 "", 278 " initialize();", 279 "", 280 " }", 281 "", 282 " @SuppressWarnings(\"unchecked\")", 283 " private void initialize() {", 284 " this.fooProvider = " 285 + "Foo_Factory.create(Bar_Factory.create(), Bar_Factory.create());", 286 " }", 287 "", 288 " @Override", 289 " public javax.inject.Provider<Foo> foo() {", 290 " return fooProvider;", 291 " }", 292 " }", 293 "}")); 294 }); 295 } 296 297 @Test moduleProvidesBindingTest()298 public void moduleProvidesBindingTest() throws Exception { 299 Source componentSrc = 300 CompilerTests.kotlinSource( 301 "MyComponent.kt", 302 "package test", 303 "", 304 "import dagger.Component", 305 "import dagger.Module", 306 "import dagger.Provides", 307 "import javax.inject.Inject", 308 "import javax.inject.Named", 309 "import javax.inject.Provider", 310 "", 311 "@Component(modules = [MyModule::class])", 312 "interface MyComponent {", 313 " @Named(\"key\") fun foo(): Foo", 314 "}", 315 "", 316 "@Module", 317 "class MyModule {", 318 " @Provides @Named(\"key\") fun provideFoo(@Named(\"key\") bar: Bar) = Foo(bar)", 319 " @Provides @Named(\"key\") fun provideBar() = Bar()", 320 "}", 321 "", 322 "class Foo constructor(bar: Bar)", 323 "", 324 "class Bar"); 325 326 CompilerTests.daggerCompiler(componentSrc) 327 .compile( 328 subject -> { 329 subject.hasErrorCount(0); 330 subject.generatedSource( 331 CompilerTests.javaSource( 332 "test/DaggerMyComponent", 333 "package test;", 334 "", 335 "import dagger.internal.DaggerGenerated;", 336 "import dagger.internal.Preconditions;", 337 "import javax.annotation.processing.Generated;", 338 "", 339 "@DaggerGenerated", 340 "@Generated(", 341 " value = \"dagger.internal.codegen.ComponentProcessor\",", 342 " comments = \"https://dagger.dev\"", 343 ")", 344 "@SuppressWarnings({", 345 " \"unchecked\",", 346 " \"rawtypes\",", 347 " \"KotlinInternal\",", 348 " \"KotlinInternalInJava\",", 349 " \"cast\"", 350 "})", 351 "public final class DaggerMyComponent {", 352 " private DaggerMyComponent() {", 353 " }", 354 "", 355 " public static Builder builder() {", 356 " return new Builder();", 357 " }", 358 "", 359 " public static MyComponent create() {", 360 " return new Builder().build();", 361 " }", 362 "", 363 " public static final class Builder {", 364 " private MyModule myModule;", 365 "", 366 " private Builder() {", 367 " }", 368 "", 369 " public Builder myModule(MyModule myModule) {", 370 " this.myModule = Preconditions.checkNotNull(myModule);", 371 " return this;", 372 " }", 373 "", 374 " public MyComponent build() {", 375 " if (myModule == null) {", 376 " this.myModule = new MyModule();", 377 " }", 378 " return new MyComponentImpl(myModule);", 379 " }", 380 " }", 381 "", 382 " private static final class MyComponentImpl implements MyComponent {", 383 " private final MyModule myModule;", 384 "", 385 " private final MyComponentImpl myComponentImpl = this;", 386 "", 387 " private MyComponentImpl(MyModule myModuleParam) {", 388 " this.myModule = myModuleParam;", 389 "", 390 " }", 391 "", 392 " @Override", 393 " public Foo foo() {", 394 " return MyModule_ProvideFooFactory.provideFoo(" 395 + "myModule, MyModule_ProvideBarFactory.provideBar(myModule));", 396 " }", 397 " }", 398 "}")); 399 }); 400 } 401 402 @Test membersInjectionMethodTest()403 public void membersInjectionMethodTest() throws Exception { 404 Source componentSrc = 405 CompilerTests.kotlinSource( 406 "MyComponent.kt", 407 "package test", 408 "", 409 "import dagger.Component", 410 "import dagger.Module", 411 "import dagger.Provides", 412 "import javax.inject.Inject", 413 "import javax.inject.Named", 414 "import javax.inject.Provider", 415 "", 416 "@Component(modules = [MyModule::class])", 417 "interface MyComponent {", 418 " fun injectFoo(foo: Foo)", 419 "}", 420 "", 421 "@Module", 422 "class MyModule {", 423 " @Provides @Named(\"key\") fun provideBar() = Bar()", 424 "}", 425 "", 426 "class Foo {", 427 " @Inject @Named(\"key\") lateinit var bar: Bar", 428 "}", 429 "", 430 "class Bar"); 431 432 CompilerTests.daggerCompiler(componentSrc) 433 .compile( 434 subject -> { 435 subject.hasErrorCount(0); 436 subject.generatedSource( 437 CompilerTests.javaSource( 438 "test/DaggerMyComponent", 439 "package test;", 440 "", 441 "import com.google.errorprone.annotations.CanIgnoreReturnValue;", 442 "import dagger.internal.DaggerGenerated;", 443 "import dagger.internal.Preconditions;", 444 "import javax.annotation.processing.Generated;", 445 "", 446 "@DaggerGenerated", 447 "@Generated(", 448 " value = \"dagger.internal.codegen.ComponentProcessor\",", 449 " comments = \"https://dagger.dev\"", 450 ")", 451 "@SuppressWarnings({", 452 " \"unchecked\",", 453 " \"rawtypes\",", 454 " \"KotlinInternal\",", 455 " \"KotlinInternalInJava\",", 456 " \"cast\"", 457 "})", 458 "public final class DaggerMyComponent {", 459 " private DaggerMyComponent() {", 460 " }", 461 "", 462 " public static Builder builder() {", 463 " return new Builder();", 464 " }", 465 "", 466 " public static MyComponent create() {", 467 " return new Builder().build();", 468 " }", 469 "", 470 " public static final class Builder {", 471 " private MyModule myModule;", 472 "", 473 " private Builder() {", 474 " }", 475 "", 476 " public Builder myModule(MyModule myModule) {", 477 " this.myModule = Preconditions.checkNotNull(myModule);", 478 " return this;", 479 " }", 480 "", 481 " public MyComponent build() {", 482 " if (myModule == null) {", 483 " this.myModule = new MyModule();", 484 " }", 485 " return new MyComponentImpl(myModule);", 486 " }", 487 " }", 488 "", 489 " private static final class MyComponentImpl implements MyComponent {", 490 " private final MyModule myModule;", 491 "", 492 " private final MyComponentImpl myComponentImpl = this;", 493 "", 494 " private MyComponentImpl(MyModule myModuleParam) {", 495 " this.myModule = myModuleParam;", 496 "", 497 " }", 498 "", 499 " @Override", 500 " public void injectFoo(Foo foo) {", 501 " injectFoo2(foo);", 502 " }", 503 "", 504 " @CanIgnoreReturnValue", 505 " private Foo injectFoo2(Foo instance) {", 506 " Foo_MembersInjector.injectBar(" 507 + "instance, MyModule_ProvideBarFactory.provideBar(myModule));", 508 " return instance;", 509 " }", 510 " }", 511 "}")); 512 }); 513 } 514 515 @Test membersInjectionTest()516 public void membersInjectionTest() throws Exception { 517 Source componentSrc = 518 CompilerTests.kotlinSource( 519 "MyComponent.kt", 520 "package test", 521 "", 522 "import dagger.Component", 523 "import dagger.Module", 524 "import dagger.Provides", 525 "import javax.inject.Inject", 526 "import javax.inject.Named", 527 "import javax.inject.Provider", 528 "", 529 "@Component(modules = [MyModule::class])", 530 "interface MyComponent {", 531 " fun foo(): Foo", 532 "}", 533 "", 534 "@Module", 535 "class MyModule {", 536 " @Provides @Named(\"key\") fun provideBar() = Bar()", 537 "}", 538 "", 539 "class Foo @Inject constructor() {", 540 " @Inject @Named(\"key\") lateinit var bar: Bar", 541 "}", 542 "", 543 "class Bar"); 544 545 CompilerTests.daggerCompiler(componentSrc) 546 .compile( 547 subject -> { 548 subject.hasErrorCount(0); 549 subject.generatedSource( 550 CompilerTests.javaSource( 551 "test/DaggerMyComponent", 552 "package test;", 553 "", 554 "import com.google.errorprone.annotations.CanIgnoreReturnValue;", 555 "import dagger.internal.DaggerGenerated;", 556 "import dagger.internal.Preconditions;", 557 "import javax.annotation.processing.Generated;", 558 "", 559 "@DaggerGenerated", 560 "@Generated(", 561 " value = \"dagger.internal.codegen.ComponentProcessor\",", 562 " comments = \"https://dagger.dev\"", 563 ")", 564 "@SuppressWarnings({", 565 " \"unchecked\",", 566 " \"rawtypes\",", 567 " \"KotlinInternal\",", 568 " \"KotlinInternalInJava\",", 569 " \"cast\"", 570 "})", 571 "public final class DaggerMyComponent {", 572 " private DaggerMyComponent() {", 573 " }", 574 "", 575 " public static Builder builder() {", 576 " return new Builder();", 577 " }", 578 "", 579 " public static MyComponent create() {", 580 " return new Builder().build();", 581 " }", 582 "", 583 " public static final class Builder {", 584 " private MyModule myModule;", 585 "", 586 " private Builder() {", 587 " }", 588 "", 589 " public Builder myModule(MyModule myModule) {", 590 " this.myModule = Preconditions.checkNotNull(myModule);", 591 " return this;", 592 " }", 593 "", 594 " public MyComponent build() {", 595 " if (myModule == null) {", 596 " this.myModule = new MyModule();", 597 " }", 598 " return new MyComponentImpl(myModule);", 599 " }", 600 " }", 601 "", 602 " private static final class MyComponentImpl implements MyComponent {", 603 " private final MyModule myModule;", 604 "", 605 " private final MyComponentImpl myComponentImpl = this;", 606 "", 607 " private MyComponentImpl(MyModule myModuleParam) {", 608 " this.myModule = myModuleParam;", 609 "", 610 " }", 611 "", 612 " @Override", 613 " public Foo foo() {", 614 " return injectFoo(Foo_Factory.newInstance());", 615 " }", 616 "", 617 " @CanIgnoreReturnValue", 618 " private Foo injectFoo(Foo instance) {", 619 " Foo_MembersInjector.injectBar(" 620 + "instance, MyModule_ProvideBarFactory.provideBar(myModule));", 621 " return instance;", 622 " }", 623 " }", 624 "}")); 625 }); 626 } 627 } 628