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