1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2018 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 dagger.internal.codegen.TestUtils.message; 20*f585d8a3SJacky Wang import static org.junit.Assume.assumeFalse; 21*f585d8a3SJacky Wang 22*f585d8a3SJacky Wang import androidx.room.compiler.processing.XProcessingEnv; 23*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source; 24*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList; 25*f585d8a3SJacky Wang import com.google.common.collect.ImmutableMap; 26*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests; 27*f585d8a3SJacky Wang import org.junit.Test; 28*f585d8a3SJacky Wang import org.junit.runner.RunWith; 29*f585d8a3SJacky Wang import org.junit.runners.Parameterized; 30*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters; 31*f585d8a3SJacky Wang 32*f585d8a3SJacky Wang @RunWith(Parameterized.class) 33*f585d8a3SJacky Wang public class DuplicateBindingsValidationTest { 34*f585d8a3SJacky Wang 35*f585d8a3SJacky Wang @Parameters(name = "fullBindingGraphValidation={0}") parameters()36*f585d8a3SJacky Wang public static ImmutableList<Object[]> parameters() { 37*f585d8a3SJacky Wang return ImmutableList.copyOf(new Object[][] {{false}, {true}}); 38*f585d8a3SJacky Wang } 39*f585d8a3SJacky Wang 40*f585d8a3SJacky Wang private final boolean fullBindingGraphValidation; 41*f585d8a3SJacky Wang DuplicateBindingsValidationTest(boolean fullBindingGraphValidation)42*f585d8a3SJacky Wang public DuplicateBindingsValidationTest(boolean fullBindingGraphValidation) { 43*f585d8a3SJacky Wang this.fullBindingGraphValidation = fullBindingGraphValidation; 44*f585d8a3SJacky Wang } 45*f585d8a3SJacky Wang duplicateExplicitBindings_ProvidesAndComponentProvision()46*f585d8a3SJacky Wang @Test public void duplicateExplicitBindings_ProvidesAndComponentProvision() { 47*f585d8a3SJacky Wang assumeFalse(fullBindingGraphValidation); 48*f585d8a3SJacky Wang 49*f585d8a3SJacky Wang Source component = 50*f585d8a3SJacky Wang CompilerTests.javaSource( 51*f585d8a3SJacky Wang "test.Outer", 52*f585d8a3SJacky Wang "package test;", 53*f585d8a3SJacky Wang "", 54*f585d8a3SJacky Wang "import dagger.Component;", 55*f585d8a3SJacky Wang "import dagger.Module;", 56*f585d8a3SJacky Wang "import dagger.Provides;", 57*f585d8a3SJacky Wang "", 58*f585d8a3SJacky Wang "final class Outer {", 59*f585d8a3SJacky Wang " interface A {}", 60*f585d8a3SJacky Wang "", 61*f585d8a3SJacky Wang " interface B {}", 62*f585d8a3SJacky Wang "", 63*f585d8a3SJacky Wang " @Module", 64*f585d8a3SJacky Wang " static class AModule {", 65*f585d8a3SJacky Wang " @Provides String provideString() { return \"\"; }", 66*f585d8a3SJacky Wang " @Provides A provideA(String s) { return new A() {}; }", 67*f585d8a3SJacky Wang " }", 68*f585d8a3SJacky Wang "", 69*f585d8a3SJacky Wang " @Component(modules = AModule.class)", 70*f585d8a3SJacky Wang " interface Parent {", 71*f585d8a3SJacky Wang " A getA();", 72*f585d8a3SJacky Wang " }", 73*f585d8a3SJacky Wang "", 74*f585d8a3SJacky Wang " @Module", 75*f585d8a3SJacky Wang " static class BModule {", 76*f585d8a3SJacky Wang " @Provides B provideB(A a) { return new B() {}; }", 77*f585d8a3SJacky Wang " }", 78*f585d8a3SJacky Wang "", 79*f585d8a3SJacky Wang " @Component(dependencies = Parent.class, modules = { BModule.class, AModule.class})", 80*f585d8a3SJacky Wang " interface Child {", 81*f585d8a3SJacky Wang " B getB();", 82*f585d8a3SJacky Wang " }", 83*f585d8a3SJacky Wang "}"); 84*f585d8a3SJacky Wang 85*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 86*f585d8a3SJacky Wang .withProcessingOptions( 87*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 88*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 89*f585d8a3SJacky Wang .buildOrThrow()) 90*f585d8a3SJacky Wang .compile( 91*f585d8a3SJacky Wang subject -> { 92*f585d8a3SJacky Wang subject.hasErrorCount(1); 93*f585d8a3SJacky Wang subject.hasErrorContaining( 94*f585d8a3SJacky Wang message( 95*f585d8a3SJacky Wang "Outer.A is bound multiple times:", 96*f585d8a3SJacky Wang " @Provides Outer.A Outer.AModule.provideA(String)", 97*f585d8a3SJacky Wang " Outer.A Outer.Parent.getA()")) 98*f585d8a3SJacky Wang .onSource(component) 99*f585d8a3SJacky Wang .onLineContaining("interface Child"); 100*f585d8a3SJacky Wang }); 101*f585d8a3SJacky Wang } 102*f585d8a3SJacky Wang duplicateExplicitBindings_TwoProvidesMethods()103*f585d8a3SJacky Wang @Test public void duplicateExplicitBindings_TwoProvidesMethods() { 104*f585d8a3SJacky Wang Source component = 105*f585d8a3SJacky Wang CompilerTests.javaSource( 106*f585d8a3SJacky Wang "test.Outer", 107*f585d8a3SJacky Wang "package test;", 108*f585d8a3SJacky Wang "", 109*f585d8a3SJacky Wang "import dagger.Component;", 110*f585d8a3SJacky Wang "import dagger.Module;", 111*f585d8a3SJacky Wang "import dagger.Provides;", 112*f585d8a3SJacky Wang "import javax.inject.Inject;", 113*f585d8a3SJacky Wang "", 114*f585d8a3SJacky Wang "final class Outer {", 115*f585d8a3SJacky Wang " interface A {}", 116*f585d8a3SJacky Wang "", 117*f585d8a3SJacky Wang " static class B {", 118*f585d8a3SJacky Wang " @Inject B(A a) {}", 119*f585d8a3SJacky Wang " }", 120*f585d8a3SJacky Wang "", 121*f585d8a3SJacky Wang " @Module", 122*f585d8a3SJacky Wang " static class Module1 {", 123*f585d8a3SJacky Wang " @Provides A provideA1() { return new A() {}; }", 124*f585d8a3SJacky Wang " }", 125*f585d8a3SJacky Wang "", 126*f585d8a3SJacky Wang " @Module", 127*f585d8a3SJacky Wang " static class Module2 {", 128*f585d8a3SJacky Wang " @Provides String provideString() { return \"\"; }", 129*f585d8a3SJacky Wang " @Provides A provideA2(String s) { return new A() {}; }", 130*f585d8a3SJacky Wang " }", 131*f585d8a3SJacky Wang "", 132*f585d8a3SJacky Wang " @Module(includes = { Module1.class, Module2.class})", 133*f585d8a3SJacky Wang " abstract static class Module3 {}", 134*f585d8a3SJacky Wang "", 135*f585d8a3SJacky Wang " @Component(modules = { Module1.class, Module2.class})", 136*f585d8a3SJacky Wang " interface TestComponent {", 137*f585d8a3SJacky Wang " A getA();", 138*f585d8a3SJacky Wang " B getB();", 139*f585d8a3SJacky Wang " }", 140*f585d8a3SJacky Wang "}"); 141*f585d8a3SJacky Wang 142*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 143*f585d8a3SJacky Wang .withProcessingOptions( 144*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 145*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 146*f585d8a3SJacky Wang .buildOrThrow()) 147*f585d8a3SJacky Wang .compile( 148*f585d8a3SJacky Wang subject -> { 149*f585d8a3SJacky Wang // The duplicate bindngs are also requested from B, but we don't want to report them 150*f585d8a3SJacky Wang // again. 151*f585d8a3SJacky Wang subject.hasErrorCount(fullBindingGraphValidation ? 2 : 1); 152*f585d8a3SJacky Wang 153*f585d8a3SJacky Wang subject.hasErrorContaining( 154*f585d8a3SJacky Wang message( 155*f585d8a3SJacky Wang "Outer.A is bound multiple times:", 156*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module1.provideA1()", 157*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module2.provideA2(String)")) 158*f585d8a3SJacky Wang .onSource(component) 159*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 160*f585d8a3SJacky Wang 161*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 162*f585d8a3SJacky Wang subject.hasErrorContaining( 163*f585d8a3SJacky Wang message( 164*f585d8a3SJacky Wang "Outer.A is bound multiple times:", 165*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module1.provideA1()", 166*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module2.provideA2(String)")) 167*f585d8a3SJacky Wang .onSource(component) 168*f585d8a3SJacky Wang .onLineContaining("class Module3"); 169*f585d8a3SJacky Wang } 170*f585d8a3SJacky Wang }); 171*f585d8a3SJacky Wang } 172*f585d8a3SJacky Wang 173*f585d8a3SJacky Wang @Test duplicateExplicitBindings_ProvidesVsBinds()174*f585d8a3SJacky Wang public void duplicateExplicitBindings_ProvidesVsBinds() { 175*f585d8a3SJacky Wang Source component = 176*f585d8a3SJacky Wang CompilerTests.javaSource( 177*f585d8a3SJacky Wang "test.Outer", 178*f585d8a3SJacky Wang "package test;", 179*f585d8a3SJacky Wang "", 180*f585d8a3SJacky Wang "import dagger.Binds;", 181*f585d8a3SJacky Wang "import dagger.Component;", 182*f585d8a3SJacky Wang "import dagger.Module;", 183*f585d8a3SJacky Wang "import dagger.Provides;", 184*f585d8a3SJacky Wang "import javax.inject.Inject;", 185*f585d8a3SJacky Wang "", 186*f585d8a3SJacky Wang "final class Outer {", 187*f585d8a3SJacky Wang " interface A {}", 188*f585d8a3SJacky Wang "", 189*f585d8a3SJacky Wang " static final class B implements A {", 190*f585d8a3SJacky Wang " @Inject B() {}", 191*f585d8a3SJacky Wang " }", 192*f585d8a3SJacky Wang "", 193*f585d8a3SJacky Wang " @Module", 194*f585d8a3SJacky Wang " static class Module1 {", 195*f585d8a3SJacky Wang " @Provides A provideA1() { return new A() {}; }", 196*f585d8a3SJacky Wang " }", 197*f585d8a3SJacky Wang "", 198*f585d8a3SJacky Wang " @Module", 199*f585d8a3SJacky Wang " static abstract class Module2 {", 200*f585d8a3SJacky Wang " @Binds abstract A bindA2(B b);", 201*f585d8a3SJacky Wang " }", 202*f585d8a3SJacky Wang "", 203*f585d8a3SJacky Wang " @Module(includes = { Module1.class, Module2.class})", 204*f585d8a3SJacky Wang " abstract static class Module3 {}", 205*f585d8a3SJacky Wang "", 206*f585d8a3SJacky Wang " @Component(modules = { Module1.class, Module2.class})", 207*f585d8a3SJacky Wang " interface TestComponent {", 208*f585d8a3SJacky Wang " A getA();", 209*f585d8a3SJacky Wang " }", 210*f585d8a3SJacky Wang "}"); 211*f585d8a3SJacky Wang 212*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 213*f585d8a3SJacky Wang .withProcessingOptions( 214*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 215*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 216*f585d8a3SJacky Wang .buildOrThrow()) 217*f585d8a3SJacky Wang .compile( 218*f585d8a3SJacky Wang subject -> { 219*f585d8a3SJacky Wang String errorMessage = 220*f585d8a3SJacky Wang message( 221*f585d8a3SJacky Wang "Outer.A is bound multiple times:", 222*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module1.provideA1()", 223*f585d8a3SJacky Wang " @Binds Outer.A Outer.Module2.bindA2(Outer.B)"); 224*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 225*f585d8a3SJacky Wang subject.hasErrorCount(2); 226*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 227*f585d8a3SJacky Wang .onSource(component) 228*f585d8a3SJacky Wang .onLineContaining("class Module3"); 229*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 230*f585d8a3SJacky Wang .onSource(component) 231*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 232*f585d8a3SJacky Wang } else { 233*f585d8a3SJacky Wang subject.hasErrorCount(1); 234*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 235*f585d8a3SJacky Wang .onSource(component) 236*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 237*f585d8a3SJacky Wang } 238*f585d8a3SJacky Wang }); 239*f585d8a3SJacky Wang } 240*f585d8a3SJacky Wang 241*f585d8a3SJacky Wang @Test duplicateExplicitBindings_multibindingsAndExplicitSets()242*f585d8a3SJacky Wang public void duplicateExplicitBindings_multibindingsAndExplicitSets() { 243*f585d8a3SJacky Wang Source component = 244*f585d8a3SJacky Wang CompilerTests.javaSource( 245*f585d8a3SJacky Wang "test.Outer", 246*f585d8a3SJacky Wang "package test;", 247*f585d8a3SJacky Wang "", 248*f585d8a3SJacky Wang "import dagger.Binds;", 249*f585d8a3SJacky Wang "import dagger.Component;", 250*f585d8a3SJacky Wang "import dagger.Module;", 251*f585d8a3SJacky Wang "import dagger.Provides;", 252*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 253*f585d8a3SJacky Wang "import java.util.HashSet;", 254*f585d8a3SJacky Wang "import java.util.Set;", 255*f585d8a3SJacky Wang "import javax.inject.Qualifier;", 256*f585d8a3SJacky Wang "", 257*f585d8a3SJacky Wang "final class Outer {", 258*f585d8a3SJacky Wang " @Qualifier @interface SomeQualifier {}", 259*f585d8a3SJacky Wang "", 260*f585d8a3SJacky Wang " @Module", 261*f585d8a3SJacky Wang " abstract static class TestModule1 {", 262*f585d8a3SJacky Wang " @Provides @IntoSet static String stringSetElement() { return \"\"; }", 263*f585d8a3SJacky Wang "", 264*f585d8a3SJacky Wang " @Binds", 265*f585d8a3SJacky Wang " @IntoSet abstract String bindStringSetElement(@SomeQualifier String value);", 266*f585d8a3SJacky Wang "", 267*f585d8a3SJacky Wang " @Provides @SomeQualifier", 268*f585d8a3SJacky Wang " static String provideSomeQualifiedString() { return \"\"; }", 269*f585d8a3SJacky Wang " }", 270*f585d8a3SJacky Wang "", 271*f585d8a3SJacky Wang " @Module", 272*f585d8a3SJacky Wang " static class TestModule2 {", 273*f585d8a3SJacky Wang " @Provides Set<String> stringSet() { return new HashSet<String>(); }", 274*f585d8a3SJacky Wang " }", 275*f585d8a3SJacky Wang "", 276*f585d8a3SJacky Wang " @Module(includes = { TestModule1.class, TestModule2.class})", 277*f585d8a3SJacky Wang " abstract static class TestModule3 {}", 278*f585d8a3SJacky Wang "", 279*f585d8a3SJacky Wang " @Component(modules = { TestModule1.class, TestModule2.class })", 280*f585d8a3SJacky Wang " interface TestComponent {", 281*f585d8a3SJacky Wang " Set<String> getStringSet();", 282*f585d8a3SJacky Wang " }", 283*f585d8a3SJacky Wang "}"); 284*f585d8a3SJacky Wang 285*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 286*f585d8a3SJacky Wang .withProcessingOptions( 287*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 288*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 289*f585d8a3SJacky Wang .buildOrThrow()) 290*f585d8a3SJacky Wang .compile( 291*f585d8a3SJacky Wang subject -> { 292*f585d8a3SJacky Wang String errorMessage = 293*f585d8a3SJacky Wang message( 294*f585d8a3SJacky Wang "Set<String> has incompatible bindings or declarations:", 295*f585d8a3SJacky Wang " Set bindings and declarations:", 296*f585d8a3SJacky Wang " @Binds @IntoSet String " 297*f585d8a3SJacky Wang + "Outer.TestModule1.bindStringSetElement(@Outer.SomeQualifier String)", 298*f585d8a3SJacky Wang " @Provides @IntoSet String " 299*f585d8a3SJacky Wang + "Outer.TestModule1.stringSetElement()", 300*f585d8a3SJacky Wang " Unique bindings and declarations:", 301*f585d8a3SJacky Wang " @Provides Set<String> Outer.TestModule2.stringSet()"); 302*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 303*f585d8a3SJacky Wang subject.hasErrorCount(2); 304*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 305*f585d8a3SJacky Wang .onSource(component) 306*f585d8a3SJacky Wang .onLineContaining("class TestModule3"); 307*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 308*f585d8a3SJacky Wang .onSource(component) 309*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 310*f585d8a3SJacky Wang } else { 311*f585d8a3SJacky Wang subject.hasErrorCount(1); 312*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 313*f585d8a3SJacky Wang .onSource(component) 314*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 315*f585d8a3SJacky Wang } 316*f585d8a3SJacky Wang }); 317*f585d8a3SJacky Wang } 318*f585d8a3SJacky Wang 319*f585d8a3SJacky Wang @Test duplicateExplicitBindings_multibindingsAndExplicitMaps()320*f585d8a3SJacky Wang public void duplicateExplicitBindings_multibindingsAndExplicitMaps() { 321*f585d8a3SJacky Wang Source component = 322*f585d8a3SJacky Wang CompilerTests.javaSource( 323*f585d8a3SJacky Wang "test.Outer", 324*f585d8a3SJacky Wang "package test;", 325*f585d8a3SJacky Wang "", 326*f585d8a3SJacky Wang "import dagger.Binds;", 327*f585d8a3SJacky Wang "import dagger.Component;", 328*f585d8a3SJacky Wang "import dagger.Module;", 329*f585d8a3SJacky Wang "import dagger.Provides;", 330*f585d8a3SJacky Wang "import dagger.multibindings.IntoMap;", 331*f585d8a3SJacky Wang "import dagger.multibindings.StringKey;", 332*f585d8a3SJacky Wang "import java.util.HashMap;", 333*f585d8a3SJacky Wang "import java.util.Map;", 334*f585d8a3SJacky Wang "import javax.inject.Qualifier;", 335*f585d8a3SJacky Wang "", 336*f585d8a3SJacky Wang "final class Outer {", 337*f585d8a3SJacky Wang " @Qualifier @interface SomeQualifier {}", 338*f585d8a3SJacky Wang "", 339*f585d8a3SJacky Wang " @Module", 340*f585d8a3SJacky Wang " abstract static class TestModule1 {", 341*f585d8a3SJacky Wang " @Provides @IntoMap", 342*f585d8a3SJacky Wang " @StringKey(\"foo\")", 343*f585d8a3SJacky Wang " static String stringMapEntry() { return \"\"; }", 344*f585d8a3SJacky Wang "", 345*f585d8a3SJacky Wang " @Binds @IntoMap @StringKey(\"bar\")", 346*f585d8a3SJacky Wang " abstract String bindStringMapEntry(@SomeQualifier String value);", 347*f585d8a3SJacky Wang "", 348*f585d8a3SJacky Wang " @Provides @SomeQualifier", 349*f585d8a3SJacky Wang " static String provideSomeQualifiedString() { return \"\"; }", 350*f585d8a3SJacky Wang " }", 351*f585d8a3SJacky Wang "", 352*f585d8a3SJacky Wang " @Module", 353*f585d8a3SJacky Wang " static class TestModule2 {", 354*f585d8a3SJacky Wang " @Provides Map<String, String> stringMap() {", 355*f585d8a3SJacky Wang " return new HashMap<String, String>();", 356*f585d8a3SJacky Wang " }", 357*f585d8a3SJacky Wang " }", 358*f585d8a3SJacky Wang "", 359*f585d8a3SJacky Wang " @Module(includes = { TestModule1.class, TestModule2.class})", 360*f585d8a3SJacky Wang " abstract static class TestModule3 {}", 361*f585d8a3SJacky Wang "", 362*f585d8a3SJacky Wang " @Component(modules = { TestModule1.class, TestModule2.class })", 363*f585d8a3SJacky Wang " interface TestComponent {", 364*f585d8a3SJacky Wang " Map<String, String> getStringMap();", 365*f585d8a3SJacky Wang " }", 366*f585d8a3SJacky Wang "}"); 367*f585d8a3SJacky Wang 368*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 369*f585d8a3SJacky Wang .withProcessingOptions( 370*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 371*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 372*f585d8a3SJacky Wang .buildOrThrow()) 373*f585d8a3SJacky Wang .compile( 374*f585d8a3SJacky Wang subject -> { 375*f585d8a3SJacky Wang String errorMessage = 376*f585d8a3SJacky Wang message( 377*f585d8a3SJacky Wang "Map<String,String> has incompatible bindings or declarations:", 378*f585d8a3SJacky Wang " Map bindings and declarations:", 379*f585d8a3SJacky Wang " @Binds @IntoMap @StringKey(\"bar\") String" 380*f585d8a3SJacky Wang + " Outer.TestModule1.bindStringMapEntry(@Outer.SomeQualifier String)", 381*f585d8a3SJacky Wang " @Provides @IntoMap @StringKey(\"foo\") String" 382*f585d8a3SJacky Wang + " Outer.TestModule1.stringMapEntry()", 383*f585d8a3SJacky Wang " Unique bindings and declarations:", 384*f585d8a3SJacky Wang " @Provides Map<String,String> Outer.TestModule2.stringMap()"); 385*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 386*f585d8a3SJacky Wang subject.hasErrorCount(2); 387*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 388*f585d8a3SJacky Wang .onSource(component) 389*f585d8a3SJacky Wang .onLineContaining("class TestModule3"); 390*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 391*f585d8a3SJacky Wang .onSource(component) 392*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 393*f585d8a3SJacky Wang } else { 394*f585d8a3SJacky Wang subject.hasErrorCount(1); 395*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 396*f585d8a3SJacky Wang .onSource(component) 397*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 398*f585d8a3SJacky Wang } 399*f585d8a3SJacky Wang }); 400*f585d8a3SJacky Wang } 401*f585d8a3SJacky Wang 402*f585d8a3SJacky Wang @Test duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Set()403*f585d8a3SJacky Wang public void duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Set() { 404*f585d8a3SJacky Wang Source component = 405*f585d8a3SJacky Wang CompilerTests.javaSource( 406*f585d8a3SJacky Wang "test.Outer", 407*f585d8a3SJacky Wang "package test;", 408*f585d8a3SJacky Wang "", 409*f585d8a3SJacky Wang "import dagger.Component;", 410*f585d8a3SJacky Wang "import dagger.Module;", 411*f585d8a3SJacky Wang "import dagger.Provides;", 412*f585d8a3SJacky Wang "import dagger.multibindings.Multibinds;", 413*f585d8a3SJacky Wang "import java.util.HashSet;", 414*f585d8a3SJacky Wang "import java.util.Set;", 415*f585d8a3SJacky Wang "", 416*f585d8a3SJacky Wang "final class Outer {", 417*f585d8a3SJacky Wang " @Module", 418*f585d8a3SJacky Wang " abstract static class TestModule1 {", 419*f585d8a3SJacky Wang " @Multibinds abstract Set<String> stringSet();", 420*f585d8a3SJacky Wang " }", 421*f585d8a3SJacky Wang "", 422*f585d8a3SJacky Wang " @Module", 423*f585d8a3SJacky Wang " static class TestModule2 {", 424*f585d8a3SJacky Wang " @Provides Set<String> stringSet() { return new HashSet<String>(); }", 425*f585d8a3SJacky Wang " }", 426*f585d8a3SJacky Wang "", 427*f585d8a3SJacky Wang " @Module(includes = { TestModule1.class, TestModule2.class})", 428*f585d8a3SJacky Wang " abstract static class TestModule3 {}", 429*f585d8a3SJacky Wang "", 430*f585d8a3SJacky Wang " @Component(modules = { TestModule1.class, TestModule2.class })", 431*f585d8a3SJacky Wang " interface TestComponent {", 432*f585d8a3SJacky Wang " Set<String> getStringSet();", 433*f585d8a3SJacky Wang " }", 434*f585d8a3SJacky Wang "}"); 435*f585d8a3SJacky Wang 436*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 437*f585d8a3SJacky Wang .withProcessingOptions( 438*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 439*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 440*f585d8a3SJacky Wang .buildOrThrow()) 441*f585d8a3SJacky Wang .compile( 442*f585d8a3SJacky Wang subject -> { 443*f585d8a3SJacky Wang String errorMessage = 444*f585d8a3SJacky Wang message( 445*f585d8a3SJacky Wang "Set<String> has incompatible bindings or declarations:", 446*f585d8a3SJacky Wang " Set bindings and declarations:", 447*f585d8a3SJacky Wang " @Multibinds Set<String> Outer.TestModule1.stringSet()", 448*f585d8a3SJacky Wang " Unique bindings and declarations:", 449*f585d8a3SJacky Wang " @Provides Set<String> Outer.TestModule2.stringSet()"); 450*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 451*f585d8a3SJacky Wang subject.hasErrorCount(2); 452*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 453*f585d8a3SJacky Wang .onSource(component) 454*f585d8a3SJacky Wang .onLineContaining("class TestModule3"); 455*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 456*f585d8a3SJacky Wang .onSource(component) 457*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 458*f585d8a3SJacky Wang } else { 459*f585d8a3SJacky Wang subject.hasErrorCount(1); 460*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 461*f585d8a3SJacky Wang .onSource(component) 462*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 463*f585d8a3SJacky Wang } 464*f585d8a3SJacky Wang }); 465*f585d8a3SJacky Wang } 466*f585d8a3SJacky Wang 467*f585d8a3SJacky Wang @Test duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Map()468*f585d8a3SJacky Wang public void duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Map() { 469*f585d8a3SJacky Wang Source component = 470*f585d8a3SJacky Wang CompilerTests.javaSource( 471*f585d8a3SJacky Wang "test.Outer", 472*f585d8a3SJacky Wang "package test;", 473*f585d8a3SJacky Wang "", 474*f585d8a3SJacky Wang "import dagger.Component;", 475*f585d8a3SJacky Wang "import dagger.Module;", 476*f585d8a3SJacky Wang "import dagger.Provides;", 477*f585d8a3SJacky Wang "import dagger.multibindings.Multibinds;", 478*f585d8a3SJacky Wang "import java.util.HashMap;", 479*f585d8a3SJacky Wang "import java.util.Map;", 480*f585d8a3SJacky Wang "", 481*f585d8a3SJacky Wang "final class Outer {", 482*f585d8a3SJacky Wang " @Module", 483*f585d8a3SJacky Wang " abstract static class TestModule1 {", 484*f585d8a3SJacky Wang " @Multibinds abstract Map<String, String> stringMap();", 485*f585d8a3SJacky Wang " }", 486*f585d8a3SJacky Wang "", 487*f585d8a3SJacky Wang " @Module", 488*f585d8a3SJacky Wang " static class TestModule2 {", 489*f585d8a3SJacky Wang " @Provides Map<String, String> stringMap() {", 490*f585d8a3SJacky Wang " return new HashMap<String, String>();", 491*f585d8a3SJacky Wang " }", 492*f585d8a3SJacky Wang " }", 493*f585d8a3SJacky Wang "", 494*f585d8a3SJacky Wang " @Module(includes = { TestModule1.class, TestModule2.class})", 495*f585d8a3SJacky Wang " abstract static class TestModule3 {}", 496*f585d8a3SJacky Wang "", 497*f585d8a3SJacky Wang " @Component(modules = { TestModule1.class, TestModule2.class })", 498*f585d8a3SJacky Wang " interface TestComponent {", 499*f585d8a3SJacky Wang " Map<String, String> getStringMap();", 500*f585d8a3SJacky Wang " }", 501*f585d8a3SJacky Wang "}"); 502*f585d8a3SJacky Wang 503*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 504*f585d8a3SJacky Wang .withProcessingOptions( 505*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 506*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 507*f585d8a3SJacky Wang .buildOrThrow()) 508*f585d8a3SJacky Wang .compile( 509*f585d8a3SJacky Wang subject -> { 510*f585d8a3SJacky Wang String errorMessage = 511*f585d8a3SJacky Wang message( 512*f585d8a3SJacky Wang "Map<String,String> has incompatible bindings or declarations:", 513*f585d8a3SJacky Wang " Map bindings and declarations:", 514*f585d8a3SJacky Wang " @Multibinds Map<String,String> Outer.TestModule1.stringMap()", 515*f585d8a3SJacky Wang " Unique bindings and declarations:", 516*f585d8a3SJacky Wang " @Provides Map<String,String> Outer.TestModule2.stringMap()"); 517*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 518*f585d8a3SJacky Wang subject.hasErrorCount(2); 519*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 520*f585d8a3SJacky Wang .onSource(component) 521*f585d8a3SJacky Wang .onLineContaining("class TestModule3"); 522*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 523*f585d8a3SJacky Wang .onSource(component) 524*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 525*f585d8a3SJacky Wang } else { 526*f585d8a3SJacky Wang subject.hasErrorCount(1); 527*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 528*f585d8a3SJacky Wang .onSource(component) 529*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 530*f585d8a3SJacky Wang } 531*f585d8a3SJacky Wang }); 532*f585d8a3SJacky Wang } 533*f585d8a3SJacky Wang duplicateBindings_TruncateAfterLimit()534*f585d8a3SJacky Wang @Test public void duplicateBindings_TruncateAfterLimit() { 535*f585d8a3SJacky Wang Source component = 536*f585d8a3SJacky Wang CompilerTests.javaSource( 537*f585d8a3SJacky Wang "test.Outer", 538*f585d8a3SJacky Wang "package test;", 539*f585d8a3SJacky Wang "", 540*f585d8a3SJacky Wang "import dagger.Component;", 541*f585d8a3SJacky Wang "import dagger.Module;", 542*f585d8a3SJacky Wang "import dagger.Provides;", 543*f585d8a3SJacky Wang "import javax.inject.Inject;", 544*f585d8a3SJacky Wang "", 545*f585d8a3SJacky Wang "final class Outer {", 546*f585d8a3SJacky Wang " interface A {}", 547*f585d8a3SJacky Wang "", 548*f585d8a3SJacky Wang " @Module", 549*f585d8a3SJacky Wang " static class Module01 {", 550*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 551*f585d8a3SJacky Wang " }", 552*f585d8a3SJacky Wang "", 553*f585d8a3SJacky Wang " @Module", 554*f585d8a3SJacky Wang " static class Module02 {", 555*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 556*f585d8a3SJacky Wang " }", 557*f585d8a3SJacky Wang "", 558*f585d8a3SJacky Wang " @Module", 559*f585d8a3SJacky Wang " static class Module03 {", 560*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 561*f585d8a3SJacky Wang " }", 562*f585d8a3SJacky Wang "", 563*f585d8a3SJacky Wang " @Module", 564*f585d8a3SJacky Wang " static class Module04 {", 565*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 566*f585d8a3SJacky Wang " }", 567*f585d8a3SJacky Wang "", 568*f585d8a3SJacky Wang " @Module", 569*f585d8a3SJacky Wang " static class Module05 {", 570*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 571*f585d8a3SJacky Wang " }", 572*f585d8a3SJacky Wang "", 573*f585d8a3SJacky Wang " @Module", 574*f585d8a3SJacky Wang " static class Module06 {", 575*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 576*f585d8a3SJacky Wang " }", 577*f585d8a3SJacky Wang "", 578*f585d8a3SJacky Wang " @Module", 579*f585d8a3SJacky Wang " static class Module07 {", 580*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 581*f585d8a3SJacky Wang " }", 582*f585d8a3SJacky Wang "", 583*f585d8a3SJacky Wang " @Module", 584*f585d8a3SJacky Wang " static class Module08 {", 585*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 586*f585d8a3SJacky Wang " }", 587*f585d8a3SJacky Wang "", 588*f585d8a3SJacky Wang " @Module", 589*f585d8a3SJacky Wang " static class Module09 {", 590*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 591*f585d8a3SJacky Wang " }", 592*f585d8a3SJacky Wang "", 593*f585d8a3SJacky Wang " @Module", 594*f585d8a3SJacky Wang " static class Module10 {", 595*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 596*f585d8a3SJacky Wang " }", 597*f585d8a3SJacky Wang "", 598*f585d8a3SJacky Wang " @Module", 599*f585d8a3SJacky Wang " static class Module11 {", 600*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 601*f585d8a3SJacky Wang " }", 602*f585d8a3SJacky Wang "", 603*f585d8a3SJacky Wang " @Module", 604*f585d8a3SJacky Wang " static class Module12 {", 605*f585d8a3SJacky Wang " @Provides A provideA() { return new A() {}; }", 606*f585d8a3SJacky Wang " }", 607*f585d8a3SJacky Wang "", 608*f585d8a3SJacky Wang " @Module(includes = {", 609*f585d8a3SJacky Wang " Module01.class,", 610*f585d8a3SJacky Wang " Module02.class,", 611*f585d8a3SJacky Wang " Module03.class,", 612*f585d8a3SJacky Wang " Module04.class,", 613*f585d8a3SJacky Wang " Module05.class,", 614*f585d8a3SJacky Wang " Module06.class,", 615*f585d8a3SJacky Wang " Module07.class,", 616*f585d8a3SJacky Wang " Module08.class,", 617*f585d8a3SJacky Wang " Module09.class,", 618*f585d8a3SJacky Wang " Module10.class,", 619*f585d8a3SJacky Wang " Module11.class,", 620*f585d8a3SJacky Wang " Module12.class", 621*f585d8a3SJacky Wang " })", 622*f585d8a3SJacky Wang " abstract static class Modules {}", 623*f585d8a3SJacky Wang "", 624*f585d8a3SJacky Wang " @Component(modules = {", 625*f585d8a3SJacky Wang " Module01.class,", 626*f585d8a3SJacky Wang " Module02.class,", 627*f585d8a3SJacky Wang " Module03.class,", 628*f585d8a3SJacky Wang " Module04.class,", 629*f585d8a3SJacky Wang " Module05.class,", 630*f585d8a3SJacky Wang " Module06.class,", 631*f585d8a3SJacky Wang " Module07.class,", 632*f585d8a3SJacky Wang " Module08.class,", 633*f585d8a3SJacky Wang " Module09.class,", 634*f585d8a3SJacky Wang " Module10.class,", 635*f585d8a3SJacky Wang " Module11.class,", 636*f585d8a3SJacky Wang " Module12.class", 637*f585d8a3SJacky Wang " })", 638*f585d8a3SJacky Wang " interface TestComponent {", 639*f585d8a3SJacky Wang " A getA();", 640*f585d8a3SJacky Wang " }", 641*f585d8a3SJacky Wang "}"); 642*f585d8a3SJacky Wang 643*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 644*f585d8a3SJacky Wang .withProcessingOptions( 645*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 646*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 647*f585d8a3SJacky Wang .buildOrThrow()) 648*f585d8a3SJacky Wang .compile( 649*f585d8a3SJacky Wang subject -> { 650*f585d8a3SJacky Wang subject.hasErrorCount(fullBindingGraphValidation ? 2 : 1); 651*f585d8a3SJacky Wang String errorMessage = 652*f585d8a3SJacky Wang message( 653*f585d8a3SJacky Wang "Outer.A is bound multiple times:", 654*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module01.provideA()", 655*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module02.provideA()", 656*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module03.provideA()", 657*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module04.provideA()", 658*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module05.provideA()", 659*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module06.provideA()", 660*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module07.provideA()", 661*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module08.provideA()", 662*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module09.provideA()", 663*f585d8a3SJacky Wang " @Provides Outer.A Outer.Module10.provideA()", 664*f585d8a3SJacky Wang " and 2 others"); 665*f585d8a3SJacky Wang 666*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 667*f585d8a3SJacky Wang .onSource(component) 668*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 669*f585d8a3SJacky Wang 670*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 671*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 672*f585d8a3SJacky Wang .onSource(component) 673*f585d8a3SJacky Wang .onLineContaining("class Modules"); 674*f585d8a3SJacky Wang } 675*f585d8a3SJacky Wang }); 676*f585d8a3SJacky Wang } 677*f585d8a3SJacky Wang 678*f585d8a3SJacky Wang @Test childBindingConflictsWithParent()679*f585d8a3SJacky Wang public void childBindingConflictsWithParent() { 680*f585d8a3SJacky Wang Source aComponent = 681*f585d8a3SJacky Wang CompilerTests.javaSource( 682*f585d8a3SJacky Wang "test.A", 683*f585d8a3SJacky Wang "package test;", 684*f585d8a3SJacky Wang "", 685*f585d8a3SJacky Wang "import dagger.Component;", 686*f585d8a3SJacky Wang "import dagger.Module;", 687*f585d8a3SJacky Wang "import dagger.Provides;", 688*f585d8a3SJacky Wang "", 689*f585d8a3SJacky Wang "@Component(modules = A.AModule.class)", 690*f585d8a3SJacky Wang "interface A {", 691*f585d8a3SJacky Wang " Object conflict();", 692*f585d8a3SJacky Wang "", 693*f585d8a3SJacky Wang " B.Builder b();", 694*f585d8a3SJacky Wang "", 695*f585d8a3SJacky Wang " @Module(subcomponents = B.class)", 696*f585d8a3SJacky Wang " static class AModule {", 697*f585d8a3SJacky Wang " @Provides static Object abConflict() {", 698*f585d8a3SJacky Wang " return \"a\";", 699*f585d8a3SJacky Wang " }", 700*f585d8a3SJacky Wang " }", 701*f585d8a3SJacky Wang "}"); 702*f585d8a3SJacky Wang Source bComponent = 703*f585d8a3SJacky Wang CompilerTests.javaSource( 704*f585d8a3SJacky Wang "test.B", 705*f585d8a3SJacky Wang "package test;", 706*f585d8a3SJacky Wang "", 707*f585d8a3SJacky Wang "import dagger.Module;", 708*f585d8a3SJacky Wang "import dagger.Provides;", 709*f585d8a3SJacky Wang "import dagger.Subcomponent;", 710*f585d8a3SJacky Wang "", 711*f585d8a3SJacky Wang "@Subcomponent(modules = B.BModule.class)", 712*f585d8a3SJacky Wang "interface B {", 713*f585d8a3SJacky Wang " Object conflict();", 714*f585d8a3SJacky Wang "", 715*f585d8a3SJacky Wang " @Subcomponent.Builder", 716*f585d8a3SJacky Wang " interface Builder {", 717*f585d8a3SJacky Wang " B build();", 718*f585d8a3SJacky Wang " }", 719*f585d8a3SJacky Wang "", 720*f585d8a3SJacky Wang " @Module", 721*f585d8a3SJacky Wang " static class BModule {", 722*f585d8a3SJacky Wang " @Provides static Object abConflict() {", 723*f585d8a3SJacky Wang " return \"b\";", 724*f585d8a3SJacky Wang " }", 725*f585d8a3SJacky Wang " }", 726*f585d8a3SJacky Wang "}"); 727*f585d8a3SJacky Wang 728*f585d8a3SJacky Wang CompilerTests.daggerCompiler(aComponent, bComponent) 729*f585d8a3SJacky Wang .withProcessingOptions( 730*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 731*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 732*f585d8a3SJacky Wang .buildOrThrow()) 733*f585d8a3SJacky Wang .compile( 734*f585d8a3SJacky Wang subject -> { 735*f585d8a3SJacky Wang String errorMessage = 736*f585d8a3SJacky Wang message( 737*f585d8a3SJacky Wang "Object is bound multiple times:", 738*f585d8a3SJacky Wang " @Provides Object test.A.AModule.abConflict()", 739*f585d8a3SJacky Wang " @Provides Object test.B.BModule.abConflict()"); 740*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 741*f585d8a3SJacky Wang subject.hasErrorCount(2); 742*f585d8a3SJacky Wang subject.hasErrorContaining("test.A.AModule has errors") 743*f585d8a3SJacky Wang .onSource(aComponent) 744*f585d8a3SJacky Wang .onLineContaining("@Component("); 745*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 746*f585d8a3SJacky Wang .onSource(aComponent) 747*f585d8a3SJacky Wang .onLineContaining("class AModule"); 748*f585d8a3SJacky Wang } else { 749*f585d8a3SJacky Wang subject.hasErrorCount(1); 750*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 751*f585d8a3SJacky Wang .onSource(aComponent) 752*f585d8a3SJacky Wang .onLineContaining("interface A {"); 753*f585d8a3SJacky Wang } 754*f585d8a3SJacky Wang }); 755*f585d8a3SJacky Wang } 756*f585d8a3SJacky Wang 757*f585d8a3SJacky Wang @Test grandchildBindingConflictsWithGrandparent()758*f585d8a3SJacky Wang public void grandchildBindingConflictsWithGrandparent() { 759*f585d8a3SJacky Wang Source aComponent = 760*f585d8a3SJacky Wang CompilerTests.javaSource( 761*f585d8a3SJacky Wang "test.A", 762*f585d8a3SJacky Wang "package test;", 763*f585d8a3SJacky Wang "", 764*f585d8a3SJacky Wang "import dagger.Component;", 765*f585d8a3SJacky Wang "import dagger.Module;", 766*f585d8a3SJacky Wang "import dagger.Provides;", 767*f585d8a3SJacky Wang "", 768*f585d8a3SJacky Wang "@Component(modules = A.AModule.class)", 769*f585d8a3SJacky Wang "interface A {", 770*f585d8a3SJacky Wang " Object conflict();", 771*f585d8a3SJacky Wang "", 772*f585d8a3SJacky Wang " B.Builder b();", 773*f585d8a3SJacky Wang "", 774*f585d8a3SJacky Wang " @Module(subcomponents = B.class)", 775*f585d8a3SJacky Wang " static class AModule {", 776*f585d8a3SJacky Wang " @Provides static Object acConflict() {", 777*f585d8a3SJacky Wang " return \"a\";", 778*f585d8a3SJacky Wang " }", 779*f585d8a3SJacky Wang " }", 780*f585d8a3SJacky Wang "}"); 781*f585d8a3SJacky Wang Source bComponent = 782*f585d8a3SJacky Wang CompilerTests.javaSource( 783*f585d8a3SJacky Wang "test.B", 784*f585d8a3SJacky Wang "package test;", 785*f585d8a3SJacky Wang "", 786*f585d8a3SJacky Wang "import dagger.Subcomponent;", 787*f585d8a3SJacky Wang "", 788*f585d8a3SJacky Wang "@Subcomponent", 789*f585d8a3SJacky Wang "interface B {", 790*f585d8a3SJacky Wang " C.Builder c();", 791*f585d8a3SJacky Wang "", 792*f585d8a3SJacky Wang " @Subcomponent.Builder", 793*f585d8a3SJacky Wang " interface Builder {", 794*f585d8a3SJacky Wang " B build();", 795*f585d8a3SJacky Wang " }", 796*f585d8a3SJacky Wang "}"); 797*f585d8a3SJacky Wang Source cComponent = 798*f585d8a3SJacky Wang CompilerTests.javaSource( 799*f585d8a3SJacky Wang "test.C", 800*f585d8a3SJacky Wang "package test;", 801*f585d8a3SJacky Wang "", 802*f585d8a3SJacky Wang "import dagger.Module;", 803*f585d8a3SJacky Wang "import dagger.Provides;", 804*f585d8a3SJacky Wang "import dagger.Subcomponent;", 805*f585d8a3SJacky Wang "", 806*f585d8a3SJacky Wang "@Subcomponent(modules = C.CModule.class)", 807*f585d8a3SJacky Wang "interface C {", 808*f585d8a3SJacky Wang " Object conflict();", 809*f585d8a3SJacky Wang "", 810*f585d8a3SJacky Wang " @Subcomponent.Builder", 811*f585d8a3SJacky Wang " interface Builder {", 812*f585d8a3SJacky Wang " C build();", 813*f585d8a3SJacky Wang " }", 814*f585d8a3SJacky Wang "", 815*f585d8a3SJacky Wang " @Module", 816*f585d8a3SJacky Wang " static class CModule {", 817*f585d8a3SJacky Wang " @Provides static Object acConflict() {", 818*f585d8a3SJacky Wang " return \"c\";", 819*f585d8a3SJacky Wang " }", 820*f585d8a3SJacky Wang " }", 821*f585d8a3SJacky Wang "}"); 822*f585d8a3SJacky Wang 823*f585d8a3SJacky Wang CompilerTests.daggerCompiler(aComponent, bComponent, cComponent) 824*f585d8a3SJacky Wang .withProcessingOptions( 825*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 826*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 827*f585d8a3SJacky Wang .buildOrThrow()) 828*f585d8a3SJacky Wang .compile( 829*f585d8a3SJacky Wang subject -> { 830*f585d8a3SJacky Wang String errorMessage = 831*f585d8a3SJacky Wang message( 832*f585d8a3SJacky Wang "Object is bound multiple times:", 833*f585d8a3SJacky Wang " @Provides Object test.A.AModule.acConflict()", 834*f585d8a3SJacky Wang " @Provides Object test.C.CModule.acConflict()"); 835*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 836*f585d8a3SJacky Wang subject.hasErrorCount(2); 837*f585d8a3SJacky Wang subject.hasErrorContaining("test.A.AModule has errors") 838*f585d8a3SJacky Wang .onSource(aComponent) 839*f585d8a3SJacky Wang .onLineContaining("@Component("); 840*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 841*f585d8a3SJacky Wang .onSource(aComponent) 842*f585d8a3SJacky Wang .onLineContaining("class AModule"); 843*f585d8a3SJacky Wang } else { 844*f585d8a3SJacky Wang subject.hasErrorCount(1); 845*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 846*f585d8a3SJacky Wang .onSource(aComponent) 847*f585d8a3SJacky Wang .onLineContaining("interface A {"); 848*f585d8a3SJacky Wang } 849*f585d8a3SJacky Wang }); 850*f585d8a3SJacky Wang } 851*f585d8a3SJacky Wang 852*f585d8a3SJacky Wang @Test grandchildBindingConflictsWithChild()853*f585d8a3SJacky Wang public void grandchildBindingConflictsWithChild() { 854*f585d8a3SJacky Wang Source aComponent = 855*f585d8a3SJacky Wang CompilerTests.javaSource( 856*f585d8a3SJacky Wang "test.A", 857*f585d8a3SJacky Wang "package test;", 858*f585d8a3SJacky Wang "", 859*f585d8a3SJacky Wang "import dagger.Component;", 860*f585d8a3SJacky Wang "", 861*f585d8a3SJacky Wang "@Component", 862*f585d8a3SJacky Wang "interface A {", 863*f585d8a3SJacky Wang " B b();", 864*f585d8a3SJacky Wang "}"); 865*f585d8a3SJacky Wang Source bComponent = 866*f585d8a3SJacky Wang CompilerTests.javaSource( 867*f585d8a3SJacky Wang "test.B", 868*f585d8a3SJacky Wang "package test;", 869*f585d8a3SJacky Wang "", 870*f585d8a3SJacky Wang "import dagger.Module;", 871*f585d8a3SJacky Wang "import dagger.Provides;", 872*f585d8a3SJacky Wang "import dagger.Subcomponent;", 873*f585d8a3SJacky Wang "", 874*f585d8a3SJacky Wang "@Subcomponent(modules = B.BModule.class)", 875*f585d8a3SJacky Wang "interface B {", 876*f585d8a3SJacky Wang " Object conflict();", 877*f585d8a3SJacky Wang "", 878*f585d8a3SJacky Wang " C.Builder c();", 879*f585d8a3SJacky Wang "", 880*f585d8a3SJacky Wang " @Module(subcomponents = C.class)", 881*f585d8a3SJacky Wang " static class BModule {", 882*f585d8a3SJacky Wang " @Provides static Object bcConflict() {", 883*f585d8a3SJacky Wang " return \"b\";", 884*f585d8a3SJacky Wang " }", 885*f585d8a3SJacky Wang " }", 886*f585d8a3SJacky Wang "}"); 887*f585d8a3SJacky Wang Source cComponent = 888*f585d8a3SJacky Wang CompilerTests.javaSource( 889*f585d8a3SJacky Wang "test.C", 890*f585d8a3SJacky Wang "package test;", 891*f585d8a3SJacky Wang "", 892*f585d8a3SJacky Wang "import dagger.Module;", 893*f585d8a3SJacky Wang "import dagger.Provides;", 894*f585d8a3SJacky Wang "import dagger.Subcomponent;", 895*f585d8a3SJacky Wang "", 896*f585d8a3SJacky Wang "@Subcomponent(modules = C.CModule.class)", 897*f585d8a3SJacky Wang "interface C {", 898*f585d8a3SJacky Wang " Object conflict();", 899*f585d8a3SJacky Wang "", 900*f585d8a3SJacky Wang " @Subcomponent.Builder", 901*f585d8a3SJacky Wang " interface Builder {", 902*f585d8a3SJacky Wang " C build();", 903*f585d8a3SJacky Wang " }", 904*f585d8a3SJacky Wang "", 905*f585d8a3SJacky Wang " @Module", 906*f585d8a3SJacky Wang " static class CModule {", 907*f585d8a3SJacky Wang " @Provides static Object bcConflict() {", 908*f585d8a3SJacky Wang " return \"c\";", 909*f585d8a3SJacky Wang " }", 910*f585d8a3SJacky Wang " }", 911*f585d8a3SJacky Wang "}"); 912*f585d8a3SJacky Wang 913*f585d8a3SJacky Wang CompilerTests.daggerCompiler(aComponent, bComponent, cComponent) 914*f585d8a3SJacky Wang .withProcessingOptions( 915*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 916*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 917*f585d8a3SJacky Wang .buildOrThrow()) 918*f585d8a3SJacky Wang .compile( 919*f585d8a3SJacky Wang subject -> { 920*f585d8a3SJacky Wang String errorMessage = 921*f585d8a3SJacky Wang message( 922*f585d8a3SJacky Wang "Object is bound multiple times:", 923*f585d8a3SJacky Wang " @Provides Object test.B.BModule.bcConflict()", 924*f585d8a3SJacky Wang " @Provides Object test.C.CModule.bcConflict()"); 925*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 926*f585d8a3SJacky Wang subject.hasErrorCount(2); 927*f585d8a3SJacky Wang subject.hasErrorContaining("test.B.BModule has errors") 928*f585d8a3SJacky Wang .onSource(bComponent) 929*f585d8a3SJacky Wang .onLineContaining("@Subcomponent(modules = B.BModule.class)"); 930*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 931*f585d8a3SJacky Wang .onSource(bComponent) 932*f585d8a3SJacky Wang .onLineContaining("class BModule"); 933*f585d8a3SJacky Wang } else { 934*f585d8a3SJacky Wang subject.hasErrorCount(1); 935*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 936*f585d8a3SJacky Wang .onSource(aComponent) 937*f585d8a3SJacky Wang .onLineContaining("interface A {"); 938*f585d8a3SJacky Wang } 939*f585d8a3SJacky Wang }); 940*f585d8a3SJacky Wang } 941*f585d8a3SJacky Wang 942*f585d8a3SJacky Wang @Test childProvidesConflictsWithParentInjects()943*f585d8a3SJacky Wang public void childProvidesConflictsWithParentInjects() { 944*f585d8a3SJacky Wang assumeFalse(fullBindingGraphValidation); 945*f585d8a3SJacky Wang 946*f585d8a3SJacky Wang Source foo = 947*f585d8a3SJacky Wang CompilerTests.javaSource( 948*f585d8a3SJacky Wang "test.Foo", 949*f585d8a3SJacky Wang "package test;", 950*f585d8a3SJacky Wang "", 951*f585d8a3SJacky Wang "import java.util.Set;", 952*f585d8a3SJacky Wang "import javax.inject.Inject;", 953*f585d8a3SJacky Wang "", 954*f585d8a3SJacky Wang "final class Foo {", 955*f585d8a3SJacky Wang " @Inject Foo(Set<String> strings) {}", 956*f585d8a3SJacky Wang "}"); 957*f585d8a3SJacky Wang Source injected1 = 958*f585d8a3SJacky Wang CompilerTests.javaSource( 959*f585d8a3SJacky Wang "test.Injected1", 960*f585d8a3SJacky Wang "package test;", 961*f585d8a3SJacky Wang "", 962*f585d8a3SJacky Wang "import dagger.Component;", 963*f585d8a3SJacky Wang "import dagger.Module;", 964*f585d8a3SJacky Wang "import dagger.Provides;", 965*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 966*f585d8a3SJacky Wang "import java.util.Set;", 967*f585d8a3SJacky Wang "", 968*f585d8a3SJacky Wang "@Component(modules = Injected1.Injected1Module.class)", 969*f585d8a3SJacky Wang "interface Injected1 {", 970*f585d8a3SJacky Wang " Foo foo();", 971*f585d8a3SJacky Wang " Injected2 injected2();", 972*f585d8a3SJacky Wang "", 973*f585d8a3SJacky Wang " @Module", 974*f585d8a3SJacky Wang " interface Injected1Module {", 975*f585d8a3SJacky Wang " @Provides @IntoSet static String string() {", 976*f585d8a3SJacky Wang " return \"injected1\";", 977*f585d8a3SJacky Wang " }", 978*f585d8a3SJacky Wang " }", 979*f585d8a3SJacky Wang "}"); 980*f585d8a3SJacky Wang Source injected2 = 981*f585d8a3SJacky Wang CompilerTests.javaSource( 982*f585d8a3SJacky Wang "test.Injected2", 983*f585d8a3SJacky Wang "package test;", 984*f585d8a3SJacky Wang "", 985*f585d8a3SJacky Wang "import dagger.Module;", 986*f585d8a3SJacky Wang "import dagger.Provides;", 987*f585d8a3SJacky Wang "import dagger.Subcomponent;", 988*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 989*f585d8a3SJacky Wang "import java.util.Set;", 990*f585d8a3SJacky Wang "", 991*f585d8a3SJacky Wang "@Subcomponent(modules = Injected2.Injected2Module.class)", 992*f585d8a3SJacky Wang "interface Injected2 {", 993*f585d8a3SJacky Wang " Foo foo();", 994*f585d8a3SJacky Wang " Provided1 provided1();", 995*f585d8a3SJacky Wang "", 996*f585d8a3SJacky Wang " @Module", 997*f585d8a3SJacky Wang " interface Injected2Module {", 998*f585d8a3SJacky Wang " @Provides @IntoSet static String string() {", 999*f585d8a3SJacky Wang " return \"injected2\";", 1000*f585d8a3SJacky Wang " }", 1001*f585d8a3SJacky Wang " }", 1002*f585d8a3SJacky Wang "}"); 1003*f585d8a3SJacky Wang Source provided1 = 1004*f585d8a3SJacky Wang CompilerTests.javaSource( 1005*f585d8a3SJacky Wang "test.Provided1", 1006*f585d8a3SJacky Wang "package test;", 1007*f585d8a3SJacky Wang "", 1008*f585d8a3SJacky Wang "import dagger.Module;", 1009*f585d8a3SJacky Wang "import dagger.Provides;", 1010*f585d8a3SJacky Wang "import dagger.Subcomponent;", 1011*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 1012*f585d8a3SJacky Wang "import java.util.Set;", 1013*f585d8a3SJacky Wang "", 1014*f585d8a3SJacky Wang "@Subcomponent(modules = Provided1.Provided1Module.class)", 1015*f585d8a3SJacky Wang "interface Provided1 {", 1016*f585d8a3SJacky Wang " Foo foo();", 1017*f585d8a3SJacky Wang " Provided2 provided2();", 1018*f585d8a3SJacky Wang "", 1019*f585d8a3SJacky Wang " @Module", 1020*f585d8a3SJacky Wang " static class Provided1Module {", 1021*f585d8a3SJacky Wang " @Provides static Foo provideFoo(Set<String> strings) {", 1022*f585d8a3SJacky Wang " return new Foo(strings);", 1023*f585d8a3SJacky Wang " }", 1024*f585d8a3SJacky Wang "", 1025*f585d8a3SJacky Wang " @Provides @IntoSet static String string() {", 1026*f585d8a3SJacky Wang " return \"provided1\";", 1027*f585d8a3SJacky Wang " }", 1028*f585d8a3SJacky Wang " }", 1029*f585d8a3SJacky Wang "}"); 1030*f585d8a3SJacky Wang Source provided2 = 1031*f585d8a3SJacky Wang CompilerTests.javaSource( 1032*f585d8a3SJacky Wang "test.Provided2", 1033*f585d8a3SJacky Wang "package test;", 1034*f585d8a3SJacky Wang "", 1035*f585d8a3SJacky Wang "import dagger.Module;", 1036*f585d8a3SJacky Wang "import dagger.Provides;", 1037*f585d8a3SJacky Wang "import dagger.Subcomponent;", 1038*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 1039*f585d8a3SJacky Wang "", 1040*f585d8a3SJacky Wang "@Subcomponent(modules = Provided2.Provided2Module.class)", 1041*f585d8a3SJacky Wang "interface Provided2 {", 1042*f585d8a3SJacky Wang " Foo foo();", 1043*f585d8a3SJacky Wang "", 1044*f585d8a3SJacky Wang " @Module", 1045*f585d8a3SJacky Wang " static class Provided2Module {", 1046*f585d8a3SJacky Wang " @Provides @IntoSet static String string() {", 1047*f585d8a3SJacky Wang " return \"provided2\";", 1048*f585d8a3SJacky Wang " }", 1049*f585d8a3SJacky Wang " }", 1050*f585d8a3SJacky Wang "}"); 1051*f585d8a3SJacky Wang 1052*f585d8a3SJacky Wang CompilerTests.daggerCompiler(foo, injected1, injected2, provided1, provided2) 1053*f585d8a3SJacky Wang .compile( 1054*f585d8a3SJacky Wang subject -> { 1055*f585d8a3SJacky Wang subject.hasErrorCount(1); 1056*f585d8a3SJacky Wang subject.hasErrorContaining( 1057*f585d8a3SJacky Wang message( 1058*f585d8a3SJacky Wang "Foo is bound multiple times:", 1059*f585d8a3SJacky Wang " @Inject Foo(Set<String>) [Injected1]", 1060*f585d8a3SJacky Wang " @Provides Foo Provided1.Provided1Module.provideFoo(Set<String>) " 1061*f585d8a3SJacky Wang + "[Injected1 → Injected2 → Provided1]")) 1062*f585d8a3SJacky Wang .onSource(injected1) 1063*f585d8a3SJacky Wang .onLineContaining("interface Injected1 {"); 1064*f585d8a3SJacky Wang }); 1065*f585d8a3SJacky Wang } 1066*f585d8a3SJacky Wang 1067*f585d8a3SJacky Wang @Test grandchildBindingConflictsWithParentWithNullableViolationAsWarning()1068*f585d8a3SJacky Wang public void grandchildBindingConflictsWithParentWithNullableViolationAsWarning() { 1069*f585d8a3SJacky Wang Source parentConflictsWithChild = 1070*f585d8a3SJacky Wang CompilerTests.javaSource( 1071*f585d8a3SJacky Wang "test.ParentConflictsWithChild", 1072*f585d8a3SJacky Wang "package test;", 1073*f585d8a3SJacky Wang "", 1074*f585d8a3SJacky Wang "import dagger.Component;", 1075*f585d8a3SJacky Wang "import dagger.Module;", 1076*f585d8a3SJacky Wang "import dagger.Provides;", 1077*f585d8a3SJacky Wang "import javax.annotation.Nullable;", 1078*f585d8a3SJacky Wang "", 1079*f585d8a3SJacky Wang "@Component(modules = ParentConflictsWithChild.ParentModule.class)", 1080*f585d8a3SJacky Wang "interface ParentConflictsWithChild {", 1081*f585d8a3SJacky Wang " Child.Builder child();", 1082*f585d8a3SJacky Wang "", 1083*f585d8a3SJacky Wang " @Module(subcomponents = Child.class)", 1084*f585d8a3SJacky Wang " static class ParentModule {", 1085*f585d8a3SJacky Wang " @Provides @Nullable static Object nullableParentChildConflict() {", 1086*f585d8a3SJacky Wang " return \"parent\";", 1087*f585d8a3SJacky Wang " }", 1088*f585d8a3SJacky Wang " }", 1089*f585d8a3SJacky Wang "}"); 1090*f585d8a3SJacky Wang Source child = 1091*f585d8a3SJacky Wang CompilerTests.javaSource( 1092*f585d8a3SJacky Wang "test.Child", 1093*f585d8a3SJacky Wang "package test;", 1094*f585d8a3SJacky Wang "", 1095*f585d8a3SJacky Wang "import dagger.Module;", 1096*f585d8a3SJacky Wang "import dagger.Provides;", 1097*f585d8a3SJacky Wang "import dagger.Subcomponent;", 1098*f585d8a3SJacky Wang "", 1099*f585d8a3SJacky Wang "@Subcomponent(modules = Child.ChildModule.class)", 1100*f585d8a3SJacky Wang "interface Child {", 1101*f585d8a3SJacky Wang " Object parentChildConflictThatViolatesNullability();", 1102*f585d8a3SJacky Wang "", 1103*f585d8a3SJacky Wang " @Subcomponent.Builder", 1104*f585d8a3SJacky Wang " interface Builder {", 1105*f585d8a3SJacky Wang " Child build();", 1106*f585d8a3SJacky Wang " }", 1107*f585d8a3SJacky Wang "", 1108*f585d8a3SJacky Wang " @Module", 1109*f585d8a3SJacky Wang " static class ChildModule {", 1110*f585d8a3SJacky Wang " @Provides static Object nonNullableParentChildConflict() {", 1111*f585d8a3SJacky Wang " return \"child\";", 1112*f585d8a3SJacky Wang " }", 1113*f585d8a3SJacky Wang " }", 1114*f585d8a3SJacky Wang "}"); 1115*f585d8a3SJacky Wang 1116*f585d8a3SJacky Wang CompilerTests.daggerCompiler(parentConflictsWithChild, child) 1117*f585d8a3SJacky Wang .withProcessingOptions( 1118*f585d8a3SJacky Wang ImmutableMap.<String, String>builder() 1119*f585d8a3SJacky Wang .put("dagger.nullableValidation", "WARNING") 1120*f585d8a3SJacky Wang .putAll(fullBindingGraphValidationOption()) 1121*f585d8a3SJacky Wang .buildOrThrow()) 1122*f585d8a3SJacky Wang .compile( 1123*f585d8a3SJacky Wang subject -> { 1124*f585d8a3SJacky Wang String errorMessage = 1125*f585d8a3SJacky Wang message( 1126*f585d8a3SJacky Wang "Object is bound multiple times:", 1127*f585d8a3SJacky Wang " @Provides Object Child.ChildModule.nonNullableParentChildConflict()", 1128*f585d8a3SJacky Wang " @Provides @Nullable Object" 1129*f585d8a3SJacky Wang + " ParentConflictsWithChild.ParentModule.nullableParentChildConflict()"); 1130*f585d8a3SJacky Wang if (fullBindingGraphValidation) { 1131*f585d8a3SJacky Wang subject.hasErrorCount(2); 1132*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 1133*f585d8a3SJacky Wang .onSource(parentConflictsWithChild) 1134*f585d8a3SJacky Wang .onLineContaining("class ParentModule"); 1135*f585d8a3SJacky Wang subject.hasErrorContaining( 1136*f585d8a3SJacky Wang "Object is not nullable, but is being provided by @Provides @Nullable " 1137*f585d8a3SJacky Wang + "Object") 1138*f585d8a3SJacky Wang .onSource(parentConflictsWithChild) 1139*f585d8a3SJacky Wang .onLineContaining("class ParentModule"); 1140*f585d8a3SJacky Wang } else { 1141*f585d8a3SJacky Wang subject.hasErrorCount(1); 1142*f585d8a3SJacky Wang subject.hasErrorContaining(errorMessage) 1143*f585d8a3SJacky Wang .onSource(parentConflictsWithChild) 1144*f585d8a3SJacky Wang .onLineContaining("interface ParentConflictsWithChild"); 1145*f585d8a3SJacky Wang } 1146*f585d8a3SJacky Wang }); 1147*f585d8a3SJacky Wang } 1148*f585d8a3SJacky Wang fullBindingGraphValidationOption()1149*f585d8a3SJacky Wang private ImmutableMap<String, String> fullBindingGraphValidationOption() { 1150*f585d8a3SJacky Wang return ImmutableMap.of( 1151*f585d8a3SJacky Wang "dagger.fullBindingGraphValidation", 1152*f585d8a3SJacky Wang fullBindingGraphValidation ? "ERROR" : "NONE"); 1153*f585d8a3SJacky Wang } 1154*f585d8a3SJacky Wang 1155*f585d8a3SJacky Wang @Test reportedInParentAndChild()1156*f585d8a3SJacky Wang public void reportedInParentAndChild() { 1157*f585d8a3SJacky Wang Source parent = 1158*f585d8a3SJacky Wang CompilerTests.javaSource( 1159*f585d8a3SJacky Wang "test.Parent", 1160*f585d8a3SJacky Wang "package test;", 1161*f585d8a3SJacky Wang "", 1162*f585d8a3SJacky Wang "import dagger.Component;", 1163*f585d8a3SJacky Wang "", 1164*f585d8a3SJacky Wang "@Component(modules = ParentModule.class)", 1165*f585d8a3SJacky Wang "interface Parent {", 1166*f585d8a3SJacky Wang " Child.Builder childBuilder();", 1167*f585d8a3SJacky Wang " String duplicated();", 1168*f585d8a3SJacky Wang "}"); 1169*f585d8a3SJacky Wang Source parentModule = 1170*f585d8a3SJacky Wang CompilerTests.javaSource( 1171*f585d8a3SJacky Wang "test.ParentModule", 1172*f585d8a3SJacky Wang "package test;", 1173*f585d8a3SJacky Wang "", 1174*f585d8a3SJacky Wang "import dagger.BindsOptionalOf;", 1175*f585d8a3SJacky Wang "import dagger.Module;", 1176*f585d8a3SJacky Wang "import dagger.Provides;", 1177*f585d8a3SJacky Wang "import java.util.Optional;", 1178*f585d8a3SJacky Wang "", 1179*f585d8a3SJacky Wang "@Module", 1180*f585d8a3SJacky Wang "interface ParentModule {", 1181*f585d8a3SJacky Wang " @Provides static String one(Optional<Object> optional) { return \"one\"; }", 1182*f585d8a3SJacky Wang " @Provides static String two() { return \"two\"; }", 1183*f585d8a3SJacky Wang " @BindsOptionalOf Object optional();", 1184*f585d8a3SJacky Wang "}"); 1185*f585d8a3SJacky Wang Source child = 1186*f585d8a3SJacky Wang CompilerTests.javaSource( 1187*f585d8a3SJacky Wang "test.Child", 1188*f585d8a3SJacky Wang "package test;", 1189*f585d8a3SJacky Wang "", 1190*f585d8a3SJacky Wang "import dagger.Subcomponent;", 1191*f585d8a3SJacky Wang "", 1192*f585d8a3SJacky Wang "@Subcomponent(modules = ChildModule.class)", 1193*f585d8a3SJacky Wang "interface Child {", 1194*f585d8a3SJacky Wang " String duplicated();", 1195*f585d8a3SJacky Wang "", 1196*f585d8a3SJacky Wang " @Subcomponent.Builder", 1197*f585d8a3SJacky Wang " interface Builder {", 1198*f585d8a3SJacky Wang " Child build();", 1199*f585d8a3SJacky Wang " }", 1200*f585d8a3SJacky Wang "}"); 1201*f585d8a3SJacky Wang Source childModule = 1202*f585d8a3SJacky Wang CompilerTests.javaSource( 1203*f585d8a3SJacky Wang "test.ChildModule", 1204*f585d8a3SJacky Wang "package test;", 1205*f585d8a3SJacky Wang "", 1206*f585d8a3SJacky Wang "import dagger.Module;", 1207*f585d8a3SJacky Wang "import dagger.Provides;", 1208*f585d8a3SJacky Wang "import java.util.Optional;", 1209*f585d8a3SJacky Wang "", 1210*f585d8a3SJacky Wang "@Module", 1211*f585d8a3SJacky Wang "interface ChildModule {", 1212*f585d8a3SJacky Wang " @Provides static Object object() { return \"object\"; }", 1213*f585d8a3SJacky Wang "}"); 1214*f585d8a3SJacky Wang CompilerTests.daggerCompiler(parent, parentModule, child, childModule) 1215*f585d8a3SJacky Wang .compile( 1216*f585d8a3SJacky Wang subject -> { 1217*f585d8a3SJacky Wang subject.hasErrorCount(1); 1218*f585d8a3SJacky Wang subject.hasErrorContaining("String is bound multiple times") 1219*f585d8a3SJacky Wang .onSource(parent) 1220*f585d8a3SJacky Wang .onLineContaining("interface Parent"); 1221*f585d8a3SJacky Wang }); 1222*f585d8a3SJacky Wang } 1223*f585d8a3SJacky Wang 1224*f585d8a3SJacky Wang // Tests the format of the error for a somewhat complex binding method. 1225*f585d8a3SJacky Wang @Test formatTest()1226*f585d8a3SJacky Wang public void formatTest() { 1227*f585d8a3SJacky Wang Source modules = 1228*f585d8a3SJacky Wang CompilerTests.javaSource( 1229*f585d8a3SJacky Wang "test.Modules", 1230*f585d8a3SJacky Wang "package test;", 1231*f585d8a3SJacky Wang "", 1232*f585d8a3SJacky Wang "import com.google.common.collect.ImmutableList;", 1233*f585d8a3SJacky Wang "import dagger.Module;", 1234*f585d8a3SJacky Wang "import dagger.Provides;", 1235*f585d8a3SJacky Wang "import javax.inject.Singleton;", 1236*f585d8a3SJacky Wang "", 1237*f585d8a3SJacky Wang "interface Modules {", 1238*f585d8a3SJacky Wang " @interface Foo {", 1239*f585d8a3SJacky Wang " Class<?> bar();", 1240*f585d8a3SJacky Wang " }", 1241*f585d8a3SJacky Wang "", 1242*f585d8a3SJacky Wang " @Module", 1243*f585d8a3SJacky Wang " interface Module1 {", 1244*f585d8a3SJacky Wang " @Provides", 1245*f585d8a3SJacky Wang " @Singleton", 1246*f585d8a3SJacky Wang " @Foo(bar = String.class)", 1247*f585d8a3SJacky Wang " static String foo(", 1248*f585d8a3SJacky Wang " @SuppressWarnings(\"unused\") int a,", 1249*f585d8a3SJacky Wang " @SuppressWarnings(\"unused\") ImmutableList<Boolean> blah) {", 1250*f585d8a3SJacky Wang " return \"\";", 1251*f585d8a3SJacky Wang " }", 1252*f585d8a3SJacky Wang " }", 1253*f585d8a3SJacky Wang "", 1254*f585d8a3SJacky Wang " @Module", 1255*f585d8a3SJacky Wang " interface Module2 {", 1256*f585d8a3SJacky Wang " @Provides", 1257*f585d8a3SJacky Wang " @Singleton", 1258*f585d8a3SJacky Wang " @Foo(bar = String.class)", 1259*f585d8a3SJacky Wang " static String foo(", 1260*f585d8a3SJacky Wang " @SuppressWarnings(\"unused\") int a,", 1261*f585d8a3SJacky Wang " @SuppressWarnings(\"unused\") ImmutableList<Boolean> blah) {", 1262*f585d8a3SJacky Wang " return \"\";", 1263*f585d8a3SJacky Wang " }", 1264*f585d8a3SJacky Wang " }", 1265*f585d8a3SJacky Wang "}"); 1266*f585d8a3SJacky Wang Source component = 1267*f585d8a3SJacky Wang CompilerTests.javaSource( 1268*f585d8a3SJacky Wang "test.TestComponent", 1269*f585d8a3SJacky Wang "package test;", 1270*f585d8a3SJacky Wang "", 1271*f585d8a3SJacky Wang "import dagger.BindsInstance;", 1272*f585d8a3SJacky Wang "import dagger.Component;", 1273*f585d8a3SJacky Wang "import javax.inject.Singleton;", 1274*f585d8a3SJacky Wang "", 1275*f585d8a3SJacky Wang "@Singleton", 1276*f585d8a3SJacky Wang "@Component(modules = {Modules.Module1.class, Modules.Module2.class})", 1277*f585d8a3SJacky Wang "interface TestComponent {", 1278*f585d8a3SJacky Wang " @Modules.Foo(bar = String.class) String foo();", 1279*f585d8a3SJacky Wang "}"); 1280*f585d8a3SJacky Wang CompilerTests.daggerCompiler(modules, component) 1281*f585d8a3SJacky Wang .compile( 1282*f585d8a3SJacky Wang subject -> { 1283*f585d8a3SJacky Wang subject.hasErrorCount(1); 1284*f585d8a3SJacky Wang subject.hasErrorContaining( 1285*f585d8a3SJacky Wang String.format( 1286*f585d8a3SJacky Wang String.join( 1287*f585d8a3SJacky Wang "\n", 1288*f585d8a3SJacky Wang "String is bound multiple times:", 1289*f585d8a3SJacky Wang " @Provides @Singleton @Modules.Foo(%1$s) String " 1290*f585d8a3SJacky Wang + "Modules.Module1.foo(int, ImmutableList<Boolean>)", 1291*f585d8a3SJacky Wang " @Provides @Singleton @Modules.Foo(%1$s) String " 1292*f585d8a3SJacky Wang + "Modules.Module2.foo(int, ImmutableList<Boolean>)"), 1293*f585d8a3SJacky Wang // TODO(b/241293838): KSP and java should match after this is fixed. 1294*f585d8a3SJacky Wang CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP 1295*f585d8a3SJacky Wang ? "bar=String" 1296*f585d8a3SJacky Wang : "bar = String.class")); 1297*f585d8a3SJacky Wang }); 1298*f585d8a3SJacky Wang } 1299*f585d8a3SJacky Wang } 1300