All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.testng.internal.Utils Maven / Gradle / Ivy

The newest version!
package org.testng.internal;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.testng.ITestNGMethod;
import org.testng.TestNGException;
import org.testng.collections.Lists;
import org.testng.log4testng.Logger;
import org.testng.reporters.XMLStringBuffer;

/** Helper methods to parse annotations. */
public final class Utils {

  private static final String LINE_SEP = RuntimeBehavior.getDefaultLineSeparator();

  private static final char[] SPECIAL_CHARACTERS = {
    '*', '/', '\\', '?', '%', ':', ';', '<', '>', '&', '~', '|'
  };
  public static final char CHAR_REPLACEMENT = '_';
  public static final char UNICODE_REPLACEMENT = 0xFFFD;
  private static final String FORMAT = String.format("[%s]", Utils.class.getSimpleName());

  private static final Logger LOG = Logger.getLogger(Utils.class);

  private static final Map ESCAPES = new HashMap<>();

  static {
    ESCAPES.put('<', "<");
    ESCAPES.put('>', ">");
    ESCAPES.put('\'', "'");
    ESCAPES.put('"', """);
    ESCAPES.put('&', "&");
  }

  // Moved from TestRunner
  // TODO: replace with Logger?
  private static int m_verbose = 1;

  /** Hide constructor for utility class. */
  private Utils() {
    // Hide constructor
  }

  public static int getVerbose() {
    return m_verbose;
  }

  public static void setVerbose(int n) {
    m_verbose = n;
  }

  public static void writeUtf8File(
      @Nullable String outputDir, String fileName, XMLStringBuffer xsb, String prefix) {
    try {
      final File outDir =
          (outputDir != null) ? new File(outputDir) : new File("").getAbsoluteFile();
      if (!outDir.exists()) {
        boolean ignored = outDir.mkdirs();
      }
      final File file = new File(outDir, fileName);
      if (!file.exists()) {
        boolean ignored = file.createNewFile();
      }
      try (final OutputStreamWriter w =
          new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
        if (prefix != null) {
          w.append(prefix);
        }
        xsb.toWriter(w);
      }
    } catch (IOException ex) {
      LOG.error(ex.getMessage(), ex);
    }
  }

  /**
   * Writes the content of the sb string to the file named filename in outDir encoding the output as
   * UTF-8. If outDir does not exist, it is created.
   *
   * @param outputDir the output directory (may not exist). If null then current
   *     directory is used.
   * @param fileName the filename
   * @param sb the file content
   */
  public static void writeUtf8File(@Nullable String outputDir, String fileName, String sb) {
    final String outDirPath = outputDir != null ? outputDir : "";
    final File outDir = new File(outDirPath);
    writeFile(outDir, fileName, escapeUnicode(sb), "UTF-8");
  }

  /**
   * Writes the content of the sb string to the file named filename in outDir. If outDir does not
   * exist, it is created.
   *
   * @param outputDir the output directory (may not exist). If null then current
   *     directory is used.
   * @param fileName the filename
   * @param sb the file content
   */
  public static void writeFile(@Nullable String outputDir, String fileName, String sb) {
    final String outDirPath = outputDir != null ? outputDir : "";
    final File outDir = new File(outDirPath);
    writeFile(outDir, fileName, sb, null);
  }

  /**
   * Writes the content of the sb string to the file named filename in outDir. If outDir does not
   * exist, it is created.
   *
   * @param outputFolder the output directory (may not exist). If null then current
   *     directory is used.
   * @param fileNameParameter the filename
   * @param sb the file content
   */
  private static void writeFile(
      @Nullable File outputFolder, String fileNameParameter, String sb, @Nullable String encoding) {
    File outDir = outputFolder;
    String fileName = fileNameParameter;
    try {
      if (outDir == null) {
        outDir = new File("").getAbsoluteFile();
      }
      if (!outDir.exists()) {
        boolean ignored = outDir.mkdirs();
      }

      fileName = replaceSpecialCharacters(fileName);
      File outputFile = new File(outDir, fileName);
      boolean ignored = outputFile.delete();
      log(FORMAT, 3, "Attempting to create " + outputFile);
      log(FORMAT, 3, "  Directory " + outDir + " exists: " + outDir.exists());
      outputFile.createNewFile();
      writeFile(outputFile, sb, encoding);
    } catch (IOException e) {
      if (getVerbose() > 1) {
        LOG.error(e.getMessage(), e);
      } else {
        log(FORMAT, 1, e.getMessage());
      }
    }
  }

  private static void writeFile(File outputFile, String sb, @Nullable String encoding) {
    try (BufferedWriter fw = openWriter(outputFile, encoding)) {
      fw.write(sb);

      Utils.log("", 3, "Creating " + outputFile.getAbsolutePath());
    } catch (IOException ex) {
      if (getVerbose() > 1) {
        LOG.error("ERROR WHILE WRITING TO " + outputFile, ex);
      } else {
        log(FORMAT, 1, "Error while writing to " + outputFile + ": " + ex.getMessage());
      }
    }
    // ignore
  }

  /**
   * Open a BufferedWriter for the specified file. If output directory doesn't exist, it is created.
   * If the output file exists, it is deleted. The output file is created in any case.
   *
   * @param outputDir output directory. If null, then current directory is used
   * @param fileNameParameter file name
   * @throws IOException if anything goes wrong while creating files.
   */
  public static BufferedWriter openWriter(@Nullable String outputDir, String fileNameParameter)
      throws IOException {
    String fileName = fileNameParameter;
    String outDirPath = outputDir != null ? outputDir : "";
    File outDir = new File(outDirPath);
    if (!outDir.exists()) {
      boolean ignored = outDir.mkdirs();
    }
    fileName = replaceSpecialCharacters(fileName);
    File outputFile = new File(outDir, fileName);
    boolean ignored = outputFile.delete();
    return openWriter(outputFile, null);
  }

  private static BufferedWriter openWriter(File outputFile, @Nullable String encoding)
      throws IOException {
    if (!outputFile.exists()) {
      boolean ignored = outputFile.createNewFile();
    }
    OutputStreamWriter osw;
    if (null != encoding) {
      osw = new OutputStreamWriter(new FileOutputStream(outputFile), encoding);
    } else {
      osw = new OutputStreamWriter(new FileOutputStream(outputFile));
    }
    return new BufferedWriter(osw);
  }

  public static void log(String msg) {
    log("Utils", 2, msg);
  }

  /**
   * Logs the the message to System.out if level is greater than or equal to getVerbose(). The
   * message is logged as:
   *
   * 
   *     "[cls] msg"
   * 
* * @param cls the class name to prefix the log message. * @param level the logging level of the message. * @param msg the message to log to System.out. */ public static void log(String cls, int level, String msg) { // Why this coupling on a static member of getVerbose()? if (getVerbose() >= level) { if (!cls.isEmpty()) { LOG.info("[" + cls + "] " + msg); } else { LOG.info(msg); } } } public static void error(String errorMessage) { LOG.error("[Error] " + errorMessage); } public static void warn(String warnMsg) { LOG.warn(warnMsg); } /* Tokenize the string using the separator. */ public static String[] split(String string, String sep) { if (string == null || string.isEmpty()) { return new String[0]; } // TODO How different is this from: // return string.split(sep); int start = 0; int idx = string.indexOf(sep, start); int len = sep.length(); List strings = Lists.newArrayList(); while (idx != -1) { strings.add(string.substring(start, idx).trim()); start = idx + len; idx = string.indexOf(sep, start); } strings.add(string.substring(start).trim()); return strings.toArray(new String[0]); } public static void writeResourceToFile(File file, String resourceName, Class clasz) throws IOException { InputStream inputStream = clasz.getResourceAsStream("/" + resourceName); if (inputStream == null) { LOG.error("Couldn't find resource on the class path: " + resourceName); return; } try (inputStream) { try (FileOutputStream outputStream = new FileOutputStream(file)) { int nread; byte[] buffer = new byte[4096]; while (0 < (nread = inputStream.read(buffer))) { outputStream.write(buffer, 0, nread); } } } } public static String defaultIfStringEmpty(String s, String defaultValue) { return isStringEmpty(s) ? defaultValue : s; } public static boolean isStringBlank(String s) { return s == null || s.trim().isEmpty(); } public static boolean isStringEmpty(String s) { return s == null || s.isEmpty(); } public static boolean isStringNotBlank(String s) { return !isStringBlank(s); } public static boolean isStringNotEmpty(String s) { return !isStringEmpty(s); } /** * Helper that returns a short stack trace. * * @param t - The {@link Throwable} exception * @param toHtml - true if the stacktrace should be translated to html as well * @return - A string that represents the short stack trace. */ public static String longStackTrace(Throwable t, boolean toHtml) { return buildStackTrace(t, toHtml, StackTraceType.FULL); } /** * Helper that returns a long stack trace. * * @param t - The {@link Throwable} exception * @param toHtml - true if the stacktrace should be translated to html as well * @return - A string that represents the full stack trace. */ public static String shortStackTrace(Throwable t, boolean toHtml) { return buildStackTrace(t, toHtml, StackTraceType.SHORT); } private static String buildStackTrace(Throwable t, boolean toHtml, StackTraceType type) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); try { t.printStackTrace(pw); } catch (Throwable e) { // failsafe in case if printStackTrace throws exception pw.println(t.getClass().getName()); e.printStackTrace(pw); } pw.flush(); String stackTrace = sw.getBuffer().toString(); if (type == StackTraceType.SHORT && !isTooVerbose()) { stackTrace = filterTrace(sw.getBuffer().toString()); } if (toHtml) { stackTrace = escapeHtml(stackTrace); } return stackTrace; } private static boolean isTooVerbose() { return RuntimeBehavior.showTestNGStackFrames() || getVerbose() >= 2; } private enum StackTraceType { SHORT, FULL } public static String escapeHtml(String s) { if (s == null) { return null; } StringBuilder result = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); String nc = ESCAPES.get(c); if (nc != null) { result.append(nc); } else { result.append(c); } } return result.toString(); } public static String escapeUnicode(String s) { if (s == null) { return null; } StringBuilder result = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); char ca = Character.isDefined(c) ? c : UNICODE_REPLACEMENT; result.append(ca); } return result.toString(); } static String filterTrace(String trace) { StringReader stringReader = new StringReader(trace); BufferedReader bufferedReader = new BufferedReader(stringReader); StringBuilder buf = new StringBuilder(); try { // first line contains the thrown exception String line = bufferedReader.readLine(); if (line == null) { return ""; } buf.append(line).append(LINE_SEP); // // the stack frames of the trace // String[] excludedStrings = new String[] {"org.testng", "reflect", "org.gradle", "org.apache.maven.surefire"}; int excludedCount = 0; while ((line = bufferedReader.readLine()) != null) { boolean isExcluded = false; for (String excluded : excludedStrings) { if (line.contains(excluded)) { isExcluded = true; excludedCount++; break; } } if (!isExcluded) { buf.append(line).append(LINE_SEP); } } if (excludedCount > 0) { buf.append("... Removed ").append(excludedCount).append(" stack frames"); } } catch (IOException ioex) { // do nothing } return buf.toString(); } public static String toString(Object object, Class objectClass) { if (null == object) { return "null"; } final String toString = toString(object); if (isStringEmpty(toString)) { return "\"\""; } else if (String.class.equals(objectClass)) { return "\"" + toString + '\"'; } else { return toString; } } public static String detailedMethodName(ITestNGMethod method, boolean fqn) { String tempName = annotationFormFor(method); if (!tempName.isEmpty()) { tempName += " "; } return tempName + (fqn ? method.toString() : method.getMethodName()); } public static String detailedMethodName(ITestNGMethod method) { String tempName = annotationFormFor(method); if (!tempName.isEmpty()) { tempName += " "; } return tempName + method.getQualifiedName(); } /** * Given a TestNG method, returns the corresponding annotation based on the method type * * @param method - An {@link ITestNGMethod} object. * @return - A String representation of the corresponding annotation. */ public static String annotationFormFor(ITestNGMethod method) { if (method.isBeforeSuiteConfiguration()) { return "@BeforeSuite"; } if (method.isBeforeTestConfiguration()) { return "@BeforeTest"; } if (method.isBeforeClassConfiguration()) { return "@BeforeClass"; } if (method.isBeforeGroupsConfiguration()) { return "@BeforeGroups"; } if (method.isBeforeMethodConfiguration()) { return "@BeforeMethod"; } if (method.isAfterMethodConfiguration()) { return "@AfterMethod"; } if (method.isAfterGroupsConfiguration()) { return "@AfterGroups"; } if (method.isAfterClassConfiguration()) { return "@AfterClass"; } if (method.isAfterTestConfiguration()) { return "@AfterTest"; } if (method.isAfterSuiteConfiguration()) { return "@AfterSuite"; } return ""; } public static String arrayToString(String[] strings) { return String.join(", ", strings); } /** * If the file name contains special characters like *,/,\ and so on, exception will be thrown and * report file will not be created.
* Special characters are platform specific and they are not same for example on Windows and * Macintosh. * is not allowed on Windows, but it is on Macintosh.
* In order to have the same behavior of testng on the all platforms, characters like * will be * replaced on all platforms whether they are causing the problem or not. * * @param fileNameParameter file name that could contain special characters. * @return fileName with special characters replaced */ public static String replaceSpecialCharacters(String fileNameParameter) { String fileName = fileNameParameter; if (fileName == null || fileName.isEmpty()) { return fileName; } for (char element : SPECIAL_CHARACTERS) { fileName = fileName.replace(element, CHAR_REPLACEMENT); } return fileName; } public static String join(List objects, String separator) { return objects.stream().map(Object::toString).collect(Collectors.joining(separator)); } /* Make sure that either we have an instance or if not, that the method is static */ public static void checkInstanceOrStatic(Object instance, Method method) { if (instance == null && method != null && !Modifier.isStatic(method.getModifiers())) { throw new TestNGException( "Can't invoke " + method + ": either make it static or add " + "a no-args constructor to your class"); } } public static void checkReturnType(Method method, Class... returnTypes) { if (method == null) { return; } for (Class returnType : returnTypes) { if (method.getReturnType() == returnType) { return; } } throw new TestNGException( method.getDeclaringClass().getName() + "." + method.getName() + " MUST return " + toString(returnTypes) + " but returns " + method.getReturnType().getName()); } private static String toString(Class[] classes) { StringBuilder sb = new StringBuilder("[ "); for (int i = 0; i < classes.length; i++) { Class clazz = classes[i]; if (clazz.isArray()) { sb.append(clazz.getComponentType().getName()).append("[]"); } else { sb.append(clazz.getName()); } if ((i + 1) < classes.length) { // increment and compare sb.append(" or "); } } sb.append(" ]"); return sb.toString(); } /** * Returns the string representation of the specified object, transparently handling null * references and arrays. * * @param obj the object * @return the string representation */ public static String toString(Object obj) { String result; if (obj != null) { if (obj instanceof boolean[]) { result = Arrays.toString((boolean[]) obj); } else if (obj instanceof byte[]) { result = Arrays.toString((byte[]) obj); } else if (obj instanceof char[]) { result = Arrays.toString((char[]) obj); } else if (obj instanceof double[]) { result = Arrays.toString((double[]) obj); } else if (obj instanceof float[]) { result = Arrays.toString((float[]) obj); } else if (obj instanceof int[]) { result = Arrays.toString((int[]) obj); } else if (obj instanceof long[]) { result = Arrays.toString((long[]) obj); } else if (obj instanceof Object[]) { result = Arrays.deepToString((Object[]) obj); } else if (obj instanceof short[]) { result = Arrays.toString((short[]) obj); } else { result = obj.toString(); } } else { result = "null"; } return result; } public static String stringifyTypes(Class[] parameterTypes) { return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(",")); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy