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

hazendaz / jmockit1 / 85

26 Apr 2025 06:37PM UTC coverage: 73.285% (-0.02%) from 73.308%
85

push

github

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

Use nio more per modernizer and update more tests to junit 5

5625 of 8178 branches covered (68.78%)

Branch coverage included in aggregate %.

5 of 43 new or added lines in 14 files covered. (11.63%)

3 existing lines in 3 files now uncovered.

11885 of 15715 relevant lines covered (75.63%)

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.Serializable;
17
import java.nio.file.Files;
18
import java.nio.file.Path;
19
import java.util.ArrayList;
20
import java.util.Iterator;
21
import java.util.LinkedHashMap;
22
import java.util.List;
23
import java.util.Map;
24
import java.util.Map.Entry;
25
import java.util.jar.JarEntry;
26
import java.util.jar.JarFile;
27

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

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

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

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

46
    private boolean withCallPoints;
47

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

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

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

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

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

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

80
        return fileData;
×
81
    }
82

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

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

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

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

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

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

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

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

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

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

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

148
        return minPercentage;
×
149
    }
150

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

221
        return coveredClass;
×
222
    }
223

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

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

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

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

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

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