Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2008 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 
     17 package com.google.inject.util;
     18 
     19 import static com.google.inject.Asserts.assertContains;
     20 import static com.google.inject.Asserts.assertEqualWhenReserialized;
     21 import static com.google.inject.Asserts.assertEqualsBothWays;
     22 import static com.google.inject.util.Types.subtypeOf;
     23 import static com.google.inject.util.Types.supertypeOf;
     24 
     25 import com.google.inject.TypeLiteral;
     26 import com.google.inject.internal.MoreTypes;
     27 import java.io.IOException;
     28 import java.lang.reflect.GenericArrayType;
     29 import java.lang.reflect.ParameterizedType;
     30 import java.lang.reflect.Type;
     31 import java.lang.reflect.WildcardType;
     32 import java.util.List;
     33 import java.util.Map;
     34 import java.util.Set;
     35 import junit.framework.Assert;
     36 import junit.framework.TestCase;
     37 
     38 /** @author jessewilson (at) google.com (Jesse Wilson) */
     39 public class TypesTest extends TestCase {
     40 
     41   // generic types for comparison
     42   Map<String, Integer> a;
     43   Inner<Float, Double> b;
     44   List<Set<String>[][]> c;
     45   List<String> d;
     46   Set<String> e;
     47   Outer<String>.Inner f;
     48 
     49   private ParameterizedType mapStringInteger;
     50   private ParameterizedType innerFloatDouble;
     51   private ParameterizedType listSetStringArray;
     52   private ParameterizedType listString;
     53   private ParameterizedType setString;
     54   private ParameterizedType outerInner;
     55   private GenericArrayType setStringArray;
     56 
     57   @Override
     58   protected void setUp() throws Exception {
     59     super.setUp();
     60     mapStringInteger = (ParameterizedType) getClass().getDeclaredField("a").getGenericType();
     61     innerFloatDouble = (ParameterizedType) getClass().getDeclaredField("b").getGenericType();
     62     listSetStringArray = (ParameterizedType) getClass().getDeclaredField("c").getGenericType();
     63     listString = (ParameterizedType) getClass().getDeclaredField("d").getGenericType();
     64     setString = (ParameterizedType) getClass().getDeclaredField("e").getGenericType();
     65     outerInner = (ParameterizedType) getClass().getDeclaredField("f").getGenericType();
     66     setStringArray = (GenericArrayType) listSetStringArray.getActualTypeArguments()[0];
     67   }
     68 
     69   public void testListSetMap() {
     70     assertEqualsBothWays(mapStringInteger, Types.mapOf(String.class, Integer.class));
     71     assertEqualsBothWays(listString, Types.listOf(String.class));
     72     assertEqualsBothWays(setString, Types.setOf(String.class));
     73   }
     74 
     75   public void testDefensiveCopies() {
     76     Type[] arguments = new Type[] {String.class, Integer.class};
     77     ParameterizedType parameterizedType = Types.newParameterizedType(Map.class, arguments);
     78     arguments[0] = null;
     79     assertEquals(String.class, parameterizedType.getActualTypeArguments()[0]);
     80     parameterizedType.getActualTypeArguments()[1] = null;
     81     assertEquals(Integer.class, parameterizedType.getActualTypeArguments()[1]);
     82   }
     83 
     84   public void testTypeWithOwnerType() {
     85     ParameterizedType actual =
     86         Types.newParameterizedTypeWithOwner(
     87             TypesTest.class, Inner.class, Float.class, Double.class);
     88     assertEquals(TypesTest.class, actual.getOwnerType());
     89     assertEqualsBothWays(innerFloatDouble, actual);
     90     // The JDK prints this out as:
     91     //     com.google.inject.util.TypesTest.com.google.inject.util.TypesTest$Inner<java.lang.Float, java.lang.Double>
     92     // and we think that's wrong, so the assertEquals comparison is worthless. :-(
     93     //    assertEquals(innerFloatDouble.toString(), actual.toString());
     94 
     95     // We think the correct comparison is:
     96     assertEquals(
     97         "com.google.inject.util.TypesTest$Inner<java.lang.Float, java.lang.Double>",
     98         actual.toString());
     99   }
    100 
    101   public void testTypeParametersMustNotBePrimitives() {
    102     try {
    103       Types.newParameterizedType(Map.class, String.class, int.class);
    104       fail();
    105     } catch (IllegalArgumentException expected) {
    106       assertContains(
    107           expected.getMessage(), "Primitive types are not allowed in type parameters: int");
    108     }
    109   }
    110 
    111   public List<? extends CharSequence> wildcardExtends;
    112   public List<? super CharSequence> wildcardSuper;
    113   public List<?> wildcardObject;
    114 
    115   public void testWildcardTypes() throws NoSuchFieldException, IOException {
    116     assertEqualsBothWays(getWildcard("wildcardSuper"), supertypeOf(CharSequence.class));
    117     assertEqualsBothWays(getWildcard("wildcardExtends"), subtypeOf(CharSequence.class));
    118     assertEqualsBothWays(getWildcard("wildcardObject"), subtypeOf(Object.class));
    119 
    120     assertEquals("? super java.lang.CharSequence", supertypeOf(CharSequence.class).toString());
    121     assertEquals("? extends java.lang.CharSequence", subtypeOf(CharSequence.class).toString());
    122     assertEquals("?", subtypeOf(Object.class).toString());
    123 
    124     assertEqualWhenReserialized(supertypeOf(CharSequence.class));
    125     assertEqualWhenReserialized(subtypeOf(CharSequence.class));
    126   }
    127 
    128   public void testWildcardBoundsMustNotBePrimitives() {
    129     try {
    130       supertypeOf(int.class);
    131       fail();
    132     } catch (IllegalArgumentException expected) {
    133       assertContains(
    134           expected.getMessage(), "Primitive types are not allowed in wildcard bounds: int");
    135     }
    136 
    137     try {
    138       subtypeOf(int.class);
    139       fail();
    140     } catch (IllegalArgumentException expected) {
    141       assertContains(
    142           expected.getMessage(), "Primitive types are not allowed in wildcard bounds: int");
    143     }
    144   }
    145 
    146   private WildcardType getWildcard(String fieldName) throws NoSuchFieldException {
    147     ParameterizedType type = (ParameterizedType) getClass().getField(fieldName).getGenericType();
    148     return (WildcardType) type.getActualTypeArguments()[0];
    149   }
    150 
    151   public void testEqualsAndHashcode() {
    152     ParameterizedType parameterizedType =
    153         Types.newParameterizedType(Map.class, String.class, Integer.class);
    154     assertEqualsBothWays(mapStringInteger, parameterizedType);
    155     assertEquals(mapStringInteger.toString(), parameterizedType.toString());
    156 
    157     GenericArrayType genericArrayType =
    158         Types.arrayOf(Types.arrayOf(Types.newParameterizedType(Set.class, String.class)));
    159     assertEqualsBothWays(setStringArray, genericArrayType);
    160     assertEquals(setStringArray.toString(), genericArrayType.toString());
    161   }
    162 
    163   public void testToString() {
    164     Assert.assertEquals("java.lang.String", MoreTypes.typeToString(String.class));
    165     assertEquals("java.util.Set<java.lang.String>[][]", MoreTypes.typeToString(setStringArray));
    166     assertEquals(
    167         "java.util.Map<java.lang.String, java.lang.Integer>",
    168         MoreTypes.typeToString(mapStringInteger));
    169     assertEquals(
    170         "java.util.List<java.util.Set<java.lang.String>[][]>",
    171         MoreTypes.typeToString(listSetStringArray));
    172     assertEquals(innerFloatDouble.toString(), MoreTypes.typeToString(innerFloatDouble));
    173   }
    174 
    175   static class Owning<A> {}
    176 
    177   /** Ensure that owning types are required when necessary, and forbidden otherwise. */
    178   public void testCanonicalizeRequiresOwnerTypes() {
    179     try {
    180       Types.newParameterizedType(Owning.class, String.class);
    181       fail();
    182     } catch (IllegalArgumentException expected) {
    183       assertContains(expected.getMessage(), "No owner type for enclosed " + Owning.class);
    184     }
    185 
    186     try {
    187       Types.newParameterizedTypeWithOwner(Object.class, Set.class, String.class);
    188       fail("Expected IllegalArgumentException");
    189     } catch (IllegalArgumentException expected) {
    190       assertContains(expected.getMessage(), "Owner type for unenclosed " + Set.class);
    191     }
    192   }
    193 
    194   @SuppressWarnings("UnusedDeclaration")
    195   class Inner<T1, T2> {}
    196 
    197   public void testInnerParameterizedEvenWithZeroArgs() {
    198     TypeLiteral<Outer<String>.Inner> type = new TypeLiteral<Outer<String>.Inner>() {};
    199     assertEqualsBothWays(outerInner, type.getType());
    200 
    201     ParameterizedType parameterizedType = (ParameterizedType) type.getType();
    202     assertEquals(0, parameterizedType.getActualTypeArguments().length);
    203     assertEquals(new TypeLiteral<Outer<String>>() {}.getType(), parameterizedType.getOwnerType());
    204     assertEquals(Outer.Inner.class, parameterizedType.getRawType());
    205   }
    206 
    207   static class Outer<T> {
    208     @SuppressWarnings("ClassCanBeStatic")
    209     class Inner {}
    210   }
    211 }
    212