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 static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass; 20*f585d8a3SJacky Wang import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod; 21*f585d8a3SJacky Wang 22*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source; 23*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList; 24*f585d8a3SJacky Wang import dagger.Module; 25*f585d8a3SJacky Wang import dagger.producers.ProducerModule; 26*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests; 27*f585d8a3SJacky Wang import java.lang.annotation.Annotation; 28*f585d8a3SJacky Wang import java.util.Collection; 29*f585d8a3SJacky Wang import javax.inject.Inject; 30*f585d8a3SJacky Wang import javax.inject.Qualifier; 31*f585d8a3SJacky Wang import javax.inject.Singleton; 32*f585d8a3SJacky Wang import org.junit.Test; 33*f585d8a3SJacky Wang import org.junit.runner.RunWith; 34*f585d8a3SJacky Wang import org.junit.runners.Parameterized; 35*f585d8a3SJacky Wang import org.junit.runners.Parameterized.Parameters; 36*f585d8a3SJacky Wang 37*f585d8a3SJacky Wang /** Tests {@link dagger.internal.codegen.validation.BindsOptionalOfMethodValidator}. */ 38*f585d8a3SJacky Wang @RunWith(Parameterized.class) 39*f585d8a3SJacky Wang public class BindsOptionalOfMethodValidationTest { 40*f585d8a3SJacky Wang @Parameters(name = "{0}") data()41*f585d8a3SJacky Wang public static Collection<Object[]> data() { 42*f585d8a3SJacky Wang return ImmutableList.copyOf(new Object[][] {{Module.class}, {ProducerModule.class}}); 43*f585d8a3SJacky Wang } 44*f585d8a3SJacky Wang 45*f585d8a3SJacky Wang private final String moduleDeclaration; 46*f585d8a3SJacky Wang BindsOptionalOfMethodValidationTest(Class<? extends Annotation> moduleAnnotation)47*f585d8a3SJacky Wang public BindsOptionalOfMethodValidationTest(Class<? extends Annotation> moduleAnnotation) { 48*f585d8a3SJacky Wang moduleDeclaration = "@" + moduleAnnotation.getCanonicalName() + " abstract class %s { %s }"; 49*f585d8a3SJacky Wang } 50*f585d8a3SJacky Wang 51*f585d8a3SJacky Wang @Test nonAbstract()52*f585d8a3SJacky Wang public void nonAbstract() { 53*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf Object concrete() { return null; }") 54*f585d8a3SJacky Wang .hasError("must be abstract"); 55*f585d8a3SJacky Wang } 56*f585d8a3SJacky Wang 57*f585d8a3SJacky Wang @Test hasParameters()58*f585d8a3SJacky Wang public void hasParameters() { 59*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf abstract Object hasParameters(String s1);") 60*f585d8a3SJacky Wang .hasError("parameters"); 61*f585d8a3SJacky Wang } 62*f585d8a3SJacky Wang 63*f585d8a3SJacky Wang @Test typeParameters()64*f585d8a3SJacky Wang public void typeParameters() { 65*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf abstract <S> S generic();").hasError("type parameters"); 66*f585d8a3SJacky Wang } 67*f585d8a3SJacky Wang 68*f585d8a3SJacky Wang @Test notInModule()69*f585d8a3SJacky Wang public void notInModule() { 70*f585d8a3SJacky Wang assertThatMethodInUnannotatedClass("@BindsOptionalOf abstract Object notInModule();") 71*f585d8a3SJacky Wang .hasError("within a @Module or @ProducerModule"); 72*f585d8a3SJacky Wang } 73*f585d8a3SJacky Wang 74*f585d8a3SJacky Wang @Test throwsException()75*f585d8a3SJacky Wang public void throwsException() { 76*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf abstract Object throwsException() throws RuntimeException;") 77*f585d8a3SJacky Wang .hasError("may not throw"); 78*f585d8a3SJacky Wang } 79*f585d8a3SJacky Wang 80*f585d8a3SJacky Wang @Test returnsVoid()81*f585d8a3SJacky Wang public void returnsVoid() { 82*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf abstract void returnsVoid();").hasError("void"); 83*f585d8a3SJacky Wang } 84*f585d8a3SJacky Wang 85*f585d8a3SJacky Wang @Test returnsMembersInjector()86*f585d8a3SJacky Wang public void returnsMembersInjector() { 87*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf abstract MembersInjector<Object> returnsMembersInjector();") 88*f585d8a3SJacky Wang .hasError("framework"); 89*f585d8a3SJacky Wang } 90*f585d8a3SJacky Wang 91*f585d8a3SJacky Wang @Test tooManyQualifiers()92*f585d8a3SJacky Wang public void tooManyQualifiers() { 93*f585d8a3SJacky Wang assertThatMethod( 94*f585d8a3SJacky Wang "@BindsOptionalOf @Qualifier1 @Qualifier2 abstract String tooManyQualifiers();") 95*f585d8a3SJacky Wang .importing(Qualifier1.class, Qualifier2.class) 96*f585d8a3SJacky Wang .hasError("more than one @Qualifier"); 97*f585d8a3SJacky Wang } 98*f585d8a3SJacky Wang 99*f585d8a3SJacky Wang @Test intoSet()100*f585d8a3SJacky Wang public void intoSet() { 101*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf @IntoSet abstract String intoSet();") 102*f585d8a3SJacky Wang .hasError("cannot have multibinding annotations"); 103*f585d8a3SJacky Wang } 104*f585d8a3SJacky Wang 105*f585d8a3SJacky Wang @Test elementsIntoSet()106*f585d8a3SJacky Wang public void elementsIntoSet() { 107*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf @ElementsIntoSet abstract Set<String> elementsIntoSet();") 108*f585d8a3SJacky Wang .hasError("cannot have multibinding annotations"); 109*f585d8a3SJacky Wang } 110*f585d8a3SJacky Wang 111*f585d8a3SJacky Wang @Test intoMap()112*f585d8a3SJacky Wang public void intoMap() { 113*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf @IntoMap abstract String intoMap();") 114*f585d8a3SJacky Wang .hasError("cannot have multibinding annotations"); 115*f585d8a3SJacky Wang } 116*f585d8a3SJacky Wang 117*f585d8a3SJacky Wang /** 118*f585d8a3SJacky Wang * Tests that @BindsOptionalOf @IntoMap actually causes module validation to fail. 119*f585d8a3SJacky Wang * 120*f585d8a3SJacky Wang * @see <a href="http://b/118434447">bug 118434447</a> 121*f585d8a3SJacky Wang */ 122*f585d8a3SJacky Wang @Test intoMapWithComponent()123*f585d8a3SJacky Wang public void intoMapWithComponent() { 124*f585d8a3SJacky Wang Source module = 125*f585d8a3SJacky Wang CompilerTests.javaSource( 126*f585d8a3SJacky Wang "test.TestModule", 127*f585d8a3SJacky Wang "package test;", 128*f585d8a3SJacky Wang "", 129*f585d8a3SJacky Wang "import dagger.BindsOptionalOf;", 130*f585d8a3SJacky Wang "import dagger.Module;", 131*f585d8a3SJacky Wang "import dagger.multibindings.IntoMap;", 132*f585d8a3SJacky Wang "", 133*f585d8a3SJacky Wang "@Module", 134*f585d8a3SJacky Wang "interface TestModule {", 135*f585d8a3SJacky Wang " @BindsOptionalOf @IntoMap Object object();", 136*f585d8a3SJacky Wang "}"); 137*f585d8a3SJacky Wang Source component = 138*f585d8a3SJacky Wang CompilerTests.javaSource( 139*f585d8a3SJacky Wang "test.TestComponent", 140*f585d8a3SJacky Wang "package test;", 141*f585d8a3SJacky Wang "", 142*f585d8a3SJacky Wang "import dagger.Component;", 143*f585d8a3SJacky Wang "", 144*f585d8a3SJacky Wang "@Component(modules = TestModule.class)", 145*f585d8a3SJacky Wang "interface TestComponent {}"); 146*f585d8a3SJacky Wang 147*f585d8a3SJacky Wang CompilerTests.daggerCompiler(module, component) 148*f585d8a3SJacky Wang .compile( 149*f585d8a3SJacky Wang subject -> { 150*f585d8a3SJacky Wang subject.hasErrorCount(2); 151*f585d8a3SJacky Wang subject.hasErrorContaining("test.TestModule has errors") 152*f585d8a3SJacky Wang .onSource(component) 153*f585d8a3SJacky Wang .onLineContaining("@Component(modules = TestModule.class)"); 154*f585d8a3SJacky Wang subject.hasErrorContaining("cannot have multibinding annotations") 155*f585d8a3SJacky Wang .onSource(module) 156*f585d8a3SJacky Wang .onLineContaining("object()"); 157*f585d8a3SJacky Wang }); 158*f585d8a3SJacky Wang } 159*f585d8a3SJacky Wang 160*f585d8a3SJacky Wang /** An injectable value object. */ 161*f585d8a3SJacky Wang public static final class Thing { 162*f585d8a3SJacky Wang @Inject Thing()163*f585d8a3SJacky Wang Thing() {} 164*f585d8a3SJacky Wang } 165*f585d8a3SJacky Wang 166*f585d8a3SJacky Wang @Test implicitlyProvidedType()167*f585d8a3SJacky Wang public void implicitlyProvidedType() { 168*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf abstract Thing thing();") 169*f585d8a3SJacky Wang .importing(Thing.class) 170*f585d8a3SJacky Wang .hasError("return unqualified types that have an @Inject-annotated constructor"); 171*f585d8a3SJacky Wang } 172*f585d8a3SJacky Wang 173*f585d8a3SJacky Wang @Test hasScope()174*f585d8a3SJacky Wang public void hasScope() { 175*f585d8a3SJacky Wang assertThatMethod("@BindsOptionalOf @Singleton abstract String scoped();") 176*f585d8a3SJacky Wang .importing(Singleton.class) 177*f585d8a3SJacky Wang .hasError("cannot be scoped"); 178*f585d8a3SJacky Wang } 179*f585d8a3SJacky Wang assertThatMethod(String method)180*f585d8a3SJacky Wang private DaggerModuleMethodSubject assertThatMethod(String method) { 181*f585d8a3SJacky Wang return assertThatModuleMethod(method).withDeclaration(moduleDeclaration); 182*f585d8a3SJacky Wang } 183*f585d8a3SJacky Wang 184*f585d8a3SJacky Wang /** A qualifier. */ 185*f585d8a3SJacky Wang @Qualifier 186*f585d8a3SJacky Wang public @interface Qualifier1 {} 187*f585d8a3SJacky Wang 188*f585d8a3SJacky Wang /** A qualifier. */ 189*f585d8a3SJacky Wang @Qualifier 190*f585d8a3SJacky Wang public @interface Qualifier2 {} 191*f585d8a3SJacky Wang } 192