1
2
3
4
5
6 package mockit.coverage;
7
8 import edu.umd.cs.findbugs.annotations.NonNull;
9
10 import java.io.File;
11 import java.io.IOException;
12 import java.io.Writer;
13 import java.nio.charset.StandardCharsets;
14 import java.nio.file.Files;
15 import java.nio.file.Path;
16 import java.util.Map.Entry;
17
18 import mockit.coverage.data.CoverageData;
19 import mockit.coverage.data.FileCoverageData;
20 import mockit.coverage.lines.LineCoverageData;
21 import mockit.coverage.lines.PerFileLineCoverage;
22
23 import org.checkerframework.checker.index.qual.NonNegative;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 final class XmlFile {
41
42
43 private static final Logger logger = LoggerFactory.getLogger(XmlFile.class);
44
45 @NonNull
46 private final String srcDir;
47 @NonNull
48 private final File outputFile;
49 @NonNull
50 private final CoverageData coverageData;
51
52 XmlFile(@NonNull String outputDir, @NonNull CoverageData coverageData) {
53
54 String firstSrcDir = Configuration.getProperty("srcDirs", "").split("\\s*,\\s*")[0];
55 srcDir = firstSrcDir.isEmpty() ? "" : firstSrcDir + '/';
56
57 String parentDir = Configuration.getOrChooseOutputDirectory(outputDir);
58 outputFile = Path.of(parentDir, "coverage.xml").toFile();
59 this.coverageData = coverageData;
60 }
61
62 void generate() throws IOException {
63 try (Writer out = Files.newBufferedWriter(outputFile.toPath(), StandardCharsets.UTF_8)) {
64 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
65 out.write("<coverage version=\"1\">\n");
66
67 for (Entry<String, FileCoverageData> fileAndData : coverageData.getFileToFileData().entrySet()) {
68 String sourceFileName = fileAndData.getKey();
69 writeOpeningXmlElementForSourceFile(out, sourceFileName);
70
71 PerFileLineCoverage lineInfo = fileAndData.getValue().lineCoverageInfo;
72 writeXmlElementsForExecutableLines(out, lineInfo);
73
74 out.write("\t</file>\n");
75 }
76
77 out.write("</coverage>\n");
78 }
79
80 logger.info("JMockit: Coverage data written to {}", outputFile.getCanonicalPath());
81 }
82
83 private void writeOpeningXmlElementForSourceFile(@NonNull Writer out, @NonNull String sourceFileName)
84 throws IOException {
85 out.write("\t<file path=\"");
86 out.write(srcDir);
87 out.write(sourceFileName);
88 out.write("\">\n");
89 }
90
91 private static void writeXmlElementsForExecutableLines(@NonNull Writer out, @NonNull PerFileLineCoverage lineInfo)
92 throws IOException {
93 int lineCount = lineInfo.getLineCount();
94
95 for (int lineNum = 1; lineNum <= lineCount; lineNum++) {
96 if (lineInfo.hasLineData(lineNum)) {
97 LineCoverageData lineData = lineInfo.getLineData(lineNum);
98
99 out.write("\t\t<lineToCover lineNumber=\"");
100 writeNumber(out, lineNum);
101 out.write("\" covered=\"");
102 out.write(Boolean.toString(lineData.isCovered()));
103
104 if (lineData.containsBranches()) {
105 out.write("\" branchesToCover=\"");
106 writeNumber(out, lineData.getNumberOfBranchingSourcesAndTargets());
107 out.write("\" coveredBranches=\"");
108 writeNumber(out, lineData.getNumberOfCoveredBranchingSourcesAndTargets());
109 }
110
111 out.write("\"/>\n");
112 }
113 }
114 }
115
116 private static void writeNumber(@NonNull Writer out, @NonNegative int value) throws IOException {
117 out.write(Integer.toString(value));
118 }
119 }