View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
4    */
5   package mockit.coverage;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import java.lang.instrument.ClassFileTransformer;
11  import java.security.ProtectionDomain;
12  
13  import mockit.coverage.data.CoverageData;
14  import mockit.coverage.modification.ClassModification;
15  import mockit.coverage.modification.ClassesNotLoaded;
16  import mockit.internal.startup.Startup;
17  
18  public final class CodeCoverage implements ClassFileTransformer {
19      @NonNull
20      private final ClassModification classModification;
21  
22      public static void main(@NonNull String[] args) {
23          OutputFileGenerator generator = createOutputFileGenerator();
24          generator.generateAggregateReportFromInputFiles(args);
25      }
26  
27      @NonNull
28      private static OutputFileGenerator createOutputFileGenerator() {
29          OutputFileGenerator generator = new OutputFileGenerator();
30          CoverageData.instance().setWithCallPoints(generator.isWithCallPoints());
31          return generator;
32      }
33  
34      public static boolean active() {
35          String coverageOutput = Configuration.getProperty("output");
36          String coverageClasses = Configuration.getProperty("classes");
37          return (coverageOutput != null || coverageClasses != null) && !"none".equals(coverageOutput)
38                  && !"none".equals(coverageClasses);
39      }
40  
41      public CodeCoverage() {
42          classModification = new ClassModification();
43          final OutputFileGenerator outputGenerator = createOutputFileGenerator();
44          final CoverageCheck coverageCheck = CoverageCheck.createIfApplicable();
45  
46          Runtime.getRuntime().addShutdownHook(new Thread() {
47              @Override
48              public void run() {
49                  TestRun.terminate();
50  
51                  if (outputGenerator.isOutputToBeGenerated()) {
52                      if (classModification.shouldConsiderClassesNotLoaded()) {
53                          new ClassesNotLoaded(classModification).gatherCoverageData();
54                      }
55  
56                      Startup.instrumentation().removeTransformer(CodeCoverage.this);
57                      outputGenerator.generate();
58                  } else {
59                      Startup.instrumentation().removeTransformer(CodeCoverage.this);
60                  }
61  
62                  if (coverageCheck != null) {
63                      coverageCheck.verifyThresholds();
64                  }
65              }
66          });
67      }
68  
69      @Nullable
70      @Override
71      public byte[] transform(@Nullable ClassLoader loader, @NonNull String internalClassName,
72              @Nullable Class<?> classBeingRedefined, @Nullable ProtectionDomain protectionDomain,
73              @NonNull byte[] originalClassfile) {
74          if (loader == null || classBeingRedefined != null || protectionDomain == null) {
75              return null;
76          }
77  
78          String className = internalClassName.replace('/', '.');
79          return classModification.modifyClass(className, protectionDomain, originalClassfile);
80      }
81  }