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 dagger.internal.codegen.base.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
20 import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
21 
22 import androidx.room.compiler.processing.util.Source;
23 import com.google.common.collect.ImmutableList;
24 import dagger.internal.codegen.binding.ErrorMessages;
25 import dagger.testing.compile.CompilerTests;
26 import dagger.testing.golden.GoldenFileRule;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.junit.runners.Parameterized;
31 import org.junit.runners.Parameterized.Parameters;
32 
33 /** Tests for {@link dagger.Subcomponent.Builder} validation. */
34 @RunWith(Parameterized.class)
35 public class SubcomponentBuilderValidationTest {
36   @Parameters(name = "{0}")
parameters()37   public static ImmutableList<Object[]> parameters() {
38     return CompilerMode.TEST_PARAMETERS;
39   }
40 
41   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
42 
43   private final CompilerMode compilerMode;
44 
SubcomponentBuilderValidationTest(CompilerMode compilerMode)45   public SubcomponentBuilderValidationTest(CompilerMode compilerMode) {
46     this.compilerMode = compilerMode;
47   }
48 
49   private static final ErrorMessages.ComponentCreatorMessages MSGS =
50       creatorMessagesFor(SUBCOMPONENT_BUILDER);
51 
52   @Test
testMoreThanOneArgFails()53   public void testMoreThanOneArgFails() {
54     Source childComponentFile = CompilerTests.javaSource("test.ChildComponent",
55         "package test;",
56         "",
57         "import dagger.Subcomponent;",
58         "",
59         "@Subcomponent",
60         "abstract class ChildComponent {",
61         "  @Subcomponent.Builder",
62         "  interface Builder {",
63         "    ChildComponent build();",
64         "    Builder set(String s, Integer i);",
65         "    Builder set(Number n, Double d);",
66         "  }",
67         "}");
68 
69     CompilerTests.daggerCompiler(childComponentFile)
70         .withProcessingOptions(compilerMode.processorOptions())
71         .compile(
72             subject -> {
73               subject.hasErrorCount(2);
74               subject
75                   .hasErrorContaining(MSGS.setterMethodsMustTakeOneArg())
76                   .onSource(childComponentFile)
77                   .onLine(10);
78               subject
79                   .hasErrorContaining(MSGS.setterMethodsMustTakeOneArg())
80                   .onSource(childComponentFile)
81                   .onLine(11);
82             });
83   }
84 
85   @Test
testInheritedMoreThanOneArgFails()86   public void testInheritedMoreThanOneArgFails() {
87      Source childComponentFile = CompilerTests.javaSource("test.ChildComponent",
88         "package test;",
89         "",
90         "import dagger.Subcomponent;",
91         "",
92         "@Subcomponent",
93         "abstract class ChildComponent {",
94         "  interface Parent {",
95         "    ChildComponent build();",
96         "    Builder set1(String s, Integer i);",
97         "  }",
98         "",
99         "  @Subcomponent.Builder",
100         "  interface Builder extends Parent {}",
101         "}");
102 
103     String expectedErrorMsg =
104         String.format(
105             MSGS.inheritedSetterMethodsMustTakeOneArg(),
106             "test.ChildComponent.Builder test.ChildComponent.Parent.set1(String, Integer)");
107     CompilerTests.daggerCompiler(childComponentFile)
108         .withProcessingOptions(compilerMode.processorOptions())
109         .compile(
110             subject -> {
111               subject.hasErrorCount(1);
112               subject
113                   .hasErrorContaining(expectedErrorMsg)
114                   .onSource(childComponentFile)
115                   .onLine(13);
116             });
117   }
118 
119   @Test
testSetterReturningNonVoidOrBuilderFails()120   public void testSetterReturningNonVoidOrBuilderFails() {
121      Source childComponentFile = CompilerTests.javaSource("test.ChildComponent",
122         "package test;",
123         "",
124         "import dagger.Subcomponent;",
125         "",
126         "@Subcomponent",
127         "abstract class ChildComponent {",
128         "  @Subcomponent.Builder",
129         "  interface Builder {",
130         "    ChildComponent build();",
131         "    String set(Integer i);",
132         "  }",
133         "}");
134 
135     CompilerTests.daggerCompiler(childComponentFile)
136         .withProcessingOptions(compilerMode.processorOptions())
137         .compile(
138             subject -> {
139               subject.hasErrorCount(1);
140               subject
141                   .hasErrorContaining(MSGS.setterMethodsMustReturnVoidOrBuilder())
142                   .onSource(childComponentFile)
143                   .onLine(10);
144             });
145   }
146 
147   @Test
testInheritedSetterReturningNonVoidOrBuilderFails()148   public void testInheritedSetterReturningNonVoidOrBuilderFails() {
149      Source childComponentFile = CompilerTests.javaSource("test.ChildComponent",
150         "package test;",
151         "",
152         "import dagger.Subcomponent;",
153         "",
154         "@Subcomponent",
155         "abstract class ChildComponent {",
156         "  interface Parent {",
157         "    ChildComponent build();",
158         "    String set(Integer i);",
159         "  }",
160         "",
161         "  @Subcomponent.Builder",
162         "  interface Builder extends Parent {}",
163         "}");
164 
165     CompilerTests.daggerCompiler(childComponentFile)
166         .withProcessingOptions(compilerMode.processorOptions())
167         .compile(
168             subject -> {
169               subject.hasErrorCount(1);
170               subject
171                   .hasErrorContaining(
172                       String.format(
173                           MSGS.inheritedSetterMethodsMustReturnVoidOrBuilder(),
174                           "String test.ChildComponent.Parent.set(Integer)"))
175                   .onSource(childComponentFile)
176                   .onLine(13);
177             });
178   }
179 
180   @Test
testGenericsOnSetterMethodFails()181   public void testGenericsOnSetterMethodFails() {
182      Source childComponentFile = CompilerTests.javaSource("test.ChildComponent",
183         "package test;",
184         "",
185         "import dagger.Subcomponent;",
186         "",
187         "@Subcomponent",
188         "abstract class ChildComponent {",
189         "  @Subcomponent.Builder",
190         "  interface Builder {",
191         "    ChildComponent build();",
192         "    <T> Builder set(T t);",
193         "  }",
194         "}");
195 
196     CompilerTests.daggerCompiler(childComponentFile)
197         .withProcessingOptions(compilerMode.processorOptions())
198         .compile(
199             subject -> {
200               subject.hasErrorCount(1);
201               subject
202                   .hasErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
203                   .onSource(childComponentFile)
204                   .onLine(10);
205             });
206   }
207 
208   @Test
testGenericsOnInheritedSetterMethodFails()209   public void testGenericsOnInheritedSetterMethodFails() {
210      Source childComponentFile = CompilerTests.javaSource("test.ChildComponent",
211         "package test;",
212         "",
213         "import dagger.Subcomponent;",
214         "",
215         "@Subcomponent",
216         "abstract class ChildComponent {",
217         "  interface Parent {",
218         "    ChildComponent build();",
219         "    <T> Builder set(T t);",
220         "  }",
221         "",
222         "  @Subcomponent.Builder",
223         "  interface Builder extends Parent {}",
224         "}");
225 
226     CompilerTests.daggerCompiler(childComponentFile)
227         .withProcessingOptions(compilerMode.processorOptions())
228         .compile(
229             subject -> {
230               subject.hasErrorCount(1);
231               subject
232                   .hasErrorContaining(
233                       String.format(
234                           MSGS.inheritedMethodsMayNotHaveTypeParameters(),
235                           "test.ChildComponent.Builder test.ChildComponent.Parent.set(T)"))
236                   .onSource(childComponentFile)
237                   .onLine(13);
238             });
239   }
240 }
241