• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
called(String id)47   private void called(String id) {
48     calls.add(id);
49   }
50 
getCalls()51   protected String getCalls() {
52     return calls.toString();
53   }
54 
isCalled()55   protected boolean isCalled() {
56     return !calls.isEmpty();
57   }
58 
59   @SuppressWarnings("unchecked")
createProxyInstance(Class<T> c)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    */
asString(Method method)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 
getDefaultValue(Class<?> returnType)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 
callAllPublicMethods(Class<T> theClass, T object)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