1 /* 2 * Copyright (C) 2007 The Guava Authors 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.common.collect; 18 19 import com.google.common.base.Function; 20 import com.google.common.base.Joiner; 21 22 import junit.framework.TestCase; 23 24 import java.lang.reflect.Array; 25 import java.lang.reflect.InvocationHandler; 26 import java.lang.reflect.InvocationTargetException; 27 import java.lang.reflect.Method; 28 import java.lang.reflect.Proxy; 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 import java.util.Collection; 32 import java.util.Collections; 33 import java.util.Iterator; 34 import java.util.List; 35 import java.util.Set; 36 37 /** 38 * Base test case for testing the variety of forwarding classes. 39 * 40 * @author Robert Konigsberg 41 * @author Louis Wasserman 42 */ 43 public abstract class ForwardingTestCase extends TestCase { 44 45 private List<String> calls = new ArrayList<String>(); 46 47 private void called(String id) { 48 calls.add(id); 49 } 50 51 protected String getCalls() { 52 return calls.toString(); 53 } 54 55 protected boolean isCalled() { 56 return !calls.isEmpty(); 57 } 58 59 @SuppressWarnings("unchecked") 60 protected <T> T createProxyInstance(Class<T> c) { 61 /* 62 * This invocation handler only registers that a method was called, 63 * and then returns a bogus, but acceptable, value. 64 */ 65 InvocationHandler handler = new InvocationHandler() { 66 @Override 67 public Object invoke(Object proxy, Method method, Object[] args) 68 throws Throwable { 69 called(asString(method)); 70 71 return getDefaultValue(method.getReturnType()); 72 } 73 }; 74 75 return (T) Proxy.newProxyInstance(c.getClassLoader(), 76 new Class[] { c }, handler); 77 } 78 79 private static final Joiner COMMA_JOINER = Joiner.on(","); 80 81 /* 82 * Returns string representation of a method. 83 * 84 * If the method takes no parameters, it returns the name (e.g. 85 * "isEmpty". If the method takes parameters, it returns the simple names 86 * of the parameters (e.g. "put(Object,Object)".) 87 */ 88 private String asString(Method method) { 89 String methodName = method.getName(); 90 Class<?>[] parameterTypes = method.getParameterTypes(); 91 92 if (parameterTypes.length == 0) { 93 return methodName; 94 } 95 96 Iterable<String> parameterNames = Iterables.transform( 97 Arrays.asList(parameterTypes), 98 new Function<Class<?>, String>() { 99 @Override 100 public String apply(Class<?> from) { 101 return from.getSimpleName(); 102 } 103 }); 104 return methodName + "(" + COMMA_JOINER.join(parameterNames) + ")"; 105 } 106 107 private static Object getDefaultValue(Class<?> returnType) { 108 if (returnType == boolean.class || returnType == Boolean.class) { 109 return Boolean.FALSE; 110 } else if (returnType == int.class || returnType == Integer.class) { 111 return 0; 112 } else if ((returnType == Set.class) || (returnType == Collection.class)) { 113 return Collections.emptySet(); 114 } else if (returnType == Iterator.class){ 115 return Iterators.emptyModifiableIterator(); 116 } else if (returnType.isArray()) { 117 return Array.newInstance(returnType.getComponentType(), 0); 118 } else { 119 return null; 120 } 121 } 122 123 protected static <T> void callAllPublicMethods(Class<T> theClass, T object) 124 throws InvocationTargetException { 125 for (Method method : theClass.getMethods()) { 126 Class<?>[] parameterTypes = method.getParameterTypes(); 127 Object[] parameters = new Object[parameterTypes.length]; 128 for (int i = 0; i < parameterTypes.length; i++) { 129 parameters[i] = getDefaultValue(parameterTypes[i]); 130 } 131 try { 132 try { 133 method.invoke(object, parameters); 134 } catch (InvocationTargetException ex) { 135 try { 136 throw ex.getCause(); 137 } catch (UnsupportedOperationException unsupported) { 138 // this is a legit exception 139 } 140 } 141 } catch (Throwable cause) { 142 throw new InvocationTargetException(cause, 143 method.toString() + " with args: " + Arrays.toString(parameters)); 144 } 145 } 146 } 147 } 148