package fr.inria.diversify;
import fr.inria.diversify.buildSystem.AbstractBuilder;
import fr.inria.diversify.buildSystem.android.InvalidSdkException;
import fr.inria.diversify.buildSystem.ant.AntBuilder;
import fr.inria.diversify.buildSystem.maven.MavenBuilder;
import fr.inria.diversify.coverage.CoverageReport;
import fr.inria.diversify.coverage.ICoverageReport;
import fr.inria.diversify.coverage.MultiCoverageReport;
import fr.inria.diversify.coverage.NullCoverageReport;
import fr.inria.diversify.diversification.*;
import fr.inria.diversify.persistence.json.input.JsonTransformationLoader;
import fr.inria.diversify.persistence.json.output.JsonTransformationWriter;
import fr.inria.diversify.statistic.CVLMetric;
import fr.inria.diversify.transformation.SingleTransformation;
import fr.inria.diversify.transformation.Transformation;
import fr.inria.diversify.transformation.TransformationParser;
import fr.inria.diversify.transformation.TransformationParserException;
import fr.inria.diversify.transformation.query.*;
import fr.inria.diversify.util.InitUtils;
import fr.inria.diversify.util.Log;
import fr.inria.diversify.visu.Visu;
import javassist.NotFoundException;
import org.json.JSONException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Main class for the sosie generator.
* <p/>
* User: Simon
* Date: 9/11/13
* Time: 11:41 AM
*/
public class DiversifyMain {
/**
* The input program that we are about to sosiefy
*/
private InputProgram inputProgram;
/**
* The input configuration given by the user is parsed by this class which helps other parts of the program to
* interact with the input parameters
* s
*/
private InputConfiguration inputConfiguration;
public DiversifyMain(String propertiesFile) throws Exception, InvalidSdkException {
inputConfiguration = new InputConfiguration(propertiesFile);
InitUtils.initLogLevel(inputConfiguration);
InitUtils.initDependency(inputConfiguration);
inputProgram = InitUtils.initInputProgram(inputConfiguration);
InitUtils.initSpoon(inputProgram, false);
TransformationQuery query = initTransformationQuery();
AbstractDiversify runner = initRunner();
runner.setTransformationQuery(query);
AbstractBuilder builder = initBuilder(runner.getTmpDir());
inputProgram.setCoverageReport(initCoverageReport(runner.getTmpDir()));
runner.setBuilder(builder);
if (inputConfiguration.getProperty("stat").equals("true")) {
computeStatistic();
} else {
int n = Integer.parseInt(inputConfiguration.getProperty("nbRun"));
runner.run(n);
writeResult(runner);
runner.deleteTmpFiles();
}
}
protected AbstractDiversify initRunner() throws Exception {
AbstractDiversify abstractDiversify = null;
String runner = inputConfiguration.getProperty("runner", "simple");
String project = inputConfiguration.getProperty("project");
String src = inputConfiguration.getProperty("src");
String testSrcDir = inputConfiguration.getProperty("testSrc", null);
String sosieDir = inputConfiguration.getProperty("copy.sosie.sources.to", "");
String resultDir = inputConfiguration.getProperty("result");
switch (runner) {
case "simple":
abstractDiversify = new SinglePointDiversify(inputConfiguration, project, src);
break;
case "gh":
abstractDiversify = new GHDiversify(inputConfiguration, project, src, inputConfiguration.getProperty("testScripBefore"), inputConfiguration.getProperty("testScriptAfter") ,inputConfiguration.getProperty("testProject"));
break;
// case "dumpfailure":
// abstractDiversify = new DumpFailure(inputConfiguration, project, src);
// break;
case "multi": {
int multiTransformationSize = Integer.parseInt(inputConfiguration.getProperty("multiTransformation.size"));
MultiTransformationGenerator multi = new MultiTransformationGenerator(inputConfiguration, project, src);
multi.setTransformationSize(multiTransformationSize);
multi.setOnlySosie(false);
abstractDiversify = multi;
break;
}
case "multisosie": {
int multiTransformationSize = Integer.parseInt(inputConfiguration.getProperty("multiTransformation.size"));
MultiTransformationGenerator multi = new MultiTransformationGenerator(inputConfiguration, project, src);
multi.setTransformationSize(multiTransformationSize);
multi.setOnlySosie(true);
abstractDiversify = multi;
break;
}
case "fse": {
DiversifyAndCompare dac = new DiversifyAndCompare(inputConfiguration, project, src, testSrcDir, inputConfiguration.getProperty("compare.filter"));
dac.setAmplifiedTestDir(inputConfiguration.getProperty("amplifiedTestDir"));
dac.setOriginalLogDir(inputConfiguration.getProperty("compare.originalLog"));
abstractDiversify = dac;
break;
}
case "android": {
abstractDiversify = new SinglePointDiversify(inputConfiguration, project, src);
abstractDiversify.setAndroid(true);
break;
}
}
abstractDiversify.setSosieSourcesDir(sosieDir);
abstractDiversify.init(project, inputConfiguration.getProperty("tmpDir"));
// abstractDiversify.setBuilder(initBuilder(tmpDir));
abstractDiversify.setResultDir(resultDir);
return abstractDiversify;
}
protected AbstractBuilder initBuilder(String directory) throws Exception {
AbstractBuilder rb;
String builder = inputConfiguration.getProperty("builder");
if(builder.equals("maven")) {
String[] phases = new String[]{inputConfiguration.getProperty("phase")};
if(phases[0] == null) {
phases = new String[]{"clean", "test" };
}
rb = new MavenBuilder(directory);
String androidSdk = inputConfiguration.getProperty("AndroidSdk", "null");
if(!androidSdk.equals("null") ) {
rb.stopAndroidEmulation();
rb.startAndroidEmulation();
}
rb.setGoals(phases);
initTimeOut(rb);
URL[] URL = new URL[1];
URL[0] = new File(directory + "/"+ inputProgram.getClassesDir()).toURI().toURL();
URLClassLoader child = new URLClassLoader(URL, Thread.currentThread().getContextClassLoader());
Thread.currentThread().setContextClassLoader(child);
//Thread.currentThread().getContextClassLoader().loadClass("org.apache.commons.collection4.map.LazyMap");
String pomFile = inputConfiguration.getProperty("newPomFile");
if (!pomFile.equals("")) {
rb.initPom(pomFile);
}
} else { //builder == ant
rb = new AntBuilder(directory, inputConfiguration.getProperty("builder.testTarget"));
rb.setGoals(new String[]{"clean", inputConfiguration.getProperty("builder.testTarget")});
initTimeOut(rb);
}
//Obtain some other builder properties
boolean saveOutput = Boolean.parseBoolean(inputConfiguration.getProperty("save.builder.output", "false"));
boolean useClojure = Boolean.parseBoolean(inputConfiguration.getProperty("clojure", "false"));
String results = inputConfiguration.getProperty("result");
rb.setSaveOutputDir(results);
rb.setClojureTest(useClojure);
rb.setSaveOutputToFile(saveOutput);
return rb;
}
protected void initTimeOut(AbstractBuilder rb) throws InterruptedException {
int t = Integer.parseInt(inputConfiguration.getProperty("timeOut").trim());
if (t == -1) {
rb.initTimeOut();
} else {
rb.setTimeOut(t);
}
}
protected TransformationQuery initTransformationQuery() throws ClassNotFoundException, NotFoundException, TransformationParserException, IOException, JSONException {
String type = inputConfiguration.getProperty("transformation.type").toLowerCase();
boolean subType = Boolean.parseBoolean(inputConfiguration.getProperty("transformation.subtype", "false"));
switch (type) {
case "checkreturnif":
return new CheckReturnQuery(inputProgram);
case "checkreturn":
return new CheckReturn(inputProgram);
case "shufflecollectionbeforereturn":
return new ShuffleCollectionBeforeReturnQuery(inputProgram);
case "subclassreplace":
return new SubClassReplaceQuery(inputProgram);
case "mutation":
return new MutationQuery(inputProgram);
case "shuffle":
return new ShuffleStmtQuery(inputProgram);
case "other":
return new OtherQuery(inputProgram);
case "all":
return new CompositeQuery(inputProgram);
case "cvl":
return new CvlQuery(inputProgram);
case "bytecode":
return new ByteCodeTransformationQuery(inputProgram);
case "replacenewlist":
return new ReplaceNewListQuery(inputProgram);
case "replacenewlistrandom":
return new ReplaceNewListRandomQuery(inputProgram);
case "arraylisttolinkedlist":
return new ReplaceArrayListToLinkedListQuery(inputProgram);
case "adr": {
Class cl = Class.forName(inputConfiguration.getProperty("CodeFragmentClass"));
return new ASTTransformationQuery(inputProgram, cl, subType, false);
}
case "adrstupid": {
Class cl = Class.forName(inputConfiguration.getProperty("CodeFragmentClass"));
return new ASTTransformationQuery(inputProgram, cl, subType, true);
}
case "fromlist": {
int rangeMin = Integer.parseInt(inputConfiguration.getProperty("transformation.range.min", "-1"));
int rangeMax = Integer.parseInt(inputConfiguration.getProperty("transformation.range.max", "-1"));
FromListQuery query;
if(rangeMax == -1 || rangeMin == -1) {
query = new FromListQuery(inputProgram);
} else {
query = new FromListQuery(inputProgram, rangeMin, rangeMax);
}
query.setShuffle(true);
query.setRemoveAfterQuery(true);
return query;
}
case "ampsosie": {
AmpSosieQuery query = new AmpSosieQuery(inputProgram);
query.initDiff(inputConfiguration.getPreviousTransformationPath(), inputConfiguration.getProperty("compare.filter"));
query.setShuffle(true);
query.setRemoveAfterQuery(false);
return query;
}
case "fse":{
Class cl = Class.forName(inputConfiguration.getProperty("CodeFragmentClass"));
return new ASTTransformationQuery(inputProgram, cl, subType, false);
}
case "issta": {
}
default:
//Try to construct the executeQuery from the explicit class
try {
Class[] intArgsClass = new Class[]{InputProgram.class};
Class strategyClass = Class.forName(type);
Constructor constructor = strategyClass.getConstructor(intArgsClass);
return (TransformationQuery) constructor.newInstance(inputProgram);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
protected ICoverageReport initCoverageReport(String tmpDir) {
String jacocoFile = inputConfiguration.getProperty("jacoco");
String classes = tmpDir + "/" + inputProgram.getClassesDir();
ICoverageReport icr = null;
if (jacocoFile != null) {
try {
File file = new File(jacocoFile);
if (file.isDirectory()) {
icr = new MultiCoverageReport(classes, file);
} else {
String classToCover = inputConfiguration.getProperty("coverage.class", null);
icr = new CoverageReport(classes, file, classToCover);
}
icr.create();
return icr;
} catch (IOException e) {
Log.warn("Unable to find coverage file or corrupt information: using NullCoverage");
icr = null;
}
} else {
//Try to use the trace coverage
String traceDir = inputConfiguration.getProperty("trace.dirs");
Boolean binaryTrace = Boolean.parseBoolean(inputConfiguration.getProperty("binary.trace", "false"));
if (traceDir != null) {
String[] dirs = traceDir.split(";");
ArrayList<File> traceFiles = new ArrayList();
for (String s : dirs) {
File f = new File(s);
if (f.exists() && f.isDirectory()) {
traceFiles.add(f);
} else {
Log.warn("Invalid trace dir: " + s);
}
}
if (traceFiles.size() > 0) {
try {
icr = new MultiCoverageReport(traceFiles, binaryTrace);
icr.create();
return icr;
} catch (IOException e) {
Log.warn("Unable to find coverage file or corrupt information: using NullCoverage");
icr = null;
}
}
}
}
if (icr == null) {
icr = new NullCoverageReport();
}
return icr;
}
protected void computeStatistic() throws Exception {
String out = inputConfiguration.getProperty("result");
// computeCodeFragmentStatistic(out);
String transDir = inputConfiguration.getProperty("transformation.directory");
if (transDir != null) {
computeDiversifyStat(transDir, out);
}
// computeOtherStat();
}
protected void computeDiversifyStat(String transDir, String output) throws Exception {
TransformationParser tf = new TransformationParser(true, inputProgram);
// Collection<Transformation> transformations = tf.parse(transDir);
JsonTransformationLoader loader = new JsonTransformationLoader(inputProgram);
Collection<Transformation> transformations = loader.load(transDir, false);
// TransformationsWriter write = new TransformationsWriter(transformations, fileName);
JsonTransformationWriter writer = new JsonTransformationWriter();
File out = new File(output);
if(!out.exists()) {
out.mkdirs();
}
writer.write(transformations, output+".json", inputProgram.getProgramDir() + "/pom.xml");
Set<Transformation> sosies = transformations.stream()
.filter(t -> t.isSosie())
.collect(Collectors.toSet());
writer.write(sosies, output+"_sosie.json", inputProgram.getProgramDir() + "/pom.xml");
CVLMetric cvlMetric = new CVLMetric(inputProgram);
cvlMetric.printMetrics(output + "_cvlMetric.csv");
// visu(sosies);
// FailureMatrix matrix = new FailureMatrix(transformations,inputConfiguration.getProperty("allTestFile"));
// matrix.printAllMatrix(fileName);
}
protected void visu(Collection<Transformation> transformations) throws Exception {
String out = inputConfiguration.getProperty("result");
Set<SingleTransformation> singleTransformation = transformations.stream()
.filter(t -> t instanceof SingleTransformation)
.map(t -> (SingleTransformation) t)
.collect(Collectors.toSet());
Visu v = new Visu(out + "_visu/visu", inputProgram);
v.writeJSON(singleTransformation);
}
protected Set<String> getAllTransformationType(Collection<Transformation> transformations) {
Set<String> types = new HashSet<String>();
for (Transformation t : transformations)
types.add(t.getType());
return types;
}
protected void writeResult(AbstractDiversify runner) {
String repo = inputConfiguration.getProperty("gitRepository");
if (repo.equals("null")) {
runner.printResult(inputConfiguration.getProperty("result"));
} else {
runner.printResultInGitRepo(inputConfiguration.getProperty("result"), repo);
}
}
}