org.conqat.engine.sourcecode.coverage.MultiFileRangeCoverageInfo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of teamscale-commons Show documentation
Show all versions of teamscale-commons Show documentation
Provides common DTOs for Teamscale
The newest version!
package org.conqat.engine.sourcecode.coverage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import org.conqat.lib.commons.collections.CompactLines;
import org.conqat.lib.commons.test.IndexValueClass;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.teamscale.commons.utils.StringPool;
/**
* Holds line range coverage information for a test covering multiple files.
*/
@IndexValueClass(containedInBackup = true)
public class MultiFileRangeCoverageInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Mapping from normalized uniform path to a list of line numbers. The list may contain duplicates
* and may be unsorted.
*/
@JsonProperty("uniformPathToRanges")
private Map uniformPathToRanges;
/**
* The timestamp of the code this coverage data refers to. May be -1 if unknown.
*/
@JsonProperty("timestamp")
private long timestamp;
/**
* Coverable lines as provided by an external coverage tool. In case none provided,
* Teamscale-internal heuristic is used.
*/
@JsonProperty("coverableLines")
private final Map uniformPathToCoverableLineRanges;
/** Constructor with a default timestamp. */
@JsonCreator
public MultiFileRangeCoverageInfo() {
this(-1);
}
public MultiFileRangeCoverageInfo(long timestamp) {
this.timestamp = timestamp;
uniformPathToRanges = new HashMap<>();
uniformPathToCoverableLineRanges = new HashMap<>();
}
/**
* Merges all coverage contained in newCoverage into this coverage. Coverage from the same test case
* replaces existing coverage.
*/
public void addLineCoverage(MultiFileRangeCoverageInfo newCoverage) {
Set> newTestCoverage = newCoverage.uniformPathToRanges.entrySet();
for (Entry testCoverage : newTestCoverage) {
uniformPathToRanges.put(testCoverage.getKey(), testCoverage.getValue());
}
}
/** Adds the coverage information for the given lines. */
public void addLineCoverage(String uniformPath, CompactLines lines) {
uniformPathToRanges.computeIfAbsent(uniformPath, k -> new CompactLines()).addAll(lines);
}
/** Adds the coverable lines for the given uniform path. */
public void addCoverableLines(String uniformPath, CompactLines lines) {
uniformPathToCoverableLineRanges.computeIfAbsent(uniformPath, k -> new CompactLines()).addAll(lines);
}
/** @see #timestamp */
public long getTimestamp() {
return timestamp;
}
/** @see #timestamp */
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/** Returns the coverage represented by this object in raw form. */
public Map getCoverage() {
return uniformPathToRanges;
}
/** Returns the coverage lines represented by this object in raw form. */
public Map getCoverableLines() {
if (uniformPathToCoverableLineRanges == null) {
// might be null when the object is deserialized from the Teamscale backup
return new HashMap<>();
}
return uniformPathToCoverableLineRanges;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "Covered: "
+ uniformPathToRanges.entrySet().stream().sorted(Entry.comparingByKey())
.map(pair -> pair.getKey() + " " + pair.getValue()).collect(Collectors.joining(", "))
+ "; timestamp: " + timestamp;
}
/**
* If the test contains coverage from the given file, the uniform path is adjusted to match the path
* used inside Teamscale.
*/
public void changeFilePath(String reportPath, String pathInTeamscale) {
if (uniformPathToRanges.containsKey(reportPath) && !reportPath.equals(pathInTeamscale)) {
CompactLines ranges = uniformPathToRanges.remove(reportPath);
uniformPathToRanges.put(pathInTeamscale, ranges);
}
}
/**
* We use a custom de-serialization here so that we can intern the paths directly after they have
* been read and therefore avoid high peaks in RAM usage because the same paths end up multiple
* times in memory otherwise, because readUTF does not use Java's internal string deduplication.
*/
private void readObject(ObjectInputStream inputStream) throws ClassNotFoundException, IOException {
timestamp = inputStream.readLong();
uniformPathToRanges = new HashMap<>();
int entries = inputStream.readInt();
for (int i = 0; i < entries; i++) {
String path = StringPool.intern(inputStream.readUTF());
CompactLines list = (CompactLines) inputStream.readObject();
uniformPathToRanges.put(path, list);
}
}
private void writeObject(ObjectOutputStream outputStream) throws IOException {
outputStream.writeLong(timestamp);
outputStream.writeInt(uniformPathToRanges.size());
for (Entry entry : uniformPathToRanges.entrySet()) {
outputStream.writeUTF(entry.getKey());
outputStream.writeObject(entry.getValue());
}
}
/**
* Returns the estimated size of the object in bytes. This is used to determine how much we can keep
* in the in-memory cache at once.
*/
public long getEstimatedSizeBytes() {
return uniformPathToRanges.entrySet().stream()
.mapToLong(entry -> entry.getKey().length() + entry.getValue().size() * 4L).sum();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy