| /* |
| * Copyright 2010 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.google.android.testing.mocking; |
| |
| import javassist.CannotCompileException; |
| import javassist.ClassPool; |
| import javassist.CtClass; |
| import javassist.CtMethod; |
| import javassist.NotFoundException; |
| |
| import junit.framework.TestCase; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| |
| /** |
| * Various tests that verify that different types of Classes are handled |
| * correctly. |
| * |
| * @author swoodward@google.com (Stephen Woodward) |
| */ |
| public class ClassTypeTests extends TestCase { |
| private AndroidMockGenerator androidMockGenerator = new AndroidMockGenerator(); |
| |
| private AndroidMockGenerator getAndroidMockGenerator() { |
| return androidMockGenerator; |
| } |
| |
| private void assertAllMethodNames(List<String> expectedNames, |
| Map<String, List<String>> expectedMethods, List<GeneratedClassFile> classes) |
| throws IOException { |
| for (GeneratedClassFile clazz : classes) { |
| assertTrue(expectedNames.contains(clazz.getClassName())); |
| assertUnorderedContentsSame(expectedMethods.get(clazz.getClassName()), getMethodNames(clazz)); |
| } |
| } |
| |
| private <T> void assertUnorderedContentsSame(Iterable<T> expected, Iterable<T> actual) { |
| List<T> missingItems = new ArrayList<T>(); |
| List<T> extraItems = new ArrayList<T>(); |
| for (T item : expected) { |
| missingItems.add(item); |
| } |
| for (T item : actual) { |
| missingItems.remove(item); |
| extraItems.add(item); |
| } |
| for (T item : expected) { |
| extraItems.remove(item); |
| } |
| if (missingItems.size() + extraItems.size() != 0) { |
| String errorMessage = |
| "Contents were different. Missing: " + Arrays.toString(missingItems.toArray()) |
| + " Extra: " + Arrays.toString(extraItems.toArray()); |
| fail(errorMessage); |
| } |
| } |
| |
| private List<String> getExpectedNames(Class<?> clazz) { |
| return new ArrayList<String>(Arrays.asList(new String[] { |
| "genmocks." + clazz.getCanonicalName() + "DelegateInterface", |
| "genmocks." + clazz.getCanonicalName() + "DelegateSubclass"})); |
| } |
| |
| private Iterable<String> getMethodNames(GeneratedClassFile clazz) throws IOException { |
| ByteArrayInputStream classInputStream = new ByteArrayInputStream(clazz.getContents()); |
| CtClass ctClass; |
| try { |
| ctClass = ClassPool.getDefault().getCtClass(clazz.getClassName()); |
| if (ctClass.isFrozen()) { |
| ctClass.defrost(); |
| } |
| } catch (NotFoundException e) { |
| // That's ok, we're just defrosting any classes that affect us that were created |
| // by other tests. NotFoundException implies the class is not frozen. |
| } |
| ctClass = ClassPool.getDefault().makeClass(classInputStream); |
| return getMethodNames(ctClass.getDeclaredMethods()); |
| } |
| |
| private List<String> getMethodNames(CtMethod[] methods) { |
| List<String> methodNames = new ArrayList<String>(); |
| for (CtMethod method : methods) { |
| methodNames.add(method.getName()); |
| } |
| return methodNames; |
| } |
| |
| private List<String> getMethodNames(Method[] methods, String[] exclusions) { |
| List<String> methodNames = new ArrayList<String>(); |
| for (Method method : methods) { |
| if (!Arrays.asList(exclusions).contains(method.getName())) { |
| methodNames.add(method.getName()); |
| } |
| } |
| return methodNames; |
| } |
| |
| private Map<String, List<String>> getExpectedMethodsMap(List<String> expectedNames, |
| Class<?> clazz) { |
| return getExpectedMethodsMap(expectedNames, clazz, new String[0]); |
| } |
| |
| private Map<String, List<String>> getExpectedMethodsMap(List<String> expectedNames, |
| Class<?> clazz, String[] exclusions) { |
| Map<String, List<String>> expectedMethods = new HashMap<String, List<String>>(); |
| expectedMethods.put(expectedNames.get(0), new ArrayList<String>(Arrays.asList(new String[] { |
| "finalize", "clone"}))); |
| expectedMethods.put(expectedNames.get(1), new ArrayList<String>(Arrays.asList(new String[] { |
| "finalize", "clone", "setDelegate___AndroidMock", "getDelegate___AndroidMock"}))); |
| expectedMethods.get(expectedNames.get(0)).addAll( |
| getMethodNames(clazz.getDeclaredMethods(), exclusions)); |
| expectedMethods.get(expectedNames.get(1)).addAll( |
| getMethodNames(clazz.getDeclaredMethods(), exclusions)); |
| return expectedMethods; |
| } |
| |
| public void testClassIsDuplicate() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| List<GeneratedClassFile> classList = |
| getAndroidMockGenerator().createMocksForClass(Object.class); |
| List<GeneratedClassFile> secondClassList = |
| getAndroidMockGenerator().createMocksForClass(Object.class); |
| assertEquals(classList, secondClassList); |
| } |
| |
| public void testClassHasDelegateMethods() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| List<String> expectedNames = getExpectedNames(ClassHasDelegateMethods.class); |
| Map<String, List<String>> expectedMethods = |
| getExpectedMethodsMap(expectedNames, ClassHasDelegateMethods.class, |
| new String[] {"getDelegate___AndroidMock"}); |
| // This use case doesn't fit our util in any nice way, so just tweak it. |
| expectedMethods.get( |
| "genmocks.com.google.android.testing.mocking.ClassHasDelegateMethodsDelegateInterface") |
| .add("getDelegate___AndroidMock"); |
| |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = |
| mockGenerator.createMocksForClass(ClassHasDelegateMethods.class); |
| assertEquals(2, classes.size()); |
| assertAllMethodNames(expectedNames, expectedMethods, classes); |
| } |
| |
| public void testClassHasFinalMethods() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| List<String> expectedNames = getExpectedNames(ClassHasFinalMethods.class); |
| Map<String, List<String>> expectedMethods = |
| getExpectedMethodsMap(expectedNames, ClassHasFinalMethods.class, new String[] {"foo", |
| "foobar"}); |
| |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = |
| mockGenerator.createMocksForClass(ClassHasFinalMethods.class); |
| assertEquals(2, classes.size()); |
| assertAllMethodNames(expectedNames, expectedMethods, classes); |
| } |
| |
| public void testClassHasNoDefaultConstructor() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = |
| mockGenerator.createMocksForClass(ClassHasNoDefaultConstructor.class); |
| assertEquals(2, classes.size()); |
| } |
| |
| public void testClassHasNoPublicConstructors() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = |
| mockGenerator.createMocksForClass(ClassHasNoPublicConstructors.class); |
| assertEquals(0, classes.size()); |
| } |
| |
| public void testClassHasOverloadedMethods() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| List<String> expectedNames = getExpectedNames(ClassHasOverloadedMethods.class); |
| Map<String, List<String>> expectedMethods = |
| getExpectedMethodsMap(expectedNames, ClassHasOverloadedMethods.class); |
| |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = |
| mockGenerator.createMocksForClass(ClassHasOverloadedMethods.class); |
| assertEquals(2, classes.size()); |
| assertAllMethodNames(expectedNames, expectedMethods, classes); |
| } |
| |
| public void testClassHasStaticMethods() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| List<String> expectedNames = getExpectedNames(ClassHasStaticMethods.class); |
| Map<String, List<String>> expectedMethods = |
| getExpectedMethodsMap(expectedNames, ClassHasStaticMethods.class, |
| new String[] {"staticFoo"}); |
| |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = |
| mockGenerator.createMocksForClass(ClassHasStaticMethods.class); |
| assertEquals(2, classes.size()); |
| assertAllMethodNames(expectedNames, expectedMethods, classes); |
| } |
| |
| public void testClassIsAnnotation() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsAnnotation.class); |
| assertEquals(0, classes.size()); |
| } |
| |
| public void testClassIsEnum() throws ClassNotFoundException, IOException, CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsEnum.class); |
| assertEquals(0, classes.size()); |
| } |
| |
| public void testClassIsFinal() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsFinal.class); |
| assertEquals(0, classes.size()); |
| } |
| |
| public void testClassIsInterface() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(ClassIsInterface.class); |
| assertEquals(0, classes.size()); |
| } |
| |
| public void testClassIsArray() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Object[].class); |
| assertEquals(0, classes.size()); |
| } |
| |
| public void testClassIsNormal() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Object.class); |
| assertEquals(2, classes.size()); |
| } |
| |
| public void testClassIsPrimitive() throws ClassNotFoundException, IOException, |
| CannotCompileException { |
| AndroidMockGenerator mockGenerator = getAndroidMockGenerator(); |
| List<GeneratedClassFile> classes = mockGenerator.createMocksForClass(Integer.TYPE); |
| assertEquals(0, classes.size()); |
| } |
| } |