• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.common.truth.Truth.assertAbout;
20 import static com.google.testing.compile.CompilationSubject.assertThat;
21 import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
22 import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
23 import static dagger.internal.codegen.Compilers.compilerWithOptions;
24 import static dagger.internal.codegen.Compilers.daggerCompiler;
25 
26 import com.google.common.collect.ImmutableList;
27 import com.google.testing.compile.Compilation;
28 import com.google.testing.compile.JavaFileObjects;
29 import javax.tools.JavaFileObject;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.junit.runners.JUnit4;
33 
34 @RunWith(JUnit4.class)
35 // TODO(gak): add tests for generation in the default package.
36 public final class InjectConstructorFactoryGeneratorTest {
37   private static final JavaFileObject QUALIFIER_A =
38       JavaFileObjects.forSourceLines("test.QualifierA",
39           "package test;",
40           "",
41           "import javax.inject.Qualifier;",
42           "",
43           "@Qualifier @interface QualifierA {}");
44   private static final JavaFileObject QUALIFIER_B =
45       JavaFileObjects.forSourceLines("test.QualifierB",
46           "package test;",
47           "",
48           "import javax.inject.Qualifier;",
49           "",
50           "@Qualifier @interface QualifierB {}");
51   private static final JavaFileObject SCOPE_A =
52       JavaFileObjects.forSourceLines("test.ScopeA",
53           "package test;",
54           "",
55           "import javax.inject.Scope;",
56           "",
57           "@Scope @interface ScopeA {}");
58   private static final JavaFileObject SCOPE_B =
59       JavaFileObjects.forSourceLines("test.ScopeB",
60           "package test;",
61           "",
62           "import javax.inject.Scope;",
63           "",
64           "@Scope @interface ScopeB {}");
65 
injectOnPrivateConstructor()66   @Test public void injectOnPrivateConstructor() {
67     JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateConstructor",
68         "package test;",
69         "",
70         "import javax.inject.Inject;",
71         "",
72         "class PrivateConstructor {",
73         "  @Inject private PrivateConstructor() {}",
74         "}");
75     Compilation compilation = daggerCompiler().compile(file);
76     assertThat(compilation).failed();
77     assertThat(compilation)
78         .hadErrorContaining("Dagger does not support injection into private constructors")
79         .inFile(file)
80         .onLine(6);
81   }
82 
injectConstructorOnInnerClass()83   @Test public void injectConstructorOnInnerClass() {
84     JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
85         "package test;",
86         "",
87         "import javax.inject.Inject;",
88         "",
89         "class OuterClass {",
90         "  class InnerClass {",
91         "    @Inject InnerClass() {}",
92         "  }",
93         "}");
94     Compilation compilation = daggerCompiler().compile(file);
95     assertThat(compilation).failed();
96     assertThat(compilation)
97         .hadErrorContaining(
98             "@Inject constructors are invalid on inner classes. "
99                 + "Did you mean to make the class static?")
100         .inFile(file)
101         .onLine(7);
102   }
103 
injectConstructorOnAbstractClass()104   @Test public void injectConstructorOnAbstractClass() {
105     JavaFileObject file = JavaFileObjects.forSourceLines("test.AbstractClass",
106         "package test;",
107         "",
108         "import javax.inject.Inject;",
109         "",
110         "abstract class AbstractClass {",
111         "  @Inject AbstractClass() {}",
112         "}");
113     Compilation compilation = daggerCompiler().compile(file);
114     assertThat(compilation).failed();
115     assertThat(compilation)
116         .hadErrorContaining("@Inject is nonsense on the constructor of an abstract class")
117         .inFile(file)
118         .onLine(6);
119   }
120 
injectConstructorOnGenericClass()121   @Test public void injectConstructorOnGenericClass() {
122     JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
123         "package test;",
124         "",
125         "import javax.inject.Inject;",
126         "",
127         "class GenericClass<T> {",
128         "  @Inject GenericClass(T t) {}",
129         "}");
130     JavaFileObject expected =
131         JavaFileObjects.forSourceLines(
132             "test.GenericClass_Factory",
133             "package test;",
134             "",
135             GeneratedLines.generatedImports(
136                 "import dagger.internal.Factory;",
137                 "import javax.inject.Provider;"),
138             "",
139             GeneratedLines.generatedAnnotations(),
140             "public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
141             "  private final Provider<T> tProvider;",
142             "",
143             "  public GenericClass_Factory(Provider<T> tProvider) {",
144             "    this.tProvider = tProvider;",
145             "  }",
146             "",
147             "  @Override",
148             "  public GenericClass<T> get() {",
149             "    return newInstance(tProvider.get());",
150             "  }",
151             "",
152             "  public static <T> GenericClass_Factory<T> create(Provider<T> tProvider) {",
153             "    return new GenericClass_Factory<T>(tProvider);",
154             "  }",
155             "",
156             "  public static <T> GenericClass<T> newInstance(T t) {",
157             "    return new GenericClass<T>(t);",
158             "  }",
159             "}");
160     assertAbout(javaSource()).that(file)
161         .processedWith(new ComponentProcessor())
162         .compilesWithoutError()
163         .and().generatesSources(expected);
164   }
165 
fieldAndMethodGenerics()166   @Test public void fieldAndMethodGenerics() {
167     JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
168         "package test;",
169         "",
170         "import javax.inject.Inject;",
171         "",
172         "class GenericClass<A, B> {",
173         "  @Inject A a;",
174         "",
175         "  @Inject GenericClass() {}",
176         "",
177         " @Inject void register(B b) {}",
178         "}");
179     JavaFileObject expected =
180         JavaFileObjects.forSourceLines(
181             "test.GenericClass_Factory",
182             "package test;",
183             "",
184             GeneratedLines.generatedImports(
185                 "import dagger.internal.Factory;",
186                 "import javax.inject.Provider;"),
187             "",
188             GeneratedLines.generatedAnnotations(),
189             "public final class GenericClass_Factory<A, B> implements",
190             "    Factory<GenericClass<A, B>> {",
191             "  private final Provider<A> aProvider;",
192             "  private final Provider<B> bProvider;",
193             "",
194             "  public GenericClass_Factory(",
195             "      Provider<A> aProvider, Provider<B> bProvider) {",
196             "    this.aProvider = aProvider;",
197             "    this.bProvider = bProvider;",
198             "  }",
199             "",
200             "  @Override",
201             "  public GenericClass<A, B> get() {",
202             "    GenericClass<A, B> instance = newInstance();",
203             "    GenericClass_MembersInjector.injectA(instance, aProvider.get());",
204             "    GenericClass_MembersInjector.injectRegister(instance, bProvider.get());",
205             "    return instance;",
206             "  }",
207             "",
208             "  public static <A, B> GenericClass_Factory<A, B> create(",
209             "      Provider<A> aProvider, Provider<B> bProvider) {",
210             "    return new GenericClass_Factory<A, B>(aProvider, bProvider);",
211             "  }",
212             "",
213             "  public static <A, B> GenericClass<A, B> newInstance() {",
214             "    return new GenericClass<A, B>();",
215             "  }",
216             "}");
217     assertAbout(javaSource()).that(file)
218         .processedWith(new ComponentProcessor())
219         .compilesWithoutError()
220         .and().generatesSources(expected);
221   }
222 
genericClassWithNoDependencies()223   @Test public void genericClassWithNoDependencies() {
224     JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
225         "package test;",
226         "",
227         "import javax.inject.Inject;",
228         "",
229         "class GenericClass<T> {",
230         "  @Inject GenericClass() {}",
231         "}");
232     JavaFileObject expected =
233         JavaFileObjects.forSourceLines(
234             "test.GenericClass_Factory",
235             "package test;",
236             "",
237             GeneratedLines.generatedImports("import dagger.internal.Factory;"),
238             "",
239             GeneratedLines.generatedAnnotations(),
240             "public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
241             "  @Override",
242             "  public GenericClass<T> get() {",
243             "    return newInstance();",
244             "  }",
245             "",
246             "  @SuppressWarnings(\"unchecked\")",
247             "  public static <T> GenericClass_Factory<T> create() {",
248             "    return InstanceHolder.INSTANCE;",
249             "  }",
250             "",
251             "  public static <T> GenericClass<T> newInstance() {",
252             "    return new GenericClass<T>();",
253             "  }",
254             "",
255             "  private static final class InstanceHolder {",
256             "    @SuppressWarnings(\"rawtypes\")",
257             "    private static final GenericClass_Factory INSTANCE = new GenericClass_Factory();",
258             "  }",
259             "}");
260     assertAbout(javaSource()).that(file)
261         .processedWith(new ComponentProcessor())
262         .compilesWithoutError()
263         .and().generatesSources(expected);
264   }
265 
twoGenericTypes()266   @Test public void twoGenericTypes() {
267     JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
268         "package test;",
269         "",
270         "import javax.inject.Inject;",
271         "",
272         "class GenericClass<A, B> {",
273         "  @Inject GenericClass(A a, B b) {}",
274         "}");
275     JavaFileObject expected =
276         JavaFileObjects.forSourceLines(
277             "test.GenericClass_Factory",
278             "package test;",
279             "",
280             GeneratedLines.generatedImports(
281                 "import dagger.internal.Factory;",
282                 "import javax.inject.Provider;"),
283             "",
284             GeneratedLines.generatedAnnotations(),
285             "public final class GenericClass_Factory<A, B>",
286             "    implements Factory<GenericClass<A, B>> {",
287             "  private final Provider<A> aProvider;",
288             "  private final Provider<B> bProvider;",
289             "",
290             "  public GenericClass_Factory(Provider<A> aProvider, Provider<B> bProvider) {",
291             "    this.aProvider = aProvider;",
292             "    this.bProvider = bProvider;",
293             "  }",
294             "",
295             "  @Override",
296             "  public GenericClass<A, B> get() {",
297             "    return newInstance(aProvider.get(), bProvider.get());",
298             "  }",
299             "",
300             "  public static <A, B> GenericClass_Factory<A, B> create(",
301             "      Provider<A> aProvider, Provider<B> bProvider) {",
302             "    return new GenericClass_Factory<A, B>(aProvider, bProvider);",
303             "  }",
304             "",
305             "  public static <A, B> GenericClass<A, B> newInstance(A a, B b) {",
306             "    return new GenericClass<A, B>(a, b);",
307             "  }",
308             "}");
309     assertAbout(javaSource()).that(file)
310         .processedWith(new ComponentProcessor())
311         .compilesWithoutError()
312         .and().generatesSources(expected);
313   }
314 
boundedGenerics()315   @Test public void boundedGenerics() {
316     JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
317         "package test;",
318         "",
319         "import javax.inject.Inject;",
320         "import java.util.List;",
321         "",
322         "class GenericClass<A extends Number & Comparable<A>,",
323         "    B extends List<? extends String>,",
324         "    C extends List<? super String>> {",
325         "  @Inject GenericClass(A a, B b, C c) {}",
326         "}");
327     JavaFileObject expected =
328         JavaFileObjects.forSourceLines(
329             "test.GenericClass_Factory",
330             "package test;",
331             "",
332             GeneratedLines.generatedImports(
333                 "import dagger.internal.Factory;",
334                 "import java.util.List;",
335                 "import javax.inject.Provider;"),
336             "",
337             GeneratedLines.generatedAnnotations(),
338             "public final class GenericClass_Factory<A extends Number & Comparable<A>,",
339             "        B extends List<? extends String>,",
340             "        C extends List<? super String>>",
341             "    implements Factory<GenericClass<A, B, C>> {",
342             "  private final Provider<A> aProvider;",
343             "  private final Provider<B> bProvider;",
344             "  private final Provider<C> cProvider;",
345             "",
346             "  public GenericClass_Factory(Provider<A> aProvider,",
347             "      Provider<B> bProvider,",
348             "      Provider<C> cProvider) {",
349             "    this.aProvider = aProvider;",
350             "    this.bProvider = bProvider;",
351             "    this.cProvider = cProvider;",
352             "  }",
353             "",
354             "  @Override",
355             "  public GenericClass<A, B, C> get() {",
356             "    return newInstance(aProvider.get(), bProvider.get(), cProvider.get());",
357             "  }",
358             "",
359             "  public static <A extends Number & Comparable<A>,",
360             "      B extends List<? extends String>,",
361             "      C extends List<? super String>> GenericClass_Factory<A, B, C> create(",
362             "          Provider<A> aProvider, Provider<B> bProvider, Provider<C> cProvider) {",
363             "    return new GenericClass_Factory<A, B, C>(aProvider, bProvider, cProvider);",
364             "  }",
365             "",
366             "  public static <",
367             "          A extends Number & Comparable<A>,",
368             "          B extends List<? extends String>,",
369             "          C extends List<? super String>>",
370             "      GenericClass<A, B, C> newInstance(A a, B b, C c) {",
371             "    return new GenericClass<A, B, C>(a, b, c);",
372             "  }",
373             "}");
374     assertAbout(javaSource()).that(file)
375         .processedWith(new ComponentProcessor())
376         .compilesWithoutError()
377         .and().generatesSources(expected);
378   }
379 
multipleSameTypesWithGenericsAndQualifiersAndLazies()380   @Test public void multipleSameTypesWithGenericsAndQualifiersAndLazies() {
381     JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
382         "package test;",
383         "",
384         "import javax.inject.Inject;",
385         "import javax.inject.Provider;",
386         "import dagger.Lazy;",
387         "",
388         "class GenericClass<A, B> {",
389         "  @Inject GenericClass(A a, A a2, Provider<A> pa, @QualifierA A qa, Lazy<A> la, ",
390         "                       String s, String s2, Provider<String> ps, ",
391         "                       @QualifierA String qs, Lazy<String> ls,",
392         "                       B b, B b2, Provider<B> pb, @QualifierA B qb, Lazy<B> lb) {}",
393         "}");
394     JavaFileObject expected =
395         JavaFileObjects.forSourceLines(
396             "test.GenericClass_Factory",
397             "package test;",
398             "",
399             GeneratedLines.generatedImports(
400                 "import dagger.Lazy;",
401                 "import dagger.internal.DoubleCheck;",
402                 "import dagger.internal.Factory;",
403                 "import javax.inject.Provider;"),
404             "",
405             GeneratedLines.generatedAnnotations(),
406             "public final class GenericClass_Factory<A, B>",
407             "    implements Factory<GenericClass<A, B>> {",
408             "  private final Provider<A> aProvider;",
409             "  private final Provider<A> a2Provider;",
410             "  private final Provider<A> paProvider;",
411             "  private final Provider<A> qaProvider;",
412             "  private final Provider<A> laProvider;",
413             "  private final Provider<String> sProvider;",
414             "  private final Provider<String> s2Provider;",
415             "  private final Provider<String> psProvider;",
416             "  private final Provider<String> qsProvider;",
417             "  private final Provider<String> lsProvider;",
418             "  private final Provider<B> bProvider;",
419             "  private final Provider<B> b2Provider;",
420             "  private final Provider<B> pbProvider;",
421             "  private final Provider<B> qbProvider;",
422             "  private final Provider<B> lbProvider;",
423             "",
424             "  public GenericClass_Factory(",
425             "      Provider<A> aProvider,",
426             "      Provider<A> a2Provider,",
427             "      Provider<A> paProvider,",
428             "      Provider<A> qaProvider,",
429             "      Provider<A> laProvider,",
430             "      Provider<String> sProvider,",
431             "      Provider<String> s2Provider,",
432             "      Provider<String> psProvider,",
433             "      Provider<String> qsProvider,",
434             "      Provider<String> lsProvider,",
435             "      Provider<B> bProvider,",
436             "      Provider<B> b2Provider,",
437             "      Provider<B> pbProvider,",
438             "      Provider<B> qbProvider,",
439             "      Provider<B> lbProvider) {",
440             "    this.aProvider = aProvider;",
441             "    this.a2Provider = a2Provider;",
442             "    this.paProvider = paProvider;",
443             "    this.qaProvider = qaProvider;",
444             "    this.laProvider = laProvider;",
445             "    this.sProvider = sProvider;",
446             "    this.s2Provider = s2Provider;",
447             "    this.psProvider = psProvider;",
448             "    this.qsProvider = qsProvider;",
449             "    this.lsProvider = lsProvider;",
450             "    this.bProvider = bProvider;",
451             "    this.b2Provider = b2Provider;",
452             "    this.pbProvider = pbProvider;",
453             "    this.qbProvider = qbProvider;",
454             "    this.lbProvider = lbProvider;",
455             "  }",
456             "",
457             "  @Override",
458             "  public GenericClass<A, B> get() {",
459             "    return newInstance(",
460             "        aProvider.get(),",
461             "        a2Provider.get(),",
462             "        paProvider,",
463             "        qaProvider.get(),",
464             "        DoubleCheck.lazy(laProvider),",
465             "        sProvider.get(),",
466             "        s2Provider.get(),",
467             "        psProvider,",
468             "        qsProvider.get(),",
469             "        DoubleCheck.lazy(lsProvider),",
470             "        bProvider.get(),",
471             "        b2Provider.get(),",
472             "        pbProvider,",
473             "        qbProvider.get(),",
474             "        DoubleCheck.lazy(lbProvider));",
475             "  }",
476             "",
477             "  public static <A, B> GenericClass_Factory<A, B> create(",
478             "      Provider<A> aProvider,",
479             "      Provider<A> a2Provider,",
480             "      Provider<A> paProvider,",
481             "      Provider<A> qaProvider,",
482             "      Provider<A> laProvider,",
483             "      Provider<String> sProvider,",
484             "      Provider<String> s2Provider,",
485             "      Provider<String> psProvider,",
486             "      Provider<String> qsProvider,",
487             "      Provider<String> lsProvider,",
488             "      Provider<B> bProvider,",
489             "      Provider<B> b2Provider,",
490             "      Provider<B> pbProvider,",
491             "      Provider<B> qbProvider,",
492             "      Provider<B> lbProvider) {",
493             "    return new GenericClass_Factory<A, B>(",
494             "        aProvider,",
495             "        a2Provider,",
496             "        paProvider,",
497             "        qaProvider,",
498             "        laProvider,",
499             "        sProvider,",
500             "        s2Provider,",
501             "        psProvider,",
502             "        qsProvider,",
503             "        lsProvider,",
504             "        bProvider,",
505             "        b2Provider,",
506             "        pbProvider,",
507             "        qbProvider,",
508             "        lbProvider);",
509             "  }",
510             "",
511             "  public static <A, B> GenericClass<A, B> newInstance(",
512             "      A a,",
513             "      A a2,",
514             "      Provider<A> pa,",
515             "      A qa,",
516             "      Lazy<A> la,",
517             "      String s,",
518             "      String s2,",
519             "      Provider<String> ps,",
520             "      String qs,",
521             "      Lazy<String> ls,",
522             "      B b,",
523             "      B b2,",
524             "      Provider<B> pb,",
525             "      B qb,",
526             "      Lazy<B> lb) {",
527             "    return new GenericClass<A, B>(",
528             "        a, a2, pa, qa, la, s, s2, ps, qs, ls, b, b2, pb, qb, lb);",
529             "  }",
530             "}");
531     assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A))
532         .processedWith(new ComponentProcessor())
533         .compilesWithoutError()
534         .and().generatesSources(expected);
535   }
536 
multipleInjectConstructors()537   @Test public void multipleInjectConstructors() {
538     JavaFileObject file = JavaFileObjects.forSourceLines("test.TooManyInjectConstructors",
539         "package test;",
540         "",
541         "import javax.inject.Inject;",
542         "",
543         "class TooManyInjectConstructors {",
544         "  @Inject TooManyInjectConstructors() {}",
545         "  TooManyInjectConstructors(int i) {}",
546         "  @Inject TooManyInjectConstructors(String s) {}",
547         "}");
548     Compilation compilation = daggerCompiler().compile(file);
549     assertThat(compilation).failed();
550     assertThat(compilation)
551         .hadErrorContaining("Types may only contain one injected constructor")
552         .inFile(file)
553         .onLine(6);
554     assertThat(compilation)
555         .hadErrorContaining("Types may only contain one injected constructor")
556         .inFile(file)
557         .onLine(8);
558   }
559 
multipleQualifiersOnInjectConstructorParameter()560   @Test public void multipleQualifiersOnInjectConstructorParameter() {
561     JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierConstructorParam",
562         "package test;",
563         "",
564         "import javax.inject.Inject;",
565         "",
566         "class MultipleQualifierConstructorParam {",
567         "  @Inject MultipleQualifierConstructorParam(@QualifierA @QualifierB String s) {}",
568         "}");
569     Compilation compilation = daggerCompiler().compile(file, QUALIFIER_A, QUALIFIER_B);
570     assertThat(compilation).failed();
571     // for whatever reason, javac only reports the error once on the constructor
572     assertThat(compilation)
573         .hadErrorContaining("A single dependency request may not use more than one @Qualifier")
574         .inFile(file)
575         .onLine(6);
576   }
577 
injectConstructorOnClassWithMultipleScopes()578   @Test public void injectConstructorOnClassWithMultipleScopes() {
579     JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleScopeClass",
580         "package test;",
581         "",
582         "import javax.inject.Inject;",
583         "",
584         "@ScopeA @ScopeB class MultipleScopeClass {",
585         "  @Inject MultipleScopeClass() {}",
586         "}");
587     Compilation compilation = daggerCompiler().compile(file, SCOPE_A, SCOPE_B);
588     assertThat(compilation).failed();
589     assertThat(compilation)
590         .hadErrorContaining("A single binding may not declare more than one @Scope")
591         .inFile(file)
592         .onLine(5)
593         .atColumn(1);
594     assertThat(compilation)
595         .hadErrorContaining("A single binding may not declare more than one @Scope")
596         .inFile(file)
597         .onLine(5)
598         .atColumn(9);
599   }
600 
injectConstructorWithQualifier()601   @Test public void injectConstructorWithQualifier() {
602     JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleScopeClass",
603         "package test;",
604         "",
605         "import javax.inject.Inject;",
606         "",
607         "class MultipleScopeClass {",
608         "  @Inject",
609         "  @QualifierA",
610         "  @QualifierB",
611         "  MultipleScopeClass() {}",
612         "}");
613     Compilation compilation = daggerCompiler().compile(file, QUALIFIER_A, QUALIFIER_B);
614     assertThat(compilation).failed();
615     assertThat(compilation)
616         .hadErrorContaining("@Qualifier annotations are not allowed on @Inject constructors")
617         .inFile(file)
618         .onLine(7);
619     assertThat(compilation)
620         .hadErrorContaining("@Qualifier annotations are not allowed on @Inject constructors")
621         .inFile(file)
622         .onLine(8);
623   }
624 
injectConstructorWithCheckedExceptionsError()625   @Test public void injectConstructorWithCheckedExceptionsError() {
626     JavaFileObject file = JavaFileObjects.forSourceLines("test.CheckedExceptionClass",
627         "package test;",
628         "",
629         "import javax.inject.Inject;",
630         "",
631         "class CheckedExceptionClass {",
632         "  @Inject CheckedExceptionClass() throws Exception {}",
633         "}");
634     Compilation compilation = daggerCompiler().compile(file);
635     assertThat(compilation).failed();
636     assertThat(compilation)
637         .hadErrorContaining("Dagger does not support checked exceptions on @Inject constructors")
638         .inFile(file)
639         .onLine(6);
640   }
641 
injectConstructorWithCheckedExceptionsWarning()642   @Test public void injectConstructorWithCheckedExceptionsWarning() {
643     JavaFileObject file = JavaFileObjects.forSourceLines("test.CheckedExceptionClass",
644         "package test;",
645         "",
646         "import javax.inject.Inject;",
647         "",
648         "class CheckedExceptionClass {",
649         "  @Inject CheckedExceptionClass() throws Exception {}",
650         "}");
651     Compilation compilation =
652         compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
653     assertThat(compilation).succeeded();
654     assertThat(compilation)
655         .hadWarningContaining("Dagger does not support checked exceptions on @Inject constructors")
656         .inFile(file)
657         .onLine(6);
658   }
659 
privateInjectClassError()660   @Test public void privateInjectClassError() {
661     JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
662         "package test;",
663         "",
664         "import javax.inject.Inject;",
665         "",
666         "final class OuterClass {",
667         "  private static final class InnerClass {",
668         "    @Inject InnerClass() {}",
669         "  }",
670         "}");
671     Compilation compilation = daggerCompiler().compile(file);
672     assertThat(compilation).failed();
673     assertThat(compilation)
674         .hadErrorContaining("Dagger does not support injection into private classes")
675         .inFile(file)
676         .onLine(7);
677   }
678 
privateInjectClassWarning()679   @Test public void privateInjectClassWarning() {
680     JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
681         "package test;",
682         "",
683         "import javax.inject.Inject;",
684         "",
685         "final class OuterClass {",
686         "  private static final class InnerClass {",
687         "    @Inject InnerClass() {}",
688         "  }",
689         "}");
690     Compilation compilation =
691         compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
692     assertThat(compilation).succeeded();
693     assertThat(compilation)
694         .hadWarningContaining("Dagger does not support injection into private classes")
695         .inFile(file)
696         .onLine(7);
697   }
698 
nestedInPrivateInjectClassError()699   @Test public void nestedInPrivateInjectClassError() {
700     JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
701         "package test;",
702         "",
703         "import javax.inject.Inject;",
704         "",
705         "final class OuterClass {",
706         "  private static final class MiddleClass {",
707         "    static final class InnerClass {",
708         "      @Inject InnerClass() {}",
709         "    }",
710         "  }",
711         "}");
712     Compilation compilation = daggerCompiler().compile(file);
713     assertThat(compilation).failed();
714     assertThat(compilation)
715         .hadErrorContaining("Dagger does not support injection into private classes")
716         .inFile(file)
717         .onLine(8);
718   }
719 
nestedInPrivateInjectClassWarning()720   @Test public void nestedInPrivateInjectClassWarning() {
721     JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
722         "package test;",
723         "",
724         "import javax.inject.Inject;",
725         "",
726         "final class OuterClass {",
727         "  private static final class MiddleClass {",
728         "    static final class InnerClass {",
729         "      @Inject InnerClass() {}",
730         "    }",
731         "  }",
732         "}");
733     Compilation compilation =
734         compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
735     assertThat(compilation).succeeded();
736     assertThat(compilation)
737         .hadWarningContaining("Dagger does not support injection into private classes")
738         .inFile(file)
739         .onLine(8);
740   }
741 
finalInjectField()742   @Test public void finalInjectField() {
743     JavaFileObject file = JavaFileObjects.forSourceLines("test.FinalInjectField",
744         "package test;",
745         "",
746         "import javax.inject.Inject;",
747         "",
748         "class FinalInjectField {",
749         "  @Inject final String s;",
750         "}");
751     Compilation compilation = daggerCompiler().compile(file);
752     assertThat(compilation).failed();
753     assertThat(compilation)
754         .hadErrorContaining("@Inject fields may not be final")
755         .inFile(file)
756         .onLine(6);
757   }
758 
privateInjectFieldError()759   @Test public void privateInjectFieldError() {
760     JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectField",
761         "package test;",
762         "",
763         "import javax.inject.Inject;",
764         "",
765         "class PrivateInjectField {",
766         "  @Inject private String s;",
767         "}");
768     Compilation compilation = daggerCompiler().compile(file);
769     assertThat(compilation).failed();
770     assertThat(compilation)
771         .hadErrorContaining("Dagger does not support injection into private fields")
772         .inFile(file)
773         .onLine(6);
774   }
775 
privateInjectFieldWarning()776   @Test public void privateInjectFieldWarning() {
777     JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectField",
778         "package test;",
779         "",
780         "import javax.inject.Inject;",
781         "",
782         "class PrivateInjectField {",
783         "  @Inject private String s;",
784         "}");
785     Compilation compilation =
786         compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
787     assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
788   }
789 
staticInjectFieldError()790   @Test public void staticInjectFieldError() {
791     JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectField",
792         "package test;",
793         "",
794         "import javax.inject.Inject;",
795         "",
796         "class StaticInjectField {",
797         "  @Inject static String s;",
798         "}");
799     Compilation compilation = daggerCompiler().compile(file);
800     assertThat(compilation).failed();
801     assertThat(compilation)
802         .hadErrorContaining("Dagger does not support injection into static fields")
803         .inFile(file)
804         .onLine(6);
805   }
806 
staticInjectFieldWarning()807   @Test public void staticInjectFieldWarning() {
808     JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectField",
809         "package test;",
810         "",
811         "import javax.inject.Inject;",
812         "",
813         "class StaticInjectField {",
814         "  @Inject static String s;",
815         "}");
816     Compilation compilation =
817         compilerWithOptions("-Adagger.staticMemberValidation=WARNING").compile(file);
818     assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
819   }
820 
multipleQualifiersOnField()821   @Test public void multipleQualifiersOnField() {
822     JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierInjectField",
823         "package test;",
824         "",
825         "import javax.inject.Inject;",
826         "",
827         "class MultipleQualifierInjectField {",
828         "  @Inject @QualifierA @QualifierB String s;",
829         "}");
830     Compilation compilation = daggerCompiler().compile(file, QUALIFIER_A, QUALIFIER_B);
831     assertThat(compilation).failed();
832     assertThat(compilation)
833         .hadErrorContaining("A single dependency request may not use more than one @Qualifier")
834         .inFile(file)
835         .onLine(6)
836         .atColumn(11);
837     assertThat(compilation)
838         .hadErrorContaining("A single dependency request may not use more than one @Qualifier")
839         .inFile(file)
840         .onLine(6)
841         .atColumn(23);
842   }
843 
abstractInjectMethod()844   @Test public void abstractInjectMethod() {
845     JavaFileObject file = JavaFileObjects.forSourceLines("test.AbstractInjectMethod",
846         "package test;",
847         "",
848         "import javax.inject.Inject;",
849         "",
850         "abstract class AbstractInjectMethod {",
851         "  @Inject abstract void method();",
852         "}");
853     Compilation compilation = daggerCompiler().compile(file);
854     assertThat(compilation).failed();
855     assertThat(compilation)
856         .hadErrorContaining("Methods with @Inject may not be abstract")
857         .inFile(file)
858         .onLine(6);
859   }
860 
privateInjectMethodError()861   @Test public void privateInjectMethodError() {
862     JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectMethod",
863         "package test;",
864         "",
865         "import javax.inject.Inject;",
866         "",
867         "class PrivateInjectMethod {",
868         "  @Inject private void method(){}",
869         "}");
870     Compilation compilation = daggerCompiler().compile(file);
871     assertThat(compilation).failed();
872     assertThat(compilation)
873         .hadErrorContaining("Dagger does not support injection into private methods")
874         .inFile(file)
875         .onLine(6);
876   }
877 
privateInjectMethodWarning()878   @Test public void privateInjectMethodWarning() {
879     JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectMethod",
880         "package test;",
881         "",
882         "import javax.inject.Inject;",
883         "",
884         "class PrivateInjectMethod {",
885         "  @Inject private void method(){}",
886         "}");
887     Compilation compilation =
888         compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
889     assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
890   }
891 
staticInjectMethodError()892   @Test public void staticInjectMethodError() {
893     JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectMethod",
894         "package test;",
895         "",
896         "import javax.inject.Inject;",
897         "",
898         "class StaticInjectMethod {",
899         "  @Inject static void method(){}",
900         "}");
901     Compilation compilation = daggerCompiler().compile(file);
902     assertThat(compilation).failed();
903     assertThat(compilation)
904         .hadErrorContaining("Dagger does not support injection into static methods")
905         .inFile(file)
906         .onLine(6);
907   }
908 
staticInjectMethodWarning()909   @Test public void staticInjectMethodWarning() {
910     JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectMethod",
911         "package test;",
912         "",
913         "import javax.inject.Inject;",
914         "",
915         "class StaticInjectMethod {",
916         "  @Inject static void method(){}",
917         "}");
918     Compilation compilation =
919         compilerWithOptions("-Adagger.staticMemberValidation=WARNING").compile(file);
920     assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
921   }
922 
genericInjectMethod()923   @Test public void genericInjectMethod() {
924     JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericInjectMethod",
925         "package test;",
926         "",
927         "import javax.inject.Inject;",
928         "",
929         "class AbstractInjectMethod {",
930         "  @Inject <T> void method();",
931         "}");
932     Compilation compilation = daggerCompiler().compile(file);
933     assertThat(compilation).failed();
934     assertThat(compilation)
935         .hadErrorContaining("Methods with @Inject may not declare type parameters")
936         .inFile(file)
937         .onLine(6);
938   }
939 
multipleQualifiersOnInjectMethodParameter()940   @Test public void multipleQualifiersOnInjectMethodParameter() {
941     JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierMethodParam",
942         "package test;",
943         "",
944         "import javax.inject.Inject;",
945         "",
946         "class MultipleQualifierMethodParam {",
947         "  @Inject void method(@QualifierA @QualifierB String s) {}",
948         "}");
949     Compilation compilation = daggerCompiler().compile(file, QUALIFIER_A, QUALIFIER_B);
950     assertThat(compilation).failed();
951     assertThat(compilation)
952         .hadErrorContaining("A single dependency request may not use more than one @Qualifier")
953         .inFile(file)
954         .onLine(6);
955   }
956 
injectConstructorDependsOnProduced()957   @Test public void injectConstructorDependsOnProduced() {
958     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
959         "package test;",
960         "",
961         "import dagger.producers.Produced;",
962         "import javax.inject.Inject;",
963         "",
964         "final class A {",
965         "  @Inject A(Produced<String> str) {}",
966         "}");
967     Compilation compilation = daggerCompiler().compile(aFile);
968     assertThat(compilation).failed();
969     assertThat(compilation)
970         .hadErrorContaining("Produced may only be injected in @Produces methods");
971   }
972 
injectConstructorDependsOnProducer()973   @Test public void injectConstructorDependsOnProducer() {
974     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
975         "package test;",
976         "",
977         "import dagger.producers.Producer;",
978         "import javax.inject.Inject;",
979         "",
980         "final class A {",
981         "  @Inject A(Producer<String> str) {}",
982         "}");
983     Compilation compilation = daggerCompiler().compile(aFile);
984     assertThat(compilation).failed();
985     assertThat(compilation)
986         .hadErrorContaining("Producer may only be injected in @Produces methods");
987   }
988 
injectFieldDependsOnProduced()989   @Test public void injectFieldDependsOnProduced() {
990     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
991         "package test;",
992         "",
993         "import dagger.producers.Produced;",
994         "import javax.inject.Inject;",
995         "",
996         "final class A {",
997         "  @Inject Produced<String> str;",
998         "}");
999     Compilation compilation = daggerCompiler().compile(aFile);
1000     assertThat(compilation).failed();
1001     assertThat(compilation)
1002         .hadErrorContaining("Produced may only be injected in @Produces methods");
1003   }
1004 
injectFieldDependsOnProducer()1005   @Test public void injectFieldDependsOnProducer() {
1006     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
1007         "package test;",
1008         "",
1009         "import dagger.producers.Producer;",
1010         "import javax.inject.Inject;",
1011         "",
1012         "final class A {",
1013         "  @Inject Producer<String> str;",
1014         "}");
1015     Compilation compilation = daggerCompiler().compile(aFile);
1016     assertThat(compilation).failed();
1017     assertThat(compilation)
1018         .hadErrorContaining("Producer may only be injected in @Produces methods");
1019   }
1020 
injectMethodDependsOnProduced()1021   @Test public void injectMethodDependsOnProduced() {
1022     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
1023         "package test;",
1024         "",
1025         "import dagger.producers.Produced;",
1026         "import javax.inject.Inject;",
1027         "",
1028         "final class A {",
1029         "  @Inject void inject(Produced<String> str) {}",
1030         "}");
1031     Compilation compilation = daggerCompiler().compile(aFile);
1032     assertThat(compilation).failed();
1033     assertThat(compilation)
1034         .hadErrorContaining("Produced may only be injected in @Produces methods");
1035   }
1036 
injectMethodDependsOnProducer()1037   @Test public void injectMethodDependsOnProducer() {
1038     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
1039         "package test;",
1040         "",
1041         "import dagger.producers.Producer;",
1042         "import javax.inject.Inject;",
1043         "",
1044         "final class A {",
1045         "  @Inject void inject(Producer<String> str) {}",
1046         "}");
1047     Compilation compilation = daggerCompiler().compile(aFile);
1048     assertThat(compilation).failed();
1049     assertThat(compilation)
1050         .hadErrorContaining("Producer may only be injected in @Produces methods");
1051   }
1052 
1053 
injectConstructor()1054   @Test public void injectConstructor() {
1055     JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
1056         "package test;",
1057         "",
1058         "import javax.inject.Inject;",
1059         "",
1060         "class InjectConstructor {",
1061         "  @Inject InjectConstructor(String s) {}",
1062         "}");
1063     JavaFileObject expected =
1064         JavaFileObjects.forSourceLines(
1065             "test.InjectConstructor_Factory",
1066             "package test;",
1067             "",
1068             GeneratedLines.generatedImports(
1069                 "import dagger.internal.Factory;",
1070                 "import javax.inject.Provider;"),
1071             "",
1072             GeneratedLines.generatedAnnotations(),
1073             "public final class InjectConstructor_Factory ",
1074             "    implements Factory<InjectConstructor> {",
1075             "",
1076             "  private final Provider<String> sProvider;",
1077             "",
1078             "  public InjectConstructor_Factory(Provider<String> sProvider) {",
1079             "    this.sProvider = sProvider;",
1080             "  }",
1081             "",
1082             "  @Override public InjectConstructor get() {",
1083             "    return newInstance(sProvider.get());",
1084             "  }",
1085             "",
1086             "  public static InjectConstructor_Factory create(Provider<String> sProvider) {",
1087             "    return new InjectConstructor_Factory(sProvider);",
1088             "  }",
1089             "",
1090             "  public static InjectConstructor newInstance(String s) {",
1091             "    return new InjectConstructor(s);",
1092             "  }",
1093             "}");
1094     assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
1095         .compilesWithoutError()
1096         .and().generatesSources(expected);
1097   }
1098 
injectConstructorAndMembersInjection()1099   @Test public void injectConstructorAndMembersInjection() {
1100     JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections",
1101         "package test;",
1102         "",
1103         "import javax.inject.Inject;",
1104         "",
1105         "class AllInjections {",
1106         "  @Inject String s;",
1107         "  @Inject AllInjections(String s) {}",
1108         "  @Inject void s(String s) {}",
1109         "}");
1110     JavaFileObject expectedFactory =
1111         JavaFileObjects.forSourceLines(
1112             "test.AllInjections_Factory",
1113             "package test;",
1114             "",
1115             GeneratedLines.generatedImports(
1116                 "import dagger.internal.Factory;",
1117                 "import javax.inject.Provider;"),
1118             "",
1119             GeneratedLines.generatedAnnotations(),
1120             "public final class AllInjections_Factory implements Factory<AllInjections> {",
1121             "  private final Provider<String> sProvider;",
1122             "  private final Provider<String> sProvider2;",
1123             "  private final Provider<String> sProvider3;",
1124             "",
1125             "  public AllInjections_Factory(",
1126             "      Provider<String> sProvider,",
1127             "      Provider<String> sProvider2,",
1128             "      Provider<String> sProvider3) {",
1129             "    this.sProvider = sProvider;",
1130             "    this.sProvider2 = sProvider2;",
1131             "    this.sProvider3 = sProvider3;",
1132             "  }",
1133             "",
1134             "  @Override",
1135             "  public AllInjections get() {",
1136             "    AllInjections instance = newInstance(sProvider.get());",
1137             "    AllInjections_MembersInjector.injectS(instance, sProvider2.get());",
1138             "    AllInjections_MembersInjector.injectS2(instance, sProvider3.get());",
1139             "    return instance;",
1140             "  }",
1141             "",
1142             "  public static AllInjections_Factory create(",
1143             "      Provider<String> sProvider,",
1144             "      Provider<String> sProvider2,",
1145             "      Provider<String> sProvider3) {",
1146             "    return new AllInjections_Factory(sProvider, sProvider2, sProvider3);",
1147             "  }",
1148             "",
1149             "  public static AllInjections newInstance(String s) {",
1150             "    return new AllInjections(s);",
1151             "  }",
1152             "}");
1153     assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
1154         .compilesWithoutError()
1155         .and()
1156         .generatesSources(expectedFactory);
1157   }
1158 
1159   @Test
wildcardDependency()1160   public void wildcardDependency() {
1161     JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
1162         "package test;",
1163         "",
1164         "import java.util.List;",
1165         "import javax.inject.Inject;",
1166         "",
1167         "class InjectConstructor {",
1168         "  @Inject InjectConstructor(List<?> objects) {}",
1169         "}");
1170     JavaFileObject expected =
1171         JavaFileObjects.forSourceLines(
1172             "test.InjectConstructor_Factory",
1173             "package test;",
1174             "",
1175             GeneratedLines.generatedImports(
1176                 "import dagger.internal.Factory;",
1177                 "import java.util.List;",
1178                 "import javax.inject.Provider;"),
1179             "",
1180             GeneratedLines.generatedAnnotations(),
1181             "public final class InjectConstructor_Factory ",
1182             "    implements Factory<InjectConstructor> {",
1183             "",
1184             "  private final Provider<List<?>> objectsProvider;",
1185             "",
1186             "  public InjectConstructor_Factory(Provider<List<?>> objectsProvider) {",
1187             "    this.objectsProvider = objectsProvider;",
1188             "  }",
1189             "",
1190             "  @Override public InjectConstructor get() {",
1191             "    return newInstance(objectsProvider.get());",
1192             "  }",
1193             "",
1194             "  public static InjectConstructor_Factory create(",
1195             "      Provider<List<?>> objectsProvider) {",
1196             "    return new InjectConstructor_Factory(objectsProvider);",
1197             "  }",
1198             "",
1199             "  public static InjectConstructor newInstance(List<?> objects) {",
1200             "    return new InjectConstructor(objects);",
1201             "  }",
1202             "}");
1203     assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
1204         .compilesWithoutError()
1205         .and().generatesSources(expected);
1206   }
1207 
1208   @Test
basicNameCollision()1209   public void basicNameCollision() {
1210     JavaFileObject factoryFile = JavaFileObjects.forSourceLines("other.pkg.Factory",
1211         "package other.pkg;",
1212         "",
1213         "public class Factory {}");
1214     JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
1215         "package test;",
1216         "",
1217         "import javax.inject.Inject;",
1218         "import other.pkg.Factory;",
1219         "",
1220         "class InjectConstructor {",
1221         "  @Inject InjectConstructor(Factory factory) {}",
1222         "}");
1223     JavaFileObject expected =
1224         JavaFileObjects.forSourceLines(
1225             "test.InjectConstructor_Factory",
1226             "package test;",
1227             "",
1228             GeneratedLines.generatedImports(
1229                 "import dagger.internal.Factory;",
1230                 "import javax.inject.Provider;"),
1231             "",
1232             GeneratedLines.generatedAnnotations(),
1233             "public final class InjectConstructor_Factory ",
1234             "    implements Factory<InjectConstructor> {",
1235             "",
1236             "  private final Provider<other.pkg.Factory> factoryProvider;",
1237             "",
1238             "  public InjectConstructor_Factory(Provider<other.pkg.Factory> factoryProvider) {",
1239             "    this.factoryProvider = factoryProvider;",
1240             "  }",
1241             "",
1242             "  @Override public InjectConstructor get() {",
1243             "    return newInstance(factoryProvider.get());",
1244             "  }",
1245             "",
1246             "  public static InjectConstructor_Factory create(",
1247             "      Provider<other.pkg.Factory> factoryProvider) {",
1248             "    return new InjectConstructor_Factory(factoryProvider);",
1249             "  }",
1250             "",
1251             "  public static InjectConstructor newInstance(",
1252             "      other.pkg.Factory factory) {",
1253             "    return new InjectConstructor(factory);",
1254             "  }",
1255             "}");
1256     assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file))
1257         .processedWith(new ComponentProcessor())
1258         .compilesWithoutError()
1259         .and().generatesSources(expected);
1260   }
1261 
1262   @Test
nestedNameCollision()1263   public void nestedNameCollision() {
1264     JavaFileObject factoryFile = JavaFileObjects.forSourceLines("other.pkg.Outer",
1265         "package other.pkg;",
1266         "",
1267         "public class Outer {",
1268         "  public class Factory {}",
1269         "}");
1270     JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
1271         "package test;",
1272         "",
1273         "import javax.inject.Inject;",
1274         "import other.pkg.Outer;",
1275         "",
1276         "class InjectConstructor {",
1277         "  @Inject InjectConstructor(Outer.Factory factory) {}",
1278         "}");
1279     JavaFileObject expected =
1280         JavaFileObjects.forSourceLines(
1281             "test.InjectConstructor_Factory",
1282             "package test;",
1283             "",
1284             GeneratedLines.generatedImports(
1285                 "import dagger.internal.Factory;",
1286                 "import javax.inject.Provider;",
1287                 "import other.pkg.Outer;"),
1288             "",
1289             GeneratedLines.generatedAnnotations(),
1290             "public final class InjectConstructor_Factory ",
1291             "    implements Factory<InjectConstructor> {",
1292             "",
1293             "  private final Provider<Outer.Factory> factoryProvider;",
1294             "",
1295             "  public InjectConstructor_Factory(Provider<Outer.Factory> factoryProvider) {",
1296             "    this.factoryProvider = factoryProvider;",
1297             "  }",
1298             "",
1299             "  @Override public InjectConstructor get() {",
1300             "    return newInstance(factoryProvider.get());",
1301             "  }",
1302             "",
1303             "  public static InjectConstructor_Factory create(",
1304             "      Provider<Outer.Factory> factoryProvider) {",
1305             "    return new InjectConstructor_Factory(factoryProvider);",
1306             "  }",
1307             "",
1308             "  public static InjectConstructor newInstance(",
1309             "      Outer.Factory factory) {",
1310             "    return new InjectConstructor(factory);",
1311             "  }",
1312             "}");
1313     assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file))
1314         .processedWith(new ComponentProcessor())
1315         .compilesWithoutError()
1316         .and().generatesSources(expected);
1317   }
1318 
1319   @Test
samePackageNameCollision()1320   public void samePackageNameCollision() {
1321     JavaFileObject samePackageInterface = JavaFileObjects.forSourceLines("test.CommonName",
1322         "package test;",
1323         "",
1324         "public interface CommonName {}");
1325     JavaFileObject differentPackageInterface = JavaFileObjects.forSourceLines(
1326         "other.pkg.CommonName",
1327         "package other.pkg;",
1328         "",
1329         "public interface CommonName {}");
1330     JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
1331         "package test;",
1332         "",
1333         "import javax.inject.Inject;",
1334         "",
1335         "class InjectConstructor implements CommonName {",
1336         "  @Inject InjectConstructor(other.pkg.CommonName otherPackage, CommonName samePackage) {}",
1337         "}");
1338     JavaFileObject expected =
1339         JavaFileObjects.forSourceLines(
1340             "test.InjectConstructor_Factory",
1341             "package test;",
1342             "",
1343             GeneratedLines.generatedImports(
1344                 "import dagger.internal.Factory;",
1345                 "import javax.inject.Provider;"),
1346             "",
1347             GeneratedLines.generatedAnnotations(),
1348             "public final class InjectConstructor_Factory ",
1349             "    implements Factory<InjectConstructor> {",
1350             "",
1351             "  private final Provider<other.pkg.CommonName> otherPackageProvider;",
1352             "  private final Provider<CommonName> samePackageProvider;",
1353             "",
1354             "  public InjectConstructor_Factory(",
1355             "      Provider<other.pkg.CommonName> otherPackageProvider,",
1356             "      Provider<CommonName> samePackageProvider) {",
1357             "    this.otherPackageProvider = otherPackageProvider;",
1358             "    this.samePackageProvider = samePackageProvider;",
1359             "  }",
1360             "",
1361             "  @Override public InjectConstructor get() {",
1362             "    return newInstance(otherPackageProvider.get(), samePackageProvider.get());",
1363             "  }",
1364             "",
1365             "  public static InjectConstructor_Factory create(",
1366             "      Provider<other.pkg.CommonName> otherPackageProvider,",
1367             "      Provider<CommonName> samePackageProvider) {",
1368             "    return new InjectConstructor_Factory(otherPackageProvider, samePackageProvider);",
1369             "  }",
1370             "",
1371             "  public static InjectConstructor newInstance(",
1372             "      other.pkg.CommonName otherPackage, CommonName samePackage) {",
1373             "    return new InjectConstructor(otherPackage, samePackage);",
1374             "  }",
1375             "}");
1376     assertAbout(javaSources())
1377         .that(ImmutableList.of(samePackageInterface, differentPackageInterface, file))
1378         .processedWith(new ComponentProcessor())
1379         .compilesWithoutError()
1380         .and().generatesSources(expected);
1381   }
1382 
1383   @Test
noDeps()1384   public void noDeps() {
1385     JavaFileObject simpleType = JavaFileObjects.forSourceLines("test.SimpleType",
1386         "package test;",
1387         "",
1388         "import javax.inject.Inject;",
1389         "",
1390         "final class SimpleType {",
1391         "  @Inject SimpleType() {}",
1392         "}");
1393     JavaFileObject factory =
1394         JavaFileObjects.forSourceLines(
1395             "test.SimpleType_Factory",
1396             "package test;",
1397             "",
1398             GeneratedLines.generatedImports("import dagger.internal.Factory;"),
1399             "",
1400             GeneratedLines.generatedAnnotations(),
1401             "public final class SimpleType_Factory implements Factory<SimpleType> {",
1402             "  @Override public SimpleType get() {",
1403             "    return newInstance();",
1404             "  }",
1405             "",
1406             "  public static SimpleType_Factory create() {",
1407             "    return InstanceHolder.INSTANCE;",
1408             "  }",
1409             "",
1410             "  public static SimpleType newInstance() {",
1411             "    return new SimpleType();",
1412             "  }",
1413             "",
1414             "  private static final class InstanceHolder {",
1415             "    private static final SimpleType_Factory INSTANCE = new SimpleType_Factory();",
1416             "  }",
1417             "}");
1418     assertAbout(javaSource())
1419         .that(simpleType)
1420         .processedWith(new ComponentProcessor())
1421         .compilesWithoutError()
1422         .and().generatesSources(factory);
1423   }
1424 
simpleComponentWithNesting()1425   @Test public void simpleComponentWithNesting() {
1426     JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines("test.OuterType",
1427         "package test;",
1428         "",
1429         "import dagger.Component;",
1430         "import javax.inject.Inject;",
1431         "",
1432         "final class OuterType {",
1433         "  static class A {",
1434         "    @Inject A() {}",
1435         "  }",
1436         "  static class B {",
1437         "    @Inject A a;",
1438         "  }",
1439         "}");
1440     JavaFileObject aFactory =
1441         JavaFileObjects.forSourceLines(
1442             "test.OuterType_A_Factory",
1443             "package test;",
1444             "",
1445             GeneratedLines.generatedImports("import dagger.internal.Factory;"),
1446             "",
1447             GeneratedLines.generatedAnnotations(),
1448             "public final class OuterType_A_Factory implements Factory<OuterType.A> {",
1449             "  @Override public OuterType.A get() {",
1450             "    return newInstance();",
1451             "  }",
1452             "",
1453             "  public static OuterType_A_Factory create() {",
1454             "    return InstanceHolder.INSTANCE;",
1455             "  }",
1456             "",
1457             "  public static OuterType.A newInstance() {",
1458             "    return new OuterType.A();",
1459             "  }",
1460             "",
1461             "  private static final class InstanceHolder {",
1462             "    private static final OuterType_A_Factory INSTANCE = new OuterType_A_Factory();",
1463             "  }",
1464             "}");
1465     assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile))
1466         .processedWith(new ComponentProcessor())
1467         .compilesWithoutError()
1468         .and().generatesSources(aFactory);
1469   }
1470 }
1471