Utils.java revision 2244:c7d95b8c9857
1226048Sobrien/* 268349Sobrien * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. 3330569Sgordon * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 468349Sobrien * 568349Sobrien * This code is free software; you can redistribute it and/or modify it 6186690Sobrien * under the terms of the GNU General Public License version 2 only, as 768349Sobrien * published by the Free Software Foundation. 868349Sobrien * 968349Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT 1068349Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11192348Sdelphij * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12192348Sdelphij * version 2 for more details (a copy is included in the LICENSE file that 13133359Sobrien * accompanied this code). 14226048Sobrien * 15226048Sobrien * You should have received a copy of the GNU General Public License version 16226048Sobrien * 2 along with this work; if not, write to the Free Software Foundation, 1768349Sobrien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18330569Sgordon * 19330569Sgordon * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20330569Sgordon * or visit www.oracle.com if you need additional information or have any 21330569Sgordon * questions. 22330569Sgordon */ 23330569Sgordon 24330569Sgordonpackage jdk.test.lib; 25330569Sgordon 26330569Sgordonimport java.io.File; 27330569Sgordonimport java.io.IOException; 28330569Sgordonimport java.net.InetAddress; 29330569Sgordonimport java.net.MalformedURLException; 30330569Sgordonimport java.net.ServerSocket; 31330569Sgordonimport java.net.URL; 32330569Sgordonimport java.net.URLClassLoader; 33330569Sgordonimport java.net.UnknownHostException; 34330569Sgordonimport java.nio.file.Files; 35330569Sgordonimport java.nio.file.Path; 36330569Sgordonimport java.nio.file.Paths; 37330569Sgordonimport java.util.ArrayList; 38330569Sgordonimport java.util.Arrays; 39330569Sgordonimport java.util.Collection; 40330569Sgordonimport java.util.Collections; 41330569Sgordonimport java.util.Iterator; 42330569Sgordonimport java.util.Map; 43330569Sgordonimport java.util.HashMap; 44330569Sgordonimport java.util.List; 45330569Sgordonimport java.util.Objects; 46330569Sgordonimport java.util.Random; 47330569Sgordonimport java.util.function.BooleanSupplier; 48330569Sgordonimport java.util.concurrent.TimeUnit; 49330569Sgordonimport java.util.function.Consumer; 50330569Sgordonimport java.util.function.Function; 51330569Sgordonimport java.util.regex.Matcher; 52330569Sgordonimport java.util.regex.Pattern; 53330569Sgordon 54330569Sgordonimport static jdk.test.lib.Asserts.assertTrue; 55330569Sgordonimport jdk.test.lib.process.ProcessTools; 56330569Sgordonimport jdk.test.lib.process.OutputAnalyzer; 57330569Sgordon 58330569Sgordon/** 59330569Sgordon * Common library for various test helper functions. 60330569Sgordon */ 61330569Sgordonpublic final class Utils { 62330569Sgordon 63330569Sgordon /** 64330569Sgordon * Returns the value of 'test.class.path' system property. 65330569Sgordon */ 66330569Sgordon public static final String TEST_CLASS_PATH = System.getProperty("test.class.path", "."); 67330569Sgordon 6868349Sobrien /** 69267843Sdelphij * Returns the sequence used by operating system to separate lines. 70267843Sdelphij */ 7168349Sobrien public static final String NEW_LINE = System.getProperty("line.separator"); 72267843Sdelphij 73267843Sdelphij /** 74267843Sdelphij * Returns the value of 'test.vm.opts' system property. 75330569Sgordon */ 76267843Sdelphij public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim(); 77267843Sdelphij 7868349Sobrien /** 7968349Sobrien * Returns the value of 'test.java.opts' system property. 80186690Sobrien */ 8168349Sobrien public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); 82330569Sgordon 83330569Sgordon /** 84330569Sgordon * Returns the value of 'test.src' system property. 85330569Sgordon */ 86330569Sgordon public static final String TEST_SRC = System.getProperty("test.src", "").trim(); 87330569Sgordon 88330569Sgordon /* 89330569Sgordon * Returns the value of 'test.jdk' system property 90330569Sgordon */ 91330569Sgordon public static final String TEST_JDK = System.getProperty("test.jdk"); 92330569Sgordon 93330569Sgordon /** 94330569Sgordon * Returns the value of 'test.classes' system property 95330569Sgordon */ 96330569Sgordon public static final String TEST_CLASSES = System.getProperty("test.classes", "."); 97330569Sgordon /** 98330569Sgordon * Defines property name for seed value. 99330569Sgordon */ 100330569Sgordon public static final String SEED_PROPERTY_NAME = "jdk.test.lib.random.seed"; 10168349Sobrien 10268349Sobrien /* (non-javadoc) 103330569Sgordon * Random generator with (or without) predefined seed. Depends on 104330569Sgordon * "jdk.test.lib.random.seed" property value. 105330569Sgordon */ 106330569Sgordon private static volatile Random RANDOM_GENERATOR; 107330569Sgordon 10868349Sobrien /** 10968349Sobrien * Contains the seed value used for {@link java.util.Random} creation. 11068349Sobrien */ 11168349Sobrien public static final long SEED = Long.getLong(SEED_PROPERTY_NAME, new Random().nextLong()); 11268349Sobrien /** 11368349Sobrien * Returns the value of 'test.timeout.factor' system property 11468349Sobrien * converted to {@code double}. 11568349Sobrien */ 11668349Sobrien public static final double TIMEOUT_FACTOR; 11768349Sobrien static { 11868349Sobrien String toFactor = System.getProperty("test.timeout.factor", "1.0"); 11968349Sobrien TIMEOUT_FACTOR = Double.parseDouble(toFactor); 12068349Sobrien } 12168349Sobrien 12268349Sobrien /** 12368349Sobrien * Returns the value of JTREG default test timeout in milliseconds 12468349Sobrien * converted to {@code long}. 12568349Sobrien */ 12668349Sobrien public static final long DEFAULT_TEST_TIMEOUT = TimeUnit.SECONDS.toMillis(120); 12768349Sobrien 12868349Sobrien private Utils() { 12968349Sobrien // Private constructor to prevent class instantiation 13068349Sobrien } 13168349Sobrien 132330569Sgordon /** 133330569Sgordon * Returns the list of VM options. 13468349Sobrien * 135330569Sgordon * @return List of VM options 136330569Sgordon */ 137133359Sobrien public static List<String> getVmOptions() { 138133359Sobrien return Arrays.asList(safeSplitString(VM_OPTIONS)); 139330569Sgordon } 140330569Sgordon 141330569Sgordon /** 142330569Sgordon * Returns the list of VM options with -J prefix. 143330569Sgordon * 144330569Sgordon * @return The list of VM options with -J prefix 145330569Sgordon */ 146330569Sgordon public static List<String> getForwardVmOptions() { 147330569Sgordon String[] opts = safeSplitString(VM_OPTIONS); 148330569Sgordon for (int i = 0; i < opts.length; i++) { 149330569Sgordon opts[i] = "-J" + opts[i]; 150330569Sgordon } 151330569Sgordon return Arrays.asList(opts); 152330569Sgordon } 153330569Sgordon 154330569Sgordon /** 155330569Sgordon * Returns the default JTReg arguments for a jvm running a test. 156330569Sgordon * This is the combination of JTReg arguments test.vm.opts and test.java.opts. 157330569Sgordon * @return An array of options, or an empty array if no options. 158330569Sgordon */ 159330569Sgordon public static String[] getTestJavaOpts() { 160330569Sgordon List<String> opts = new ArrayList<String>(); 161330569Sgordon Collections.addAll(opts, safeSplitString(VM_OPTIONS)); 162330569Sgordon Collections.addAll(opts, safeSplitString(JAVA_OPTIONS)); 163330569Sgordon return opts.toArray(new String[0]); 164330569Sgordon } 165330569Sgordon 166330569Sgordon /** 167330569Sgordon * Combines given arguments with default JTReg arguments for a jvm running a test. 168330569Sgordon * This is the combination of JTReg arguments test.vm.opts and test.java.opts 169330569Sgordon * @return The combination of JTReg test java options and user args. 170330569Sgordon */ 171330569Sgordon public static String[] addTestJavaOpts(String... userArgs) { 172330569Sgordon List<String> opts = new ArrayList<String>(); 173330569Sgordon Collections.addAll(opts, getTestJavaOpts()); 174330569Sgordon Collections.addAll(opts, userArgs); 175330569Sgordon return opts.toArray(new String[0]); 176330569Sgordon } 177330569Sgordon 178330569Sgordon /** 179330569Sgordon * Removes any options specifying which GC to use, for example "-XX:+UseG1GC". 180330569Sgordon * Removes any options matching: -XX:(+/-)Use*GC 181330569Sgordon * Used when a test need to set its own GC version. Then any 182330569Sgordon * GC specified by the framework must first be removed. 183330569Sgordon * @return A copy of given opts with all GC options removed. 184330569Sgordon */ 185330569Sgordon private static final Pattern useGcPattern = Pattern.compile( 186330569Sgordon "(?:\\-XX\\:[\\+\\-]Use.+GC)" 187330569Sgordon + "|(?:\\-Xconcgc)"); 188330569Sgordon public static List<String> removeGcOpts(List<String> opts) { 189330569Sgordon List<String> optsWithoutGC = new ArrayList<String>(); 190330569Sgordon for (String opt : opts) { 191330569Sgordon if (useGcPattern.matcher(opt).matches()) { 192133359Sobrien System.out.println("removeGcOpts: removed " + opt); 193330569Sgordon } else { 194330569Sgordon optsWithoutGC.add(opt); 195330569Sgordon } 196330569Sgordon } 197330569Sgordon return optsWithoutGC; 198330569Sgordon } 199330569Sgordon 200330569Sgordon /** 201330569Sgordon * Returns the default JTReg arguments for a jvm running a test without 202330569Sgordon * options that matches regular expressions in {@code filters}. 203330569Sgordon * This is the combination of JTReg arguments test.vm.opts and test.java.opts. 204330569Sgordon * @param filters Regular expressions used to filter out options. 205330569Sgordon * @return An array of options, or an empty array if no options. 206330569Sgordon */ 207330569Sgordon public static String[] getFilteredTestJavaOpts(String... filters) { 208330569Sgordon String options[] = getTestJavaOpts(); 209330569Sgordon 210330569Sgordon if (filters.length == 0) { 211330569Sgordon return options; 212330569Sgordon } 213330569Sgordon 214330569Sgordon List<String> filteredOptions = new ArrayList<String>(options.length); 215330569Sgordon Pattern patterns[] = new Pattern[filters.length]; 216330569Sgordon for (int i = 0; i < filters.length; i++) { 217330569Sgordon patterns[i] = Pattern.compile(filters[i]); 218330569Sgordon } 219330569Sgordon 220330569Sgordon for (String option : options) { 221330569Sgordon boolean matched = false; 222330569Sgordon for (int i = 0; i < patterns.length && !matched; i++) { 223330569Sgordon Matcher matcher = patterns[i].matcher(option); 224330569Sgordon matched = matcher.find(); 225330569Sgordon } 226330569Sgordon if (!matched) { 227330569Sgordon filteredOptions.add(option); 228330569Sgordon } 229330569Sgordon } 230330569Sgordon 231330569Sgordon return filteredOptions.toArray(new String[filteredOptions.size()]); 232330569Sgordon } 233330569Sgordon 234330569Sgordon /** 235330569Sgordon * Splits a string by white space. 236330569Sgordon * Works like String.split(), but returns an empty array 237330569Sgordon * if the string is null or empty. 238330569Sgordon */ 239330569Sgordon private static String[] safeSplitString(String s) { 240330569Sgordon if (s == null || s.trim().isEmpty()) { 241330569Sgordon return new String[] {}; 242330569Sgordon } 243330569Sgordon return s.trim().split("\\s+"); 244330569Sgordon } 245330569Sgordon 246330569Sgordon /** 247330569Sgordon * @return The full command line for the ProcessBuilder. 248330569Sgordon */ 249330569Sgordon public static String getCommandLine(ProcessBuilder pb) { 250330569Sgordon StringBuilder cmd = new StringBuilder(); 251330569Sgordon for (String s : pb.command()) { 252330569Sgordon cmd.append(s).append(" "); 253330569Sgordon } 254330569Sgordon return cmd.toString(); 255133359Sobrien } 256133359Sobrien 257133359Sobrien /** 258226048Sobrien * Returns the free port on the local host. 259330569Sgordon * The function will spin until a valid port number is found. 260226048Sobrien * 261330569Sgordon * @return The port number 262330569Sgordon * @throws InterruptedException if any thread has interrupted the current thread 263330569Sgordon * @throws IOException if an I/O error occurs when opening the socket 264330569Sgordon */ 265330569Sgordon public static int getFreePort() throws InterruptedException, IOException { 266330569Sgordon int port = -1; 267330569Sgordon 268330569Sgordon while (port <= 0) { 269330569Sgordon Thread.sleep(100); 270330569Sgordon 271330569Sgordon ServerSocket serverSocket = null; 272330569Sgordon try { 273330569Sgordon serverSocket = new ServerSocket(0); 274330569Sgordon port = serverSocket.getLocalPort(); 275330569Sgordon } finally { 276330569Sgordon serverSocket.close(); 277330569Sgordon } 278330569Sgordon } 279330569Sgordon 280330569Sgordon return port; 281330569Sgordon } 282330569Sgordon 283330569Sgordon /** 284330569Sgordon * Returns the name of the local host. 285330569Sgordon * 286226048Sobrien * @return The host name 287330569Sgordon * @throws UnknownHostException if IP address of a host could not be determined 288330569Sgordon */ 289330569Sgordon public static String getHostname() throws UnknownHostException { 290330569Sgordon InetAddress inetAddress = InetAddress.getLocalHost(); 291330569Sgordon String hostName = inetAddress.getHostName(); 292192348Sdelphij 293133359Sobrien assertTrue((hostName != null && !hostName.isEmpty()), 294226048Sobrien "Cannot get hostname"); 295226048Sobrien 296133359Sobrien return hostName; 297330569Sgordon } 298330569Sgordon 299226048Sobrien /** 300169962Sobrien * Uses "jcmd -l" to search for a jvm pid. This function will wait 301226048Sobrien * forever (until jtreg timeout) for the pid to be found. 302226048Sobrien * @param key Regular expression to search for 303330569Sgordon * @return The found pid. 304330569Sgordon */ 305330569Sgordon public static int waitForJvmPid(String key) throws Throwable { 306330569Sgordon final long iterationSleepMillis = 250; 307330569Sgordon System.out.println("waitForJvmPid: Waiting for key '" + key + "'"); 308330569Sgordon System.out.flush(); 309226048Sobrien while (true) { 310267843Sdelphij int pid = tryFindJvmPid(key); 311267843Sdelphij if (pid >= 0) { 312330569Sgordon return pid; 313330569Sgordon } 314330569Sgordon Thread.sleep(iterationSleepMillis); 315330569Sgordon } 316330569Sgordon } 317330569Sgordon 318330569Sgordon /** 319330569Sgordon * Searches for a jvm pid in the output from "jcmd -l". 320330569Sgordon * 321330569Sgordon * Example output from jcmd is: 322330569Sgordon * 12498 sun.tools.jcmd.JCmd -l 323267843Sdelphij * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar 324267843Sdelphij * 325330569Sgordon * @param key A regular expression to search for. 326267843Sdelphij * @return The found pid, or -1 if not found. 327267843Sdelphij * @throws Exception If multiple matching jvms are found. 328330569Sgordon */ 329330569Sgordon public static int tryFindJvmPid(String key) throws Throwable { 330330569Sgordon OutputAnalyzer output = null; 331330569Sgordon try { 332330569Sgordon JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd"); 333330569Sgordon jcmdLauncher.addToolArg("-l"); 334 output = ProcessTools.executeProcess(jcmdLauncher.getCommand()); 335 output.shouldHaveExitValue(0); 336 337 // Search for a line starting with numbers (pid), follwed by the key. 338 Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n"); 339 Matcher matcher = pattern.matcher(output.getStdout()); 340 341 int pid = -1; 342 if (matcher.find()) { 343 pid = Integer.parseInt(matcher.group(1)); 344 System.out.println("findJvmPid.pid: " + pid); 345 if (matcher.find()) { 346 throw new Exception("Found multiple JVM pids for key: " + key); 347 } 348 } 349 return pid; 350 } catch (Throwable t) { 351 System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t)); 352 throw t; 353 } 354 } 355 356 /** 357 * Adjusts the provided timeout value for the TIMEOUT_FACTOR 358 * @param tOut the timeout value to be adjusted 359 * @return The timeout value adjusted for the value of "test.timeout.factor" 360 * system property 361 */ 362 public static long adjustTimeout(long tOut) { 363 return Math.round(tOut * Utils.TIMEOUT_FACTOR); 364 } 365 366 /** 367 * Return the contents of the named file as a single String, 368 * or null if not found. 369 * @param filename name of the file to read 370 * @return String contents of file, or null if file not found. 371 * @throws IOException 372 * if an I/O error occurs reading from the file or a malformed or 373 * unmappable byte sequence is read 374 */ 375 public static String fileAsString(String filename) throws IOException { 376 Path filePath = Paths.get(filename); 377 if (!Files.exists(filePath)) return null; 378 return new String(Files.readAllBytes(filePath)); 379 } 380 381 private static final char[] hexArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 382 383 /** 384 * Returns hex view of byte array 385 * 386 * @param bytes byte array to process 387 * @return Space separated hexadecimal string representation of bytes 388 */ 389 390 public static String toHexString(byte[] bytes) { 391 char[] hexView = new char[bytes.length * 3]; 392 int i = 0; 393 for (byte b : bytes) { 394 hexView[i++] = hexArray[(b >> 4) & 0x0F]; 395 hexView[i++] = hexArray[b & 0x0F]; 396 hexView[i++] = ' '; 397 } 398 return new String(hexView); 399 } 400 401 /** 402 * Returns {@link java.util.Random} generator initialized with particular seed. 403 * The seed could be provided via system property {@link Utils#SEED_PROPERTY_NAME} 404 * In case no seed is provided, the method uses a random number. 405 * The used seed printed to stdout. 406 * @return {@link java.util.Random} generator with particular seed. 407 */ 408 public static Random getRandomInstance() { 409 if (RANDOM_GENERATOR == null) { 410 synchronized (Utils.class) { 411 if (RANDOM_GENERATOR == null) { 412 RANDOM_GENERATOR = new Random(SEED); 413 System.out.printf("For random generator using seed: %d%n", SEED); 414 System.out.printf("To re-run test with same seed value please add \"-D%s=%d\" to command line.%n", SEED_PROPERTY_NAME, SEED); 415 } 416 } 417 } 418 return RANDOM_GENERATOR; 419 } 420 421 /** 422 * Returns random element of non empty collection 423 * 424 * @param <T> a type of collection element 425 * @param collection collection of elements 426 * @return random element of collection 427 * @throws IllegalArgumentException if collection is empty 428 */ 429 public static <T> T getRandomElement(Collection<T> collection) 430 throws IllegalArgumentException { 431 if (collection.isEmpty()) { 432 throw new IllegalArgumentException("Empty collection"); 433 } 434 Random random = getRandomInstance(); 435 int elementIndex = 1 + random.nextInt(collection.size() - 1); 436 Iterator<T> iterator = collection.iterator(); 437 while (--elementIndex != 0) { 438 iterator.next(); 439 } 440 return iterator.next(); 441 } 442 443 /** 444 * Returns random element of non empty array 445 * 446 * @param <T> a type of array element 447 * @param array array of elements 448 * @return random element of array 449 * @throws IllegalArgumentException if array is empty 450 */ 451 public static <T> T getRandomElement(T[] array) 452 throws IllegalArgumentException { 453 if (array == null || array.length == 0) { 454 throw new IllegalArgumentException("Empty or null array"); 455 } 456 Random random = getRandomInstance(); 457 return array[random.nextInt(array.length)]; 458 } 459 460 /** 461 * Wait for condition to be true 462 * 463 * @param condition, a condition to wait for 464 */ 465 public static final void waitForCondition(BooleanSupplier condition) { 466 waitForCondition(condition, -1L, 100L); 467 } 468 469 /** 470 * Wait until timeout for condition to be true 471 * 472 * @param condition, a condition to wait for 473 * @param timeout a time in milliseconds to wait for condition to be true 474 * specifying -1 will wait forever 475 * @return condition value, to determine if wait was successful 476 */ 477 public static final boolean waitForCondition(BooleanSupplier condition, 478 long timeout) { 479 return waitForCondition(condition, timeout, 100L); 480 } 481 482 /** 483 * Wait until timeout for condition to be true for specified time 484 * 485 * @param condition, a condition to wait for 486 * @param timeout a time in milliseconds to wait for condition to be true, 487 * specifying -1 will wait forever 488 * @param sleepTime a time to sleep value in milliseconds 489 * @return condition value, to determine if wait was successful 490 */ 491 public static final boolean waitForCondition(BooleanSupplier condition, 492 long timeout, long sleepTime) { 493 long startTime = System.currentTimeMillis(); 494 while (!(condition.getAsBoolean() || (timeout != -1L 495 && ((System.currentTimeMillis() - startTime) > timeout)))) { 496 try { 497 Thread.sleep(sleepTime); 498 } catch (InterruptedException e) { 499 Thread.currentThread().interrupt(); 500 throw new Error(e); 501 } 502 } 503 return condition.getAsBoolean(); 504 } 505 506 /** 507 * Interface same as java.lang.Runnable but with 508 * method {@code run()} able to throw any Throwable. 509 */ 510 public static interface ThrowingRunnable { 511 void run() throws Throwable; 512 } 513 514 /** 515 * Filters out an exception that may be thrown by the given 516 * test according to the given filter. 517 * 518 * @param test - method that is invoked and checked for exception. 519 * @param filter - function that checks if the thrown exception matches 520 * criteria given in the filter's implementation. 521 * @return - exception that matches the filter if it has been thrown or 522 * {@code null} otherwise. 523 * @throws Throwable - if test has thrown an exception that does not 524 * match the filter. 525 */ 526 public static Throwable filterException(ThrowingRunnable test, 527 Function<Throwable, Boolean> filter) throws Throwable { 528 try { 529 test.run(); 530 } catch (Throwable t) { 531 if (filter.apply(t)) { 532 return t; 533 } else { 534 throw t; 535 } 536 } 537 return null; 538 } 539 540 /** 541 * Ensures a requested class is loaded 542 * @param aClass class to load 543 */ 544 public static void ensureClassIsLoaded(Class<?> aClass) { 545 if (aClass == null) { 546 throw new Error("Requested null class"); 547 } 548 try { 549 Class.forName(aClass.getName(), /* initialize = */ true, 550 ClassLoader.getSystemClassLoader()); 551 } catch (ClassNotFoundException e) { 552 throw new Error("Class not found", e); 553 } 554 } 555 /** 556 * @param parent a class loader to be the parent for the returned one 557 * @return an UrlClassLoader with urls made of the 'test.class.path' jtreg 558 * property and with the given parent 559 */ 560 public static URLClassLoader getTestClassPathURLClassLoader(ClassLoader parent) { 561 URL[] urls = Arrays.stream(TEST_CLASS_PATH.split(File.pathSeparator)) 562 .map(Paths::get) 563 .map(Path::toUri) 564 .map(x -> { 565 try { 566 return x.toURL(); 567 } catch (MalformedURLException ex) { 568 throw new Error("Test issue. JTREG property" 569 + " 'test.class.path'" 570 + " is not defined correctly", ex); 571 } 572 }).toArray(URL[]::new); 573 return new URLClassLoader(urls, parent); 574 } 575 576 /** 577 * Runs runnable and checks that it throws expected exception. If exceptionException is null it means 578 * that we expect no exception to be thrown. 579 * @param runnable what we run 580 * @param expectedException expected exception 581 */ 582 public static void runAndCheckException(Runnable runnable, Class<? extends Throwable> expectedException) { 583 runAndCheckException(runnable, t -> { 584 if (t == null) { 585 if (expectedException != null) { 586 throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName()); 587 } 588 } else { 589 String message = "Got unexpected exception " + t.getClass().getSimpleName(); 590 if (expectedException == null) { 591 throw new AssertionError(message, t); 592 } else if (!expectedException.isAssignableFrom(t.getClass())) { 593 message += " instead of " + expectedException.getSimpleName(); 594 throw new AssertionError(message, t); 595 } 596 } 597 }); 598 } 599 600 /** 601 * Runs runnable and makes some checks to ensure that it throws expected exception. 602 * @param runnable what we run 603 * @param checkException a consumer which checks that we got expected exception and raises a new exception otherwise 604 */ 605 public static void runAndCheckException(Runnable runnable, Consumer<Throwable> checkException) { 606 try { 607 runnable.run(); 608 checkException.accept(null); 609 } catch (Throwable t) { 610 checkException.accept(t); 611 } 612 } 613 614 /** 615 * Converts to VM type signature 616 * 617 * @param type Java type to convert 618 * @return string representation of VM type 619 */ 620 public static String toJVMTypeSignature(Class<?> type) { 621 if (type.isPrimitive()) { 622 if (type == boolean.class) { 623 return "Z"; 624 } else if (type == byte.class) { 625 return "B"; 626 } else if (type == char.class) { 627 return "C"; 628 } else if (type == double.class) { 629 return "D"; 630 } else if (type == float.class) { 631 return "F"; 632 } else if (type == int.class) { 633 return "I"; 634 } else if (type == long.class) { 635 return "J"; 636 } else if (type == short.class) { 637 return "S"; 638 } else if (type == void.class) { 639 return "V"; 640 } else { 641 throw new Error("Unsupported type: " + type); 642 } 643 } 644 String result = type.getName().replaceAll("\\.", "/"); 645 if (!type.isArray()) { 646 return "L" + result + ";"; 647 } 648 return result; 649 } 650 651 public static Object[] getNullValues(Class<?>... types) { 652 Object[] result = new Object[types.length]; 653 int i = 0; 654 for (Class<?> type : types) { 655 result[i++] = NULL_VALUES.get(type); 656 } 657 return result; 658 } 659 private static Map<Class<?>, Object> NULL_VALUES = new HashMap<>(); 660 static { 661 NULL_VALUES.put(boolean.class, false); 662 NULL_VALUES.put(byte.class, (byte) 0); 663 NULL_VALUES.put(short.class, (short) 0); 664 NULL_VALUES.put(char.class, '\0'); 665 NULL_VALUES.put(int.class, 0); 666 NULL_VALUES.put(long.class, 0L); 667 NULL_VALUES.put(float.class, 0.0f); 668 NULL_VALUES.put(double.class, 0.0d); 669 } 670 671 /** 672 * Returns mandatory property value 673 * @param propName is a name of property to request 674 * @return a String with requested property value 675 */ 676 public static String getMandatoryProperty(String propName) { 677 Objects.requireNonNull(propName, "Requested null property"); 678 String prop = System.getProperty(propName); 679 Objects.requireNonNull(prop, 680 String.format("A mandatory property '%s' isn't set", propName)); 681 return prop; 682 } 683} 684 685