• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / jmockit1 / 421

30 Oct 2025 07:01PM UTC coverage: 72.198% (+0.02%) from 72.177%
421

push

github

hazendaz
Use better logic for remove redundant source directories

5681 of 8356 branches covered (67.99%)

Branch coverage included in aggregate %.

0 of 6 new or added lines in 1 file covered. (0.0%)

36 existing lines in 4 files now uncovered.

11941 of 16052 relevant lines covered (74.39%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/main/src/main/java/mockit/coverage/reporting/packages/IndexPage.java
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.reporting.packages;
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.lang.reflect.Method;
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.Date;
17
import java.util.HashMap;
18
import java.util.List;
19
import java.util.Map;
20

21
import mockit.coverage.CoveragePercentage;
22
import mockit.coverage.data.FileCoverageData;
23
import mockit.coverage.reporting.OutputFile;
24
import mockit.coverage.testRedundancy.TestCoverage;
25

26
import org.checkerframework.checker.index.qual.NonNegative;
27

28
public final class IndexPage extends ListWithFilesAndPercentages {
×
29
    @Nullable
30
    private final List<File> sourceDirs;
31
    @NonNull
32
    private final Map<String, List<String>> packageToFiles;
33
    @NonNull
34
    private final Map<String, Integer> packageToPackagePercentages;
35
    @NonNull
36
    private final PackageCoverageReport packageReport;
37
    @NonNegative
38
    private final int totalFileCount;
39

40
    public IndexPage(@NonNull File outputFile, @Nullable List<File> sourceDirs,
41
            @Nullable Collection<String> sourceFilesNotFound, @NonNull Map<String, List<String>> packageToFiles,
42
            @NonNull Map<String, FileCoverageData> fileToFileData) throws IOException {
43
        super(new OutputFile(outputFile), "    ");
×
44
        this.sourceDirs = sourceDirs;
×
45
        this.packageToFiles = packageToFiles;
×
46
        packageToPackagePercentages = new HashMap<>();
×
47
        packageReport = new PackageCoverageReport(output, sourceFilesNotFound, fileToFileData, packageToFiles.values());
×
48
        totalFileCount = totalNumberOfSourceFilesWithCoverageData(fileToFileData.values());
×
49
    }
×
50

51
    @NonNegative
52
    private static int totalNumberOfSourceFilesWithCoverageData(@NonNull Collection<FileCoverageData> fileData) {
53
        return fileData.size() - Collections.frequency(fileData, null);
×
54
    }
55

56
    public void generate() {
57
        try {
58
            writeHeader();
×
59

60
            List<String> packages = new ArrayList<>(packageToFiles.keySet());
×
61
            writeMetricsForEachFile(null, packages);
×
62
            writeLineWithCoverageTotal();
×
63
            output.println("  </table>");
×
64

65
            writeListOfRedundantTestsIfAny();
×
66
            writeFooter();
×
67
        } finally {
68
            output.close();
×
69
        }
70
    }
×
71

72
    private void writeHeader() {
73
        ((OutputFile) output).writeCommonHeader("Code Coverage Report");
×
74

75
        output.println("  <table id='packages'>");
×
76

77
        writeTableCaption();
×
78
        writeTableFirstRowWithColumnTitles();
×
79
    }
×
80

81
    private void writeTableCaption() {
82
        if (sourceDirs == null) {
×
83
            output.println("    <caption>All Packages and Files</caption>");
×
84
        } else {
85
            output.write("    <caption>All Packages and Files<div style='font-size: smaller'>");
×
86
            output.write(getCommaSeparatedListOfSourceDirs());
×
87
            output.println("</div></caption>");
×
88
        }
89
    }
×
90

91
    @NonNull
92
    private String getCommaSeparatedListOfSourceDirs() {
93
        List<File> dirs = sourceDirs;
×
94
        assert dirs != null;
×
95
        removeRedundantSourceDirectories(dirs);
×
96

97
        String concatenatedSourceDirs = dirs.toString();
×
98
        String prefixToRemove = ".." + File.separatorChar;
×
99
        String commaSepDirs = concatenatedSourceDirs.replace(prefixToRemove, "");
×
100
        return commaSepDirs.substring(1, commaSepDirs.length() - 1);
×
101
    }
102

103
    private static void removeRedundantSourceDirectories(@NonNull List<File> dirs) {
NEW
104
        int i = 0;
×
NEW
105
        while (i < dirs.size()) {
×
NEW
106
            int newIndex = removeRedundantSourceDirectory(dirs, i);
×
NEW
107
            if (newIndex == i) {
×
NEW
108
                i++;
×
109
            } else {
NEW
110
                i = newIndex;
×
111
            }
112
        }
×
113
    }
×
114

115
    private static int removeRedundantSourceDirectory(@NonNull List<File> dirs, @NonNegative int dirIndex) {
116
        String dir1 = dirs.get(dirIndex).getPath();
×
117
        int j = dirIndex + 1;
×
118

119
        while (j < dirs.size()) {
×
120
            String dir2 = dirs.get(j).getPath();
×
121

122
            if (dir1.startsWith(dir2)) {
×
123
                dirs.remove(j);
×
124
            } else if (dir2.startsWith(dir1)) {
×
125
                dirs.remove(dirIndex);
×
126
                dirIndex--;
×
127
                break;
×
128
            } else {
129
                j++;
×
130
            }
131
        }
×
132

133
        return dirIndex;
×
134
    }
135

136
    private void writeTableFirstRowWithColumnTitles() {
137
        output.println("    <tr>");
×
138
        output.write("      <th style='cursor: col-resize' onclick='showHideAllFiles()'>Packages: ");
×
139
        output.print(packageToFiles.size());
×
140
        output.println("</th>");
×
141
        output.write("      <th onclick='location.reload()' style='cursor: n-resize' title='"
×
142
                + "Click on the column title to the right to sort by size (total number of items).'>Files: ");
143
        output.print(totalFileCount);
×
144
        output.println("</th>");
×
145
        writeHeaderCellWithMetricNameAndDescription();
×
146
        output.println("    </tr>");
×
147
    }
×
148

149
    private void writeHeaderCellWithMetricNameAndDescription() {
150
        output.println("      <th onclick='sortTables()' style='cursor: n-resize' title='"
×
151
                + "Measures how much of the executable production code (executable lines and fields) was exercised by tests.\n\n"
152
                + "An executable line of code contains one or more executable segments, separated by branching points\n"
153
                + "(if..else instructions, logical operators, etc.).\n\n"
154
                + "A non-final field must have the last value assigned to it read by at least one test, to be considered as covered.\n\n"
155
                + "Percentages are calculated as          100 × (CS + CF)\n"
156
                + "                                                         ────────\n"
157
                + "                                                                   S + F\n\n"
158
                + "where S+F is the total number of segments and fields, and CS+CF the covered segments and fields."
159
                + "'>Cvrg</th>");
160
    }
×
161

162
    private void writeLineWithCoverageTotal() {
163
        output.println("    <tr class='total'>");
×
164
        output.println("      <td>Total</td><td>&nbsp;</td>");
×
165

166
        int covered = coveredItems;
×
167
        int total = totalItems;
×
168
        int percentage = CoveragePercentage.calculate(covered, total);
×
169
        printCoveragePercentage(covered, total, percentage);
×
170

171
        output.println("    </tr>");
×
172
    }
×
173

174
    @Override
175
    @SuppressWarnings("ParameterNameDiffersFromOverriddenParameter")
176
    protected void writeMetricsForFile(String unused, @NonNull String packageName) {
177
        writeRowStart();
×
178
        writeTableCellWithPackageName(packageName);
×
179
        writeInternalTableForSourceFiles(packageName);
×
180
        writeCoveragePercentageForPackage(packageName);
×
181
        writeRowClose();
×
182
    }
×
183

184
    private void writeTableCellWithPackageName(@NonNull String packageName) {
185
        printIndent();
×
186
        output.write("  <td");
×
187

188
        List<String> filesInPackage = packageToFiles.get(packageName);
×
189

190
        if (filesInPackage.size() > 1) {
×
191
            output.write(" class='click' onclick='shFls(this)'");
×
192
        }
193

194
        output.write('>');
×
195
        output.write(packageName.replace('/', '.'));
×
196
        output.println("</td>");
×
197
    }
×
198

199
    private void writeInternalTableForSourceFiles(@NonNull String packageName) {
200
        printIndent();
×
201
        output.println("  <td>");
×
202

203
        printIndent();
×
204
        output.println("    <table>");
×
205

206
        List<String> fileNames = packageToFiles.get(packageName);
×
207
        packageReport.writeMetricsForEachFile(packageName, fileNames);
×
208

209
        recordCoverageInformationForPackage(packageName);
×
210

211
        printIndent();
×
212
        output.println("    </table>");
×
213
        printIndent();
×
214

215
        writeInitiallyHiddenSourceFileCount(fileNames.size());
×
216
        printIndent();
×
217
        output.println("  </td>");
×
218
    }
×
219

220
    private void recordCoverageInformationForPackage(@NonNull String packageName) {
221
        int coveredInPackage = packageReport.coveredItems;
×
222
        int totalInPackage = packageReport.totalItems;
×
223
        int packagePercentage = CoveragePercentage.calculate(coveredInPackage, totalInPackage);
×
224

225
        totalItems += totalInPackage;
×
226
        coveredItems += coveredInPackage;
×
227
        packageToPackagePercentages.put(packageName, packagePercentage);
×
228
    }
×
229

230
    private void writeInitiallyHiddenSourceFileCount(@NonNegative int fileCount) {
231
        output.write("    <span>(");
×
232
        output.print(fileCount);
×
233
        output.println(" source files)</span>");
×
234
    }
×
235

236
    private void writeCoveragePercentageForPackage(@NonNull String packageName) {
237
        int filePercentage = packageToPackagePercentages.get(packageName);
×
238
        printCoveragePercentage(packageReport.coveredItems, packageReport.totalItems, filePercentage);
×
239
    }
×
240

241
    private void writeListOfRedundantTestsIfAny() {
242
        TestCoverage testCoverage = TestCoverage.INSTANCE;
×
243

244
        if (testCoverage == null) {
×
245
            return;
×
246
        }
247

248
        List<Method> redundantTests = testCoverage.getRedundantTests();
×
249

250
        if (!redundantTests.isEmpty()) {
×
251
            output.println("  <br>Redundant tests:");
×
252
            output.println("  <ol title=\"Tests are regarded as redundant when they don't cover any additional line "
×
253
                    + "segments or fields that haven't already been covered by a previous test.\n"
254
                    + "Note this means the list of redundant tests depends on the order of test execution.\n"
255
                    + "Such a test can be removed without weakening the test suite, as long as another test "
256
                    + "for the same scenario performs its assertions.\">");
257

258
            for (Method testMethod : redundantTests) {
×
259
                String testDescription = testMethod.getDeclaringClass().getSimpleName() + '.' + testMethod.getName();
×
260

261
                output.append("");
×
262
                output.write("    <li>");
×
263
                output.write(testDescription);
×
264
                output.println("</li>");
×
265
            }
×
266

267
            output.println("  </ol>");
×
268
        }
269
    }
×
270

271
    private void writeFooter() {
272
        output.println("  <p>");
×
273
        output.println("    <a href='http://jmockit.github.io'><img src='logo.png'></a>");
×
274
        output.write("    Generated on ");
×
275
        output.println(new Date());
×
276
        output.println("  </p>");
×
277
        ((OutputFile) output).writeCommonFooter();
×
278
    }
×
279
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc