1 /* 2 * Copyright (C) 2016 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen; 18 19 import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass; 20 import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod; 21 import static java.lang.annotation.RetentionPolicy.RUNTIME; 22 23 import com.google.common.collect.ImmutableList; 24 import dagger.Module; 25 import dagger.multibindings.IntKey; 26 import dagger.multibindings.LongKey; 27 import dagger.producers.ProducerModule; 28 import java.lang.annotation.Annotation; 29 import java.lang.annotation.Retention; 30 import java.util.Collection; 31 import javax.inject.Qualifier; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.junit.runners.Parameterized; 35 import org.junit.runners.Parameterized.Parameters; 36 37 @RunWith(Parameterized.class) 38 public class BindsMethodValidationTest { 39 @Parameters data()40 public static Collection<Object[]> data() { 41 return ImmutableList.copyOf(new Object[][] {{Module.class}, {ProducerModule.class}}); 42 } 43 44 private final String moduleDeclaration; 45 BindsMethodValidationTest(Class<? extends Annotation> moduleAnnotation)46 public BindsMethodValidationTest(Class<? extends Annotation> moduleAnnotation) { 47 moduleDeclaration = "@" + moduleAnnotation.getCanonicalName() + " abstract class %s { %s }"; 48 } 49 50 @Test nonAbstract()51 public void nonAbstract() { 52 assertThatMethod("@Binds Object concrete(String impl) { return null; }") 53 .hasError("must be abstract"); 54 } 55 56 @Test notAssignable()57 public void notAssignable() { 58 assertThatMethod("@Binds abstract String notAssignable(Object impl);").hasError("assignable"); 59 } 60 61 @Test moreThanOneParameter()62 public void moreThanOneParameter() { 63 assertThatMethod("@Binds abstract Object tooManyParameters(String s1, String s2);") 64 .hasError("one parameter"); 65 } 66 67 @Test typeParameters()68 public void typeParameters() { 69 assertThatMethod("@Binds abstract <S, T extends S> S generic(T t);") 70 .hasError("type parameters"); 71 } 72 73 @Test notInModule()74 public void notInModule() { 75 assertThatMethodInUnannotatedClass("@Binds abstract Object bindObject(String s);") 76 .hasError("within a @Module or @ProducerModule"); 77 } 78 79 @Test throwsException()80 public void throwsException() { 81 assertThatMethod("@Binds abstract Object throwsException(String s1) throws RuntimeException;") 82 .hasError("may not throw"); 83 } 84 85 @Test returnsVoid()86 public void returnsVoid() { 87 assertThatMethod("@Binds abstract void returnsVoid(Object impl);").hasError("void"); 88 } 89 90 @Test tooManyQualifiersOnMethod()91 public void tooManyQualifiersOnMethod() { 92 assertThatMethod( 93 "@Binds @Qualifier1 @Qualifier2 abstract String tooManyQualifiers(String impl);") 94 .importing(Qualifier1.class, Qualifier2.class) 95 .hasError("more than one @Qualifier"); 96 } 97 98 @Test tooManyQualifiersOnParameter()99 public void tooManyQualifiersOnParameter() { 100 assertThatMethod( 101 "@Binds abstract String tooManyQualifiers(@Qualifier1 @Qualifier2 String impl);") 102 .importing(Qualifier1.class, Qualifier2.class) 103 .hasError("more than one @Qualifier"); 104 } 105 106 @Test noParameters()107 public void noParameters() { 108 assertThatMethod("@Binds abstract Object noParameters();").hasError("one parameter"); 109 } 110 111 @Test setElementsNotAssignable()112 public void setElementsNotAssignable() { 113 assertThatMethod( 114 "@Binds @ElementsIntoSet abstract Set<String> bindSetOfIntegers(Set<Integer> ints);") 115 .hasError("assignable"); 116 } 117 118 @Test setElements_primitiveArgument()119 public void setElements_primitiveArgument() { 120 assertThatMethod("@Binds @ElementsIntoSet abstract Set<Number> bindInt(int integer);") 121 .hasError("assignable"); 122 } 123 124 @Test elementsIntoSet_withRawSets()125 public void elementsIntoSet_withRawSets() { 126 assertThatMethod("@Binds @ElementsIntoSet abstract Set bindRawSet(HashSet hashSet);") 127 .hasError("cannot return a raw Set"); 128 } 129 130 @Test intoMap_noMapKey()131 public void intoMap_noMapKey() { 132 assertThatMethod("@Binds @IntoMap abstract Object bindNoMapKey(String string);") 133 .hasError("methods of type map must declare a map key"); 134 } 135 136 @Test intoMap_multipleMapKeys()137 public void intoMap_multipleMapKeys() { 138 assertThatMethod( 139 "@Binds @IntoMap @IntKey(1) @LongKey(2L) abstract Object manyMapKeys(String string);") 140 .importing(IntKey.class, LongKey.class) 141 .hasError("may not have more than one map key"); 142 } 143 assertThatMethod(String method)144 private DaggerModuleMethodSubject assertThatMethod(String method) { 145 return assertThatModuleMethod(method).withDeclaration(moduleDeclaration); 146 } 147 148 @Qualifier 149 @Retention(RUNTIME) 150 public @interface Qualifier1 {} 151 152 @Qualifier 153 @Retention(RUNTIME) 154 public @interface Qualifier2 {} 155 } 156