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.util.Source; 20*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList; 21*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests; 22*f585d8a3SJacky Wang import org.junit.Test; 23*f585d8a3SJacky Wang import org.junit.runner.RunWith; 24*f585d8a3SJacky Wang import org.junit.runners.Parameterized; 25*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters; 26*f585d8a3SJacky Wang 27*f585d8a3SJacky Wang /** 28*f585d8a3SJacky Wang * Tests that errors are reported correctly when a {@code @Binds} method's delegate (the type of its 29*f585d8a3SJacky Wang * parameter) is missing. 30*f585d8a3SJacky Wang */ 31*f585d8a3SJacky Wang @RunWith(Parameterized.class) 32*f585d8a3SJacky Wang public class BindsMissingDelegateValidationTest { 33*f585d8a3SJacky Wang @Parameters(name = "{0}") parameters()34*f585d8a3SJacky Wang public static ImmutableList<Object[]> parameters() { 35*f585d8a3SJacky Wang return CompilerMode.TEST_PARAMETERS; 36*f585d8a3SJacky Wang } 37*f585d8a3SJacky Wang 38*f585d8a3SJacky Wang private final CompilerMode compilerMode; 39*f585d8a3SJacky Wang BindsMissingDelegateValidationTest(CompilerMode compilerMode)40*f585d8a3SJacky Wang public BindsMissingDelegateValidationTest(CompilerMode compilerMode) { 41*f585d8a3SJacky Wang this.compilerMode = compilerMode; 42*f585d8a3SJacky Wang } 43*f585d8a3SJacky Wang 44*f585d8a3SJacky Wang @Test bindsMissingDelegate()45*f585d8a3SJacky Wang public void bindsMissingDelegate() { 46*f585d8a3SJacky Wang Source component = 47*f585d8a3SJacky Wang CompilerTests.javaSource( 48*f585d8a3SJacky Wang "test.C", 49*f585d8a3SJacky Wang "package test;", 50*f585d8a3SJacky Wang "", 51*f585d8a3SJacky Wang "import dagger.Binds;", 52*f585d8a3SJacky Wang "import dagger.Component;", 53*f585d8a3SJacky Wang "import dagger.Module;", 54*f585d8a3SJacky Wang "", 55*f585d8a3SJacky Wang "@Component(modules = C.TestModule.class)", 56*f585d8a3SJacky Wang "interface C {", 57*f585d8a3SJacky Wang " Object object();", 58*f585d8a3SJacky Wang "", 59*f585d8a3SJacky Wang " static class NotBound {}", 60*f585d8a3SJacky Wang "", 61*f585d8a3SJacky Wang " @Module", 62*f585d8a3SJacky Wang " abstract static class TestModule {", 63*f585d8a3SJacky Wang " @Binds abstract Object bindObject(NotBound notBound);", 64*f585d8a3SJacky Wang " }", 65*f585d8a3SJacky Wang "}"); 66*f585d8a3SJacky Wang 67*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 68*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 69*f585d8a3SJacky Wang .compile( 70*f585d8a3SJacky Wang subject -> { 71*f585d8a3SJacky Wang subject.hasErrorCount(1); 72*f585d8a3SJacky Wang subject.hasErrorContaining("test.C.NotBound cannot be provided") 73*f585d8a3SJacky Wang .onSource(component) 74*f585d8a3SJacky Wang .onLineContaining("interface C"); 75*f585d8a3SJacky Wang }); 76*f585d8a3SJacky Wang } 77*f585d8a3SJacky Wang 78*f585d8a3SJacky Wang @Test bindsMissingDelegate_duplicateBinding()79*f585d8a3SJacky Wang public void bindsMissingDelegate_duplicateBinding() { 80*f585d8a3SJacky Wang Source component = 81*f585d8a3SJacky Wang CompilerTests.javaSource( 82*f585d8a3SJacky Wang "test.C", 83*f585d8a3SJacky Wang "package test;", 84*f585d8a3SJacky Wang "", 85*f585d8a3SJacky Wang "import dagger.Binds;", 86*f585d8a3SJacky Wang "import dagger.Component;", 87*f585d8a3SJacky Wang "import dagger.Module;", 88*f585d8a3SJacky Wang "import dagger.Provides;", 89*f585d8a3SJacky Wang "", 90*f585d8a3SJacky Wang "@Component(modules = C.TestModule.class)", 91*f585d8a3SJacky Wang "interface C {", 92*f585d8a3SJacky Wang " Object object();", 93*f585d8a3SJacky Wang "", 94*f585d8a3SJacky Wang " static class NotBound {}", 95*f585d8a3SJacky Wang "", 96*f585d8a3SJacky Wang " @Module", 97*f585d8a3SJacky Wang " abstract static class TestModule {", 98*f585d8a3SJacky Wang " @Binds abstract Object bindObject(NotBound notBound);", 99*f585d8a3SJacky Wang " @Provides static Object provideObject() { return new Object(); }", 100*f585d8a3SJacky Wang " }", 101*f585d8a3SJacky Wang "}"); 102*f585d8a3SJacky Wang 103*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 104*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 105*f585d8a3SJacky Wang .compile( 106*f585d8a3SJacky Wang subject -> { 107*f585d8a3SJacky Wang subject.hasErrorCount(1); 108*f585d8a3SJacky Wang // Some versions of javacs report only the first error for each source line so we 109*f585d8a3SJacky Wang // allow 1 of the assertions below to fail. 110*f585d8a3SJacky Wang // TODO(bcorso): Add CompilationResultSubject#hasErrorContainingMatch() to do this 111*f585d8a3SJacky Wang // more elegantly (see CL/469765892). 112*f585d8a3SJacky Wang java.util.List<Error> errors = new java.util.ArrayList<>(); 113*f585d8a3SJacky Wang try { 114*f585d8a3SJacky Wang subject.hasErrorContaining("test.C.NotBound cannot be provided") 115*f585d8a3SJacky Wang .onSource(component) 116*f585d8a3SJacky Wang .onLineContaining("interface C"); 117*f585d8a3SJacky Wang } catch (Error e) { 118*f585d8a3SJacky Wang errors.add(e); 119*f585d8a3SJacky Wang } 120*f585d8a3SJacky Wang try { 121*f585d8a3SJacky Wang subject.hasErrorContaining("Object is bound multiple times:") 122*f585d8a3SJacky Wang .onSource(component) 123*f585d8a3SJacky Wang .onLineContaining("interface C"); 124*f585d8a3SJacky Wang subject.hasErrorContaining( 125*f585d8a3SJacky Wang "@Binds Object test.C.TestModule.bindObject(test.C.NotBound)"); 126*f585d8a3SJacky Wang subject.hasErrorContaining("@Provides Object test.C.TestModule.provideObject()"); 127*f585d8a3SJacky Wang } catch (Error e) { 128*f585d8a3SJacky Wang errors.add(e); 129*f585d8a3SJacky Wang } 130*f585d8a3SJacky Wang com.google.common.truth.Truth.assertThat(errors.size()).isAtMost(1); 131*f585d8a3SJacky Wang }); 132*f585d8a3SJacky Wang } 133*f585d8a3SJacky Wang 134*f585d8a3SJacky Wang @Test bindsMissingDelegate_setBinding()135*f585d8a3SJacky Wang public void bindsMissingDelegate_setBinding() { 136*f585d8a3SJacky Wang Source component = 137*f585d8a3SJacky Wang CompilerTests.javaSource( 138*f585d8a3SJacky Wang "test.C", 139*f585d8a3SJacky Wang "package test;", 140*f585d8a3SJacky Wang "", 141*f585d8a3SJacky Wang "import dagger.Binds;", 142*f585d8a3SJacky Wang "import dagger.Component;", 143*f585d8a3SJacky Wang "import dagger.Module;", 144*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 145*f585d8a3SJacky Wang "import java.util.Set;", 146*f585d8a3SJacky Wang "", 147*f585d8a3SJacky Wang "@Component(modules = C.TestModule.class)", 148*f585d8a3SJacky Wang "interface C {", 149*f585d8a3SJacky Wang " Set<Object> objects();", 150*f585d8a3SJacky Wang "", 151*f585d8a3SJacky Wang " static class NotBound {}", 152*f585d8a3SJacky Wang "", 153*f585d8a3SJacky Wang " @Module", 154*f585d8a3SJacky Wang " abstract static class TestModule {", 155*f585d8a3SJacky Wang " @Binds @IntoSet abstract Object bindObject(NotBound notBound);", 156*f585d8a3SJacky Wang " }", 157*f585d8a3SJacky Wang "}"); 158*f585d8a3SJacky Wang 159*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 160*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 161*f585d8a3SJacky Wang .compile( 162*f585d8a3SJacky Wang subject -> { 163*f585d8a3SJacky Wang subject.hasErrorCount(1); 164*f585d8a3SJacky Wang subject.hasErrorContaining("test.C.NotBound cannot be provided") 165*f585d8a3SJacky Wang .onSource(component) 166*f585d8a3SJacky Wang .onLineContaining("interface C"); 167*f585d8a3SJacky Wang }); 168*f585d8a3SJacky Wang } 169*f585d8a3SJacky Wang 170*f585d8a3SJacky Wang @Test bindsMissingDelegate_mapBinding()171*f585d8a3SJacky Wang public void bindsMissingDelegate_mapBinding() { 172*f585d8a3SJacky Wang Source component = 173*f585d8a3SJacky Wang CompilerTests.javaSource( 174*f585d8a3SJacky Wang "test.C", 175*f585d8a3SJacky Wang "package test;", 176*f585d8a3SJacky Wang "", 177*f585d8a3SJacky Wang "import dagger.Binds;", 178*f585d8a3SJacky Wang "import dagger.Component;", 179*f585d8a3SJacky Wang "import dagger.Module;", 180*f585d8a3SJacky Wang "import dagger.multibindings.IntoMap;", 181*f585d8a3SJacky Wang "import dagger.multibindings.StringKey;", 182*f585d8a3SJacky Wang "import java.util.Map;", 183*f585d8a3SJacky Wang "", 184*f585d8a3SJacky Wang "@Component(modules = C.TestModule.class)", 185*f585d8a3SJacky Wang "interface C {", 186*f585d8a3SJacky Wang " Map<String, Object> objects();", 187*f585d8a3SJacky Wang "", 188*f585d8a3SJacky Wang " static class NotBound {}", 189*f585d8a3SJacky Wang "", 190*f585d8a3SJacky Wang " @Module", 191*f585d8a3SJacky Wang " abstract static class TestModule {", 192*f585d8a3SJacky Wang " @Binds @IntoMap @StringKey(\"key\")", 193*f585d8a3SJacky Wang " abstract Object bindObject(NotBound notBound);", 194*f585d8a3SJacky Wang " }", 195*f585d8a3SJacky Wang "}"); 196*f585d8a3SJacky Wang 197*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 198*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 199*f585d8a3SJacky Wang .compile( 200*f585d8a3SJacky Wang subject -> { 201*f585d8a3SJacky Wang subject.hasErrorCount(1); 202*f585d8a3SJacky Wang subject.hasErrorContaining("test.C.NotBound cannot be provided") 203*f585d8a3SJacky Wang .onSource(component) 204*f585d8a3SJacky Wang .onLineContaining("interface C"); 205*f585d8a3SJacky Wang }); 206*f585d8a3SJacky Wang } 207*f585d8a3SJacky Wang 208*f585d8a3SJacky Wang @Test bindsMissingDelegate_mapBinding_sameKey()209*f585d8a3SJacky Wang public void bindsMissingDelegate_mapBinding_sameKey() { 210*f585d8a3SJacky Wang Source component = 211*f585d8a3SJacky Wang CompilerTests.javaSource( 212*f585d8a3SJacky Wang "test.C", 213*f585d8a3SJacky Wang "package test;", 214*f585d8a3SJacky Wang "", 215*f585d8a3SJacky Wang "import dagger.Binds;", 216*f585d8a3SJacky Wang "import dagger.Component;", 217*f585d8a3SJacky Wang "import dagger.Module;", 218*f585d8a3SJacky Wang "import dagger.Provides;", 219*f585d8a3SJacky Wang "import dagger.multibindings.IntoMap;", 220*f585d8a3SJacky Wang "import dagger.multibindings.StringKey;", 221*f585d8a3SJacky Wang "import java.util.Map;", 222*f585d8a3SJacky Wang "", 223*f585d8a3SJacky Wang "@Component(modules = C.TestModule.class)", 224*f585d8a3SJacky Wang "interface C {", 225*f585d8a3SJacky Wang " Map<String, Object> objects();", 226*f585d8a3SJacky Wang "", 227*f585d8a3SJacky Wang " static class NotBound {}", 228*f585d8a3SJacky Wang "", 229*f585d8a3SJacky Wang " @Module", 230*f585d8a3SJacky Wang " abstract static class TestModule {", 231*f585d8a3SJacky Wang " @Binds @IntoMap @StringKey(\"key\")", 232*f585d8a3SJacky Wang " abstract Object bindObject(NotBound notBound);", 233*f585d8a3SJacky Wang "", 234*f585d8a3SJacky Wang " @Provides @IntoMap @StringKey(\"key\")", 235*f585d8a3SJacky Wang " static Object provideObject() { return new Object(); }", 236*f585d8a3SJacky Wang " }", 237*f585d8a3SJacky Wang "}"); 238*f585d8a3SJacky Wang 239*f585d8a3SJacky Wang 240*f585d8a3SJacky Wang CompilerTests.daggerCompiler(component) 241*f585d8a3SJacky Wang .withProcessingOptions(compilerMode.processorOptions()) 242*f585d8a3SJacky Wang .compile( 243*f585d8a3SJacky Wang subject -> { 244*f585d8a3SJacky Wang subject.hasErrorCount(1); 245*f585d8a3SJacky Wang // Some versions of javacs report only the first error for each source line so we 246*f585d8a3SJacky Wang // allow 1 of the assertions below to fail. 247*f585d8a3SJacky Wang // TODO(bcorso): Add CompilationResultSubject#hasErrorContainingMatch() to do this 248*f585d8a3SJacky Wang // more elegantly (see CL/469765892). 249*f585d8a3SJacky Wang java.util.List<Error> errors = new java.util.ArrayList<>(); 250*f585d8a3SJacky Wang try { 251*f585d8a3SJacky Wang subject.hasErrorContaining("test.C.NotBound cannot be provided") 252*f585d8a3SJacky Wang .onSource(component) 253*f585d8a3SJacky Wang .onLineContaining("interface C"); 254*f585d8a3SJacky Wang } catch (Error e) { 255*f585d8a3SJacky Wang errors.add(e); 256*f585d8a3SJacky Wang } 257*f585d8a3SJacky Wang try { 258*f585d8a3SJacky Wang subject.hasErrorContaining("same map key is bound more than once") 259*f585d8a3SJacky Wang .onSource(component) 260*f585d8a3SJacky Wang .onLineContaining("interface C"); 261*f585d8a3SJacky Wang } catch (Error e) { 262*f585d8a3SJacky Wang errors.add(e); 263*f585d8a3SJacky Wang } 264*f585d8a3SJacky Wang com.google.common.truth.Truth.assertThat(errors.size()).isAtMost(1); 265*f585d8a3SJacky Wang }); 266*f585d8a3SJacky Wang } 267*f585d8a3SJacky Wang } 268