1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen; 17 18 import com.google.auto.common.MoreTypes; 19 import com.google.common.base.Equivalence; 20 import com.google.common.base.Optional; 21 import com.google.common.collect.Iterables; 22 import com.google.common.util.concurrent.ListenableFuture; 23 import com.google.testing.compile.CompilationRule; 24 import dagger.Module; 25 import dagger.Provides; 26 import dagger.producers.ProducerModule; 27 import dagger.producers.Produces; 28 import java.util.Set; 29 import javax.inject.Inject; 30 import javax.inject.Qualifier; 31 import javax.lang.model.element.AnnotationMirror; 32 import javax.lang.model.element.Element; 33 import javax.lang.model.element.ExecutableElement; 34 import javax.lang.model.element.TypeElement; 35 import javax.lang.model.type.ExecutableType; 36 import javax.lang.model.type.TypeMirror; 37 import javax.lang.model.util.ElementFilter; 38 import javax.lang.model.util.Elements; 39 import javax.lang.model.util.Types; 40 import org.junit.Before; 41 import org.junit.Rule; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 import org.junit.runners.JUnit4; 45 46 import static com.google.common.truth.Truth.assertThat; 47 import static dagger.Provides.Type.SET; 48 import static dagger.Provides.Type.SET_VALUES; 49 50 /** 51 * Tests {@link Key}. 52 */ 53 @RunWith(JUnit4.class) 54 public class KeyTest { 55 @Rule public CompilationRule compilationRule = new CompilationRule(); 56 57 private Elements elements; 58 private Types types; 59 private Key.Factory keyFactory; 60 setUp()61 @Before public void setUp() { 62 this.types = compilationRule.getTypes(); 63 this.elements = compilationRule.getElements(); 64 this.keyFactory = new Key.Factory(types, elements); 65 } 66 forInjectConstructorWithResolvedType()67 @Test public void forInjectConstructorWithResolvedType() { 68 TypeElement typeElement = 69 compilationRule.getElements().getTypeElement(InjectedClass.class.getCanonicalName()); 70 ExecutableElement constructor = 71 Iterables.getOnlyElement(ElementFilter.constructorsIn(typeElement.getEnclosedElements())); 72 assertThat( 73 keyFactory.forInjectConstructorWithResolvedType(constructor.getEnclosingElement().asType())) 74 .isEqualTo(new AutoValue_Key( 75 Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(), 76 MoreTypes.equivalence().wrap(typeElement.asType()))); 77 } 78 79 static final class InjectedClass { 80 @SuppressWarnings("unused") InjectedClass(String s, int i)81 @Inject InjectedClass(String s, int i) {} 82 } 83 forProvidesMethod()84 @Test public void forProvidesMethod() { 85 TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType(); 86 TypeElement moduleElement = 87 elements.getTypeElement(ProvidesMethodModule.class.getCanonicalName()); 88 ExecutableElement providesMethod = 89 Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements())); 90 assertThat( 91 keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod)) 92 .isEqualTo(new AutoValue_Key( 93 Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(), 94 MoreTypes.equivalence().wrap(stringType))); 95 } 96 97 @Module 98 static final class ProvidesMethodModule { provideString()99 @Provides String provideString() { 100 return null; 101 } 102 } 103 forProvidesMethod_qualified()104 @Test public void forProvidesMethod_qualified() { 105 TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType(); 106 TypeElement qualifierElement = 107 elements.getTypeElement(TestQualifier.class.getCanonicalName()); 108 TypeElement moduleElement = 109 elements.getTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName()); 110 ExecutableElement providesMethod = 111 Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements())); 112 Key key = 113 keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod); 114 assertThat(MoreTypes.equivalence().wrap(key.qualifier().get().getAnnotationType())) 115 .isEqualTo(MoreTypes.equivalence().wrap(qualifierElement.asType())); 116 assertThat(key.wrappedType()).isEqualTo(MoreTypes.equivalence().wrap(stringType)); 117 } 118 qualifiedKeyEquivalents()119 @Test public void qualifiedKeyEquivalents() { 120 TypeElement moduleElement = 121 elements.getTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName()); 122 ExecutableElement providesMethod = 123 Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements())); 124 Key provisionKey = 125 keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod); 126 127 TypeMirror type = elements.getTypeElement(String.class.getCanonicalName()).asType(); 128 TypeElement injectableElement = 129 elements.getTypeElement(QualifiedFieldHolder.class.getCanonicalName()); 130 Element injectionField = 131 Iterables.getOnlyElement(ElementFilter.fieldsIn(injectableElement.getEnclosedElements())); 132 AnnotationMirror qualifier = Iterables.getOnlyElement(injectionField.getAnnotationMirrors()); 133 Key injectionKey = keyFactory.forQualifiedType(Optional.<AnnotationMirror>of(qualifier), type); 134 135 assertThat(provisionKey).isEqualTo(injectionKey); 136 } 137 138 @Module 139 static final class QualifiedProvidesMethodModule { 140 @Provides 141 @TestQualifier(@InnerAnnotation) provideQualifiedString()142 String provideQualifiedString() { 143 return null; 144 } 145 } 146 147 static final class QualifiedFieldHolder { 148 @TestQualifier(@InnerAnnotation) String aString; 149 } 150 151 @Qualifier 152 @interface TestQualifier { value()153 InnerAnnotation[] value(); 154 } 155 156 @interface InnerAnnotation {} 157 forProvidesMethod_sets()158 @Test public void forProvidesMethod_sets() { 159 TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName()); 160 TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType(); 161 TypeMirror setOfStringsType = types.getDeclaredType(setElement, stringType); 162 TypeElement moduleElement = 163 elements.getTypeElement(SetProvidesMethodsModule.class.getCanonicalName()); 164 for (ExecutableElement providesMethod 165 : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) { 166 assertThat( 167 keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod)) 168 .isEqualTo(new AutoValue_Key( 169 Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(), 170 MoreTypes.equivalence().wrap(setOfStringsType))); 171 } 172 } 173 174 @Module 175 static final class SetProvidesMethodsModule { provideString()176 @Provides(type = SET) String provideString() { 177 return null; 178 } 179 provideStrings()180 @Provides(type = SET_VALUES) Set<String> provideStrings() { 181 return null; 182 } 183 } 184 185 @Module 186 static final class PrimitiveTypes { foo()187 @Provides int foo() { 188 return 0; 189 } 190 } 191 192 @Module 193 static final class BoxedPrimitiveTypes { foo()194 @Provides Integer foo() { 195 return 0; 196 } 197 } 198 primitiveKeysMatchBoxedKeys()199 @Test public void primitiveKeysMatchBoxedKeys() { 200 TypeElement primitiveHolder = elements.getTypeElement(PrimitiveTypes.class.getCanonicalName()); 201 ExecutableElement intMethod = 202 Iterables.getOnlyElement(ElementFilter.methodsIn(primitiveHolder.getEnclosedElements())); 203 TypeElement boxedPrimitiveHolder = 204 elements.getTypeElement(BoxedPrimitiveTypes.class.getCanonicalName()); 205 ExecutableElement integerMethod = Iterables.getOnlyElement( 206 ElementFilter.methodsIn(boxedPrimitiveHolder.getEnclosedElements())); 207 208 // TODO(cgruber): Truth subject for TypeMirror and TypeElement 209 TypeMirror intType = intMethod.getReturnType(); 210 assertThat(intType.getKind().isPrimitive()).isTrue(); 211 TypeMirror integerType = integerMethod.getReturnType(); 212 assertThat(integerType.getKind().isPrimitive()).isFalse(); 213 assertThat(types.isSameType(intType, integerType)).named("type equality").isFalse(); 214 215 Key intKey = keyFactory.forProvidesMethod((ExecutableType) intMethod.asType(), intMethod); 216 Key integerKey = 217 keyFactory.forProvidesMethod((ExecutableType) integerMethod.asType(), integerMethod); 218 assertThat(intKey).isEqualTo(integerKey); 219 } 220 forProducesMethod()221 @Test public void forProducesMethod() { 222 TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType(); 223 TypeElement moduleElement = 224 elements.getTypeElement(ProducesMethodsModule.class.getCanonicalName()); 225 for (ExecutableElement producesMethod 226 : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) { 227 assertThat(keyFactory.forProducesMethod( 228 (ExecutableType) producesMethod.asType(), producesMethod)) 229 .isEqualTo(new AutoValue_Key( 230 Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(), 231 MoreTypes.equivalence().wrap(stringType))); 232 } 233 } 234 235 @ProducerModule 236 static final class ProducesMethodsModule { produceString()237 @Produces String produceString() { 238 return null; 239 } 240 produceFutureString()241 @Produces ListenableFuture<String> produceFutureString() { 242 return null; 243 } 244 } 245 forProducesMethod_sets()246 @Test public void forProducesMethod_sets() { 247 TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName()); 248 TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType(); 249 TypeMirror setOfStringsType = types.getDeclaredType(setElement, stringType); 250 TypeElement moduleElement = 251 elements.getTypeElement(SetProducesMethodsModule.class.getCanonicalName()); 252 for (ExecutableElement producesMethod 253 : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) { 254 assertThat(keyFactory.forProducesMethod( 255 (ExecutableType) producesMethod.asType(), producesMethod)) 256 .isEqualTo(new AutoValue_Key( 257 Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(), 258 MoreTypes.equivalence().wrap(setOfStringsType))); 259 } 260 } 261 262 @ProducerModule 263 static final class SetProducesMethodsModule { produceString()264 @Produces(type = Produces.Type.SET) String produceString() { 265 return null; 266 } 267 produceFutureString()268 @Produces(type = Produces.Type.SET) ListenableFuture<String> produceFutureString() { 269 return null; 270 } 271 produceStrings()272 @Produces(type = Produces.Type.SET_VALUES) Set<String> produceStrings() { 273 return null; 274 } 275 276 @Produces(type = Produces.Type.SET_VALUES) produceFutureStrings()277 ListenableFuture<Set<String>> produceFutureStrings() { 278 return null; 279 } 280 } 281 } 282