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

mockit.coverage.data.CoverageData Maven / Gradle / Ivy

/*
 * Copyright (c) 2006-2014 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.coverage.data;

import java.io.*;
import java.security.*;
import java.util.*;

import org.jetbrains.annotations.*;

import mockit.coverage.*;

/**
 * Coverage data captured for all source files exercised during a test run.
 */
public final class CoverageData implements Serializable
{
   private static final long serialVersionUID = -4860004226098360259L;
   @NotNull private static final CoverageData instance = new CoverageData();

   @NotNull public static CoverageData instance() { return instance; }

   private boolean withCallPoints;

   @NotNull private final Map fileToFileData = new HashMap();
   @NotNull private final List indexedFileData = new ArrayList(100);

   public boolean isWithCallPoints() { return withCallPoints; }
   public void setWithCallPoints(boolean withCallPoints) { this.withCallPoints = withCallPoints; }

   /**
    * Returns an immutable map containing all source files with the corresponding coverage data gathered for each
    * file during a test run.
    */
   @NotNull public Map getFileToFileDataMap()
   {
      return Collections.unmodifiableMap(new HashMap(fileToFileData));
   }

   @NotNull public FileCoverageData getOrAddFile(@NotNull String file, @Nullable String kindOfTopLevelType)
   {
      FileCoverageData fileData = fileToFileData.get(file);

      // For a class with nested/inner classes, a previous class in the same source file may already have been added.
      if (fileData == null) {
         int fileIndex = indexedFileData.size();
         fileData = new FileCoverageData(fileIndex, kindOfTopLevelType);
         indexedFileData.add(fileData);
         fileToFileData.put(file, fileData);
      }
      else if (kindOfTopLevelType != null) {
         fileData.kindOfTopLevelType = kindOfTopLevelType;
      }

      return fileData;
   }

   @NotNull public FileCoverageData getFileData(@NotNull String file) { return fileToFileData.get(file); }
   @NotNull public FileCoverageData getFileData(int fileIndex) { return indexedFileData.get(fileIndex); }

   public boolean isEmpty() { return fileToFileData.isEmpty(); }
   public void clear() { fileToFileData.clear(); }

   /**
    * Computes the coverage percentage for a given metric, over a subset of the available source files.
    *
    * @param fileNamePrefix a regular expression for matching the names of the source files to be considered, or
    *                      {@code null} to consider all files
    *
    * @return the computed percentage from {@literal 0} to {@literal 100} (inclusive), or {@literal -1} if no
    * meaningful value could be computed for the metric
    */
   public int getPercentage(@NotNull Metrics metric, @Nullable String fileNamePrefix)
   {
      int coveredItems = 0;
      int totalItems = 0;

      for (Map.Entry fileAndFileData : fileToFileData.entrySet()) {
         String sourceFile = fileAndFileData.getKey();

         if (fileNamePrefix == null || sourceFile.startsWith(fileNamePrefix)) {
            FileCoverageData fileData = fileAndFileData.getValue();
            PerFileCoverage coverageInfo = fileData.getPerFileCoverage(metric);
            coveredItems += coverageInfo.getCoveredItems();
            totalItems += coverageInfo.getTotalItems();
         }
      }

      return CoveragePercentage.calculate(coveredItems, totalItems);
   }

   /**
    * Finds the source file with the smallest coverage percentage for a given metric.
    *
    * @return the percentage value for the file found, or {@code Integer.MAX_VALUE} if no file is found with a
    * meaningful coverage percentage
    */
   public int getSmallestPerFilePercentage(@NotNull Metrics metric)
   {
      int minPercentage = Integer.MAX_VALUE;

      for (FileCoverageData fileData : fileToFileData.values()) {
         PerFileCoverage coverageInfo = fileData.getPerFileCoverage(metric);
         int percentage = coverageInfo.getCoveragePercentage();
         if (percentage >= 0 && percentage < minPercentage) minPercentage = percentage;
      }

      return minPercentage;
   }

   public void reset()
   {
      for (FileCoverageData fileCoverageData : fileToFileData.values()) {
         fileCoverageData.reset();
      }
   }

   public void fillLastModifiedTimesForAllClassFiles()
   {
      for (Iterator> itr = fileToFileData.entrySet().iterator(); itr.hasNext(); ) {
         Map.Entry fileAndFileData = itr.next();
         File coveredClassFile = getClassFile(fileAndFileData.getKey());

         if (coveredClassFile != null) {
            fileAndFileData.getValue().lastModified = coveredClassFile.lastModified();
         }
         else {
            itr.remove();
         }
      }
   }

   @Nullable private File getClassFile(@NotNull String sourceFilePath)
   {
      String sourceFilePathNoExt = sourceFilePath.substring(0, sourceFilePath.lastIndexOf('.'));
      String className = sourceFilePathNoExt.replace('/', '.');

      Class coveredClass = findCoveredClass(className);

      if (coveredClass == null) {
         return null;
      }

      CodeSource codeSource = coveredClass.getProtectionDomain().getCodeSource();
      String pathToClassFile = codeSource.getLocation().getPath() + sourceFilePathNoExt + ".class";

      return new File(pathToClassFile);
   }

   @Nullable private Class findCoveredClass(@NotNull String className)
   {
      ClassLoader currentCL = getClass().getClassLoader();
      Class coveredClass = loadClass(className, currentCL);

      if (coveredClass == null) {
         ClassLoader systemCL = ClassLoader.getSystemClassLoader();

         if (systemCL != currentCL) {
            coveredClass = loadClass(className, systemCL);
         }

         if (coveredClass == null) {
            ClassLoader contextCL = Thread.currentThread().getContextClassLoader();

            if (contextCL != null && contextCL != systemCL) {
               coveredClass = loadClass(className, contextCL);
            }
         }
      }

      return coveredClass;
   }

   @Nullable private Class loadClass(@NotNull String className, @Nullable ClassLoader loader)
   {
      try {
         return Class.forName(className, false, loader);
      }
      catch (ClassNotFoundException ignore) { return null; }
      catch (NoClassDefFoundError ignored) { return null; }
   }

   /**
    * Reads a serialized {@code CoverageData} object from the given file (normally, a "coverage.ser" file
    * generated at the end of a previous test run).
    *
    * @param dataFile the ".ser" file containing a serialized {@code CoverageData} instance
    *
    * @return a new object containing all coverage data resulting from a previous test run
    */
   @NotNull public static CoverageData readDataFromFile(@NotNull File dataFile) throws IOException
   {
      ObjectInputStream input = new ObjectInputStream(new BufferedInputStream(new FileInputStream(dataFile)));

      try {
         return (CoverageData) input.readObject();
      }
      catch (ClassNotFoundException e) {
         throw new RuntimeException(
            "Serialized class in coverage data file \"" + dataFile + "\" not found in classpath", e);
      }
      finally {
         input.close();
      }
   }

   public void writeDataToFile(@NotNull File dataFile) throws IOException
   {
      ObjectOutputStream output = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)));

      try {
         output.writeObject(this);
      }
      finally {
         output.close();
      }
   }

   public void merge(@NotNull CoverageData previousData)
   {
      withCallPoints |= previousData.withCallPoints;

      for (Map.Entry previousFileAndFileData : previousData.fileToFileData.entrySet()) {
         String previousFile = previousFileAndFileData.getKey();
         FileCoverageData previousFileData = previousFileAndFileData.getValue();
         FileCoverageData fileData = fileToFileData.get(previousFile);

         if (fileData == null) {
            fileToFileData.put(previousFile, previousFileData);
         }
         else if (previousFileData.lastModified == fileData.lastModified) {
            fileData.mergeWithDataFromPreviousTestRun(previousFileData);
         }
      }
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy