Home | History | Annotate | Download | only in codegen
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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