• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.internal.codegen;
18 
19 import static com.google.testing.compile.CompilationSubject.assertThat;
20 import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
21 import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
22 import static dagger.internal.codegen.Compilers.compilerWithOptions;
23 
24 import com.google.testing.compile.Compilation;
25 import com.google.testing.compile.JavaFileObjects;
26 import java.util.Collection;
27 import javax.tools.JavaFileObject;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.junit.runners.Parameterized;
31 import org.junit.runners.Parameterized.Parameters;
32 
33 @RunWith(Parameterized.class)
34 public class ComponentRequirementFieldTest {
35   @Parameters(name = "{0}")
parameters()36   public static Collection<Object[]> parameters() {
37     return CompilerMode.TEST_PARAMETERS;
38   }
39 
40   private final CompilerMode compilerMode;
41 
ComponentRequirementFieldTest(CompilerMode compilerMode)42   public ComponentRequirementFieldTest(CompilerMode compilerMode) {
43     this.compilerMode = compilerMode;
44   }
45 
46   @Test
bindsInstance()47   public void bindsInstance() {
48     JavaFileObject component =
49         JavaFileObjects.forSourceLines(
50             "test.TestComponent",
51             "package test;",
52             "",
53             "import dagger.BindsInstance;",
54             "import dagger.Component;",
55             "import java.util.List;",
56             "",
57             "@Component",
58             "interface TestComponent {",
59             "  int i();",
60             "  List<String> list();",
61             "",
62             "  @Component.Builder",
63             "  interface Builder {",
64             "    @BindsInstance Builder i(int i);",
65             "    @BindsInstance Builder list(List<String> list);",
66             "    TestComponent build();",
67             "  }",
68             "}");
69     Compilation compilation =
70         compilerWithOptions(compilerMode.javacopts()).compile(component);
71     assertThat(compilation).succeeded();
72     assertThat(compilation)
73         .generatedSourceFile("test.DaggerTestComponent")
74         .containsElementsIn(
75             JavaFileObjects.forSourceLines(
76                 "test.DaggerTestComponent",
77                 "package test;",
78                 "",
79                 GeneratedLines.generatedAnnotations(),
80                 "final class DaggerTestComponent implements TestComponent {",
81                 "  private final Integer i;",
82                 "  private final List<String> list;",
83                 "",
84                 "  private DaggerTestComponent(Integer iParam, List<String> listParam) {",
85                 "    this.i = iParam;",
86                 "    this.list = listParam;",
87                 "  }",
88                 "",
89                 "  @Override",
90                 "  public int i() {",
91                 "    return i;",
92                 "  }",
93                 "",
94                 "  @Override",
95                 "  public List<String> list() {",
96                 "    return list;",
97                 "  }",
98                 "",
99                 "  private static final class Builder implements TestComponent.Builder {",
100                 "    private Integer i;",
101                 "    private List<String> list;",
102                 "",
103                 "    @Override",
104                 "    public Builder i(int i) {",
105                 "      this.i = Preconditions.checkNotNull(i);",
106                 "      return this;",
107                 "    }",
108                 "",
109                 "    @Override",
110                 "    public Builder list(List<String> list) {",
111                 "      this.list = Preconditions.checkNotNull(list);",
112                 "      return this;",
113                 "    }",
114                 "",
115                 "    @Override",
116                 "    public TestComponent build() {",
117                 "      Preconditions.checkBuilderRequirement(i, Integer.class);",
118                 "      Preconditions.checkBuilderRequirement(list, List.class);",
119                 "      return new DaggerTestComponent(i, list);",
120                 "    }",
121                 "  }",
122                 "}"));
123   }
124 
125   @Test
instanceModuleMethod()126   public void instanceModuleMethod() {
127     JavaFileObject module =
128         JavaFileObjects.forSourceLines(
129             "test.ParentModule",
130             "package test;",
131             "",
132             "import dagger.Module;",
133             "import dagger.Provides;",
134             "",
135             "@Module",
136             "class ParentModule {",
137             "  @Provides int i() { return 0; }",
138             "}");
139     JavaFileObject otherPackageModule =
140         JavaFileObjects.forSourceLines(
141             "other.OtherPackageModule",
142             "package other;",
143             "",
144             "import dagger.Module;",
145             "import dagger.Provides;",
146             "",
147             "@Module",
148             "public class OtherPackageModule {",
149             "  @Provides long l() { return 0L; }",
150             "}");
151     JavaFileObject component =
152         JavaFileObjects.forSourceLines(
153             "test.TestComponent",
154             "package test;",
155             "",
156             "import dagger.Component;",
157             "import other.OtherPackageModule;",
158             "",
159             "@Component(modules = {ParentModule.class, OtherPackageModule.class})",
160             "interface TestComponent {",
161             "  int i();",
162             "  long l();",
163             "}");
164     Compilation compilation =
165         compilerWithOptions(compilerMode.javacopts())
166             .compile(module, otherPackageModule, component);
167     assertThat(compilation).succeeded();
168     JavaFileObject generatedComponent =
169         JavaFileObjects.forSourceLines(
170             "test.DaggerTestComponent",
171             "package test;",
172             "",
173             "import other.OtherPackageModule;",
174             "import other.OtherPackageModule_LFactory;",
175             "",
176             GeneratedLines.generatedAnnotations(),
177             "final class DaggerTestComponent implements TestComponent {",
178             "  private final ParentModule parentModule;",
179             "  private final OtherPackageModule otherPackageModule;",
180             "",
181             "  @Override",
182             "  public int i() {",
183             "    return parentModule.i();",
184             "  }",
185             "",
186             "  @Override",
187             "  public long l() {",
188             "    return OtherPackageModule_LFactory.l(otherPackageModule);",
189             "  }",
190             "}");
191     assertThat(compilation)
192         .generatedSourceFile("test.DaggerTestComponent")
193         .containsElementsIn(generatedComponent);
194   }
195 
196   @Test
componentInstances()197   public void componentInstances() {
198     JavaFileObject dependency =
199         JavaFileObjects.forSourceLines(
200             "test.Dep",
201             "package test;",
202             "",
203             "interface Dep {",
204             "  String string();",
205             "  Object object();",
206             "}");
207 
208     JavaFileObject component =
209         JavaFileObjects.forSourceLines(
210             "test.TestComponent",
211             "package test;",
212             "",
213             "import dagger.Component;",
214             "",
215             "@Component(dependencies = Dep.class)",
216             "interface TestComponent {",
217             "  TestComponent self();",
218             "  TestSubcomponent subcomponent();",
219             "",
220             "  Dep dep();",
221             "  String methodOnDep();",
222             "  Object otherMethodOnDep();",
223             "}");
224     JavaFileObject subcomponent =
225         JavaFileObjects.forSourceLines(
226             "test.TestComponent",
227             "package test;",
228             "",
229             "import dagger.Subcomponent;",
230             "",
231             "@Subcomponent",
232             "interface TestSubcomponent {",
233             "  TestComponent parent();",
234             "  Dep depFromSubcomponent();",
235             "}");
236 
237     Compilation compilation =
238         compilerWithOptions(compilerMode.javacopts())
239             .compile(dependency, component, subcomponent);
240     assertThat(compilation).succeeded();
241     assertThat(compilation)
242         .generatedSourceFile("test.DaggerTestComponent")
243         .containsElementsIn(
244             JavaFileObjects.forSourceLines(
245                 "test.DaggerTestComponent",
246                 "package test;",
247                 "",
248                 GeneratedLines.generatedAnnotations(),
249                 "final class DaggerTestComponent implements TestComponent {",
250                 "  private final Dep dep;",
251                 "",
252                 "  private DaggerTestComponent(Dep depParam) {",
253                 "    this.dep = depParam;",
254                 "  }",
255                 "",
256                 "  @Override",
257                 "  public TestComponent self() {",
258                 "    return this;",
259                 "  }",
260                 "",
261                 "  @Override",
262                 "  public Dep dep() {",
263                 "    return dep;",
264                 "  }",
265                 "",
266                 "  @Override",
267                 "  public String methodOnDep() {",
268                 "    return Preconditions.checkNotNullFromComponent(",
269                 "        dep.string());",
270                 "  }",
271                 "",
272                 "  @Override",
273                 "  public Object otherMethodOnDep() {",
274                 "    return Preconditions.checkNotNullFromComponent(dep.object());",
275                 "  }",
276                 "",
277                 "  private static final class TestSubcomponentImpl implements TestSubcomponent {",
278                 "    @Override",
279                 "    public TestComponent parent() {",
280                 "      return testComponent;",
281                 "    }",
282                 "",
283                 "    @Override",
284                 "    public Dep depFromSubcomponent() {",
285                 "      return testComponent.dep;",
286                 "    }",
287                 "  }",
288                 "}"));
289   }
290 
291   @Test
componentRequirementNeededInFactoryCreationOfSubcomponent()292   public void componentRequirementNeededInFactoryCreationOfSubcomponent() {
293     JavaFileObject parentModule =
294         JavaFileObjects.forSourceLines(
295             "test.ParentModule",
296             "package test;",
297             "",
298             "import dagger.Module;",
299             "import dagger.multibindings.IntoSet;",
300             "import dagger.Provides;",
301             "import java.util.Set;",
302             "",
303             "@Module",
304             "class ParentModule {",
305             "  @Provides",
306             // intentionally non-static. this needs to require the module when the subcompnent
307             // adds to the Set binding
308             "  Object reliesOnMultibinding(Set<Object> set) { return set; }",
309             "",
310             "  @Provides @IntoSet static Object contribution() { return new Object(); }",
311             "}");
312 
313     JavaFileObject childModule =
314         JavaFileObjects.forSourceLines(
315             "test.ChildModule",
316             "package test;",
317             "",
318             "import dagger.Module;",
319             "import dagger.multibindings.IntoSet;",
320             "import dagger.Provides;",
321             "",
322             "@Module",
323             "class ChildModule {",
324             "  @Provides @IntoSet static Object contribution() { return new Object(); }",
325             "}");
326 
327     JavaFileObject component =
328         JavaFileObjects.forSourceLines(
329             "test.TestComponent",
330             "package test;",
331             "",
332             "import dagger.Component;",
333             "import javax.inject.Provider;",
334             "",
335             "@Component(modules = ParentModule.class)",
336             "interface TestComponent {",
337             "  Provider<Object> dependsOnMultibinding();",
338             "  TestSubcomponent subcomponent();",
339             "}");
340 
341     JavaFileObject subcomponent =
342         JavaFileObjects.forSourceLines(
343             "test.TestSubcomponent",
344             "package test;",
345             "",
346             "import dagger.Subcomponent;",
347             "import javax.inject.Provider;",
348             "",
349             "@Subcomponent(modules = ChildModule.class)",
350             "interface TestSubcomponent {",
351             "  Provider<Object> dependsOnMultibinding();",
352             "}");
353 
354     Compilation compilation =
355         compilerWithOptions(compilerMode.javacopts())
356             .compile(parentModule, childModule, component, subcomponent);
357     assertThat(compilation).succeeded();
358     assertThat(compilation)
359         .generatedSourceFile("test.DaggerTestComponent")
360         .containsElementsIn(
361             compilerMode
362                 .javaFileBuilder("test.DaggerSimpleComponent")
363                 .addLines(
364                     "package test;",
365                     "",
366                     GeneratedLines.generatedAnnotations(),
367                     "final class DaggerTestComponent implements TestComponent {",
368                     "  private final ParentModule parentModule;",
369                     "",
370                     "  private DaggerTestComponent(ParentModule parentModuleParam) {",
371                     "    this.parentModule = parentModuleParam;",
372                     "    initialize(parentModuleParam);",
373                     "  }")
374                 .addLinesIn(
375                     DEFAULT_MODE,
376                     "  @SuppressWarnings(\"unchecked\")",
377                     "  private void initialize(final ParentModule parentModuleParam) {",
378                     "    this.setOfObjectProvider =",
379                     "        SetFactory.<Object>builder(1, 0)",
380                     "            .addProvider(ParentModule_ContributionFactory.create())",
381                     "            .build();",
382                     "    this.reliesOnMultibindingProvider =",
383                     "        ParentModule_ReliesOnMultibindingFactory",
384                     "            .create(parentModuleParam, setOfObjectProvider);",
385                     "  }")
386                 .addLinesIn(
387                     FAST_INIT_MODE,
388                     "",
389                     "  private Set<Object> setOfObject() {",
390                     "    return ImmutableSet.<Object>of(",
391                     "        ParentModule_ContributionFactory.contribution());",
392                     "  }",
393                     "",
394                     "  @SuppressWarnings(\"unchecked\")",
395                     "  private void initialize(final ParentModule parentModuleParam) {",
396                     "    this.reliesOnMultibindingProvider =",
397                     "        new SwitchingProvider<>(testComponent, 0);",
398                     "  }")
399                 .addLines(
400                     "  @Override",
401                     "  public Provider<Object> dependsOnMultibinding() {",
402                     "    return reliesOnMultibindingProvider;",
403                     "  }",
404                     "",
405                     "  @Override",
406                     "  public TestSubcomponent subcomponent() {",
407                     "    return new TestSubcomponentImpl(testComponent);",
408                     "  }",
409                     "",
410                     "  private static final class TestSubcomponentImpl",
411                     "      implements TestSubcomponent {")
412                 .addLinesIn(
413                     DEFAULT_MODE,
414                     "    @SuppressWarnings(\"unchecked\")",
415                     "    private void initialize() {",
416                     "      this.setOfObjectProvider =",
417                     "          SetFactory.<Object>builder(2, 0)",
418                     "              .addProvider(ParentModule_ContributionFactory.create())",
419                     "              .addProvider(ChildModule_ContributionFactory.create())",
420                     "              .build();",
421                     "      this.reliesOnMultibindingProvider =",
422                     "          ParentModule_ReliesOnMultibindingFactory",
423                     "              .create(testComponent.parentModule, setOfObjectProvider);",
424                     "    }")
425                 .addLinesIn(
426                     FAST_INIT_MODE,
427                     "    private Set<Object> setOfObject() {",
428                     "      return ImmutableSet.<Object>of(",
429                     "          ParentModule_ContributionFactory.contribution(),",
430                     "          ChildModule_ContributionFactory.contribution());",
431                     "    }",
432                     "",
433                     "    @SuppressWarnings(\"unchecked\")",
434                     "    private void initialize() {",
435                     "      this.reliesOnMultibindingProvider =",
436                     "          new SwitchingProvider<>(testComponent, testSubcomponentImpl, 0);",
437                     "    }")
438                 .addLines(
439                     "    @Override",
440                     "    public Provider<Object> dependsOnMultibinding() {",
441                     "      return reliesOnMultibindingProvider;",
442                     "    }")
443                 .addLinesIn(
444                     FAST_INIT_MODE,
445                     "    private static final class SwitchingProvider<T> implements Provider<T> {",
446                     "      @SuppressWarnings(\"unchecked\")",
447                     "      @Override",
448                     "      public T get() {",
449                     "        switch (id) {",
450                     "          case 0:",
451                     "          return (T) ParentModule_ReliesOnMultibindingFactory",
452                     "            .reliesOnMultibinding(",
453                     "              testComponent.parentModule,",
454                     "              testSubcomponentImpl.setOfObject());",
455                     "          default: throw new AssertionError(id);",
456                     "        }",
457                     "      }",
458                     "    }",
459                     "  }",
460                     "",
461                     "  private static final class SwitchingProvider<T> implements Provider<T> {",
462                     "    @SuppressWarnings(\"unchecked\")",
463                     "    @Override",
464                     "    public T get() {",
465                     "      switch (id) {",
466                     "        case 0:",
467                     "        return (T) ParentModule_ReliesOnMultibindingFactory",
468                     "          .reliesOnMultibinding(",
469                     "             testComponent.parentModule, testComponent.setOfObject());",
470                     "        default: throw new AssertionError(id);",
471                     "      }",
472                     "    }",
473                     "  }",
474                     "}")
475                 .build());
476   }
477 }
478