1 package org.testng.internal; 2 3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.FileOutputStream; 8 import java.io.FileWriter; 9 import java.io.IOException; 10 import java.io.InputStream; 11 import java.io.OutputStream; 12 import java.io.OutputStreamWriter; 13 import java.io.PrintWriter; 14 import java.io.StringReader; 15 import java.io.StringWriter; 16 import java.lang.reflect.Method; 17 import java.lang.reflect.Modifier; 18 import java.util.Arrays; 19 import java.util.HashMap; 20 import java.util.List; 21 import java.util.Map; 22 import java.util.StringTokenizer; 23 import java.util.logging.FileHandler; 24 import java.util.logging.Level; 25 import java.util.logging.Logger; 26 27 import org.testng.ITestNGMethod; 28 import org.testng.TestNG; 29 import org.testng.TestNGException; 30 import org.testng.TestRunner; 31 import org.testng.annotations.IConfigurationAnnotation; 32 import org.testng.annotations.ITestAnnotation; 33 import org.testng.collections.Lists; 34 import org.testng.internal.annotations.AnnotationHelper; 35 import org.testng.internal.annotations.IAnnotationFinder; 36 import org.testng.log.TextFormatter; 37 import org.testng.reporters.XMLStringBuffer; 38 import org.testng.xml.XmlClass; 39 40 /** 41 * Helper methods to parse annotations. 42 * 43 * @author Cedric Beust, Apr 26, 2004 44 */ 45 public final class Utils { 46 private static final String LINE_SEP = System.getProperty("line.separator"); 47 48 public static final char[] SPECIAL_CHARACTERS = 49 {'*','/','\\','?','%',':',';','<','>','&','~','|'}; 50 public static final char CHAR_REPLACEMENT = '_'; 51 public static final char UNICODE_REPLACEMENT = 0xFFFD; 52 53 /** 54 * Hide constructor for utility class. 55 */ Utils()56 private Utils() { 57 // Hide constructor 58 } 59 60 /** 61 * Splits the given String s into tokens where the separator is 62 * either the space character or the comma character. For example, 63 * if s is "a,b, c" this method returns {"a", "b", "c"} 64 * 65 * @param s the string to split 66 * @return the split token 67 */ stringToArray(String s)68 public static String[] stringToArray(String s) { 69 // TODO CQ would s.split() be a better way of doing this? 70 StringTokenizer st = new StringTokenizer(s, " ,"); 71 String[] result = new String[st.countTokens()]; 72 for (int i = 0; i < result.length; i++) { 73 result[i] = st.nextToken(); 74 } 75 76 return result; 77 } 78 classesToXmlClasses(Class<?>[] classes)79 public static XmlClass[] classesToXmlClasses(Class<?>[] classes) { 80 List<XmlClass> result = Lists.newArrayList(); 81 82 for (Class<?> cls : classes) { 83 result.add(new XmlClass(cls, true /* load classes */)); 84 } 85 86 return result.toArray(new XmlClass[classes.length]); 87 } 88 parseMultiLine(String line)89 public static String[] parseMultiLine(String line) { 90 List<String> vResult = Lists.newArrayList(); 91 if (isStringNotBlank(line)) { 92 StringTokenizer st = new StringTokenizer(line, " "); 93 while (st.hasMoreTokens()) { 94 vResult.add(st.nextToken()); 95 } 96 // Bug in split when passed " " : returns one too many result 97 // result = line.split(" "); 98 } 99 100 return vResult.toArray(new String[vResult.size()]); 101 } 102 writeUtf8File(@ullable String outputDir, String fileName, XMLStringBuffer xsb, String prefix)103 public static void writeUtf8File(@Nullable String outputDir, String fileName, XMLStringBuffer xsb, String prefix) { 104 try { 105 final File outDir = (outputDir != null) ? new File(outputDir) : new File("").getAbsoluteFile(); 106 if (!outDir.exists()) { 107 outDir.mkdirs(); 108 } 109 final File file = new File(outDir, fileName); 110 if (!file.exists()) { 111 file.createNewFile(); 112 } 113 final OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); 114 if (prefix != null) { 115 w.append(prefix); 116 } 117 xsb.toWriter(w); 118 w.close(); 119 } catch(IOException ex) { 120 ex.printStackTrace(); 121 } 122 } 123 124 /** 125 * Writes the content of the sb string to the file named filename in outDir encoding the output as UTF-8. 126 * If outDir does not exist, it is created. 127 * 128 * @param outputDir the output directory (may not exist). If <tt>null</tt> then current directory is used. 129 * @param fileName the filename 130 * @param sb the file content 131 */ writeUtf8File(@ullable String outputDir, String fileName, String sb)132 public static void writeUtf8File(@Nullable String outputDir, String fileName, String sb) { 133 final String outDirPath= outputDir != null ? outputDir : ""; 134 final File outDir= new File(outDirPath); 135 writeFile(outDir, fileName, escapeUnicode(sb), "UTF-8", false /* don't append */); 136 } 137 138 /** 139 * Writes the content of the sb string to the file named filename in outDir. If 140 * outDir does not exist, it is created. 141 * 142 * @param outputDir the output directory (may not exist). If <tt>null</tt> then current directory is used. 143 * @param fileName the filename 144 * @param sb the file content 145 */ writeFile(@ullable String outputDir, String fileName, String sb)146 public static void writeFile(@Nullable String outputDir, String fileName, String sb) { 147 final String outDirPath= outputDir != null ? outputDir : ""; 148 final File outDir= new File(outDirPath); 149 writeFile(outDir, fileName, sb, null, false /* don't append */); 150 } 151 152 /** 153 * Writes the content of the sb string to the file named filename in outDir. If 154 * outDir does not exist, it is created. 155 * 156 * @param outDir the output directory (may not exist). If <tt>null</tt> then current directory is used. 157 * @param fileName the filename 158 * @param sb the file content 159 */ writeFile(@ullable File outDir, String fileName, String sb, @Nullable String encoding, boolean append)160 private static void writeFile(@Nullable File outDir, String fileName, String sb, @Nullable String encoding, boolean append) { 161 try { 162 if (outDir == null) { 163 outDir = new File("").getAbsoluteFile(); 164 } 165 if (!outDir.exists()) { 166 outDir.mkdirs(); 167 } 168 169 fileName = replaceSpecialCharacters(fileName); 170 File outputFile = new File(outDir, fileName); 171 if (!append) { 172 outputFile.delete(); 173 outputFile.createNewFile(); 174 } 175 writeFile(outputFile, sb, encoding, append); 176 } 177 catch (IOException e) { 178 if (TestRunner.getVerbose() > 1) { 179 e.printStackTrace(); 180 } 181 else { 182 log("[Utils]", 1, e.getMessage()); 183 } 184 } 185 } 186 writeFile(File outputFile, String sb, @Nullable String encoding, boolean append)187 private static void writeFile(File outputFile, String sb, @Nullable String encoding, boolean append) { 188 BufferedWriter fw = null; 189 try { 190 fw = openWriter(outputFile, encoding, append); 191 fw.write(sb); 192 193 Utils.log("", 3, "Creating " + outputFile.getAbsolutePath()); 194 } 195 catch(IOException ex) { 196 if (TestRunner.getVerbose() > 1) { 197 System.err.println("ERROR WHILE WRITING TO " + outputFile); 198 ex.printStackTrace(); 199 } 200 else { 201 log("[Utils]", 1, "Error while writing to " + outputFile + ": " + ex.getMessage()); 202 } 203 } 204 finally { 205 try { 206 if (fw != null) { 207 fw.close(); 208 } 209 } 210 catch (IOException e) { 211 ; // ignore 212 } 213 } 214 } 215 216 /** 217 * Open a BufferedWriter for the specified file. If output directory doesn't 218 * exist, it is created. If the output file exists, it is deleted. The output file is 219 * created in any case. 220 * @param outputDir output directory. If <tt>null</tt>, then current directory is used 221 * @param fileName file name 222 * @throws IOException if anything goes wrong while creating files. 223 */ openWriter(@ullable String outputDir, String fileName)224 public static BufferedWriter openWriter(@Nullable String outputDir, String fileName) throws IOException { 225 String outDirPath= outputDir != null ? outputDir : ""; 226 File outDir= new File(outDirPath); 227 if (outDir.exists()) { 228 outDir.mkdirs(); 229 } 230 fileName = replaceSpecialCharacters(fileName); 231 File outputFile = new File(outDir, fileName); 232 outputFile.delete(); 233 return openWriter(outputFile, null, false); 234 } 235 openWriter(File outputFile, @Nullable String encoding, boolean append)236 private static BufferedWriter openWriter(File outputFile, @Nullable String encoding, boolean append) throws IOException { 237 if (!outputFile.exists()) { 238 outputFile.createNewFile(); 239 } 240 OutputStreamWriter osw= null; 241 if (null != encoding) { 242 osw = new OutputStreamWriter(new FileOutputStream(outputFile, append), encoding); 243 } 244 else { 245 osw = new OutputStreamWriter(new FileOutputStream(outputFile, append)); 246 } 247 return new BufferedWriter(osw); 248 } 249 ppp(String s)250 private static void ppp(String s) { 251 Utils.log("Utils", 0, s); 252 } 253 254 /** 255 * @param result 256 */ dumpMap(Map<?, ?> result)257 public static void dumpMap(Map<?, ?> result) { 258 System.out.println("vvvvv"); 259 for (Map.Entry<?, ?> entry : result.entrySet()) { 260 System.out.println(entry.getKey() + " => " + entry.getValue()); 261 } 262 System.out.println("^^^^^"); 263 } 264 265 /** 266 * @param allMethods 267 */ dumpMethods(List<ITestNGMethod> allMethods)268 public static void dumpMethods(List<ITestNGMethod> allMethods) { 269 ppp("======== METHODS:"); 270 for (ITestNGMethod tm : allMethods) { 271 ppp(" " + tm); 272 } 273 } 274 275 /** 276 * @return The list of dependent groups for this method, including the 277 * class groups 278 */ dependentGroupsForThisMethodForTest(Method m, IAnnotationFinder finder)279 public static String[] dependentGroupsForThisMethodForTest(Method m, IAnnotationFinder finder) { 280 List<String> vResult = Lists.newArrayList(); 281 Class<?> cls = m.getDeclaringClass(); 282 283 // Collect groups on the class 284 ITestAnnotation tc = AnnotationHelper.findTest(finder, cls); 285 if (null != tc) { 286 for (String group : tc.getDependsOnGroups()) { 287 vResult.add(group); 288 } 289 } 290 291 // Collect groups on the method 292 ITestAnnotation tm = AnnotationHelper.findTest(finder, m); 293 if (null != tm) { 294 String[] groups = tm.getDependsOnGroups(); 295 296 // ppp("Method:" + m + " #Groups:" + groups.length); 297 for (String group : groups) { 298 vResult.add(group); 299 } 300 } 301 302 return vResult.toArray(new String[vResult.size()]); 303 } 304 305 /** 306 * @return The list of groups this method belongs to, including the 307 * class groups 308 */ groupsForThisMethodForTest(Method m, IAnnotationFinder finder)309 public static String[] groupsForThisMethodForTest(Method m, IAnnotationFinder finder) { 310 List<String> vResult = Lists.newArrayList(); 311 Class<?> cls = m.getDeclaringClass(); 312 313 // Collect groups on the class 314 ITestAnnotation tc = AnnotationHelper.findTest(finder, cls); 315 if (null != tc) { 316 for (String group : tc.getGroups()) { 317 vResult.add(group); 318 } 319 } 320 321 // Collect groups on the method 322 ITestAnnotation tm = AnnotationHelper.findTest(finder, m); 323 if (null != tm) { 324 String[] groups = tm.getGroups(); 325 326 // ppp("Method:" + m + " #Groups:" + groups.length); 327 for (String group : groups) { 328 vResult.add(group); 329 } 330 } 331 332 return vResult.toArray(new String[vResult.size()]); 333 } 334 335 /** 336 * @return The list of groups this method belongs to, including the 337 * class groups 338 */ groupsForThisMethodForConfiguration(Method m, IAnnotationFinder finder)339 public static String[] groupsForThisMethodForConfiguration(Method m, IAnnotationFinder finder) { 340 String[] result = {}; 341 342 // Collect groups on the method 343 ITestAnnotation tm = AnnotationHelper.findTest(finder, m); 344 if (null != tm) { 345 result = tm.getGroups(); 346 } 347 348 return result; 349 } 350 351 /** 352 * @return The list of groups this method depends on, including the 353 * class groups 354 */ dependentGroupsForThisMethodForConfiguration(Method m, IAnnotationFinder finder)355 public static String[] dependentGroupsForThisMethodForConfiguration(Method m, 356 IAnnotationFinder finder) { 357 String[] result = {}; 358 359 // Collect groups on the method 360 IConfigurationAnnotation tm = AnnotationHelper.findConfiguration(finder, m); 361 if (null != tm) { 362 result = tm.getDependsOnGroups(); 363 } 364 365 return result; 366 } 367 log(String msg)368 public static void log(String msg) { 369 log("Utils", 2, msg); 370 } 371 372 /** 373 * Logs the the message to System.out if level is greater than 374 * or equal to TestRunner.getVerbose(). The message is logged as: 375 * <pre> 376 * "[cls] msg" 377 * </pre> 378 * 379 * @param cls the class name to prefix the log message. 380 * @param level the logging level of the message. 381 * @param msg the message to log to System.out. 382 */ log(String cls, int level, String msg)383 public static void log(String cls, int level, String msg) { 384 // Why this coupling on a static member of TestRunner.getVerbose()? 385 if (TestRunner.getVerbose() >= level) { 386 if (cls.length() > 0) { 387 System.out.println("[" + cls + "] " + msg); 388 } 389 else { 390 System.out.println(msg); 391 } 392 } 393 } 394 error(String errorMessage)395 public static void error(String errorMessage) { 396 System.err.println("[Error] " + errorMessage); 397 } 398 399 /** 400 * @return The number of methods invoked, taking into account the number 401 * of instances. 402 */ 403 // public static int calculateInvokedMethodCount(IResultMap map) { 404 // return calculateInvokedMethodCount( 405 // (ITestNGMethod[]) map.getAllMethods().toArray(new ITestNGMethod[map.size()])); 406 // } 407 calculateInvokedMethodCount(ITestNGMethod[] methods)408 public static int calculateInvokedMethodCount(ITestNGMethod[] methods) { 409 return methods.length; 410 // int result = 0; 411 // 412 // for (ITestNGMethod method : methods) { 413 // int instanceCount = method.getInvocationCount(); 414 // result += instanceCount; 415 // } 416 // 417 // return result; 418 } 419 420 // public static int calculateInvokedMethodCount(Map<ITestNGMethod, ITestResult> methods) { 421 // return calculateInvokedMethodCount(methods.keySet().toArray(new ITestNGMethod[methods.values() 422 // .size()])); 423 // } 424 425 /** 426 * Tokenize the string using the separator. 427 */ split(String string, String sep)428 public static String[] split(String string, String sep) { 429 if ((string == null) || (string.length() == 0)) { 430 return new String[0]; 431 } 432 433 // TODO How different is this from: 434 // return string.split(sep); 435 436 int start = 0; 437 int idx = string.indexOf(sep, start); 438 int len = sep.length(); 439 List<String> strings = Lists.newArrayList(); 440 441 while (idx != -1) { 442 strings.add(string.substring(start, idx).trim()); 443 start = idx + len; 444 idx = string.indexOf(sep, start); 445 } 446 447 strings.add(string.substring(start).trim()); 448 449 return strings.toArray(new String[strings.size()]); 450 } 451 initLogger(Logger logger, String outputLogPath)452 public static void initLogger(Logger logger, String outputLogPath) { 453 try { 454 logger.setUseParentHandlers(false); 455 FileHandler fh = new FileHandler(outputLogPath); 456 fh.setFormatter(new TextFormatter()); 457 fh.setLevel(Level.INFO); 458 logger.addHandler(fh); 459 } 460 catch (SecurityException | IOException se) { 461 se.printStackTrace(); 462 } 463 } 464 logInvocation(String reason, Method thisMethod, Object[] parameters)465 public static void logInvocation(String reason, Method thisMethod, Object[] parameters) { 466 String clsName = thisMethod.getDeclaringClass().getName(); 467 int n = clsName.lastIndexOf("."); 468 if (n >= 0) { 469 clsName = clsName.substring(n + 1); 470 } 471 String methodName = clsName + '.' + thisMethod.getName(); 472 if (TestRunner.getVerbose() >= 2) { 473 StringBuffer paramString = new StringBuffer(); 474 if (parameters != null) { 475 for (Object p : parameters) { 476 paramString.append(p.toString()).append(' '); 477 } 478 } 479 log("", 2, "Invoking " + reason + methodName + '(' + paramString + ')'); 480 } 481 } 482 writeResourceToFile(File file, String resourceName, Class<?> clasz)483 public static void writeResourceToFile(File file, String resourceName, Class<?> clasz) throws IOException { 484 InputStream inputStream = clasz.getResourceAsStream("/" + resourceName); 485 if (inputStream == null) { 486 System.err.println("Couldn't find resource on the class path: " + resourceName); 487 // throw new IllegalArgumentException("Resource does not exist: " + resourceName); 488 } 489 490 else { 491 492 try { 493 FileOutputStream outputStream = new FileOutputStream(file); 494 try { 495 int nread; 496 byte[] buffer = new byte[4096]; 497 while (0 < (nread = inputStream.read(buffer))) { 498 outputStream.write(buffer, 0, nread); 499 } 500 } finally { 501 outputStream.close(); 502 } 503 } finally { 504 inputStream.close(); 505 } 506 } 507 } 508 defaultIfStringEmpty(String s, String defaultValue)509 public static String defaultIfStringEmpty(String s, String defaultValue) { 510 return isStringEmpty(s) ? defaultValue : s; 511 } 512 isStringBlank(String s)513 public static boolean isStringBlank(String s) { 514 return s == null || "".equals(s.trim()); 515 } 516 isStringEmpty(String s)517 public static boolean isStringEmpty(String s) { 518 return s == null || "".equals(s); 519 } 520 isStringNotBlank(String s)521 public static boolean isStringNotBlank(String s) { 522 return !isStringBlank(s); 523 } 524 isStringNotEmpty(String s)525 public static boolean isStringNotEmpty(String s) { 526 return !isStringEmpty(s); 527 } 528 529 /** 530 * @return an array of two strings: the short stack trace and the long stack trace. 531 */ stackTrace(Throwable t, boolean toHtml)532 public static String[] stackTrace(Throwable t, boolean toHtml) { 533 StringWriter sw = new StringWriter(); 534 PrintWriter pw = new PrintWriter(sw); 535 t.printStackTrace(pw); 536 pw.flush(); 537 538 String fullStackTrace = sw.getBuffer().toString(); 539 String shortStackTrace; 540 541 if (Boolean.getBoolean(TestNG.SHOW_TESTNG_STACK_FRAMES) || TestRunner.getVerbose() >= 2) { 542 shortStackTrace = fullStackTrace; 543 } else { 544 shortStackTrace = filterTrace(sw.getBuffer().toString()); 545 } 546 547 if (toHtml) { 548 shortStackTrace = escapeHtml(shortStackTrace); 549 fullStackTrace = escapeHtml(fullStackTrace); 550 } 551 552 return new String[] { 553 shortStackTrace, fullStackTrace 554 }; 555 } 556 557 private static final Map<Character, String> ESCAPES = new HashMap<Character, String>() { 558 private static final long serialVersionUID = 1285607660247157523L; 559 560 { 561 put('<', "<"); 562 put('>', ">"); 563 put('\'', "'"); 564 put('"', """); 565 put('&', "&"); 566 }}; 567 escapeHtml(String s)568 public static String escapeHtml(String s) { 569 if (s == null) { 570 return null; 571 } 572 573 StringBuilder result = new StringBuilder(); 574 575 for (int i = 0; i < s.length(); i++) { 576 char c = s.charAt(i); 577 String nc = ESCAPES.get(c); 578 if (nc != null) { 579 result.append(nc); 580 } else { 581 result.append(c); 582 } 583 } 584 585 return result.toString(); 586 } 587 escapeUnicode(String s)588 public static String escapeUnicode(String s) { 589 if (s == null) { 590 return null; 591 } 592 593 StringBuilder result = new StringBuilder(); 594 595 for (int i = 0; i < s.length(); i++) { 596 char c = s.charAt(i); 597 char ca = (Character.isDefined(c)) ? c: UNICODE_REPLACEMENT; 598 result.append(ca); 599 } 600 601 return result.toString(); 602 } 603 filterTrace(String trace)604 private static String filterTrace(String trace) { 605 StringReader stringReader = new StringReader(trace); 606 BufferedReader bufferedReader = new BufferedReader(stringReader); 607 StringBuffer buf = new StringBuffer(); 608 609 try { 610 // first line contains the thrown exception 611 String line = bufferedReader.readLine(); 612 if(line == null) { 613 return ""; 614 } 615 buf.append(line).append(LINE_SEP); 616 617 // 618 // the stack frames of the trace 619 // 620 String[] excludedStrings = new String[] { 621 "org.testng", 622 "reflect", 623 "org.apache.maven.surefire" 624 }; 625 626 int excludedCount = 0; 627 while((line = bufferedReader.readLine()) != null) { 628 boolean isExcluded = false; 629 for (String excluded : excludedStrings) { 630 if(line.contains(excluded)) { 631 isExcluded = true; 632 excludedCount++; 633 break; 634 } 635 } 636 if (! isExcluded) { 637 buf.append(line).append(LINE_SEP); 638 } 639 } 640 if (excludedCount > 0) { 641 buf.append("... Removed " + excludedCount + " stack frames"); 642 } 643 } 644 catch(IOException ioex) { 645 ; // do nothing 646 } 647 648 return buf.toString(); 649 } 650 toString(Object object, Class<?> objectClass)651 public static String toString(Object object, Class<?> objectClass) { 652 if(null == object) { 653 return "null"; 654 } 655 final String toString= object.toString(); 656 if(isStringEmpty(toString)) { 657 return "\"\""; 658 } 659 else if (String.class.equals(objectClass)) { 660 return "\"" + toString + '\"'; 661 } 662 else { 663 return toString; 664 } 665 } 666 detailedMethodName(ITestNGMethod method, boolean fqn)667 public static String detailedMethodName(ITestNGMethod method, boolean fqn) { 668 StringBuffer buf= new StringBuffer(); 669 if(method.isBeforeSuiteConfiguration()) { 670 buf.append("@BeforeSuite "); 671 } 672 else if(method.isBeforeTestConfiguration()) { 673 buf.append("@BeforeTest "); 674 } 675 else if(method.isBeforeClassConfiguration()) { 676 buf.append("@BeforeClass "); 677 } 678 else if(method.isBeforeGroupsConfiguration()) { 679 buf.append("@BeforeGroups "); 680 } 681 else if(method.isBeforeMethodConfiguration()) { 682 buf.append("@BeforeMethod "); 683 } 684 else if(method.isAfterMethodConfiguration()) { 685 buf.append("@AfterMethod "); 686 } 687 else if(method.isAfterGroupsConfiguration()) { 688 buf.append("@AfterGroups "); 689 } 690 else if(method.isAfterClassConfiguration()) { 691 buf.append("@AfterClass "); 692 } 693 else if(method.isAfterTestConfiguration()) { 694 buf.append("@AfterTest "); 695 } 696 else if(method.isAfterSuiteConfiguration()) { 697 buf.append("@AfterSuite "); 698 } 699 700 return buf.append(fqn ? method.toString() : method.getMethodName()).toString(); 701 } 702 arrayToString(String[] strings)703 public static String arrayToString(String[] strings) { 704 StringBuffer result = new StringBuffer(""); 705 if ((strings != null) && (strings.length > 0)) { 706 for (int i = 0; i < strings.length; i++) { 707 result.append(strings[i]); 708 if (i < strings.length - 1) { 709 result.append(", "); 710 } 711 } 712 } 713 return result.toString(); 714 } 715 716 /** 717 * If the file name contains special characters like *,/,\ and so on, 718 * exception will be thrown and report file will not be created.<br> 719 * Special characters are platform specific and they are not same for 720 * example on Windows and Macintosh. * is not allowed on Windows, but it is on Macintosh.<br> 721 * In order to have the same behavior of testng on the all platforms, characters like * will 722 * be replaced on all platforms whether they are causing the problem or not. 723 * 724 * @param fileName file name that could contain special characters. 725 * @return fileName with special characters replaced 726 * @author Borojevic 727 */ replaceSpecialCharacters(String fileName)728 public static String replaceSpecialCharacters(String fileName) { 729 if (fileName == null || fileName.length() == 0) { 730 return fileName; 731 } 732 for (char element : SPECIAL_CHARACTERS) { 733 fileName = fileName.replace(element, CHAR_REPLACEMENT); 734 } 735 736 return fileName; 737 } 738 join(List<T> objects, String separator)739 public static <T> String join(List<T> objects, String separator) { 740 StringBuilder result = new StringBuilder(); 741 for (int i = 0; i < objects.size(); i++) { 742 if (i > 0) { 743 result.append(separator); 744 } 745 result.append(objects.get(i).toString()); 746 } 747 return result.toString(); 748 } 749 copyFile(File from, File to)750 public static void copyFile(File from, File to) { 751 to.getParentFile().mkdirs(); 752 try (InputStream in = new FileInputStream(from); OutputStream out = new FileOutputStream(to)) { 753 byte[] buf = new byte[1024]; 754 int len; 755 while ((len = in.read(buf)) > 0) { 756 out.write(buf, 0, len); 757 } 758 } catch(IOException e){ 759 e.printStackTrace(); 760 } 761 } 762 763 /** 764 * @return a temporary file with the given content. 765 */ createTempFile(String content)766 public static File createTempFile(String content) { 767 try { 768 // Create temp file. 769 File result = File.createTempFile("testng-tmp", ""); 770 771 // Delete temp file when program exits. 772 result.deleteOnExit(); 773 774 // Write to temp file 775 BufferedWriter out = new BufferedWriter(new FileWriter(result)); 776 out.write(content); 777 out.close(); 778 779 return result; 780 } catch (IOException e) { 781 throw new TestNGException(e); 782 } 783 } 784 785 /** 786 * Make sure that either we have an instance or if not, that the method is static 787 */ checkInstanceOrStatic(Object instance, Method method)788 public static void checkInstanceOrStatic(Object instance, Method method) { 789 if (instance == null && method != null && ! Modifier.isStatic(method.getModifiers())) { 790 throw new TestNGException("Can't invoke " + method + ": either make it static or add " 791 + "a no-args constructor to your class"); 792 } 793 } 794 checkReturnType(Method method, Class<?>... returnTypes)795 public static void checkReturnType(Method method, Class<?>... returnTypes) { 796 if (method == null) { 797 return; 798 } 799 for (Class<?> returnType : returnTypes) { 800 if (method.getReturnType() == returnType) { 801 return; 802 } 803 } 804 throw new TestNGException(method.getDeclaringClass().getName() + "." 805 + method.getName() + " MUST return " + toString(returnTypes) + " but returns " + method.getReturnType().getName()); 806 } 807 toString(Class<?>[] classes)808 private static String toString(Class<?>[] classes) { 809 StringBuilder sb = new StringBuilder("[ "); 810 for (int i=0; i<classes.length;) { 811 Class<?> clazz = classes[i]; 812 if (clazz.isArray()) { 813 sb.append(clazz.getComponentType().getName()).append("[]"); 814 } else { 815 sb.append(clazz.getName()); 816 } 817 if (++i < classes.length) { // increment and compare 818 sb.append(" or "); 819 } 820 } 821 sb.append(" ]"); 822 return sb.toString(); 823 } 824 825 /** 826 * Returns the string representation of the specified object, transparently 827 * handling null references and arrays. 828 * 829 * @param obj 830 * the object 831 * @return the string representation 832 */ toString(Object obj)833 public static String toString(Object obj) { 834 String result; 835 if (obj != null) { 836 if (obj instanceof boolean[]) { 837 result = Arrays.toString((boolean[]) obj); 838 } else if (obj instanceof byte[]) { 839 result = Arrays.toString((byte[]) obj); 840 } else if (obj instanceof char[]) { 841 result = Arrays.toString((char[]) obj); 842 } else if (obj instanceof double[]) { 843 result = Arrays.toString((double[]) obj); 844 } else if (obj instanceof float[]) { 845 result = Arrays.toString((float[]) obj); 846 } else if (obj instanceof int[]) { 847 result = Arrays.toString((int[]) obj); 848 } else if (obj instanceof long[]) { 849 result = Arrays.toString((long[]) obj); 850 } else if (obj instanceof Object[]) { 851 result = Arrays.deepToString((Object[]) obj); 852 } else if (obj instanceof short[]) { 853 result = Arrays.toString((short[]) obj); 854 } else { 855 result = obj.toString(); 856 } 857 } else { 858 result = "null"; 859 } 860 return result; 861 } 862 } 863