content: /*
   * Copyright (C) 2011 The Android Open Source Project
   *
   * 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.
   */
  import java.lang.reflect.*;
  
  public class ReturnsAndArgPassing {
  
    public static final String testName = "ReturnsAndArgPassing";
  
    static void check(boolean x) {
      if (!x) {
        throw new AssertionError(testName + " Check failed");
      }
    }
  
    interface MyInterface {
      void voidFoo();
      void voidBar();
      boolean booleanFoo();
      boolean booleanBar();
      byte byteFoo();
      byte byteBar();
      char charFoo();
      char charBar();
      short shortFoo();
      short shortBar();
      int intFoo();
      int intBar();
      long longFoo();
      long longBar();
      float floatFoo();
      float floatBar();
      double doubleFoo();
      double doubleBar();
      Object selectArg(int select, int a, long b, float c, double d, Object x);
    }
  
    static int fooInvocations = 0;
    static int barInvocations = 0;
  
    static class MyInvocationHandler implements InvocationHandler {
      boolean causeNpeOnReturn = false;
      Class<?> returnType = null;
      public Object invoke(Object proxy, Method method, Object[] args) {
        check(proxy instanceof Proxy);
        check(method.getDeclaringClass() == MyInterface.class);
        String name = method.getName();
        // Check for moving GC bugs in proxy stubs.
        Runtime.getRuntime().gc();
        if (name.endsWith("Foo")) {
          check(args == null);
          fooInvocations++;
        } else if (name.endsWith("Bar")) {
          check(args == null);
          barInvocations++;
        }
        if (causeNpeOnReturn) {
          return null;
        } else if (name.equals("voidFoo") || name.equals("voidBar")) {
          return null;
        } else if (name.equals("booleanFoo")) {
          return true;
        } else if (name.equals("booleanBar")) {
          return false;
        } else if (name.equals("selectArg")) {
          check(args.length == 6);
          int select = (Integer)args[0];
          return args[select];
        } else {
          try {
            if (name.endsWith("Foo")) {
              return returnType.getField("MAX_VALUE").get(null);
            } else {
              check(name.endsWith("Bar"));
              return returnType.getField("MIN_VALUE").get(null);
            }
          } catch (Exception e) {
            throw new Error("return type = " + returnType, e);
          }
        }
      }
    }
  
    static void testProxyReturns() {
      System.out.println(testName + ".testProxyReturns RUNNING");
      MyInvocationHandler myHandler = new MyInvocationHandler();
      MyInterface proxyMyInterface =
          (MyInterface)Proxy.newProxyInstance(ReturnsAndArgPassing.class.getClassLoader(),
                                              new Class[] { MyInterface.class },
                                              myHandler);
      check(fooInvocations == 0);
      proxyMyInterface.voidFoo();
      check(fooInvocations == 1);
  
      check(barInvocations == 0);
      proxyMyInterface.voidBar();
      check(barInvocations == 1);
  
      check(fooInvocations == 1);
      myHandler.returnType = Boolean.class;
      check(proxyMyInterface.booleanFoo() == true);
      check(fooInvocations == 2);
  
      check(barInvocations == 1);
      check(proxyMyInterface.booleanBar() == false);
      check(barInvocations == 2);
  
      check(fooInvocations == 2);
      myHandler.returnType = Byte.class;
      check(proxyMyInterface.byteFoo() == Byte.MAX_VALUE);
      check(fooInvocations == 3);
  
      check(barInvocations == 2);
      check(proxyMyInterface.byteBar() == Byte.MIN_VALUE);
      check(barInvocations == 3);
  
      check(fooInvocations == 3);
      myHandler.returnType = Character.class;
      check(proxyMyInterface.charFoo() == Character.MAX_VALUE);
      check(fooInvocations == 4);
  
      check(barInvocations == 3);
      check(proxyMyInterface.charBar() == Character.MIN_VALUE);
      check(barInvocations == 4);
  
      check(fooInvocations == 4);
      myHandler.returnType = Short.class;
      check(proxyMyInterface.shortFoo() == Short.MAX_VALUE);
      check(fooInvocations == 5);
  
      check(barInvocations == 4);
      check(proxyMyInterface.shortBar() == Short.MIN_VALUE);
      check(barInvocations == 5);
  
      check(fooInvocations == 5);
      myHandler.returnType = Integer.class;
      check(proxyMyInterface.intFoo() == Integer.MAX_VALUE);
      check(fooInvocations == 6);
  
      check(barInvocations == 5);
      check(proxyMyInterface.intBar() == Integer.MIN_VALUE);
      check(barInvocations == 6);
  
      check(fooInvocations == 6);
      myHandler.returnType = Long.class;
      check(proxyMyInterface.longFoo() == Long.MAX_VALUE);
      check(fooInvocations == 7);
  
      check(barInvocations == 6);
      check(proxyMyInterface.longBar() == Long.MIN_VALUE);
      check(barInvocations == 7);
  
      check(fooInvocations == 7);
      myHandler.returnType = Float.class;
      check(proxyMyInterface.floatFoo() == Float.MAX_VALUE);
      check(fooInvocations == 8);
  
      check(barInvocations == 7);
      check(proxyMyInterface.floatBar() == Float.MIN_VALUE);
      check(barInvocations == 8);
  
      check(fooInvocations == 8);
      myHandler.returnType = Double.class;
      check(proxyMyInterface.doubleFoo() == Double.MAX_VALUE);
      check(fooInvocations == 9);
  
      check(barInvocations == 8);
      check(proxyMyInterface.doubleBar() == Double.MIN_VALUE);
      check(barInvocations == 9);
  
      // Toggle flag to get return values to cause NPEs
      myHandler.causeNpeOnReturn = true;
  
      check(fooInvocations == 9);
      try {
          proxyMyInterface.booleanFoo();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(fooInvocations == 10);
  
      check(barInvocations == 9);
      try {
          proxyMyInterface.booleanBar();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(barInvocations == 10);
  
      check(fooInvocations == 10);
      try {
          proxyMyInterface.byteFoo();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(fooInvocations == 11);
  
      check(barInvocations == 10);
      try {
          proxyMyInterface.byteBar();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(barInvocations == 11);
  
      check(fooInvocations == 11);
      try {
          proxyMyInterface.charFoo();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(fooInvocations == 12);
  
      check(barInvocations == 11);
      try {
          proxyMyInterface.charBar();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(barInvocations == 12);
  
      check(fooInvocations == 12);
      try {
          proxyMyInterface.shortFoo();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(fooInvocations == 13);
  
      check(barInvocations == 12);
      try {
          proxyMyInterface.shortBar();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(barInvocations == 13);
  
      check(fooInvocations == 13);
      try {
          proxyMyInterface.intFoo();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(fooInvocations == 14);
  
      check(barInvocations == 13);
      try {
          proxyMyInterface.intBar();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(barInvocations == 14);
  
      check(fooInvocations == 14);
      try {
          proxyMyInterface.longFoo();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(fooInvocations == 15);
  
      check(barInvocations == 14);
      try {
          proxyMyInterface.longBar();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(barInvocations == 15);
  
      check(fooInvocations == 15);
      try {
          proxyMyInterface.floatFoo();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(fooInvocations == 16);
  
      check(barInvocations == 15);
      try {
          proxyMyInterface.floatBar();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(barInvocations == 16);
  
      check(fooInvocations == 16);
      try {
          proxyMyInterface.doubleFoo();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(fooInvocations == 17);
  
      check(barInvocations == 16);
      try {
          proxyMyInterface.doubleBar();
          throw new AssertionError("Expected NPE");
      } catch (NullPointerException e) {
      }
      check(barInvocations == 17);
  
      // Toggle flag to stop NPEs
      myHandler.causeNpeOnReturn = false;
  
      check(fooInvocations == 17);
      myHandler.returnType = Double.class;  // Double -> byte == fail
      try {
          proxyMyInterface.byteFoo();
          throw new AssertionError("Expected ClassCastException");
      } catch (ClassCastException e) {
      }
      check(fooInvocations == 18);
  
      check(barInvocations == 17);
      try {
          proxyMyInterface.byteBar();
          throw new AssertionError("Expected NPE");
      } catch (ClassCastException e) {
      }
      check(barInvocations == 18);
  
      check(fooInvocations == 18);
      myHandler.returnType = Float.class;  // Float -> byte == fail
      try {
          proxyMyInterface.byteFoo();
          throw new AssertionError("Expected ClassCastException");
      } catch (ClassCastException e) {
      }
      check(fooInvocations == 19);
  
      check(barInvocations == 18);
      try {
          proxyMyInterface.byteBar();
          throw new AssertionError("Expected NPE");
      } catch (ClassCastException e) {
      }
      check(barInvocations == 19);
  
      check(fooInvocations == 19);
      myHandler.returnType = Long.class;  // Long -> byte == fail
      try {
          proxyMyInterface.byteFoo();
          throw new AssertionError("Expected ClassCastException");
      } catch (ClassCastException e) {
      }
      check(fooInvocations == 20);
  
      check(barInvocations == 19);
      try {
          proxyMyInterface.byteBar();
          throw new AssertionError("Expected NPE");
      } catch (ClassCastException e) {
      }
      check(barInvocations == 20);
  
      check(fooInvocations == 20);
      myHandler.returnType = Integer.class;  // Int -> byte == fail
      try {
          proxyMyInterface.byteFoo();
          throw new AssertionError("Expected ClassCastException");
      } catch (ClassCastException e) {
      }
      check(fooInvocations == 21);
  
      check(barInvocations == 20);
      try {
          proxyMyInterface.byteBar();
          throw new AssertionError("Expected NPE");
      } catch (ClassCastException e) {
      }
      check(barInvocations == 21);
  
      check(fooInvocations == 21);
      myHandler.returnType = Short.class;  // Short -> byte == fail
      try {
          proxyMyInterface.byteFoo();
          throw new AssertionError("Expected ClassCastException");
      } catch (ClassCastException e) {
      }
      check(fooInvocations == 22);
  
      check(barInvocations == 21);
      try {
          proxyMyInterface.byteBar();
          throw new AssertionError("Expected NPE");
      } catch (ClassCastException e) {
      }
      check(barInvocations == 22);
  
      check(fooInvocations == 22);
      myHandler.returnType = Character.class;  // Char -> byte == fail
      try {
          proxyMyInterface.byteFoo();
          throw new AssertionError("Expected ClassCastException");
      } catch (ClassCastException e) {
      }
      check(fooInvocations == 23);
  
      check(barInvocations == 22);
      try {
          proxyMyInterface.byteBar();
          throw new AssertionError("Expected NPE");
      } catch (ClassCastException e) {
      }
      check(barInvocations == 23);
  
      check(fooInvocations == 23);
      myHandler.returnType = Character.class;  // Char -> short == fail
      try {
          proxyMyInterface.shortFoo();
          throw new AssertionError("Expected ClassCastException");
      } catch (ClassCastException e) {
      }
      check(fooInvocations == 24);
  
      check(barInvocations == 23);
      try {
          proxyMyInterface.shortBar();
          throw new AssertionError("Expected NPE");
      } catch (ClassCastException e) {
      }
      check(barInvocations == 24);
  
      System.out.println(testName + ".testProxyReturns PASSED");
    }
  
    static void testProxyArgPassing() {
      System.out.println(testName + ".testProxyArgPassing RUNNING");
      MyInvocationHandler myHandler = new MyInvocationHandler();
      MyInterface proxyMyInterface =
          (MyInterface)Proxy.newProxyInstance(ReturnsAndArgPassing.class.getClassLoader(),
                                              new Class[] { MyInterface.class },
                                              myHandler);
  
      check((Integer)proxyMyInterface.selectArg(0, Integer.MAX_VALUE, Long.MAX_VALUE,
          Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == 0);
      check((Integer)proxyMyInterface.selectArg(1, Integer.MAX_VALUE, Long.MAX_VALUE,
          Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Integer.MAX_VALUE);
      check((Long)proxyMyInterface.selectArg(2, Integer.MAX_VALUE, Long.MAX_VALUE,
          Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Long.MAX_VALUE);
      check((Float)proxyMyInterface.selectArg(3, Integer.MAX_VALUE, Long.MAX_VALUE,
          Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Float.MAX_VALUE);
      check((Double)proxyMyInterface.selectArg(4, Integer.MAX_VALUE, Long.MAX_VALUE,
          Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Double.MAX_VALUE);
      check(proxyMyInterface.selectArg(5, Integer.MAX_VALUE, Long.MAX_VALUE,
          Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Object.class);
  
      System.out.println(testName + ".testProxyArgPassing PASSED");
    }
  
    public static void main(String args[]) {
      testProxyReturns();
      testProxyArgPassing();
    }
  }
  