11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2007 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.collect;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Function;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Joiner;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
220888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport junit.framework.TestCase;
230888a09821a98ac0680fad765217302858e70fa4Paul Duffin
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.reflect.Array;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.reflect.InvocationHandler;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.reflect.InvocationTargetException;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.reflect.Method;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.reflect.Proxy;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.ArrayList;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Arrays;
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collection;
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collections;
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Iterator;
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.List;
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Set;
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Base test case for testing the variety of forwarding classes.
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Robert Konigsberg
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Louis Wasserman
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic abstract class ForwardingTestCase extends TestCase {
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
457dd252788645e940eada959bdde927426e2531c9Paul Duffin  private final List<String> calls = new ArrayList<String>();
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private void called(String id) {
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    calls.add(id);
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected String getCalls() {
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return calls.toString();
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected boolean isCalled() {
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return !calls.isEmpty();
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("unchecked")
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected <T> T createProxyInstance(Class<T> c) {
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /*
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * This invocation handler only registers that a method was called,
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * and then returns a bogus, but acceptable, value.
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    InvocationHandler handler = new InvocationHandler() {
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public Object invoke(Object proxy, Method method, Object[] args)
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          throws Throwable {
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        called(asString(method));
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return getDefaultValue(method.getReturnType());
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return (T) Proxy.newProxyInstance(c.getClassLoader(),
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new Class[] { c }, handler);
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final Joiner COMMA_JOINER = Joiner.on(",");
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /*
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns string representation of a method.
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * If the method takes no parameters, it returns the name (e.g.
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * "isEmpty". If the method takes parameters, it returns the simple names
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * of the parameters (e.g. "put(Object,Object)".)
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private String asString(Method method) {
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    String methodName = method.getName();
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Class<?>[] parameterTypes = method.getParameterTypes();
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (parameterTypes.length == 0) {
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return methodName;
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Iterable<String> parameterNames = Iterables.transform(
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Arrays.asList(parameterTypes),
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new Function<Class<?>, String>() {
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          @Override
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          public String apply(Class<?> from) {
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            return from.getSimpleName();
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    });
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return methodName + "(" + COMMA_JOINER.join(parameterNames) + ")";
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static Object getDefaultValue(Class<?> returnType) {
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (returnType == boolean.class || returnType == Boolean.class) {
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return Boolean.FALSE;
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } else if (returnType == int.class || returnType == Integer.class) {
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return 0;
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } else if ((returnType == Set.class) || (returnType == Collection.class)) {
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return Collections.emptySet();
1140888a09821a98ac0680fad765217302858e70fa4Paul Duffin    } else if (returnType == Iterator.class) {
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return Iterators.emptyModifiableIterator();
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } else if (returnType.isArray()) {
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return Array.newInstance(returnType.getComponentType(), 0);
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } else {
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return null;
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected static <T> void callAllPublicMethods(Class<T> theClass, T object)
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throws InvocationTargetException {
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (Method method : theClass.getMethods()) {
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Class<?>[] parameterTypes = method.getParameterTypes();
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object[] parameters = new Object[parameterTypes.length];
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 0; i < parameterTypes.length; i++) {
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        parameters[i] = getDefaultValue(parameterTypes[i]);
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          method.invoke(object, parameters);
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } catch (InvocationTargetException ex) {
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          try {
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            throw ex.getCause();
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          } catch (UnsupportedOperationException unsupported) {
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            // this is a legit exception
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (Throwable cause) {
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new InvocationTargetException(cause,
1430888a09821a98ac0680fad765217302858e70fa4Paul Duffin            method + " with args: " + Arrays.toString(parameters));
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
148