1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2020 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 /** 29*f585d8a3SJacky Wang * Tests to make sure that delegate bindings where the impl depends on a binding in a subcomponent 30*f585d8a3SJacky Wang * properly fail. These are regression tests for b/147020838. 31*f585d8a3SJacky Wang */ 32*f585d8a3SJacky Wang @RunWith(Parameterized.class) 33*f585d8a3SJacky Wang public class BindsDependsOnSubcomponentValidationTest { 34*f585d8a3SJacky Wang @Parameters(name = "{0}") parameters()35*f585d8a3SJacky Wang public static ImmutableList<Object[]> parameters() { 36*f585d8a3SJacky Wang return CompilerMode.TEST_PARAMETERS; 37*f585d8a3SJacky Wang } 38*f585d8a3SJacky Wang 39*f585d8a3SJacky Wang private final CompilerMode compilerMode; 40*f585d8a3SJacky Wang BindsDependsOnSubcomponentValidationTest(CompilerMode compilerMode)41*f585d8a3SJacky Wang public BindsDependsOnSubcomponentValidationTest(CompilerMode compilerMode) { 42*f585d8a3SJacky Wang this.compilerMode = compilerMode; 43*f585d8a3SJacky Wang } 44*f585d8a3SJacky Wang 45*f585d8a3SJacky Wang @Test testBinds()46*f585d8a3SJacky Wang public void testBinds() { 47*f585d8a3SJacky Wang Source parentComponent = 48*f585d8a3SJacky Wang CompilerTests.javaSource( 49*f585d8a3SJacky Wang "test.ParentComponent", 50*f585d8a3SJacky Wang "package test;", 51*f585d8a3SJacky Wang "", 52*f585d8a3SJacky Wang "import dagger.Component;", 53*f585d8a3SJacky Wang "", 54*f585d8a3SJacky Wang "@Component(modules = ParentModule.class)", 55*f585d8a3SJacky Wang "interface ParentComponent {", 56*f585d8a3SJacky Wang " ChildComponent getChild();", 57*f585d8a3SJacky Wang "}"); 58*f585d8a3SJacky Wang Source parentModule = 59*f585d8a3SJacky Wang CompilerTests.javaSource( 60*f585d8a3SJacky Wang "test.ParentModule", 61*f585d8a3SJacky Wang "package test;", 62*f585d8a3SJacky Wang "", 63*f585d8a3SJacky Wang "import dagger.Binds;", 64*f585d8a3SJacky Wang "import dagger.Module;", 65*f585d8a3SJacky Wang "", 66*f585d8a3SJacky Wang "@Module", 67*f585d8a3SJacky Wang "interface ParentModule {", 68*f585d8a3SJacky Wang " @Binds Foo bindFoo(FooImpl impl);", 69*f585d8a3SJacky Wang "}"); 70*f585d8a3SJacky Wang Source childComponent = 71*f585d8a3SJacky Wang CompilerTests.javaSource( 72*f585d8a3SJacky Wang "test.ChildComponent", 73*f585d8a3SJacky Wang "package test;", 74*f585d8a3SJacky Wang "", 75*f585d8a3SJacky Wang "import dagger.Subcomponent;", 76*f585d8a3SJacky Wang "", 77*f585d8a3SJacky Wang "@Subcomponent(modules = ChildModule.class)", 78*f585d8a3SJacky Wang "interface ChildComponent {", 79*f585d8a3SJacky Wang " Foo getFoo();", 80*f585d8a3SJacky Wang "}"); 81*f585d8a3SJacky Wang Source childModule = 82*f585d8a3SJacky Wang CompilerTests.javaSource( 83*f585d8a3SJacky Wang "test.ChildModule", 84*f585d8a3SJacky Wang "package test;", 85*f585d8a3SJacky Wang "", 86*f585d8a3SJacky Wang "import dagger.Module;", 87*f585d8a3SJacky Wang "import dagger.Provides;", 88*f585d8a3SJacky Wang "", 89*f585d8a3SJacky Wang "@Module", 90*f585d8a3SJacky Wang "interface ChildModule {", 91*f585d8a3SJacky Wang " @Provides static Long providLong() {", 92*f585d8a3SJacky Wang " return 0L;", 93*f585d8a3SJacky Wang " }", 94*f585d8a3SJacky Wang "}"); 95*f585d8a3SJacky Wang Source iface = 96*f585d8a3SJacky Wang CompilerTests.javaSource( 97*f585d8a3SJacky Wang "test.Foo", 98*f585d8a3SJacky Wang "package test;", 99*f585d8a3SJacky Wang "", 100*f585d8a3SJacky Wang "interface Foo {}"); 101*f585d8a3SJacky Wang Source impl = 102*f585d8a3SJacky Wang CompilerTests.javaSource( 103*f585d8a3SJacky Wang "test.FooImpl", 104*f585d8a3SJacky Wang "package test;", 105*f585d8a3SJacky Wang "", 106*f585d8a3SJacky Wang "import javax.inject.Inject;", 107*f585d8a3SJacky Wang "", 108*f585d8a3SJacky Wang "class FooImpl implements Foo {", 109*f585d8a3SJacky Wang " @Inject FooImpl(Long l) {}", 110*f585d8a3SJacky Wang "}"); 111*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 112*f585d8a3SJacky Wang parentComponent, parentModule, childComponent, childModule, iface, impl) 113*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 114*f585d8a3SJacky Wang .compile( 115*f585d8a3SJacky Wang subject -> { 116*f585d8a3SJacky Wang subject.hasErrorCount(1); 117*f585d8a3SJacky Wang subject.hasErrorContaining("Long cannot be provided without an @Inject constructor") 118*f585d8a3SJacky Wang .onSource(parentComponent) 119*f585d8a3SJacky Wang .onLineContaining("interface ParentComponent"); 120*f585d8a3SJacky Wang }); 121*f585d8a3SJacky Wang } 122*f585d8a3SJacky Wang 123*f585d8a3SJacky Wang @Test testSetBindings()124*f585d8a3SJacky Wang public void testSetBindings() { 125*f585d8a3SJacky Wang Source parentComponent = 126*f585d8a3SJacky Wang CompilerTests.javaSource( 127*f585d8a3SJacky Wang "test.ParentComponent", 128*f585d8a3SJacky Wang "package test;", 129*f585d8a3SJacky Wang "", 130*f585d8a3SJacky Wang "import dagger.Component;", 131*f585d8a3SJacky Wang "", 132*f585d8a3SJacky Wang "@Component(modules = ParentModule.class)", 133*f585d8a3SJacky Wang "interface ParentComponent {", 134*f585d8a3SJacky Wang " ChildComponent getChild();", 135*f585d8a3SJacky Wang "}"); 136*f585d8a3SJacky Wang Source parentModule = 137*f585d8a3SJacky Wang CompilerTests.javaSource( 138*f585d8a3SJacky Wang "test.ParentModule", 139*f585d8a3SJacky Wang "package test;", 140*f585d8a3SJacky Wang "", 141*f585d8a3SJacky Wang "import dagger.Binds;", 142*f585d8a3SJacky Wang "import dagger.Module;", 143*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 144*f585d8a3SJacky Wang "", 145*f585d8a3SJacky Wang "@Module", 146*f585d8a3SJacky Wang "interface ParentModule {", 147*f585d8a3SJacky Wang " @Binds @IntoSet Foo bindFoo(FooImpl impl);", 148*f585d8a3SJacky Wang "}"); 149*f585d8a3SJacky Wang Source childComponent = 150*f585d8a3SJacky Wang CompilerTests.javaSource( 151*f585d8a3SJacky Wang "test.ChildComponent", 152*f585d8a3SJacky Wang "package test;", 153*f585d8a3SJacky Wang "", 154*f585d8a3SJacky Wang "import dagger.Subcomponent;", 155*f585d8a3SJacky Wang "import java.util.Set;", 156*f585d8a3SJacky Wang "", 157*f585d8a3SJacky Wang "@Subcomponent(modules = ChildModule.class)", 158*f585d8a3SJacky Wang "interface ChildComponent {", 159*f585d8a3SJacky Wang " Set<Foo> getFooSet();", 160*f585d8a3SJacky Wang "}"); 161*f585d8a3SJacky Wang Source childModule = 162*f585d8a3SJacky Wang CompilerTests.javaSource( 163*f585d8a3SJacky Wang "test.ChildModule", 164*f585d8a3SJacky Wang "package test;", 165*f585d8a3SJacky Wang "", 166*f585d8a3SJacky Wang "import dagger.Module;", 167*f585d8a3SJacky Wang "import dagger.Provides;", 168*f585d8a3SJacky Wang "", 169*f585d8a3SJacky Wang "@Module", 170*f585d8a3SJacky Wang "interface ChildModule {", 171*f585d8a3SJacky Wang " @Provides static Long providLong() {", 172*f585d8a3SJacky Wang " return 0L;", 173*f585d8a3SJacky Wang " }", 174*f585d8a3SJacky Wang "}"); 175*f585d8a3SJacky Wang Source iface = 176*f585d8a3SJacky Wang CompilerTests.javaSource( 177*f585d8a3SJacky Wang "test.Foo", 178*f585d8a3SJacky Wang "package test;", 179*f585d8a3SJacky Wang "", 180*f585d8a3SJacky Wang "interface Foo {}"); 181*f585d8a3SJacky Wang Source impl = 182*f585d8a3SJacky Wang CompilerTests.javaSource( 183*f585d8a3SJacky Wang "test.FooImpl", 184*f585d8a3SJacky Wang "package test;", 185*f585d8a3SJacky Wang "", 186*f585d8a3SJacky Wang "import javax.inject.Inject;", 187*f585d8a3SJacky Wang "", 188*f585d8a3SJacky Wang "class FooImpl implements Foo {", 189*f585d8a3SJacky Wang " @Inject FooImpl(Long l) {}", 190*f585d8a3SJacky Wang "}"); 191*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 192*f585d8a3SJacky Wang parentComponent, parentModule, childComponent, childModule, iface, impl) 193*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 194*f585d8a3SJacky Wang .compile( 195*f585d8a3SJacky Wang subject -> { 196*f585d8a3SJacky Wang subject.hasErrorCount(1); 197*f585d8a3SJacky Wang subject.hasErrorContaining("Long cannot be provided without an @Inject constructor") 198*f585d8a3SJacky Wang .onSource(parentComponent) 199*f585d8a3SJacky Wang .onLineContaining("interface ParentComponent"); 200*f585d8a3SJacky Wang }); 201*f585d8a3SJacky Wang } 202*f585d8a3SJacky Wang 203*f585d8a3SJacky Wang @Test testSetValueBindings()204*f585d8a3SJacky Wang public void testSetValueBindings() { 205*f585d8a3SJacky Wang Source parentComponent = 206*f585d8a3SJacky Wang CompilerTests.javaSource( 207*f585d8a3SJacky Wang "test.ParentComponent", 208*f585d8a3SJacky Wang "package test;", 209*f585d8a3SJacky Wang "", 210*f585d8a3SJacky Wang "import dagger.Component;", 211*f585d8a3SJacky Wang "", 212*f585d8a3SJacky Wang "@Component(modules = ParentModule.class)", 213*f585d8a3SJacky Wang "interface ParentComponent {", 214*f585d8a3SJacky Wang " ChildComponent getChild();", 215*f585d8a3SJacky Wang "}"); 216*f585d8a3SJacky Wang Source parentModule = 217*f585d8a3SJacky Wang CompilerTests.javaSource( 218*f585d8a3SJacky Wang "test.ParentModule", 219*f585d8a3SJacky Wang "package test;", 220*f585d8a3SJacky Wang "", 221*f585d8a3SJacky Wang "import dagger.Module;", 222*f585d8a3SJacky Wang "import dagger.Provides;", 223*f585d8a3SJacky Wang "import dagger.multibindings.ElementsIntoSet;", 224*f585d8a3SJacky Wang "import java.util.Collections;", 225*f585d8a3SJacky Wang "import java.util.Set;", 226*f585d8a3SJacky Wang "", 227*f585d8a3SJacky Wang "@Module", 228*f585d8a3SJacky Wang "interface ParentModule {", 229*f585d8a3SJacky Wang " @Provides @ElementsIntoSet", 230*f585d8a3SJacky Wang " static Set<Foo> provideFoo(FooImpl impl) {", 231*f585d8a3SJacky Wang " return Collections.singleton(impl);", 232*f585d8a3SJacky Wang " }", 233*f585d8a3SJacky Wang "}"); 234*f585d8a3SJacky Wang Source childComponent = 235*f585d8a3SJacky Wang CompilerTests.javaSource( 236*f585d8a3SJacky Wang "test.ChildComponent", 237*f585d8a3SJacky Wang "package test;", 238*f585d8a3SJacky Wang "", 239*f585d8a3SJacky Wang "import dagger.Subcomponent;", 240*f585d8a3SJacky Wang "import java.util.Set;", 241*f585d8a3SJacky Wang "", 242*f585d8a3SJacky Wang "@Subcomponent(modules = ChildModule.class)", 243*f585d8a3SJacky Wang "interface ChildComponent {", 244*f585d8a3SJacky Wang " Set<Foo> getFooSet();", 245*f585d8a3SJacky Wang "}"); 246*f585d8a3SJacky Wang Source childModule = 247*f585d8a3SJacky Wang CompilerTests.javaSource( 248*f585d8a3SJacky Wang "test.ChildModule", 249*f585d8a3SJacky Wang "package test;", 250*f585d8a3SJacky Wang "", 251*f585d8a3SJacky Wang "import dagger.Module;", 252*f585d8a3SJacky Wang "import dagger.Provides;", 253*f585d8a3SJacky Wang "", 254*f585d8a3SJacky Wang "@Module", 255*f585d8a3SJacky Wang "interface ChildModule {", 256*f585d8a3SJacky Wang " @Provides static Long providLong() {", 257*f585d8a3SJacky Wang " return 0L;", 258*f585d8a3SJacky Wang " }", 259*f585d8a3SJacky Wang "}"); 260*f585d8a3SJacky Wang Source iface = 261*f585d8a3SJacky Wang CompilerTests.javaSource( 262*f585d8a3SJacky Wang "test.Foo", 263*f585d8a3SJacky Wang "package test;", 264*f585d8a3SJacky Wang "", 265*f585d8a3SJacky Wang "interface Foo {}"); 266*f585d8a3SJacky Wang Source impl = 267*f585d8a3SJacky Wang CompilerTests.javaSource( 268*f585d8a3SJacky Wang "test.FooImpl", 269*f585d8a3SJacky Wang "package test;", 270*f585d8a3SJacky Wang "", 271*f585d8a3SJacky Wang "import javax.inject.Inject;", 272*f585d8a3SJacky Wang "", 273*f585d8a3SJacky Wang "class FooImpl implements Foo {", 274*f585d8a3SJacky Wang " @Inject FooImpl(Long l) {}", 275*f585d8a3SJacky Wang "}"); 276*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 277*f585d8a3SJacky Wang parentComponent, parentModule, childComponent, childModule, iface, impl) 278*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 279*f585d8a3SJacky Wang .compile( 280*f585d8a3SJacky Wang subject -> { 281*f585d8a3SJacky Wang subject.hasErrorCount(1); 282*f585d8a3SJacky Wang subject.hasErrorContaining("Long cannot be provided without an @Inject constructor") 283*f585d8a3SJacky Wang .onSource(parentComponent) 284*f585d8a3SJacky Wang .onLineContaining("interface ParentComponent"); 285*f585d8a3SJacky Wang }); 286*f585d8a3SJacky Wang } 287*f585d8a3SJacky Wang 288*f585d8a3SJacky Wang @Test testMapBindings()289*f585d8a3SJacky Wang public void testMapBindings() { 290*f585d8a3SJacky Wang Source parentComponent = 291*f585d8a3SJacky Wang CompilerTests.javaSource( 292*f585d8a3SJacky Wang "test.ParentComponent", 293*f585d8a3SJacky Wang "package test;", 294*f585d8a3SJacky Wang "", 295*f585d8a3SJacky Wang "import dagger.Component;", 296*f585d8a3SJacky Wang "", 297*f585d8a3SJacky Wang "@Component(modules = ParentModule.class)", 298*f585d8a3SJacky Wang "interface ParentComponent {", 299*f585d8a3SJacky Wang " ChildComponent getChild();", 300*f585d8a3SJacky Wang "}"); 301*f585d8a3SJacky Wang Source parentModule = 302*f585d8a3SJacky Wang CompilerTests.javaSource( 303*f585d8a3SJacky Wang "test.ParentModule", 304*f585d8a3SJacky Wang "package test;", 305*f585d8a3SJacky Wang "", 306*f585d8a3SJacky Wang "import dagger.Binds;", 307*f585d8a3SJacky Wang "import dagger.Module;", 308*f585d8a3SJacky Wang "import dagger.multibindings.IntoMap;", 309*f585d8a3SJacky Wang "import dagger.multibindings.StringKey;", 310*f585d8a3SJacky Wang "", 311*f585d8a3SJacky Wang "@Module", 312*f585d8a3SJacky Wang "interface ParentModule {", 313*f585d8a3SJacky Wang " @Binds @IntoMap @StringKey(\"foo\") Foo bindFoo(FooImpl impl);", 314*f585d8a3SJacky Wang "}"); 315*f585d8a3SJacky Wang Source childComponent = 316*f585d8a3SJacky Wang CompilerTests.javaSource( 317*f585d8a3SJacky Wang "test.ChildComponent", 318*f585d8a3SJacky Wang "package test;", 319*f585d8a3SJacky Wang "", 320*f585d8a3SJacky Wang "import dagger.Subcomponent;", 321*f585d8a3SJacky Wang "import java.util.Map;", 322*f585d8a3SJacky Wang "", 323*f585d8a3SJacky Wang "@Subcomponent(modules = ChildModule.class)", 324*f585d8a3SJacky Wang "interface ChildComponent {", 325*f585d8a3SJacky Wang " Map<String, Foo> getFooSet();", 326*f585d8a3SJacky Wang "}"); 327*f585d8a3SJacky Wang Source childModule = 328*f585d8a3SJacky Wang CompilerTests.javaSource( 329*f585d8a3SJacky Wang "test.ChildModule", 330*f585d8a3SJacky Wang "package test;", 331*f585d8a3SJacky Wang "", 332*f585d8a3SJacky Wang "import dagger.Module;", 333*f585d8a3SJacky Wang "import dagger.Provides;", 334*f585d8a3SJacky Wang "", 335*f585d8a3SJacky Wang "@Module", 336*f585d8a3SJacky Wang "interface ChildModule {", 337*f585d8a3SJacky Wang " @Provides static Long providLong() {", 338*f585d8a3SJacky Wang " return 0L;", 339*f585d8a3SJacky Wang " }", 340*f585d8a3SJacky Wang "}"); 341*f585d8a3SJacky Wang Source iface = 342*f585d8a3SJacky Wang CompilerTests.javaSource( 343*f585d8a3SJacky Wang "test.Foo", 344*f585d8a3SJacky Wang "package test;", 345*f585d8a3SJacky Wang "", 346*f585d8a3SJacky Wang "interface Foo {}"); 347*f585d8a3SJacky Wang Source impl = 348*f585d8a3SJacky Wang CompilerTests.javaSource( 349*f585d8a3SJacky Wang "test.FooImpl", 350*f585d8a3SJacky Wang "package test;", 351*f585d8a3SJacky Wang "", 352*f585d8a3SJacky Wang "import javax.inject.Inject;", 353*f585d8a3SJacky Wang "", 354*f585d8a3SJacky Wang "class FooImpl implements Foo {", 355*f585d8a3SJacky Wang " @Inject FooImpl(Long l) {}", 356*f585d8a3SJacky Wang "}"); 357*f585d8a3SJacky Wang CompilerTests.daggerCompiler( 358*f585d8a3SJacky Wang parentComponent, parentModule, childComponent, childModule, iface, impl) 359*f585d8a3SJacky Wang .withProcessingOptions( 360*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 361*f585d8a3SJacky Wang .putAll(compilerMode.processorOptions()) 362*f585d8a3SJacky Wang // TODO(erichang): make this flag the default and remove this 363*f585d8a3SJacky Wang .put("dagger.strictMultibindingValidation", "enabled") 364*f585d8a3SJacky Wang .build()) 365*f585d8a3SJacky Wang .compile( 366*f585d8a3SJacky Wang subject -> { 367*f585d8a3SJacky Wang subject.hasErrorCount(1); 368*f585d8a3SJacky Wang subject.hasErrorContaining("Long cannot be provided without an @Inject constructor") 369*f585d8a3SJacky Wang .onSource(parentComponent) 370*f585d8a3SJacky Wang .onLineContaining("interface ParentComponent"); 371*f585d8a3SJacky Wang }); 372*f585d8a3SJacky Wang } 373*f585d8a3SJacky Wang } 374