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