package org.jmlspecs.openjmltest.testcases; import static org.junit.Assert.fail; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.jmlspecs.openjml.Utils; import org.jmlspecs.openjmltest.EscBase; import org.junit.Assume; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.ParameterizedWithNames; import org.junit.runners.Parameterized.Parameters; /** These tests check running ESC on files in the file system, comparing the * output against expected files. These tests are a bit easier to create, since * the file and output do not have to be converted into Strings; however, they * are not as easily read, since the content is tucked away in files, rather * than immediately there in the test class. * <P> * To add a new test: * <UL> * <LI> create a directory containing the test files as a subdirectory of * 'test' * <LI> add a test to this class - typically named similarly to the folder * containing the source data * </UL> */ @RunWith(ParameterizedWithNames.class) public class escfiles extends EscBase { boolean enableSubexpressions = false; public escfiles(String options, String solver) { super(options,solver); } String[] rac = null; /** The command-line to use to run ESC on a program */ String[] sysrac = new String[]{jdk, "-classpath","bin"+z+"../OpenJML/bin-runtime",null}; @Override public void setUp() throws Exception { rac = sysrac; super.setUp(); ignoreNotes = true; } public void helpTF(String testDirname, String ... opts) { String d = "test/" + testDirname; String[] newopts = new String[opts.length+3]; newopts[0] = "-classpath"; newopts[1] = d; newopts[2] = "-checkFeasibility=precondition,assert,reachable,exit"; System.arraycopy(opts,0,newopts,3,opts.length); helpTCF(d,d,newopts); } public void helpDemo(String testDirname, String outdir, String ... opts) { String d = OpenJMLDemoPath + "/src/openjml/" + testDirname; String[] newopts = new String[opts.length+2]; newopts[0] = "-classpath"; newopts[1] = d; System.arraycopy(opts,0,newopts,2,opts.length); helpTCF(d,"test/" + outdir,newopts); } public void helpTCF(String sourceDirname, String outDir, String ... opts) { List<String> list = Arrays.asList(opts); list = new ArrayList<String>(list); list.add("-checkFeasibility=precondition,exit,reachable"); opts = list.toArray(opts); escOnFiles(sourceDirname,outDir,opts); } @Test public void testDemo() { expectedExit = 1; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClock.java","test/escDemo"); } @Test public void testDemo1() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClock1.java","test/escDemo1","-escMaxWarnings=1"); } @Test public void testDemoA() { expectedExit = 1; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClockA.java","test/escDemoA","-subexpressions","-method=tick"); } @Test public void testDemoA1() { expectedExit = 1; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClockA1.java","test/escDemoA1","-subexpressions","-method=tick"); } @Test public void testDemoB() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClockB.java","test/escDemoB");//,"-method=tick","-show","-escMaxWarnings=1","-checkFeasibility=debug"); } @Test public void testDemoB1() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClockB1.java","test/escDemoB1", "-progress","-escMaxWarningsPath",enableSubexpressions ? "-subexpressions" : ""); } @Test public void testDemoB2() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClockB2.java","test/escDemoB2"); } @Test public void testDemoB3() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClockB3.java","test/escDemoB3",enableSubexpressions ? "-subexpressions" : ""); } @Test public void testDemoC() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClockC.java","test/escDemoC","-subexpressions"); } @Test public void testDemoD() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/clock/TickTockClockD.java","test/escDemoD","-subexpressions"); } @Test public void testDemoTypes() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/Types.java","test/escDemoTypes","-typeQuants=true","-noInternalSpecs",enableSubexpressions ? "-subexpressions" : ""); } @Test // Problem with reasoning about generic types public void testDemoTypesAuto() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/Types.java","test/escDemoTypes","-typeQuants=auto","-noInternalSpecs",enableSubexpressions ? "-subexpressions" : ""); } @Test public void testDemoTypesDef() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/Types.java","test/escDemoTypes","-typeQuants=false","-noInternalSpecs",enableSubexpressions ? "-subexpressions" : ""); } @Test // FIXME - Problem with int / short conversions public void testDemoTime() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/Time.java","test/escDemoTime","-logic=AUFNIA"); } @Test @Ignore // FIXME - order of errors is too non-deterministic public void testBag() { expectedExit = 0; helpTCF("test/bag","test/bag"); } @Test public void testBagModified() { expectedExit = 0; helpTCF("test/bagModified","test/bagModified"); } @Test @Ignore // FIXME - hangs up sometimes with some solvers; takes a while with others - comment out while we are doing repeated testing public void testLoopExercises() { expectedExit = 0; helpTCF("test/loopExercises","test/loopExercises","-logic=AUFNIA"); } @Test @Ignore // FIXME - CVC4 crashes public void testPurseCard() { if ("cvc4".equals(solver)) fail(); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/purse","test/purse","-logic=AUFNIA","-timeout=15"); } @Test @Ignore // FIXME - CVC4 crashes public void testPurseCardMod() { if ("cvc4".equals(solver)) fail(); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/purseMod","test/purseMod","-classpath",OpenJMLDemoPath + "/src/openjml/purseMod","-logic=AUFNIA","-timeout=15"); } @Test public void testTaxpayer() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/Taxpayer.java","test/demoTaxpayer","-classpath",OpenJMLDemoPath + "/src/openjml/demo"); } @Test public void testBeanCan() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/BeanCan.java","test/demoBeancan","-classpath",OpenJMLDemoPath + "/src/openjml/demo"); } @Test @Ignore // FIXME - stuck or just long? public void testECU() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/ecudemo","test/ecuesc","-classpath",OpenJMLDemoPath + "/src/openjml/ecudemo","-logic=AUFNIA"); } @Test public void testException() { helpTF("escException"); } @Test public void testAdd() { expectedExit = 1; helpTF("escAdd"); } @Test public void testAdd2() { expectedExit = 0; helpTF("escAdd2"); } @Test public void testCashAmount() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/CashAmount.java","test/escCashAmount","-classpath",OpenJMLDemoPath + "/src/openjml/demo","-escMaxWarnings=1","-logic=AUFNIA"); } @Test public void testCashAmount2() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/CashAmountOnlyPrivate.java","test/escCashAmountonlyPrivate","-classpath",OpenJMLDemoPath + "/src/openjml/demo"); } @Test public void testCashAmountMutable() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/CashAmountMutable.java","test/escCashAmountMutable","-classpath",OpenJMLDemoPath + "/src/openjml/demo"); } @Test public void testCashAmountMF() { expectedExit = 0; helpTCF(OpenJMLDemoPath + "/src/openjml/demo/CashAmountMF.java","test/escCashAmountMF","-classpath",OpenJMLDemoPath + "/src/openjml/demo","-escMaxWarnings=1"); } @Test public void testSettableClock() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpDemo("settableClock","escSettableClock","-logic=AUFNIA"); } @Test public void testVector() { expectedExit = 0; helpTF("escVector","-code-math=java"); } @Test @Ignore // FIXME - make this work by carrying information about variables into the first cycle of a loop public void testDMZLoop() { expectedExit = 0; helpTF("escDMZLoop","-method=findMax","-show"); } @Test public void testDMZLoopA() { expectedExit = 0; helpTF("escDMZLoopA","-method=findMax"); } @Test public void testDMZLoopB() { expectedExit = 0; helpTF("escDMZLoopB","-method=findMax"); } @Test public void testRecursiveInvariant() { expectedExit = 1; helpTF("escRecursiveInvariant","-no-minQuant"); } @Test public void testRecursiveInvariantMQ() { expectedExit = 1; helpTF("escRecursiveInvariantMQ","-minQuant"); } @Test public void testRecursiveInvariant2() { expectedExit = 1; helpTF("escRecursiveInvariant2","-no-minQuant"); } @Test public void testRecursiveInvariant2MQ() { expectedExit = 1; helpTF("escRecursiveInvariant2","-minQuant"); } // FIXME - reasoning about getClass @Test public void testBadCast() { expectedExit = 0; helpTF("escBadCast");//,"-show","-method=BadCast.equals"); } @Test public void testCashAmountPrivate2() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); expectedExit = 0; helpTCF("test/escCashAmountPrivate2/CashAmountOnlyPrivate.java","test/escCashAmountPrivate2","-classpath","test/escCashAmountPrivate2","-method=increase","-logic=AUFNIA"); } @Test public void testJLS() { expectedExit = 0; helpTF("escJLS"); } @Test public void testDoublyLinkedList() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); helpTF("escDoublyLinkedList"); } @Test public void testEscModelFields() { helpTF("escModelFields","-progress"); } @Test public void testEscSimpleString() { Assume.assumeTrue(runLongTests || !"cvc4".equals(solver)); // FIXME - CVC4 crashes or is long helpTF("escSimpleString","-nonnullByDefault","-timeout=240");//,"-method=esc.SimpleString.SimpleString(int[])","-show","-subexpressions"); } @Test public void testEscSimpleString2() { helpTF("escSimpleString2","-nonnullByDefault"); } @Test public void testEscSimpleString3() { helpTF("escSimpleString3","-nonnullByDefault"); } @Test @Ignore // FIXME - long running, probably because of the logic public void testEscDiverges() { helpTF("escDiverges","-nonnullByDefault","-logic=AUFNIRA"); } @Test @Ignore // FIXME - long running, probably because of the logic public void testEscDiverges2() { helpTF("escDiverges2","-nonnullByDefault","-logic=AUFNIRA"); } @Test public void testEscDeterministic() { helpTF("escDeterministic"); } @Test public void testEscDeterministic2() { helpTF("escDeterministic2"); } @Test public void testEscInvariants() { helpTF("escInvariants"); } @Test public void testEscInvariants2() { helpTF("escInvariants2"); } @Test public void testJmlSpecPublic() { helpTCF("test/escSeparateJml/BankingExample.java","test/escSeparateJml","-classpath","test/escSeparateJml");//,"-show","-method=credit","-subexpressions","-checkFeasibility=all"); } @Test public void escAssignableBug() { helpTF("escAssignableBug"); } @Test public void escDerivedInvariant() { helpTF("escDerivedInvariant"); } @Test public void testEscConstructor() { helpTF("escConstructor"); } @Test public void testEscConstructor2() { helpTF("escConstructor2"); } @Test public void testEscConstructor3() { helpTF("escConstructor3"); } @Test public void testEscConstructor4() { helpTF("escConstructor4"); } @Test public void testEscConstructor5() { helpTF("escConstructor5"); } @Test public void testEscConstructor6() { helpTF("escConstructor6"); } @Test public void testEscShortCircuit() { helpTF("escShortCircuit"); } @Test // FIXME - still has problems with imports in JML files and with checks on field initializers public void testEscJml() { helpTCF("test/escJml/Test.java","test/escJml","-specspath=test/escJml/specs"); } @Test public void testEscJml1() { helpTCF("test/escJml1/StorageParameters.java","test/escJml1","-specspath=test/escJml1/specs");//,"-show","-method=main"); } @Test public void testEscJml2() { helpTCF("test/escJml2/StorageParameters.java","test/escJml2","-specspath=test/escJml2/specs"); } @Test public void testEscJml3() { helpTCF("test/escJml3/StorageParameters.java","test/escJml3","-specspath=test/escJml2/specs"); } @Test public void testEscJmlDup() { helpTF("escDup"); } // The following are split into multiple tests to minimize the combinatorial non-determinism in the output @Test public void testEscSF420() { helpTF("sfbug420","-exclude=count;itemAt;main;isEmpty;push;top"); } @Test public void testEscSF420a() { helpTF("sfbug420a","-method=count"); } @Test public void testEscSF420b() { helpTF("sfbug420b","-method=itemAt"); } @Test public void testEscSF420c() { helpTF("sfbug420c","-method=main"); } @Test public void testEscSF420d() { helpTF("sfbug420d","-method=isEmpty"); } @Test public void testEscSF420e() { helpTF("sfbug420e","-method=push"); } @Test public void testEscSF420f() { helpTF("sfbug420f","-method=top"); } @Test public void testEscSF420X() { helpTF("sfbug420X"); } @Test public void testEscRawding() { helpTF("escRawding","-specspath=test/escRawding","-code-math=safe"); } // The following are really just typecheck problems @Test public void testEscVisibilitySimple() { expectedExit = 1; helpTF("visibilitySimple"); } @Test public void testVisibilityB() { expectedExit = 1; helpTCF("test/visibilityB/org/apache/commons/cli/Option.java","test/visibilityB","-classpath","test/visibilityB"); } }