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

hazendaz / jmockit1 / 96

26 Apr 2025 07:08PM UTC coverage: 73.252%. Remained the same
96

push

github

web-flow
Merge pull request #329 from hazendaz/paths

Minor updates / note that jdk 25 is supported

5622 of 8178 branches covered (68.75%)

Branch coverage included in aggregate %.

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

1 existing line in 1 file now uncovered.

11880 of 15715 relevant lines covered (75.6%)

0.76 hits per line

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

0.0
/main/src/main/java/mockit/coverage/data/CoverageData.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.data;
6

7
import edu.umd.cs.findbugs.annotations.NonNull;
8
import edu.umd.cs.findbugs.annotations.Nullable;
9

10
import java.io.BufferedInputStream;
11
import java.io.BufferedOutputStream;
12
import java.io.File;
13
import java.io.IOException;
14
import java.io.ObjectInputStream;
15
import java.io.ObjectOutputStream;
16
import java.io.OutputStream;
17
import java.io.Serializable;
18
import java.nio.file.Files;
19
import java.nio.file.Path;
20
import java.util.ArrayList;
21
import java.util.Iterator;
22
import java.util.LinkedHashMap;
23
import java.util.List;
24
import java.util.Map;
25
import java.util.Map.Entry;
26
import java.util.jar.JarEntry;
27
import java.util.jar.JarFile;
28

29
import mockit.coverage.CoveragePercentage;
30
import mockit.internal.util.Utilities;
31

32
import org.checkerframework.checker.index.qual.NonNegative;
33

34
/**
35
 * Coverage data captured for all source files exercised during a test run.
36
 */
37
public final class CoverageData implements Serializable {
×
38
    private static final long serialVersionUID = -4860004226098360259L;
39
    @NonNull
40
    private static final CoverageData instance = new CoverageData();
×
41

42
    @NonNull
43
    public static CoverageData instance() {
44
        return instance;
×
45
    }
46

47
    private boolean withCallPoints;
48

49
    @NonNull
×
50
    private final Map<String, FileCoverageData> fileToFileData = new LinkedHashMap<>();
51
    @NonNull
×
52
    private final List<FileCoverageData> indexedFileData = new ArrayList<>(100);
53

54
    public boolean isWithCallPoints() {
55
        return withCallPoints;
×
56
    }
57

58
    public void setWithCallPoints(boolean withCallPoints) {
59
        this.withCallPoints = withCallPoints;
×
60
    }
×
61

62
    @NonNull
63
    public Map<String, FileCoverageData> getFileToFileData() {
64
        return fileToFileData;
×
65
    }
66

67
    @NonNull
68
    public FileCoverageData getOrAddFile(@NonNull String file, @Nullable String kindOfTopLevelType) {
69
        FileCoverageData fileData = fileToFileData.get(file);
×
70

71
        // For a class with nested/inner classes, a previous class in the same source file may already have been added.
72
        if (fileData == null) {
×
73
            int fileIndex = indexedFileData.size();
×
74
            fileData = new FileCoverageData(fileIndex, kindOfTopLevelType);
×
75
            indexedFileData.add(fileData);
×
76
            fileToFileData.put(file, fileData);
×
77
        } else if (kindOfTopLevelType != null) {
×
78
            fileData.kindOfTopLevelType = kindOfTopLevelType;
×
79
        }
80

81
        return fileData;
×
82
    }
83

84
    @NonNull
85
    public FileCoverageData getFileData(@NonNull String file) {
86
        return fileToFileData.get(file);
×
87
    }
88

89
    @NonNull
90
    public FileCoverageData getFileData(@NonNegative int fileIndex) {
91
        return indexedFileData.get(fileIndex);
×
92
    }
93

94
    public boolean isEmpty() {
95
        return fileToFileData.isEmpty();
×
96
    }
97

98
    public void clear() {
99
        fileToFileData.clear();
×
100
    }
×
101

102
    /**
103
     * Computes the coverage percentage over a subset of the available source files.
104
     *
105
     * @param fileNamePrefix
106
     *            a regular expression for matching the names of the source files to be considered, or <code>null</code>
107
     *            to consider <em>all</em> files
108
     *
109
     * @return the computed percentage from <code>0</code> to <code>100</code> (inclusive), or <code>-1</code> if no
110
     *         meaningful value could be computed
111
     */
112
    public int getPercentage(@Nullable String fileNamePrefix) {
113
        int coveredItems = 0;
×
114
        int totalItems = 0;
×
115

116
        for (Entry<String, FileCoverageData> fileAndFileData : fileToFileData.entrySet()) {
×
117
            String sourceFile = fileAndFileData.getKey();
×
118

119
            if (fileNamePrefix == null || sourceFile.startsWith(fileNamePrefix)) {
×
120
                FileCoverageData fileData = fileAndFileData.getValue();
×
121
                coveredItems += fileData.getCoveredItems();
×
122
                totalItems += fileData.getTotalItems();
×
123
            }
124
        }
×
125

126
        return CoveragePercentage.calculate(coveredItems, totalItems);
×
127
    }
128

129
    /**
130
     * Finds the source file with the smallest coverage percentage.
131
     *
132
     * @return the percentage value for the file found, or <code>Integer.MAX_VALUE</code> if no file is found with a
133
     *         meaningful percentage
134
     */
135
    @NonNegative
136
    public int getSmallestPerFilePercentage() {
137
        int minPercentage = Integer.MAX_VALUE;
×
138

139
        for (FileCoverageData fileData : fileToFileData.values()) {
×
140
            if (!fileData.wasLoadedAfterTestCompletion()) {
×
141
                int percentage = fileData.getCoveragePercentage();
×
142

143
                if (percentage >= 0 && percentage < minPercentage) {
×
144
                    minPercentage = percentage;
×
145
                }
146
            }
147
        }
×
148

149
        return minPercentage;
×
150
    }
151

152
    public void fillLastModifiedTimesForAllClassFiles() {
153
        for (Iterator<Entry<String, FileCoverageData>> itr = fileToFileData.entrySet().iterator(); itr.hasNext();) {
×
154
            Entry<String, FileCoverageData> fileAndFileData = itr.next();
×
155
            long lastModified = getLastModifiedTimeForClassFile(fileAndFileData.getKey());
×
156

157
            if (lastModified > 0L) {
×
158
                FileCoverageData fileCoverageData = fileAndFileData.getValue();
×
159
                fileCoverageData.lastModified = lastModified;
×
160
                continue;
×
161
            }
162

163
            itr.remove();
×
164
        }
×
165
    }
×
166

167
    private long getLastModifiedTimeForClassFile(@NonNull String sourceFilePath) {
168
        String sourceFilePathNoExt = sourceFilePath.substring(0, sourceFilePath.lastIndexOf('.'));
×
169
        String className = sourceFilePathNoExt.replace('/', '.');
×
170

171
        Class<?> coveredClass = findCoveredClass(className);
×
172

173
        if (coveredClass == null) {
×
174
            return 0L;
×
175
        }
176

177
        String locationPath = Utilities.getClassFileLocationPath(coveredClass);
×
178

179
        if (locationPath.endsWith(".jar")) {
×
180
            try {
181
                return getLastModifiedTimeFromJarEntry(sourceFilePathNoExt, locationPath);
×
182
            } catch (IOException ignore) {
×
183
                return 0L;
×
184
            }
185
        }
186

187
        String pathToClassFile = locationPath + sourceFilePathNoExt + ".class";
×
188

189
        return Path.of(pathToClassFile).toFile().lastModified();
×
190
    }
191

192
    private static long getLastModifiedTimeFromJarEntry(@NonNull String sourceFilePathNoExt,
193
            @NonNull String locationPath) throws IOException {
194

195
        try (JarFile jarFile = new JarFile(locationPath)) {
×
196
            JarEntry classEntry = jarFile.getJarEntry(sourceFilePathNoExt + ".class");
×
197
            return classEntry.getTime();
×
198
        }
199
    }
200

201
    @Nullable
202
    private Class<?> findCoveredClass(@NonNull String className) {
203
        ClassLoader currentCL = getClass().getClassLoader();
×
204
        Class<?> coveredClass = loadClass(className, currentCL);
×
205

206
        if (coveredClass == null) {
×
207
            ClassLoader systemCL = ClassLoader.getSystemClassLoader();
×
208

209
            if (systemCL != currentCL) {
×
210
                coveredClass = loadClass(className, systemCL);
×
211
            }
212

213
            if (coveredClass == null) {
×
214
                ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
×
215

216
                if (contextCL != null && contextCL != systemCL) {
×
217
                    coveredClass = loadClass(className, contextCL);
×
218
                }
219
            }
220
        }
221

222
        return coveredClass;
×
223
    }
224

225
    @Nullable
226
    private static Class<?> loadClass(@NonNull String className, @Nullable ClassLoader loader) {
227
        try {
228
            return Class.forName(className, false, loader);
×
229
        } catch (ClassNotFoundException | NoClassDefFoundError ignore) {
×
230
            return null;
×
231
        }
232
    }
233

234
    /**
235
     * Reads a serialized <code>CoverageData</code> object from the given file (normally, a "<code>coverage.ser</code>"
236
     * file generated at the end of a previous test run).
237
     *
238
     * @param dataFile
239
     *            the ".ser" file containing a serialized <code>CoverageData</code> instance
240
     *
241
     * @return a new object containing all coverage data resulting from a previous test run
242
     */
243
    @NonNull
244
    public static CoverageData readDataFromFile(@NonNull File dataFile) throws IOException {
245
        try (ObjectInputStream input = new ObjectInputStream(
×
246
                new BufferedInputStream(Files.newInputStream(dataFile.toPath())))) {
×
247
            return (CoverageData) input.readObject();
×
248
        } catch (ClassNotFoundException e) {
×
249
            throw new RuntimeException(
×
250
                    "Serialized class in coverage data file \"" + dataFile + "\" not found in classpath", e);
251
        }
252
    }
253

254
    public void writeDataToFile(@NonNull File dataFile) throws IOException {
NEW
255
        try (OutputStream outputStream = Files.newOutputStream(dataFile.toPath());
×
NEW
256
                ObjectOutputStream output = new ObjectOutputStream(new BufferedOutputStream(outputStream))) {
×
UNCOV
257
            output.writeObject(this);
×
258
        }
259
    }
×
260

261
    public void merge(@NonNull CoverageData previousData) {
262
        withCallPoints |= previousData.withCallPoints;
×
263

264
        for (Entry<String, FileCoverageData> previousFileAndFileData : previousData.fileToFileData.entrySet()) {
×
265
            String previousFile = previousFileAndFileData.getKey();
×
266
            FileCoverageData previousFileData = previousFileAndFileData.getValue();
×
267
            FileCoverageData fileData = fileToFileData.get(previousFile);
×
268

269
            if (fileData == null) {
×
270
                fileToFileData.put(previousFile, previousFileData);
×
271
            } else if (fileData.lastModified > 0 && previousFileData.lastModified == fileData.lastModified) {
×
272
                fileData.mergeWithDataFromPreviousTestRun(previousFileData);
×
273
            }
274
        }
×
275
    }
×
276
}
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