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 }