xref: /aosp_15_r20/external/dagger2/javatests/dagger/internal/codegen/ComponentValidationTest.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1*f585d8a3SJacky Wang /*
2*f585d8a3SJacky Wang  * Copyright (C) 2014 The Dagger Authors.
3*f585d8a3SJacky Wang  *
4*f585d8a3SJacky Wang  * Licensed under the Apache License, Version 2.0 (the "License");
5*f585d8a3SJacky Wang  * you may not use this file except in compliance with the License.
6*f585d8a3SJacky Wang  * You may obtain a copy of the License at
7*f585d8a3SJacky Wang  *
8*f585d8a3SJacky Wang  * http://www.apache.org/licenses/LICENSE-2.0
9*f585d8a3SJacky Wang  *
10*f585d8a3SJacky Wang  * Unless required by applicable law or agreed to in writing, software
11*f585d8a3SJacky Wang  * distributed under the License is distributed on an "AS IS" BASIS,
12*f585d8a3SJacky Wang  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f585d8a3SJacky Wang  * See the License for the specific language governing permissions and
14*f585d8a3SJacky Wang  * limitations under the License.
15*f585d8a3SJacky Wang  */
16*f585d8a3SJacky Wang 
17*f585d8a3SJacky Wang package dagger.internal.codegen;
18*f585d8a3SJacky Wang 
19*f585d8a3SJacky Wang import static com.google.testing.compile.CompilationSubject.assertThat;
20*f585d8a3SJacky Wang import static dagger.internal.codegen.Compilers.daggerCompiler;
21*f585d8a3SJacky Wang import static dagger.internal.codegen.TestUtils.message;
22*f585d8a3SJacky Wang 
23*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source;
24*f585d8a3SJacky Wang import com.google.common.collect.ImmutableMap;
25*f585d8a3SJacky Wang import com.google.testing.compile.Compilation;
26*f585d8a3SJacky Wang import com.google.testing.compile.JavaFileObjects;
27*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests;
28*f585d8a3SJacky Wang import javax.tools.JavaFileObject;
29*f585d8a3SJacky Wang import org.junit.Test;
30*f585d8a3SJacky Wang import org.junit.runner.RunWith;
31*f585d8a3SJacky Wang import org.junit.runners.JUnit4;
32*f585d8a3SJacky Wang 
33*f585d8a3SJacky Wang @RunWith(JUnit4.class)
34*f585d8a3SJacky Wang public final class ComponentValidationTest {
35*f585d8a3SJacky Wang   @Test
componentOnConcreteClass()36*f585d8a3SJacky Wang   public void componentOnConcreteClass() {
37*f585d8a3SJacky Wang     Source componentFile =
38*f585d8a3SJacky Wang         CompilerTests.javaSource(
39*f585d8a3SJacky Wang             "test.NotAComponent",
40*f585d8a3SJacky Wang             "package test;",
41*f585d8a3SJacky Wang             "",
42*f585d8a3SJacky Wang             "import dagger.Component;",
43*f585d8a3SJacky Wang             "",
44*f585d8a3SJacky Wang             "@Component",
45*f585d8a3SJacky Wang             "final class NotAComponent {}");
46*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile)
47*f585d8a3SJacky Wang         .compile(
48*f585d8a3SJacky Wang             subject -> {
49*f585d8a3SJacky Wang               subject.hasErrorCount(1);
50*f585d8a3SJacky Wang               subject.hasErrorContaining("interface");
51*f585d8a3SJacky Wang             });
52*f585d8a3SJacky Wang   }
53*f585d8a3SJacky Wang 
54*f585d8a3SJacky Wang   @Test
componentOnOverridingBuilder_failsWhenMethodNameConflictsWithStaticCreatorName()55*f585d8a3SJacky Wang   public void componentOnOverridingBuilder_failsWhenMethodNameConflictsWithStaticCreatorName() {
56*f585d8a3SJacky Wang     Source componentFile =
57*f585d8a3SJacky Wang         CompilerTests.javaSource(
58*f585d8a3SJacky Wang             "test.TestComponent",
59*f585d8a3SJacky Wang             "package test;",
60*f585d8a3SJacky Wang             "",
61*f585d8a3SJacky Wang             "import dagger.Component;",
62*f585d8a3SJacky Wang             "",
63*f585d8a3SJacky Wang             "@Component(modules=TestModule.class)",
64*f585d8a3SJacky Wang             "interface TestComponent {",
65*f585d8a3SJacky Wang             "  String builder();",
66*f585d8a3SJacky Wang             "}");
67*f585d8a3SJacky Wang     Source moduleFile =
68*f585d8a3SJacky Wang         CompilerTests.javaSource(
69*f585d8a3SJacky Wang             "test.TestModule",
70*f585d8a3SJacky Wang             "package test;",
71*f585d8a3SJacky Wang             "",
72*f585d8a3SJacky Wang             "import dagger.Module;",
73*f585d8a3SJacky Wang             "import dagger.Provides;",
74*f585d8a3SJacky Wang             "",
75*f585d8a3SJacky Wang             "@Module",
76*f585d8a3SJacky Wang             "interface TestModule {",
77*f585d8a3SJacky Wang             "  @Provides",
78*f585d8a3SJacky Wang             "  static String provideString() { return \"test\"; }",
79*f585d8a3SJacky Wang             "}");
80*f585d8a3SJacky Wang 
81*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile, moduleFile)
82*f585d8a3SJacky Wang         .compile(
83*f585d8a3SJacky Wang             subject -> {
84*f585d8a3SJacky Wang               subject.hasErrorCount(1);
85*f585d8a3SJacky Wang               subject.hasErrorContaining(
86*f585d8a3SJacky Wang                   "The method test.TestComponent.builder() conflicts with a method");
87*f585d8a3SJacky Wang             });
88*f585d8a3SJacky Wang   }
89*f585d8a3SJacky Wang 
90*f585d8a3SJacky Wang   @Test
componentOnOverridingCreate_failsWhenGeneratedCreateMethod()91*f585d8a3SJacky Wang   public void componentOnOverridingCreate_failsWhenGeneratedCreateMethod() {
92*f585d8a3SJacky Wang     Source componentFile =
93*f585d8a3SJacky Wang         CompilerTests.javaSource(
94*f585d8a3SJacky Wang             "test.TestComponent",
95*f585d8a3SJacky Wang             "package test;",
96*f585d8a3SJacky Wang             "",
97*f585d8a3SJacky Wang             "import dagger.Component;",
98*f585d8a3SJacky Wang             "",
99*f585d8a3SJacky Wang             "@Component(modules=TestModule.class)",
100*f585d8a3SJacky Wang             "interface TestComponent {",
101*f585d8a3SJacky Wang             "  String create();",
102*f585d8a3SJacky Wang             "}");
103*f585d8a3SJacky Wang     Source moduleFile =
104*f585d8a3SJacky Wang         CompilerTests.javaSource(
105*f585d8a3SJacky Wang             "test.TestModule",
106*f585d8a3SJacky Wang             "package test;",
107*f585d8a3SJacky Wang             "",
108*f585d8a3SJacky Wang             "import dagger.Module;",
109*f585d8a3SJacky Wang             "import dagger.Provides;",
110*f585d8a3SJacky Wang             "",
111*f585d8a3SJacky Wang             "@Module",
112*f585d8a3SJacky Wang             "interface TestModule {",
113*f585d8a3SJacky Wang             "  @Provides",
114*f585d8a3SJacky Wang             "  static String provideString() { return \"test\"; }",
115*f585d8a3SJacky Wang             "}");
116*f585d8a3SJacky Wang 
117*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile, moduleFile)
118*f585d8a3SJacky Wang         .compile(
119*f585d8a3SJacky Wang             subject -> {
120*f585d8a3SJacky Wang               subject.hasErrorCount(1);
121*f585d8a3SJacky Wang               subject.hasErrorContaining(
122*f585d8a3SJacky Wang                   "The method test.TestComponent.create() conflicts with a method");
123*f585d8a3SJacky Wang             });
124*f585d8a3SJacky Wang   }
125*f585d8a3SJacky Wang 
126*f585d8a3SJacky Wang   @Test
subcomponentMethodNameBuilder_succeeds()127*f585d8a3SJacky Wang   public void subcomponentMethodNameBuilder_succeeds() {
128*f585d8a3SJacky Wang     Source componentFile =
129*f585d8a3SJacky Wang         CompilerTests.javaSource(
130*f585d8a3SJacky Wang             "test.TestComponent",
131*f585d8a3SJacky Wang             "package test;",
132*f585d8a3SJacky Wang             "",
133*f585d8a3SJacky Wang             "import dagger.Component;",
134*f585d8a3SJacky Wang             "",
135*f585d8a3SJacky Wang             "@Component",
136*f585d8a3SJacky Wang             "interface TestComponent {",
137*f585d8a3SJacky Wang             "  TestSubcomponent.Builder subcomponent();",
138*f585d8a3SJacky Wang             "}");
139*f585d8a3SJacky Wang     Source subcomponentFile =
140*f585d8a3SJacky Wang         CompilerTests.javaSource(
141*f585d8a3SJacky Wang             "test.TestSubcomponent",
142*f585d8a3SJacky Wang             "package test;",
143*f585d8a3SJacky Wang             "",
144*f585d8a3SJacky Wang             "import dagger.Subcomponent;",
145*f585d8a3SJacky Wang             "",
146*f585d8a3SJacky Wang             "@Subcomponent(modules=TestModule.class)",
147*f585d8a3SJacky Wang             "interface TestSubcomponent {",
148*f585d8a3SJacky Wang             "  String builder();",
149*f585d8a3SJacky Wang             "  @Subcomponent.Builder",
150*f585d8a3SJacky Wang             "  interface Builder {",
151*f585d8a3SJacky Wang             "    TestSubcomponent build();",
152*f585d8a3SJacky Wang             "  }",
153*f585d8a3SJacky Wang             "}");
154*f585d8a3SJacky Wang     Source moduleFile =
155*f585d8a3SJacky Wang         CompilerTests.javaSource(
156*f585d8a3SJacky Wang             "test.TestModule",
157*f585d8a3SJacky Wang             "package test;",
158*f585d8a3SJacky Wang             "",
159*f585d8a3SJacky Wang             "import dagger.Module;",
160*f585d8a3SJacky Wang             "import dagger.Provides;",
161*f585d8a3SJacky Wang             "",
162*f585d8a3SJacky Wang             "@Module",
163*f585d8a3SJacky Wang             "interface TestModule {",
164*f585d8a3SJacky Wang             "  @Provides",
165*f585d8a3SJacky Wang             "  static String provideString() { return \"test\"; }",
166*f585d8a3SJacky Wang             "}");
167*f585d8a3SJacky Wang 
168*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile, subcomponentFile, moduleFile)
169*f585d8a3SJacky Wang         .compile(subject -> subject.hasErrorCount(0));
170*f585d8a3SJacky Wang   }
171*f585d8a3SJacky Wang 
componentOnEnum()172*f585d8a3SJacky Wang   @Test public void componentOnEnum() {
173*f585d8a3SJacky Wang     Source componentFile =
174*f585d8a3SJacky Wang         CompilerTests.javaSource(
175*f585d8a3SJacky Wang             "test.NotAComponent",
176*f585d8a3SJacky Wang             "package test;",
177*f585d8a3SJacky Wang             "",
178*f585d8a3SJacky Wang             "import dagger.Component;",
179*f585d8a3SJacky Wang             "",
180*f585d8a3SJacky Wang             "@Component",
181*f585d8a3SJacky Wang             "enum NotAComponent {",
182*f585d8a3SJacky Wang             "  INSTANCE",
183*f585d8a3SJacky Wang             "}");
184*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile)
185*f585d8a3SJacky Wang         .compile(
186*f585d8a3SJacky Wang             subject -> {
187*f585d8a3SJacky Wang               subject.hasErrorCount(1);
188*f585d8a3SJacky Wang               subject.hasErrorContaining("interface");
189*f585d8a3SJacky Wang             });
190*f585d8a3SJacky Wang   }
191*f585d8a3SJacky Wang 
componentOnAnnotation()192*f585d8a3SJacky Wang   @Test public void componentOnAnnotation() {
193*f585d8a3SJacky Wang     Source componentFile =
194*f585d8a3SJacky Wang         CompilerTests.javaSource(
195*f585d8a3SJacky Wang             "test.NotAComponent",
196*f585d8a3SJacky Wang             "package test;",
197*f585d8a3SJacky Wang             "",
198*f585d8a3SJacky Wang             "import dagger.Component;",
199*f585d8a3SJacky Wang             "",
200*f585d8a3SJacky Wang             "@Component",
201*f585d8a3SJacky Wang             "@interface NotAComponent {}");
202*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile)
203*f585d8a3SJacky Wang         .compile(
204*f585d8a3SJacky Wang             subject -> {
205*f585d8a3SJacky Wang               subject.hasErrorCount(1);
206*f585d8a3SJacky Wang               subject.hasErrorContaining("interface");
207*f585d8a3SJacky Wang             });
208*f585d8a3SJacky Wang   }
209*f585d8a3SJacky Wang 
nonModuleModule()210*f585d8a3SJacky Wang   @Test public void nonModuleModule() {
211*f585d8a3SJacky Wang     Source componentFile =
212*f585d8a3SJacky Wang         CompilerTests.javaSource(
213*f585d8a3SJacky Wang             "test.NotAComponent",
214*f585d8a3SJacky Wang             "package test;",
215*f585d8a3SJacky Wang             "",
216*f585d8a3SJacky Wang             "import dagger.Component;",
217*f585d8a3SJacky Wang             "",
218*f585d8a3SJacky Wang             "@Component(modules = Object.class)",
219*f585d8a3SJacky Wang             "interface NotAComponent {}");
220*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(componentFile)
221*f585d8a3SJacky Wang         .compile(
222*f585d8a3SJacky Wang             subject -> {
223*f585d8a3SJacky Wang               subject.hasErrorCount(1);
224*f585d8a3SJacky Wang               subject.hasErrorContaining("is not annotated with @Module");
225*f585d8a3SJacky Wang             });
226*f585d8a3SJacky Wang   }
227*f585d8a3SJacky Wang 
228*f585d8a3SJacky Wang   @Test
componentWithInvalidModule()229*f585d8a3SJacky Wang   public void componentWithInvalidModule() {
230*f585d8a3SJacky Wang     Source module =
231*f585d8a3SJacky Wang         CompilerTests.javaSource(
232*f585d8a3SJacky Wang             "test.BadModule",
233*f585d8a3SJacky Wang             "package test;",
234*f585d8a3SJacky Wang             "",
235*f585d8a3SJacky Wang             "import dagger.Binds;",
236*f585d8a3SJacky Wang             "import dagger.Module;",
237*f585d8a3SJacky Wang             "",
238*f585d8a3SJacky Wang             "@Module",
239*f585d8a3SJacky Wang             "abstract class BadModule {",
240*f585d8a3SJacky Wang             "  @Binds abstract Object noParameters();",
241*f585d8a3SJacky Wang             "}");
242*f585d8a3SJacky Wang     Source component =
243*f585d8a3SJacky Wang         CompilerTests.javaSource(
244*f585d8a3SJacky Wang             "test.BadComponent",
245*f585d8a3SJacky Wang             "package test;",
246*f585d8a3SJacky Wang             "",
247*f585d8a3SJacky Wang             "import dagger.Component;",
248*f585d8a3SJacky Wang             "",
249*f585d8a3SJacky Wang             "@Component(modules = BadModule.class)",
250*f585d8a3SJacky Wang             "interface BadComponent {",
251*f585d8a3SJacky Wang             "  Object object();",
252*f585d8a3SJacky Wang             "}");
253*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(module, component)
254*f585d8a3SJacky Wang         .compile(
255*f585d8a3SJacky Wang             subject -> {
256*f585d8a3SJacky Wang               subject.hasErrorCount(2);
257*f585d8a3SJacky Wang               subject.hasErrorContaining("test.BadModule has errors")
258*f585d8a3SJacky Wang                   .onSource(component)
259*f585d8a3SJacky Wang                   .onLine(5);
260*f585d8a3SJacky Wang               subject.hasErrorContaining(
261*f585d8a3SJacky Wang                       "@Binds methods must have exactly one parameter, whose type is assignable to "
262*f585d8a3SJacky Wang                           + "the return type")
263*f585d8a3SJacky Wang                   .onSource(module)
264*f585d8a3SJacky Wang                   .onLine(8);
265*f585d8a3SJacky Wang             });
266*f585d8a3SJacky Wang   }
267*f585d8a3SJacky Wang 
268*f585d8a3SJacky Wang   @Test
attemptToInjectWildcardGenerics()269*f585d8a3SJacky Wang   public void attemptToInjectWildcardGenerics() {
270*f585d8a3SJacky Wang     Source testComponent =
271*f585d8a3SJacky Wang         CompilerTests.javaSource(
272*f585d8a3SJacky Wang             "test.TestComponent",
273*f585d8a3SJacky Wang             "package test;",
274*f585d8a3SJacky Wang             "",
275*f585d8a3SJacky Wang             "import dagger.Component;",
276*f585d8a3SJacky Wang             "import dagger.Lazy;",
277*f585d8a3SJacky Wang             "import javax.inject.Provider;",
278*f585d8a3SJacky Wang             "",
279*f585d8a3SJacky Wang             "@Component",
280*f585d8a3SJacky Wang             "interface TestComponent {",
281*f585d8a3SJacky Wang             "  Lazy<? extends Number> wildcardNumberLazy();",
282*f585d8a3SJacky Wang             "  Provider<? super Number> wildcardNumberProvider();",
283*f585d8a3SJacky Wang             "}");
284*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(testComponent)
285*f585d8a3SJacky Wang         .compile(
286*f585d8a3SJacky Wang             subject -> {
287*f585d8a3SJacky Wang               subject.hasErrorCount(2);
288*f585d8a3SJacky Wang               subject.hasErrorContaining("wildcard type").onSource(testComponent).onLine(9);
289*f585d8a3SJacky Wang               subject.hasErrorContaining("wildcard type").onSource(testComponent).onLine(10);
290*f585d8a3SJacky Wang             });
291*f585d8a3SJacky Wang   }
292*f585d8a3SJacky Wang 
293*f585d8a3SJacky Wang   // TODO(b/245954367): Migrate test to XProcessing Testing after this bug has been fixed.
294*f585d8a3SJacky Wang   @Test
invalidComponentDependencies()295*f585d8a3SJacky Wang   public void invalidComponentDependencies() {
296*f585d8a3SJacky Wang     JavaFileObject testComponent =
297*f585d8a3SJacky Wang         JavaFileObjects.forSourceLines(
298*f585d8a3SJacky Wang             "test.TestComponent",
299*f585d8a3SJacky Wang             "package test;",
300*f585d8a3SJacky Wang             "",
301*f585d8a3SJacky Wang             "import dagger.Component;",
302*f585d8a3SJacky Wang             "",
303*f585d8a3SJacky Wang             "@Component(dependencies = int.class)",
304*f585d8a3SJacky Wang             "interface TestComponent {}");
305*f585d8a3SJacky Wang     Compilation compilation = daggerCompiler().compile(testComponent);
306*f585d8a3SJacky Wang     assertThat(compilation).failed();
307*f585d8a3SJacky Wang     assertThat(compilation).hadErrorContaining("int is not a valid component dependency type");
308*f585d8a3SJacky Wang   }
309*f585d8a3SJacky Wang 
310*f585d8a3SJacky Wang   // TODO(b/245954367): Migrate test to XProcessing Testing after this bug has been fixed.
311*f585d8a3SJacky Wang   @Test
invalidComponentModules()312*f585d8a3SJacky Wang   public void invalidComponentModules() {
313*f585d8a3SJacky Wang     JavaFileObject testComponent =
314*f585d8a3SJacky Wang         JavaFileObjects.forSourceLines(
315*f585d8a3SJacky Wang             "test.TestComponent",
316*f585d8a3SJacky Wang             "package test;",
317*f585d8a3SJacky Wang             "",
318*f585d8a3SJacky Wang             "import dagger.Component;",
319*f585d8a3SJacky Wang             "",
320*f585d8a3SJacky Wang             "@Component(modules = int.class)",
321*f585d8a3SJacky Wang             "interface TestComponent {}");
322*f585d8a3SJacky Wang     Compilation compilation = daggerCompiler().compile(testComponent);
323*f585d8a3SJacky Wang     assertThat(compilation).failed();
324*f585d8a3SJacky Wang     assertThat(compilation).hadErrorContaining("int is not a valid module type");
325*f585d8a3SJacky Wang   }
326*f585d8a3SJacky Wang 
327*f585d8a3SJacky Wang   @Test
moduleInDependencies()328*f585d8a3SJacky Wang   public void moduleInDependencies() {
329*f585d8a3SJacky Wang     Source testModule =
330*f585d8a3SJacky Wang         CompilerTests.javaSource(
331*f585d8a3SJacky Wang             "test.TestModule",
332*f585d8a3SJacky Wang             "package test;",
333*f585d8a3SJacky Wang             "",
334*f585d8a3SJacky Wang             "import dagger.Module;",
335*f585d8a3SJacky Wang             "import dagger.Provides;",
336*f585d8a3SJacky Wang             "",
337*f585d8a3SJacky Wang             "@Module",
338*f585d8a3SJacky Wang             "final class TestModule {",
339*f585d8a3SJacky Wang             "  @Provides String s() { return null; }",
340*f585d8a3SJacky Wang             "}");
341*f585d8a3SJacky Wang     Source testComponent =
342*f585d8a3SJacky Wang         CompilerTests.javaSource(
343*f585d8a3SJacky Wang             "test.TestComponent",
344*f585d8a3SJacky Wang             "package test;",
345*f585d8a3SJacky Wang             "",
346*f585d8a3SJacky Wang             "import dagger.Component;",
347*f585d8a3SJacky Wang             "",
348*f585d8a3SJacky Wang             "@Component(dependencies = TestModule.class)",
349*f585d8a3SJacky Wang             "interface TestComponent {}");
350*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(testModule, testComponent)
351*f585d8a3SJacky Wang         .compile(
352*f585d8a3SJacky Wang             subject -> {
353*f585d8a3SJacky Wang               subject.hasErrorCount(1);
354*f585d8a3SJacky Wang               subject.hasErrorContaining(
355*f585d8a3SJacky Wang                   "test.TestModule is a module, which cannot be a component dependency");
356*f585d8a3SJacky Wang             });
357*f585d8a3SJacky Wang   }
358*f585d8a3SJacky Wang 
359*f585d8a3SJacky Wang   @Test
componentDependencyMustNotCycle_Direct()360*f585d8a3SJacky Wang   public void componentDependencyMustNotCycle_Direct() {
361*f585d8a3SJacky Wang     Source shortLifetime =
362*f585d8a3SJacky Wang         CompilerTests.javaSource(
363*f585d8a3SJacky Wang             "test.ComponentShort",
364*f585d8a3SJacky Wang             "package test;",
365*f585d8a3SJacky Wang             "",
366*f585d8a3SJacky Wang             "import dagger.Component;",
367*f585d8a3SJacky Wang             "",
368*f585d8a3SJacky Wang             "@Component(dependencies = ComponentShort.class)",
369*f585d8a3SJacky Wang             "interface ComponentShort {",
370*f585d8a3SJacky Wang             "}");
371*f585d8a3SJacky Wang 
372*f585d8a3SJacky Wang     String errorMessage =
373*f585d8a3SJacky Wang         message(
374*f585d8a3SJacky Wang             "test.ComponentShort contains a cycle in its component dependencies:",
375*f585d8a3SJacky Wang             "    test.ComponentShort");
376*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(shortLifetime)
377*f585d8a3SJacky Wang         .compile(
378*f585d8a3SJacky Wang             subject -> {
379*f585d8a3SJacky Wang               subject.hasErrorCount(1);
380*f585d8a3SJacky Wang               subject.hasErrorContaining(errorMessage);
381*f585d8a3SJacky Wang             });
382*f585d8a3SJacky Wang 
383*f585d8a3SJacky Wang     // Test that this also fails when transitive validation is disabled.
384*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(shortLifetime)
385*f585d8a3SJacky Wang         .withProcessingOptions(
386*f585d8a3SJacky Wang             ImmutableMap.of("dagger.validateTransitiveComponentDependencies", "DISABLED"))
387*f585d8a3SJacky Wang         .compile(
388*f585d8a3SJacky Wang             subject -> {
389*f585d8a3SJacky Wang               subject.hasErrorCount(1);
390*f585d8a3SJacky Wang               subject.hasErrorContaining(errorMessage);
391*f585d8a3SJacky Wang             });
392*f585d8a3SJacky Wang   }
393*f585d8a3SJacky Wang 
394*f585d8a3SJacky Wang   @Test
componentDependencyMustNotCycle_Indirect()395*f585d8a3SJacky Wang   public void componentDependencyMustNotCycle_Indirect() {
396*f585d8a3SJacky Wang     Source longLifetime =
397*f585d8a3SJacky Wang         CompilerTests.javaSource(
398*f585d8a3SJacky Wang             "test.ComponentLong",
399*f585d8a3SJacky Wang             "package test;",
400*f585d8a3SJacky Wang             "",
401*f585d8a3SJacky Wang             "import dagger.Component;",
402*f585d8a3SJacky Wang             "",
403*f585d8a3SJacky Wang             "@Component(dependencies = ComponentMedium.class)",
404*f585d8a3SJacky Wang             "interface ComponentLong {",
405*f585d8a3SJacky Wang             "}");
406*f585d8a3SJacky Wang     Source mediumLifetime =
407*f585d8a3SJacky Wang         CompilerTests.javaSource(
408*f585d8a3SJacky Wang             "test.ComponentMedium",
409*f585d8a3SJacky Wang             "package test;",
410*f585d8a3SJacky Wang             "",
411*f585d8a3SJacky Wang             "import dagger.Component;",
412*f585d8a3SJacky Wang             "",
413*f585d8a3SJacky Wang             "@Component(dependencies = ComponentLong.class)",
414*f585d8a3SJacky Wang             "interface ComponentMedium {",
415*f585d8a3SJacky Wang             "}");
416*f585d8a3SJacky Wang     Source shortLifetime =
417*f585d8a3SJacky Wang         CompilerTests.javaSource(
418*f585d8a3SJacky Wang             "test.ComponentShort",
419*f585d8a3SJacky Wang             "package test;",
420*f585d8a3SJacky Wang             "",
421*f585d8a3SJacky Wang             "import dagger.Component;",
422*f585d8a3SJacky Wang             "",
423*f585d8a3SJacky Wang             "@Component(dependencies = ComponentMedium.class)",
424*f585d8a3SJacky Wang             "interface ComponentShort {",
425*f585d8a3SJacky Wang             "}");
426*f585d8a3SJacky Wang 
427*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(longLifetime, mediumLifetime, shortLifetime)
428*f585d8a3SJacky Wang         .compile(
429*f585d8a3SJacky Wang             subject -> {
430*f585d8a3SJacky Wang               subject.hasErrorCount(3);
431*f585d8a3SJacky Wang               subject.hasErrorContaining(
432*f585d8a3SJacky Wang                       message(
433*f585d8a3SJacky Wang                           "test.ComponentLong contains a cycle in its component dependencies:",
434*f585d8a3SJacky Wang                           "    test.ComponentLong",
435*f585d8a3SJacky Wang                           "    test.ComponentMedium",
436*f585d8a3SJacky Wang                           "    test.ComponentLong"))
437*f585d8a3SJacky Wang                   .onSource(longLifetime);
438*f585d8a3SJacky Wang               subject.hasErrorContaining(
439*f585d8a3SJacky Wang                       message(
440*f585d8a3SJacky Wang                           "test.ComponentMedium contains a cycle in its component dependencies:",
441*f585d8a3SJacky Wang                           "    test.ComponentMedium",
442*f585d8a3SJacky Wang                           "    test.ComponentLong",
443*f585d8a3SJacky Wang                           "    test.ComponentMedium"))
444*f585d8a3SJacky Wang                   .onSource(mediumLifetime);
445*f585d8a3SJacky Wang               subject.hasErrorContaining(
446*f585d8a3SJacky Wang                       message(
447*f585d8a3SJacky Wang                           "test.ComponentShort contains a cycle in its component dependencies:",
448*f585d8a3SJacky Wang                           "    test.ComponentMedium",
449*f585d8a3SJacky Wang                           "    test.ComponentLong",
450*f585d8a3SJacky Wang                           "    test.ComponentMedium",
451*f585d8a3SJacky Wang                           "    test.ComponentShort"))
452*f585d8a3SJacky Wang                   .onSource(shortLifetime);
453*f585d8a3SJacky Wang             });
454*f585d8a3SJacky Wang 
455*f585d8a3SJacky Wang     // Test that compilation succeeds when transitive validation is disabled because the cycle
456*f585d8a3SJacky Wang     // cannot be detected.
457*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(longLifetime, mediumLifetime, shortLifetime)
458*f585d8a3SJacky Wang         .withProcessingOptions(
459*f585d8a3SJacky Wang             ImmutableMap.of("dagger.validateTransitiveComponentDependencies", "DISABLED"))
460*f585d8a3SJacky Wang         .compile(subject -> subject.hasErrorCount(0));
461*f585d8a3SJacky Wang   }
462*f585d8a3SJacky Wang 
463*f585d8a3SJacky Wang   @Test
abstractModuleWithInstanceMethod()464*f585d8a3SJacky Wang   public void abstractModuleWithInstanceMethod() {
465*f585d8a3SJacky Wang     Source module =
466*f585d8a3SJacky Wang         CompilerTests.javaSource(
467*f585d8a3SJacky Wang             "test.TestModule",
468*f585d8a3SJacky Wang             "package test;",
469*f585d8a3SJacky Wang             "",
470*f585d8a3SJacky Wang             "import dagger.Module;",
471*f585d8a3SJacky Wang             "import dagger.Provides;",
472*f585d8a3SJacky Wang             "",
473*f585d8a3SJacky Wang             "@Module",
474*f585d8a3SJacky Wang             "abstract class TestModule {",
475*f585d8a3SJacky Wang             "  @Provides int i() { return 1; }",
476*f585d8a3SJacky Wang             "}");
477*f585d8a3SJacky Wang     Source component =
478*f585d8a3SJacky Wang         CompilerTests.javaSource(
479*f585d8a3SJacky Wang             "test.TestComponent",
480*f585d8a3SJacky Wang             "package test;",
481*f585d8a3SJacky Wang             "",
482*f585d8a3SJacky Wang             "import dagger.Component;",
483*f585d8a3SJacky Wang             "",
484*f585d8a3SJacky Wang             "@Component(modules = TestModule.class)",
485*f585d8a3SJacky Wang             "interface TestComponent {",
486*f585d8a3SJacky Wang             "  int i();",
487*f585d8a3SJacky Wang             "}");
488*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(module, component)
489*f585d8a3SJacky Wang         .compile(
490*f585d8a3SJacky Wang             subject -> {
491*f585d8a3SJacky Wang               subject.hasErrorCount(1);
492*f585d8a3SJacky Wang               subject.hasErrorContaining(
493*f585d8a3SJacky Wang                       "TestModule is abstract and has instance @Provides methods")
494*f585d8a3SJacky Wang                   .onSource(component)
495*f585d8a3SJacky Wang                   .onLineContaining("interface TestComponent");
496*f585d8a3SJacky Wang             });
497*f585d8a3SJacky Wang   }
498*f585d8a3SJacky Wang 
499*f585d8a3SJacky Wang   @Test
abstractModuleWithInstanceMethod_subclassedIsAllowed()500*f585d8a3SJacky Wang   public void abstractModuleWithInstanceMethod_subclassedIsAllowed() {
501*f585d8a3SJacky Wang     Source abstractModule =
502*f585d8a3SJacky Wang         CompilerTests.javaSource(
503*f585d8a3SJacky Wang             "test.AbstractModule",
504*f585d8a3SJacky Wang             "package test;",
505*f585d8a3SJacky Wang             "",
506*f585d8a3SJacky Wang             "import dagger.Module;",
507*f585d8a3SJacky Wang             "import dagger.Provides;",
508*f585d8a3SJacky Wang             "",
509*f585d8a3SJacky Wang             "@Module",
510*f585d8a3SJacky Wang             "abstract class AbstractModule {",
511*f585d8a3SJacky Wang             "  @Provides int i() { return 1; }",
512*f585d8a3SJacky Wang             "}");
513*f585d8a3SJacky Wang     Source subclassedModule =
514*f585d8a3SJacky Wang         CompilerTests.javaSource(
515*f585d8a3SJacky Wang             "test.SubclassedModule",
516*f585d8a3SJacky Wang             "package test;",
517*f585d8a3SJacky Wang             "",
518*f585d8a3SJacky Wang             "import dagger.Module;",
519*f585d8a3SJacky Wang             "",
520*f585d8a3SJacky Wang             "@Module",
521*f585d8a3SJacky Wang             "class SubclassedModule extends AbstractModule {}");
522*f585d8a3SJacky Wang     Source component =
523*f585d8a3SJacky Wang         CompilerTests.javaSource(
524*f585d8a3SJacky Wang             "test.TestComponent",
525*f585d8a3SJacky Wang             "package test;",
526*f585d8a3SJacky Wang             "",
527*f585d8a3SJacky Wang             "import dagger.Component;",
528*f585d8a3SJacky Wang             "",
529*f585d8a3SJacky Wang             "@Component(modules = SubclassedModule.class)",
530*f585d8a3SJacky Wang             "interface TestComponent {",
531*f585d8a3SJacky Wang             "  int i();",
532*f585d8a3SJacky Wang             "}");
533*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(abstractModule, subclassedModule, component)
534*f585d8a3SJacky Wang         .compile(subject -> subject.hasErrorCount(0));
535*f585d8a3SJacky Wang   }
536*f585d8a3SJacky Wang }
537