/* * Copyright (C) 2014 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.squareup.javapoet; import static com.google.common.truth.Truth.assertThat; import static com.google.testing.compile.CompilationSubject.assertThat; import static com.google.testing.compile.Compiler.javac; import static javax.lang.model.util.ElementFilter.fieldsIn; import static org.junit.Assert.*; import com.google.testing.compile.Compilation; import com.google.testing.compile.JavaFileObjects; import java.io.Serializable; import java.lang.annotation.Annotation; import java.nio.charset.Charset; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.ErrorType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVisitor; import javax.lang.model.type.WildcardType; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.JavaFileObject; import org.junit.Test; public abstract class AbstractTypesTest { protected abstract Elements getElements(); protected abstract Types getTypes(); private TypeElement getElement(Class<?> clazz) { return getElements().getTypeElement(clazz.getCanonicalName()); } private TypeMirror getMirror(Class<?> clazz) { return getElement(clazz).asType(); } @Test public void getBasicTypeMirror() { assertThat(TypeName.get(getMirror(Object.class))) .isEqualTo(ClassName.get(Object.class)); assertThat(TypeName.get(getMirror(Charset.class))) .isEqualTo(ClassName.get(Charset.class)); assertThat(TypeName.get(getMirror(AbstractTypesTest.class))) .isEqualTo(ClassName.get(AbstractTypesTest.class)); } @Test public void getParameterizedTypeMirror() { DeclaredType setType = getTypes().getDeclaredType(getElement(Set.class), getMirror(Object.class)); assertThat(TypeName.get(setType)) .isEqualTo(ParameterizedTypeName.get(ClassName.get(Set.class), ClassName.OBJECT)); } @Test public void errorTypes() { JavaFileObject hasErrorTypes = JavaFileObjects.forSourceLines( "com.squareup.tacos.ErrorTypes", "package com.squareup.tacos;", "", "@SuppressWarnings(\"hook-into-compiler\")", "class ErrorTypes {", " Tacos tacos;", " Ingredients.Guacamole guacamole;", "}"); Compilation compilation = javac().withProcessors(new AbstractProcessor() { @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { TypeElement classFile = processingEnv.getElementUtils().getTypeElement("com.squareup.tacos.ErrorTypes"); List<VariableElement> fields = fieldsIn(classFile.getEnclosedElements()); ErrorType topLevel = (ErrorType) fields.get(0).asType(); ErrorType member = (ErrorType) fields.get(1).asType(); assertThat(TypeName.get(topLevel)).isEqualTo(ClassName.get("", "Tacos")); assertThat(TypeName.get(member)).isEqualTo(ClassName.get("Ingredients", "Guacamole")); return false; } @Override public Set<String> getSupportedAnnotationTypes() { return Collections.singleton("*"); } }).compile(hasErrorTypes); assertThat(compilation).failed(); } static class Parameterized< Simple, ExtendsClass extends Number, ExtendsInterface extends Runnable, ExtendsTypeVariable extends Simple, Intersection extends Number & Runnable, IntersectionOfInterfaces extends Runnable & Serializable> {} @Test public void getTypeVariableTypeMirror() { List<? extends TypeParameterElement> typeVariables = getElement(Parameterized.class).getTypeParameters(); // Members of converted types use ClassName and not Class<?>. ClassName number = ClassName.get(Number.class); ClassName runnable = ClassName.get(Runnable.class); ClassName serializable = ClassName.get(Serializable.class); assertThat(TypeName.get(typeVariables.get(0).asType())) .isEqualTo(TypeVariableName.get("Simple")); assertThat(TypeName.get(typeVariables.get(1).asType())) .isEqualTo(TypeVariableName.get("ExtendsClass", number)); assertThat(TypeName.get(typeVariables.get(2).asType())) .isEqualTo(TypeVariableName.get("ExtendsInterface", runnable)); assertThat(TypeName.get(typeVariables.get(3).asType())) .isEqualTo(TypeVariableName.get("ExtendsTypeVariable", TypeVariableName.get("Simple"))); assertThat(TypeName.get(typeVariables.get(4).asType())) .isEqualTo(TypeVariableName.get("Intersection", number, runnable)); assertThat(TypeName.get(typeVariables.get(5).asType())) .isEqualTo(TypeVariableName.get("IntersectionOfInterfaces", runnable, serializable)); assertThat(((TypeVariableName) TypeName.get(typeVariables.get(4).asType())).bounds) .containsExactly(number, runnable); } static class Recursive<T extends Map<List<T>, Set<T[]>>> {} @Test public void getTypeVariableTypeMirrorRecursive() { TypeMirror typeMirror = getElement(Recursive.class).asType(); ParameterizedTypeName typeName = (ParameterizedTypeName) TypeName.get(typeMirror); String className = Recursive.class.getCanonicalName(); assertThat(typeName.toString()).isEqualTo(className + "<T>"); TypeVariableName typeVariableName = (TypeVariableName) typeName.typeArguments.get(0); try { typeVariableName.bounds.set(0, null); fail("Expected UnsupportedOperationException"); } catch (UnsupportedOperationException expected) { } assertThat(typeVariableName.toString()).isEqualTo("T"); assertThat(typeVariableName.bounds.toString()) .isEqualTo("[java.util.Map<java.util.List<T>, java.util.Set<T[]>>]"); } @Test public void getPrimitiveTypeMirror() { assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.BOOLEAN))) .isEqualTo(TypeName.BOOLEAN); assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.BYTE))) .isEqualTo(TypeName.BYTE); assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.SHORT))) .isEqualTo(TypeName.SHORT); assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.INT))) .isEqualTo(TypeName.INT); assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.LONG))) .isEqualTo(TypeName.LONG); assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.CHAR))) .isEqualTo(TypeName.CHAR); assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.FLOAT))) .isEqualTo(TypeName.FLOAT); assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.DOUBLE))) .isEqualTo(TypeName.DOUBLE); } @Test public void getArrayTypeMirror() { assertThat(TypeName.get(getTypes().getArrayType(getMirror(Object.class)))) .isEqualTo(ArrayTypeName.of(ClassName.OBJECT)); } @Test public void getVoidTypeMirror() { assertThat(TypeName.get(getTypes().getNoType(TypeKind.VOID))) .isEqualTo(TypeName.VOID); } @Test public void getNullTypeMirror() { try { TypeName.get(getTypes().getNullType()); fail(); } catch (IllegalArgumentException expected) { } } @Test public void parameterizedType() throws Exception { ParameterizedTypeName type = ParameterizedTypeName.get(Map.class, String.class, Long.class); assertThat(type.toString()).isEqualTo("java.util.Map<java.lang.String, java.lang.Long>"); } @Test public void arrayType() throws Exception { ArrayTypeName type = ArrayTypeName.of(String.class); assertThat(type.toString()).isEqualTo("java.lang.String[]"); } @Test public void wildcardExtendsType() throws Exception { WildcardTypeName type = WildcardTypeName.subtypeOf(CharSequence.class); assertThat(type.toString()).isEqualTo("? extends java.lang.CharSequence"); } @Test public void wildcardExtendsObject() throws Exception { WildcardTypeName type = WildcardTypeName.subtypeOf(Object.class); assertThat(type.toString()).isEqualTo("?"); } @Test public void wildcardSuperType() throws Exception { WildcardTypeName type = WildcardTypeName.supertypeOf(String.class); assertThat(type.toString()).isEqualTo("? super java.lang.String"); } @Test public void wildcardMirrorNoBounds() throws Exception { WildcardType wildcard = getTypes().getWildcardType(null, null); TypeName type = TypeName.get(wildcard); assertThat(type.toString()).isEqualTo("?"); } @Test public void wildcardMirrorExtendsType() throws Exception { Types types = getTypes(); Elements elements = getElements(); TypeMirror charSequence = elements.getTypeElement(CharSequence.class.getName()).asType(); WildcardType wildcard = types.getWildcardType(charSequence, null); TypeName type = TypeName.get(wildcard); assertThat(type.toString()).isEqualTo("? extends java.lang.CharSequence"); } @Test public void wildcardMirrorSuperType() throws Exception { Types types = getTypes(); Elements elements = getElements(); TypeMirror string = elements.getTypeElement(String.class.getName()).asType(); WildcardType wildcard = types.getWildcardType(null, string); TypeName type = TypeName.get(wildcard); assertThat(type.toString()).isEqualTo("? super java.lang.String"); } @Test public void typeVariable() throws Exception { TypeVariableName type = TypeVariableName.get("T", CharSequence.class); assertThat(type.toString()).isEqualTo("T"); // (Bounds are only emitted in declaration.) } @Test public void box() throws Exception { assertThat(TypeName.INT.box()).isEqualTo(ClassName.get(Integer.class)); assertThat(TypeName.VOID.box()).isEqualTo(ClassName.get(Void.class)); assertThat(ClassName.get(Integer.class).box()).isEqualTo(ClassName.get(Integer.class)); assertThat(ClassName.get(Void.class).box()).isEqualTo(ClassName.get(Void.class)); assertThat(TypeName.OBJECT.box()).isEqualTo(TypeName.OBJECT); assertThat(ClassName.get(String.class).box()).isEqualTo(ClassName.get(String.class)); } @Test public void unbox() throws Exception { assertThat(TypeName.INT).isEqualTo(TypeName.INT.unbox()); assertThat(TypeName.VOID).isEqualTo(TypeName.VOID.unbox()); assertThat(ClassName.get(Integer.class).unbox()).isEqualTo(TypeName.INT.unbox()); assertThat(ClassName.get(Void.class).unbox()).isEqualTo(TypeName.VOID.unbox()); try { TypeName.OBJECT.unbox(); fail(); } catch (UnsupportedOperationException expected) { } try { ClassName.get(String.class).unbox(); fail(); } catch (UnsupportedOperationException expected) { } } }