1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2016 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 androidx.room.compiler.processing.util.Source; 20*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList; 21*f585d8a3SJacky Wang import com.google.common.collect.ImmutableMap; 22*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests; 23*f585d8a3SJacky Wang import org.junit.Test; 24*f585d8a3SJacky Wang import org.junit.runner.RunWith; 25*f585d8a3SJacky Wang import org.junit.runners.Parameterized; 26*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters; 27*f585d8a3SJacky Wang 28*f585d8a3SJacky Wang /** Tests for {ComponentHierarchyValidator}. */ 29*f585d8a3SJacky Wang @RunWith(Parameterized.class) 30*f585d8a3SJacky Wang public class ComponentHierarchyValidationTest { 31*f585d8a3SJacky Wang @Parameters(name = "{0}") parameters()32*f585d8a3SJacky Wang public static ImmutableList<Object[]> parameters() { 33*f585d8a3SJacky Wang return CompilerMode.TEST_PARAMETERS; 34*f585d8a3SJacky Wang } 35*f585d8a3SJacky Wang 36*f585d8a3SJacky Wang private final CompilerMode compilerMode; 37*f585d8a3SJacky Wang ComponentHierarchyValidationTest(CompilerMode compilerMode)38*f585d8a3SJacky Wang public ComponentHierarchyValidationTest(CompilerMode compilerMode) { 39*f585d8a3SJacky Wang this.compilerMode = compilerMode; 40*f585d8a3SJacky Wang } 41*f585d8a3SJacky Wang 42*f585d8a3SJacky Wang @Test singletonSubcomponent()43*f585d8a3SJacky Wang public void singletonSubcomponent() { 44*f585d8a3SJacky Wang Source component = 45*f585d8a3SJacky Wang CompilerTests.javaSource( 46*f585d8a3SJacky Wang "test.Parent", 47*f585d8a3SJacky Wang "package test;", 48*f585d8a3SJacky Wang "", 49*f585d8a3SJacky Wang "import dagger.Component;", 50*f585d8a3SJacky Wang "import javax.inject.Singleton;", 51*f585d8a3SJacky Wang "", 52*f585d8a3SJacky Wang "@Singleton", 53*f585d8a3SJacky Wang "@Component", 54*f585d8a3SJacky Wang "interface Parent {", 55*f585d8a3SJacky Wang " Child child();", 56*f585d8a3SJacky Wang "}"); 57*f585d8a3SJacky Wang Source subcomponent = 58*f585d8a3SJacky Wang CompilerTests.javaSource( 59*f585d8a3SJacky Wang "test.Child", 60*f585d8a3SJacky Wang "package test;", 61*f585d8a3SJacky Wang "", 62*f585d8a3SJacky Wang "import dagger.Subcomponent;", 63*f585d8a3SJacky Wang "import javax.inject.Singleton;", 64*f585d8a3SJacky Wang "", 65*f585d8a3SJacky Wang "@Singleton", 66*f585d8a3SJacky Wang "@Subcomponent", 67*f585d8a3SJacky Wang "interface Child {}"); 68*f585d8a3SJacky Wang 69*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component, subcomponent) 70*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 71*f585d8a3SJacky Wang .compile( 72*f585d8a3SJacky Wang subject -> { 73*f585d8a3SJacky Wang subject.hasErrorCount(1); 74*f585d8a3SJacky Wang subject.hasErrorContaining( 75*f585d8a3SJacky Wang String.join( 76*f585d8a3SJacky Wang "\n", 77*f585d8a3SJacky Wang "test.Child has conflicting scopes:", 78*f585d8a3SJacky Wang " test.Parent also has @Singleton")); 79*f585d8a3SJacky Wang }); 80*f585d8a3SJacky Wang 81*f585d8a3SJacky Wang // Check that compiling with disableInterComponentScopeValidation=none flag succeeds. 82*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component, subcomponent) 83*f585d8a3SJacky Wang .withProcessingOptions( 84*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 85*f585d8a3SJacky Wang .putAll(compilerMode.processorOptions()) 86*f585d8a3SJacky Wang .put("dagger.disableInterComponentScopeValidation", "none") 87*f585d8a3SJacky Wang .buildOrThrow()) 88*f585d8a3SJacky Wang .compile(subject -> subject.hasErrorCount(0)); 89*f585d8a3SJacky Wang } 90*f585d8a3SJacky Wang 91*f585d8a3SJacky Wang @Test productionComponents_productionScopeImplicitOnBoth()92*f585d8a3SJacky Wang public void productionComponents_productionScopeImplicitOnBoth() { 93*f585d8a3SJacky Wang Source component = 94*f585d8a3SJacky Wang CompilerTests.javaSource( 95*f585d8a3SJacky Wang "test.Parent", 96*f585d8a3SJacky Wang "package test;", 97*f585d8a3SJacky Wang "", 98*f585d8a3SJacky Wang "import dagger.producers.ProductionComponent;", 99*f585d8a3SJacky Wang "", 100*f585d8a3SJacky Wang "@ProductionComponent(modules = ParentModule.class)", 101*f585d8a3SJacky Wang "interface Parent {", 102*f585d8a3SJacky Wang " Child child();", 103*f585d8a3SJacky Wang " Object productionScopedObject();", 104*f585d8a3SJacky Wang "}"); 105*f585d8a3SJacky Wang Source parentModule = 106*f585d8a3SJacky Wang CompilerTests.javaSource( 107*f585d8a3SJacky Wang "test.ParentModule", 108*f585d8a3SJacky Wang "package test;", 109*f585d8a3SJacky Wang "", 110*f585d8a3SJacky Wang "import dagger.Provides;", 111*f585d8a3SJacky Wang "import dagger.producers.ProducerModule;", 112*f585d8a3SJacky Wang "import dagger.producers.ProductionScope;", 113*f585d8a3SJacky Wang "", 114*f585d8a3SJacky Wang "@ProducerModule", 115*f585d8a3SJacky Wang "class ParentModule {", 116*f585d8a3SJacky Wang " @Provides @ProductionScope Object parentScopedObject() { return new Object(); }", 117*f585d8a3SJacky Wang "}"); 118*f585d8a3SJacky Wang Source subcomponent = 119*f585d8a3SJacky Wang CompilerTests.javaSource( 120*f585d8a3SJacky Wang "test.Child", 121*f585d8a3SJacky Wang "package test;", 122*f585d8a3SJacky Wang "", 123*f585d8a3SJacky Wang "import dagger.producers.ProductionSubcomponent;", 124*f585d8a3SJacky Wang "", 125*f585d8a3SJacky Wang "@ProductionSubcomponent(modules = ChildModule.class)", 126*f585d8a3SJacky Wang "interface Child {", 127*f585d8a3SJacky Wang " String productionScopedString();", 128*f585d8a3SJacky Wang "}"); 129*f585d8a3SJacky Wang Source childModule = 130*f585d8a3SJacky Wang CompilerTests.javaSource( 131*f585d8a3SJacky Wang "test.ChildModule", 132*f585d8a3SJacky Wang "package test;", 133*f585d8a3SJacky Wang "", 134*f585d8a3SJacky Wang "import dagger.Provides;", 135*f585d8a3SJacky Wang "import dagger.producers.ProducerModule;", 136*f585d8a3SJacky Wang "import dagger.producers.ProductionScope;", 137*f585d8a3SJacky Wang "", 138*f585d8a3SJacky Wang "@ProducerModule", 139*f585d8a3SJacky Wang "class ChildModule {", 140*f585d8a3SJacky Wang " @Provides @ProductionScope String childScopedString() { return new String(); }", 141*f585d8a3SJacky Wang "}"); 142*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component, subcomponent, parentModule, childModule) 143*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 144*f585d8a3SJacky Wang .compile(subject -> subject.hasErrorCount(0)); 145*f585d8a3SJacky Wang } 146*f585d8a3SJacky Wang 147*f585d8a3SJacky Wang @Test producerModuleRepeated()148*f585d8a3SJacky Wang public void producerModuleRepeated() { 149*f585d8a3SJacky Wang Source component = 150*f585d8a3SJacky Wang CompilerTests.javaSource( 151*f585d8a3SJacky Wang "test.Parent", 152*f585d8a3SJacky Wang "package test;", 153*f585d8a3SJacky Wang "", 154*f585d8a3SJacky Wang "import dagger.producers.ProductionComponent;", 155*f585d8a3SJacky Wang "", 156*f585d8a3SJacky Wang "@ProductionComponent(modules = RepeatedProducerModule.class)", 157*f585d8a3SJacky Wang "interface Parent {", 158*f585d8a3SJacky Wang " Child child();", 159*f585d8a3SJacky Wang "}"); 160*f585d8a3SJacky Wang Source repeatedModule = 161*f585d8a3SJacky Wang CompilerTests.javaSource( 162*f585d8a3SJacky Wang "test.RepeatedProducerModule", 163*f585d8a3SJacky Wang "package test;", 164*f585d8a3SJacky Wang "", 165*f585d8a3SJacky Wang "import dagger.producers.ProducerModule;", 166*f585d8a3SJacky Wang "", 167*f585d8a3SJacky Wang "@ProducerModule", 168*f585d8a3SJacky Wang "interface RepeatedProducerModule {}"); 169*f585d8a3SJacky Wang Source subcomponent = 170*f585d8a3SJacky Wang CompilerTests.javaSource( 171*f585d8a3SJacky Wang "test.Child", 172*f585d8a3SJacky Wang "package test;", 173*f585d8a3SJacky Wang "", 174*f585d8a3SJacky Wang "import dagger.producers.ProductionSubcomponent;", 175*f585d8a3SJacky Wang "", 176*f585d8a3SJacky Wang "@ProductionSubcomponent(modules = RepeatedProducerModule.class)", 177*f585d8a3SJacky Wang "interface Child {}"); 178*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component, subcomponent, repeatedModule) 179*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 180*f585d8a3SJacky Wang .compile( 181*f585d8a3SJacky Wang subject -> { 182*f585d8a3SJacky Wang subject.hasErrorCount(1); 183*f585d8a3SJacky Wang subject.hasErrorContaining( 184*f585d8a3SJacky Wang String.join( 185*f585d8a3SJacky Wang "\n", 186*f585d8a3SJacky Wang "test.Child repeats @ProducerModules:", 187*f585d8a3SJacky Wang "test.Parent also installs: test.RepeatedProducerModule")) 188*f585d8a3SJacky Wang .onSource(component) 189*f585d8a3SJacky Wang .onLineContaining("interface Parent"); 190*f585d8a3SJacky Wang }); 191*f585d8a3SJacky Wang } 192*f585d8a3SJacky Wang 193*f585d8a3SJacky Wang @Test factoryMethodForSubcomponentWithBuilder_isNotAllowed()194*f585d8a3SJacky Wang public void factoryMethodForSubcomponentWithBuilder_isNotAllowed() { 195*f585d8a3SJacky Wang Source module = 196*f585d8a3SJacky Wang CompilerTests.javaSource( 197*f585d8a3SJacky Wang "test.TestModule", 198*f585d8a3SJacky Wang "package test;", 199*f585d8a3SJacky Wang "", 200*f585d8a3SJacky Wang "import dagger.Module;", 201*f585d8a3SJacky Wang "import dagger.Provides;", 202*f585d8a3SJacky Wang "", 203*f585d8a3SJacky Wang "@Module(subcomponents = Sub.class)", 204*f585d8a3SJacky Wang "class TestModule {", 205*f585d8a3SJacky Wang "}"); 206*f585d8a3SJacky Wang 207*f585d8a3SJacky Wang Source subcomponent = 208*f585d8a3SJacky Wang CompilerTests.javaSource( 209*f585d8a3SJacky Wang "test.Sub", 210*f585d8a3SJacky Wang "package test;", 211*f585d8a3SJacky Wang "", 212*f585d8a3SJacky Wang "import dagger.Subcomponent;", 213*f585d8a3SJacky Wang "", 214*f585d8a3SJacky Wang "@Subcomponent", 215*f585d8a3SJacky Wang "interface Sub {", 216*f585d8a3SJacky Wang " @Subcomponent.Builder", 217*f585d8a3SJacky Wang " interface Builder {", 218*f585d8a3SJacky Wang " Sub build();", 219*f585d8a3SJacky Wang " }", 220*f585d8a3SJacky Wang "}"); 221*f585d8a3SJacky Wang 222*f585d8a3SJacky Wang Source component = 223*f585d8a3SJacky Wang CompilerTests.javaSource( 224*f585d8a3SJacky Wang "test.C", 225*f585d8a3SJacky Wang "package test;", 226*f585d8a3SJacky Wang "", 227*f585d8a3SJacky Wang "import dagger.Component;", 228*f585d8a3SJacky Wang "", 229*f585d8a3SJacky Wang "@Component(modules = TestModule.class)", 230*f585d8a3SJacky Wang "interface C {", 231*f585d8a3SJacky Wang " Sub newSub();", 232*f585d8a3SJacky Wang "}"); 233*f585d8a3SJacky Wang 234*f585d8a3SJacky Wang CompilerTests.daggerCompiler(module, component, subcomponent) 235*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 236*f585d8a3SJacky Wang .compile( 237*f585d8a3SJacky Wang subject -> { 238*f585d8a3SJacky Wang subject.hasErrorCount(1); 239*f585d8a3SJacky Wang subject.hasErrorContaining( 240*f585d8a3SJacky Wang "Components may not have factory methods for subcomponents that define a " 241*f585d8a3SJacky Wang + "builder."); 242*f585d8a3SJacky Wang }); 243*f585d8a3SJacky Wang } 244*f585d8a3SJacky Wang 245*f585d8a3SJacky Wang @Test repeatedModulesWithScopes()246*f585d8a3SJacky Wang public void repeatedModulesWithScopes() { 247*f585d8a3SJacky Wang Source testScope = 248*f585d8a3SJacky Wang CompilerTests.javaSource( 249*f585d8a3SJacky Wang "test.TestScope", 250*f585d8a3SJacky Wang "package test;", 251*f585d8a3SJacky Wang "", 252*f585d8a3SJacky Wang "import javax.inject.Scope;", 253*f585d8a3SJacky Wang "", 254*f585d8a3SJacky Wang "@Scope", 255*f585d8a3SJacky Wang "@interface TestScope {}"); 256*f585d8a3SJacky Wang Source moduleWithScopedProvides = 257*f585d8a3SJacky Wang CompilerTests.javaSource( 258*f585d8a3SJacky Wang "test.ModuleWithScopedProvides", 259*f585d8a3SJacky Wang "package test;", 260*f585d8a3SJacky Wang "", 261*f585d8a3SJacky Wang "import dagger.Module;", 262*f585d8a3SJacky Wang "import dagger.Provides;", 263*f585d8a3SJacky Wang "", 264*f585d8a3SJacky Wang "@Module", 265*f585d8a3SJacky Wang "class ModuleWithScopedProvides {", 266*f585d8a3SJacky Wang " @Provides", 267*f585d8a3SJacky Wang " @TestScope", 268*f585d8a3SJacky Wang " static Object o() { return new Object(); }", 269*f585d8a3SJacky Wang "}"); 270*f585d8a3SJacky Wang Source moduleWithScopedBinds = 271*f585d8a3SJacky Wang CompilerTests.javaSource( 272*f585d8a3SJacky Wang "test.ModuleWithScopedBinds", 273*f585d8a3SJacky Wang "package test;", 274*f585d8a3SJacky Wang "", 275*f585d8a3SJacky Wang "import dagger.Binds;", 276*f585d8a3SJacky Wang "import dagger.Module;", 277*f585d8a3SJacky Wang "", 278*f585d8a3SJacky Wang "@Module", 279*f585d8a3SJacky Wang "interface ModuleWithScopedBinds {", 280*f585d8a3SJacky Wang " @Binds", 281*f585d8a3SJacky Wang " @TestScope", 282*f585d8a3SJacky Wang " Object o(String s);", 283*f585d8a3SJacky Wang "}"); 284*f585d8a3SJacky Wang Source parent = 285*f585d8a3SJacky Wang CompilerTests.javaSource( 286*f585d8a3SJacky Wang "test.Parent", 287*f585d8a3SJacky Wang "package test;", 288*f585d8a3SJacky Wang "", 289*f585d8a3SJacky Wang "import dagger.Component;", 290*f585d8a3SJacky Wang "", 291*f585d8a3SJacky Wang "@Component(modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})", 292*f585d8a3SJacky Wang "interface Parent {", 293*f585d8a3SJacky Wang " Child child();", 294*f585d8a3SJacky Wang "}"); 295*f585d8a3SJacky Wang Source child = 296*f585d8a3SJacky Wang CompilerTests.javaSource( 297*f585d8a3SJacky Wang "test.Child", 298*f585d8a3SJacky Wang "package test;", 299*f585d8a3SJacky Wang "", 300*f585d8a3SJacky Wang "import dagger.Subcomponent;", 301*f585d8a3SJacky Wang "", 302*f585d8a3SJacky Wang "@Subcomponent(", 303*f585d8a3SJacky Wang " modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})", 304*f585d8a3SJacky Wang "interface Child {}"); 305*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 306*f585d8a3SJacky Wang testScope, moduleWithScopedProvides, moduleWithScopedBinds, parent, child) 307*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 308*f585d8a3SJacky Wang .compile( 309*f585d8a3SJacky Wang subject -> { 310*f585d8a3SJacky Wang subject.hasErrorCount(1); 311*f585d8a3SJacky Wang subject.hasErrorContaining( 312*f585d8a3SJacky Wang String.join( 313*f585d8a3SJacky Wang "\n", 314*f585d8a3SJacky Wang "test.Child repeats modules with scoped bindings or declarations:", 315*f585d8a3SJacky Wang "- test.Parent also includes:", 316*f585d8a3SJacky Wang " - test.ModuleWithScopedProvides with scopes: @test.TestScope", 317*f585d8a3SJacky Wang " - test.ModuleWithScopedBinds with scopes: @test.TestScope")); 318*f585d8a3SJacky Wang }); 319*f585d8a3SJacky Wang } 320*f585d8a3SJacky Wang 321*f585d8a3SJacky Wang @Test repeatedModulesWithReusableScope()322*f585d8a3SJacky Wang public void repeatedModulesWithReusableScope() { 323*f585d8a3SJacky Wang Source moduleWithScopedProvides = 324*f585d8a3SJacky Wang CompilerTests.javaSource( 325*f585d8a3SJacky Wang "test.ModuleWithScopedProvides", 326*f585d8a3SJacky Wang "package test;", 327*f585d8a3SJacky Wang "", 328*f585d8a3SJacky Wang "import dagger.Module;", 329*f585d8a3SJacky Wang "import dagger.Provides;", 330*f585d8a3SJacky Wang "import dagger.Reusable;", 331*f585d8a3SJacky Wang "", 332*f585d8a3SJacky Wang "@Module", 333*f585d8a3SJacky Wang "class ModuleWithScopedProvides {", 334*f585d8a3SJacky Wang " @Provides", 335*f585d8a3SJacky Wang " @Reusable", 336*f585d8a3SJacky Wang " static Object o() { return new Object(); }", 337*f585d8a3SJacky Wang "}"); 338*f585d8a3SJacky Wang Source moduleWithScopedBinds = 339*f585d8a3SJacky Wang CompilerTests.javaSource( 340*f585d8a3SJacky Wang "test.ModuleWithScopedBinds", 341*f585d8a3SJacky Wang "package test;", 342*f585d8a3SJacky Wang "", 343*f585d8a3SJacky Wang "import dagger.Binds;", 344*f585d8a3SJacky Wang "import dagger.Module;", 345*f585d8a3SJacky Wang "import dagger.Reusable;", 346*f585d8a3SJacky Wang "", 347*f585d8a3SJacky Wang "@Module", 348*f585d8a3SJacky Wang "interface ModuleWithScopedBinds {", 349*f585d8a3SJacky Wang " @Binds", 350*f585d8a3SJacky Wang " @Reusable", 351*f585d8a3SJacky Wang " Object o(String s);", 352*f585d8a3SJacky Wang "}"); 353*f585d8a3SJacky Wang Source parent = 354*f585d8a3SJacky Wang CompilerTests.javaSource( 355*f585d8a3SJacky Wang "test.Parent", 356*f585d8a3SJacky Wang "package test;", 357*f585d8a3SJacky Wang "", 358*f585d8a3SJacky Wang "import dagger.Component;", 359*f585d8a3SJacky Wang "", 360*f585d8a3SJacky Wang "@Component(modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})", 361*f585d8a3SJacky Wang "interface Parent {", 362*f585d8a3SJacky Wang " Child child();", 363*f585d8a3SJacky Wang "}"); 364*f585d8a3SJacky Wang Source child = 365*f585d8a3SJacky Wang CompilerTests.javaSource( 366*f585d8a3SJacky Wang "test.Child", 367*f585d8a3SJacky Wang "package test;", 368*f585d8a3SJacky Wang "", 369*f585d8a3SJacky Wang "import dagger.Subcomponent;", 370*f585d8a3SJacky Wang "", 371*f585d8a3SJacky Wang "@Subcomponent(", 372*f585d8a3SJacky Wang " modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})", 373*f585d8a3SJacky Wang "interface Child {}"); 374*f585d8a3SJacky Wang CompilerTests.daggerCompiler(moduleWithScopedProvides, moduleWithScopedBinds, parent, child) 375*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 376*f585d8a3SJacky Wang .compile( 377*f585d8a3SJacky Wang subject -> { 378*f585d8a3SJacky Wang subject.hasErrorCount(0); 379*f585d8a3SJacky Wang subject.hasWarningCount(0); 380*f585d8a3SJacky Wang }); 381*f585d8a3SJacky Wang } 382*f585d8a3SJacky Wang } 383