1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2016 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.internal.codegen; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source; 20*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests; 21*f585d8a3SJacky Wang import org.junit.Test; 22*f585d8a3SJacky Wang import org.junit.runner.RunWith; 23*f585d8a3SJacky Wang import org.junit.runners.JUnit4; 24*f585d8a3SJacky Wang 25*f585d8a3SJacky Wang @RunWith(JUnit4.class) 26*f585d8a3SJacky Wang public class MultibindingTest { 27*f585d8a3SJacky Wang 28*f585d8a3SJacky Wang @Test providesWithTwoMultibindingAnnotations_failsToCompile()29*f585d8a3SJacky Wang public void providesWithTwoMultibindingAnnotations_failsToCompile() { 30*f585d8a3SJacky Wang Source module = 31*f585d8a3SJacky Wang CompilerTests.javaSource( 32*f585d8a3SJacky Wang "test.MultibindingModule", 33*f585d8a3SJacky Wang "package test;", 34*f585d8a3SJacky Wang "", 35*f585d8a3SJacky Wang "import dagger.Module;", 36*f585d8a3SJacky Wang "import dagger.Provides;", 37*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 38*f585d8a3SJacky Wang "import dagger.multibindings.IntoMap;", 39*f585d8a3SJacky Wang "", 40*f585d8a3SJacky Wang "@Module", 41*f585d8a3SJacky Wang "class MultibindingModule {", 42*f585d8a3SJacky Wang " @Provides", 43*f585d8a3SJacky Wang " @IntoSet", 44*f585d8a3SJacky Wang " @IntoMap", 45*f585d8a3SJacky Wang " Integer provideInt() { ", 46*f585d8a3SJacky Wang " return 1;", 47*f585d8a3SJacky Wang " }", 48*f585d8a3SJacky Wang "}"); 49*f585d8a3SJacky Wang 50*f585d8a3SJacky Wang CompilerTests.daggerCompiler(module) 51*f585d8a3SJacky Wang .compile( 52*f585d8a3SJacky Wang subject -> { 53*f585d8a3SJacky Wang subject.hasErrorCount(3); 54*f585d8a3SJacky Wang subject.hasErrorContaining( 55*f585d8a3SJacky Wang "@Provides methods cannot have more than one multibinding annotation") 56*f585d8a3SJacky Wang .onSource(module) 57*f585d8a3SJacky Wang .onLine(11); 58*f585d8a3SJacky Wang subject.hasErrorContaining( 59*f585d8a3SJacky Wang "@Provides methods cannot have more than one multibinding annotation") 60*f585d8a3SJacky Wang .onSource(module) 61*f585d8a3SJacky Wang .onLine(12); 62*f585d8a3SJacky Wang subject.hasErrorContaining("@Provides methods of type map must declare a map key") 63*f585d8a3SJacky Wang .onSource(module) 64*f585d8a3SJacky Wang .onLine(13); 65*f585d8a3SJacky Wang }); 66*f585d8a3SJacky Wang } 67*f585d8a3SJacky Wang 68*f585d8a3SJacky Wang @Test appliedOnInvalidMethods_failsToCompile()69*f585d8a3SJacky Wang public void appliedOnInvalidMethods_failsToCompile() { 70*f585d8a3SJacky Wang Source someType = 71*f585d8a3SJacky Wang CompilerTests.javaSource( 72*f585d8a3SJacky Wang "test.SomeType", 73*f585d8a3SJacky Wang "package test;", 74*f585d8a3SJacky Wang "", 75*f585d8a3SJacky Wang "import java.util.Set;", 76*f585d8a3SJacky Wang "import java.util.Map;", 77*f585d8a3SJacky Wang "import dagger.Component;", 78*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 79*f585d8a3SJacky Wang "import dagger.multibindings.ElementsIntoSet;", 80*f585d8a3SJacky Wang "import dagger.multibindings.IntoMap;", 81*f585d8a3SJacky Wang "", 82*f585d8a3SJacky Wang "interface SomeType {", 83*f585d8a3SJacky Wang " @IntoSet Set<Integer> ints();", 84*f585d8a3SJacky Wang " @ElementsIntoSet Set<Double> doubles();", 85*f585d8a3SJacky Wang " @IntoMap Map<Integer, Double> map();", 86*f585d8a3SJacky Wang "}"); 87*f585d8a3SJacky Wang 88*f585d8a3SJacky Wang CompilerTests.daggerCompiler(someType) 89*f585d8a3SJacky Wang .compile( 90*f585d8a3SJacky Wang subject -> { 91*f585d8a3SJacky Wang subject.hasErrorCount(3); 92*f585d8a3SJacky Wang String error = 93*f585d8a3SJacky Wang "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods"; 94*f585d8a3SJacky Wang subject.hasErrorContaining(error).onSource(someType).onLineContaining("ints();"); 95*f585d8a3SJacky Wang subject.hasErrorContaining(error).onSource(someType).onLineContaining("doubles();"); 96*f585d8a3SJacky Wang subject.hasErrorContaining(error).onSource(someType).onLineContaining("map();"); 97*f585d8a3SJacky Wang }); 98*f585d8a3SJacky Wang } 99*f585d8a3SJacky Wang 100*f585d8a3SJacky Wang @Test concreteBindingForMultibindingAlias()101*f585d8a3SJacky Wang public void concreteBindingForMultibindingAlias() { 102*f585d8a3SJacky Wang Source module = 103*f585d8a3SJacky Wang CompilerTests.javaSource( 104*f585d8a3SJacky Wang "test.TestModule", 105*f585d8a3SJacky Wang "package test;", 106*f585d8a3SJacky Wang "", 107*f585d8a3SJacky Wang "import dagger.Module;", 108*f585d8a3SJacky Wang "import dagger.Provides;", 109*f585d8a3SJacky Wang "import java.util.Collections;", 110*f585d8a3SJacky Wang "import java.util.Map;", 111*f585d8a3SJacky Wang "import javax.inject.Provider;", 112*f585d8a3SJacky Wang "", 113*f585d8a3SJacky Wang "@Module", 114*f585d8a3SJacky Wang "class TestModule {", 115*f585d8a3SJacky Wang " @Provides", 116*f585d8a3SJacky Wang " Map<String, Provider<String>> mapOfStringToProviderOfString() {", 117*f585d8a3SJacky Wang " return Collections.emptyMap();", 118*f585d8a3SJacky Wang " }", 119*f585d8a3SJacky Wang "}"); 120*f585d8a3SJacky Wang Source component = 121*f585d8a3SJacky Wang CompilerTests.javaSource( 122*f585d8a3SJacky Wang "test.TestComponent", 123*f585d8a3SJacky Wang "package test;", 124*f585d8a3SJacky Wang "", 125*f585d8a3SJacky Wang "import dagger.Component;", 126*f585d8a3SJacky Wang "import java.util.Map;", 127*f585d8a3SJacky Wang "", 128*f585d8a3SJacky Wang "@Component(modules = TestModule.class)", 129*f585d8a3SJacky Wang "interface TestComponent {", 130*f585d8a3SJacky Wang " Map<String, String> mapOfStringToString();", 131*f585d8a3SJacky Wang "}"); 132*f585d8a3SJacky Wang CompilerTests.daggerCompiler(module, component) 133*f585d8a3SJacky Wang .compile( 134*f585d8a3SJacky Wang subject -> { 135*f585d8a3SJacky Wang subject.hasErrorCount(1); 136*f585d8a3SJacky Wang subject.hasErrorContaining( 137*f585d8a3SJacky Wang "Map<String,String> cannot be provided without an @Provides-annotated method") 138*f585d8a3SJacky Wang .onSource(component) 139*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 140*f585d8a3SJacky Wang }); 141*f585d8a3SJacky Wang } 142*f585d8a3SJacky Wang 143*f585d8a3SJacky Wang @Test produceConcreteSet_andRequestSetOfProduced()144*f585d8a3SJacky Wang public void produceConcreteSet_andRequestSetOfProduced() { 145*f585d8a3SJacky Wang Source module = 146*f585d8a3SJacky Wang CompilerTests.javaSource( 147*f585d8a3SJacky Wang "test.TestModule", 148*f585d8a3SJacky Wang "package test;", 149*f585d8a3SJacky Wang "", 150*f585d8a3SJacky Wang "import dagger.producers.ProducerModule;", 151*f585d8a3SJacky Wang "import dagger.producers.Produces;", 152*f585d8a3SJacky Wang "import java.util.Collections;", 153*f585d8a3SJacky Wang "import java.util.Set;", 154*f585d8a3SJacky Wang "", 155*f585d8a3SJacky Wang "@ProducerModule", 156*f585d8a3SJacky Wang "class TestModule {", 157*f585d8a3SJacky Wang " @Produces", 158*f585d8a3SJacky Wang " Set<String> setOfString() {", 159*f585d8a3SJacky Wang " return Collections.emptySet();", 160*f585d8a3SJacky Wang " }", 161*f585d8a3SJacky Wang "}"); 162*f585d8a3SJacky Wang Source component = 163*f585d8a3SJacky Wang CompilerTests.javaSource( 164*f585d8a3SJacky Wang "test.TestComponent", 165*f585d8a3SJacky Wang "package test;", 166*f585d8a3SJacky Wang "", 167*f585d8a3SJacky Wang "import com.google.common.util.concurrent.ListenableFuture;", 168*f585d8a3SJacky Wang "import dagger.BindsInstance;", 169*f585d8a3SJacky Wang "import dagger.producers.Produced;", 170*f585d8a3SJacky Wang "import dagger.producers.Production;", 171*f585d8a3SJacky Wang "import dagger.producers.ProductionComponent;", 172*f585d8a3SJacky Wang "import java.util.concurrent.Executor;", 173*f585d8a3SJacky Wang "import java.util.Set;", 174*f585d8a3SJacky Wang "", 175*f585d8a3SJacky Wang "@ProductionComponent(modules = TestModule.class)", 176*f585d8a3SJacky Wang "interface TestComponent {", 177*f585d8a3SJacky Wang " ListenableFuture<Set<Produced<String>>> setOfProduced();", 178*f585d8a3SJacky Wang "", 179*f585d8a3SJacky Wang " @ProductionComponent.Builder", 180*f585d8a3SJacky Wang " interface Builder {", 181*f585d8a3SJacky Wang " @BindsInstance Builder executor(@Production Executor executor);", 182*f585d8a3SJacky Wang " TestComponent build();", 183*f585d8a3SJacky Wang " }", 184*f585d8a3SJacky Wang "}"); 185*f585d8a3SJacky Wang CompilerTests.daggerCompiler(module, component) 186*f585d8a3SJacky Wang .compile( 187*f585d8a3SJacky Wang subject -> { 188*f585d8a3SJacky Wang subject.hasErrorCount(1); 189*f585d8a3SJacky Wang subject.hasErrorContaining( 190*f585d8a3SJacky Wang "Set<Produced<String>> cannot be provided without an @Provides- or " 191*f585d8a3SJacky Wang + "@Produces-annotated method") 192*f585d8a3SJacky Wang .onSource(component) 193*f585d8a3SJacky Wang .onLineContaining("interface TestComponent"); 194*f585d8a3SJacky Wang }); 195*f585d8a3SJacky Wang } 196*f585d8a3SJacky Wang 197*f585d8a3SJacky Wang @Test provideExplicitSetInParent_AndMultibindingContributionInChild()198*f585d8a3SJacky Wang public void provideExplicitSetInParent_AndMultibindingContributionInChild() { 199*f585d8a3SJacky Wang Source parent = 200*f585d8a3SJacky Wang CompilerTests.javaSource( 201*f585d8a3SJacky Wang "test.Parent", 202*f585d8a3SJacky Wang "package test;", 203*f585d8a3SJacky Wang "", 204*f585d8a3SJacky Wang "import dagger.Component;", 205*f585d8a3SJacky Wang "import java.util.Set;", 206*f585d8a3SJacky Wang "", 207*f585d8a3SJacky Wang "@Component(modules = ParentModule.class)", 208*f585d8a3SJacky Wang "interface Parent {", 209*f585d8a3SJacky Wang " Set<String> set();", 210*f585d8a3SJacky Wang " Child child();", 211*f585d8a3SJacky Wang "}"); 212*f585d8a3SJacky Wang Source parentModule = 213*f585d8a3SJacky Wang CompilerTests.javaSource( 214*f585d8a3SJacky Wang "test.ParentModule", 215*f585d8a3SJacky Wang "package test;", 216*f585d8a3SJacky Wang "", 217*f585d8a3SJacky Wang "import dagger.Module;", 218*f585d8a3SJacky Wang "import dagger.Provides;", 219*f585d8a3SJacky Wang "import java.util.HashSet;", 220*f585d8a3SJacky Wang "import java.util.Set;", 221*f585d8a3SJacky Wang "", 222*f585d8a3SJacky Wang "@Module", 223*f585d8a3SJacky Wang "class ParentModule {", 224*f585d8a3SJacky Wang " @Provides", 225*f585d8a3SJacky Wang " Set<String> set() {", 226*f585d8a3SJacky Wang " return new HashSet();", 227*f585d8a3SJacky Wang " }", 228*f585d8a3SJacky Wang "}"); 229*f585d8a3SJacky Wang 230*f585d8a3SJacky Wang Source child = 231*f585d8a3SJacky Wang CompilerTests.javaSource( 232*f585d8a3SJacky Wang "test.Child", 233*f585d8a3SJacky Wang "package test;", 234*f585d8a3SJacky Wang "", 235*f585d8a3SJacky Wang "import dagger.Subcomponent;", 236*f585d8a3SJacky Wang "import java.util.Set;", 237*f585d8a3SJacky Wang "", 238*f585d8a3SJacky Wang "@Subcomponent(modules = ChildModule.class)", 239*f585d8a3SJacky Wang "interface Child {", 240*f585d8a3SJacky Wang " Set<String> set();", 241*f585d8a3SJacky Wang "}"); 242*f585d8a3SJacky Wang Source childModule = 243*f585d8a3SJacky Wang CompilerTests.javaSource( 244*f585d8a3SJacky Wang "test.ChildModule", 245*f585d8a3SJacky Wang "package test;", 246*f585d8a3SJacky Wang "", 247*f585d8a3SJacky Wang "import dagger.Module;", 248*f585d8a3SJacky Wang "import dagger.multibindings.IntoSet;", 249*f585d8a3SJacky Wang "import dagger.Provides;", 250*f585d8a3SJacky Wang "", 251*f585d8a3SJacky Wang "@Module", 252*f585d8a3SJacky Wang "class ChildModule {", 253*f585d8a3SJacky Wang " @Provides", 254*f585d8a3SJacky Wang " @IntoSet", 255*f585d8a3SJacky Wang " String setContribution() {", 256*f585d8a3SJacky Wang " return new String();", 257*f585d8a3SJacky Wang " }", 258*f585d8a3SJacky Wang "}"); 259*f585d8a3SJacky Wang 260*f585d8a3SJacky Wang CompilerTests.daggerCompiler(parent, parentModule, child, childModule) 261*f585d8a3SJacky Wang .compile( 262*f585d8a3SJacky Wang subject -> { 263*f585d8a3SJacky Wang subject.hasErrorCount(1); 264*f585d8a3SJacky Wang subject.hasErrorContaining("incompatible bindings or declarations") 265*f585d8a3SJacky Wang .onSource(parent) 266*f585d8a3SJacky Wang .onLineContaining("interface Parent"); 267*f585d8a3SJacky Wang }); 268*f585d8a3SJacky Wang } 269*f585d8a3SJacky Wang } 270