• 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.Compilers.daggerCompiler;
21 import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
22 import static dagger.internal.codegen.GeneratedLines.NPE_FROM_COMPONENT_METHOD;
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         daggerCompiler().withOptions(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                 GENERATED_ANNOTATION,
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         daggerCompiler()
166             .withOptions(compilerMode.javacopts())
167             .compile(module, otherPackageModule, component);
168     assertThat(compilation).succeeded();
169     JavaFileObject generatedComponent =
170         JavaFileObjects.forSourceLines(
171             "test.DaggerTestComponent",
172             "package test;",
173             "",
174             "import other.OtherPackageModule;",
175             "import other.OtherPackageModule_LFactory;",
176             "",
177             GENERATED_ANNOTATION,
178             "final class DaggerTestComponent implements TestComponent {",
179             "  private final ParentModule parentModule;",
180             "  private final OtherPackageModule otherPackageModule;",
181             "",
182             "  @Override",
183             "  public int i() {",
184             "    return parentModule.i();",
185             "  }",
186             "",
187             "  @Override",
188             "  public long l() {",
189             "    return OtherPackageModule_LFactory.l(otherPackageModule);",
190             "  }",
191             "}");
192     assertThat(compilation)
193         .generatedSourceFile("test.DaggerTestComponent")
194         .containsElementsIn(generatedComponent);
195   }
196 
197   @Test
componentInstances()198   public void componentInstances() {
199     JavaFileObject dependency =
200         JavaFileObjects.forSourceLines(
201             "test.Dep",
202             "package test;",
203             "",
204             "interface Dep {",
205             "  String string();",
206             "  Object object();",
207             "}");
208 
209     JavaFileObject component =
210         JavaFileObjects.forSourceLines(
211             "test.TestComponent",
212             "package test;",
213             "",
214             "import dagger.Component;",
215             "",
216             "@Component(dependencies = Dep.class)",
217             "interface TestComponent {",
218             "  TestComponent self();",
219             "  TestSubcomponent subcomponent();",
220             "",
221             "  Dep dep();",
222             "  String methodOnDep();",
223             "  Object otherMethodOnDep();",
224             "}");
225     JavaFileObject subcomponent =
226         JavaFileObjects.forSourceLines(
227             "test.TestComponent",
228             "package test;",
229             "",
230             "import dagger.Subcomponent;",
231             "",
232             "@Subcomponent",
233             "interface TestSubcomponent {",
234             "  TestComponent parent();",
235             "  Dep depFromSubcomponent();",
236             "}");
237 
238     Compilation compilation =
239         daggerCompiler()
240             .withOptions(compilerMode.javacopts())
241             .compile(dependency, component, subcomponent);
242     assertThat(compilation).succeeded();
243     assertThat(compilation)
244         .generatedSourceFile("test.DaggerTestComponent")
245         .containsElementsIn(
246             JavaFileObjects.forSourceLines(
247                 "test.DaggerTestComponent",
248                 "package test;",
249                 "",
250                 GENERATED_ANNOTATION,
251                 "final class DaggerTestComponent implements TestComponent {",
252                 "  private final Dep dep;",
253                 "",
254                 "  private DaggerTestComponent(Dep depParam) {",
255                 "    this.dep = depParam;",
256                 "  }",
257                 "",
258                 "  @Override",
259                 "  public TestComponent self() {",
260                 "    return this;",
261                 "  }",
262                 "",
263                 "  @Override",
264                 "  public Dep dep() {",
265                 "    return dep;",
266                 "  }",
267                 "",
268                 "  @Override",
269                 "  public String methodOnDep() {",
270                 "    return Preconditions.checkNotNull(",
271                 "        dep.string(), " + NPE_FROM_COMPONENT_METHOD + " );",
272                 "  }",
273                 "",
274                 "  @Override",
275                 "  public Object otherMethodOnDep() {",
276                 "    return Preconditions.checkNotNull(",
277                 "        dep.object(), " + NPE_FROM_COMPONENT_METHOD + " );",
278                 "  }",
279                 "",
280                 "  private final class TestSubcomponentImpl implements TestSubcomponent {",
281                 "    @Override",
282                 "    public TestComponent parent() {",
283                 "      return DaggerTestComponent.this;",
284                 "    }",
285                 "",
286                 "    @Override",
287                 "    public Dep depFromSubcomponent() {",
288                 "      return DaggerTestComponent.this.dep;",
289                 "    }",
290                 "  }",
291                 "}"));
292   }
293 
294   @Test
componentRequirementNeededInFactoryCreationOfSubcomponent()295   public void componentRequirementNeededInFactoryCreationOfSubcomponent() {
296     JavaFileObject parentModule =
297         JavaFileObjects.forSourceLines(
298             "test.ParentModule",
299             "package test;",
300             "",
301             "import dagger.Module;",
302             "import dagger.multibindings.IntoSet;",
303             "import dagger.Provides;",
304             "import java.util.Set;",
305             "",
306             "@Module",
307             "class ParentModule {",
308             "  @Provides",
309             // intentionally non-static. this needs to require the module when the subcompnent
310             // adds to the Set binding
311             "  Object reliesOnMultibinding(Set<Object> set) { return set; }",
312             "",
313             "  @Provides @IntoSet static Object contribution() { return new Object(); }",
314             "}");
315 
316     JavaFileObject childModule =
317         JavaFileObjects.forSourceLines(
318             "test.ChildModule",
319             "package test;",
320             "",
321             "import dagger.Module;",
322             "import dagger.multibindings.IntoSet;",
323             "import dagger.Provides;",
324             "",
325             "@Module",
326             "class ChildModule {",
327             "  @Provides @IntoSet static Object contribution() { return new Object(); }",
328             "}");
329 
330     JavaFileObject component =
331         JavaFileObjects.forSourceLines(
332             "test.TestComponent",
333             "package test;",
334             "",
335             "import dagger.Component;",
336             "import javax.inject.Provider;",
337             "",
338             "@Component(modules = ParentModule.class)",
339             "interface TestComponent {",
340             "  Provider<Object> dependsOnMultibinding();",
341             "  TestSubcomponent subcomponent();",
342             "}");
343 
344     JavaFileObject subcomponent =
345         JavaFileObjects.forSourceLines(
346             "test.TestSubcomponent",
347             "package test;",
348             "",
349             "import dagger.Subcomponent;",
350             "import javax.inject.Provider;",
351             "",
352             "@Subcomponent(modules = ChildModule.class)",
353             "interface TestSubcomponent {",
354             "  Provider<Object> dependsOnMultibinding();",
355             "}");
356     JavaFileObject generatedComponent;
357     switch (compilerMode) {
358       case FAST_INIT_MODE:
359         generatedComponent =
360             JavaFileObjects.forSourceLines(
361                 "test.DaggerTestComponent",
362                 "package test;",
363                 "",
364                 GENERATED_ANNOTATION,
365                 "final class DaggerTestComponent implements TestComponent {",
366                 "  private final ParentModule parentModule;",
367                 "",
368                 "  private DaggerTestComponent(ParentModule parentModuleParam) {",
369                 "    this.parentModule = parentModuleParam;",
370                 "  }",
371                 "",
372                 "  private final class TestSubcomponentImpl implements TestSubcomponent {",
373                 "    private Set<Object> getSetOfObject() {",
374                 "      return ImmutableSet.<Object>of(",
375                 "          ParentModule_ContributionFactory.contribution(),",
376                 "          ChildModule_ContributionFactory.contribution());",
377                 "    }",
378                 "",
379                 "    private Object getObject() {",
380                 "      return ParentModule_ReliesOnMultibindingFactory.reliesOnMultibinding(",
381                 "          DaggerTestComponent.this.parentModule, getSetOfObject());",
382                 "    }",
383                 "  }",
384                 "}");
385         break;
386       default:
387         generatedComponent =
388             JavaFileObjects.forSourceLines(
389                 "test.DaggerTestComponent",
390                 "package test;",
391                 "",
392                 GENERATED_ANNOTATION,
393                 "final class DaggerTestComponent implements TestComponent {",
394                 "  private final ParentModule parentModule;",
395                 "",
396                 "  private DaggerTestComponent(ParentModule parentModuleParam) {",
397                 "    this.parentModule = parentModuleParam;",
398                 "    initialize(parentModuleParam);",
399                 "  }",
400                 "",
401                 "  @SuppressWarnings(\"unchecked\")",
402                 "  private void initialize(final ParentModule parentModuleParam) {",
403                 "    this.setOfObjectProvider =",
404                 "        SetFactory.<Object>builder(1, 0)",
405                 "            .addProvider(ParentModule_ContributionFactory.create())",
406                 "            .build();",
407                 "    this.reliesOnMultibindingProvider =",
408                 "        ParentModule_ReliesOnMultibindingFactory.create(",
409                 "            parentModuleParam, setOfObjectProvider);",
410                 "  }",
411                 "",
412                 "  private final class TestSubcomponentImpl implements TestSubcomponent {",
413                 "    @SuppressWarnings(\"unchecked\")",
414                 "    private void initialize() {",
415                 "      this.setOfObjectProvider =",
416                 "          SetFactory.<Object>builder(2, 0)",
417                 "              .addProvider(ParentModule_ContributionFactory.create())",
418                 "              .addProvider(ChildModule_ContributionFactory.create())",
419                 "              .build();",
420                 "      this.reliesOnMultibindingProvider =",
421                 "          ParentModule_ReliesOnMultibindingFactory.create(",
422                 "              DaggerTestComponent.this.parentModule, setOfObjectProvider);",
423                 "    }",
424                 "  }",
425                 "}");
426     }
427     Compilation compilation =
428         daggerCompiler()
429             .withOptions(compilerMode.javacopts())
430             .compile(parentModule, childModule, component, subcomponent);
431     assertThat(compilation).succeeded();
432     assertThat(compilation)
433         .generatedSourceFile("test.DaggerTestComponent")
434         .containsElementsIn(generatedComponent);
435   }
436 }
437