Home | History | Annotate | Download | only in mocking
      1 /*
      2  * Copyright 2010 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 package com.google.android.testing.mocking;
     17 
     18 import javassist.CannotCompileException;
     19 import javassist.ClassPool;
     20 import javassist.CtClass;
     21 import javassist.CtMethod;
     22 import javassist.NotFoundException;
     23 
     24 import junit.framework.TestCase;
     25 
     26 import java.io.ByteArrayInputStream;
     27 import java.io.IOException;
     28 import java.lang.reflect.Method;
     29 import java.util.ArrayList;
     30 import java.util.Arrays;
     31 import java.util.HashMap;
     32 import java.util.List;
     33 import java.util.Map;
     34 
     35 
     36 /**
     37  * Various tests that verify that different types of Classes are handled
     38  * correctly.
     39  *
     40  * @author swoodward (at) google.com (Stephen Woodward)
     41  */
     42 public class ClassTypeTests extends TestCase {
     43   private AndroidMockGenerator androidMockGenerator = new AndroidMockGenerator();
     44 
     45   private AndroidMockGenerator getAndroidMockGenerator() {
     46     return androidMockGenerator;
     47   }
     48 
     49   private void assertAllMethodNames(List<String> expectedNames,
     50       Map<String, List<String>> expectedMethods, List<GeneratedClassFile> classes)
     51       throws IOException {
     52     for (GeneratedClassFile clazz : classes) {
     53       assertTrue(expectedNames.contains(clazz.getClassName()));
     54       assertUnorderedContentsSame(expectedMethods.get(clazz.getClassName()), getMethodNames(clazz));
     55     }
     56   }
     57 
     58   private <T> void assertUnorderedContentsSame(Iterable<T> expected, Iterable<T> actual) {
     59     List<T> missingItems = new ArrayList<T>();
     60     List<T> extraItems = new ArrayList<T>();
     61     for (T item : expected) {
     62       missingItems.add(item);
     63     }
     64     for (T item : actual) {
     65       missingItems.remove(item);
     66       extraItems.add(item);
     67     }
     68     for (T item : expected) {
     69       extraItems.remove(item);
     70     }
     71     if (missingItems.size() + extraItems.size() != 0) {
     72       String errorMessage =
     73           "Contents were different. Missing: " + Arrays.toString(missingItems.toArray())
     74               + " Extra: " + Arrays.toString(extraItems.toArray());
     75       fail(errorMessage);
     76     }
     77   }
     78 
     79   private List<String> getExpectedNames(Class<?> clazz) {
     80     return new ArrayList<String>(Arrays.asList(new String[] {
     81         "genmocks." + clazz.getCanonicalName() + "DelegateInterface",
     82         "genmocks." + clazz.getCanonicalName() + "DelegateSubclass"}));
     83   }
     84 
     85   private Iterable<String> getMethodNames(GeneratedClassFile clazz) throws IOException {
     86     ByteArrayInputStream classInputStream = new ByteArrayInputStream(clazz.getContents());
     87     CtClass ctClass;
     88     try {
     89       ctClass = ClassPool.getDefault().getCtClass(clazz.getClassName());
     90       if (ctClass.isFrozen()) {
     91         ctClass.defrost();
     92       }
     93     } catch (NotFoundException e) {
     94       // That's ok, we're just defrosting any classes that affect us that were created
     95       // by other tests.  NotFoundException implies the class is not frozen.
     96     }
     97     ctClass = ClassPool.getDefault().makeClass(classInputStream);
     98     return getMethodNames(ctClass.getDeclaredMethods());
     99   }
    100 
    101   private List<String> getMethodNames(CtMethod[] methods) {
    102     List<String> methodNames = new ArrayList<String>();
    103     for (CtMethod method : methods) {
    104       methodNames.add(method.getName());
    105     }
    106     return methodNames;
    107   }
    108 
    109   private List<String> getMethodNames(Method[] methods, String[] exclusions) {
    110     List<String> methodNames = new ArrayList<String>();
    111     for (Method method : methods) {
    112       if (!Arrays.asList(exclusions).contains(method.getName())) {
    113         methodNames.add(method.getName());
    114       }
    115     }
    116     return methodNames;
    117   }
    118 
    119   private Map<String, List<String>> getExpectedMethodsMap(List<String> expectedNames,
    120       Class<?> clazz) {
    121     return getExpectedMethodsMap(expectedNames, clazz, new String[0]);
    122   }
    123 
    124   private Map<String, List<String>> getExpectedMethodsMap(List<String> expectedNames,
    125       Class<?> clazz, String[] exclusions) {
    126     Map<String, List<String>> expectedMethods = new HashMap<String, List<String>>();
    127     expectedMethods.put(expectedNames.get(0), new ArrayList<String>(Arrays.asList(new String[] {
    128         "finalize", "clone"})));
    129     expectedMethods.put(expectedNames.get(1), new ArrayList<String>(Arrays.asList(new String[] {
    130         "finalize", "clone", "setDelegate___AndroidMock", "getDelegate___AndroidMock"})));
    131     expectedMethods.get(expectedNames.get(0)).addAll(
    132         getMethodNames(clazz.getDeclaredMethods(), exclusions));
    133     expectedMethods.get(expectedNames.get(1)).addAll(
    134         getMethodNames(clazz.getDeclaredMethods(), exclusions));
    135     return expectedMethods;
    136   }
    137 
    138   public void testClassIsDuplicate() throws ClassNotFoundException, IOException,
    139       CannotCompileException {
    140     List<GeneratedClassFile> classList =
    141         getAndroidMockGenerator().createMocksForClass(Object.class);
    142     List<GeneratedClassFile> secondClassList =
    143         getAndroidMockGenerator().createMocksForClass(Object.class);
    144     assertEquals(classList, secondClassList);
    145   }
    146 
    147   public void testClassHasDelegateMethods() throws ClassNotFoundException, IOException,
    148       CannotCompileException {
    149     List<String> expectedNames = getExpectedNames(ClassHasDelegateMethods.class);
    150     Map<String, List<String>> expectedMethods =
    151         getExpectedMethodsMap(expectedNames, ClassHasDelegateMethods.class,
    152             new String[] {"getDelegate___AndroidMock"});
    153     // This use case doesn't fit our util in any nice way, so just tweak it.
    154     expectedMethods.get(
    155         "genmocks.com.google.android.testing.mocking.ClassHasDelegateMethodsDelegateInterface")
    156         .add("getDelegate___AndroidMock");
    157 
    158     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    159     List<GeneratedClassFile> classes =
    160         mockGenerator.createMocksForClass(ClassHasDelegateMethods.class);
    161     assertEquals(2, classes.size());
    162     assertAllMethodNames(expectedNames, expectedMethods, classes);
    163   }
    164 
    165   public void testClassHasFinalMethods() throws ClassNotFoundException, IOException,
    166       CannotCompileException {
    167     List<String> expectedNames = getExpectedNames(ClassHasFinalMethods.class);
    168     Map<String, List<String>> expectedMethods =
    169         getExpectedMethodsMap(expectedNames, ClassHasFinalMethods.class, new String[] {"foo",
    170             "foobar"});
    171 
    172     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    173     List<GeneratedClassFile> classes =
    174         mockGenerator.createMocksForClass(ClassHasFinalMethods.class);
    175     assertEquals(2, classes.size());
    176     assertAllMethodNames(expectedNames, expectedMethods, classes);
    177   }
    178 
    179   public void testClassHasNoDefaultConstructor() throws ClassNotFoundException, IOException,
    180       CannotCompileException {
    181     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    182     List<GeneratedClassFile> classes =
    183         mockGenerator.createMocksForClass(ClassHasNoDefaultConstructor.class);
    184     assertEquals(2, classes.size());
    185   }
    186 
    187   public void testClassHasNoPublicConstructors() throws ClassNotFoundException, IOException,
    188       CannotCompileException {
    189     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    190     List<GeneratedClassFile> classes =
    191         mockGenerator.createMocksForClass(ClassHasNoPublicConstructors.class);
    192     assertEquals(0, classes.size());
    193   }
    194 
    195   public void testClassHasOverloadedMethods() throws ClassNotFoundException, IOException,
    196       CannotCompileException {
    197     List<String> expectedNames = getExpectedNames(ClassHasOverloadedMethods.class);
    198     Map<String, List<String>> expectedMethods =
    199         getExpectedMethodsMap(expectedNames, ClassHasOverloadedMethods.class);
    200 
    201     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    202     List<GeneratedClassFile> classes =
    203         mockGenerator.createMocksForClass(ClassHasOverloadedMethods.class);
    204     assertEquals(2, classes.size());
    205     assertAllMethodNames(expectedNames, expectedMethods, classes);
    206   }
    207 
    208   public void testClassHasStaticMethods() throws ClassNotFoundException, IOException,
    209       CannotCompileException {
    210     List<String> expectedNames = getExpectedNames(ClassHasStaticMethods.class);
    211     Map<String, List<String>> expectedMethods =
    212         getExpectedMethodsMap(expectedNames, ClassHasStaticMethods.class,
    213             new String[] {"staticFoo"});
    214 
    215     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    216     List<GeneratedClassFile> classes =
    217         mockGenerator.createMocksForClass(ClassHasStaticMethods.class);
    218     assertEquals(2, classes.size());
    219     assertAllMethodNames(expectedNames, expectedMethods, classes);
    220   }
    221 
    222   public void testClassIsAnnotation() throws ClassNotFoundException, IOException,
    223       CannotCompileException {
    224     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    225     List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsAnnotation.class);
    226     assertEquals(0, classes.size());
    227   }
    228 
    229   public void testClassIsEnum() throws ClassNotFoundException, IOException, CannotCompileException {
    230     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    231     List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsEnum.class);
    232     assertEquals(0, classes.size());
    233   }
    234 
    235   public void testClassIsFinal() throws ClassNotFoundException, IOException,
    236       CannotCompileException {
    237     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    238     List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsFinal.class);
    239     assertEquals(0, classes.size());
    240   }
    241 
    242   public void testClassIsInterface() throws ClassNotFoundException, IOException,
    243       CannotCompileException {
    244     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    245     List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsInterface.class);
    246     assertEquals(0, classes.size());
    247   }
    248 
    249   public void testClassIsArray() throws ClassNotFoundException, IOException,
    250       CannotCompileException {
    251     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    252     List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Object[].class);
    253     assertEquals(0, classes.size());
    254   }
    255 
    256   public void testClassIsNormal() throws ClassNotFoundException, IOException,
    257       CannotCompileException {
    258     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    259     List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Object.class);
    260     assertEquals(2, classes.size());
    261   }
    262 
    263   public void testClassIsPrimitive() throws ClassNotFoundException, IOException,
    264       CannotCompileException {
    265     AndroidMockGenerator mockGenerator = getAndroidMockGenerator();
    266     List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Integer.TYPE);
    267     assertEquals(0, classes.size());
    268   }
    269 }
    270