• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.internal.codegen;
18 
19 import static com.google.testing.compile.CompilationSubject.assertThat;
20 import static dagger.internal.codegen.Compilers.daggerCompiler;
21 import static dagger.internal.codegen.ComponentCreatorAnnotation.COMPONENT_BUILDER;
22 import static dagger.internal.codegen.ErrorMessages.creatorMessagesFor;
23 import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
24 
25 import com.google.testing.compile.Compilation;
26 import com.google.testing.compile.JavaFileObjects;
27 import java.util.Collection;
28 import javax.tools.JavaFileObject;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.junit.runners.Parameterized;
32 import org.junit.runners.Parameterized.Parameters;
33 
34 /** Tests for {@link dagger.Component.Builder} */
35 @RunWith(Parameterized.class)
36 public class ComponentBuilderTest {
37   @Parameters(name = "{0}")
parameters()38   public static Collection<Object[]> parameters() {
39     return CompilerMode.TEST_PARAMETERS;
40   }
41 
42   private final CompilerMode compilerMode;
43 
ComponentBuilderTest(CompilerMode compilerMode)44   public ComponentBuilderTest(CompilerMode compilerMode) {
45     this.compilerMode = compilerMode;
46   }
47 
48   private static final ErrorMessages.ComponentCreatorMessages MSGS =
49       creatorMessagesFor(COMPONENT_BUILDER);
50 
51   @Test
testUsesBuildAndSetterNames()52   public void testUsesBuildAndSetterNames() {
53     JavaFileObject moduleFile =
54         JavaFileObjects.forSourceLines(
55             "test.TestModule",
56             "package test;",
57             "",
58             "import dagger.Module;",
59             "import dagger.Provides;",
60             "",
61             "@Module",
62             "final class TestModule {",
63             "  @Provides String string() { return null; }",
64             "}");
65 
66     JavaFileObject componentFile =
67         JavaFileObjects.forSourceLines(
68             "test.TestComponent",
69             "package test;",
70             "",
71             "import dagger.Component;",
72             "",
73             "@Component(modules = TestModule.class)",
74             "interface TestComponent {",
75             "  String string();",
76             "",
77             "  @Component.Builder",
78             "  interface Builder {",
79             "    Builder setTestModule(TestModule testModule);",
80             "    TestComponent create();",
81             "  }",
82             "}");
83     JavaFileObject generatedComponent =
84         JavaFileObjects.forSourceLines(
85             "test.DaggerTestComponent",
86             "package test;",
87             "",
88             "import dagger.internal.Preconditions;",
89             "",
90             GENERATED_ANNOTATION,
91             "final class DaggerTestComponent implements TestComponent {",
92             "  private static final class Builder implements TestComponent.Builder {",
93             "    private TestModule testModule;",
94             "",
95             "    @Override",
96             "    public Builder setTestModule(TestModule testModule) {",
97             "      this.testModule = Preconditions.checkNotNull(testModule);",
98             "      return this;",
99             "    }",
100             "",
101             "    @Override",
102             "    public TestComponent create() {",
103             "      if (testModule == null) {",
104             "        this.testModule = new TestModule();",
105             "      }",
106             "      return new DaggerTestComponent(testModule);",
107             "    }",
108             "  }",
109             "}");
110     Compilation compilation =
111         daggerCompiler().withOptions(compilerMode.javacopts()).compile(moduleFile, componentFile);
112     assertThat(compilation).succeeded();
113     assertThat(compilation)
114         .generatedSourceFile("test.DaggerTestComponent")
115         .containsElementsIn(generatedComponent);
116   }
117 
118   @Test
testSetterMethodWithMoreThanOneArgFails()119   public void testSetterMethodWithMoreThanOneArgFails() {
120     JavaFileObject componentFile =
121         JavaFileObjects.forSourceLines(
122             "test.SimpleComponent",
123             "package test;",
124             "",
125             "import dagger.Component;",
126             "import javax.inject.Provider;",
127             "",
128             "@Component",
129             "abstract class SimpleComponent {",
130             "  @Component.Builder",
131             "  interface Builder {",
132             "    SimpleComponent build();",
133             "    Builder set(String s, Integer i);",
134             "    Builder set(Number n, Double d);",
135             "  }",
136             "}");
137     Compilation compilation =
138         daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
139     assertThat(compilation).failed();
140     assertThat(compilation)
141         .hadErrorContaining(MSGS.setterMethodsMustTakeOneArg())
142         .inFile(componentFile)
143         .onLineContaining("Builder set(String s, Integer i);");
144     assertThat(compilation)
145         .hadErrorContaining(MSGS.setterMethodsMustTakeOneArg())
146         .inFile(componentFile)
147         .onLineContaining("Builder set(Number n, Double d);");
148   }
149 
150   @Test
testInheritedSetterMethodWithMoreThanOneArgFails()151   public void testInheritedSetterMethodWithMoreThanOneArgFails() {
152     JavaFileObject componentFile =
153         JavaFileObjects.forSourceLines(
154             "test.SimpleComponent",
155             "package test;",
156             "",
157             "import dagger.Component;",
158             "import javax.inject.Provider;",
159             "",
160             "@Component",
161             "abstract class SimpleComponent {",
162             "  interface Parent {",
163             "    SimpleComponent build();",
164             "    Builder set1(String s, Integer i);",
165             "  }",
166             "",
167             "  @Component.Builder",
168             "  interface Builder extends Parent {}",
169             "}");
170     Compilation compilation =
171         daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
172     assertThat(compilation).failed();
173     assertThat(compilation)
174         .hadErrorContaining(
175             String.format(
176                 MSGS.inheritedSetterMethodsMustTakeOneArg(),
177                 "set1(java.lang.String,java.lang.Integer)"))
178         .inFile(componentFile)
179         .onLineContaining("interface Builder");
180   }
181 
182   @Test
testSetterReturningNonVoidOrBuilderFails()183   public void testSetterReturningNonVoidOrBuilderFails() {
184     JavaFileObject componentFile =
185         JavaFileObjects.forSourceLines(
186             "test.SimpleComponent",
187             "package test;",
188             "",
189             "import dagger.Component;",
190             "import javax.inject.Provider;",
191             "",
192             "@Component",
193             "abstract class SimpleComponent {",
194             "  @Component.Builder",
195             "  interface Builder {",
196             "    SimpleComponent build();",
197             "    String set(Integer i);",
198             "  }",
199             "}");
200     Compilation compilation =
201         daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
202     assertThat(compilation).failed();
203     assertThat(compilation)
204         .hadErrorContaining(MSGS.setterMethodsMustReturnVoidOrBuilder())
205         .inFile(componentFile)
206         .onLineContaining("String set(Integer i);");
207   }
208 
209   @Test
testInheritedSetterReturningNonVoidOrBuilderFails()210   public void testInheritedSetterReturningNonVoidOrBuilderFails() {
211     JavaFileObject componentFile =
212         JavaFileObjects.forSourceLines(
213             "test.SimpleComponent",
214             "package test;",
215             "",
216             "import dagger.Component;",
217             "import javax.inject.Provider;",
218             "",
219             "@Component",
220             "abstract class SimpleComponent {",
221             "  interface Parent {",
222             "    SimpleComponent build();",
223             "    String set(Integer i);",
224             "  }",
225             "",
226             "  @Component.Builder",
227             "  interface Builder extends Parent {}",
228             "}");
229     Compilation compilation =
230         daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
231     assertThat(compilation).failed();
232     assertThat(compilation)
233         .hadErrorContaining(
234             String.format(
235                 MSGS.inheritedSetterMethodsMustReturnVoidOrBuilder(), "set(java.lang.Integer)"))
236         .inFile(componentFile)
237         .onLineContaining("interface Builder");
238   }
239 
240   @Test
testGenericsOnSetterMethodFails()241   public void testGenericsOnSetterMethodFails() {
242     JavaFileObject componentFile =
243         JavaFileObjects.forSourceLines(
244             "test.SimpleComponent",
245             "package test;",
246             "",
247             "import dagger.Component;",
248             "import javax.inject.Provider;",
249             "",
250             "@Component",
251             "abstract class SimpleComponent {",
252             "  @Component.Builder",
253             "  interface Builder {",
254             "    SimpleComponent build();",
255             "    <T> Builder set(T t);",
256             "  }",
257             "}");
258     Compilation compilation =
259         daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
260     assertThat(compilation).failed();
261     assertThat(compilation)
262         .hadErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
263         .inFile(componentFile)
264         .onLineContaining("<T> Builder set(T t);");
265   }
266 
267   @Test
testGenericsOnInheritedSetterMethodFails()268   public void testGenericsOnInheritedSetterMethodFails() {
269     JavaFileObject componentFile =
270         JavaFileObjects.forSourceLines(
271             "test.SimpleComponent",
272             "package test;",
273             "",
274             "import dagger.Component;",
275             "import javax.inject.Provider;",
276             "",
277             "@Component",
278             "abstract class SimpleComponent {",
279             "  interface Parent {",
280             "    SimpleComponent build();",
281             "    <T> Builder set(T t);",
282             "  }",
283             "",
284             "  @Component.Builder",
285             "  interface Builder extends Parent {}",
286             "}");
287     Compilation compilation =
288         daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
289     assertThat(compilation).failed();
290     assertThat(compilation)
291         .hadErrorContaining(
292             String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
293         .inFile(componentFile)
294         .onLineContaining("interface Builder");
295   }
296 
297   @Test
testBindsInstanceNotAllowedOnBothSetterAndParameter()298   public void testBindsInstanceNotAllowedOnBothSetterAndParameter() {
299     JavaFileObject componentFile =
300         JavaFileObjects.forSourceLines(
301             "test.SimpleComponent",
302             "package test;",
303             "",
304             "import dagger.BindsInstance;",
305             "import dagger.Component;",
306             "",
307             "@Component",
308             "abstract class SimpleComponent {",
309             "  abstract String s();",
310             "",
311             "  @Component.Builder",
312             "  interface Builder {",
313             "    @BindsInstance",
314             "    Builder s(@BindsInstance String s);",
315             "",
316             "    SimpleComponent build();",
317             "  }",
318             "}");
319 
320     Compilation compilation =
321         daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
322     assertThat(compilation).failed();
323     assertThat(compilation)
324         .hadErrorContaining(MSGS.bindsInstanceNotAllowedOnBothSetterMethodAndParameter())
325         .inFile(componentFile)
326         .onLineContaining("Builder s(");
327   }
328 
329   @Test
testBindsInstanceNotAllowedOnBothSetterAndParameter_inherited()330   public void testBindsInstanceNotAllowedOnBothSetterAndParameter_inherited() {
331     JavaFileObject componentFile =
332         JavaFileObjects.forSourceLines(
333             "test.SimpleComponent",
334             "package test;",
335             "",
336             "import dagger.BindsInstance;",
337             "import dagger.Component;",
338             "",
339             "@Component",
340             "abstract class SimpleComponent {",
341             "  abstract String s();",
342             "",
343             "  interface BuilderParent<B extends BuilderParent> {",
344             "    @BindsInstance",
345             "    B s(@BindsInstance String s);",
346             "  }",
347             "",
348             "  @Component.Builder",
349             "  interface Builder extends BuilderParent<Builder> {",
350             "    SimpleComponent build();",
351             "  }",
352             "}");
353 
354     Compilation compilation =
355         daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
356     assertThat(compilation).failed();
357     assertThat(compilation)
358         .hadErrorContaining(
359             String.format(
360                 MSGS.inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter(),
361                 "s(java.lang.String)"))
362         .inFile(componentFile)
363         .onLineContaining("Builder extends BuilderParent<Builder>");
364   }
365 }
366