• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package dagger.internal.codegen;
17 
18 import com.google.common.collect.ImmutableList;
19 import com.google.testing.compile.JavaFileObjects;
20 import javax.tools.JavaFileObject;
21 import org.junit.Test;
22 import org.junit.runner.RunWith;
23 import org.junit.runners.JUnit4;
24 
25 import static com.google.common.truth.Truth.assertAbout;
26 import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
27 import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
28 
29 /** Tests for {@link dagger.Component.Builder} */
30 @RunWith(JUnit4.class)
31 public class ComponentBuilderTest {
32 
33   private static final ErrorMessages.ComponentBuilderMessages MSGS =
34       ErrorMessages.ComponentBuilderMessages.INSTANCE;
35 
36   @Test
testEmptyBuilder()37   public void testEmptyBuilder() {
38     JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
39         "package test;",
40         "",
41         "import javax.inject.Inject;",
42         "",
43         "final class SomeInjectableType {",
44         "  @Inject SomeInjectableType() {}",
45         "}");
46     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
47         "package test;",
48         "",
49         "import dagger.Component;",
50         "",
51         "import javax.inject.Provider;",
52         "",
53         "@Component",
54         "interface SimpleComponent {",
55         "  SomeInjectableType someInjectableType();",
56         "",
57         "  @Component.Builder",
58         "  static interface Builder {",
59         "     SimpleComponent build();",
60         "  }",
61         "}");
62     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
63         "test.DaggerSimpleComponent",
64         "package test;",
65         "",
66         "import javax.annotation.Generated;",
67         "import test.SimpleComponent",
68         "",
69         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
70         "public final class DaggerSimpleComponent implements SimpleComponent {",
71         "  private DaggerSimpleComponent(Builder builder) {",
72         "    assert builder != null;",
73         "    initialize(builder);",
74         "  }",
75         "",
76         "  public static SimpleComponent.Builder builder() {",
77         "    return new Builder();",
78         "  }",
79         "",
80         "  public static SimpleComponent create() {",
81         "    return builder().build();",
82         "  }",
83         "",
84         "  @SuppressWarnings(\"unchecked\")",
85         "  private void initialize(final Builder builder) {",
86         "  }",
87         "",
88         "  @Override",
89         "  public SomeInjectableType someInjectableType() {",
90         "    return SomeInjectableType_Factory.create().get();",
91         "  }",
92         "",
93         "  private static final class Builder implements SimpleComponent.Builder {",
94         "    @Override",
95         "    public SimpleComponent build() {",
96         "      return new DaggerSimpleComponent(this);",
97         "    }",
98         "  }",
99         "}");
100     assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
101         .processedWith(new ComponentProcessor())
102         .compilesWithoutError()
103         .and().generatesSources(generatedComponent);
104   }
105 
106   @Test
testUsesBuildAndSetterNames()107   public void testUsesBuildAndSetterNames() {
108     JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
109         "package test;",
110         "",
111         "import dagger.Module;",
112         "import dagger.Provides;",
113         "",
114         "@Module",
115         "final class TestModule {",
116         "  @Provides String string() { return null; }",
117         "}");
118 
119     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
120         "package test;",
121         "",
122         "import dagger.Component;",
123         "",
124         "@Component(modules = TestModule.class)",
125         "interface TestComponent {",
126         "  String string();",
127         "",
128         "  @Component.Builder",
129         "  interface Builder {",
130         "    Builder setTestModule(TestModule testModule);",
131         "    TestComponent create();",
132         "  }",
133         "}");
134     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
135         "test.DaggerTestComponent",
136         "package test;",
137         "",
138         "import javax.annotation.Generated;",
139         "import javax.inject.Provider;",
140         "import test.TestComponent;",
141         "",
142         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
143         "public final class DaggerTestComponent implements TestComponent {",
144         "  private Provider<String> stringProvider;",
145         "",
146         "  private DaggerTestComponent(Builder builder) {",
147         "    assert builder != null;",
148         "    initialize(builder);",
149         "  }",
150         "",
151         "  public static TestComponent.Builder builder() {",
152         "    return new Builder();",
153         "  }",
154         "",
155         "  public static TestComponent create() {",
156         "    return builder().create();",
157         "  }",
158         "",
159         "  @SuppressWarnings(\"unchecked\")",
160         "  private void initialize(final Builder builder) {",
161         "    this.stringProvider = TestModule_StringFactory.create(builder.testModule);",
162         "  }",
163         "",
164         "  @Override",
165         "  public String string() {",
166         "    return stringProvider.get();",
167         "  }",
168         "",
169         "  private static final class Builder implements TestComponent.Builder {",
170         "    private TestModule testModule;",
171         "",
172         "    @Override",
173         "    public TestComponent create() {",
174         "      if (testModule == null) {",
175         "        this.testModule = new TestModule();",
176         "      }",
177         "      return new DaggerTestComponent(this);",
178         "    }",
179         "",
180         "    @Override",
181         "    public Builder setTestModule(TestModule testModule) {",
182         "      if (testModule == null) {",
183         "        throw new NullPointerException();",
184         "      }",
185         "      this.testModule = testModule;",
186         "      return this;",
187         "    }",
188         "  }",
189         "}");
190     assertAbout(javaSources())
191         .that(ImmutableList.of(moduleFile, componentFile))
192         .processedWith(new ComponentProcessor())
193         .compilesWithoutError()
194         .and().generatesSources(generatedComponent);
195   }
196 
197   @Test
testIgnoresModulesNotInApi()198   public void testIgnoresModulesNotInApi() {
199     JavaFileObject module1 = JavaFileObjects.forSourceLines("test.TestModule1",
200         "package test;",
201         "",
202         "import dagger.Module;",
203         "import dagger.Provides;",
204         "",
205         "@Module",
206         "final class TestModule1 {",
207         "  @Provides String string() { return null; }",
208         "}");
209     JavaFileObject module2 = JavaFileObjects.forSourceLines("test.TestModule2",
210         "package test;",
211         "",
212         "import dagger.Module;",
213         "import dagger.Provides;",
214         "",
215         "@Module",
216         "final class TestModule2 {",
217         "  @Provides Integer integer() { return null; }",
218         "}");
219 
220     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
221         "package test;",
222         "",
223         "import dagger.Component;",
224         "",
225         "@Component(modules = {TestModule1.class, TestModule2.class})",
226         "interface TestComponent {",
227         "  String string();",
228         "  Integer integer();",
229         "",
230         "  @Component.Builder",
231         "  interface Builder {",
232         "    Builder testModule1(TestModule1 testModule1);",
233         "    TestComponent build();",
234         "  }",
235         "}");
236     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
237         "test.DaggerTestComponent",
238         "package test;",
239         "",
240         "import javax.annotation.Generated;",
241         "import javax.inject.Provider;",
242         "import test.TestComponent;",
243         "",
244         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
245         "public final class DaggerTestComponent implements TestComponent {",
246         "  private Provider<String> stringProvider;",
247         "  private Provider<Integer> integerProvider;",
248         "",
249         "  private DaggerTestComponent(Builder builder) {",
250         "    assert builder != null;",
251         "    initialize(builder);",
252         "  }",
253         "",
254         "  public static TestComponent.Builder builder() {",
255         "    return new Builder();",
256         "  }",
257         "",
258         "  public static TestComponent create() {",
259         "    return builder().build();",
260         "  }",
261         "",
262         "  @SuppressWarnings(\"unchecked\")",
263         "  private void initialize(final Builder builder) {",
264         "    this.stringProvider = TestModule1_StringFactory.create(builder.testModule1);",
265         "    this.integerProvider = TestModule2_IntegerFactory.create(builder.testModule2);",
266         "  }",
267         "",
268         "  @Override",
269         "  public String string() {",
270         "    return stringProvider.get();",
271         "  }",
272         "",
273         "  @Override",
274         "  public Integer integer() {",
275         "    return integerProvider.get();",
276         "  }",
277         "",
278         "  private static final class Builder implements TestComponent.Builder {",
279         "    private TestModule1 testModule1;",
280         "    private TestModule2 testModule2;",
281         "",
282         "    @Override",
283         "    public TestComponent build() {",
284         "      if (testModule1 == null) {",
285         "        this.testModule1 = new TestModule1();",
286         "      }",
287         "      if (testModule2 == null) {",
288         "        this.testModule2 = new TestModule2();",
289         "      }",
290         "      return new DaggerTestComponent(this);",
291         "    }",
292         "",
293         "    @Override",
294         "    public Builder testModule1(TestModule1 testModule1) {",
295         "      if (testModule1 == null) {",
296         "        throw new NullPointerException();",
297         "      }",
298         "      this.testModule1 = testModule1;",
299         "      return this;",
300         "    }",
301         "  }",
302         "}");
303     assertAbout(javaSources())
304         .that(ImmutableList.of(module1, module2, componentFile))
305         .processedWith(new ComponentProcessor())
306         .compilesWithoutError()
307         .and().generatesSources(generatedComponent);
308   }
309 
310   @Test
testMoreThanOneBuilderFails()311   public void testMoreThanOneBuilderFails() {
312     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
313         "package test;",
314         "",
315         "import dagger.Component;",
316         "",
317         "import javax.inject.Provider;",
318         "",
319         "@Component",
320         "interface SimpleComponent {",
321         "  @Component.Builder",
322         "  static interface Builder {",
323         "     SimpleComponent build();",
324         "  }",
325         "",
326         "  @Component.Builder",
327         "  interface Builder2 {",
328         "     SimpleComponent build();",
329         "  }",
330         "}");
331     assertAbout(javaSource()).that(componentFile)
332         .processedWith(new ComponentProcessor())
333         .failsToCompile()
334         .withErrorContaining(String.format(MSGS.moreThanOne(),
335             "[test.SimpleComponent.Builder, test.SimpleComponent.Builder2]"))
336         .in(componentFile);
337   }
338 
339   @Test
testBuilderGenericsFails()340   public void testBuilderGenericsFails() {
341     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
342         "package test;",
343         "",
344         "import dagger.Component;",
345         "",
346         "import javax.inject.Provider;",
347         "",
348         "@Component",
349         "interface SimpleComponent {",
350         "  @Component.Builder",
351         "  interface Builder<T> {",
352         "     SimpleComponent build();",
353         "  }",
354         "}");
355     assertAbout(javaSource()).that(componentFile)
356         .processedWith(new ComponentProcessor())
357         .failsToCompile()
358         .withErrorContaining(MSGS.generics())
359         .in(componentFile);
360   }
361 
362   @Test
testBuilderNotInComponentFails()363   public void testBuilderNotInComponentFails() {
364     JavaFileObject builder = JavaFileObjects.forSourceLines("test.Builder",
365         "package test;",
366         "",
367         "import dagger.Component;",
368         "",
369         "@Component.Builder",
370         "interface Builder {}");
371     assertAbout(javaSource()).that(builder)
372         .processedWith(new ComponentProcessor())
373         .failsToCompile()
374         .withErrorContaining(MSGS.mustBeInComponent())
375         .in(builder);
376   }
377 
378   @Test
testBuilderMissingBuildMethodFails()379   public void testBuilderMissingBuildMethodFails() {
380     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
381         "package test;",
382         "",
383         "import dagger.Component;",
384         "",
385         "import javax.inject.Provider;",
386         "",
387         "@Component",
388         "interface SimpleComponent {",
389         "  @Component.Builder",
390         "  interface Builder {}",
391         "}");
392     assertAbout(javaSource()).that(componentFile)
393         .processedWith(new ComponentProcessor())
394         .failsToCompile()
395         .withErrorContaining(MSGS.missingBuildMethod())
396         .in(componentFile);
397   }
398 
399   @Test
testPrivateBuilderFails()400   public void testPrivateBuilderFails() {
401     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
402         "package test;",
403         "",
404         "import dagger.Component;",
405         "",
406         "import javax.inject.Provider;",
407         "",
408         "@Component",
409         "abstract class SimpleComponent {",
410         "  @Component.Builder",
411         "  private interface Builder {}",
412         "}");
413     assertAbout(javaSource()).that(componentFile)
414         .processedWith(new ComponentProcessor())
415         .failsToCompile()
416         .withErrorContaining(MSGS.isPrivate())
417         .in(componentFile);
418   }
419 
420   @Test
testNonStaticBuilderFails()421   public void testNonStaticBuilderFails() {
422     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
423         "package test;",
424         "",
425         "import dagger.Component;",
426         "",
427         "import javax.inject.Provider;",
428         "",
429         "@Component",
430         "abstract class SimpleComponent {",
431         "  @Component.Builder",
432         "  abstract class Builder {}",
433         "}");
434     assertAbout(javaSource()).that(componentFile)
435         .processedWith(new ComponentProcessor())
436         .failsToCompile()
437         .withErrorContaining(MSGS.mustBeStatic())
438         .in(componentFile);
439   }
440 
441   @Test
testNonAbstractBuilderFails()442   public void testNonAbstractBuilderFails() {
443     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
444         "package test;",
445         "",
446         "import dagger.Component;",
447         "",
448         "import javax.inject.Provider;",
449         "",
450         "@Component",
451         "abstract class SimpleComponent {",
452         "  @Component.Builder",
453         "  static class Builder {}",
454         "}");
455     assertAbout(javaSource()).that(componentFile)
456         .processedWith(new ComponentProcessor())
457         .failsToCompile()
458         .withErrorContaining(MSGS.mustBeAbstract());
459   }
460 
461   @Test
testBuilderOneCxtorWithArgsFails()462   public void testBuilderOneCxtorWithArgsFails() {
463     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
464         "package test;",
465         "",
466         "import dagger.Component;",
467         "",
468         "import javax.inject.Provider;",
469         "",
470         "@Component",
471         "abstract class SimpleComponent {",
472         "  @Component.Builder",
473         "  static abstract class Builder {",
474         "    Builder(String unused) {}",
475         "  }",
476         "}");
477     assertAbout(javaSource()).that(componentFile)
478         .processedWith(new ComponentProcessor())
479         .failsToCompile()
480         .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
481         .in(componentFile);
482   }
483 
484   @Test
testBuilderMoreThanOneCxtorFails()485   public void testBuilderMoreThanOneCxtorFails() {
486     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
487         "package test;",
488         "",
489         "import dagger.Component;",
490         "",
491         "import javax.inject.Provider;",
492         "",
493         "@Component",
494         "abstract class SimpleComponent {",
495         "  @Component.Builder",
496         "  static abstract class Builder {",
497         "    Builder() {}",
498         "    Builder(String unused) {}",
499         "  }",
500         "}");
501     assertAbout(javaSource()).that(componentFile)
502         .processedWith(new ComponentProcessor())
503         .failsToCompile()
504         .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
505         .in(componentFile);
506   }
507 
508   @Test
testBuilderEnumFails()509   public void testBuilderEnumFails() {
510     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
511         "package test;",
512         "",
513         "import dagger.Component;",
514         "",
515         "import javax.inject.Provider;",
516         "",
517         "@Component",
518         "abstract class SimpleComponent {",
519         "  @Component.Builder",
520         "  enum Builder {}",
521         "}");
522     assertAbout(javaSource()).that(componentFile)
523         .processedWith(new ComponentProcessor())
524         .failsToCompile()
525         .withErrorContaining(MSGS.mustBeClassOrInterface())
526         .in(componentFile);
527   }
528 
529   @Test
testBuilderBuildReturnsWrongTypeFails()530   public void testBuilderBuildReturnsWrongTypeFails() {
531     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
532         "package test;",
533         "",
534         "import dagger.Component;",
535         "",
536         "import javax.inject.Provider;",
537         "",
538         "@Component",
539         "abstract class SimpleComponent {",
540         "  @Component.Builder",
541         "  interface Builder {",
542         "    String build();",
543         "  }",
544         "}");
545     assertAbout(javaSource()).that(componentFile)
546         .processedWith(new ComponentProcessor())
547         .failsToCompile()
548         .withErrorContaining(MSGS.buildMustReturnComponentType())
549             .in(componentFile).onLine(11);
550   }
551 
552   @Test
testInheritedBuilderBuildReturnsWrongTypeFails()553   public void testInheritedBuilderBuildReturnsWrongTypeFails() {
554     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
555         "package test;",
556         "",
557         "import dagger.Component;",
558         "",
559         "import javax.inject.Provider;",
560         "",
561         "@Component",
562         "abstract class SimpleComponent {",
563         "  interface Parent {",
564         "    String build();",
565         "  }",
566         "",
567         "  @Component.Builder",
568         "  interface Builder extends Parent {}",
569         "}");
570     assertAbout(javaSource()).that(componentFile)
571         .processedWith(new ComponentProcessor())
572         .failsToCompile()
573         .withErrorContaining(
574             String.format(MSGS.inheritedBuildMustReturnComponentType(), "build"))
575             .in(componentFile).onLine(14);
576   }
577 
578   @Test
testTwoBuildMethodsFails()579   public void testTwoBuildMethodsFails() {
580     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
581         "package test;",
582         "",
583         "import dagger.Component;",
584         "",
585         "import javax.inject.Provider;",
586         "",
587         "@Component",
588         "abstract class SimpleComponent {",
589         "  @Component.Builder",
590         "  interface Builder {",
591         "    SimpleComponent build();",
592         "    SimpleComponent create();",
593         "  }",
594         "}");
595     assertAbout(javaSource()).that(componentFile)
596         .processedWith(new ComponentProcessor())
597         .failsToCompile()
598         .withErrorContaining(String.format(MSGS.twoBuildMethods(), "build()"))
599             .in(componentFile).onLine(12);
600   }
601 
602   @Test
testInheritedTwoBuildMethodsFails()603   public void testInheritedTwoBuildMethodsFails() {
604     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
605         "package test;",
606         "",
607         "import dagger.Component;",
608         "",
609         "import javax.inject.Provider;",
610         "",
611         "@Component",
612         "abstract class SimpleComponent {",
613         "  interface Parent {",
614         "    SimpleComponent build();",
615         "    SimpleComponent create();",
616         "  }",
617         "",
618         "  @Component.Builder",
619         "  interface Builder extends Parent {}",
620         "}");
621     assertAbout(javaSource()).that(componentFile)
622         .processedWith(new ComponentProcessor())
623         .failsToCompile()
624         .withErrorContaining(
625             String.format(MSGS.inheritedTwoBuildMethods(), "create()", "build()"))
626             .in(componentFile).onLine(15);
627   }
628 
629   @Test
testMoreThanOneArgFails()630   public void testMoreThanOneArgFails() {
631     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
632         "package test;",
633         "",
634         "import dagger.Component;",
635         "",
636         "import javax.inject.Provider;",
637         "",
638         "@Component",
639         "abstract class SimpleComponent {",
640         "  @Component.Builder",
641         "  interface Builder {",
642         "    SimpleComponent build();",
643         "    Builder set(String s, Integer i);",
644         "    Builder set(Number n, Double d);",
645         "  }",
646         "}");
647     assertAbout(javaSource()).that(componentFile)
648         .processedWith(new ComponentProcessor())
649         .failsToCompile()
650         .withErrorContaining(MSGS.methodsMustTakeOneArg())
651             .in(componentFile).onLine(12)
652         .and().withErrorContaining(MSGS.methodsMustTakeOneArg())
653             .in(componentFile).onLine(13);
654   }
655 
656   @Test
testInheritedMoreThanOneArgFails()657   public void testInheritedMoreThanOneArgFails() {
658     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
659         "package test;",
660         "",
661         "import dagger.Component;",
662         "",
663         "import javax.inject.Provider;",
664         "",
665         "@Component",
666         "abstract class SimpleComponent {",
667         "  interface Parent {",
668         "    SimpleComponent build();",
669         "    Builder set1(String s, Integer i);",
670         "  }",
671         "",
672         "  @Component.Builder",
673         "  interface Builder extends Parent {}",
674         "}");
675     assertAbout(javaSource()).that(componentFile)
676         .processedWith(new ComponentProcessor())
677         .failsToCompile()
678         .withErrorContaining(
679             String.format(MSGS.inheritedMethodsMustTakeOneArg(),
680                 "set1(java.lang.String,java.lang.Integer)"))
681             .in(componentFile).onLine(15);
682   }
683 
684   @Test
testSetterReturningNonVoidOrBuilderFails()685   public void testSetterReturningNonVoidOrBuilderFails() {
686     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
687         "package test;",
688         "",
689         "import dagger.Component;",
690         "",
691         "import javax.inject.Provider;",
692         "",
693         "@Component",
694         "abstract class SimpleComponent {",
695         "  @Component.Builder",
696         "  interface Builder {",
697         "    SimpleComponent build();",
698         "    String set(Integer i);",
699         "  }",
700         "}");
701     assertAbout(javaSource()).that(componentFile)
702         .processedWith(new ComponentProcessor())
703         .failsToCompile()
704         .withErrorContaining(MSGS.methodsMustReturnVoidOrBuilder())
705             .in(componentFile).onLine(12);
706   }
707 
708   @Test
testInheritedSetterReturningNonVoidOrBuilderFails()709   public void testInheritedSetterReturningNonVoidOrBuilderFails() {
710     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
711         "package test;",
712         "",
713         "import dagger.Component;",
714         "",
715         "import javax.inject.Provider;",
716         "",
717         "@Component",
718         "abstract class SimpleComponent {",
719         "  interface Parent {",
720         "    SimpleComponent build();",
721         "    String set(Integer i);",
722         "  }",
723         "",
724         "  @Component.Builder",
725         "  interface Builder extends Parent {}",
726         "}");
727     assertAbout(javaSource()).that(componentFile)
728         .processedWith(new ComponentProcessor())
729         .failsToCompile()
730         .withErrorContaining(
731             String.format(MSGS.inheritedMethodsMustReturnVoidOrBuilder(),
732                 "set(java.lang.Integer)"))
733             .in(componentFile).onLine(15);
734   }
735 
736   @Test
testGenericsOnSetterMethodFails()737   public void testGenericsOnSetterMethodFails() {
738     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
739         "package test;",
740         "",
741         "import dagger.Component;",
742         "",
743         "import javax.inject.Provider;",
744         "",
745         "@Component",
746         "abstract class SimpleComponent {",
747         "  @Component.Builder",
748         "  interface Builder {",
749         "    SimpleComponent build();",
750         "    <T> Builder set(T t);",
751         "  }",
752         "}");
753     assertAbout(javaSource()).that(componentFile)
754         .processedWith(new ComponentProcessor())
755         .failsToCompile()
756         .withErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
757             .in(componentFile).onLine(12);
758   }
759 
760   @Test
testGenericsOnInheritedSetterMethodFails()761   public void testGenericsOnInheritedSetterMethodFails() {
762     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
763         "package test;",
764         "",
765         "import dagger.Component;",
766         "",
767         "import javax.inject.Provider;",
768         "",
769         "@Component",
770         "abstract class SimpleComponent {",
771         "  interface Parent {",
772         "    SimpleComponent build();",
773         "    <T> Builder set(T t);",
774         "  }",
775         "",
776         "  @Component.Builder",
777         "  interface Builder extends Parent {}",
778         "}");
779     assertAbout(javaSource()).that(componentFile)
780         .processedWith(new ComponentProcessor())
781         .failsToCompile()
782         .withErrorContaining(
783             String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
784             .in(componentFile).onLine(15);
785   }
786 
787   @Test
testMultipleSettersPerTypeFails()788   public void testMultipleSettersPerTypeFails() {
789     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
790         "package test;",
791         "",
792         "import dagger.Component;",
793         "",
794         "import javax.inject.Provider;",
795         "",
796         "@Component",
797         "abstract class SimpleComponent {",
798         "  @Component.Builder",
799         "  interface Builder {",
800         "    SimpleComponent build();",
801         "    void set1(String s);",
802         "    void set2(String s);",
803         "  }",
804         "}");
805     assertAbout(javaSource()).that(componentFile)
806         .processedWith(new ComponentProcessor())
807         .failsToCompile()
808         .withErrorContaining(
809             String.format(MSGS.manyMethodsForType(),
810                   "java.lang.String", "[set1(java.lang.String), set2(java.lang.String)]"))
811             .in(componentFile).onLine(10);
812   }
813 
814   @Test
testMultipleSettersPerTypeIncludingResolvedGenericsFails()815   public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
816     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
817         "package test;",
818         "",
819         "import dagger.Component;",
820         "",
821         "import javax.inject.Provider;",
822         "",
823         "@Component",
824         "abstract class SimpleComponent {",
825         "  interface Parent<T> {",
826         "    void set1(T t);",
827         "  }",
828         "",
829         "  @Component.Builder",
830         "  interface Builder extends Parent<String> {",
831         "    SimpleComponent build();",
832         "    void set2(String s);",
833         "  }",
834         "}");
835     assertAbout(javaSource()).that(componentFile)
836         .processedWith(new ComponentProcessor())
837         .failsToCompile()
838         .withErrorContaining(
839             String.format(MSGS.manyMethodsForType(),
840                   "java.lang.String", "[set1(T), set2(java.lang.String)]"))
841             .in(componentFile).onLine(14);
842   }
843 
844   @Test
testExtraSettersFails()845   public void testExtraSettersFails() {
846     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
847         "package test;",
848         "",
849         "import dagger.Component;",
850         "",
851         "import javax.inject.Provider;",
852         "",
853         "@Component",
854         "abstract class SimpleComponent {",
855         "  @Component.Builder",
856         "  interface Builder {",
857         "    SimpleComponent build();",
858         "    void set1(String s);",
859         "    void set2(Integer s);",
860         "  }",
861         "}");
862     assertAbout(javaSource()).that(componentFile)
863         .processedWith(new ComponentProcessor())
864         .failsToCompile()
865         .withErrorContaining(
866             String.format(MSGS.extraSetters(),
867                   "[void test.SimpleComponent.Builder.set1(String),"
868                   + " void test.SimpleComponent.Builder.set2(Integer)]"))
869             .in(componentFile).onLine(10);
870 
871   }
872 
873   @Test
testMissingSettersFail()874   public void testMissingSettersFail() {
875     JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
876         "package test;",
877         "",
878         "import dagger.Module;",
879         "import dagger.Provides;",
880         "",
881         "@Module",
882         "final class TestModule {",
883         "  TestModule(String unused) {}",
884         "  @Provides String s() { return null; }",
885         "}");
886     JavaFileObject module2File = JavaFileObjects.forSourceLines("test.Test2Module",
887         "package test;",
888         "",
889         "import dagger.Module;",
890         "import dagger.Provides;",
891         "",
892         "@Module",
893         "final class Test2Module {",
894         "  @Provides Integer i() { return null; }",
895         "}");
896     JavaFileObject module3File = JavaFileObjects.forSourceLines("test.Test3Module",
897         "package test;",
898         "",
899         "import dagger.Module;",
900         "import dagger.Provides;",
901         "",
902         "@Module",
903         "final class Test3Module {",
904         "  Test3Module(String unused) {}",
905         "  @Provides Double d() { return null; }",
906         "}");
907     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
908         "package test;",
909         "",
910         "import dagger.Component;",
911         "",
912         "@Component(modules = {TestModule.class, Test2Module.class, Test3Module.class},",
913         "           dependencies = OtherComponent.class)",
914         "interface TestComponent {",
915         "  String string();",
916         "  Integer integer();",
917         "",
918         "  @Component.Builder",
919         "  interface Builder {",
920         "    TestComponent create();",
921         "  }",
922         "}");
923     JavaFileObject otherComponent = JavaFileObjects.forSourceLines("test.OtherComponent",
924         "package test;",
925         "",
926         "import dagger.Component;",
927         "",
928         "@Component",
929         "interface OtherComponent {}");
930     assertAbout(javaSources())
931         .that(ImmutableList.of(moduleFile, module2File, module3File, componentFile, otherComponent))
932         .processedWith(new ComponentProcessor())
933         .failsToCompile()
934         .withErrorContaining(
935             // Ignores Test2Module because we can construct it ourselves.
936             // TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
937             String.format(MSGS.missingSetters(),
938                 "[test.TestModule, test.Test3Module, test.OtherComponent]"))
939             .in(componentFile).onLine(12);
940   }
941 }
942