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

mockit.coverage.modification.ClassSelection Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains mocking/faking APIs and a code coverage tool, supporting both JUnit and TestNG. The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested in isolation from selected dependencies.

There is a newer version: 1.49
Show newest version
/*
 * Copyright (c) 2006 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.coverage.modification;

import java.net.*;
import java.security.*;
import java.util.regex.*;
import javax.annotation.*;
import static java.util.regex.Pattern.*;

import mockit.coverage.*;
import static mockit.internal.util.GeneratedClasses.isExternallyGeneratedSubclass;

final class ClassSelection
{
   private static final String THIS_CLASS_NAME = ClassSelection.class.getName();
   private static final ClassLoader THIS_CLASS_LOADER = ClassSelection.class.getClassLoader();
   private static final Pattern CSV = compile(",");
   private static final Pattern DOT = compile("\\.");
   private static final Pattern STAR = compile("\\*");
   private static final Pattern TEST_CLASS_NAME = compile(".+Test(\\$.+)?");

   boolean loadedOnly;
   @Nullable private Matcher classesToInclude;
   @Nullable private Matcher classesToExclude;
   @Nullable private final Matcher testCode;
   private boolean configurationRead;

   ClassSelection()
   {
      if (CodeCoverage.isTestRun()) {
         testCode = TEST_CLASS_NAME.matcher("");
      }
      else {
         testCode = null;
         readConfiguration();
      }
   }

   @Nullable
   private static Matcher newMatcherForClassSelection(@Nonnull String specification)
   {
      if (specification.isEmpty()) {
         return null;
      }

      String[] specs = CSV.split(specification);
      StringBuilder finalRegexBuilder = new StringBuilder();
      String sep = "";

      for (String spec : specs) {
         String regex = null;

         if (spec.indexOf('\\') >= 0) {
            regex = spec;
         }
         else if (!spec.isEmpty()) {
            regex = DOT.matcher(spec).replaceAll("\\.");
            regex = STAR.matcher(regex).replaceAll(".*");
            regex = regex.replace('?', '.');
         }

         if (regex != null) {
            finalRegexBuilder.append(sep).append(regex);
            sep = "|";
         }
      }

      String finalRegex = finalRegexBuilder.toString();
      return finalRegex.isEmpty() ? null : compile(finalRegex).matcher("");
   }

   boolean isSelected(@Nonnull String className, @Nonnull ProtectionDomain protectionDomain)
   {
      CodeSource codeSource = protectionDomain.getCodeSource();

      if (
         codeSource == null || isIneligibleForSelection(className) ||
         !canAccessJMockitFromClassToBeMeasured(protectionDomain)
      ) {
         return false;
      }

      URL location = findLocationInCodeSource(className, protectionDomain);

      if (location == null) {
         return false;
      }

      if (!configurationRead) {
         readConfiguration();
      }

      if (isClassExcludedFromCoverage(className)) {
         return false;
      }

      if (classesToInclude != null) {
         return classesToInclude.reset(className).matches();
      }

      return !isClassFromExternalLibrary(location);
   }

   private static boolean isIneligibleForSelection(@Nonnull String className)
   {
      return
         className.charAt(0) == '[' ||
         className.startsWith("mockit.") || className.contains(".attach.") ||
         className.startsWith("org.hamcrest.") ||
         className.startsWith("org.junit.") || className.startsWith("junit.") ||
         className.startsWith("org.testng.") ||
         className.startsWith("org.apache.maven.surefire.") ||
         isExternallyGeneratedSubclass(className);
   }

   private static boolean canAccessJMockitFromClassToBeMeasured(@Nonnull ProtectionDomain protectionDomain)
   {
      ClassLoader loaderOfClassToBeMeasured = protectionDomain.getClassLoader();

      if (loaderOfClassToBeMeasured != null) {
         try {
            Class thisClass = loaderOfClassToBeMeasured.loadClass(THIS_CLASS_NAME);
            return thisClass == ClassSelection.class;
         }
         catch (ClassNotFoundException ignore) {}
      }

      return false;
   }

   @Nullable
   private static URL findLocationInCodeSource(@Nonnull String className, @Nonnull ProtectionDomain protectionDomain)
   {
      URL location = protectionDomain.getCodeSource().getLocation();

      if (location == null) {
         if (protectionDomain.getClassLoader() == THIS_CLASS_LOADER) {
            return null; // it's likely a dynamically generated class
         }

         // It's from a custom class loader, so it may exist in the classpath.
         String classFileName = className.replace('.', '/') + ".class";
         location = THIS_CLASS_LOADER.getResource(classFileName);
      }

      return location;
   }

   private boolean isClassExcludedFromCoverage(@Nonnull String className)
   {
      return
         classesToExclude != null && classesToExclude.reset(className).matches() ||
         testCode != null && testCode.reset(className).matches();
   }

   private boolean isClassFromExternalLibrary(@Nonnull URL location)
   {
      if ("jar".equals(location.getProtocol())) {
         return true;
      }

      String path = location.getPath();
      return path.endsWith(".jar") || path.endsWith("/.cp/") || testCode != null && path.endsWith("/test-classes/");
   }

   private void readConfiguration()
   {
      String classes = Configuration.getProperty("classes", "");
      loadedOnly = "loaded".equals(classes);
      classesToInclude = loadedOnly ? null : newMatcherForClassSelection(classes);

      String excludes = Configuration.getProperty("excludes", "");
      classesToExclude = newMatcherForClassSelection(excludes);

      configurationRead = true;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy