1
2
3
4
5 package mockit.coverage.reporting;
6
7 import edu.umd.cs.findbugs.annotations.NonNull;
8 import edu.umd.cs.findbugs.annotations.Nullable;
9
10 import java.io.File;
11 import java.io.IOException;
12 import java.nio.file.Path;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.Set;
20
21 import mockit.coverage.Configuration;
22 import mockit.coverage.data.CoverageData;
23 import mockit.coverage.data.FileCoverageData;
24 import mockit.coverage.reporting.packages.IndexPage;
25 import mockit.coverage.reporting.sourceFiles.FileCoverageReport;
26 import mockit.coverage.reporting.sourceFiles.InputFile;
27
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 public final class CoverageReport {
32
33
34 private static final Logger logger = LoggerFactory.getLogger(CoverageReport.class);
35
36 @NonNull
37 private final String outputDir;
38 private boolean outputDirCreated;
39 @Nullable
40 private final List<File> sourceDirs;
41 @NonNull
42 private final Map<String, FileCoverageData> fileToFileData;
43 @NonNull
44 private final Map<String, List<String>> packageToFiles;
45 private final boolean withCallPoints;
46 @Nullable
47 private final Collection<String> sourceFilesNotFound;
48
49 public CoverageReport(@NonNull String outputDir, boolean outputDirCreated, @Nullable String[] srcDirs,
50 @NonNull CoverageData coverageData, boolean withCallPoints) {
51 this.outputDir = Configuration.getOrChooseOutputDirectory(outputDir, "coverage-report");
52 this.outputDirCreated = outputDirCreated;
53 sourceDirs = srcDirs == null ? null : new SourceFiles().buildListOfSourceDirectories(srcDirs);
54 fileToFileData = coverageData.getFileToFileData();
55 packageToFiles = new HashMap<>();
56 this.withCallPoints = withCallPoints;
57 sourceFilesNotFound = srcDirs == null ? null : new ArrayList<>();
58 }
59
60 public void generate() throws IOException {
61 createReportOutputDirIfNotExists();
62
63 File outputFile = createOutputFileForIndexPage();
64
65 if (outputFile == null) {
66 return;
67 }
68
69 boolean withSourceFilePages = sourceDirs != null;
70
71 if (withSourceFilePages && sourceDirs.size() > 1) {
72 logger.info("JMockit: Coverage source dirs: {}", sourceDirs);
73 }
74
75 generateFileCoverageReportsWhileBuildingPackageLists();
76
77 new StaticFiles(outputDir).copyToOutputDir(withSourceFilePages);
78 new IndexPage(outputFile, sourceDirs, sourceFilesNotFound, packageToFiles, fileToFileData).generate();
79
80 logger.info("JMockit: Coverage report written to {}", outputFile.getParentFile().getCanonicalPath());
81 }
82
83 private void createReportOutputDirIfNotExists() {
84 if (!outputDirCreated) {
85 File outDir = Path.of(outputDir).toFile();
86 outputDirCreated = outDir.mkdirs();
87 }
88 }
89
90 @Nullable
91 private File createOutputFileForIndexPage() throws IOException {
92 File outputFile = Path.of(outputDir, "index.html").toFile();
93
94 if (outputFile.exists() && !outputFile.canWrite()) {
95 logger.info("JMockit: {} is read-only; report generation canceled", outputFile.getCanonicalPath());
96 return null;
97 }
98
99 return outputFile;
100 }
101
102 private void generateFileCoverageReportsWhileBuildingPackageLists() throws IOException {
103 Set<Entry<String, FileCoverageData>> files = fileToFileData.entrySet();
104
105 for (Entry<String, FileCoverageData> fileAndFileData : files) {
106 generateFileCoverageReport(fileAndFileData.getKey(), fileAndFileData.getValue());
107 }
108 }
109
110 private void generateFileCoverageReport(@NonNull String sourceFile, @NonNull FileCoverageData fileData)
111 throws IOException {
112 if (sourceDirs != null) {
113 InputFile inputFile = InputFile.createIfFileExists(sourceDirs, sourceFile);
114
115 if (inputFile != null) {
116 new FileCoverageReport(outputDir, inputFile, fileData, withCallPoints).generate();
117 } else {
118 deleteOutdatedHTMLFileIfExists(sourceFile);
119
120 if (sourceFilesNotFound != null) {
121 sourceFilesNotFound.add(sourceFile);
122 }
123 }
124 }
125
126 addFileToPackageFileList(sourceFile);
127 }
128
129 private void addFileToPackageFileList(@NonNull String file) {
130 int p = file.lastIndexOf('/');
131 String filePackage = p < 0 ? "" : file.substring(0, p);
132 List<String> filesInPackage = packageToFiles.get(filePackage);
133
134 if (filesInPackage == null) {
135 filesInPackage = new ArrayList<>();
136 packageToFiles.put(filePackage, filesInPackage);
137 }
138
139 filesInPackage.add(file.substring(p + 1));
140 }
141
142 private void deleteOutdatedHTMLFileIfExists(@NonNull String filePath) {
143 if (!outputDirCreated) {
144 File outputFile = OutputFile.getOutputFile(outputDir, filePath);
145
146 outputFile.delete();
147 }
148 }
149 }