org.pitest.mutationtest.incremental.ObjectOutputStreamHistory Maven / Gradle / Ivy
package org.pitest.mutationtest.incremental;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Serializable;
import java.util.Base64;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.pitest.classinfo.ClassHash;
import org.pitest.classinfo.ClassName;
import org.pitest.classinfo.HierarchicalClassId;
import org.pitest.classpath.CodeSource;
import org.pitest.coverage.CoverageDatabase;
import java.util.Optional;
import java.util.stream.Collectors;
import org.pitest.mutationtest.ClassHistory;
import org.pitest.mutationtest.History;
import org.pitest.mutationtest.MutationAnalyser;
import org.pitest.mutationtest.MutationResult;
import org.pitest.mutationtest.MutationStatusTestPair;
import org.pitest.mutationtest.engine.MutationDetails;
import org.pitest.mutationtest.engine.MutationIdentifier;
import org.pitest.util.Log;
import org.pitest.util.Unchecked;
public class ObjectOutputStreamHistory implements History {
private static final Logger LOG = Log
.getLogger();
private final CodeSource code;
private final WriterFactory outputFactory;
private final BufferedReader input;
private final Map previousResults = new HashMap<>();
private final Map previousClassPath = new HashMap<>();
private CoverageDatabase coverageData;
public ObjectOutputStreamHistory(CodeSource code, WriterFactory output,
final Optional input) {
this.code = code;
this.outputFactory = output;
this.input = createReader(input);
}
private BufferedReader createReader(Optional input) {
return input.map(BufferedReader::new)
.orElse(null);
}
@Override
public void recordResult(final MutationResult result) {
final PrintWriter output = this.outputFactory.create();
output.println(serialize(new ObjectOutputStreamHistory.IdResult(
result.getDetails().getId(), result.getStatusTestPair())));
output.flush();
}
@Override
public List analyse(List mutationsForClasses) {
final MutationAnalyser analyser = new IncrementalAnalyser(new CodeHistory(code, this.previousResults, this.previousClassPath),
this.coverageData);
return analyser.analyse(mutationsForClasses);
}
@Override
public void close() {
}
@Override
public void initialize() {
if (this.input != null) {
restoreClassPath();
restoreResults();
try {
this.input.close();
} catch (final IOException e) {
throw Unchecked.translateCheckedException(e);
}
}
}
@Override
public void processCoverage(CoverageDatabase coverageData) {
this.coverageData = coverageData;
recordClassPath(coverageData);
}
private void recordClassPath(CoverageDatabase coverageData) {
Set allClassNames = code.getAllClassAndTestNames();
// sort by classname to ensure order consistent across machines
List ids = this.code.fetchClassHashes(allClassNames).stream()
.map(ClassHash::getHierarchicalId)
.sorted(Comparator.comparing(HierarchicalClassId::getName))
.collect(Collectors.toList());
final PrintWriter output = this.outputFactory.create();
output.println(ids.size());
for (final HierarchicalClassId each : ids) {
final ClassHistory coverage = new ClassHistory(each,
coverageData.getCoverageIdForClass(each.getName()).toString(16));
output.println(serialize(coverage));
}
output.flush();
}
private void restoreResults() {
String line;
try {
line = this.input.readLine();
while (line != null) {
final IdResult result = deserialize(line, IdResult.class);
this.previousResults.put(result.id, result.status);
line = this.input.readLine();
}
} catch (final Exception e) {
LOG.warning("Could not read previous results");
}
}
private void restoreClassPath() {
try {
final long classPathSize = Long.parseLong(this.input.readLine());
for (int i = 0; i != classPathSize; i++) {
final ClassHistory coverage = deserialize(this.input.readLine(),
ClassHistory.class);
this.previousClassPath.put(coverage.getName(), coverage);
}
} catch (final IOException e) {
LOG.warning("Could not read previous classpath");
}
}
private T deserialize(String string, Class clazz) throws IOException {
try {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
Base64.getDecoder().decode(string));
final ObjectInputStream objectInputStream = new ObjectInputStream(
byteArrayInputStream);
return clazz.cast(objectInputStream.readObject());
} catch (final ClassNotFoundException e) {
throw Unchecked.translateCheckedException(e);
}
}
private String serialize(T t) {
try {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final ObjectOutputStream objectOutputStream = new ObjectOutputStream(
byteArrayOutputStream);
objectOutputStream.writeObject(t);
return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
} catch (final IOException e) {
throw Unchecked.translateCheckedException(e);
}
}
public Map getHistoricClassPath() {
return this.previousClassPath;
}
public Map getHistoricResults() {
return this.previousResults;
}
private static class IdResult implements Serializable {
private static final long serialVersionUID = 1L;
final MutationIdentifier id;
final MutationStatusTestPair status;
IdResult(final MutationIdentifier id, final MutationStatusTestPair status) {
this.id = id;
this.status = status;
}
}
}