• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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