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 androidx.room.compiler.processing.XProcessingEnv; 20*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source; 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.JUnit4; 26*f585d8a3SJacky Wang 27*f585d8a3SJacky Wang @RunWith(JUnit4.class) 28*f585d8a3SJacky Wang public class ScopingValidationTest { 29*f585d8a3SJacky Wang @Test componentWithoutScopeIncludesScopedBindings_Fail()30*f585d8a3SJacky Wang public void componentWithoutScopeIncludesScopedBindings_Fail() { 31*f585d8a3SJacky Wang Source componentFile = 32*f585d8a3SJacky Wang CompilerTests.javaSource( 33*f585d8a3SJacky Wang "test.MyComponent", 34*f585d8a3SJacky Wang "package test;", 35*f585d8a3SJacky Wang "", 36*f585d8a3SJacky Wang "import dagger.Component;", 37*f585d8a3SJacky Wang "import javax.inject.Singleton;", 38*f585d8a3SJacky Wang "", 39*f585d8a3SJacky Wang "@Component(modules = ScopedModule.class)", 40*f585d8a3SJacky Wang "interface MyComponent {", 41*f585d8a3SJacky Wang " ScopedType string();", 42*f585d8a3SJacky Wang "}"); 43*f585d8a3SJacky Wang Source typeFile = 44*f585d8a3SJacky Wang CompilerTests.javaSource( 45*f585d8a3SJacky Wang "test.ScopedType", 46*f585d8a3SJacky Wang "package test;", 47*f585d8a3SJacky Wang "", 48*f585d8a3SJacky Wang "import javax.inject.Inject;", 49*f585d8a3SJacky Wang "import javax.inject.Singleton;", 50*f585d8a3SJacky Wang "", 51*f585d8a3SJacky Wang "@Singleton", 52*f585d8a3SJacky Wang "class ScopedType {", 53*f585d8a3SJacky Wang " @Inject ScopedType(String s, long l, float f) {}", 54*f585d8a3SJacky Wang "}"); 55*f585d8a3SJacky Wang Source moduleFile = 56*f585d8a3SJacky Wang CompilerTests.javaSource( 57*f585d8a3SJacky Wang "test.ScopedModule", 58*f585d8a3SJacky Wang "package test;", 59*f585d8a3SJacky Wang "", 60*f585d8a3SJacky Wang "import dagger.Module;", 61*f585d8a3SJacky Wang "import dagger.Provides;", 62*f585d8a3SJacky Wang "import javax.inject.Singleton;", 63*f585d8a3SJacky Wang "", 64*f585d8a3SJacky Wang "@Module", 65*f585d8a3SJacky Wang "class ScopedModule {", 66*f585d8a3SJacky Wang " @Provides @Singleton String string() { return \"a string\"; }", 67*f585d8a3SJacky Wang " @Provides long integer() { return 0L; }", 68*f585d8a3SJacky Wang " @Provides float floatingPoint() { return 0.0f; }", 69*f585d8a3SJacky Wang "}"); 70*f585d8a3SJacky Wang 71*f585d8a3SJacky Wang CompilerTests.daggerCompiler(componentFile, typeFile, moduleFile) 72*f585d8a3SJacky Wang .compile( 73*f585d8a3SJacky Wang subject -> { 74*f585d8a3SJacky Wang subject.hasErrorCount(1); 75*f585d8a3SJacky Wang subject.hasErrorContaining( 76*f585d8a3SJacky Wang String.join( 77*f585d8a3SJacky Wang "\n", 78*f585d8a3SJacky Wang "MyComponent (unscoped) may not reference scoped bindings:", 79*f585d8a3SJacky Wang " @Singleton class ScopedType", 80*f585d8a3SJacky Wang " ScopedType is requested at", 81*f585d8a3SJacky Wang " MyComponent.string()", 82*f585d8a3SJacky Wang "", 83*f585d8a3SJacky Wang " @Provides @Singleton String ScopedModule.string()")); 84*f585d8a3SJacky Wang }); 85*f585d8a3SJacky Wang } 86*f585d8a3SJacky Wang 87*f585d8a3SJacky Wang @Test // b/79859714 bindsWithChildScope_inParentModule_notAllowed()88*f585d8a3SJacky Wang public void bindsWithChildScope_inParentModule_notAllowed() { 89*f585d8a3SJacky Wang Source childScope = 90*f585d8a3SJacky Wang CompilerTests.javaSource( 91*f585d8a3SJacky Wang "test.ChildScope", 92*f585d8a3SJacky Wang "package test;", 93*f585d8a3SJacky Wang "", 94*f585d8a3SJacky Wang "import javax.inject.Scope;", 95*f585d8a3SJacky Wang "", 96*f585d8a3SJacky Wang "@Scope", 97*f585d8a3SJacky Wang "@interface ChildScope {}"); 98*f585d8a3SJacky Wang 99*f585d8a3SJacky Wang Source foo = 100*f585d8a3SJacky Wang CompilerTests.javaSource( 101*f585d8a3SJacky Wang "test.Foo", 102*f585d8a3SJacky Wang "package test;", 103*f585d8a3SJacky Wang "", // 104*f585d8a3SJacky Wang "interface Foo {}"); 105*f585d8a3SJacky Wang 106*f585d8a3SJacky Wang Source fooImpl = 107*f585d8a3SJacky Wang CompilerTests.javaSource( 108*f585d8a3SJacky Wang "test.FooImpl", 109*f585d8a3SJacky Wang "package test;", 110*f585d8a3SJacky Wang "", 111*f585d8a3SJacky Wang "import javax.inject.Inject;", 112*f585d8a3SJacky Wang "", 113*f585d8a3SJacky Wang "class FooImpl implements Foo {", 114*f585d8a3SJacky Wang " @Inject FooImpl() {}", 115*f585d8a3SJacky Wang "}"); 116*f585d8a3SJacky Wang 117*f585d8a3SJacky Wang Source parentModule = 118*f585d8a3SJacky Wang CompilerTests.javaSource( 119*f585d8a3SJacky Wang "test.ParentModule", 120*f585d8a3SJacky Wang "package test;", 121*f585d8a3SJacky Wang "", 122*f585d8a3SJacky Wang "import dagger.Binds;", 123*f585d8a3SJacky Wang "import dagger.Module;", 124*f585d8a3SJacky Wang "", 125*f585d8a3SJacky Wang "@Module", 126*f585d8a3SJacky Wang "interface ParentModule {", 127*f585d8a3SJacky Wang " @Binds @ChildScope Foo bind(FooImpl fooImpl);", 128*f585d8a3SJacky Wang "}"); 129*f585d8a3SJacky Wang 130*f585d8a3SJacky Wang Source parent = 131*f585d8a3SJacky Wang CompilerTests.javaSource( 132*f585d8a3SJacky Wang "test.Parent", 133*f585d8a3SJacky Wang "package test;", 134*f585d8a3SJacky Wang "", 135*f585d8a3SJacky Wang "import dagger.Component;", 136*f585d8a3SJacky Wang "import javax.inject.Singleton;", 137*f585d8a3SJacky Wang "", 138*f585d8a3SJacky Wang "@Singleton", 139*f585d8a3SJacky Wang "@Component(modules = ParentModule.class)", 140*f585d8a3SJacky Wang "interface Parent {", 141*f585d8a3SJacky Wang " Child child();", 142*f585d8a3SJacky Wang "}"); 143*f585d8a3SJacky Wang 144*f585d8a3SJacky Wang Source child = 145*f585d8a3SJacky Wang CompilerTests.javaSource( 146*f585d8a3SJacky Wang "test.Child", 147*f585d8a3SJacky Wang "package test;", 148*f585d8a3SJacky Wang "", 149*f585d8a3SJacky Wang "import dagger.Subcomponent;", 150*f585d8a3SJacky Wang "", 151*f585d8a3SJacky Wang "@ChildScope", 152*f585d8a3SJacky Wang "@Subcomponent", 153*f585d8a3SJacky Wang "interface Child {", 154*f585d8a3SJacky Wang " Foo foo();", 155*f585d8a3SJacky Wang "}"); 156*f585d8a3SJacky Wang 157*f585d8a3SJacky Wang CompilerTests.daggerCompiler(childScope, foo, fooImpl, parentModule, parent, child) 158*f585d8a3SJacky Wang .compile( 159*f585d8a3SJacky Wang subject -> { 160*f585d8a3SJacky Wang subject.hasErrorCount(1); 161*f585d8a3SJacky Wang subject.hasErrorContaining( 162*f585d8a3SJacky Wang String.join( 163*f585d8a3SJacky Wang "\n", 164*f585d8a3SJacky Wang "Parent scoped with @Singleton may not reference bindings with different " 165*f585d8a3SJacky Wang + "scopes:", 166*f585d8a3SJacky Wang " @Binds @ChildScope Foo ParentModule.bind(FooImpl)")); 167*f585d8a3SJacky Wang }); 168*f585d8a3SJacky Wang } 169*f585d8a3SJacky Wang 170*f585d8a3SJacky Wang @Test componentWithScopeIncludesIncompatiblyScopedBindings_Fail()171*f585d8a3SJacky Wang public void componentWithScopeIncludesIncompatiblyScopedBindings_Fail() { 172*f585d8a3SJacky Wang Source componentFile = 173*f585d8a3SJacky Wang CompilerTests.javaSource( 174*f585d8a3SJacky Wang "test.MyComponent", 175*f585d8a3SJacky Wang "package test;", 176*f585d8a3SJacky Wang "", 177*f585d8a3SJacky Wang "import dagger.Component;", 178*f585d8a3SJacky Wang "import javax.inject.Singleton;", 179*f585d8a3SJacky Wang "", 180*f585d8a3SJacky Wang "@Singleton", 181*f585d8a3SJacky Wang "@Component(modules = ScopedModule.class)", 182*f585d8a3SJacky Wang "interface MyComponent {", 183*f585d8a3SJacky Wang " ScopedType string();", 184*f585d8a3SJacky Wang "}"); 185*f585d8a3SJacky Wang Source scopeFile = 186*f585d8a3SJacky Wang CompilerTests.javaSource( 187*f585d8a3SJacky Wang "test.PerTest", 188*f585d8a3SJacky Wang "package test;", 189*f585d8a3SJacky Wang "", 190*f585d8a3SJacky Wang "import javax.inject.Scope;", 191*f585d8a3SJacky Wang "", 192*f585d8a3SJacky Wang "@Scope", 193*f585d8a3SJacky Wang "@interface PerTest {}"); 194*f585d8a3SJacky Wang Source scopeWithAttribute = 195*f585d8a3SJacky Wang CompilerTests.javaSource( 196*f585d8a3SJacky Wang "test.Per", 197*f585d8a3SJacky Wang "package test;", 198*f585d8a3SJacky Wang "", 199*f585d8a3SJacky Wang "import javax.inject.Scope;", 200*f585d8a3SJacky Wang "", 201*f585d8a3SJacky Wang "@Scope", 202*f585d8a3SJacky Wang "@interface Per {", 203*f585d8a3SJacky Wang " Class<?> value();", 204*f585d8a3SJacky Wang "}"); 205*f585d8a3SJacky Wang Source typeFile = 206*f585d8a3SJacky Wang CompilerTests.javaSource( 207*f585d8a3SJacky Wang "test.ScopedType", 208*f585d8a3SJacky Wang "package test;", 209*f585d8a3SJacky Wang "", 210*f585d8a3SJacky Wang "import javax.inject.Inject;", 211*f585d8a3SJacky Wang "", 212*f585d8a3SJacky Wang "@PerTest", // incompatible scope 213*f585d8a3SJacky Wang "class ScopedType {", 214*f585d8a3SJacky Wang " @Inject ScopedType(String s, long l, float f, boolean b) {}", 215*f585d8a3SJacky Wang "}"); 216*f585d8a3SJacky Wang Source moduleFile = 217*f585d8a3SJacky Wang CompilerTests.javaSource( 218*f585d8a3SJacky Wang "test.ScopedModule", 219*f585d8a3SJacky Wang "package test;", 220*f585d8a3SJacky Wang "", 221*f585d8a3SJacky Wang "import dagger.Module;", 222*f585d8a3SJacky Wang "import dagger.Provides;", 223*f585d8a3SJacky Wang "import javax.inject.Singleton;", 224*f585d8a3SJacky Wang "", 225*f585d8a3SJacky Wang "@Module", 226*f585d8a3SJacky Wang "class ScopedModule {", 227*f585d8a3SJacky Wang " @Provides @PerTest String string() { return \"a string\"; }", // incompatible scope 228*f585d8a3SJacky Wang " @Provides long integer() { return 0L; }", // unscoped - valid 229*f585d8a3SJacky Wang " @Provides @Singleton float floatingPoint() { return 0.0f; }", // same scope - valid 230*f585d8a3SJacky Wang " @Provides @Per(MyComponent.class) boolean bool() { return false; }", // incompatible 231*f585d8a3SJacky Wang "}"); 232*f585d8a3SJacky Wang 233*f585d8a3SJacky Wang CompilerTests.daggerCompiler(componentFile, scopeFile, scopeWithAttribute, typeFile, moduleFile) 234*f585d8a3SJacky Wang .compile( 235*f585d8a3SJacky Wang subject -> { 236*f585d8a3SJacky Wang subject.hasErrorCount(1); 237*f585d8a3SJacky Wang subject 238*f585d8a3SJacky Wang .hasErrorContaining( 239*f585d8a3SJacky Wang String.join( 240*f585d8a3SJacky Wang "\n", 241*f585d8a3SJacky Wang "MyComponent scoped with @Singleton may not reference bindings with " 242*f585d8a3SJacky Wang + "different scopes:", 243*f585d8a3SJacky Wang " @PerTest class ScopedType", 244*f585d8a3SJacky Wang " ScopedType is requested at", 245*f585d8a3SJacky Wang " MyComponent.string()", 246*f585d8a3SJacky Wang "", 247*f585d8a3SJacky Wang " @Provides @PerTest String ScopedModule.string()", 248*f585d8a3SJacky Wang "", 249*f585d8a3SJacky Wang // TODO(b/241293838): Remove dependency on backend once this bug is fixed. 250*f585d8a3SJacky Wang CompilerTests.backend(subject).equals(XProcessingEnv.Backend.JAVAC) 251*f585d8a3SJacky Wang ? " @Provides @Per(MyComponent.class) boolean ScopedModule.bool()" 252*f585d8a3SJacky Wang : " @Provides @Per(MyComponent) boolean ScopedModule.bool()")) 253*f585d8a3SJacky Wang .onSource(componentFile) 254*f585d8a3SJacky Wang .onLineContaining("interface MyComponent"); 255*f585d8a3SJacky Wang }); 256*f585d8a3SJacky Wang 257*f585d8a3SJacky Wang // The @Inject binding for ScopedType should not appear here, but the @Singleton binding should. 258*f585d8a3SJacky Wang CompilerTests.daggerCompiler(componentFile, scopeFile, scopeWithAttribute, typeFile, moduleFile) 259*f585d8a3SJacky Wang .withProcessingOptions(ImmutableMap.of("dagger.fullBindingGraphValidation", "ERROR")) 260*f585d8a3SJacky Wang .compile( 261*f585d8a3SJacky Wang subject -> { 262*f585d8a3SJacky Wang subject.hasErrorCount(2); 263*f585d8a3SJacky Wang subject.hasErrorContaining( 264*f585d8a3SJacky Wang String.join( 265*f585d8a3SJacky Wang "\n", 266*f585d8a3SJacky Wang "ScopedModule contains bindings with different scopes:", 267*f585d8a3SJacky Wang " @Provides @PerTest String ScopedModule.string()", 268*f585d8a3SJacky Wang "", 269*f585d8a3SJacky Wang " @Provides @Singleton float ScopedModule.floatingPoint()", 270*f585d8a3SJacky Wang "", 271*f585d8a3SJacky Wang // TODO(b/241293838): Remove dependency on backend once this bug is fixed. 272*f585d8a3SJacky Wang CompilerTests.backend(subject).equals(XProcessingEnv.Backend.JAVAC) 273*f585d8a3SJacky Wang ? " @Provides @Per(MyComponent.class) boolean ScopedModule.bool()" 274*f585d8a3SJacky Wang : " @Provides @Per(MyComponent) boolean ScopedModule.bool()")) 275*f585d8a3SJacky Wang .onSource(moduleFile) 276*f585d8a3SJacky Wang .onLineContaining("class ScopedModule"); 277*f585d8a3SJacky Wang }); 278*f585d8a3SJacky Wang } 279*f585d8a3SJacky Wang 280*f585d8a3SJacky Wang @Test fullBindingGraphValidationDoesNotReportForOneScope()281*f585d8a3SJacky Wang public void fullBindingGraphValidationDoesNotReportForOneScope() { 282*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 283*f585d8a3SJacky Wang CompilerTests.javaSource( 284*f585d8a3SJacky Wang "test.TestModule", 285*f585d8a3SJacky Wang "package test;", 286*f585d8a3SJacky Wang "", 287*f585d8a3SJacky Wang "import dagger.Module;", 288*f585d8a3SJacky Wang "import dagger.Provides;", 289*f585d8a3SJacky Wang "import javax.inject.Singleton;", 290*f585d8a3SJacky Wang "", 291*f585d8a3SJacky Wang "@Module", 292*f585d8a3SJacky Wang "interface TestModule {", 293*f585d8a3SJacky Wang " @Provides @Singleton static Object object() { return \"object\"; }", 294*f585d8a3SJacky Wang " @Provides @Singleton static String string() { return \"string\"; }", 295*f585d8a3SJacky Wang " @Provides static int integer() { return 4; }", 296*f585d8a3SJacky Wang "}")) 297*f585d8a3SJacky Wang .withProcessingOptions( 298*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 299*f585d8a3SJacky Wang .put("dagger.fullBindingGraphValidation", "ERROR") 300*f585d8a3SJacky Wang .put("dagger.moduleHasDifferentScopesValidation", "ERROR") 301*f585d8a3SJacky Wang .buildOrThrow()) 302*f585d8a3SJacky Wang .compile( 303*f585d8a3SJacky Wang subject -> { 304*f585d8a3SJacky Wang subject.hasErrorCount(0); 305*f585d8a3SJacky Wang subject.hasWarningCount(0); 306*f585d8a3SJacky Wang }); 307*f585d8a3SJacky Wang } 308*f585d8a3SJacky Wang 309*f585d8a3SJacky Wang @Test fullBindingGraphValidationDoesNotReportInjectBindings()310*f585d8a3SJacky Wang public void fullBindingGraphValidationDoesNotReportInjectBindings() { 311*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 312*f585d8a3SJacky Wang CompilerTests.javaSource( 313*f585d8a3SJacky Wang "test.UsedInRootRedScoped", 314*f585d8a3SJacky Wang "package test;", 315*f585d8a3SJacky Wang "", 316*f585d8a3SJacky Wang "import javax.inject.Inject;", 317*f585d8a3SJacky Wang "", 318*f585d8a3SJacky Wang "@RedScope", 319*f585d8a3SJacky Wang "final class UsedInRootRedScoped {", 320*f585d8a3SJacky Wang " @Inject UsedInRootRedScoped() {}", 321*f585d8a3SJacky Wang "}"), 322*f585d8a3SJacky Wang CompilerTests.javaSource( 323*f585d8a3SJacky Wang "test.UsedInRootBlueScoped", 324*f585d8a3SJacky Wang "package test;", 325*f585d8a3SJacky Wang "", 326*f585d8a3SJacky Wang "import javax.inject.Inject;", 327*f585d8a3SJacky Wang "", 328*f585d8a3SJacky Wang "@BlueScope", 329*f585d8a3SJacky Wang "final class UsedInRootBlueScoped {", 330*f585d8a3SJacky Wang " @Inject UsedInRootBlueScoped() {}", 331*f585d8a3SJacky Wang "}"), 332*f585d8a3SJacky Wang CompilerTests.javaSource( 333*f585d8a3SJacky Wang "test.RedScope", 334*f585d8a3SJacky Wang "package test;", 335*f585d8a3SJacky Wang "", 336*f585d8a3SJacky Wang "import javax.inject.Scope;", 337*f585d8a3SJacky Wang "", 338*f585d8a3SJacky Wang "@Scope", 339*f585d8a3SJacky Wang "@interface RedScope {}"), 340*f585d8a3SJacky Wang CompilerTests.javaSource( 341*f585d8a3SJacky Wang "test.BlueScope", 342*f585d8a3SJacky Wang "package test;", 343*f585d8a3SJacky Wang "", 344*f585d8a3SJacky Wang "import javax.inject.Scope;", 345*f585d8a3SJacky Wang "", 346*f585d8a3SJacky Wang "@Scope", 347*f585d8a3SJacky Wang "@interface BlueScope {}"), 348*f585d8a3SJacky Wang CompilerTests.javaSource( 349*f585d8a3SJacky Wang "test.TestModule", 350*f585d8a3SJacky Wang "package test;", 351*f585d8a3SJacky Wang "", 352*f585d8a3SJacky Wang "import dagger.Module;", 353*f585d8a3SJacky Wang "import dagger.Provides;", 354*f585d8a3SJacky Wang "import javax.inject.Singleton;", 355*f585d8a3SJacky Wang "", 356*f585d8a3SJacky Wang "@Module(subcomponents = Child.class)", 357*f585d8a3SJacky Wang "interface TestModule {", 358*f585d8a3SJacky Wang " @Provides @Singleton", 359*f585d8a3SJacky Wang " static Object object(", 360*f585d8a3SJacky Wang " UsedInRootRedScoped usedInRootRedScoped,", 361*f585d8a3SJacky Wang " UsedInRootBlueScoped usedInRootBlueScoped) {", 362*f585d8a3SJacky Wang " return \"object\";", 363*f585d8a3SJacky Wang " }", 364*f585d8a3SJacky Wang "}"), 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 "interface Child {", 373*f585d8a3SJacky Wang " UsedInChildRedScoped usedInChildRedScoped();", 374*f585d8a3SJacky Wang " UsedInChildBlueScoped usedInChildBlueScoped();", 375*f585d8a3SJacky Wang "", 376*f585d8a3SJacky Wang " @Subcomponent.Builder", 377*f585d8a3SJacky Wang " interface Builder {", 378*f585d8a3SJacky Wang " Child child();", 379*f585d8a3SJacky Wang " }", 380*f585d8a3SJacky Wang "}"), 381*f585d8a3SJacky Wang CompilerTests.javaSource( 382*f585d8a3SJacky Wang "test.UsedInChildRedScoped", 383*f585d8a3SJacky Wang "package test;", 384*f585d8a3SJacky Wang "", 385*f585d8a3SJacky Wang "import javax.inject.Inject;", 386*f585d8a3SJacky Wang "", 387*f585d8a3SJacky Wang "@RedScope", 388*f585d8a3SJacky Wang "final class UsedInChildRedScoped {", 389*f585d8a3SJacky Wang " @Inject UsedInChildRedScoped() {}", 390*f585d8a3SJacky Wang "}"), 391*f585d8a3SJacky Wang CompilerTests.javaSource( 392*f585d8a3SJacky Wang "test.UsedInChildBlueScoped", 393*f585d8a3SJacky Wang "package test;", 394*f585d8a3SJacky Wang "", 395*f585d8a3SJacky Wang "import javax.inject.Inject;", 396*f585d8a3SJacky Wang "", 397*f585d8a3SJacky Wang "@BlueScope", 398*f585d8a3SJacky Wang "final class UsedInChildBlueScoped {", 399*f585d8a3SJacky Wang " @Inject UsedInChildBlueScoped() {}", 400*f585d8a3SJacky Wang "}")) 401*f585d8a3SJacky Wang .withProcessingOptions( 402*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 403*f585d8a3SJacky Wang .put("dagger.fullBindingGraphValidation", "ERROR") 404*f585d8a3SJacky Wang .put("dagger.moduleHasDifferentScopesValidation", "ERROR") 405*f585d8a3SJacky Wang .buildOrThrow()) 406*f585d8a3SJacky Wang .compile( 407*f585d8a3SJacky Wang subject -> { 408*f585d8a3SJacky Wang subject.hasErrorCount(0); 409*f585d8a3SJacky Wang subject.hasWarningCount(0); 410*f585d8a3SJacky Wang }); 411*f585d8a3SJacky Wang } 412*f585d8a3SJacky Wang 413*f585d8a3SJacky Wang @Test componentWithScopeCanDependOnMultipleScopedComponents()414*f585d8a3SJacky Wang public void componentWithScopeCanDependOnMultipleScopedComponents() { 415*f585d8a3SJacky Wang // If a scoped component will have dependencies, they can include multiple scoped component 416*f585d8a3SJacky Wang Source type = 417*f585d8a3SJacky Wang CompilerTests.javaSource( 418*f585d8a3SJacky Wang "test.SimpleType", 419*f585d8a3SJacky Wang "package test;", 420*f585d8a3SJacky Wang "", 421*f585d8a3SJacky Wang "import javax.inject.Inject;", 422*f585d8a3SJacky Wang "", 423*f585d8a3SJacky Wang "class SimpleType {", 424*f585d8a3SJacky Wang " @Inject SimpleType() {}", 425*f585d8a3SJacky Wang " static class A { @Inject A() {} }", 426*f585d8a3SJacky Wang " static class B { @Inject B() {} }", 427*f585d8a3SJacky Wang "}"); 428*f585d8a3SJacky Wang Source simpleScope = 429*f585d8a3SJacky Wang CompilerTests.javaSource( 430*f585d8a3SJacky Wang "test.SimpleScope", 431*f585d8a3SJacky Wang "package test;", 432*f585d8a3SJacky Wang "", 433*f585d8a3SJacky Wang "import javax.inject.Scope;", 434*f585d8a3SJacky Wang "", 435*f585d8a3SJacky Wang "@Scope @interface SimpleScope {}"); 436*f585d8a3SJacky Wang Source singletonScopedA = 437*f585d8a3SJacky Wang CompilerTests.javaSource( 438*f585d8a3SJacky Wang "test.SingletonComponentA", 439*f585d8a3SJacky Wang "package test;", 440*f585d8a3SJacky Wang "", 441*f585d8a3SJacky Wang "import dagger.Component;", 442*f585d8a3SJacky Wang "import javax.inject.Singleton;", 443*f585d8a3SJacky Wang "", 444*f585d8a3SJacky Wang "@Singleton", 445*f585d8a3SJacky Wang "@Component", 446*f585d8a3SJacky Wang "interface SingletonComponentA {", 447*f585d8a3SJacky Wang " SimpleType.A type();", 448*f585d8a3SJacky Wang "}"); 449*f585d8a3SJacky Wang Source singletonScopedB = 450*f585d8a3SJacky Wang CompilerTests.javaSource( 451*f585d8a3SJacky Wang "test.SingletonComponentB", 452*f585d8a3SJacky Wang "package test;", 453*f585d8a3SJacky Wang "", 454*f585d8a3SJacky Wang "import dagger.Component;", 455*f585d8a3SJacky Wang "import javax.inject.Singleton;", 456*f585d8a3SJacky Wang "", 457*f585d8a3SJacky Wang "@Singleton", 458*f585d8a3SJacky Wang "@Component", 459*f585d8a3SJacky Wang "interface SingletonComponentB {", 460*f585d8a3SJacky Wang " SimpleType.B type();", 461*f585d8a3SJacky Wang "}"); 462*f585d8a3SJacky Wang Source scopeless = 463*f585d8a3SJacky Wang CompilerTests.javaSource( 464*f585d8a3SJacky Wang "test.ScopelessComponent", 465*f585d8a3SJacky Wang "package test;", 466*f585d8a3SJacky Wang "", 467*f585d8a3SJacky Wang "import dagger.Component;", 468*f585d8a3SJacky Wang "", 469*f585d8a3SJacky Wang "@Component", 470*f585d8a3SJacky Wang "interface ScopelessComponent {", 471*f585d8a3SJacky Wang " SimpleType type();", 472*f585d8a3SJacky Wang "}"); 473*f585d8a3SJacky Wang Source simpleScoped = 474*f585d8a3SJacky Wang CompilerTests.javaSource( 475*f585d8a3SJacky Wang "test.SimpleScopedComponent", 476*f585d8a3SJacky Wang "package test;", 477*f585d8a3SJacky Wang "", 478*f585d8a3SJacky Wang "import dagger.Component;", 479*f585d8a3SJacky Wang "", 480*f585d8a3SJacky Wang "@SimpleScope", 481*f585d8a3SJacky Wang "@Component(dependencies = {SingletonComponentA.class, SingletonComponentB.class})", 482*f585d8a3SJacky Wang "interface SimpleScopedComponent {", 483*f585d8a3SJacky Wang " SimpleType.A type();", 484*f585d8a3SJacky Wang "}"); 485*f585d8a3SJacky Wang 486*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 487*f585d8a3SJacky Wang type, simpleScope, simpleScoped, singletonScopedA, singletonScopedB, scopeless) 488*f585d8a3SJacky Wang .compile( 489*f585d8a3SJacky Wang subject -> { 490*f585d8a3SJacky Wang subject.hasErrorCount(0); 491*f585d8a3SJacky Wang subject.hasWarningCount(0); 492*f585d8a3SJacky Wang }); 493*f585d8a3SJacky Wang } 494*f585d8a3SJacky Wang 495*f585d8a3SJacky Wang 496*f585d8a3SJacky Wang 497*f585d8a3SJacky Wang // Tests the following component hierarchy: 498*f585d8a3SJacky Wang // 499*f585d8a3SJacky Wang // @ScopeA 500*f585d8a3SJacky Wang // ComponentA 501*f585d8a3SJacky Wang // [SimpleType getSimpleType()] 502*f585d8a3SJacky Wang // / \ 503*f585d8a3SJacky Wang // / \ 504*f585d8a3SJacky Wang // @ScopeB @ScopeB 505*f585d8a3SJacky Wang // ComponentB1 ComponentB2 506*f585d8a3SJacky Wang // \ [SimpleType getSimpleType()] 507*f585d8a3SJacky Wang // \ / 508*f585d8a3SJacky Wang // \ / 509*f585d8a3SJacky Wang // @ScopeC 510*f585d8a3SJacky Wang // ComponentC 511*f585d8a3SJacky Wang // [SimpleType getSimpleType()] 512*f585d8a3SJacky Wang @Test componentWithScopeCanDependOnMultipleScopedComponentsEvenDoingADiamond()513*f585d8a3SJacky Wang public void componentWithScopeCanDependOnMultipleScopedComponentsEvenDoingADiamond() { 514*f585d8a3SJacky Wang Source type = 515*f585d8a3SJacky Wang CompilerTests.javaSource( 516*f585d8a3SJacky Wang "test.SimpleType", 517*f585d8a3SJacky Wang "package test;", 518*f585d8a3SJacky Wang "", 519*f585d8a3SJacky Wang "import javax.inject.Inject;", 520*f585d8a3SJacky Wang "", 521*f585d8a3SJacky Wang "class SimpleType {", 522*f585d8a3SJacky Wang " @Inject SimpleType() {}", 523*f585d8a3SJacky Wang "}"); 524*f585d8a3SJacky Wang Source simpleScope = 525*f585d8a3SJacky Wang CompilerTests.javaSource( 526*f585d8a3SJacky Wang "test.SimpleScope", 527*f585d8a3SJacky Wang "package test;", 528*f585d8a3SJacky Wang "", 529*f585d8a3SJacky Wang "import javax.inject.Scope;", 530*f585d8a3SJacky Wang "", 531*f585d8a3SJacky Wang "@Scope @interface SimpleScope {}"); 532*f585d8a3SJacky Wang Source scopeA = 533*f585d8a3SJacky Wang CompilerTests.javaSource( 534*f585d8a3SJacky Wang "test.ScopeA", 535*f585d8a3SJacky Wang "package test;", 536*f585d8a3SJacky Wang "", 537*f585d8a3SJacky Wang "import javax.inject.Scope;", 538*f585d8a3SJacky Wang "", 539*f585d8a3SJacky Wang "@Scope @interface ScopeA {}"); 540*f585d8a3SJacky Wang Source scopeB = 541*f585d8a3SJacky Wang CompilerTests.javaSource( 542*f585d8a3SJacky Wang "test.ScopeB", 543*f585d8a3SJacky Wang "package test;", 544*f585d8a3SJacky Wang "", 545*f585d8a3SJacky Wang "import javax.inject.Scope;", 546*f585d8a3SJacky Wang "", 547*f585d8a3SJacky Wang "@Scope @interface ScopeB {}"); 548*f585d8a3SJacky Wang Source componentA = 549*f585d8a3SJacky Wang CompilerTests.javaSource( 550*f585d8a3SJacky Wang "test.ComponentA", 551*f585d8a3SJacky Wang "package test;", 552*f585d8a3SJacky Wang "", 553*f585d8a3SJacky Wang "import dagger.Component;", 554*f585d8a3SJacky Wang "", 555*f585d8a3SJacky Wang "@ScopeA", 556*f585d8a3SJacky Wang "@Component", 557*f585d8a3SJacky Wang "interface ComponentA {", 558*f585d8a3SJacky Wang " SimpleType type();", 559*f585d8a3SJacky Wang "}"); 560*f585d8a3SJacky Wang Source componentB1 = 561*f585d8a3SJacky Wang CompilerTests.javaSource( 562*f585d8a3SJacky Wang "test.ComponentB1", 563*f585d8a3SJacky Wang "package test;", 564*f585d8a3SJacky Wang "", 565*f585d8a3SJacky Wang "import dagger.Component;", 566*f585d8a3SJacky Wang "", 567*f585d8a3SJacky Wang "@ScopeB", 568*f585d8a3SJacky Wang "@Component(dependencies = ComponentA.class)", 569*f585d8a3SJacky Wang "interface ComponentB1 {", 570*f585d8a3SJacky Wang " SimpleType type();", 571*f585d8a3SJacky Wang "}"); 572*f585d8a3SJacky Wang Source componentB2 = 573*f585d8a3SJacky Wang CompilerTests.javaSource( 574*f585d8a3SJacky Wang "test.ComponentB2", 575*f585d8a3SJacky Wang "package test;", 576*f585d8a3SJacky Wang "", 577*f585d8a3SJacky Wang "import dagger.Component;", 578*f585d8a3SJacky Wang "", 579*f585d8a3SJacky Wang "@ScopeB", 580*f585d8a3SJacky Wang "@Component(dependencies = ComponentA.class)", 581*f585d8a3SJacky Wang "interface ComponentB2 {", 582*f585d8a3SJacky Wang "}"); 583*f585d8a3SJacky Wang Source componentC = 584*f585d8a3SJacky Wang CompilerTests.javaSource( 585*f585d8a3SJacky Wang "test.ComponentC", 586*f585d8a3SJacky Wang "package test;", 587*f585d8a3SJacky Wang "", 588*f585d8a3SJacky Wang "import dagger.Component;", 589*f585d8a3SJacky Wang "", 590*f585d8a3SJacky Wang "@SimpleScope", 591*f585d8a3SJacky Wang "@Component(dependencies = {ComponentB1.class, ComponentB2.class})", 592*f585d8a3SJacky Wang "interface ComponentC {", 593*f585d8a3SJacky Wang " SimpleType type();", 594*f585d8a3SJacky Wang "}"); 595*f585d8a3SJacky Wang 596*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 597*f585d8a3SJacky Wang type, simpleScope, scopeA, scopeB, componentA, componentB1, componentB2, componentC) 598*f585d8a3SJacky Wang .compile( 599*f585d8a3SJacky Wang subject -> { 600*f585d8a3SJacky Wang subject.hasErrorCount(0); 601*f585d8a3SJacky Wang subject.hasWarningCount(0); 602*f585d8a3SJacky Wang }); 603*f585d8a3SJacky Wang } 604*f585d8a3SJacky Wang 605*f585d8a3SJacky Wang @Test componentWithoutScopeCannotDependOnScopedComponent()606*f585d8a3SJacky Wang public void componentWithoutScopeCannotDependOnScopedComponent() { 607*f585d8a3SJacky Wang Source type = 608*f585d8a3SJacky Wang CompilerTests.javaSource( 609*f585d8a3SJacky Wang "test.SimpleType", 610*f585d8a3SJacky Wang "package test;", 611*f585d8a3SJacky Wang "", 612*f585d8a3SJacky Wang "import javax.inject.Inject;", 613*f585d8a3SJacky Wang "", 614*f585d8a3SJacky Wang "class SimpleType {", 615*f585d8a3SJacky Wang " @Inject SimpleType() {}", 616*f585d8a3SJacky Wang "}"); 617*f585d8a3SJacky Wang Source scopedComponent = 618*f585d8a3SJacky Wang CompilerTests.javaSource( 619*f585d8a3SJacky Wang "test.ScopedComponent", 620*f585d8a3SJacky Wang "package test;", 621*f585d8a3SJacky Wang "", 622*f585d8a3SJacky Wang "import dagger.Component;", 623*f585d8a3SJacky Wang "import javax.inject.Singleton;", 624*f585d8a3SJacky Wang "", 625*f585d8a3SJacky Wang "@Singleton", 626*f585d8a3SJacky Wang "@Component", 627*f585d8a3SJacky Wang "interface ScopedComponent {", 628*f585d8a3SJacky Wang " SimpleType type();", 629*f585d8a3SJacky Wang "}"); 630*f585d8a3SJacky Wang Source unscopedComponent = 631*f585d8a3SJacky Wang CompilerTests.javaSource( 632*f585d8a3SJacky Wang "test.UnscopedComponent", 633*f585d8a3SJacky Wang "package test;", 634*f585d8a3SJacky Wang "", 635*f585d8a3SJacky Wang "import dagger.Component;", 636*f585d8a3SJacky Wang "import javax.inject.Singleton;", 637*f585d8a3SJacky Wang "", 638*f585d8a3SJacky Wang "@Component(dependencies = ScopedComponent.class)", 639*f585d8a3SJacky Wang "interface UnscopedComponent {", 640*f585d8a3SJacky Wang " SimpleType type();", 641*f585d8a3SJacky Wang "}"); 642*f585d8a3SJacky Wang 643*f585d8a3SJacky Wang CompilerTests.daggerCompiler(type, scopedComponent, unscopedComponent) 644*f585d8a3SJacky Wang .compile( 645*f585d8a3SJacky Wang subject -> { 646*f585d8a3SJacky Wang subject.hasErrorCount(1); 647*f585d8a3SJacky Wang subject.hasErrorContaining( 648*f585d8a3SJacky Wang String.join( 649*f585d8a3SJacky Wang "\n", 650*f585d8a3SJacky Wang "test.UnscopedComponent (unscoped) cannot depend on scoped components:", 651*f585d8a3SJacky Wang " @Singleton test.ScopedComponent")); 652*f585d8a3SJacky Wang }); 653*f585d8a3SJacky Wang } 654*f585d8a3SJacky Wang 655*f585d8a3SJacky Wang @Test componentWithSingletonScopeMayNotDependOnOtherScope()656*f585d8a3SJacky Wang public void componentWithSingletonScopeMayNotDependOnOtherScope() { 657*f585d8a3SJacky Wang // Singleton must be the widest lifetime of present scopes. 658*f585d8a3SJacky Wang Source type = 659*f585d8a3SJacky Wang CompilerTests.javaSource( 660*f585d8a3SJacky Wang "test.SimpleType", 661*f585d8a3SJacky Wang "package test;", 662*f585d8a3SJacky Wang "", 663*f585d8a3SJacky Wang "import javax.inject.Inject;", 664*f585d8a3SJacky Wang "", 665*f585d8a3SJacky Wang "class SimpleType {", 666*f585d8a3SJacky Wang " @Inject SimpleType() {}", 667*f585d8a3SJacky Wang "}"); 668*f585d8a3SJacky Wang Source simpleScope = 669*f585d8a3SJacky Wang CompilerTests.javaSource( 670*f585d8a3SJacky Wang "test.SimpleScope", 671*f585d8a3SJacky Wang "package test;", 672*f585d8a3SJacky Wang "", 673*f585d8a3SJacky Wang "import javax.inject.Scope;", 674*f585d8a3SJacky Wang "", 675*f585d8a3SJacky Wang "@Scope @interface SimpleScope {}"); 676*f585d8a3SJacky Wang Source simpleScoped = 677*f585d8a3SJacky Wang CompilerTests.javaSource( 678*f585d8a3SJacky Wang "test.SimpleScopedComponent", 679*f585d8a3SJacky Wang "package test;", 680*f585d8a3SJacky Wang "", 681*f585d8a3SJacky Wang "import dagger.Component;", 682*f585d8a3SJacky Wang "", 683*f585d8a3SJacky Wang "@SimpleScope", 684*f585d8a3SJacky Wang "@Component", 685*f585d8a3SJacky Wang "interface SimpleScopedComponent {", 686*f585d8a3SJacky Wang " SimpleType type();", 687*f585d8a3SJacky Wang "}"); 688*f585d8a3SJacky Wang Source singletonScoped = 689*f585d8a3SJacky Wang CompilerTests.javaSource( 690*f585d8a3SJacky Wang "test.SingletonComponent", 691*f585d8a3SJacky Wang "package test;", 692*f585d8a3SJacky Wang "", 693*f585d8a3SJacky Wang "import dagger.Component;", 694*f585d8a3SJacky Wang "import javax.inject.Singleton;", 695*f585d8a3SJacky Wang "", 696*f585d8a3SJacky Wang "@Singleton", 697*f585d8a3SJacky Wang "@Component(dependencies = SimpleScopedComponent.class)", 698*f585d8a3SJacky Wang "interface SingletonComponent {", 699*f585d8a3SJacky Wang " SimpleType type();", 700*f585d8a3SJacky Wang "}"); 701*f585d8a3SJacky Wang 702*f585d8a3SJacky Wang CompilerTests.daggerCompiler(type, simpleScope, simpleScoped, singletonScoped) 703*f585d8a3SJacky Wang .compile( 704*f585d8a3SJacky Wang subject -> { 705*f585d8a3SJacky Wang subject.hasErrorCount(1); 706*f585d8a3SJacky Wang subject.hasErrorContaining( 707*f585d8a3SJacky Wang String.join( 708*f585d8a3SJacky Wang "\n", 709*f585d8a3SJacky Wang "This @Singleton component cannot depend on scoped components:", 710*f585d8a3SJacky Wang " @test.SimpleScope test.SimpleScopedComponent")); 711*f585d8a3SJacky Wang }); 712*f585d8a3SJacky Wang } 713*f585d8a3SJacky Wang 714*f585d8a3SJacky Wang @Test componentScopeWithMultipleScopedDependenciesMustNotCycle()715*f585d8a3SJacky Wang public void componentScopeWithMultipleScopedDependenciesMustNotCycle() { 716*f585d8a3SJacky Wang Source type = 717*f585d8a3SJacky Wang CompilerTests.javaSource( 718*f585d8a3SJacky Wang "test.SimpleType", 719*f585d8a3SJacky Wang "package test;", 720*f585d8a3SJacky Wang "", 721*f585d8a3SJacky Wang "import javax.inject.Inject;", 722*f585d8a3SJacky Wang "", 723*f585d8a3SJacky Wang "class SimpleType {", 724*f585d8a3SJacky Wang " @Inject SimpleType() {}", 725*f585d8a3SJacky Wang "}"); 726*f585d8a3SJacky Wang Source scopeA = 727*f585d8a3SJacky Wang CompilerTests.javaSource( 728*f585d8a3SJacky Wang "test.ScopeA", 729*f585d8a3SJacky Wang "package test;", 730*f585d8a3SJacky Wang "", 731*f585d8a3SJacky Wang "import javax.inject.Scope;", 732*f585d8a3SJacky Wang "", 733*f585d8a3SJacky Wang "@Scope @interface ScopeA {}"); 734*f585d8a3SJacky Wang Source scopeB = 735*f585d8a3SJacky Wang CompilerTests.javaSource( 736*f585d8a3SJacky Wang "test.ScopeB", 737*f585d8a3SJacky Wang "package test;", 738*f585d8a3SJacky Wang "", 739*f585d8a3SJacky Wang "import javax.inject.Scope;", 740*f585d8a3SJacky Wang "", 741*f585d8a3SJacky Wang "@Scope @interface ScopeB {}"); 742*f585d8a3SJacky Wang Source longLifetime = 743*f585d8a3SJacky Wang CompilerTests.javaSource( 744*f585d8a3SJacky Wang "test.ComponentLong", 745*f585d8a3SJacky Wang "package test;", 746*f585d8a3SJacky Wang "", 747*f585d8a3SJacky Wang "import dagger.Component;", 748*f585d8a3SJacky Wang "", 749*f585d8a3SJacky Wang "@ScopeA", 750*f585d8a3SJacky Wang "@Component", 751*f585d8a3SJacky Wang "interface ComponentLong {", 752*f585d8a3SJacky Wang " SimpleType type();", 753*f585d8a3SJacky Wang "}"); 754*f585d8a3SJacky Wang Source mediumLifetime1 = 755*f585d8a3SJacky Wang CompilerTests.javaSource( 756*f585d8a3SJacky Wang "test.ComponentMedium1", 757*f585d8a3SJacky Wang "package test;", 758*f585d8a3SJacky Wang "", 759*f585d8a3SJacky Wang "import dagger.Component;", 760*f585d8a3SJacky Wang "", 761*f585d8a3SJacky Wang "@ScopeB", 762*f585d8a3SJacky Wang "@Component(dependencies = ComponentLong.class)", 763*f585d8a3SJacky Wang "interface ComponentMedium1 {", 764*f585d8a3SJacky Wang " SimpleType type();", 765*f585d8a3SJacky Wang "}"); 766*f585d8a3SJacky Wang Source mediumLifetime2 = 767*f585d8a3SJacky Wang CompilerTests.javaSource( 768*f585d8a3SJacky Wang "test.ComponentMedium2", 769*f585d8a3SJacky Wang "package test;", 770*f585d8a3SJacky Wang "", 771*f585d8a3SJacky Wang "import dagger.Component;", 772*f585d8a3SJacky Wang "", 773*f585d8a3SJacky Wang "@ScopeB", 774*f585d8a3SJacky Wang "@Component", 775*f585d8a3SJacky Wang "interface ComponentMedium2 {", 776*f585d8a3SJacky Wang "}"); 777*f585d8a3SJacky Wang Source shortLifetime = 778*f585d8a3SJacky Wang CompilerTests.javaSource( 779*f585d8a3SJacky Wang "test.ComponentShort", 780*f585d8a3SJacky Wang "package test;", 781*f585d8a3SJacky Wang "", 782*f585d8a3SJacky Wang "import dagger.Component;", 783*f585d8a3SJacky Wang "", 784*f585d8a3SJacky Wang "@ScopeA", 785*f585d8a3SJacky Wang "@Component(dependencies = {ComponentMedium1.class, ComponentMedium2.class})", 786*f585d8a3SJacky Wang "interface ComponentShort {", 787*f585d8a3SJacky Wang " SimpleType type();", 788*f585d8a3SJacky Wang "}"); 789*f585d8a3SJacky Wang 790*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 791*f585d8a3SJacky Wang type, scopeA, scopeB, longLifetime, mediumLifetime1, mediumLifetime2, shortLifetime) 792*f585d8a3SJacky Wang .compile( 793*f585d8a3SJacky Wang subject -> { 794*f585d8a3SJacky Wang subject.hasErrorCount(1); 795*f585d8a3SJacky Wang subject.hasErrorContaining( 796*f585d8a3SJacky Wang String.join( 797*f585d8a3SJacky Wang "\n", 798*f585d8a3SJacky Wang "test.ComponentShort depends on scoped components in a non-hierarchical " 799*f585d8a3SJacky Wang + "scope ordering:", 800*f585d8a3SJacky Wang " @test.ScopeA test.ComponentLong", 801*f585d8a3SJacky Wang " @test.ScopeB test.ComponentMedium1", 802*f585d8a3SJacky Wang " @test.ScopeA test.ComponentShort")); 803*f585d8a3SJacky Wang }); 804*f585d8a3SJacky Wang } 805*f585d8a3SJacky Wang 806*f585d8a3SJacky Wang @Test componentScopeAncestryMustNotCycle()807*f585d8a3SJacky Wang public void componentScopeAncestryMustNotCycle() { 808*f585d8a3SJacky Wang // The dependency relationship of components is necessarily from shorter lifetimes to 809*f585d8a3SJacky Wang // longer lifetimes. The scoping annotations must reflect this, and so one cannot declare 810*f585d8a3SJacky Wang // scopes on components such that they cycle. 811*f585d8a3SJacky Wang Source type = 812*f585d8a3SJacky Wang CompilerTests.javaSource( 813*f585d8a3SJacky Wang "test.SimpleType", 814*f585d8a3SJacky Wang "package test;", 815*f585d8a3SJacky Wang "", 816*f585d8a3SJacky Wang "import javax.inject.Inject;", 817*f585d8a3SJacky Wang "", 818*f585d8a3SJacky Wang "class SimpleType {", 819*f585d8a3SJacky Wang " @Inject SimpleType() {}", 820*f585d8a3SJacky Wang "}"); 821*f585d8a3SJacky Wang Source scopeA = 822*f585d8a3SJacky Wang CompilerTests.javaSource( 823*f585d8a3SJacky Wang "test.ScopeA", 824*f585d8a3SJacky Wang "package test;", 825*f585d8a3SJacky Wang "", 826*f585d8a3SJacky Wang "import javax.inject.Scope;", 827*f585d8a3SJacky Wang "", 828*f585d8a3SJacky Wang "@Scope @interface ScopeA {}"); 829*f585d8a3SJacky Wang Source scopeB = 830*f585d8a3SJacky Wang CompilerTests.javaSource( 831*f585d8a3SJacky Wang "test.ScopeB", 832*f585d8a3SJacky Wang "package test;", 833*f585d8a3SJacky Wang "", 834*f585d8a3SJacky Wang "import javax.inject.Scope;", 835*f585d8a3SJacky Wang "", 836*f585d8a3SJacky Wang "@Scope @interface ScopeB {}"); 837*f585d8a3SJacky Wang Source longLifetime = 838*f585d8a3SJacky Wang CompilerTests.javaSource( 839*f585d8a3SJacky Wang "test.ComponentLong", 840*f585d8a3SJacky Wang "package test;", 841*f585d8a3SJacky Wang "", 842*f585d8a3SJacky Wang "import dagger.Component;", 843*f585d8a3SJacky Wang "", 844*f585d8a3SJacky Wang "@ScopeA", 845*f585d8a3SJacky Wang "@Component", 846*f585d8a3SJacky Wang "interface ComponentLong {", 847*f585d8a3SJacky Wang " SimpleType type();", 848*f585d8a3SJacky Wang "}"); 849*f585d8a3SJacky Wang Source mediumLifetime = 850*f585d8a3SJacky Wang CompilerTests.javaSource( 851*f585d8a3SJacky Wang "test.ComponentMedium", 852*f585d8a3SJacky Wang "package test;", 853*f585d8a3SJacky Wang "", 854*f585d8a3SJacky Wang "import dagger.Component;", 855*f585d8a3SJacky Wang "", 856*f585d8a3SJacky Wang "@ScopeB", 857*f585d8a3SJacky Wang "@Component(dependencies = ComponentLong.class)", 858*f585d8a3SJacky Wang "interface ComponentMedium {", 859*f585d8a3SJacky Wang " SimpleType type();", 860*f585d8a3SJacky Wang "}"); 861*f585d8a3SJacky Wang Source shortLifetime = 862*f585d8a3SJacky Wang CompilerTests.javaSource( 863*f585d8a3SJacky Wang "test.ComponentShort", 864*f585d8a3SJacky Wang "package test;", 865*f585d8a3SJacky Wang "", 866*f585d8a3SJacky Wang "import dagger.Component;", 867*f585d8a3SJacky Wang "", 868*f585d8a3SJacky Wang "@ScopeA", 869*f585d8a3SJacky Wang "@Component(dependencies = ComponentMedium.class)", 870*f585d8a3SJacky Wang "interface ComponentShort {", 871*f585d8a3SJacky Wang " SimpleType type();", 872*f585d8a3SJacky Wang "}"); 873*f585d8a3SJacky Wang 874*f585d8a3SJacky Wang CompilerTests.daggerCompiler(type, scopeA, scopeB, longLifetime, mediumLifetime, shortLifetime) 875*f585d8a3SJacky Wang .compile( 876*f585d8a3SJacky Wang subject -> { 877*f585d8a3SJacky Wang subject.hasErrorCount(1); 878*f585d8a3SJacky Wang subject.hasErrorContaining( 879*f585d8a3SJacky Wang String.join( 880*f585d8a3SJacky Wang "\n", 881*f585d8a3SJacky Wang "test.ComponentShort depends on scoped components in a non-hierarchical " 882*f585d8a3SJacky Wang + "scope ordering:", 883*f585d8a3SJacky Wang " @test.ScopeA test.ComponentLong", 884*f585d8a3SJacky Wang " @test.ScopeB test.ComponentMedium", 885*f585d8a3SJacky Wang " @test.ScopeA test.ComponentShort")); 886*f585d8a3SJacky Wang }); 887*f585d8a3SJacky Wang 888*f585d8a3SJacky Wang // Test that compilation succeeds when transitive validation is disabled because the scope cycle 889*f585d8a3SJacky Wang // cannot be detected. 890*f585d8a3SJacky Wang CompilerTests.daggerCompiler(type, scopeA, scopeB, longLifetime, mediumLifetime, shortLifetime) 891*f585d8a3SJacky Wang .withProcessingOptions( 892*f585d8a3SJacky Wang ImmutableMap.of("dagger.validateTransitiveComponentDependencies", "DISABLED")) 893*f585d8a3SJacky Wang .compile(subject -> subject.hasErrorCount(0)); 894*f585d8a3SJacky Wang } 895*f585d8a3SJacky Wang 896*f585d8a3SJacky Wang @Test reusableNotAllowedOnComponent()897*f585d8a3SJacky Wang public void reusableNotAllowedOnComponent() { 898*f585d8a3SJacky Wang Source someComponent = 899*f585d8a3SJacky Wang CompilerTests.javaSource( 900*f585d8a3SJacky Wang "test.SomeComponent", 901*f585d8a3SJacky Wang "package test;", 902*f585d8a3SJacky Wang "", 903*f585d8a3SJacky Wang "import dagger.Component;", 904*f585d8a3SJacky Wang "import dagger.Reusable;", 905*f585d8a3SJacky Wang "", 906*f585d8a3SJacky Wang "@Reusable", 907*f585d8a3SJacky Wang "@Component", 908*f585d8a3SJacky Wang "interface SomeComponent {}"); 909*f585d8a3SJacky Wang CompilerTests.daggerCompiler(someComponent) 910*f585d8a3SJacky Wang .compile( 911*f585d8a3SJacky Wang subject -> { 912*f585d8a3SJacky Wang subject.hasErrorCount(1); 913*f585d8a3SJacky Wang subject.hasErrorContaining( 914*f585d8a3SJacky Wang "@Reusable cannot be applied to components or subcomponents") 915*f585d8a3SJacky Wang .onSource(someComponent) 916*f585d8a3SJacky Wang .onLine(6); 917*f585d8a3SJacky Wang }); 918*f585d8a3SJacky Wang } 919*f585d8a3SJacky Wang 920*f585d8a3SJacky Wang @Test reusableNotAllowedOnSubcomponent()921*f585d8a3SJacky Wang public void reusableNotAllowedOnSubcomponent() { 922*f585d8a3SJacky Wang Source someSubcomponent = 923*f585d8a3SJacky Wang CompilerTests.javaSource( 924*f585d8a3SJacky Wang "test.SomeComponent", 925*f585d8a3SJacky Wang "package test;", 926*f585d8a3SJacky Wang "", 927*f585d8a3SJacky Wang "import dagger.Reusable;", 928*f585d8a3SJacky Wang "import dagger.Subcomponent;", 929*f585d8a3SJacky Wang "", 930*f585d8a3SJacky Wang "@Reusable", 931*f585d8a3SJacky Wang "@Subcomponent", 932*f585d8a3SJacky Wang "interface SomeSubcomponent {}"); 933*f585d8a3SJacky Wang CompilerTests.daggerCompiler(someSubcomponent) 934*f585d8a3SJacky Wang .compile( 935*f585d8a3SJacky Wang subject -> { 936*f585d8a3SJacky Wang subject.hasErrorCount(1); 937*f585d8a3SJacky Wang subject.hasErrorContaining( 938*f585d8a3SJacky Wang "@Reusable cannot be applied to components or subcomponents") 939*f585d8a3SJacky Wang .onSource(someSubcomponent) 940*f585d8a3SJacky Wang .onLine(6); 941*f585d8a3SJacky Wang }); 942*f585d8a3SJacky Wang } 943*f585d8a3SJacky Wang } 944