• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.TruthJUnit.assume;
20 import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
21 import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
22 import static dagger.internal.codegen.ComponentCreatorTest.CompilerType.JAVAC;
23 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.COMPONENT_BUILDER;
24 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.COMPONENT_FACTORY;
25 import static dagger.internal.codegen.base.ComponentCreatorKind.BUILDER;
26 import static dagger.internal.codegen.base.ComponentCreatorKind.FACTORY;
27 import static dagger.internal.codegen.base.ComponentKind.COMPONENT;
28 import static dagger.internal.codegen.binding.ErrorMessages.componentMessagesFor;
29 
30 import androidx.room.compiler.processing.util.Source;
31 import com.google.common.collect.ImmutableList;
32 import com.google.common.collect.ImmutableMap;
33 import dagger.internal.codegen.base.ComponentCreatorAnnotation;
34 import dagger.testing.compile.CompilerTests;
35 import dagger.testing.golden.GoldenFileRule;
36 import java.util.Collection;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 import org.junit.runners.Parameterized;
41 import org.junit.runners.Parameterized.Parameters;
42 
43 /** Tests for properties of component creators shared by both builders and factories. */
44 @RunWith(Parameterized.class)
45 public class ComponentCreatorTest extends ComponentCreatorTestHelper {
46   enum CompilerType {
47     JAVAC
48   }
49 
50   private final CompilerType compilerType;
51   private final ImmutableMap<String, String> compilerOptions;
52 
53   @Parameters(name = "compilerMode={0}, creatorKind={1}")
parameters()54   public static Collection<Object[]> parameters() {
55     return ImmutableList.of(
56       new Object[]{DEFAULT_MODE, COMPONENT_BUILDER, JAVAC},
57       new Object[]{DEFAULT_MODE, COMPONENT_FACTORY, JAVAC},
58       new Object[]{FAST_INIT_MODE, COMPONENT_BUILDER, JAVAC},
59       new Object[]{FAST_INIT_MODE, COMPONENT_FACTORY, JAVAC});
60   }
61 
62   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
63 
ComponentCreatorTest( CompilerMode compilerMode, ComponentCreatorAnnotation componentCreatorAnnotation, CompilerType compilerType)64   public ComponentCreatorTest(
65       CompilerMode compilerMode,
66       ComponentCreatorAnnotation componentCreatorAnnotation,
67       CompilerType compilerType) {
68     super(compilerMode, componentCreatorAnnotation);
69     this.compilerType = compilerType;
70     this.compilerOptions =
71         ImmutableMap.<String, String>builder()
72             .putAll(compilerMode.processorOptions())
73             .build();
74   }
75 
76   @Test
testEmptyCreator()77   public void testEmptyCreator() throws Exception {
78     assume().that(compilerType).isEqualTo(JAVAC);
79     Source injectableTypeFile =
80         CompilerTests.javaSource(
81             "test.SomeInjectableType",
82             "package test;",
83             "",
84             "import javax.inject.Inject;",
85             "",
86             "final class SomeInjectableType {",
87             "  @Inject SomeInjectableType() {}",
88             "}");
89     Source componentFile =
90         preprocessedJavaSource(
91             "test.SimpleComponent",
92             "package test;",
93             "",
94             "import dagger.Component;",
95             "import javax.inject.Provider;",
96             "",
97             "@Component",
98             "interface SimpleComponent {",
99             "  SomeInjectableType someInjectableType();",
100             "",
101             "  @Component.Builder",
102             "  static interface Builder {",
103             "     SimpleComponent build();",
104             "  }",
105             "}");
106 
107     CompilerTests.daggerCompiler(injectableTypeFile, componentFile)
108         .withProcessingOptions(compilerOptions)
109         .compile(
110             subject -> {
111               subject.hasErrorCount(0);
112               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
113             });
114   }
115 
116   @Test
testCanInstantiateModulesUserCannotSet()117   public void testCanInstantiateModulesUserCannotSet() throws Exception {
118     assume().that(compilerType).isEqualTo(JAVAC);
119     Source module =
120         CompilerTests.javaSource(
121             "test.TestModule",
122             "package test;",
123             "",
124             "import dagger.Module;",
125             "import dagger.Provides;",
126             "",
127             "@Module",
128             "final class TestModule {",
129             "  @Provides String string() { return null; }",
130             "}");
131 
132     Source componentFile =
133         preprocessedJavaSource(
134             "test.TestComponent",
135             "package test;",
136             "",
137             "import dagger.Component;",
138             "",
139             "@Component(modules = TestModule.class)",
140             "interface TestComponent {",
141             "  String string();",
142             "",
143             "  @Component.Builder",
144             "  interface Builder {",
145             "    TestComponent build();",
146             "  }",
147             "}");
148 
149     CompilerTests.daggerCompiler(module, componentFile)
150         .withProcessingOptions(compilerOptions)
151         .compile(
152             subject -> {
153               subject.hasErrorCount(0);
154               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
155             });
156   }
157 
158   @Test
testMoreThanOneCreatorOfSameTypeFails()159   public void testMoreThanOneCreatorOfSameTypeFails() {
160     Source componentFile =
161         preprocessedJavaSource(
162             "test.SimpleComponent",
163             "package test;",
164             "",
165             "import dagger.Component;",
166             "import javax.inject.Provider;",
167             "",
168             "@Component",
169             "interface SimpleComponent {",
170             "  @Component.Builder",
171             "  static interface Builder {",
172             "     SimpleComponent build();",
173             "  }",
174             "",
175             "  @Component.Builder",
176             "  interface Builder2 {",
177             "     SimpleComponent build();",
178             "  }",
179             "}");
180 
181     CompilerTests.daggerCompiler(componentFile)
182         .withProcessingOptions(compilerOptions)
183         .compile(
184             subject -> {
185               subject.hasErrorCount(1);
186               subject.hasErrorContaining(
187                       String.format(
188                           componentMessagesFor(COMPONENT).moreThanOne(),
189                           process("[test.SimpleComponent.Builder, test.SimpleComponent.Builder2]")))
190                   .onSource(componentFile);
191             });
192   }
193 
194   @Test
testBothBuilderAndFactoryFails()195   public void testBothBuilderAndFactoryFails() {
196     Source componentFile =
197         CompilerTests.javaSource(
198             "test.SimpleComponent",
199             "package test;",
200             "",
201             "import dagger.Component;",
202             "import javax.inject.Provider;",
203             "",
204             "@Component",
205             "interface SimpleComponent {",
206             "  @Component.Builder",
207             "  static interface Builder {",
208             "     SimpleComponent build();",
209             "  }",
210             "",
211             "  @Component.Factory",
212             "  interface Factory {",
213             "     SimpleComponent create();",
214             "  }",
215             "}");
216     CompilerTests.daggerCompiler(componentFile)
217         .withProcessingOptions(compilerOptions)
218         .compile(
219             subject -> {
220               subject.hasErrorCount(1);
221               subject.hasErrorContaining(
222                       String.format(
223                           componentMessagesFor(COMPONENT).moreThanOne(),
224                           "[test.SimpleComponent.Builder, test.SimpleComponent.Factory]"))
225                   .onSource(componentFile);
226             });
227   }
228 
229   @Test
testGenericCreatorTypeFails()230   public void testGenericCreatorTypeFails() {
231     Source componentFile =
232         preprocessedJavaSource(
233             "test.SimpleComponent",
234             "package test;",
235             "",
236             "import dagger.Component;",
237             "import javax.inject.Provider;",
238             "",
239             "@Component",
240             "interface SimpleComponent {",
241             "  @Component.Builder",
242             "  interface Builder<T> {",
243             "     SimpleComponent build();",
244             "  }",
245             "}");
246     CompilerTests.daggerCompiler(componentFile)
247         .withProcessingOptions(compilerOptions)
248         .compile(
249             subject -> {
250               subject.hasErrorCount(1);
251               subject.hasErrorContaining(messages.generics()).onSource(componentFile);
252             });
253   }
254 
255   @Test
testCreatorNotInComponentFails()256   public void testCreatorNotInComponentFails() {
257     Source builder =
258         preprocessedJavaSource(
259             "test.Builder",
260             "package test;",
261             "",
262             "import dagger.Component;",
263             "",
264             "@Component.Builder",
265             "interface Builder {}");
266     CompilerTests.daggerCompiler(builder)
267         .withProcessingOptions(compilerOptions)
268         .compile(
269             subject -> {
270               subject.hasErrorCount(1);
271               subject.hasErrorContaining(messages.mustBeInComponent()).onSource(builder);
272             });
273   }
274 
275   @Test
testCreatorMissingFactoryMethodFails()276   public void testCreatorMissingFactoryMethodFails() {
277     Source componentFile =
278         preprocessedJavaSource(
279             "test.SimpleComponent",
280             "package test;",
281             "",
282             "import dagger.Component;",
283             "import javax.inject.Provider;",
284             "",
285             "@Component",
286             "interface SimpleComponent {",
287             "  @Component.Builder",
288             "  interface Builder {}",
289             "}");
290     CompilerTests.daggerCompiler(componentFile)
291         .withProcessingOptions(compilerOptions)
292         .compile(
293             subject -> {
294               subject.hasErrorCount(1);
295               subject.hasErrorContaining(messages.missingFactoryMethod())
296                   .onSource(componentFile);
297             });
298   }
299 
300   @Test
testCreatorWithBindsInstanceNoStaticCreateGenerated()301   public void testCreatorWithBindsInstanceNoStaticCreateGenerated() throws Exception {
302     assume().that(compilerType).isEqualTo(JAVAC);
303     Source componentFile =
304         javaFileBuilder("test.SimpleComponent")
305             .addLines(
306                 "package test;",
307                 "",
308                 "import dagger.BindsInstance;",
309                 "import dagger.Component;",
310                 "import javax.inject.Provider;",
311                 "",
312                 "@Component",
313                 "interface SimpleComponent {",
314                 "  Object object();",
315                 "")
316             .addLinesIf(
317                 BUILDER,
318                 "  @Component.Builder",
319                 "  interface Builder {",
320                 "    @BindsInstance Builder object(Object object);",
321                 "    SimpleComponent build();",
322                 "  }")
323             .addLinesIf(
324                 FACTORY,
325                 "  @Component.Factory",
326                 "  interface Factory {",
327                 "    SimpleComponent create(@BindsInstance Object object);",
328                 "  }")
329             .addLines("}")
330             .buildSource();
331 
332     CompilerTests.daggerCompiler(componentFile)
333         .withProcessingOptions(compilerOptions)
334         .compile(
335             subject -> {
336               subject.hasErrorCount(0);
337               subject.hasWarningCount(0);
338               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
339             });
340   }
341 
342   @Test
testCreatorWithPrimitiveBindsInstance()343   public void testCreatorWithPrimitiveBindsInstance() throws Exception {
344     assume().that(compilerType).isEqualTo(JAVAC);
345     Source componentFile =
346         javaFileBuilder("test.SimpleComponent")
347             .addLines(
348                 "package test;",
349                 "",
350                 "import dagger.BindsInstance;",
351                 "import dagger.Component;",
352                 "import javax.inject.Provider;",
353                 "",
354                 "@Component",
355                 "interface SimpleComponent {",
356                 "  int anInt();",
357                 "")
358             .addLinesIf(
359                 BUILDER,
360                 "  @Component.Builder",
361                 "  interface Builder {",
362                 "    @BindsInstance Builder i(int i);",
363                 "    SimpleComponent build();",
364                 "  }")
365             .addLinesIf(
366                 FACTORY,
367                 "  @Component.Factory",
368                 "  interface Factory {",
369                 "    SimpleComponent create(@BindsInstance int i);",
370                 "  }")
371             .addLines(
372                 "}")
373             .buildSource();
374 
375     CompilerTests.daggerCompiler(componentFile)
376         .withProcessingOptions(compilerOptions)
377         .compile(
378             subject -> {
379               subject.hasErrorCount(0);
380               subject.hasWarningCount(0);
381               subject.generatedSource(goldenFileRule.goldenSource("test/DaggerSimpleComponent"));
382             });
383   }
384 
385   @Test
testPrivateCreatorFails()386   public void testPrivateCreatorFails() {
387     Source componentFile =
388         preprocessedJavaSource(
389             "test.SimpleComponent",
390             "package test;",
391             "",
392             "import dagger.Component;",
393             "import javax.inject.Provider;",
394             "",
395             "@Component",
396             "abstract class SimpleComponent {",
397             "  @Component.Builder",
398             "  private interface Builder {}",
399             "}");
400     CompilerTests.daggerCompiler(componentFile)
401         .withProcessingOptions(compilerOptions)
402         .compile(
403             subject -> {
404               subject.hasErrorCount(1);
405               subject.hasErrorContaining(messages.isPrivate()).onSource(componentFile);
406             });
407   }
408 
409   @Test
testNonStaticCreatorFails()410   public void testNonStaticCreatorFails() {
411     Source componentFile =
412         preprocessedJavaSource(
413             "test.SimpleComponent",
414             "package test;",
415             "",
416             "import dagger.Component;",
417             "import javax.inject.Provider;",
418             "",
419             "@Component",
420             "abstract class SimpleComponent {",
421             "  @Component.Builder",
422             "  abstract class Builder {}",
423             "}");
424     CompilerTests.daggerCompiler(componentFile)
425         .withProcessingOptions(compilerOptions)
426         .compile(
427             subject -> {
428               subject.hasErrorCount(1);
429               subject.hasErrorContaining(messages.mustBeStatic()).onSource(componentFile);
430             });
431   }
432 
433   @Test
testNonAbstractCreatorFails()434   public void testNonAbstractCreatorFails() {
435     Source componentFile =
436         preprocessedJavaSource(
437             "test.SimpleComponent",
438             "package test;",
439             "",
440             "import dagger.Component;",
441             "import javax.inject.Provider;",
442             "",
443             "@Component",
444             "abstract class SimpleComponent {",
445             "  @Component.Builder",
446             "  static class Builder {}",
447             "}");
448     CompilerTests.daggerCompiler(componentFile)
449         .withProcessingOptions(compilerOptions)
450         .compile(
451             subject -> {
452               subject.hasErrorCount(1);
453               subject.hasErrorContaining(messages.mustBeAbstract()).onSource(componentFile);
454             });
455   }
456 
457   @Test
testCreatorOneConstructorWithArgsFails()458   public void testCreatorOneConstructorWithArgsFails() {
459     Source componentFile =
460         preprocessedJavaSource(
461             "test.SimpleComponent",
462             "package test;",
463             "",
464             "import dagger.Component;",
465             "import javax.inject.Provider;",
466             "",
467             "@Component",
468             "abstract class SimpleComponent {",
469             "  @Component.Builder",
470             "  static abstract class Builder {",
471             "    Builder(String unused) {}",
472             "  }",
473             "}");
474     CompilerTests.daggerCompiler(componentFile)
475         .withProcessingOptions(compilerOptions)
476         .compile(
477             subject -> {
478               subject.hasErrorCount(2);
479               subject.hasErrorContaining(messages.invalidConstructor())
480                   .onSource(componentFile);
481             });
482   }
483 
484   @Test
testCreatorMoreThanOneConstructorFails()485   public void testCreatorMoreThanOneConstructorFails() {
486     Source componentFile =
487         preprocessedJavaSource(
488             "test.SimpleComponent",
489             "package test;",
490             "",
491             "import dagger.Component;",
492             "import javax.inject.Provider;",
493             "",
494             "@Component",
495             "abstract class SimpleComponent {",
496             "  @Component.Builder",
497             "  static abstract class Builder {",
498             "    Builder() {}",
499             "    Builder(String unused) {}",
500             "  }",
501             "}");
502     CompilerTests.daggerCompiler(componentFile)
503         .withProcessingOptions(compilerOptions)
504         .compile(
505             subject -> {
506               subject.hasErrorCount(2);
507               subject.hasErrorContaining(messages.invalidConstructor())
508                   .onSource(componentFile);
509             });
510   }
511 
512   @Test
testCreatorEnumFails()513   public void testCreatorEnumFails() {
514     Source componentFile =
515         preprocessedJavaSource(
516             "test.SimpleComponent",
517             "package test;",
518             "",
519             "import dagger.Component;",
520             "import javax.inject.Provider;",
521             "",
522             "@Component",
523             "abstract class SimpleComponent {",
524             "  @Component.Builder",
525             "  enum Builder {}",
526             "}");
527     CompilerTests.daggerCompiler(componentFile)
528         .withProcessingOptions(compilerOptions)
529         .compile(
530             subject -> {
531               subject.hasErrorCount(1);
532               subject.hasErrorContaining(messages.mustBeClassOrInterface())
533                   .onSource(componentFile);
534             });
535   }
536 
537   @Test
testCreatorFactoryMethodReturnsWrongTypeFails()538   public void testCreatorFactoryMethodReturnsWrongTypeFails() {
539     Source componentFile =
540         preprocessedJavaSource(
541             "test.SimpleComponent",
542             "package test;",
543             "",
544             "import dagger.Component;",
545             "import javax.inject.Provider;",
546             "",
547             "@Component",
548             "abstract class SimpleComponent {",
549             "  @Component.Builder",
550             "  interface Builder {",
551             "    String build();",
552             "  }",
553             "}");
554     CompilerTests.daggerCompiler(componentFile)
555         .withProcessingOptions(compilerOptions)
556         .compile(
557             subject -> {
558               subject.hasErrorCount(1);
559               subject.hasErrorContaining(messages.factoryMethodMustReturnComponentType())
560                   .onSource(componentFile)
561                   .onLineContaining(process("String build();"));
562             });
563   }
564 
565   @Test
testCreatorSetterForNonBindsInstancePrimitiveFails()566   public void testCreatorSetterForNonBindsInstancePrimitiveFails() {
567     Source component =
568         javaFileBuilder("test.TestComponent")
569             .addLines(
570                 "package test;",
571                 "",
572                 "import dagger.Component;",
573                 "",
574                 "@Component",
575                 "interface TestComponent {",
576                 "  Object object();",
577                 "")
578             .addLinesIf(
579                 BUILDER,
580                 "  @Component.Builder",
581                 "  interface Builder {",
582                 "    Builder primitive(long l);",
583                 "    TestComponent build();",
584                 "  }")
585             .addLinesIf(
586                 FACTORY,
587                 "  @Component.Factory",
588                 "  interface Factory {",
589                 "    TestComponent create(long l);",
590                 "  }")
591             .addLines( //
592                 "}")
593             .buildSource();
594     CompilerTests.daggerCompiler(component)
595         .withProcessingOptions(compilerOptions)
596         .compile(
597             subject -> {
598               subject.hasErrorCount(1);
599               subject.hasErrorContaining(messages.nonBindsInstanceParametersMayNotBePrimitives())
600                   .onSource(component)
601                   .onLineContaining("(long l)");
602             });
603   }
604 
605   @Test
testInheritedBuilderBuildReturnsWrongTypeFails()606   public void testInheritedBuilderBuildReturnsWrongTypeFails() {
607     Source componentFile =
608         preprocessedJavaSource(
609             "test.SimpleComponent",
610             "package test;",
611             "",
612             "import dagger.Component;",
613             "import javax.inject.Provider;",
614             "",
615             "@Component",
616             "abstract class SimpleComponent {",
617             "  interface Parent {",
618             "    String build();",
619             "  }",
620             "",
621             "  @Component.Builder",
622             "  interface Builder extends Parent {}",
623             "}");
624     CompilerTests.daggerCompiler(componentFile)
625         .withProcessingOptions(compilerOptions)
626         .compile(
627             subject -> {
628               subject.hasErrorCount(1);
629               subject.hasErrorContaining(
630                     String.format(
631                         messages.inheritedFactoryMethodMustReturnComponentType(),
632                         process("String test.SimpleComponent.Parent.build()")))
633                   .onSource(componentFile)
634                   .onLineContaining(process("interface Builder"));
635             });
636   }
637 
638   @Test
testTwoFactoryMethodsFails()639   public void testTwoFactoryMethodsFails() {
640     Source componentFile =
641         preprocessedJavaSource(
642             "test.SimpleComponent",
643             "package test;",
644             "",
645             "import dagger.Component;",
646             "import javax.inject.Provider;",
647             "",
648             "@Component",
649             "abstract class SimpleComponent {",
650             "  @Component.Builder",
651             "  interface Builder {",
652             "    SimpleComponent build();",
653             "    SimpleComponent newSimpleComponent();",
654             "  }",
655             "}");
656     CompilerTests.daggerCompiler(componentFile)
657         .withProcessingOptions(compilerOptions)
658         .compile(
659             subject -> {
660               subject.hasErrorCount(1);
661               subject.hasErrorContaining(
662                       String.format(
663                           messages.twoFactoryMethods(),
664                           process("test.SimpleComponent test.SimpleComponent.Builder.build()")))
665                   .onSource(componentFile)
666                   .onLineContaining("SimpleComponent newSimpleComponent();");
667             });
668   }
669 
670   @Test
testInheritedTwoFactoryMethodsFails()671   public void testInheritedTwoFactoryMethodsFails() {
672     Source componentFile =
673         preprocessedJavaSource(
674             "test.SimpleComponent",
675             "package test;",
676             "",
677             "import dagger.Component;",
678             "import javax.inject.Provider;",
679             "",
680             "@Component",
681             "abstract class SimpleComponent {",
682             "  interface Parent {",
683             "    SimpleComponent build();",
684             "    SimpleComponent newSimpleComponent();",
685             "  }",
686             "",
687             "  @Component.Builder",
688             "  interface Builder extends Parent {}",
689             "}");
690     CompilerTests.daggerCompiler(componentFile)
691         .withProcessingOptions(compilerOptions)
692         .compile(
693             subject -> {
694               subject.hasErrorCount(1);
695               subject.hasErrorContaining(
696                       String.format(
697                           messages.inheritedTwoFactoryMethods(),
698                           process("test.SimpleComponent test.SimpleComponent.Parent.build()"),
699                           "test.SimpleComponent test.SimpleComponent.Parent.newSimpleComponent()"))
700                   .onSource(componentFile)
701                   .onLineContaining(process("interface Builder"));
702             });
703   }
704 
705   @Test
testMultipleSettersPerTypeFails()706   public void testMultipleSettersPerTypeFails() {
707     assume().that(compilerType).isEqualTo(JAVAC);
708     Source moduleFile =
709         CompilerTests.javaSource(
710             "test.TestModule",
711             "package test;",
712             "",
713             "import dagger.Module;",
714             "import dagger.Provides;",
715             "",
716             "@Module",
717             "final class TestModule {",
718             "  @Provides String s() { return \"\"; }",
719             "}");
720     Source componentFile =
721         javaFileBuilder("test.SimpleComponent")
722             .addLines(
723                 "package test;",
724                 "",
725                 "import dagger.Component;",
726                 "import javax.inject.Provider;",
727                 "",
728                 "@Component(modules = TestModule.class)",
729                 "abstract class SimpleComponent {",
730                 "  abstract String s();",
731                 "")
732             .addLinesIf(
733                 BUILDER,
734                 "  @Component.Builder",
735                 "  interface Builder {",
736                 "    SimpleComponent build();",
737                 "    void set1(TestModule s);",
738                 "    void set2(TestModule s);",
739                 "  }")
740             .addLinesIf(
741                 FACTORY,
742                 "  @Component.Factory",
743                 "  interface Factory {",
744                 "    SimpleComponent create(TestModule m1, TestModule m2);",
745                 "  }")
746             .addLines( //
747                 "}")
748             .buildSource();
749     CompilerTests.daggerCompiler(moduleFile, componentFile)
750         .withProcessingOptions(compilerOptions)
751         .compile(
752             subject -> {
753               subject.hasErrorCount(1);
754               String elements =
755                   creatorKind.equals(BUILDER)
756                       ? "[void test.SimpleComponent.Builder.set1(test.TestModule), "
757                           + "void test.SimpleComponent.Builder.set2(test.TestModule)]"
758                       : "[test.TestModule m1, test.TestModule m2]";
759               subject.hasErrorContaining(
760                       String.format(
761                           messages.multipleSettersForModuleOrDependencyType(),
762                           "test.TestModule",
763                           elements))
764                   .onSource(componentFile)
765                   .onLineContaining(process("interface Builder"));
766             });
767   }
768 
769   @Test
testMultipleSettersPerTypeIncludingResolvedGenericsFails()770   public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
771     assume().that(compilerType).isEqualTo(JAVAC);
772     Source moduleFile =
773         CompilerTests.javaSource(
774             "test.TestModule",
775             "package test;",
776             "",
777             "import dagger.Module;",
778             "import dagger.Provides;",
779             "",
780             "@Module",
781             "final class TestModule {",
782             "  @Provides String s() { return \"\"; }",
783             "}");
784     Source componentFile =
785         javaFileBuilder("test.SimpleComponent")
786             .addLines(
787                 "package test;",
788                 "",
789                 "import dagger.Component;",
790                 "import javax.inject.Provider;",
791                 "",
792                 "@Component(modules = TestModule.class)",
793                 "abstract class SimpleComponent {",
794                 "  abstract String s();",
795                 "")
796             .addLinesIf(
797                 BUILDER,
798                 "  interface Parent<T> {",
799                 "    void set1(T t);",
800                 "  }",
801                 "",
802                 "  @Component.Builder",
803                 "  interface Builder extends Parent<TestModule> {",
804                 "    SimpleComponent build();",
805                 "    void set2(TestModule s);",
806                 "  }")
807             .addLinesIf(
808                 FACTORY,
809                 "  interface Parent<C, T> {",
810                 "    C create(TestModule m1, T t);",
811                 "  }",
812                 "",
813                 "  @Component.Factory",
814                 "  interface Factory extends Parent<SimpleComponent, TestModule> {}")
815             .addLines( //
816                 "}")
817             .buildSource();
818     CompilerTests.daggerCompiler(moduleFile, componentFile)
819         .withProcessingOptions(compilerOptions)
820         .compile(
821             subject -> {
822               subject.hasErrorCount(1);
823               String elements =
824                   creatorKind.equals(BUILDER)
825                       ? "[void test.SimpleComponent.Builder.set1(test.TestModule), "
826                           + "void test.SimpleComponent.Builder.set2(test.TestModule)]"
827                       : "[test.TestModule m1, test.TestModule t]";
828               subject.hasErrorContaining(
829                       String.format(
830                           messages.multipleSettersForModuleOrDependencyType(),
831                           "test.TestModule",
832                           elements))
833                   .onSource(componentFile)
834                   .onLineContaining(process("interface Builder"));
835             });
836   }
837 
838   @Test
testExtraSettersFails()839   public void testExtraSettersFails() {
840     assume().that(compilerType).isEqualTo(JAVAC);
841     Source componentFile =
842         javaFileBuilder("test.SimpleComponent")
843             .addLines(
844                 "package test;",
845                 "",
846                 "import dagger.Component;",
847                 "import javax.inject.Provider;",
848                 "",
849                 "@Component(modules = AbstractModule.class)",
850                 "abstract class SimpleComponent {")
851             .addLinesIf(
852                 BUILDER,
853                 "  @Component.Builder",
854                 "  interface Builder {",
855                 "    SimpleComponent build();",
856                 "    void abstractModule(AbstractModule abstractModule);",
857                 "    void other(String s);",
858                 "  }")
859             .addLinesIf(
860                 FACTORY,
861                 "  @Component.Factory",
862                 "  interface Factory {",
863                 "    SimpleComponent create(AbstractModule abstractModule, String s);",
864                 "  }")
865             .addLines("}")
866             .buildSource();
867     Source abstractModule =
868         CompilerTests.javaSource(
869             "test.AbstractModule",
870             "package test;",
871             "",
872             "import dagger.Module;",
873             "",
874             "@Module",
875             "abstract class AbstractModule {}");
876     CompilerTests.daggerCompiler(componentFile, abstractModule)
877         .withProcessingOptions(compilerOptions)
878         .compile(
879             subject -> {
880               subject.hasErrorCount(1);
881               String elements =
882                   creatorKind.equals(BUILDER)
883                       ? "[void test.SimpleComponent.Builder.abstractModule(test.AbstractModule), "
884                           + "void test.SimpleComponent.Builder.other(String)]"
885                       : "[test.AbstractModule abstractModule, String s]";
886               subject.hasErrorContaining(String.format(messages.extraSetters(), elements))
887                   .onSource(componentFile)
888                   .onLineContaining(process("interface Builder"));
889             });
890   }
891 
892   @Test
testMissingSettersFail()893   public void testMissingSettersFail() {
894     assume().that(compilerType).isEqualTo(JAVAC);
895     Source moduleFile =
896         CompilerTests.javaSource(
897             "test.TestModule",
898             "package test;",
899             "",
900             "import dagger.Module;",
901             "import dagger.Provides;",
902             "",
903             "@Module",
904             "final class TestModule {",
905             "  TestModule(String unused) {}",
906             "  @Provides String s() { return null; }",
907             "}");
908     Source module2File =
909         CompilerTests.javaSource(
910             "test.Test2Module",
911             "package test;",
912             "",
913             "import dagger.Module;",
914             "import dagger.Provides;",
915             "",
916             "@Module",
917             "final class Test2Module {",
918             "  @Provides Integer i() { return null; }",
919             "}");
920     Source module3File =
921         CompilerTests.javaSource(
922             "test.Test3Module",
923             "package test;",
924             "",
925             "import dagger.Module;",
926             "import dagger.Provides;",
927             "",
928             "@Module",
929             "final class Test3Module {",
930             "  Test3Module(String unused) {}",
931             "  @Provides Double d() { return null; }",
932             "}");
933     Source componentFile =
934         preprocessedJavaSource(
935             "test.TestComponent",
936             "package test;",
937             "",
938             "import dagger.Component;",
939             "",
940             "@Component(",
941             "    modules = {TestModule.class, Test2Module.class, Test3Module.class},",
942             "    dependencies = OtherComponent.class",
943             ")",
944             "interface TestComponent {",
945             "  String string();",
946             "  Integer integer();",
947             "",
948             "  @Component.Builder",
949             "  interface Builder {",
950             "    TestComponent create();",
951             "  }",
952             "}");
953     Source otherComponent =
954         CompilerTests.javaSource(
955             "test.OtherComponent",
956             "package test;",
957             "",
958             "import dagger.Component;",
959             "",
960             "@Component",
961             "interface OtherComponent {}");
962     CompilerTests.daggerCompiler(
963             moduleFile, module2File, module3File, componentFile, otherComponent)
964         .withProcessingOptions(compilerOptions)
965         .compile(
966             subject -> {
967               subject.hasErrorCount(1);
968               subject.hasErrorContaining(
969                       // Ignores Test2Module because we can construct it ourselves.
970                       // TODO(sameb): Ignore Test3Module because it's not used within transitive
971                       // dependencies.
972                       String.format(
973                           messages.missingSetters(),
974                           "[test.TestModule, test.Test3Module, test.OtherComponent]"))
975                   .onSource(componentFile)
976                   .onLineContaining(process("interface Builder"));
977             });
978   }
979 
980   @Test
covariantFactoryMethodReturnType()981   public void covariantFactoryMethodReturnType() {
982     assume().that(compilerType).isEqualTo(JAVAC);
983     Source foo =
984         CompilerTests.javaSource(
985             "test.Foo",
986             "package test;",
987             "",
988             "import javax.inject.Inject;",
989             "",
990             "class Foo {",
991             "  @Inject Foo() {}",
992             "}");
993     Source supertype =
994         CompilerTests.javaSource(
995             "test.Supertype",
996             "package test;",
997             "",
998             "interface Supertype {",
999             "  Foo foo();",
1000             "}");
1001 
1002     Source component =
1003         preprocessedJavaSource(
1004             "test.HasSupertype",
1005             "package test;",
1006             "",
1007             "import dagger.Component;",
1008             "",
1009             "@Component",
1010             "interface HasSupertype extends Supertype {",
1011             "  @Component.Builder",
1012             "  interface Builder {",
1013             "    Supertype build();",
1014             "  }",
1015             "}");
1016 
1017     CompilerTests.daggerCompiler(foo, supertype, component)
1018         .withProcessingOptions(compilerOptions)
1019         .compile(
1020             subject -> {
1021               subject.hasErrorCount(0);
1022               subject.hasWarningCount(0);
1023             });
1024   }
1025 
1026   @Test
covariantFactoryMethodReturnType_hasNewMethod()1027   public void covariantFactoryMethodReturnType_hasNewMethod() {
1028     assume().that(compilerType).isEqualTo(JAVAC);
1029     Source foo =
1030         CompilerTests.javaSource(
1031             "test.Foo",
1032             "package test;",
1033             "",
1034             "import javax.inject.Inject;",
1035             "",
1036             "class Foo {",
1037             "  @Inject Foo() {}",
1038             "}");
1039     Source bar =
1040         CompilerTests.javaSource(
1041             "test.Bar",
1042             "package test;",
1043             "",
1044             "import javax.inject.Inject;",
1045             "",
1046             "class Bar {",
1047             "  @Inject Bar() {}",
1048             "}");
1049     Source supertype =
1050         CompilerTests.javaSource(
1051             "test.Supertype",
1052             "package test;",
1053             "",
1054             "interface Supertype {",
1055             "  Foo foo();",
1056             "}");
1057 
1058     Source component =
1059         preprocessedJavaSource(
1060             "test.HasSupertype",
1061             "package test;",
1062             "",
1063             "import dagger.Component;",
1064             "",
1065             "@Component",
1066             "interface HasSupertype extends Supertype {",
1067             "  Bar bar();",
1068             "",
1069             "  @Component.Builder",
1070             "  interface Builder {",
1071             "    Supertype build();",
1072             "  }",
1073             "}");
1074 
1075     CompilerTests.daggerCompiler(foo, bar, supertype, component)
1076         .withProcessingOptions(compilerOptions)
1077         .compile(
1078             subject -> {
1079               subject.hasErrorCount(0);
1080               subject.hasWarningContaining(
1081                       process(
1082                           "test.HasSupertype.Builder.build() returns test.Supertype, but "
1083                               + "test.HasSupertype declares additional component method(s): bar(). "
1084                               + "In order to provide type-safe access to these methods, override "
1085                               + "build() to return test.HasSupertype"))
1086                   .onSource(component)
1087                   .onLine(11);
1088             });
1089   }
1090 
1091   @Test
covariantFactoryMethodReturnType_hasNewMethod_factoryMethodInherited()1092   public void covariantFactoryMethodReturnType_hasNewMethod_factoryMethodInherited() {
1093     assume().that(compilerType).isEqualTo(JAVAC);
1094     Source foo =
1095         CompilerTests.javaSource(
1096             "test.Foo",
1097             "package test;",
1098             "",
1099             "import javax.inject.Inject;",
1100             "",
1101             "class Foo {",
1102             "  @Inject Foo() {}",
1103             "}");
1104     Source bar =
1105         CompilerTests.javaSource(
1106             "test.Bar",
1107             "package test;",
1108             "",
1109             "import javax.inject.Inject;",
1110             "",
1111             "class Bar {",
1112             "  @Inject Bar() {}",
1113             "}");
1114     Source supertype =
1115         CompilerTests.javaSource(
1116             "test.Supertype",
1117             "package test;",
1118             "",
1119             "interface Supertype {",
1120             "  Foo foo();",
1121             "}");
1122 
1123     Source creatorSupertype =
1124         preprocessedJavaSource(
1125             "test.CreatorSupertype",
1126             "package test;",
1127             "",
1128             "interface CreatorSupertype {",
1129             "  Supertype build();",
1130             "}");
1131 
1132     Source component =
1133         preprocessedJavaSource(
1134             "test.HasSupertype",
1135             "package test;",
1136             "",
1137             "import dagger.Component;",
1138             "",
1139             "@Component",
1140             "interface HasSupertype extends Supertype {",
1141             "  Bar bar();",
1142             "",
1143             "  @Component.Builder",
1144             "  interface Builder extends CreatorSupertype {}",
1145             "}");
1146 
1147     CompilerTests.daggerCompiler(foo, bar, supertype, creatorSupertype, component)
1148         .withProcessingOptions(compilerOptions)
1149         .compile(
1150             subject -> {
1151               subject.hasErrorCount(0);
1152               subject.hasWarningContaining(
1153                   process(
1154                       "test.HasSupertype.Builder.build() returns test.Supertype, but "
1155                           + "test.HasSupertype declares additional component method(s): bar(). "
1156                           + "In order to provide type-safe access to these methods, override "
1157                           + "build() to return test.HasSupertype"));
1158             });
1159   }
1160 
1161   @Test
testGenericsOnFactoryMethodFails()1162   public void testGenericsOnFactoryMethodFails() {
1163     Source componentFile =
1164         preprocessedJavaSource(
1165             "test.SimpleComponent",
1166             "package test;",
1167             "",
1168             "import dagger.Component;",
1169             "import javax.inject.Provider;",
1170             "",
1171             "@Component",
1172             "abstract class SimpleComponent {",
1173             "  @Component.Builder",
1174             "  interface Builder {",
1175             "    <T> SimpleComponent build();",
1176             "  }",
1177             "}");
1178     CompilerTests.daggerCompiler(componentFile)
1179         .withProcessingOptions(compilerOptions)
1180         .compile(
1181             subject -> {
1182               subject.hasErrorCount(1);
1183               subject.hasErrorContaining(messages.methodsMayNotHaveTypeParameters())
1184                   .onSource(componentFile)
1185                   .onLineContaining(process("<T> SimpleComponent build();"));
1186             });
1187   }
1188 
1189   @Test
testGenericsOnInheritedFactoryMethodFails()1190   public void testGenericsOnInheritedFactoryMethodFails() {
1191     Source componentFile =
1192         preprocessedJavaSource(
1193             "test.SimpleComponent",
1194             "package test;",
1195             "",
1196             "import dagger.Component;",
1197             "import javax.inject.Provider;",
1198             "",
1199             "@Component",
1200             "abstract class SimpleComponent {",
1201             "  interface Parent {",
1202             "    <T> SimpleComponent build();",
1203             "  }",
1204             "",
1205             "  @Component.Builder",
1206             "  interface Builder extends Parent {}",
1207             "}");
1208     CompilerTests.daggerCompiler(componentFile)
1209         .withProcessingOptions(compilerOptions)
1210         .compile(
1211             subject -> {
1212               subject.hasErrorCount(1);
1213               subject.hasErrorContaining(
1214                       String.format(
1215                           messages.inheritedMethodsMayNotHaveTypeParameters(),
1216                           process("test.SimpleComponent test.SimpleComponent.Parent.build()")))
1217                   .onSource(componentFile)
1218                   .onLineContaining(process("interface Builder"));
1219             });
1220   }
1221 }
1222