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 */
16package dagger.internal.codegen;
17
18import com.google.common.collect.ImmutableList;
19import com.google.testing.compile.JavaFileObjects;
20import javax.tools.JavaFileObject;
21import org.junit.Test;
22import org.junit.runner.RunWith;
23import org.junit.runners.JUnit4;
24
25import static com.google.common.truth.Truth.assertAbout;
26import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
27import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
28
29/** Tests for {@link dagger.Subcomponent.Builder} validation. */
30@RunWith(JUnit4.class)
31public class SubcomponentBuilderValidationTest {
32
33  private static final ErrorMessages.SubcomponentBuilderMessages MSGS =
34      new ErrorMessages.SubcomponentBuilderMessages();
35
36  @Test
37  public void testRefSubcomponentAndSubBuilderFails() {
38    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
39        "package test;",
40        "",
41        "import dagger.Component;",
42        "",
43        "import javax.inject.Provider;",
44        "",
45        "@Component",
46        "interface ParentComponent {",
47        "  ChildComponent child();",
48        "  ChildComponent.Builder builder();",
49        "}");
50    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
51        "package test;",
52        "",
53        "import dagger.Subcomponent;",
54        "",
55        "@Subcomponent",
56        "interface ChildComponent {",
57        "  @Subcomponent.Builder",
58        "  static interface Builder {",
59        "    ChildComponent build();",
60        "  }",
61        "}");
62    assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
63        .processedWith(new ComponentProcessor())
64        .failsToCompile()
65        .withErrorContaining(String.format(MSGS.moreThanOneRefToSubcomponent(),
66            "test.ChildComponent", "[child(), builder()]"))
67        .in(componentFile);
68  }
69
70  @Test
71  public void testRefSubBuilderTwiceFails() {
72    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
73        "package test;",
74        "",
75        "import dagger.Component;",
76        "",
77        "import javax.inject.Provider;",
78        "",
79        "@Component",
80        "interface ParentComponent {",
81        "  ChildComponent.Builder builder1();",
82        "  ChildComponent.Builder builder2();",
83        "}");
84    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
85        "package test;",
86        "",
87        "import dagger.Subcomponent;",
88        "",
89        "@Subcomponent",
90        "interface ChildComponent {",
91        "  @Subcomponent.Builder",
92        "  static interface Builder {",
93        "    ChildComponent build();",
94        "  }",
95        "}");
96    assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
97        .processedWith(new ComponentProcessor())
98        .failsToCompile()
99        .withErrorContaining(String.format(MSGS.moreThanOneRefToSubcomponent(),
100            "test.ChildComponent", "[builder1(), builder2()]"))
101        .in(componentFile);
102  }
103
104  @Test
105  public void testMoreThanOneBuilderFails() {
106    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
107        "package test;",
108        "",
109        "import dagger.Component;",
110        "",
111        "import javax.inject.Provider;",
112        "",
113        "@Component",
114        "interface ParentComponent {",
115        "  ChildComponent.Builder1 build();",
116        "}");
117    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
118        "package test;",
119        "",
120        "import dagger.Subcomponent;",
121        "",
122        "@Subcomponent",
123        "interface ChildComponent {",
124        "  @Subcomponent.Builder",
125        "  static interface Builder1 {",
126        "    ChildComponent build();",
127        "  }",
128        "",
129        "  @Subcomponent.Builder",
130        "  static interface Builder2 {",
131        "    ChildComponent build();",
132        "  }",
133        "}");
134    assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
135        .processedWith(new ComponentProcessor())
136        .failsToCompile()
137        .withErrorContaining(String.format(MSGS.moreThanOne(),
138            "[test.ChildComponent.Builder1, test.ChildComponent.Builder2]"))
139        .in(childComponentFile);
140  }
141
142  @Test
143  public void testBuilderGenericsFails() {
144    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
145        "package test;",
146        "",
147        "import dagger.Component;",
148        "",
149        "import javax.inject.Provider;",
150        "",
151        "@Component",
152        "interface ParentComponent {",
153        "  ChildComponent.Builder1 build();",
154        "}");
155    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
156        "package test;",
157        "",
158        "import dagger.Subcomponent;",
159        "",
160        "@Subcomponent",
161        "interface ChildComponent {",
162        "  @Subcomponent.Builder",
163        "  interface Builder<T> {",
164        "     ChildComponent build();",
165        "  }",
166        "}");
167    assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
168        .processedWith(new ComponentProcessor())
169        .failsToCompile()
170        .withErrorContaining(MSGS.generics())
171        .in(childComponentFile);
172  }
173
174  @Test
175  public void testBuilderNotInComponentFails() {
176    JavaFileObject builder = JavaFileObjects.forSourceLines("test.Builder",
177        "package test;",
178        "",
179        "import dagger.Subcomponent;",
180        "",
181        "@Subcomponent.Builder",
182        "interface Builder {}");
183    assertAbout(javaSource()).that(builder)
184        .processedWith(new ComponentProcessor())
185        .failsToCompile()
186        .withErrorContaining(MSGS.mustBeInComponent())
187        .in(builder);
188  }
189
190  @Test
191  public void testBuilderMissingBuildMethodFails() {
192    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
193        "package test;",
194        "",
195        "import dagger.Component;",
196        "",
197        "import javax.inject.Provider;",
198        "",
199        "@Component",
200        "interface ParentComponent {",
201        "  ChildComponent.Builder1 build();",
202        "}");
203    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
204        "package test;",
205        "",
206        "import dagger.Subcomponent;",
207        "",
208        "@Subcomponent",
209        "interface ChildComponent {",
210        "  @Subcomponent.Builder",
211        "  interface Builder {}",
212        "}");
213    assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
214        .processedWith(new ComponentProcessor())
215        .failsToCompile()
216        .withErrorContaining(MSGS.missingBuildMethod())
217        .in(childComponentFile);
218  }
219
220  @Test
221  public void testPrivateBuilderFails() {
222    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
223        "package test;",
224        "",
225        "import dagger.Subcomponent;",
226        "",
227        "@Subcomponent",
228        "abstract class ChildComponent {",
229        "  @Subcomponent.Builder",
230        "  private interface Builder {}",
231        "}");
232    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
233        .processedWith(new ComponentProcessor())
234        .failsToCompile()
235        .withErrorContaining(MSGS.isPrivate())
236        .in(childComponentFile);
237  }
238
239  @Test
240  public void testNonStaticBuilderFails() {
241    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
242        "package test;",
243        "",
244        "import dagger.Subcomponent;",
245        "",
246        "@Subcomponent",
247        "abstract class ChildComponent {",
248        "  @Subcomponent.Builder",
249        "  abstract class Builder {}",
250        "}");
251    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
252        .processedWith(new ComponentProcessor())
253        .failsToCompile()
254        .withErrorContaining(MSGS.mustBeStatic())
255        .in(childComponentFile);
256  }
257
258  @Test
259  public void testNonAbstractBuilderFails() {
260    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
261        "package test;",
262        "",
263        "import dagger.Subcomponent;",
264        "",
265        "@Subcomponent",
266        "abstract class ChildComponent {",
267        "  @Subcomponent.Builder",
268        "  static class Builder {}",
269        "}");
270    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
271        .processedWith(new ComponentProcessor())
272        .failsToCompile()
273        .withErrorContaining(MSGS.mustBeAbstract())
274        .in(childComponentFile);
275  }
276
277  @Test
278  public void testBuilderOneCxtorWithArgsFails() {
279    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
280        "package test;",
281        "",
282        "import dagger.Subcomponent;",
283        "",
284        "@Subcomponent",
285        "abstract class ChildComponent {",
286        "  @Subcomponent.Builder",
287        "  static abstract class Builder {",
288        "    Builder(String unused) {}",
289        "  }",
290        "}");
291    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
292        .processedWith(new ComponentProcessor())
293        .failsToCompile()
294        .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
295        .in(childComponentFile);
296  }
297
298  @Test
299  public void testBuilderMoreThanOneCxtorFails() {
300    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
301        "package test;",
302        "",
303        "import dagger.Subcomponent;",
304        "",
305        "@Subcomponent",
306        "abstract class ChildComponent {",
307        "  @Subcomponent.Builder",
308        "  static abstract class Builder {",
309        "    Builder() {}",
310        "    Builder(String unused) {}",
311        "  }",
312        "}");
313    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
314        .processedWith(new ComponentProcessor())
315        .failsToCompile()
316        .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
317        .in(childComponentFile);
318  }
319
320  @Test
321  public void testBuilderEnumFails() {
322    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
323        "package test;",
324        "",
325        "import dagger.Subcomponent;",
326        "",
327        "@Subcomponent",
328        "abstract class ChildComponent {",
329        "  @Subcomponent.Builder",
330        "  enum Builder {}",
331        "}");
332    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
333        .processedWith(new ComponentProcessor())
334        .failsToCompile()
335        .withErrorContaining(MSGS.mustBeClassOrInterface())
336        .in(childComponentFile);
337  }
338
339  @Test
340  public void testBuilderBuildReturnsWrongTypeFails() {
341    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
342        "package test;",
343        "",
344        "import dagger.Subcomponent;",
345        "",
346        "@Subcomponent",
347        "abstract class ChildComponent {",
348        "  @Subcomponent.Builder",
349        "  interface Builder {",
350        "    String build();",
351        "  }",
352        "}");
353    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
354        .processedWith(new ComponentProcessor())
355        .failsToCompile()
356        .withErrorContaining(MSGS.buildMustReturnComponentType())
357            .in(childComponentFile).onLine(9);
358  }
359
360  @Test
361  public void testInheritedBuilderBuildReturnsWrongTypeFails() {
362    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
363        "package test;",
364        "",
365        "import dagger.Subcomponent;",
366        "",
367        "@Subcomponent",
368        "abstract class ChildComponent {",
369        "  interface Parent {",
370        "    String build();",
371        "  }",
372        "",
373        "  @Subcomponent.Builder",
374        "  interface Builder extends Parent {}",
375        "}");
376    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
377        .processedWith(new ComponentProcessor())
378        .failsToCompile()
379        .withErrorContaining(
380            String.format(MSGS.inheritedBuildMustReturnComponentType(), "build"))
381            .in(childComponentFile).onLine(12);
382  }
383
384  @Test
385  public void testTwoBuildMethodsFails() {
386    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
387        "package test;",
388        "",
389        "import dagger.Subcomponent;",
390        "",
391        "@Subcomponent",
392        "abstract class ChildComponent {",
393        "  @Subcomponent.Builder",
394        "  interface Builder {",
395        "    ChildComponent build();",
396        "    ChildComponent create();",
397        "  }",
398        "}");
399    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
400        .processedWith(new ComponentProcessor())
401        .failsToCompile()
402        .withErrorContaining(String.format(MSGS.twoBuildMethods(), "build()"))
403            .in(childComponentFile).onLine(10);
404  }
405
406  @Test
407  public void testInheritedTwoBuildMethodsFails() {
408    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
409        "package test;",
410        "",
411        "import dagger.Subcomponent;",
412        "",
413        "@Subcomponent",
414        "abstract class ChildComponent {",
415        "  interface Parent {",
416        "    ChildComponent build();",
417        "    ChildComponent create();",
418        "  }",
419        "",
420        "  @Subcomponent.Builder",
421        "  interface Builder extends Parent {}",
422        "}");
423    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
424        .processedWith(new ComponentProcessor())
425        .failsToCompile()
426        .withErrorContaining(
427            String.format(MSGS.inheritedTwoBuildMethods(), "create()", "build()"))
428            .in(childComponentFile).onLine(13);
429  }
430
431  @Test
432  public void testMoreThanOneArgFails() {
433    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
434        "package test;",
435        "",
436        "import dagger.Subcomponent;",
437        "",
438        "@Subcomponent",
439        "abstract class ChildComponent {",
440        "  @Subcomponent.Builder",
441        "  interface Builder {",
442        "    ChildComponent build();",
443        "    Builder set(String s, Integer i);",
444        "    Builder set(Number n, Double d);",
445        "  }",
446        "}");
447    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
448        .processedWith(new ComponentProcessor())
449        .failsToCompile()
450        .withErrorContaining(MSGS.methodsMustTakeOneArg())
451            .in(childComponentFile).onLine(10)
452        .and().withErrorContaining(MSGS.methodsMustTakeOneArg())
453            .in(childComponentFile).onLine(11);
454  }
455
456  @Test
457  public void testInheritedMoreThanOneArgFails() {
458    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
459        "package test;",
460        "",
461        "import dagger.Subcomponent;",
462        "",
463        "@Subcomponent",
464        "abstract class ChildComponent {",
465        "  interface Parent {",
466        "    ChildComponent build();",
467        "    Builder set1(String s, Integer i);",
468        "  }",
469        "",
470        "  @Subcomponent.Builder",
471        "  interface Builder extends Parent {}",
472        "}");
473    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
474        .processedWith(new ComponentProcessor())
475        .failsToCompile()
476        .withErrorContaining(
477            String.format(MSGS.inheritedMethodsMustTakeOneArg(),
478                "set1(java.lang.String,java.lang.Integer)"))
479            .in(childComponentFile).onLine(13);
480  }
481
482  @Test
483  public void testSetterReturningNonVoidOrBuilderFails() {
484    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
485        "package test;",
486        "",
487        "import dagger.Subcomponent;",
488        "",
489        "@Subcomponent",
490        "abstract class ChildComponent {",
491        "  @Subcomponent.Builder",
492        "  interface Builder {",
493        "    ChildComponent build();",
494        "    String set(Integer i);",
495        "  }",
496        "}");
497    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
498        .processedWith(new ComponentProcessor())
499        .failsToCompile()
500        .withErrorContaining(MSGS.methodsMustReturnVoidOrBuilder())
501            .in(childComponentFile).onLine(10);
502  }
503
504  @Test
505  public void testInheritedSetterReturningNonVoidOrBuilderFails() {
506    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
507        "package test;",
508        "",
509        "import dagger.Subcomponent;",
510        "",
511        "@Subcomponent",
512        "abstract class ChildComponent {",
513        "  interface Parent {",
514        "    ChildComponent build();",
515        "    String set(Integer i);",
516        "  }",
517        "",
518        "  @Subcomponent.Builder",
519        "  interface Builder extends Parent {}",
520        "}");
521    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
522        .processedWith(new ComponentProcessor())
523        .failsToCompile()
524        .withErrorContaining(
525            String.format(MSGS.inheritedMethodsMustReturnVoidOrBuilder(),
526                "set(java.lang.Integer)"))
527            .in(childComponentFile).onLine(13);
528  }
529
530  @Test
531  public void testGenericsOnSetterMethodFails() {
532    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
533        "package test;",
534        "",
535        "import dagger.Subcomponent;",
536        "",
537        "@Subcomponent",
538        "abstract class ChildComponent {",
539        "  @Subcomponent.Builder",
540        "  interface Builder {",
541        "    ChildComponent build();",
542        "    <T> Builder set(T t);",
543        "  }",
544        "}");
545    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
546        .processedWith(new ComponentProcessor())
547        .failsToCompile()
548        .withErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
549            .in(childComponentFile).onLine(10);
550  }
551
552  @Test
553  public void testGenericsOnInheritedSetterMethodFails() {
554    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
555        "package test;",
556        "",
557        "import dagger.Subcomponent;",
558        "",
559        "@Subcomponent",
560        "abstract class ChildComponent {",
561        "  interface Parent {",
562        "    ChildComponent build();",
563        "    <T> Builder set(T t);",
564        "  }",
565        "",
566        "  @Subcomponent.Builder",
567        "  interface Builder extends Parent {}",
568        "}");
569    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
570        .processedWith(new ComponentProcessor())
571        .failsToCompile()
572        .withErrorContaining(
573            String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
574            .in(childComponentFile).onLine(13);
575  }
576
577  @Test
578  public void testMultipleSettersPerTypeFails() {
579    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
580        "package test;",
581        "",
582        "import dagger.Subcomponent;",
583        "",
584        "@Subcomponent",
585        "abstract class ChildComponent {",
586        "  @Subcomponent.Builder",
587        "  interface Builder {",
588        "    ChildComponent build();",
589        "    void set1(String s);",
590        "    void set2(String s);",
591        "  }",
592        "}");
593    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
594        .processedWith(new ComponentProcessor())
595        .failsToCompile()
596        .withErrorContaining(
597            String.format(MSGS.manyMethodsForType(),
598                  "java.lang.String", "[set1(java.lang.String), set2(java.lang.String)]"))
599            .in(childComponentFile).onLine(8);
600  }
601
602  @Test
603  public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
604    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
605        "package test;",
606        "",
607        "import dagger.Subcomponent;",
608        "",
609        "@Subcomponent",
610        "abstract class ChildComponent {",
611        "  interface Parent<T> {",
612        "    void set1(T t);",
613        "  }",
614        "",
615        "  @Subcomponent.Builder",
616        "  interface Builder extends Parent<String> {",
617        "    ChildComponent build();",
618        "    void set2(String s);",
619        "  }",
620        "}");
621    assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
622        .processedWith(new ComponentProcessor())
623        .failsToCompile()
624        .withErrorContaining(
625            String.format(MSGS.manyMethodsForType(),
626                  "java.lang.String", "[set1(T), set2(java.lang.String)]"))
627            .in(childComponentFile).onLine(12);
628  }
629
630  @Test
631  public void testExtraSettersFails() {
632    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
633        "package test;",
634        "",
635        "import dagger.Component;",
636        "",
637        "import javax.inject.Provider;",
638        "",
639        "@Component",
640        "interface ParentComponent {",
641        "  ChildComponent.Builder build();",
642        "}");
643    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
644        "package test;",
645        "",
646        "import dagger.Subcomponent;",
647        "",
648        "@Subcomponent",
649        "interface ChildComponent {",
650        "  @Subcomponent.Builder",
651        "  interface Builder {",
652        "    ChildComponent build();",
653        "    void set1(String s);",
654        "    void set2(Integer s);",
655        "  }",
656        "}");
657    assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
658        .processedWith(new ComponentProcessor())
659        .failsToCompile()
660        .withErrorContaining(
661            String.format(MSGS.extraSetters(),
662                  "[void test.ChildComponent.Builder.set1(String),"
663                  + " void test.ChildComponent.Builder.set2(Integer)]"))
664            .in(childComponentFile).onLine(8);
665
666  }
667
668  @Test
669  public void testMissingSettersFail() {
670    JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
671        "package test;",
672        "",
673        "import dagger.Module;",
674        "import dagger.Provides;",
675        "",
676        "@Module",
677        "final class TestModule {",
678        "  TestModule(String unused) {}",
679        "  @Provides String s() { return null; }",
680        "}");
681    JavaFileObject module2File = JavaFileObjects.forSourceLines("test.Test2Module",
682        "package test;",
683        "",
684        "import dagger.Module;",
685        "import dagger.Provides;",
686        "",
687        "@Module",
688        "final class Test2Module {",
689        "  @Provides Integer i() { return null; }",
690        "}");
691    JavaFileObject module3File = JavaFileObjects.forSourceLines("test.Test3Module",
692        "package test;",
693        "",
694        "import dagger.Module;",
695        "import dagger.Provides;",
696        "",
697        "@Module",
698        "final class Test3Module {",
699        "  Test3Module(String unused) {}",
700        "  @Provides Double d() { return null; }",
701        "}");
702    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
703        "package test;",
704        "",
705        "import dagger.Component;",
706        "",
707        "import javax.inject.Provider;",
708        "",
709        "@Component",
710        "interface ParentComponent {",
711        "  ChildComponent.Builder build();",
712        "}");
713    JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
714        "package test;",
715        "",
716        "import dagger.Subcomponent;",
717        "",
718        "@Subcomponent(modules = {TestModule.class, Test2Module.class, Test3Module.class})",
719        "interface ChildComponent {",
720        "  String string();",
721        "  Integer integer();",
722        "",
723        "  @Subcomponent.Builder",
724        "  interface Builder {",
725        "    ChildComponent create();",
726        "  }",
727        "}");
728    assertAbout(javaSources())
729        .that(ImmutableList.of(moduleFile,
730            module2File,
731            module3File,
732            componentFile,
733            childComponentFile))
734        .processedWith(new ComponentProcessor())
735        .failsToCompile()
736        .withErrorContaining(
737            // Ignores Test2Module because we can construct it ourselves.
738            // TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
739            String.format(MSGS.missingSetters(), "[test.TestModule, test.Test3Module]"))
740            .in(childComponentFile).onLine(11);
741  }
742}
743