/** * */ 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(); } } } }