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

com.squareup.spoon.html.HtmlUtils Maven / Gradle / Ivy

The newest version!
package com.squareup.spoon.html;

import com.squareup.spoon.DeviceDetails;
import com.squareup.spoon.DeviceTestResult;
import com.squareup.spoon.misc.StackTrace;
import java.io.File;
import java.io.IOException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringEscapeUtils;

import static com.squareup.spoon.DeviceTestResult.SCREENSHOT_SEPARATOR;

/** Utilities for representing the execution in HTML. */
final class HtmlUtils {
  private static final String INVALID_ID_CHARS = "[^a-zA-Z0-9]";
  private static final ThreadLocal DATE_FORMAT = new ThreadLocal() {
    @Override protected Format initialValue() {
      return new SimpleDateFormat("yyyy-MM-dd hh:mm a");
    }
  };
  private static final ThreadLocal DATE_FORMAT_TV = new ThreadLocal() {
    @Override protected Format initialValue() {
      return new SimpleDateFormat("EEEE, MMMM dd, h:mm a");
    }
  };

  static String deviceDetailsToString(DeviceDetails details) {
    if (details == null) return null;

    StringBuilder builder = new StringBuilder();
    builder.append("Running Android ")
        .append(details.getVersion())
        .append(" (API ")
        .append(details.getApiLevel())
        .append(")");

    if (details.getLanguage() != null || details.getRegion() != null) {
      builder.append(" with locale ");
      if (details.getLanguage() != null) {
        builder.append(details.getLanguage());
        if (details.getRegion() != null) {
          builder.append("-");
        }
        if (details.getRegion() != null) {
          builder.append(details.getRegion());
        }
      }
    }

    return builder.toString();
  }

  static String dateToString(long date) {
    return DATE_FORMAT.get().format(new Date(date));
  }

  public static String dateToTvString(long date) {
    return DATE_FORMAT_TV.get().format(new Date(date));
  }

  /** Convert a class name and method name to a single HTML ID. */
  static String testClassAndMethodToId(String className, String methodName) {
    return className.replaceAll(INVALID_ID_CHARS, "-") + "-" //
        + methodName.replaceAll(INVALID_ID_CHARS, "-");
  }

  /** Fake Class#getSimpleName logic. */
  static String getClassSimpleName(String className) {
    int lastPeriod = className.lastIndexOf(".");
    if (lastPeriod != -1) {
      return className.substring(lastPeriod + 1);
    }
    return className;
  }

  /** Convert a test result status into an HTML CSS class. */
  static String getStatusCssClass(DeviceTestResult testResult) {
    String status;
    switch (testResult.getStatus()) {
      case PASS:
        status = "pass";
        break;
      case FAIL:
        status = "fail";
        break;
      default:
        throw new IllegalArgumentException("Unknown result status: " + testResult.getStatus());
    }
    return status;
  }

  /** Convert a method name from {@code testThisThing_DoesThat} to "This Thing, Does That". */
  static String prettifyMethodName(String methodName) {
    if (methodName.startsWith("test")) {
      methodName = methodName.substring(4);
    } else if (Character.isLowerCase(methodName.charAt(0))) {
      methodName = Character.toUpperCase(methodName.charAt(0)) + methodName.substring(1);
    }
    StringBuilder pretty = new StringBuilder();
    String[] parts = methodName.split("_");
    for (String part : parts) {
      if ("".equals(part.trim())) {
        continue; // Skip empty parts.
      }
      if (pretty.length() > 0) {
        pretty.append(",");
      }
      boolean inUpper = true;
      for (char letter : part.toCharArray()) {
        boolean isUpper = Character.isUpperCase(letter);
        if (!isUpper && inUpper && pretty.length() > 1 //
            && pretty.charAt(pretty.length() - 2) != ' ') {
          // Lowercase coming from an uppercase, insert a space before uppercase if not present.
          pretty.insert(pretty.length() - 1, " ");
        } else if (isUpper && !inUpper) {
          // Uppercase coming from a lowercase, add a space.
          pretty.append(" ");
        }
        inUpper = isUpper; // Update current upper/lower status.
        pretty.append(letter); // Append ourselves!
      }
    }
    return pretty.toString();
  }

  /** Convert an image name from {@code 87243508_this-here-is-it} to "This Here Is It". */
  static String prettifyImageName(String imageName) {
    imageName = FilenameUtils.removeExtension(imageName);

    // Remove the timestamp information.
    imageName = imageName.split(SCREENSHOT_SEPARATOR, 2)[1];

    StringBuilder pretty = new StringBuilder();
    for (String part : imageName.replace('_', '-').split("-")) {
      if ("".equals(part.trim())) {
        continue; // Skip empty parts.
      }

      pretty.append(Character.toUpperCase(part.charAt(0)));
      pretty.append(part, 1, part.length());
      pretty.append(" ");
    }

    return pretty.deleteCharAt(pretty.length() - 1).toString();
  }

  /** Get a relative URI for {@code file} from {@code output} folder. */
  static String createRelativeUri(File file, File output) {
    if (file == null) {
      return null;
    }
    try {
      file = file.getCanonicalFile();
      output = output.getCanonicalFile();
      if (file.equals(output)) {
        throw new IllegalArgumentException("File path and output folder are the same.");
      }
      StringBuilder builder = new StringBuilder();
      while (!file.equals(output)) {
        if (builder.length() > 0) {
          builder.insert(0, "/");
        }
        builder.insert(0, file.getName());
        file = file.getParentFile().getCanonicalFile();
      }
      return builder.toString();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  /** Get a HTML representation of a screenshot with respect to {@code output} directory. */
  static Screenshot getScreenshot(File screenshot, File output) {
    String relativePath = createRelativeUri(screenshot, output);
    String caption = prettifyImageName(screenshot.getName());
    return new Screenshot(relativePath, caption);
  }

  public static HtmlUtils.SavedFile getFile(File file, File output) {
    return new SavedFile(createRelativeUri(file, output), file.getName());
  }

  /** Parse the string representation of an exception to a {@link ExceptionInfo} instance. */
  static ExceptionInfo processStackTrace(StackTrace exception) {
    if (exception == null) {
      return null;
    }
    // Escape any special HTML characters in the exception that would otherwise break the HTML
    // rendering (e.g. the angle brackets around the default toString() for enums).
    String message = StringEscapeUtils.escapeHtml4(exception.toString());

    // Newline characters are usually stripped out by the parsing code in
    // {@link StackTrace#from(String)}, but they can sometimes remain (e.g. when the stack trace
    // is not in an expected format).  This replacement needs to be done after any HTML escaping.
    message = message.replace("\n", "
"); List lines = new ArrayList(); for (StackTrace.Element element : exception.getElements()) { lines.add("    at " + element.toString()); } while (exception.getCause() != null) { exception = exception.getCause(); String causeMessage = StringEscapeUtils.escapeHtml4(exception.toString()); lines.add("Caused by: " + causeMessage.replace("\n", "
")); } return new ExceptionInfo(message, lines); } static String humanReadableDuration(long length) { long minutes = length / 60; long seconds = length - (minutes * 60); StringBuilder builder = new StringBuilder(); if (minutes != 0) { builder.append(minutes).append(" minute"); if (minutes != 1) { builder.append("s"); } } if (seconds != 0 || minutes == 0) { if (builder.length() > 0) { builder.append(", "); } builder.append(seconds).append(" second"); if (seconds != 1) { builder.append("s"); } } return builder.toString(); } static final class Screenshot { private static final AtomicLong ID = new AtomicLong(0); public final long id; public final String path; public final String caption; Screenshot(String path, String caption) { this.id = ID.getAndIncrement(); this.path = path; this.caption = caption; } } static final class SavedFile { private static final AtomicLong ID = new AtomicLong(0); private final long id; public final String path; public final String name; SavedFile(String path, String name) { this.id = ID.incrementAndGet(); this.path = path; this.name = name; } } static final class ExceptionInfo { private static final AtomicLong ID = new AtomicLong(0); public final long id; public final String title; public final List body; ExceptionInfo(String title, List body) { this.id = ID.getAndIncrement(); this.title = title; this.body = body; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy