mockit.coverage.lines.PerFileLineCoverage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmockit Show documentation
Show all versions of jmockit Show documentation
JMockit is a Java toolkit for automated developer testing.
It contains mocking/faking APIs and a code coverage tool, supporting both JUnit and TestNG.
The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested
in isolation from selected dependencies.
/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.coverage.lines;
import java.io.*;
import java.util.*;
import javax.annotation.*;
import mockit.coverage.*;
import mockit.coverage.data.*;
public final class PerFileLineCoverage implements PerFileCoverage
{
private static final long serialVersionUID = 6318915843739466316L;
private static final int[] NO_EXECUTIONS_YET = new int[0];
@Nonnull private final Map lineToLineData = new HashMap(128);
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
@Nonnull private int[] executionCounts = NO_EXECUTIONS_YET;
@Nonnull private transient LineCoverageData sharedLineData;
// Computed on demand:
private int lastLine;
private transient int totalSegments;
private transient int coveredSegments;
public PerFileLineCoverage()
{
sharedLineData = new LineCoverageData();
initializeCache();
}
private void initializeCache() { totalSegments = coveredSegments = -1; }
private void readObject(@Nonnull ObjectInputStream in) throws IOException, ClassNotFoundException
{
sharedLineData = new LineCoverageData();
initializeCache();
in.defaultReadObject();
if (executionCounts.length == 0) {
executionCounts = NO_EXECUTIONS_YET;
}
}
public void addLine(int line, boolean reprocessing)
{
if (lineToLineData.containsKey(line)) {
if (reprocessing) {
LineCoverageData lineData = lineToLineData.get(line);
if (lineData != null) {
lineData.clearBranches();
}
}
}
else {
lineToLineData.put(line, null);
}
if (line > lastLine) {
// Happens for source files with multiple types, where one is only loaded
// after another has already executed some code.
int[] initialExecutionCounts = executionCounts;
if (initialExecutionCounts != NO_EXECUTIONS_YET && line >= initialExecutionCounts.length) {
int[] newCounts = new int[line + 30];
System.arraycopy(initialExecutionCounts, 0, newCounts, 0, initialExecutionCounts.length);
executionCounts = newCounts;
}
lastLine = line;
}
}
@Nonnull
public LineCoverageData getOrCreateLineData(int line)
{
LineCoverageData lineData = lineToLineData.get(line);
if (lineData == null) {
lineData = new LineCoverageData();
lineToLineData.put(line, lineData);
}
return lineData;
}
@Nonnull
public BranchCoverageData getBranchData(int line, int index)
{
LineCoverageData lineData = lineToLineData.get(line);
return lineData.getBranchData(index);
}
public void markLastLineSegmentAsEmpty(int line)
{
LineCoverageData lineData = lineToLineData.get(line);
lineData.markLastSegmentAsEmpty();
}
public boolean acceptsAdditionalCallPoints(int line)
{
LineCoverageData lineData = getOrCreateLineData(line);
return lineData.acceptsAdditionalCallPoints();
}
public int registerExecution(int line, @Nullable CallPoint callPoint)
{
if (executionCounts == NO_EXECUTIONS_YET) {
executionCounts = new int[lastLine + 1];
}
int previousExecutionCount = executionCounts[line]++;
if (callPoint != null) {
LineCoverageData lineData = lineToLineData.get(line);
lineData.registerExecution(callPoint);
}
return previousExecutionCount;
}
public boolean hasValidBranch(int line, int branchIndex)
{
LineCoverageData lineData = lineToLineData.get(line);
return lineData.isValidBranch(branchIndex);
}
public boolean acceptsAdditionalCallPoints(int line, int branchIndex)
{
LineCoverageData lineData = lineToLineData.get(line);
return lineData.acceptsAdditionalCallPoints(branchIndex);
}
public int registerExecution(int line, int branchIndex, @Nullable CallPoint callPoint)
{
LineCoverageData lineData = lineToLineData.get(line);
return lineData.registerExecution(branchIndex, callPoint);
}
public int getLineCount() { return lastLine; }
public int getExecutableLineCount() { return lineToLineData.size(); }
public boolean hasLineData(int line)
{
return executionCounts != NO_EXECUTIONS_YET && lineToLineData.containsKey(line);
}
@Nonnull
public LineCoverageData getLineData(int line)
{
LineCoverageData data = lineToLineData.get(line);
if (data == null) {
data = sharedLineData;
}
data.setExecutionCount(executionCounts[line]);
return data;
}
public int getExecutionCount(int line)
{
return line < executionCounts.length ? executionCounts[line] : -1;
}
@Override
public int getTotalItems()
{
computeValuesIfNeeded();
return totalSegments;
}
@Override
public int getCoveredItems()
{
computeValuesIfNeeded();
return coveredSegments;
}
@Override
public int getCoveragePercentage()
{
computeValuesIfNeeded();
return CoveragePercentage.calculate(coveredSegments, totalSegments);
}
private void computeValuesIfNeeded()
{
if (totalSegments >= 0) return;
totalSegments = coveredSegments = 0;
for (int line = 1, n = lastLine; line <= n; line++) {
if (lineToLineData.containsKey(line)) {
LineCoverageData lineData = lineToLineData.get(line);
int executionCount = executionCounts == NO_EXECUTIONS_YET ? 0 : executionCounts[line];
if (lineData == null) {
totalSegments++;
if (executionCount > 0) {
coveredSegments++;
}
}
else {
lineData.setExecutionCount(executionCount);
totalSegments += lineData.getNumberOfSegments();
coveredSegments += lineData.getNumberOfCoveredSegments();
}
}
}
}
public int getNumberOfSegments(int line)
{
if (!lineToLineData.containsKey(line)) {
return 0;
}
LineCoverageData lineData = lineToLineData.get(line);
return lineData == null ? 1 : lineData.getNumberOfSegments();
}
public int getNumberOfBranchingSourcesAndTargets(int line)
{
LineCoverageData lineData = lineToLineData.get(line);
if (lineData == null) {
return 0;
}
return lineData.getNumberOfBranchingSourcesAndTargets();
}
public void mergeInformation(@Nonnull PerFileLineCoverage previousCoverage)
{
Map previousInfo = previousCoverage.lineToLineData;
boolean previousRunHadLinesExecuted = previousCoverage.executionCounts.length > 0;
for (Map.Entry lineAndInfo : lineToLineData.entrySet()) {
Integer line = lineAndInfo.getKey();
LineCoverageData previousLineInfo = previousInfo.get(line);
if (previousLineInfo != null) {
LineCoverageData lineInfo = lineAndInfo.getValue();
if (lineInfo == null) {
lineInfo = new LineCoverageData();
lineAndInfo.setValue(lineInfo);
}
lineInfo.addCountsFromPreviousTestRun(previousLineInfo);
if (previousRunHadLinesExecuted) {
createExecutionCountsArrayIfNeeded(previousCoverage);
executionCounts[line] += previousCoverage.executionCounts[line];
}
}
}
for (Map.Entry lineAndInfo : previousInfo.entrySet()) {
Integer line = lineAndInfo.getKey();
if (!lineToLineData.containsKey(line)) {
LineCoverageData previousLineInfo = lineAndInfo.getValue();
lineToLineData.put(line, previousLineInfo);
if (previousRunHadLinesExecuted) {
createExecutionCountsArrayIfNeeded(previousCoverage);
executionCounts[line] = previousCoverage.executionCounts[line];
}
}
}
}
private void createExecutionCountsArrayIfNeeded(@Nonnull PerFileLineCoverage previousCoverage)
{
if (executionCounts == NO_EXECUTIONS_YET) {
executionCounts = new int[previousCoverage.executionCounts.length];
}
}
}