• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Google, Inc.
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 package dagger.internal.codegen;
17 
18 import com.google.common.base.Joiner;
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.ImmutableSet;
21 import com.google.testing.compile.JavaFileObjects;
22 import dagger.internal.codegen.writer.StringLiteral;
23 import java.io.IOException;
24 import java.io.Writer;
25 import java.util.Set;
26 import javax.annotation.processing.AbstractProcessor;
27 import javax.annotation.processing.Processor;
28 import javax.annotation.processing.RoundEnvironment;
29 import javax.lang.model.element.TypeElement;
30 import javax.tools.JavaFileObject;
31 import org.junit.Ignore;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.junit.runners.JUnit4;
35 
36 import static com.google.common.truth.Truth.assertAbout;
37 import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
38 import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
39 import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT;
40 import static javax.tools.StandardLocation.SOURCE_OUTPUT;
41 
42 @RunWith(JUnit4.class)
43 public class ComponentProcessorTest {
44   private static final StringLiteral NPE_LITERAL =
45       StringLiteral.forValue(ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD);
46 
componentOnConcreteClass()47   @Test public void componentOnConcreteClass() {
48     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
49         "package test;",
50         "",
51         "import dagger.Component;",
52         "",
53         "@Component",
54         "final class NotAComponent {}");
55     assertAbout(javaSource()).that(componentFile)
56         .processedWith(new ComponentProcessor())
57         .failsToCompile()
58         .withErrorContaining("interface");
59   }
60 
componentOnEnum()61   @Test public void componentOnEnum() {
62     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
63         "package test;",
64         "",
65         "import dagger.Component;",
66         "",
67         "@Component",
68         "enum NotAComponent {",
69         "  INSTANCE",
70         "}");
71     assertAbout(javaSource()).that(componentFile)
72         .processedWith(new ComponentProcessor())
73         .failsToCompile()
74         .withErrorContaining("interface");
75   }
76 
componentOnAnnotation()77   @Test public void componentOnAnnotation() {
78     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
79         "package test;",
80         "",
81         "import dagger.Component;",
82         "",
83         "@Component",
84         "@interface NotAComponent {}");
85     assertAbout(javaSource()).that(componentFile)
86         .processedWith(new ComponentProcessor())
87         .failsToCompile()
88         .withErrorContaining("interface");
89   }
90 
nonModuleModule()91   @Test public void nonModuleModule() {
92     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
93         "package test;",
94         "",
95         "import dagger.Component;",
96         "",
97         "@Component(modules = Object.class)",
98         "interface NotAComponent {}");
99     assertAbout(javaSource()).that(componentFile)
100         .processedWith(new ComponentProcessor())
101         .failsToCompile()
102         .withErrorContaining("is not annotated with @Module");
103   }
104 
checkCannotReferToModuleOfType(String moduleType)105   private void checkCannotReferToModuleOfType(String moduleType) {
106     JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
107         "package test;",
108         "",
109         "import dagger.Module;",
110         "",
111         "@Module",
112         moduleType + " TestModule {}");
113     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.BadComponent",
114         "package test;",
115         "",
116         "import dagger.Component;",
117         "",
118         "@Component(modules = TestModule.class)",
119         "interface BadComponent {}");
120     assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile))
121         .processedWith(new ComponentProcessor())
122         .failsToCompile()
123         .withErrorContaining(
124             String.format(REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT, "test.TestModule"));
125   }
126 
cannotReferToAbstractClassModules()127   @Test public void cannotReferToAbstractClassModules() {
128     checkCannotReferToModuleOfType("abstract class");
129   }
130 
cannotReferToInterfaceModules()131   @Test public void cannotReferToInterfaceModules() {
132     checkCannotReferToModuleOfType("interface");
133   }
134 
doubleBindingFromResolvedModules()135   @Test public void doubleBindingFromResolvedModules() {
136     JavaFileObject parent = JavaFileObjects.forSourceLines("test.ParentModule",
137         "package test;",
138         "",
139         "import dagger.Module;",
140         "import dagger.Provides;",
141         "import java.util.List;",
142         "",
143         "@Module",
144         "abstract class ParentModule<A> {",
145         "  @Provides List<A> provideListB(A a) { return null; }",
146         "}");
147     JavaFileObject child = JavaFileObjects.forSourceLines("test.ChildModule",
148         "package test;",
149         "",
150         "import dagger.Module;",
151         "import dagger.Provides;",
152         "",
153         "@Module",
154         "class ChildNumberModule extends ParentModule<Integer> {",
155         "  @Provides Integer provideInteger() { return null; }",
156         "}");
157     JavaFileObject another = JavaFileObjects.forSourceLines("test.AnotherModule",
158         "package test;",
159         "",
160         "import dagger.Module;",
161         "import dagger.Provides;",
162         "import java.util.List;",
163         "",
164         "@Module",
165         "class AnotherModule {",
166         "  @Provides List<Integer> provideListOfInteger() { return null; }",
167         "}");
168     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.BadComponent",
169         "package test;",
170         "",
171         "import dagger.Component;",
172         "import java.util.List;",
173         "",
174         "@Component(modules = {ChildNumberModule.class, AnotherModule.class})",
175         "interface BadComponent {",
176         "  List<Integer> listOfInteger();",
177         "}");
178     assertAbout(javaSources()).that(ImmutableList.of(parent, child, another, componentFile))
179         .processedWith(new ComponentProcessor())
180         .failsToCompile().withErrorContaining(
181             "java.util.List<java.lang.Integer> is bound multiple times")
182         .and().withErrorContaining(
183             "@Provides List<Integer> test.ChildNumberModule.provideListB(Integer)")
184         .and().withErrorContaining(
185             "@Provides List<Integer> test.AnotherModule.provideListOfInteger()");
186   }
187 
simpleComponent()188   @Test public void simpleComponent() {
189     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
190         "package test;",
191         "",
192         "import javax.inject.Inject;",
193         "",
194         "final class SomeInjectableType {",
195         "  @Inject SomeInjectableType() {}",
196         "}");
197     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
198         "package test;",
199         "",
200         "import dagger.Component;",
201         "import dagger.Lazy;",
202         "",
203         "import javax.inject.Provider;",
204         "",
205         "@Component",
206         "interface SimpleComponent {",
207         "  SomeInjectableType someInjectableType();",
208         "  Lazy<SomeInjectableType> lazySomeInjectableType();",
209         "  Provider<SomeInjectableType> someInjectableTypeProvider();",
210         "}");
211     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
212         "test.DaggerSimpleComponent",
213         "package test;",
214         "",
215         "import dagger.Lazy;",
216         "import dagger.internal.DoubleCheckLazy;",
217         "import javax.annotation.Generated;",
218         "import javax.inject.Provider;",
219         "",
220         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
221         "public final class DaggerSimpleComponent implements SimpleComponent {",
222         "  private DaggerSimpleComponent(Builder builder) {",
223         "    assert builder != null;",
224         "    initialize(builder);",
225         "  }",
226         "",
227         "  public static Builder builder() {",
228         "    return new Builder();",
229         "  }",
230         "",
231         "  public static SimpleComponent create() {",
232         "    return builder().build();",
233         "  }",
234         "",
235         "  @SuppressWarnings(\"unchecked\")",
236         "  private void initialize(final Builder builder) {",
237         "  }",
238         "",
239         "  @Override",
240         "  public SomeInjectableType someInjectableType() {",
241         "    return SomeInjectableType_Factory.create().get();",
242         "  }",
243         "",
244         "  @Override",
245         "  public Lazy<SomeInjectableType> lazySomeInjectableType() {",
246         "    return DoubleCheckLazy.create(SomeInjectableType_Factory.create());",
247         "  }",
248         "",
249         "  @Override",
250         "  public Provider<SomeInjectableType> someInjectableTypeProvider() {",
251         "    return SomeInjectableType_Factory.create();",
252         "  }",
253         "",
254         "  public static final class Builder {",
255         "    private Builder() {",
256         "    }",
257         "",
258         "    public SimpleComponent build() {",
259         "      return new DaggerSimpleComponent(this);",
260         "    }",
261         "  }",
262         "}");
263     assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
264         .processedWith(new ComponentProcessor())
265         .compilesWithoutError()
266         .and().generatesSources(generatedComponent);
267   }
268 
componentWithScope()269   @Test public void componentWithScope() {
270     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
271         "package test;",
272         "",
273         "import javax.inject.Inject;",
274         "import javax.inject.Singleton;",
275         "",
276         "@Singleton",
277         "final class SomeInjectableType {",
278         "  @Inject SomeInjectableType() {}",
279         "}");
280     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
281         "package test;",
282         "",
283         "import dagger.Component;",
284         "import dagger.Lazy;",
285         "import javax.inject.Provider;",
286         "import javax.inject.Singleton;",
287         "",
288         "@Singleton",
289         "@Component",
290         "interface SimpleComponent {",
291         "  SomeInjectableType someInjectableType();",
292         "  Lazy<SomeInjectableType> lazySomeInjectableType();",
293         "  Provider<SomeInjectableType> someInjectableTypeProvider();",
294         "}");
295     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
296         "test.DaggerSimpleComponent",
297         "package test;",
298         "",
299         "import dagger.Lazy;",
300         "import dagger.internal.DoubleCheckLazy;",
301         "import dagger.internal.ScopedProvider;",
302         "import javax.annotation.Generated;",
303         "import javax.inject.Provider;",
304         "",
305         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
306         "public final class DaggerSimpleComponent implements SimpleComponent {",
307         "  private Provider<SomeInjectableType> someInjectableTypeProvider;",
308         "",
309         "  private DaggerSimpleComponent(Builder builder) {",
310         "    assert builder != null;",
311         "    initialize(builder);",
312         "  }",
313         "",
314         "  public static Builder builder() {",
315         "    return new Builder();",
316         "  }",
317         "",
318         "  public static SimpleComponent create() {",
319         "    return builder().build();",
320         "  }",
321         "",
322         "  @SuppressWarnings(\"unchecked\")",
323         "  private void initialize(final Builder builder) {",
324         "    this.someInjectableTypeProvider =",
325         "        ScopedProvider.create(SomeInjectableType_Factory.create());",
326         "  }",
327         "",
328         "  @Override",
329         "  public SomeInjectableType someInjectableType() {",
330         "    return someInjectableTypeProvider.get();",
331         "  }",
332         "",
333         "  @Override",
334         "  public Lazy<SomeInjectableType> lazySomeInjectableType() {",
335         "    return DoubleCheckLazy.create(someInjectableTypeProvider);",
336         "  }",
337         "",
338         "  @Override",
339         "  public Provider<SomeInjectableType> someInjectableTypeProvider() {",
340         "    return someInjectableTypeProvider;",
341         "  }",
342         "",
343         "  public static final class Builder {",
344         "    private Builder() {",
345         "    }",
346         "",
347         "    public SimpleComponent build() {",
348         "      return new DaggerSimpleComponent(this);",
349         "    }",
350         "  }",
351         "}");
352     assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
353         .processedWith(new ComponentProcessor())
354         .compilesWithoutError()
355         .and().generatesSources(generatedComponent);
356   }
357 
simpleComponentWithNesting()358   @Test public void simpleComponentWithNesting() {
359     JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines("test.OuterType",
360         "package test;",
361         "",
362         "import dagger.Component;",
363         "import javax.inject.Inject;",
364         "",
365         "final class OuterType {",
366         "  static class A {",
367         "    @Inject A() {}",
368         "  }",
369         "  static class B {",
370         "    @Inject A a;",
371         "  }",
372         "  @Component interface SimpleComponent {",
373         "    A a();",
374         "    void inject(B b);",
375         "  }",
376         "}");
377 
378     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
379         "test.DaggerOuterType_SimpleComponent",
380         "package test;",
381         "",
382         "import dagger.MembersInjector;",
383         "import javax.annotation.Generated;",
384         "import test.OuterType.A;",
385         "import test.OuterType.B;",
386         "import test.OuterType.SimpleComponent;",
387         "",
388         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
389         "public final class DaggerOuterType_SimpleComponent implements SimpleComponent {",
390         "  private MembersInjector<B> bMembersInjector;",
391         "",
392         "  private DaggerOuterType_SimpleComponent(Builder builder) {",
393         "    assert builder != null;",
394         "    initialize(builder);",
395         "  }",
396         "",
397         "  public static Builder builder() {",
398         "    return new Builder();",
399         "  }",
400         "",
401         "  public static SimpleComponent create() {",
402         "    return builder().build();",
403         "  }",
404         "",
405         "  @SuppressWarnings(\"unchecked\")",
406         "  private void initialize(final Builder builder) {",
407         "    this.bMembersInjector =",
408         "        OuterType$B_MembersInjector.create(OuterType$A_Factory.create());",
409         "  }",
410         "",
411         "  @Override",
412         "  public A a() {",
413         "    return OuterType$A_Factory.create().get();",
414         "  }",
415         "",
416         "  @Override",
417         "  public void inject(B b) {",
418         "    bMembersInjector.injectMembers(b);",
419         "  }",
420         "",
421         "  public static final class Builder {",
422         "    private Builder() {",
423         "    }",
424         "",
425         "    public SimpleComponent build() {",
426         "      return new DaggerOuterType_SimpleComponent(this);",
427         "    }",
428         "  }",
429         "}");
430     assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile))
431         .processedWith(new ComponentProcessor())
432         .compilesWithoutError()
433         .and().generatesSources(generatedComponent);
434   }
435 
componentWithModule()436   @Test public void componentWithModule() {
437     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
438         "package test;",
439         "",
440         "import javax.inject.Inject;",
441         "",
442         "final class A {",
443         "  @Inject A(B b) {}",
444         "}");
445     JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
446         "package test;",
447         "",
448         "interface B {}");
449     JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
450         "package test;",
451         "",
452         "import javax.inject.Inject;",
453         "",
454         "final class C {",
455         "  @Inject C() {}",
456         "}");
457 
458     JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
459         "package test;",
460         "",
461         "import dagger.Module;",
462         "import dagger.Provides;",
463         "",
464         "@Module",
465         "final class TestModule {",
466         "  @Provides B b(C c) { return null; }",
467         "}");
468 
469     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
470         "package test;",
471         "",
472         "import dagger.Component;",
473         "",
474         "import javax.inject.Provider;",
475         "",
476         "@Component(modules = TestModule.class)",
477         "interface TestComponent {",
478         "  A a();",
479         "}");
480     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
481         "test.DaggerTestComponent",
482         "package test;",
483         "",
484         "import javax.annotation.Generated;",
485         "import javax.inject.Provider;",
486         "",
487         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
488         "public final class DaggerTestComponent implements TestComponent {",
489         "  private Provider<B> bProvider;",
490         "  private Provider<A> aProvider;",
491         "",
492         "  private DaggerTestComponent(Builder builder) {",
493         "    assert builder != null;",
494         "    initialize(builder);",
495         "  }",
496         "",
497         "  public static Builder builder() {",
498         "    return new Builder();",
499         "  }",
500         "",
501         "  public static TestComponent create() {",
502         "    return builder().build();",
503         "  }",
504         "",
505         "  @SuppressWarnings(\"unchecked\")",
506         "  private void initialize(final Builder builder) {",
507         "    this.bProvider = TestModule_BFactory.create(builder.testModule,",
508         "        C_Factory.create());",
509         "    this.aProvider = A_Factory.create(bProvider);",
510         "  }",
511         "",
512         "  @Override",
513         "  public A a() {",
514         "    return aProvider.get();",
515         "  }",
516         "",
517         "  public static final class Builder {",
518         "    private TestModule testModule;",
519         "",
520         "    private Builder() {",
521         "    }",
522         "",
523         "    public TestComponent build() {",
524         "      if (testModule == null) {",
525         "        this.testModule = new TestModule();",
526         "      }",
527         "      return new DaggerTestComponent(this);",
528         "    }",
529         "",
530         "    public Builder testModule(TestModule testModule) {",
531         "      if (testModule == null) {",
532         "        throw new NullPointerException();",
533         "      }",
534         "      this.testModule = testModule;",
535         "      return this;",
536         "    }",
537         "  }",
538         "}");
539     assertAbout(javaSources())
540         .that(ImmutableList.of(aFile, bFile, cFile, moduleFile, componentFile))
541         .processedWith(new ComponentProcessor())
542         .compilesWithoutError()
543         .and().generatesSources(generatedComponent);
544   }
545 
transitiveModuleDeps()546   @Test public void transitiveModuleDeps() {
547     JavaFileObject always = JavaFileObjects.forSourceLines("test.AlwaysIncluded",
548         "package test;",
549         "",
550         "import dagger.Module;",
551         "",
552         "@Module",
553         "final class AlwaysIncluded {}");
554     JavaFileObject testModule = JavaFileObjects.forSourceLines("test.TestModule",
555         "package test;",
556         "",
557         "import dagger.Module;",
558         "",
559         "@Module(includes = {DepModule.class, AlwaysIncluded.class})",
560         "final class TestModule extends ParentTestModule {}");
561     JavaFileObject parentTest = JavaFileObjects.forSourceLines("test.ParentTestModule",
562         "package test;",
563         "",
564         "import dagger.Module;",
565         "",
566         "@Module(includes = {ParentTestIncluded.class, AlwaysIncluded.class})",
567         "class ParentTestModule {}");
568     JavaFileObject parentTestIncluded = JavaFileObjects.forSourceLines("test.ParentTestIncluded",
569         "package test;",
570         "",
571         "import dagger.Module;",
572         "",
573         "@Module(includes = AlwaysIncluded.class)",
574         "final class ParentTestIncluded {}");
575     JavaFileObject depModule = JavaFileObjects.forSourceLines("test.TestModule",
576         "package test;",
577         "",
578         "import dagger.Module;",
579         "",
580         "@Module(includes = {RefByDep.class, AlwaysIncluded.class})",
581         "final class DepModule extends ParentDepModule {}");
582     JavaFileObject refByDep = JavaFileObjects.forSourceLines("test.RefByDep",
583         "package test;",
584         "",
585         "import dagger.Module;",
586         "",
587         "@Module(includes = AlwaysIncluded.class)",
588         "final class RefByDep extends ParentDepModule {}");
589     JavaFileObject parentDep = JavaFileObjects.forSourceLines("test.ParentDepModule",
590         "package test;",
591         "",
592         "import dagger.Module;",
593         "",
594         "@Module(includes = {ParentDepIncluded.class, AlwaysIncluded.class})",
595         "class ParentDepModule {}");
596     JavaFileObject parentDepIncluded = JavaFileObjects.forSourceLines("test.ParentDepIncluded",
597         "package test;",
598         "",
599         "import dagger.Module;",
600         "",
601         "@Module(includes = AlwaysIncluded.class)",
602         "final class ParentDepIncluded {}");
603 
604     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
605         "package test;",
606         "",
607         "import dagger.Component;",
608         "",
609         "import javax.inject.Provider;",
610         "",
611         "@Component(modules = TestModule.class)",
612         "interface TestComponent {",
613         "}");
614     // Generated code includes all includes, but excludes the parent modules.
615     // The "always" module should only be listed once.
616     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
617         "test.DaggerTestComponent",
618         "package test;",
619         "",
620         "import javax.annotation.Generated;",
621         "",
622         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
623         "public final class DaggerTestComponent implements TestComponent {",
624         "",
625         "  private DaggerTestComponent(Builder builder) {",
626         "    assert builder != null;",
627         "  }",
628         "",
629         "  public static Builder builder() {",
630         "    return new Builder();",
631         "  }",
632         "",
633         "  public static TestComponent create() {",
634         "    return builder().build();",
635         "  }",
636         "",
637         "  public static final class Builder {",
638         "    private Builder() {",
639         "    }",
640         "",
641         "    public TestComponent build() {",
642         "      return new DaggerTestComponent(this);",
643         "    }",
644         "",
645         "    @Deprecated",
646         "    public Builder testModule(TestModule testModule) {",
647         "      if (testModule == null) {",
648         "        throw new NullPointerException();",
649         "      }",
650         "      return this;",
651         "    }",
652         "",
653         "    @Deprecated",
654         "    public Builder parentTestIncluded(ParentTestIncluded parentTestIncluded) {",
655         "      if (parentTestIncluded == null) {",
656         "        throw new NullPointerException();",
657         "      }",
658         "      return this;",
659         "    }",
660         "",
661         "    @Deprecated",
662         "    public Builder alwaysIncluded(AlwaysIncluded alwaysIncluded) {",
663         "      if (alwaysIncluded == null) {",
664         "        throw new NullPointerException();",
665         "      }",
666         "      return this;",
667         "    }",
668         "",
669         "    @Deprecated",
670         "    public Builder depModule(DepModule depModule) {",
671         "      if (depModule == null) {",
672         "        throw new NullPointerException();",
673         "      }",
674         "      return this;",
675         "    }",
676         "",
677         "    @Deprecated",
678         "    public Builder parentDepIncluded(ParentDepIncluded parentDepIncluded) {",
679         "      if (parentDepIncluded == null) {",
680         "        throw new NullPointerException();",
681         "      }",
682         "      return this;",
683         "    }",
684         "",
685         "    @Deprecated",
686         "    public Builder refByDep(RefByDep refByDep) {",
687         "      if (refByDep == null) {",
688         "        throw new NullPointerException();",
689         "      }",
690         "      return this;",
691         "    }",
692         "  }",
693         "}");
694     assertAbout(javaSources())
695         .that(ImmutableList.of(always,
696             testModule,
697             parentTest,
698             parentTestIncluded,
699             depModule,
700             refByDep,
701             parentDep,
702             parentDepIncluded,
703             componentFile))
704         .processedWith(new ComponentProcessor())
705         .compilesWithoutError()
706         .and().generatesSources(generatedComponent);
707   }
708 
709   @Test
generatedTransitiveModule()710   public void generatedTransitiveModule() {
711     JavaFileObject rootModule = JavaFileObjects.forSourceLines("test.RootModule",
712         "package test;",
713         "",
714         "import dagger.Module;",
715         "",
716         "@Module(includes = GeneratedModule.class)",
717         "final class RootModule {}");
718     JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
719         "package test;",
720         "",
721         "import dagger.Component;",
722         "",
723         "@Component(modules = RootModule.class)",
724         "interface TestComponent {}");
725     assertAbout(javaSources())
726         .that(ImmutableList.of(rootModule, component))
727         .processedWith(new ComponentProcessor())
728         .failsToCompile();
729     assertAbout(javaSources())
730         .that(ImmutableList.of(rootModule, component))
731         .processedWith(
732             new ComponentProcessor(),
733             new GeneratingProcessor(
734                 "test.GeneratedModule",
735                 "package test;",
736                 "",
737                 "import dagger.Module;",
738                 "",
739                 "@Module",
740                 "final class GeneratedModule {}"))
741         .compilesWithoutError();
742   }
743 
744   @Test
generatedModuleInSubcomponent()745   public void generatedModuleInSubcomponent() {
746     JavaFileObject subcomponent =
747         JavaFileObjects.forSourceLines(
748             "test.ChildComponent",
749             "package test;",
750             "",
751             "import dagger.Subcomponent;",
752             "",
753             "@Subcomponent(modules = GeneratedModule.class)",
754             "interface ChildComponent {}");
755     JavaFileObject component =
756         JavaFileObjects.forSourceLines(
757             "test.TestComponent",
758             "package test;",
759             "",
760             "import dagger.Component;",
761             "",
762             "@Component",
763             "interface TestComponent {",
764             "  ChildComponent childComponent();",
765             "}");
766     assertAbout(javaSources())
767         .that(ImmutableList.of(subcomponent, component))
768         .processedWith(new ComponentProcessor())
769         .failsToCompile();
770     assertAbout(javaSources())
771         .that(ImmutableList.of(subcomponent, component))
772         .processedWith(
773             new ComponentProcessor(),
774             new GeneratingProcessor(
775                 "test.GeneratedModule",
776                 "package test;",
777                 "",
778                 "import dagger.Module;",
779                 "",
780                 "@Module",
781                 "final class GeneratedModule {}"))
782         .compilesWithoutError();
783   }
784 
785   @Test
subcomponentOmitsInheritedBindings()786   public void subcomponentOmitsInheritedBindings() {
787     JavaFileObject parent =
788         JavaFileObjects.forSourceLines(
789             "test.Parent",
790             "package test;",
791             "",
792             "import dagger.Component;",
793             "",
794             "@Component(modules = ParentModule.class)",
795             "interface Parent {",
796             "  Child child();",
797             "}");
798     JavaFileObject parentModule =
799         JavaFileObjects.forSourceLines(
800             "test.ParentModule",
801             "package test;",
802             "",
803             "import dagger.mapkeys.StringKey;",
804             "import dagger.Module;",
805             "import dagger.Provides;",
806             "",
807             "import static dagger.Provides.Type.SET;",
808             "import static dagger.Provides.Type.MAP;",
809             "",
810             "@Module",
811             "class ParentModule {",
812             "  @Provides(type = SET) static Object parentObject() {",
813             "    return \"parent object\";",
814             "  }",
815             "",
816             "  @Provides(type = MAP) @StringKey(\"parent key\") Object parentKeyObject() {",
817             "    return \"parent value\";",
818             "  }",
819             "}");
820     JavaFileObject child =
821         JavaFileObjects.forSourceLines(
822             "test.Child",
823             "package test;",
824             "",
825             "import dagger.Subcomponent;",
826             "import java.util.Map;",
827             "import java.util.Set;",
828             "",
829             "@Subcomponent",
830             "interface Child {",
831             "  Set<Object> objectSet();",
832             "  Map<String, Object> objectMap();",
833             "}");
834     JavaFileObject expected =
835         JavaFileObjects.forSourceLines(
836             "test.DaggerParent",
837             "package test;",
838             "",
839             "import dagger.internal.MapFactory;",
840             "import dagger.internal.MapProviderFactory;",
841             "import dagger.internal.SetFactory;",
842             "import java.util.Map;",
843             "import java.util.Set;",
844             "import javax.annotation.Generated;",
845             "import javax.inject.Provider;",
846             "",
847             "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
848             "public final class DaggerParent implements Parent {",
849             "  private Provider<Set<Object>> setOfObjectContribution1Provider;",
850             "  private Provider<Set<Object>> setOfObjectProvider;",
851             "  private Provider<Object> mapOfStringAndProviderOfObjectContribution1;",
852             "  private Provider<Map<String, Provider<Object>>>",
853             "      mapOfStringAndProviderOfObjectProvider;",
854             "",
855             "  private DaggerParent(Builder builder) {",
856             "    assert builder != null;",
857             "    initialize(builder);",
858             "  }",
859             "",
860             "  public static Builder builder() {",
861             "    return new Builder();",
862             "  }",
863             "",
864             "  public static Parent create() {",
865             "    return builder().build();",
866             "  }",
867             "",
868             "  @SuppressWarnings(\"unchecked\")",
869             "  private void initialize(final Builder builder) {",
870             "    this.setOfObjectContribution1Provider =",
871             "        ParentModule_ParentObjectFactory.create();",
872             "    this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider);",
873             "    this.mapOfStringAndProviderOfObjectContribution1 =",
874             "        ParentModule_ParentKeyObjectFactory.create(builder.parentModule);",
875             "    this.mapOfStringAndProviderOfObjectProvider =",
876             "        MapProviderFactory.<String, Object>builder(1)",
877             "            .put(\"parent key\", mapOfStringAndProviderOfObjectContribution1)",
878             "            .build();",
879             "  }",
880             "",
881             "  @Override",
882             "  public Child child() {",
883             "    return new ChildImpl();",
884             "  }",
885             "",
886             "  public static final class Builder {",
887             "    private ParentModule parentModule;",
888             "",
889             "    private Builder() {}",
890             "",
891             "    public Parent build() {",
892             "      if (parentModule == null) {",
893             "        this.parentModule = new ParentModule();",
894             "      }",
895             "      return new DaggerParent(this);",
896             "    }",
897             "",
898             "    public Builder parentModule(ParentModule parentModule) {",
899             "      if (parentModule == null) {",
900             "        throw new NullPointerException();",
901             "      }",
902             "      this.parentModule = parentModule;",
903             "      return this;",
904             "    }",
905             "  }",
906             "",
907             "  private final class ChildImpl implements Child {",
908             "    private Provider<Map<String, Object>> mapOfStringAndObjectProvider;",
909             "",
910             "    private ChildImpl() {",
911             "      initialize();",
912             "    }",
913             "",
914             "    @SuppressWarnings(\"unchecked\")",
915             "    private void initialize() {",
916             "      this.mapOfStringAndObjectProvider = MapFactory.create(",
917             "          DaggerParent.this.mapOfStringAndProviderOfObjectProvider);",
918             "    }",
919             "",
920             "    @Override",
921             "    public Set<Object> objectSet() {",
922             "      return DaggerParent.this.setOfObjectProvider.get();",
923             "    }",
924             "",
925             "    @Override",
926             "    public Map<String, Object> objectMap() {",
927             "      return mapOfStringAndObjectProvider.get();",
928             "    }",
929             "  }",
930             "}");
931     assertAbout(javaSources())
932         .that(ImmutableList.of(parent, parentModule, child))
933         .processedWith(new ComponentProcessor())
934         .compilesWithoutError()
935         .and()
936         .generatesSources(expected);
937   }
938 
testDefaultPackage()939   @Test public void testDefaultPackage() {
940     JavaFileObject aClass = JavaFileObjects.forSourceLines("AClass", "class AClass {}");
941     JavaFileObject bClass = JavaFileObjects.forSourceLines("BClass",
942         "import javax.inject.Inject;",
943         "",
944         "class BClass {",
945         "  @Inject BClass(AClass a) {}",
946         "}");
947     JavaFileObject aModule = JavaFileObjects.forSourceLines("AModule",
948         "import dagger.Module;",
949         "import dagger.Provides;",
950         "",
951         "@Module class AModule {",
952         "  @Provides AClass aClass() {",
953         "    return new AClass();",
954         "  }",
955         "}");
956     JavaFileObject component = JavaFileObjects.forSourceLines("SomeComponent",
957         "import dagger.Component;",
958         "",
959         "@Component(modules = AModule.class)",
960         "interface SomeComponent {",
961         "  BClass bClass();",
962         "}");
963     assertAbout(javaSources())
964         .that(ImmutableList.of(aModule, aClass, bClass, component))
965         .processedWith(new ComponentProcessor())
966         .compilesWithoutError();
967   }
968 
setBindings()969   @Test public void setBindings() {
970     JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule",
971         "package test;",
972         "",
973         "import static dagger.Provides.Type.SET_VALUES;",
974         "",
975         "import dagger.Module;",
976         "import dagger.Provides;",
977         "import java.util.Collections;",
978         "import java.util.Set;",
979         "",
980         "@Module",
981         "final class EmptySetModule {",
982         "  @Provides(type = SET_VALUES) Set<String> emptySet() { return Collections.emptySet(); }",
983         "}");
984     JavaFileObject setModuleFile = JavaFileObjects.forSourceLines("test.SetModule",
985         "package test;",
986         "",
987         "import static dagger.Provides.Type.SET;",
988         "",
989         "import dagger.Module;",
990         "import dagger.Provides;",
991         "",
992         "@Module",
993         "final class SetModule {",
994         "  @Provides(type = SET) String string() { return \"\"; }",
995         "}");
996     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
997         "package test;",
998         "",
999         "import dagger.Component;",
1000         "import java.util.Set;",
1001         "",
1002         "import javax.inject.Provider;",
1003         "",
1004         "@Component(modules = {EmptySetModule.class, SetModule.class})",
1005         "interface TestComponent {",
1006         "  Set<String> strings();",
1007         "}");
1008     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1009         "test.DaggerTestComponent",
1010         "package test;",
1011         "",
1012         "import dagger.internal.SetFactory;",
1013         "import java.util.Set;",
1014         "import javax.annotation.Generated;",
1015         "import javax.inject.Provider;",
1016         "",
1017         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1018         "public final class DaggerTestComponent implements TestComponent {",
1019         "  private Provider<Set<String>> setOfStringContribution1Provider;",
1020         "  private Provider<Set<String>> setOfStringContribution2Provider;",
1021         "  private Provider<Set<String>> setOfStringProvider;",
1022         "",
1023         "  private DaggerTestComponent(Builder builder) {",
1024         "    assert builder != null;",
1025         "    initialize(builder);",
1026         "  }",
1027         "",
1028         "  public static Builder builder() {",
1029         "    return new Builder();",
1030         "  }",
1031         "",
1032         "  public static TestComponent create() {",
1033         "    return builder().build();",
1034         "  }",
1035         "",
1036         "  @SuppressWarnings(\"unchecked\")",
1037         "  private void initialize(final Builder builder) {",
1038         "    this.setOfStringContribution1Provider =",
1039         "        EmptySetModule_EmptySetFactory.create(builder.emptySetModule);",
1040         "    this.setOfStringContribution2Provider =",
1041         "        SetModule_StringFactory.create(builder.setModule);",
1042         "    this.setOfStringProvider = SetFactory.create(",
1043         "        setOfStringContribution1Provider, setOfStringContribution2Provider);",
1044         "  }",
1045         "",
1046         "  @Override",
1047         "  public Set<String> strings() {",
1048         "    return setOfStringProvider.get();",
1049         "  }",
1050         "",
1051         "  public static final class Builder {",
1052         "    private EmptySetModule emptySetModule;",
1053         "    private SetModule setModule;",
1054         "",
1055         "    private Builder() {",
1056         "    }",
1057         "",
1058         "    public TestComponent build() {",
1059         "      if (emptySetModule == null) {",
1060         "        this.emptySetModule = new EmptySetModule();",
1061         "      }",
1062         "      if (setModule == null) {",
1063         "        this.setModule = new SetModule();",
1064         "      }",
1065         "      return new DaggerTestComponent(this);",
1066         "    }",
1067         "",
1068         "    public Builder emptySetModule(EmptySetModule emptySetModule) {",
1069         "      if (emptySetModule == null) {",
1070         "        throw new NullPointerException();",
1071         "      }",
1072         "      this.emptySetModule = emptySetModule;",
1073         "      return this;",
1074         "    }",
1075         "",
1076         "    public Builder setModule(SetModule setModule) {",
1077         "      if (setModule == null) {",
1078         "        throw new NullPointerException();",
1079         "      }",
1080         "      this.setModule = setModule;",
1081         "      return this;",
1082         "    }",
1083         "  }",
1084         "}");
1085     assertAbout(javaSources())
1086         .that(ImmutableList.of(emptySetModuleFile, setModuleFile, componentFile))
1087         .processedWith(new ComponentProcessor())
1088         .compilesWithoutError()
1089         .and().generatesSources(generatedComponent);
1090   }
1091 
membersInjection()1092   @Test public void membersInjection() {
1093     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
1094         "package test;",
1095         "",
1096         "import javax.inject.Inject;",
1097         "",
1098         "final class SomeInjectableType {",
1099         "  @Inject SomeInjectableType() {}",
1100         "}");
1101     JavaFileObject injectedTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectedType",
1102         "package test;",
1103         "",
1104         "import javax.inject.Inject;",
1105         "",
1106         "final class SomeInjectedType {",
1107         "  @Inject SomeInjectableType injectedField;",
1108         "  SomeInjectedType() {}",
1109         "}");
1110     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
1111         "package test;",
1112         "",
1113         "import dagger.Component;",
1114         "import dagger.Lazy;",
1115         "",
1116         "import javax.inject.Provider;",
1117         "",
1118         "@Component",
1119         "interface SimpleComponent {",
1120         "  void inject(SomeInjectedType instance);",
1121         "  SomeInjectedType injectAndReturn(SomeInjectedType instance);",
1122         "}");
1123     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1124         "test.DaggerSimpleComponent",
1125         "package test;",
1126         "",
1127         "import dagger.MembersInjector;",
1128         "import javax.annotation.Generated;",
1129         "",
1130         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1131         "public final class DaggerSimpleComponent implements SimpleComponent {",
1132         "  private MembersInjector<SomeInjectedType> someInjectedTypeMembersInjector;",
1133         "",
1134         "  private DaggerSimpleComponent(Builder builder) {",
1135         "    assert builder != null;",
1136         "    initialize(builder);",
1137         "  }",
1138         "",
1139         "  public static Builder builder() {",
1140         "    return new Builder();",
1141         "  }",
1142         "",
1143         "  public static SimpleComponent create() {",
1144         "    return builder().build();",
1145         "  }",
1146         "",
1147         "  @SuppressWarnings(\"unchecked\")",
1148         "  private void initialize(final Builder builder) {",
1149         "    this.someInjectedTypeMembersInjector =",
1150         "        SomeInjectedType_MembersInjector.create(SomeInjectableType_Factory.create());",
1151         "  }",
1152         "",
1153         "  @Override",
1154         "  public void inject(SomeInjectedType instance) {",
1155         "    someInjectedTypeMembersInjector.injectMembers(instance);",
1156         "  }",
1157         "",
1158         "  @Override",
1159         "  public SomeInjectedType injectAndReturn(SomeInjectedType instance) {",
1160         "    someInjectedTypeMembersInjector.injectMembers(instance);",
1161         "    return instance;",
1162         "  }",
1163         "",
1164         "  public static final class Builder {",
1165         "    private Builder() {",
1166         "    }",
1167         "",
1168         "    public SimpleComponent build() {",
1169         "      return new DaggerSimpleComponent(this);",
1170         "    }",
1171         "  }",
1172         "}");
1173     assertAbout(javaSources())
1174         .that(ImmutableList.of(injectableTypeFile, injectedTypeFile, componentFile))
1175         .processedWith(new ComponentProcessor())
1176         .compilesWithoutError()
1177         .and().generatesSources(generatedComponent);
1178   }
1179 
componentInjection()1180   @Test public void componentInjection() {
1181     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
1182         "package test;",
1183         "",
1184         "import javax.inject.Inject;",
1185         "",
1186         "final class SomeInjectableType {",
1187         "  @Inject SomeInjectableType(SimpleComponent component) {}",
1188         "}");
1189     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
1190         "package test;",
1191         "",
1192         "import dagger.Component;",
1193         "import dagger.Lazy;",
1194         "",
1195         "import javax.inject.Provider;",
1196         "",
1197         "@Component",
1198         "interface SimpleComponent {",
1199         "  SomeInjectableType someInjectableType();",
1200         "}");
1201     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1202         "test.DaggerSimpleComponent",
1203         "package test;",
1204         "",
1205         "import dagger.internal.InstanceFactory;",
1206         "import javax.annotation.Generated;",
1207         "import javax.inject.Provider;",
1208         "",
1209         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1210         "public final class DaggerSimpleComponent implements SimpleComponent {",
1211         "  private Provider<SimpleComponent> simpleComponentProvider;",
1212         "  private Provider<SomeInjectableType> someInjectableTypeProvider;",
1213         "",
1214         "  private DaggerSimpleComponent(Builder builder) {",
1215         "    assert builder != null;",
1216         "    initialize(builder);",
1217         "  }",
1218         "",
1219         "  public static Builder builder() {",
1220         "    return new Builder();",
1221         "  }",
1222         "",
1223         "  public static SimpleComponent create() {",
1224         "    return builder().build();",
1225         "  }",
1226         "",
1227         "  @SuppressWarnings(\"unchecked\")",
1228         "  private void initialize(final Builder builder) {",
1229         "    this.simpleComponentProvider = InstanceFactory.<SimpleComponent>create(this);",
1230         "    this.someInjectableTypeProvider =",
1231         "        SomeInjectableType_Factory.create(simpleComponentProvider);",
1232         "  }",
1233         "",
1234         "  @Override",
1235         "  public SomeInjectableType someInjectableType() {",
1236         "    return someInjectableTypeProvider.get();",
1237         "  }",
1238         "",
1239         "  public static final class Builder {",
1240         "    private Builder() {",
1241         "    }",
1242         "",
1243         "    public SimpleComponent build() {",
1244         "      return new DaggerSimpleComponent(this);",
1245         "    }",
1246         "  }",
1247         "}");
1248     assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
1249         .processedWith(new ComponentProcessor())
1250         .compilesWithoutError()
1251         .and().generatesSources(generatedComponent);
1252   }
1253 
membersInjectionInsideProvision()1254   @Test public void membersInjectionInsideProvision() {
1255     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
1256         "package test;",
1257         "",
1258         "import javax.inject.Inject;",
1259         "",
1260         "final class SomeInjectableType {",
1261         "  @Inject SomeInjectableType() {}",
1262         "}");
1263     JavaFileObject injectedTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectedType",
1264         "package test;",
1265         "",
1266         "import javax.inject.Inject;",
1267         "",
1268         "final class SomeInjectedType {",
1269         "  @Inject SomeInjectableType injectedField;",
1270         "  @Inject SomeInjectedType() {}",
1271         "}");
1272     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
1273         "package test;",
1274         "",
1275         "import dagger.Component;",
1276         "",
1277         "@Component",
1278         "interface SimpleComponent {",
1279         "  SomeInjectedType createAndInject();",
1280         "}");
1281     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1282         "test.DaggerSimpleComponent",
1283         "package test;",
1284         "",
1285         "import dagger.MembersInjector;",
1286         "import javax.annotation.Generated;",
1287         "import javax.inject.Provider;",
1288         "",
1289         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1290         "public final class DaggerSimpleComponent implements SimpleComponent {",
1291         "  private MembersInjector<SomeInjectedType> someInjectedTypeMembersInjector;",
1292         "  private Provider<SomeInjectedType> someInjectedTypeProvider;",
1293         "",
1294         "  private DaggerSimpleComponent(Builder builder) {",
1295         "    assert builder != null;",
1296         "    initialize(builder);",
1297         "  }",
1298         "",
1299         "  public static Builder builder() {",
1300         "    return new Builder();",
1301         "  }",
1302         "",
1303         "  public static SimpleComponent create() {",
1304         "    return builder().build();",
1305         "  }",
1306         "",
1307         "  @SuppressWarnings(\"unchecked\")",
1308         "  private void initialize(final Builder builder) {",
1309         "    this.someInjectedTypeMembersInjector =",
1310         "        SomeInjectedType_MembersInjector.create(SomeInjectableType_Factory.create());",
1311         "    this.someInjectedTypeProvider =",
1312         "        SomeInjectedType_Factory.create(someInjectedTypeMembersInjector);",
1313         "  }",
1314         "",
1315         "  @Override",
1316         "  public SomeInjectedType createAndInject() {",
1317         "    return someInjectedTypeProvider.get();",
1318         "  }",
1319         "",
1320         "  public static final class Builder {",
1321         "    private Builder() {",
1322         "    }",
1323         "",
1324         "    public SimpleComponent build() {",
1325         "      return new DaggerSimpleComponent(this);",
1326         "    }",
1327         "  }",
1328         "}");
1329     assertAbout(javaSources())
1330         .that(ImmutableList.of(injectableTypeFile, injectedTypeFile, componentFile))
1331         .processedWith(new ComponentProcessor())
1332         .compilesWithoutError()
1333         .and().generatesSources(generatedComponent);
1334   }
1335 
injectionWithGenericBaseClass()1336   @Test public void injectionWithGenericBaseClass() {
1337     JavaFileObject genericType = JavaFileObjects.forSourceLines("test.AbstractGenericType",
1338         "package test;",
1339         "",
1340         "abstract class AbstractGenericType<T> {",
1341         "}");
1342     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
1343         "package test;",
1344         "",
1345         "import javax.inject.Inject;",
1346         "",
1347         "final class SomeInjectableType extends AbstractGenericType<String> {",
1348         "  @Inject SomeInjectableType() {}",
1349         "}");
1350     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
1351         "package test;",
1352         "",
1353         "import dagger.Component;",
1354         "",
1355         "@Component",
1356         "interface SimpleComponent {",
1357         "  SomeInjectableType someInjectableType();",
1358         "}");
1359     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1360         "test.DaggerSimpleComponent",
1361         "package test;",
1362         "",
1363         "import dagger.MembersInjector;",
1364         "import dagger.internal.MembersInjectors;",
1365         "import javax.annotation.Generated;",
1366         "import javax.inject.Provider;",
1367         "",
1368         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1369         "public final class DaggerSimpleComponent implements SimpleComponent {",
1370         "  private Provider<SomeInjectableType> someInjectableTypeProvider;",
1371         "",
1372         "  private DaggerSimpleComponent(Builder builder) {",
1373         "    assert builder != null;",
1374         "    initialize(builder);",
1375         "  }",
1376         "",
1377         "  public static Builder builder() {",
1378         "    return new Builder();",
1379         "  }",
1380         "",
1381         "  public static SimpleComponent create() {",
1382         "    return builder().build();",
1383         "  }",
1384         "",
1385         "  @SuppressWarnings(\"unchecked\")",
1386         "  private void initialize(final Builder builder) {",
1387         "    this.someInjectableTypeProvider =",
1388         "        SomeInjectableType_Factory.create((MembersInjector) MembersInjectors.noOp());",
1389         "  }",
1390         "",
1391         "  @Override",
1392         "  public SomeInjectableType someInjectableType() {",
1393         "    return someInjectableTypeProvider.get();",
1394         "  }",
1395         "",
1396         "  public static final class Builder {",
1397         "    private Builder() {",
1398         "    }",
1399         "",
1400         "    public SimpleComponent build() {",
1401         "      return new DaggerSimpleComponent(this);",
1402         "    }",
1403         "  }",
1404         "}");
1405     assertAbout(javaSources())
1406         .that(ImmutableList.of(genericType, injectableTypeFile, componentFile))
1407         .processedWith(new ComponentProcessor())
1408         .compilesWithoutError()
1409         .and().generatesSources(generatedComponent);
1410   }
1411 
componentDependency()1412   @Test public void componentDependency() {
1413     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
1414         "package test;",
1415         "",
1416         "import javax.inject.Inject;",
1417         "",
1418         "final class A {",
1419         "  @Inject A() {}",
1420         "}");
1421     JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
1422         "package test;",
1423         "",
1424         "import javax.inject.Inject;",
1425         "",
1426         "final class B {",
1427         "  @Inject B(A a) {}",
1428         "}");
1429     JavaFileObject aComponentFile = JavaFileObjects.forSourceLines("test.AComponent",
1430         "package test;",
1431         "",
1432         "import dagger.Component;",
1433         "import dagger.Lazy;",
1434         "",
1435         "import javax.inject.Provider;",
1436         "",
1437         "@Component",
1438         "interface AComponent {",
1439         "  A a();",
1440         "}");
1441     JavaFileObject bComponentFile = JavaFileObjects.forSourceLines("test.AComponent",
1442         "package test;",
1443         "",
1444         "import dagger.Component;",
1445         "import dagger.Lazy;",
1446         "",
1447         "import javax.inject.Provider;",
1448         "",
1449         "@Component(dependencies = AComponent.class)",
1450         "interface BComponent {",
1451         "  B b();",
1452         "}");
1453     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1454         "test.DaggerBComponent",
1455         "package test;",
1456         "",
1457         "import dagger.internal.Factory;",
1458         "import javax.annotation.Generated;",
1459         "import javax.inject.Provider;",
1460         "",
1461         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1462         "public final class DaggerBComponent implements BComponent {",
1463         "  private Provider<A> aProvider;",
1464         "  private Provider<B> bProvider;",
1465         "",
1466         "  private DaggerBComponent(Builder builder) {",
1467         "    assert builder != null;",
1468         "    initialize(builder);",
1469         "  }",
1470         "",
1471         "  public static Builder builder() {",
1472         "    return new Builder();",
1473         "  }",
1474         "",
1475         "  @SuppressWarnings(\"unchecked\")",
1476         "  private void initialize(final Builder builder) {",
1477         "    this.aProvider = new Factory<A>() {",
1478         "      private final AComponent aComponent = builder.aComponent;",
1479         "      @Override public A get() {",
1480         "        A provided = aComponent.a();",
1481         "        if (provided == null) {",
1482         "          throw new NullPointerException(" + NPE_LITERAL + ");",
1483         "        }",
1484         "        return provided;",
1485         "      }",
1486         "    };",
1487         "    this.bProvider = B_Factory.create(aProvider);",
1488         "  }",
1489         "",
1490         "  @Override",
1491         "  public B b() {",
1492         "    return bProvider.get();",
1493         "  }",
1494         "",
1495         "  public static final class Builder {",
1496         "    private AComponent aComponent;",
1497         "",
1498         "    private Builder() {",
1499         "    }",
1500         "",
1501         "    public BComponent build() {",
1502         "      if (aComponent == null) {",
1503         "        throw new IllegalStateException(AComponent.class.getCanonicalName()",
1504         "            + \" must be set\");",
1505         "      }",
1506         "      return new DaggerBComponent(this);",
1507         "    }",
1508         "",
1509         "    public Builder aComponent(AComponent aComponent) {",
1510         "      if (aComponent == null) {",
1511         "        throw new NullPointerException();",
1512         "      }",
1513         "      this.aComponent = aComponent;",
1514         "      return this;",
1515         "    }",
1516         "  }",
1517         "}");
1518     assertAbout(javaSources())
1519         .that(ImmutableList.of(aFile, bFile, aComponentFile, bComponentFile))
1520         .processedWith(new ComponentProcessor())
1521         .compilesWithoutError()
1522         .and().generatesSources(generatedComponent);
1523   }
1524 
moduleNameCollision()1525   @Test public void moduleNameCollision() {
1526     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
1527         "package test;",
1528         "",
1529         "public final class A {}");
1530     JavaFileObject otherAFile = JavaFileObjects.forSourceLines("other.test.A",
1531         "package other.test;",
1532         "",
1533         "public final class A {}");
1534 
1535     JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
1536         "package test;",
1537         "",
1538         "import dagger.Module;",
1539         "import dagger.Provides;",
1540         "",
1541         "@Module",
1542         "public final class TestModule {",
1543         "  @Provides A a() { return null; }",
1544         "}");
1545     JavaFileObject otherModuleFile = JavaFileObjects.forSourceLines("other.test.TestModule",
1546         "package other.test;",
1547         "",
1548         "import dagger.Module;",
1549         "import dagger.Provides;",
1550         "",
1551         "@Module",
1552         "public final class TestModule {",
1553         "  @Provides A a() { return null; }",
1554         "}");
1555 
1556     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
1557         "package test;",
1558         "",
1559         "import dagger.Component;",
1560         "",
1561         "import javax.inject.Provider;",
1562         "",
1563         "@Component(modules = {TestModule.class, other.test.TestModule.class})",
1564         "interface TestComponent {",
1565         "  A a();",
1566         "  other.test.A otherA();",
1567         "}");
1568     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1569         "test.DaggerTestComponent",
1570         "package test;",
1571         "",
1572         "import javax.annotation.Generated;",
1573         "import javax.inject.Provider;",
1574         "import other.test.A;",
1575         "import other.test.TestModule;",
1576         "import other.test.TestModule_AFactory;",
1577         "",
1578         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1579         "public final class DaggerTestComponent implements TestComponent {",
1580         "  private Provider<test.A> aProvider;",
1581         "  private Provider<A> aProvider1;",
1582         "",
1583         "  private DaggerTestComponent(Builder builder) {",
1584         "    assert builder != null;",
1585         "    initialize(builder);",
1586         "  }",
1587         "",
1588         "  public static Builder builder() {",
1589         "    return new Builder();",
1590         "  }",
1591         "",
1592         "  public static TestComponent create() {",
1593         "    return builder().build();",
1594         "  }",
1595         "",
1596         "  @SuppressWarnings(\"unchecked\")",
1597         "  private void initialize(final Builder builder) {",
1598         "    this.aProvider = test.TestModule_AFactory.create(builder.testModule);",
1599         "    this.aProvider1 = TestModule_AFactory.create(builder.testModule1);",
1600         "  }",
1601         "",
1602         "  @Override",
1603         "  public test.A a() {",
1604         "    return aProvider.get();",
1605         "  }",
1606         "",
1607         "  @Override",
1608         "  public A otherA() {",
1609         "    return aProvider1.get();",
1610         "  }",
1611         "",
1612         "  public static final class Builder {",
1613         "    private test.TestModule testModule;",
1614         "    private TestModule testModule1;",
1615         "",
1616         "    private Builder() {",
1617         "    }",
1618         "",
1619         "    public TestComponent build() {",
1620         "      if (testModule == null) {",
1621         "        this.testModule = new test.TestModule();",
1622         "      }",
1623         "      if (testModule1 == null) {",
1624         "        this.testModule1 = new TestModule();",
1625         "      }",
1626         "      return new DaggerTestComponent(this);",
1627         "    }",
1628         "",
1629         "    public Builder testModule(test.TestModule testModule) {",
1630         "      if (testModule == null) {",
1631         "        throw new NullPointerException();",
1632         "      }",
1633         "      this.testModule = testModule;",
1634         "      return this;",
1635         "    }",
1636         "",
1637         "    public Builder testModule(TestModule testModule) {",
1638         "      if (testModule == null) {",
1639         "        throw new NullPointerException();",
1640         "      }",
1641         "      this.testModule1 = testModule;",
1642         "      return this;",
1643         "    }",
1644         "  }",
1645         "}");
1646     assertAbout(javaSources())
1647         .that(ImmutableList.of(aFile, otherAFile, moduleFile, otherModuleFile, componentFile))
1648         .processedWith(new ComponentProcessor())
1649         .compilesWithoutError()
1650         .and().generatesSources(generatedComponent);
1651   }
1652 
resolutionOrder()1653   @Test public void resolutionOrder() {
1654     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
1655         "package test;",
1656         "",
1657         "import javax.inject.Inject;",
1658         "",
1659         "final class A {",
1660         "  @Inject A(B b) {}",
1661         "}");
1662     JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
1663         "package test;",
1664         "",
1665         "import javax.inject.Inject;",
1666         "",
1667         "final class B {",
1668         "  @Inject B(C c) {}",
1669         "}");
1670     JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
1671         "package test;",
1672         "",
1673         "import javax.inject.Inject;",
1674         "",
1675         "final class C {",
1676         "  @Inject C() {}",
1677         "}");
1678     JavaFileObject xFile = JavaFileObjects.forSourceLines("test.X",
1679         "package test;",
1680         "",
1681         "import javax.inject.Inject;",
1682         "",
1683         "final class X {",
1684         "  @Inject X(C c) {}",
1685         "}");
1686 
1687     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
1688         "package test;",
1689         "",
1690         "import dagger.Component;",
1691         "",
1692         "import javax.inject.Provider;",
1693         "",
1694         "@Component",
1695         "interface TestComponent {",
1696         "  A a();",
1697         "  C c();",
1698         "  X x();",
1699         "}");
1700     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1701         "test.DaggerTestComponent",
1702         "package test;",
1703         "",
1704         "import javax.annotation.Generated;",
1705         "import javax.inject.Provider;",
1706         "",
1707         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1708         "public final class DaggerTestComponent implements TestComponent {",
1709         "  private Provider<B> bProvider;",
1710         "  private Provider<A> aProvider;",
1711         "  private Provider<X> xProvider;",
1712         "",
1713         "  private DaggerTestComponent(Builder builder) {",
1714         "    assert builder != null;",
1715         "    initialize(builder);",
1716         "  }",
1717         "",
1718         "  public static Builder builder() {",
1719         "    return new Builder();",
1720         "  }",
1721         "",
1722         "  public static TestComponent create() {",
1723         "    return builder().build();",
1724         "  }",
1725         "",
1726         "  @SuppressWarnings(\"unchecked\")",
1727         "  private void initialize(final Builder builder) {",
1728         "    this.bProvider = B_Factory.create(C_Factory.create());",
1729         "    this.aProvider = A_Factory.create(bProvider);",
1730         "    this.xProvider = X_Factory.create(C_Factory.create());",
1731         "  }",
1732         "",
1733         "  @Override",
1734         "  public A a() {",
1735         "    return aProvider.get();",
1736         "  }",
1737         "",
1738         "  @Override",
1739         "  public C c() {",
1740         "    return C_Factory.create().get();",
1741         "  }",
1742         "",
1743         "  @Override",
1744         "  public X x() {",
1745         "    return xProvider.get();",
1746         "  }",
1747         "",
1748         "  public static final class Builder {",
1749         "    private Builder() {",
1750         "    }",
1751         "",
1752         "    public TestComponent build() {",
1753         "      return new DaggerTestComponent(this);",
1754         "    }",
1755         "  }",
1756         "}");
1757     assertAbout(javaSources())
1758         .that(ImmutableList.of(aFile, bFile, cFile, xFile, componentFile))
1759         .processedWith(new ComponentProcessor())
1760         .compilesWithoutError()
1761         .and().generatesSources(generatedComponent);
1762   }
1763 
simpleComponent_redundantComponentMethod()1764   @Test public void simpleComponent_redundantComponentMethod() {
1765     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
1766         "package test;",
1767         "",
1768         "import javax.inject.Inject;",
1769         "",
1770         "final class SomeInjectableType {",
1771         "  @Inject SomeInjectableType() {}",
1772         "}");
1773     JavaFileObject componentSupertypeAFile = JavaFileObjects.forSourceLines("test.SupertypeA",
1774         "package test;",
1775         "",
1776         "import dagger.Component;",
1777         "import dagger.Lazy;",
1778         "",
1779         "import javax.inject.Provider;",
1780         "",
1781         "@Component",
1782         "interface SupertypeA {",
1783         "  SomeInjectableType someInjectableType();",
1784         "}");
1785     JavaFileObject componentSupertypeBFile = JavaFileObjects.forSourceLines("test.SupertypeB",
1786         "package test;",
1787         "",
1788         "import dagger.Component;",
1789         "import dagger.Lazy;",
1790         "",
1791         "import javax.inject.Provider;",
1792         "",
1793         "@Component",
1794         "interface SupertypeB {",
1795         "  SomeInjectableType someInjectableType();",
1796         "}");
1797     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
1798         "package test;",
1799         "",
1800         "import dagger.Component;",
1801         "import dagger.Lazy;",
1802         "",
1803         "import javax.inject.Provider;",
1804         "",
1805         "@Component",
1806         "interface SimpleComponent extends SupertypeA, SupertypeB {",
1807         "}");
1808     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1809         "test.DaggerSimpleComponent",
1810         "package test;",
1811         "",
1812         "import javax.annotation.Generated;",
1813         "",
1814         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1815         "public final class DaggerSimpleComponent implements SimpleComponent {",
1816         "  private DaggerSimpleComponent(Builder builder) {",
1817         "    assert builder != null;",
1818         "    initialize(builder);",
1819         "  }",
1820         "",
1821         "  public static Builder builder() {",
1822         "    return new Builder();",
1823         "  }",
1824         "",
1825         "  public static SimpleComponent create() {",
1826         "    return builder().build();",
1827         "  }",
1828         "",
1829         "  @SuppressWarnings(\"unchecked\")",
1830         "  private void initialize(final Builder builder) {}",
1831         "",
1832         "  @Override",
1833         "  public SomeInjectableType someInjectableType() {",
1834         "    return SomeInjectableType_Factory.create().get();",
1835         "  }",
1836         "",
1837         "  public static final class Builder {",
1838         "    private Builder() {",
1839         "    }",
1840         "",
1841         "    public SimpleComponent build() {",
1842         "      return new DaggerSimpleComponent(this);",
1843         "    }",
1844         "  }",
1845         "}");
1846     assertAbout(javaSources()).that(ImmutableList.of(
1847             injectableTypeFile, componentSupertypeAFile, componentSupertypeBFile, componentFile))
1848         .processedWith(new ComponentProcessor())
1849         .compilesWithoutError()
1850         .and().generatesSources(generatedComponent);
1851   }
1852 
simpleComponent_inheritedComponentMethodDep()1853   @Test public void simpleComponent_inheritedComponentMethodDep() {
1854     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
1855         "package test;",
1856         "",
1857         "import javax.inject.Inject;",
1858         "",
1859         "final class SomeInjectableType {",
1860         "  @Inject SomeInjectableType() {}",
1861         "}");
1862     JavaFileObject componentSupertype = JavaFileObjects.forSourceLines("test.Supertype",
1863         "package test;",
1864         "",
1865         "import dagger.Component;",
1866         "import dagger.Lazy;",
1867         "",
1868         "import javax.inject.Provider;",
1869         "",
1870         "@Component",
1871         "interface Supertype {",
1872         "  SomeInjectableType someInjectableType();",
1873         "}");
1874     JavaFileObject depComponentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
1875         "package test;",
1876         "",
1877         "import dagger.Component;",
1878         "import dagger.Lazy;",
1879         "",
1880         "import javax.inject.Provider;",
1881         "",
1882         "@Component",
1883         "interface SimpleComponent extends Supertype {",
1884         "}");
1885     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ComponentWithDep",
1886         "package test;",
1887         "",
1888         "import dagger.Component;",
1889         "import dagger.Lazy;",
1890         "",
1891         "import javax.inject.Provider;",
1892         "",
1893         "@Component(dependencies = SimpleComponent.class)",
1894         "interface ComponentWithDep {",
1895         "  SomeInjectableType someInjectableType();",
1896         "}");
1897     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
1898         "test.DaggerSimpleComponent",
1899         "package test;",
1900         "",
1901         "import javax.annotation.Generated;",
1902         "",
1903         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
1904         "public final class DaggerSimpleComponent implements SimpleComponent {",
1905         "  private DaggerSimpleComponent(Builder builder) {",
1906         "    assert builder != null;",
1907         "    initialize(builder);",
1908         "  }",
1909         "",
1910         "  public static Builder builder() {",
1911         "    return new Builder();",
1912         "  }",
1913         "",
1914         "  public static SimpleComponent create() {",
1915         "    return builder().build();",
1916         "  }",
1917         "",
1918         "  @SuppressWarnings(\"unchecked\")",
1919         "  private void initialize(final Builder builder) {}",
1920         "",
1921         "  @Override",
1922         "  public SomeInjectableType someInjectableType() {",
1923         "    return SomeInjectableType_Factory.create().get();",
1924         "  }",
1925         "",
1926         "  public static final class Builder {",
1927         "    private Builder() {",
1928         "    }",
1929         "",
1930         "    public SimpleComponent build() {",
1931         "      return new DaggerSimpleComponent(this);",
1932         "    }",
1933         "  }",
1934         "}");
1935     assertAbout(javaSources()).that(ImmutableList.of(
1936             injectableTypeFile, componentSupertype, depComponentFile, componentFile))
1937         .processedWith(new ComponentProcessor())
1938         .compilesWithoutError()
1939         .and().generatesSources(generatedComponent);
1940   }
1941 
wildcardGenericsRequiresAtProvides()1942   @Test public void wildcardGenericsRequiresAtProvides() {
1943     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
1944         "package test;",
1945         "",
1946         "import javax.inject.Inject;",
1947         "",
1948         "final class A {",
1949         "  @Inject A() {}",
1950         "}");
1951     JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
1952         "package test;",
1953         "",
1954         "import javax.inject.Inject;",
1955         "import javax.inject.Provider;",
1956         "",
1957         "final class B<T> {",
1958         "  @Inject B(T t) {}",
1959         "}");
1960     JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
1961         "package test;",
1962         "",
1963         "import javax.inject.Inject;",
1964         "import javax.inject.Provider;",
1965         "",
1966         "final class C {",
1967         "  @Inject C(B<? extends A> bA) {}",
1968         "}");
1969     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
1970         "package test;",
1971         "",
1972         "import dagger.Component;",
1973         "import dagger.Lazy;",
1974         "",
1975         "import javax.inject.Provider;",
1976         "",
1977         "@Component",
1978         "interface SimpleComponent {",
1979         "  C c();",
1980         "}");
1981     assertAbout(javaSources()).that(ImmutableList.of(aFile, bFile, cFile, componentFile))
1982         .processedWith(new ComponentProcessor())
1983         .failsToCompile()
1984         .withErrorContaining(
1985             "test.B<? extends test.A> cannot be provided without an @Provides-annotated method");
1986   }
1987   @Test
componentImplicitlyDependsOnGeneratedType()1988   public void componentImplicitlyDependsOnGeneratedType() {
1989     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
1990         "package test;",
1991         "",
1992         "import javax.inject.Inject;",
1993         "",
1994         "final class SomeInjectableType {",
1995         "  @Inject SomeInjectableType(GeneratedType generatedType) {}",
1996         "}");
1997     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
1998         "package test;",
1999         "",
2000         "import dagger.Component;",
2001         "",
2002         "@Component",
2003         "interface SimpleComponent {",
2004         "  SomeInjectableType someInjectableType();",
2005         "}");
2006     assertAbout(javaSources())
2007         .that(ImmutableList.of(injectableTypeFile, componentFile))
2008         .processedWith(
2009             new ComponentProcessor(),
2010             new GeneratingProcessor(
2011                 "test.GeneratedType",
2012                 "package test;",
2013                 "",
2014                 "import javax.inject.Inject;",
2015                 "",
2016                 "final class GeneratedType {",
2017                 "  @Inject GeneratedType() {}",
2018                 "}"))
2019         .compilesWithoutError()
2020         .and()
2021         .generatesFileNamed(SOURCE_OUTPUT, "test", "DaggerSimpleComponent.java");
2022   }
2023   @Test
componentSupertypeDependsOnGeneratedType()2024   public void componentSupertypeDependsOnGeneratedType() {
2025     JavaFileObject componentFile =
2026         JavaFileObjects.forSourceLines(
2027             "test.SimpleComponent",
2028             "package test;",
2029             "",
2030             "import dagger.Component;",
2031             "",
2032             "@Component",
2033             "interface SimpleComponent extends SimpleComponentInterface {}");
2034     JavaFileObject interfaceFile =
2035         JavaFileObjects.forSourceLines(
2036             "test.SimpleComponentInterface",
2037             "package test;",
2038             "",
2039             "interface SimpleComponentInterface {",
2040             "  GeneratedType generatedType();",
2041             "}");
2042     assertAbout(javaSources())
2043         .that(ImmutableList.of(componentFile, interfaceFile))
2044         .processedWith(
2045             new ComponentProcessor(),
2046             new GeneratingProcessor(
2047                 "test.GeneratedType",
2048                 "package test;",
2049                 "",
2050                 "import javax.inject.Inject;",
2051                 "",
2052                 "final class GeneratedType {",
2053                 "  @Inject GeneratedType() {}",
2054                 "}"))
2055         .compilesWithoutError()
2056         .and()
2057         .generatesFileNamed(SOURCE_OUTPUT, "test", "DaggerSimpleComponent.java");
2058   }
2059 
2060   @Test
2061   @Ignore // modify this test as necessary while debugging for your situation.
2062   @SuppressWarnings("unused")
genericTestToLetMeDebugInEclipse()2063   public void genericTestToLetMeDebugInEclipse() {
2064     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
2065         "package test;",
2066         "",
2067          "import javax.inject.Inject;",
2068          "",
2069          "public final class A {",
2070          "  @Inject A() {}",
2071          "}");
2072      JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
2073          "package test;",
2074          "",
2075          "import javax.inject.Inject;",
2076          "import javax.inject.Provider;",
2077          "",
2078          "public class B<T> {",
2079          "  @Inject B() {}",
2080          "}");
2081      JavaFileObject dFile = JavaFileObjects.forSourceLines("test.sub.D",
2082          "package test.sub;",
2083          "",
2084          "import javax.inject.Inject;",
2085          "import javax.inject.Provider;",
2086          "import test.B;",
2087          "",
2088          "public class D {",
2089          "  @Inject D(B<A.InA> ba) {}",
2090          "}");
2091      JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
2092          "package test;",
2093          "",
2094          "import dagger.Component;",
2095          "import dagger.Lazy;",
2096          "",
2097          "import javax.inject.Provider;",
2098          "",
2099          "@Component",
2100          "interface SimpleComponent {",
2101          "  B<A> d();",
2102          "  Provider<B<A>> d2();",
2103          "}");
2104      JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
2105          "test.DaggerSimpleComponent",
2106          "package test;",
2107          "",
2108          "import javax.annotation.Generated;",
2109          "import javax.inject.Provider;",
2110          "",
2111          "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
2112          "public final class DaggerSimpleComponent implements SimpleComponent {",
2113          "  private Provider<D> dProvider;",
2114          "",
2115          "  private DaggerSimpleComponent(Builder builder) {",
2116          "    assert builder != null;",
2117          "    initialize(builder);",
2118          "  }",
2119          "",
2120          "  public static Builder builder() {",
2121          "    return new Builder();",
2122          "  }",
2123          "",
2124          "  public static SimpleComponent create() {",
2125          "    return builder().build();",
2126          "  }",
2127          "",
2128          "  @SuppressWarnings(\"unchecked\")",
2129          "  private void initialize(final Builder builder) {",
2130          "    this.dProvider = new D_Factory(B_Factory.INSTANCE);",
2131          "  }",
2132          "",
2133          "  @Override",
2134          "  public D d() {",
2135          "    return dProvider.get();",
2136          "  }",
2137          "",
2138          "  public static final class Builder {",
2139          "    private Builder() {",
2140          "    }",
2141          "",
2142          "    public SimpleComponent build() {",
2143          "      return new DaggerSimpleComponent(this);",
2144          "    }",
2145          "  }",
2146          "}");
2147      assertAbout(javaSources()).that(ImmutableList.of(aFile, bFile, componentFile))
2148          .processedWith(new ComponentProcessor())
2149          .compilesWithoutError()
2150          .and().generatesSources(generatedComponent);
2151    }
2152 
2153   /**
2154    * A simple {@link Processor} that generates one source file.
2155    */
2156   private static final class GeneratingProcessor extends AbstractProcessor {
2157     private final String generatedClassName;
2158     private final String generatedSource;
2159     private boolean processed;
2160 
GeneratingProcessor(String generatedClassName, String... source)2161     GeneratingProcessor(String generatedClassName, String... source) {
2162       this.generatedClassName = generatedClassName;
2163       this.generatedSource = Joiner.on("\n").join(source);
2164     }
2165 
2166     @Override
getSupportedAnnotationTypes()2167     public Set<String> getSupportedAnnotationTypes() {
2168       return ImmutableSet.of("*");
2169     }
2170 
2171     @Override
process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)2172     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
2173       if (!processed) {
2174         processed = true;
2175         try (Writer writer =
2176                 processingEnv.getFiler().createSourceFile(generatedClassName).openWriter()) {
2177           writer.append(generatedSource);
2178         } catch (IOException e) {
2179           throw new RuntimeException(e);
2180         }
2181       }
2182       return false;
2183     }
2184   }
2185 }
2186