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