package fr.inria.diversify.coverage;
import fr.inria.diversify.codeFragment.CodeFragment;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.MethodInfo;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IClassCoverage;
import org.jacoco.core.analysis.ICounter;
import org.jacoco.core.data.ExecutionDataReader;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.data.SessionInfoStore;
import spoon.reflect.code.CtIf;
import spoon.reflect.code.CtLoop;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtType;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class CoverageReport implements ICoverageReport {
protected CoverageBuilder coverageBuilder;
private final File executionDataFile;
private final File classesDirectory;
protected String classToCover;
private ExecutionDataStore executionDataStore;
private SessionInfoStore sessionInfoStore;
public CoverageReport(String classesDir, File jacocoFile, String classToCover) {
this.executionDataFile = jacocoFile;
this.classesDirectory = new File(classesDir);
this.classToCover = classToCover;
}
public void create() throws IOException {
loadExecutionData();
coverageBuilder = analyzeStructure();
}
private void loadExecutionData() throws IOException {
final FileInputStream fis = new FileInputStream(executionDataFile);
final ExecutionDataReader executionDataReader = new ExecutionDataReader(
fis);
executionDataStore = new ExecutionDataStore();
sessionInfoStore = new SessionInfoStore();
executionDataReader.setExecutionDataVisitor(executionDataStore);
executionDataReader.setSessionInfoVisitor(sessionInfoStore);
while (executionDataReader.read()) {}
fis.close();
}
protected CoverageBuilder analyzeStructure() throws IOException {
final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionDataStore,
coverageBuilder);
analyzer.analyzeAll(classesDirectory);
return coverageBuilder;
}
public double codeFragmentCoverage(CodeFragment stmt) {
return elementCoverage(stmt.getCtCodeFragment());
}
public double elementCoverage(CtElement elem) {
if(elem instanceof CtIf) {
CtIf ctIf = (CtIf) elem;
if(ctIf.getElseStatement() != null) {
return (coverage(ctIf.getThenStatement()) + coverage(ctIf.getElseStatement())) / 2d;
} else {
return coverage(ctIf.getThenStatement());
}
}
if(elem instanceof CtLoop) {
return coverage(((CtLoop) elem).getBody());
}
return coverage(elem);
}
protected double coverage(CtElement operator) {
CtType<?> cl = operator.getParent(CtType.class);
if(classToCover != null && !cl.getQualifiedName().equals(classToCover)) {
return 0d;
}
IClassCoverage classCoverage = null;
if(!(cl == null || cl.getPackage() == null || cl.getPackage().getSignature() == null)) {
String name = cl.getPackage().getSignature().replace(".","/")+"/"+cl.getSimpleName();
for (IClassCoverage cc : coverageBuilder.getClasses()) {
if(name.equals(cc.getName())) {
classCoverage = cc;
break;
}
}
}
if(classCoverage == null) {
return 0;
}
double ret = 0;
int start = operator.getPosition().getLine();
int end = operator.getPosition().getEndLine();
for (int i = start; i <= end; i++) {
if (classCoverage.getLine(i).getStatus() == ICounter.FULLY_COVERED) {
ret++;
}
}
return ret/(double)(end - start + 1);
}
@Override
public int opCodeCoverage(CtMethod method, int indexOpcode) {
IClassCoverage classCoverage = null;
CtClass cl = method.getDeclaringClass();
if(classToCover != null && !cl.getName().equals(classToCover)) {
return 0;
}
String name = cl.getName().replace(".","/");
for (IClassCoverage cc : coverageBuilder.getClasses()) {
if(name.equals(cc.getName())) {
classCoverage = cc;
break;
}
}
if(classCoverage == null)
return 0;
MethodInfo mInfo = method.getMethodInfo();
int line = mInfo.getLineNumber(indexOpcode);
return classCoverage.getLine(line).getStatus();
}
public String getFileName() {
return executionDataFile.getName();
}
/**
* Returns a distribution of coverage from a given statement along the list of coverage files
*
* @return An integer list containing the distribution
*/
public List<Integer> getCoverageDistribution(CodeFragment stmt) {
ArrayList<Integer> result = new ArrayList<>(1);
result.add(codeFragmentCoverage(stmt) > 0 ? 1 : 0);
return result;
}
}