/**
*
*/
package jayhorn.test.soundness;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import jayhorn.checker.EldaricaChecker;
import jayhorn.solver.ProverFactory;
import jayhorn.solver.princess.PrincessProverFactory;
import jayhorn.test.Util;
import jayhorn.test.soundness.BigSoundnessUtil.TestOutcome;
import soottocfg.cfg.Program;
import soottocfg.soot.SootToCfg;
/**
* @author schaef
*
*/
@RunWith(Parameterized.class)
public class BigSoundnessTests {
private static Map<String, TestOutcome> testResults = new LinkedHashMap<String, TestOutcome>();
private static final String userDir = System.getProperty("user.dir") + "/";
private static final String testRoot = userDir + "src/test/resources/";
private File sourceFile;
private static int resultCorrect = 0;
private static int resultImprecise = 0;
private static int resultUnsound = 0;
private static int resultException = 0;
private static String unsoundFileNames = "";
@Parameterized.Parameters(name = "{index}: check ({1})")
public static Collection<Object[]> data() {
List<Object[]> filenames = new LinkedList<Object[]>();
// collect benchmarks from multiple places
collectFileNamesRecursively(new File(testRoot + "cbmc-src"), filenames);
collectFileNamesRecursively(new File(testRoot + "horn-encoding/regression"), filenames);
collectFileNamesRecursively(new File(testRoot + "horn-encoding/backlog"), filenames);
collectFileNamesRecursively(new File(testRoot + "horn-encoding/arrays"), filenames);
collectFileNamesRecursively(new File(testRoot + "horn-encoding/mem_precision"), filenames);
collectFileNamesRecursively(new File(testRoot + "horn-encoding/classics"), filenames);
if (filenames.isEmpty()) {
throw new RuntimeException("Test data not found!");
}
return filenames;
}
private static void collectFileNamesRecursively(File file, List<Object[]> filenames) {
File[] directoryListing = file.listFiles();
if (directoryListing != null) {
Arrays.sort(directoryListing);
for (File child : directoryListing) {
if (child.isFile() && child.getName().endsWith(".java")) {
filenames.add(new Object[] { child, child.getName() });
} else if (child.isDirectory()) {
collectFileNamesRecursively(child, filenames);
} else {
// Ignore
}
}
}
}
public BigSoundnessTests(File source, String name) {
this.sourceFile = source;
}
@Test
public void testWithPrincess() throws IOException {
verifyAssertions(new PrincessProverFactory());
}
@AfterClass
public static void tearDown() {
System.out.println("tearing down");
BigSoundnessUtil.storeNewTestRun(testResults);
testResults.clear();
}
// @Test
// public void testWithZ3() {
// verifyAssertions(new Z3ProverFactory());
// }
// @Test
// public void testWithSpacer() throws IOException {
// verifyAssertions(new SpacerProverFactory());
// }
protected void verifyAssertions(ProverFactory factory) throws IOException {
System.out.println("\nRunning test " + this.sourceFile.getName() + " with " + factory.getClass() + "\n");
File classDir = null;
try {
classDir = Util.compileJavaFile(this.sourceFile);
SootToCfg soot2cfg = new SootToCfg();
// soottocfg.Options.v().setPrintCFG(true);
// soottocfg.Options.v().setExcAsAssert(true);
// soottocfg.Options.v().setMemPrecision(3);
jayhorn.Options.v().setInlineMaxSize(100);
jayhorn.Options.v().setInlineCount(5);
soottocfg.Options.v().setArrayInv(true);
soottocfg.Options.v().setExactArrayElements(0);
boolean expected = this.sourceFile.getName().startsWith("Sat");
boolean result = false;
try {
soot2cfg.run(classDir.getAbsolutePath(), null);
jayhorn.Options.v().setTimeout(100);
// jayhorn.Options.v().setPrintHorn(true);
jayhorn.Options.v().setSolverOptions("abstract");
Program program = soot2cfg.getProgram();
EldaricaChecker hornChecker = new EldaricaChecker(factory);
result = hornChecker.checkProgram(program);
if (expected == result) {
resultCorrect++;
testResults.put(this.sourceFile.getParent()+"/"+ this.sourceFile.getName(), TestOutcome.CORRECT);
} else if (expected == true) {
resultImprecise++;
testResults.put(this.sourceFile.getParent()+"/"+ this.sourceFile.getName(), TestOutcome.IMPRECISE);
} else {
resultUnsound++;
testResults.put(this.sourceFile.getParent()+"/"+ this.sourceFile.getName(), TestOutcome.UNSOUND);
StringBuilder sb = new StringBuilder();
sb.append(unsoundFileNames);
sb.append(" ");
sb.append(this.sourceFile.getAbsolutePath());
sb.append("\n");
unsoundFileNames = sb.toString();
}
} catch (Exception e) {
resultException++;
testResults.put(this.sourceFile.getParent()+"/"+ this.sourceFile.getName(), TestOutcome.EXCEPTION);
e.printStackTrace();
throw new RuntimeException(e.toString());
} finally {
StringBuilder sb = new StringBuilder();
sb.append("**************************************\n");
final String stats = String.format("unsound: %1$-5d exception: %2$-5d imprecise: %3$-5d correct: %4$-5d", resultUnsound,
resultException, resultImprecise, resultCorrect);
sb.append(stats);
sb.append("\n");
if (unsoundFileNames.length()>0) {
sb.append("\nUnsound results:\n");
sb.append(unsoundFileNames);
}
sb.append("**************************************\n");
System.err.println(sb.toString());
}
Assert.assertTrue("For " + this.sourceFile.getName() + ": expected " + expected + " but got " + result,
expected == result);
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
if (classDir != null) {
classDir.deleteOnExit();
}
}
}
}