1 /*
   2  * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 import jdk.testlibrary.TestProxy;
  27 
  28 import java.lang.reflect.Method;
  29 import java.util.Arrays;
  30 import java.util.function.Function;
  31 
  32 /**
  33  * @test
  34  * @summary Unit tests for java.lang.MethodTable internal implementations.
  35  */
  36 public class MethodTableTest {
  37 
  38     public static void main(String[] args) {
  39 
  40         testAdd(MethodTable::newSimpleArrayImpl);
  41         testAddUnlessDeclaredExists(MethodTable::newSimpleArrayImpl);
  42         testConsolidate(MethodTable::newSimpleArrayImpl);
  43         testGetFirstMethodWithMostSpecificReturnType(MethodTable::newSimpleArrayImpl);
  44 
  45         testAdd(MethodTable::newHashArrayImpl);
  46         testAddUnlessDeclaredExists(MethodTable::newHashArrayImpl);
  47         testConsolidate(MethodTable::newHashArrayImpl);
  48         testGetFirstMethodWithMostSpecificReturnType(MethodTable::newHashArrayImpl);
  49 
  50         System.out.println("All tests passed.");
  51     }
  52 
  53     // MethodTable.add
  54 
  55     static void testAdd(Method[] methods,
  56                         Function<Integer, MethodTable> mtFactory) {
  57         MethodTable mt = mtFactory.apply(methods.length);
  58         assertEmpty(mt);
  59         for (Method m : methods) mt.add(m);
  60         assertSameObjects(methods, mt.getMethods());
  61     }
  62 
  63     static void testAdd(Function<Integer, MethodTable> mtFactory) {
  64         Method[] methods = A.class.getDeclaredMethods();
  65 
  66         testAdd(methods, mtFactory);
  67 
  68         // repeated sequence
  69         Method[] methods2 = concat(methods, methods);
  70 
  71         testAdd(methods2, mtFactory);
  72     }
  73 
  74     // MethodTable.addUnlessDeclaredExists
  75 
  76     static void testAddUnlessDeclaredExists(Method[] methods,
  77                                             Class<?> declaringClass,
  78                                             Method[] expectedResult,
  79                                             Function<Integer, MethodTable> mtFactory) {
  80         MethodTable mt = mtFactory.apply(methods.length);
  81         assertEmpty(mt);
  82         for (Method m : methods) mt.addUnlessDeclaredExists(m, declaringClass);
  83         assertSameObjects(expectedResult, mt.getMethods());
  84     }
  85 
  86     static void testAddUnlessDeclaredExists(Function<Integer, MethodTable> mtFactory) {
  87         Method[] methodsA = A.class.getDeclaredMethods();
  88         Method[] methodsB = B.class.getDeclaredMethods();
  89 
  90         testAddUnlessDeclaredExists(methodsA, A.class, methodsA, mtFactory);
  91 
  92         // concatenated methods
  93         Method[] methodsAB = concat(methodsA, methodsB);
  94         Method[] methodsBA = concat(methodsB, methodsA);
  95 
  96         testAddUnlessDeclaredExists(methodsAB, Object.class, methodsAB, mtFactory);
  97         testAddUnlessDeclaredExists(methodsAB, A.class, methodsA, mtFactory);
  98         testAddUnlessDeclaredExists(methodsAB, B.class, methodsAB, mtFactory);
  99 
 100         testAddUnlessDeclaredExists(methodsBA, Object.class, methodsBA, mtFactory);
 101         testAddUnlessDeclaredExists(methodsBA, A.class, methodsBA, mtFactory);
 102         testAddUnlessDeclaredExists(methodsBA, B.class, methodsB, mtFactory);
 103     }
 104 
 105     // MethodTable.consolidate
 106 
 107     static void testConsolidate(Method[] methods,
 108                                 Class<?> declaringClass,
 109                                 Method[] expectedResult,
 110                                 Function<Integer, MethodTable> mtFactory) {
 111         MethodTable mt = mtFactory.apply(methods.length);
 112         assertEmpty(mt);
 113         for (Method m : methods) mt.consolidate(m, declaringClass);
 114         assertSameObjects(expectedResult, mt.getMethods());
 115     }
 116 
 117     static void testConsolidate(Function<Integer, MethodTable> mtFactory) {
 118         Method[] methodsA = A.class.getDeclaredMethods();
 119         Method[] methodsB = B.class.getDeclaredMethods();
 120         Method[] methodsAX = AX.class.getDeclaredMethods();
 121         Method[] methodsI = I.class.getDeclaredMethods();
 122         Method[] methodsX = X.class.getDeclaredMethods();
 123         Method[] methodsY = Y.class.getDeclaredMethods();
 124         Method[] methodsZ = Z.class.getDeclaredMethods();
 125 
 126         testConsolidate(methodsA, A.class, methodsA, mtFactory);
 127 
 128         // if given method is same method as existing method,
 129         // the operation completes without adding given method.
 130         testConsolidate(concat(methodsA, methodsA), Object.class, methodsA, mtFactory);
 131 
 132         // concatenated methods
 133         Method[] methodsAB = concat(methodsA, methodsB);
 134         Method[] methodsBA = concat(methodsB, methodsA);
 135 
 136         // if existing method is declared by given declaringClass,
 137         // the operation completes without adding given method.
 138         testConsolidate(methodsAB, A.class, methodsA, mtFactory);
 139         testConsolidate(methodsBA, B.class, methodsB, mtFactory);
 140         testConsolidate(methodsAB, Object.class, methodsAB, mtFactory);
 141         testConsolidate(methodsBA, Object.class, methodsBA, mtFactory);
 142 
 143         // if existing method is not abstract and either existing method
 144         // overrides given method...
 145         testConsolidate(concat(methodsAX, methodsA), Object.class, methodsAX, mtFactory);
 146 
 147         // ...or existing method is declared by class
 148         // and given method is declared by interface, the operation completes
 149         // without adding given method.
 150         testConsolidate(concat(methodsA, methodsI), Object.class, methodsA, mtFactory);
 151 
 152         // if given method is not abstract and either given method overrides existing
 153         // method...
 154         testConsolidate(concat(methodsA, methodsAX), Object.class, methodsAX, mtFactory);
 155 
 156         // ...or given method is declared by class and existing method is declared
 157         // by interface, then existing method is removed from this MethodTable...
 158         testConsolidate(concat(methodsI, methodsA), Object.class, methodsA, mtFactory);
 159 
 160         // ...if there are no more existing methods then given method is added to this
 161         // MethodTable and operation completes else next existing method is taken
 162         // into consideration.
 163         testConsolidate(concat(methodsX, methodsY, methodsZ), Object.class,
 164                        concat(methodsX, methodsY, methodsZ), mtFactory);
 165     }
 166 
 167     //
 168 
 169     static void testGetFirstMethodWithMostSpecificReturnType(Method[] methods,
 170                                                              Method expectedResult,
 171                                                              Function<Integer, MethodTable> mtFactory) {
 172         MethodTable mt = mtFactory.apply(methods.length);
 173         assertEmpty(mt);
 174         for (Method m : methods) mt.add(m);
 175         assertSameObject(expectedResult, mt.getFirstMethodWithMostSpecificReturnType());
 176     }
 177 
 178     static void testGetFirstMethodWithMostSpecificReturnType(Function<Integer, MethodTable> mtFactory) {
 179         Method[] methodsX = X.class.getDeclaredMethods();
 180         Method[] methodsY = Y.class.getDeclaredMethods();
 181         Method[] methodsZ = Z.class.getDeclaredMethods();
 182 
 183         testGetFirstMethodWithMostSpecificReturnType(methodsX, methodsX[0], mtFactory);
 184 
 185         testGetFirstMethodWithMostSpecificReturnType(concat(methodsX, methodsY), methodsY[0], mtFactory);
 186         testGetFirstMethodWithMostSpecificReturnType(concat(methodsY, methodsX), methodsY[0], mtFactory);
 187         testGetFirstMethodWithMostSpecificReturnType(concat(methodsY, methodsZ), methodsY[0], mtFactory);
 188         testGetFirstMethodWithMostSpecificReturnType(concat(methodsZ, methodsY), methodsZ[0], mtFactory);
 189         testGetFirstMethodWithMostSpecificReturnType(concat(methodsX, methodsZ), methodsZ[0], mtFactory);
 190         testGetFirstMethodWithMostSpecificReturnType(concat(methodsZ, methodsX), methodsZ[0], mtFactory);
 191 
 192         testGetFirstMethodWithMostSpecificReturnType(concat(methodsX, methodsY, methodsZ), methodsY[0], mtFactory);
 193         testGetFirstMethodWithMostSpecificReturnType(concat(methodsX, methodsZ, methodsY), methodsZ[0], mtFactory);
 194         testGetFirstMethodWithMostSpecificReturnType(concat(methodsY, methodsX, methodsZ), methodsY[0], mtFactory);
 195         testGetFirstMethodWithMostSpecificReturnType(concat(methodsZ, methodsX, methodsY), methodsZ[0], mtFactory);
 196         testGetFirstMethodWithMostSpecificReturnType(concat(methodsY, methodsZ, methodsX), methodsY[0], mtFactory);
 197         testGetFirstMethodWithMostSpecificReturnType(concat(methodsZ, methodsY, methodsX), methodsZ[0], mtFactory);
 198     }
 199 
 200     // test infrastructure
 201 
 202     static void assertEmpty(MethodTable mt) {
 203         if (mt.getSize() != 0) {
 204             throw new AssertionError("MethodTable is not empty");
 205         }
 206     }
 207 
 208     static void assertSameObject(Object expected, Object actual) {
 209         if (expected != actual) {
 210             throw new AssertionError("Expected:\n  " + expected +
 211                                      "\nActual:\n  " + actual);
 212 
 213         }
 214     }
 215 
 216     static void assertSameObjects(Object[] expected, Object[] actual) {
 217         boolean ok = (expected.length == actual.length);
 218         if (ok) {
 219             for (int i = 0; ok && i < expected.length; i++) {
 220                 ok = (expected[i] == actual[i]);
 221             }
 222         }
 223         if (!ok) {
 224             throw new AssertionError("Expected:\n  " + Arrays.toString(expected) +
 225                                      "\nActual:\n  " + Arrays.toString(actual));
 226         }
 227     }
 228 
 229     static Method[] concat(Method[]... mas) {
 230         int len = 0;
 231         for (Method[] ma : mas) {
 232             len += ma.length;
 233         }
 234         Method[] cma = new Method[len];
 235         int offset = 0;
 236         for (Method[] ma : mas) {
 237             System.arraycopy(ma, 0, cma, offset, ma.length);
 238             offset += ma.length;
 239         }
 240         return cma;
 241     }
 242 
 243     static class A {
 244         public void m() {
 245         }
 246 
 247         public void m(int i) {
 248         }
 249 
 250         public void m(long l) {
 251         }
 252 
 253         public void m(Object o) {
 254         }
 255 
 256         public void m(String s) {
 257         }
 258     }
 259 
 260     static class AX extends A {
 261         public void m() {
 262         }
 263 
 264         public void m(int i) {
 265         }
 266 
 267         public void m(long l) {
 268         }
 269 
 270         public void m(Object o) {
 271         }
 272 
 273         public void m(String s) {
 274         }
 275     }
 276 
 277     static class B {
 278         public void m() {
 279         }
 280 
 281         public void m(int i) {
 282         }
 283 
 284         public void m(long l) {
 285         }
 286 
 287         public void m(Object o) {
 288         }
 289 
 290         public void m(String s) {
 291         }
 292     }
 293 
 294     interface I {
 295         void m();
 296 
 297         void m(int i);
 298 
 299         void m(long l);
 300 
 301         void m(Object o);
 302 
 303         void m(String s);
 304     }
 305 
 306     interface X {
 307         Object m();
 308     }
 309 
 310     static abstract class Y {
 311         public abstract Number m();
 312     }
 313 
 314     interface Z {
 315         Number m();
 316     }
 317 
 318     // test proxy for package-private java.lang.MethodTable implementations
 319 
 320     interface MethodTable extends Iterable<Method> {
 321 
 322         static MethodTable newSimpleArrayImpl(int maxExpectedSize) {
 323             return TestProxy.newInstance(MethodTable.class,
 324                                         "java.lang.MethodTable$SimpleArrayImpl",
 325                                         ClassLoader.getSystemClassLoader(),
 326                                         new Class<?>[]{int.class},
 327                                         maxExpectedSize);
 328         }
 329 
 330         static MethodTable newHashArrayImpl(int maxExpectedSize) {
 331             return TestProxy.newInstance(MethodTable.class,
 332                                         "java.lang.MethodTable$HashArrayImpl",
 333                                         ClassLoader.getSystemClassLoader(),
 334                                         new Class<?>[]{int.class},
 335                                         maxExpectedSize);
 336         }
 337 
 338         void add(Method method);
 339 
 340         void addUnlessDeclaredExists(Method method, Class<?> declaringClass);
 341 
 342         void consolidate(Method method, Class<?> declaringClass);
 343 
 344         int getSize();
 345 
 346         void clear();
 347 
 348         Method[] getMethods();
 349 
 350         Method getFirstMethodWithMostSpecificReturnType();
 351     }
 352 }