package org.jmlspecs.openjmltest.testcases;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;
import org.jmlspecs.openjml.API;
import org.jmlspecs.openjml.Factory;
import org.jmlspecs.openjml.IAPI;
import org.jmlspecs.openjml.JmlTree;
import org.jmlspecs.openjml.JmlTree.JmlClassDecl;
import org.jmlspecs.openjml.JmlTree.JmlCompilationUnit;
import org.jmlspecs.openjml.JmlTree.JmlMethodDecl;
import org.jmlspecs.openjml.JmlTree.JmlVariableDecl;
import org.jmlspecs.openjml.JmlTreeScanner;
import org.jmlspecs.openjml.proverinterface.IProverResult;
import org.jmlspecs.openjmltest.JmlTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.comp.JmlEnter;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
/** Tests the API class */
public class api extends JmlTestCase {
@Rule
public TestName name = new TestName();
static String eol = System.getProperty("line.separator");
static String z = java.io.File.pathSeparator;
boolean print = false;
boolean capture = true;
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() {
}
/** This is a helper method that runs the compiler on the given set of
* command-line arguments, checking the result
* @param args the command-line arguments
* @param output the expected output as one string
*/
public void start(boolean capture) {
if (capture) collectOutput(true);
this.capture = capture;
}
public void endCapture() {
if (!capture) return;
collectOutput(false);
capture = false;
}
public void check(String errOutput, String output) {
if (!capture) return;
boolean cap = capture;
endCapture();
// Depending on how the log is setup, error output can go to either bout or berr
String actualErr = errorOutput().replace("\r","").replace('\\','/');
String actualOut = output().replace("\r","").replace('\\','/');
errOutput = errOutput == null ? null : errOutput.replace("\r","").replace('\\','/');
output = output == null ? null : output.replace("\r","").replace('\\','/');
while (true) {
int k = actualOut.indexOf("Note:");
if (k < 0) break;
int p = actualOut.indexOf("\n",k);
actualOut = actualOut.substring(0, k) + actualOut.substring(p+1);
}
if (print) {
System.out.println("TEST: " + name.getMethodName());
System.out.println("ERR: " + actualErr);
System.out.println("OUT: " + actualOut);
}
if (cap && errOutput != null) try {
compareStrings(errOutput,actualErr);
} catch (AssertionError ex) {
if (!print) System.out.println("TEST: " + name.getMethodName() + eol + actualErr);
throw ex;
}
if (cap && output != null) try {
compareStrings(output,actualOut.replace( "No such file or directory)","The system cannot find the file specified)"));
} catch (AssertionError ex) {
if (!print) System.out.println("TEST: " + name.getMethodName() + eol + actualOut);
throw ex;
}
}
/** A helper routine to compare two Strings and instigating a JUnit test
* failure if they are different. This differs from simple assertEquals
* in giving more information about the point of difference.
* @param expected The expected result
* @param actual The actual result
*/
public void compareStrings(String expected, String actual) {
if (expected.equals(actual)) return;
int i = 0;
String msg = "";
while (i < expected.length() && i < actual.length()) {
if (expected.charAt(i) != actual.charAt(i)) {
msg = msg + ("Strings differ at character " + i + " " + expected.charAt(i) + " vs. " + actual.charAt(i)) + eol;
}
i++;
}
if (expected.length() != actual.length()) msg = msg + ("Lengths differ " + expected.length() + " vs. " + actual.length()) + eol;
assertEquals(msg,expected,actual);
}
String prettyprint =
eol +
"public class A {" + eol +
" @Ghost " + eol +
" int i = 0;" + eol +
"}" + eol +
"// Specifications: test/testNoErrors/A.java" + eol +
"// Specification file: test/testNoErrors/A.java" + eol +
"" + eol +
"public class A {" + eol +
" @Ghost " + eol +
" int i = 0;" + eol +
"}" + eol;
String prettyprint2a =
eol +
"public class A {" + eol +
" @Ghost " + eol +
" int i = 0;" + eol +
"}" + eol +
"// Specifications: /A.java" + eol +
"// Specification file: /A.java" + eol +
"" + eol +
"public class A {" + eol +
" @Ghost " + eol +
" int i = 0;" + eol +
"}" + eol;
String prettyprint2 =
eol +
"public class A {" + eol +
" @Ghost " + eol +
" int i = 0;" + eol +
"}";
String prettyprint3 =
"package a.b;" + eol +
eol +
"public class A {" + eol +
" @Ghost " + eol +
" int i = 0;" + eol +
"}" + eol +
"// Specifications: /a/b/A.java" + eol +
"// Specification file: /a/b/A.java" + eol +
"package a.b;" + eol +
eol +
"public class A {" + eol +
" @Ghost " + eol +
" int i = 0;" + eol +
"}" + eol;
String prettyprint4 = prettyprint +
"NEXT AST" + eol +
"// Specifications: test/testNoErrors/B.java" + eol +
"// Specification file: test/testNoErrors/B.java" + eol + eol;
String parseAndPrettyPrintFromJavaFileObject() throws Exception {
java.io.File f = new java.io.File("test/testNoErrors/A.java");
IAPI m = Factory.makeAPI(new String[]{});
return m.prettyPrint(m.parseFiles(m.makeJFOfromFile(f)).get(0));
}
String parseAndPrettyPrintFromFile() throws Exception {
java.io.File f = new java.io.File("test/testNoErrors/A.java");
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseFiles(f).get(0));
}
String parseAndPrettyPrintFromMultipleFiles() throws Exception {
java.io.File fa = new java.io.File("test/testNoErrors/A.java");
java.io.File fb = new java.io.File("test/testNoErrors/B.java");
IAPI m = Factory.makeAPI();
java.util.List<org.jmlspecs.openjml.JmlTree.JmlCompilationUnit> asts = m.parseFiles(fa,fb);
return m.prettyPrint(asts,"NEXT AST"); // Pretty prints a list of asts
}
String parseAndPrettyPrintFromFileArray() throws Exception {
java.io.File fa = new java.io.File("test/testNoErrors/A.java");
java.io.File fb = new java.io.File("test/testNoErrors/B.java");
File[] files = new File[]{fa,fb};
IAPI m = Factory.makeAPI();
java.util.List<org.jmlspecs.openjml.JmlTree.JmlCompilationUnit> asts = m.parseFiles(files);
return m.prettyPrint(asts,"NEXT AST"); // Pretty prints a list of asts
}
/** Tests that a file parses and pretty prints */
// API(String[]), prettyPrint(JmlCompilationUnit, true), parseFiles
@Test
public void testParseAndPrettyPrint() {
start(true);
try {
String s = parseAndPrettyPrintFromJavaFileObject();
check("","");
s = s.replace('\\','/');
compareStrings(prettyprint,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests that a file parses and pretty prints, using the no-argument
* API constructor. */
// API(), prettyPrint(JmlCompilationUnit, true), parseFiles
@Test
public void testParseAndPrettyPrint2() {
start(true);
try {
String s = parseAndPrettyPrintFromFile();
check("","");
s = s.replace('\\','/');
compareStrings(prettyprint,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
@Test
public void testParseAndPrettyPrint3() {
start(true);
try {
String s = parseAndPrettyPrintFromMultipleFiles();
check("","error: error reading test\\testNoErrors\\B.java; test\\testNoErrors\\B.java (The system cannot find the file specified)\r\n"
);
s = s.replace('\\','/');
compareStrings(prettyprint4,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
@Test
public void testParseAndPrettyPrint4() {
start(true);
try {
String s = parseAndPrettyPrintFromFileArray();
check("","error: error reading test\\testNoErrors\\B.java; test\\testNoErrors\\B.java (The system cannot find the file specified)\r\n"
);
s = s.replace('\\','/');
compareStrings(prettyprint4,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
String parseAndPrettyPrintSingleFile() throws Exception {
String f = "test/testNoErrors/A.java";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseSingleFile(f));
}
String parseAndPrettyPrintSingleFile2() throws Exception {
IAPI m = Factory.makeAPI();
JavaFileObject f = m.makeJFOfromFilename("test/testNoErrors/A.java");
return m.prettyPrint(m.parseSingleFile(f));
}
/** Tests that a file parses and pretty prints */
// API(), prettyPrint(JmlCompilationUnit, true), parseSingleFile
@Test
public void testParseAndPrettyPrint5() {
start(true);
try {
String s = parseAndPrettyPrintSingleFile();
check("","");
s = s.replace('\\','/');
compareStrings(prettyprint2,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests that a file parses and pretty prints */
// API(), prettyPrint(JmlCompilationUnit, true), parseSingleFile
@Test
public void testParseAndPrettyPrint5a() {
start(true);
try {
String s = parseAndPrettyPrintSingleFile2();
check("","");
s = s.replace('\\','/');
compareStrings(prettyprint2,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
@Test
public void testAttach() {
start(true);
try {
IAPI m = Factory.makeAPI("-no-purityCheck");
String s1 = "public class A { /*@ ensures X;*/ void f() {} }";
//String s2 = "public class A { /*@ requires Z; ensures Y;*/ void f(); }";
JavaFileObject f1 = m.makeJFOfromString("A.java",s1);
//JavaFileObject f2 = m.makeJFOfromString("A.jml",s2);
JmlCompilationUnit ast1 = m.parseSingleFile(f1);
//JmlCompilationUnit ast2 = m.parseSingleFile(f2);
m.attachSpecs(ast1,ast1);
int n = m.typecheck(ast1);
endCapture();
if (n != 1) {
System.out.println("Errors: " + n);
assertTrue(false);
}
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
@Test
public void testAttach2() {
start(true);
try {
IAPI m = Factory.makeAPI("-no-purityCheck");
String s1 = "public class A { /*@ ensures X;*/ void f() {} }";
String s2 = "public class A { /*@ requires Z; ensures Y;*/ void f(); }";
JavaFileObject f1 = m.makeJFOfromString("A.java",s1);
JavaFileObject f2 = m.makeJFOfromString("A.jml",s2);
JmlCompilationUnit ast1 = m.parseSingleFile(f1);
JmlCompilationUnit ast2 = m.parseSingleFile(f2);
m.attachSpecs(ast1,ast2);
int n = m.typecheck(ast1);
endCapture();
if (n != 2) {
System.out.println("Errors: " + n);
assertTrue(false);
}
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
// @Test
// public void testAttach3() {
// start(true);
// try {
// IAPI m = Factory.makeAPI("-no-purityCheck");
// String s1 = "public class A { /*@ ensures true;*/ void f() {} }";
// JavaFileObject f1 = m.makeJFOfromString("A.java",s1);
// JmlCompilationUnit ast1 = m.parseSingleFile(f1);
// m.attachSpecs(ast1,null); // FIXME - this makes the source file appear to be .jml and not have a binary
// int n = m.typecheck(ast1);
// endCapture();
// if (n != 0) {
// System.out.println("Errors: " + n);
// System.out.println(actualOut.toString());
// System.out.println(actualErr.toString());
// assertTrue(false);
// }
// } catch (Exception e) {
// System.out.println(e);
// e.printStackTrace(System.out);
// assertTrue(false);
// }
// }
@Test
public void testAttach5() {
start(true);
try {
IAPI m = Factory.makeAPI("-no-purityCheck");
String s1 = "public class A { void f() {} }";
String s2 = "public class A { void g(); }";
JavaFileObject f1 = m.makeJFOfromString("A.java",s1);
JavaFileObject f2 = m.makeJFOfromString("A.jml",s2);
JmlCompilationUnit ast1 = m.parseSingleFile(f1);
JmlCompilationUnit ast2 = m.parseSingleFile(f2);
m.attachSpecs(ast1,ast2);
int n = m.typecheck(ast1);
endCapture();
// Should be one error - not checking what it is
// (the .jml should not declare methods that are not in the .java file)
if (n != 1) {
System.out.println("Errors: " + n);
assertTrue(false);
}
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
String parseAndPrettyPrintString() throws Exception {
String prog = "public class A { //@ ghost int i=0;\n }";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseString("A.java",prog));
}
String parseAndPrettyPrintString2() throws Exception {
String prog = "package a.b; public class A { //@ ghost int i=0;\n }";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseString("a/b/A.java",prog));
}
/** Tests that a String parses and pretty prints */
// API(), prettyPrint(JmlCompilationUnit, true), parseString
@Test
public void testParseAndPrettyPrint6() {
start(true);
try {
String s = parseAndPrettyPrintString();
check("","");
s = s.replace('\\','/');
compareStrings(prettyprint2a,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests that a String parses and pretty prints */
// API(), prettyPrint(JmlCompilationUnit, true), parseString
@Test
public void testParseAndPrettyPrint7() {
start(true);
try {
String s = parseAndPrettyPrintString2();
check("","");
s = s.replace('\\','/');
compareStrings(prettyprint3,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
String parseExpression() throws Exception {
String expr = "a + b * c";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseExpression(expr,false));
}
String parseJMLExpression() throws Exception {
String expr = "a <==> \\result";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseExpression(expr,true));
}
String parseStatement() throws Exception {
String expr = "a = b;";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseStatement(expr,false));
}
String parseStatement2() throws Exception {
String expr = "while (true) {}";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseStatement(expr,false));
}
String parseStatement3() throws Exception {
String expr = "{ a=b; f(); }";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseStatement(expr,false));
}
String parseJMLStatement2() throws Exception {
String expr = "/*@ assert i < 10;*/";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseStatement(expr,false));
}
String parseJMLStatement() throws Exception {
String expr = "assert i >= 0;";
IAPI m = Factory.makeAPI();
return m.prettyPrint(m.parseStatement(expr,true));
}
/** Tests parsing an Expression */
@Test
public void testParseExpression() {
start(true);
try {
String s = parseExpression();
check("","");
compareStrings("a + b * c",s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests parsing an Expression */
@Test
public void testParseJMLExpression() {
start(true);
try {
String s = parseJMLExpression();
check("","");
compareStrings("a <==> \\result",s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests parsing a Statement */
@Test
public void testParseStatement() {
start(true);
try {
String s = parseStatement();
check("","");
compareStrings("a = b;",s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests parsing a Statement */
@Test
public void testParseStatement2() {
start(true);
try {
String s = parseStatement2();
check("","");
compareStrings("while (true) {" + eol + "}",s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests parsing a Statement */
@Test
public void testParseStatement3() {
start(true);
try {
String s = parseStatement3();
check("","");
compareStrings("{" + eol + " a = b;" + eol + " f();" + eol + "}",s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests parsing a Statement */
@Test
public void testParseJMLStatement2() {
start(true);
try {
String s = parseJMLStatement2();
check("","");
compareStrings("/*@ assert i < 10;*/",s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests parsing a Statement */
@Test
public void testParseJMLStatement() {
start(true);
try {
String s = parseJMLStatement();
check("","");
compareStrings("/*@ assert i >= 0;*/",s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests that a bad option is reported, but ignored */
// API(String), parseFiles, prettyPrint
@Test
public void testAPI2() {
String output =
"openjml: invalid flag: -v" + eol +
"Usage: openjml <options> <source files>" + eol +
"use -help for a list of possible options" + eol;
start(true);
try {
Set<JavaFileObject> set = new HashSet<JavaFileObject>();
IAPI m = Factory.makeAPI("-v");
set.add(m.makeJFOfromFilename("test/testNoErrors/A.java"));
//String s = m.prettyPrint(m.parseFiles(set).get(0),true);
check(output,"");
//s = s.replace('\\','/');
//compareStrings(prettyprint,s);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
// FIXME test API() with writer and diags; test exec; test version; test static execute
/** This test builds an AST from a factory and then runs type checking
* on the AST.
*/
// API(), nodeFactory(), context(), node building, prettyPrint(...,false), enterAndCheck(jcu)
@Test
public void testAPI3() {
String out =
"/A.java:1: error: incompatible types: boolean cannot be converted to int"+eol+
"-------------"+eol+
"^"+eol+
"/A.java:1: error: duplicate class: org.test.A"+eol+
"-------------"+eol+
"^"+eol;
String err = "";
try {
start(true);
IAPI api = Factory.makeAPI("-no-purityCheck");
assertTrue(api.context() != null);
JmlTree.Maker f = api.nodeFactory();
f.at(0);
// protected int field = 5;
JCModifiers mods2 = f.Modifiers(Flags.PROTECTED);
Name field = f.Name("field");
JCExpression ty = f.TypeIdent(TypeTag.INT);
JCExpression init = f.Literal(true); // Intentional error
JCVariableDecl vdecl = f.VarDef(mods2,field,ty,init);
// The class declaration
JCModifiers mods = f.Modifiers(Flags.PUBLIC);
Name a = f.Name("A");
JCClassDecl cldef =
f.ClassDef(mods,a,List.<JCTypeParameter>nil(),
null, // super class
List.<JCExpression>nil(), // List of super interfaces
List.<JCTree>of(vdecl));
// An import statement
JCExpression n = f.QualIdent("java","io","File");
JCExpression nn = f.QualIdent("java","math","*");
JCImport imp = f.Import(n,false); // import java.io.File; (false means not static)
JCImport imp2 = f.Import(nn,false); // import java.math.*;
// The compilation unit
JCExpression packageid = f.QualIdent("org","test");
JmlCompilationUnit jcu = f.TopLevel(List.<JCAnnotation>nil(),
packageid,List.<JCTree>of(imp,imp2,cldef));
jcu.mode = JmlCompilationUnit.JAVA_SOURCE_FULL;
jcu.sourcefile = api.makeJFOfromString("A.java","-------------");
// TODO: docCOmments, endPositions, flags, lineMap, mode, namedImportSCope,
// parsedTopLevelModelTypes, starImportScope
// refinesClause, specsTopLevelModelTypes, specsSequence
// Javadoc comments // FIXME - ressurect doc comments
// Map<JCTree,String> doccomments = new HashMap<JCTree,String>();
// doccomments.put(cldef,"/** The class */");
// doccomments.put(vdecl,"/** The field */");
// jcu.docComments = doccomments;
//System.out.println(api.prettyPrint(jcu,false)); //FIXME - doc comments do not print
Collection<JmlCompilationUnit> coll = new LinkedList<JmlCompilationUnit>();
coll.add(jcu);
int errs = api.typecheck(coll);
assertEquals(1,errs);
java.util.List<JmlCompilationUnit> list = new LinkedList<JmlCompilationUnit>();
list.add(jcu);
errs += api.typecheck(list); // Complains about duplicate class
check(err,out); //FIXME - i thought the default was to send diags to System.out
assertEquals(2,errs);
} catch (Exception e) {
check(null,null);
System.out.println(e);
e.printStackTrace(System.out);
}
}
public void testAPI3a() {
String out =
"package org.test;"+eol+
eol+
"import java.io.File;"+eol+
"import java.math.*;"+eol+
eol+
"public class A {"+eol+
" protected int field = true;"+eol+
"}"+eol;
String err =
"/A.java:1: incompatible types"+eol+
"-------------"+eol+
"^"+eol+
" required: int"+eol+
" found: boolean"+eol+
"/A.java:1: duplicate class: org.test.A"+eol+
"-------------"+eol+
"^"+eol;
try {
start(true);
IAPI api = Factory.makeAPI(
new PrintWriter(System.err),null,null,"-no-purityCheck");
assertTrue(api.context() != null);
JmlTree.Maker f = api.nodeFactory();
f.at(0);
// protected int field = 5;
JCModifiers mods2 = f.Modifiers(Flags.PROTECTED);
Name field = f.Name("field");
JCExpression ty = f.TypeIdent(TypeTag.INT);
JCExpression init = f.Literal(true); // Intentional error
JCVariableDecl vdecl = f.VarDef(mods2,field,ty,init);
// The class declaration
JCModifiers mods = f.Modifiers(Flags.PUBLIC);
Name a = f.Name("A");
JCClassDecl cldef =
f.ClassDef(mods,a,List.<JCTypeParameter>nil(),
null, // super class
List.<JCExpression>nil(), // List of super interfaces
List.<JCTree>of(vdecl));
// An import statement
JCExpression n = f.QualIdent("java","io","File");
JCExpression nn = f.QualIdent("java","math","*");
JCImport imp = f.Import(n,false); // import java.io.File; (false means not static)
JCImport imp2 = f.Import(nn,false); // import java.math.*;
// The compilation unit
JCExpression packageid = f.QualIdent("org","test");
JmlCompilationUnit jcu = f.TopLevel(List.<JCAnnotation>nil(),
packageid,List.<JCTree>of(imp,imp2,cldef));
jcu.mode = JmlCompilationUnit.JAVA_SOURCE_FULL;
jcu.sourcefile = api.makeJFOfromString("A.java","-------------");
// TODO: docCOmments, endPositions, flags, lineMap, mode, namedImportSCope,
// parsedTopLevelModelTypes, starImportScope
// refinesClause, specsTopLevelModelTypes, specsSequence
// Javadoc comments // FIXME - ressurrect doc comments
// Map<JCTree,String> doccomments = new HashMap<JCTree,String>();
// doccomments.put(cldef,"/** The class */");
// doccomments.put(vdecl,"/** The field */");
// jcu.docComments = doccomments;
// System.out.println(api.prettyPrint(jcu)); //FIXME - doc comments do not print
Collection<JmlCompilationUnit> coll = new LinkedList<JmlCompilationUnit>();
coll.add(jcu);
int errs = api.typecheck(coll);
assertEquals(1,errs);
java.util.List<JmlCompilationUnit> list = new LinkedList<JmlCompilationUnit>();
list.add(jcu);
errs += api.typecheck(list); // Complains about duplicate class
check(err,out); //FIXME - i thought the default was to send diags to System.out
assertEquals(2,errs);
} catch (Exception e) {
check(null,null);
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
// TODO test enterAndCheck with >1 arguments
/** Tests running a scanner over an AST */
// parseString, tree walking // FIXME - document & test different scan modes
@Test
public void testAPI4() {
start(true);
try {
String program = "public class A { int i; }";
IAPI m = Factory.makeAPI();
JCTree ast = m.parseString("A.java",program);
TestScanner v = new TestScanner();
v.scanMode = JmlTreeScanner.AST_JAVA_MODE;
v.scan(ast);
check("","");
assertEquals(1,v.numberClasses);
assertEquals(6,v.numberNodes);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
@Test
public void testAPI6() {
start(true);
try {
IAPI m = Factory.makeAPI();
int exitcode = m.execute(null,"-cp","test/api","test/api/A.java");
assertTrue(exitcode == 0);
assertTrue(m.isTypechecked("A"));
assertTrue(!m.isTypechecked("B"));
m.parseAndCheck(new File("test/api/B.java"));
assertTrue(m.isTypechecked("B"));
ClassSymbol sym = m.getClassSymbol("B");
m.doESC(sym);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
} finally {
check("","");
}
}
@Test
public void testAPI5() {
start(false);
try {
IAPI m = Factory.makeAPI("-verbose","-noInternalSpecs");
int exitcode = m.execute(null,"-cp","test/api","test/api/A.java");
assertTrue(exitcode == 0);
assertTrue(m.isTypechecked("A"));
assertTrue(!m.isTypechecked("B"));
m.typecheck(m.parseFiles(new File("test/api/B.java")));
assertTrue(m.isTypechecked("B"));
m.doESC(m.getClassSymbol("B"));
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
} finally {
check("","");
}
}
@Test
public void testAPI7() {
start(false);
try {
IAPI m = Factory.makeAPI("-verbose","-noInternalSpecs");
int exitcode = m.execute(null,"-cp","test/api2","test/api2/p1/A.java");
assertTrue(exitcode == 0);
assertTrue(m.isTypechecked("p1.A"));
assertTrue(!m.isTypechecked("p2.B"));
m.typecheck(m.parseFiles(new File("test/api2/p2/B.java")));
assertTrue(m.isTypechecked("p2.B"));
ClassSymbol sym = m.getClassSymbol("p2.B");
sym = m.getClassSymbol("p2.B");
m.doESC(sym);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
} finally {
check("","");
}
}
public static class TestScanner extends JmlTreeScanner {
public int numberClasses = 0;
public int numberNodes = 0;
public void scan(JCTree node) {
if (node != null) numberNodes++;
super.scan(node); // Call this to scan child nodes
}
public void visitJmlClassDecl(JmlClassDecl node) {
numberClasses++;
super.visitJmlClassDecl(node); // Call this to scan child nodes
}
}
protected boolean deleteAll(File f) {
boolean b = true;
if (!f.isDirectory()) {
return f.delete();
}
for (File ff: f.listFiles()) {
b = deleteAll(ff) && b;
}
return b;
}
/** Test jmldoc through the API */ // FIXME - this and maybe others do not check for errors
// jmldoc
@Ignore @Test // FIXME - disable until jmldoc is repaired
public void testJmldoc() {
// File f = new java.io.File("tempdoc");
// if (f.exists()) {
// boolean b = deleteAll(f);
// assertTrue(b);
// }
// try {
// int exitcode = API.jmldoc(new String[]{"-d","tempdoc","-notimestamp","-no-purityCheck","-dir","test/jmldoc1/data"});
// assertEquals("Mismatched exit code",0,exitcode);
// // FIXME - run the diff program successfully, or do it programmatically
//// Process p = Runtime.getRuntime().exec("/usr/bin/diff",new String[]{"-r","-x",".svn","-x","package-tree.html","doc","../test/jmldoc1/expected"});
//// exitcode = p.exitValue();
// assertEquals(0,exitcode);
// } catch (Exception e) {
// fail();
// }
}
public final static String program =
"public class A { /*@ requires i > 0;*/void m(int i) {} void mm() { m(0); } int ff; int f; public static class B {} }";
/** Tests the enterAndCheck call */
// parseString, enterAndCheck
@Test
public void testEnterAndCheck() {
start(true);
try {
IAPI m = Factory.makeAPI();
m.addOptions("-no-purityCheck");
JmlCompilationUnit jcu = m.parseString("A.java",program);
int n = m.typecheck(jcu);
check("","");
assertTrue(n == 0);
} catch(AssertionError e) {
throw e;
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
@Test
public void testOptions() {
try {
IAPI m = Factory.makeAPI();
String s = m.getOption("-x");
assertEquals(null,s);
m.addOptions("-x");
s = m.getOption("-x");
assertEquals(null,s);
m.main().addUncheckedOption("-x");
s = m.getOption("-x");
assertEquals("",s);
m.addUncheckedOption("-x=asd");
s = m.getOption("-x");
assertEquals("asd",s);
m.addUncheckedOption("-x=false");
s = m.getOption("-x");
assertEquals(null,s);
} catch (Exception e) {
fail();
}
}
@Test
public void testClose() {
try {
IAPI m = Factory.makeAPI();
assertTrue(m.context() != null);
m.close();
assertTrue(m.context() == null);
} catch (Exception e) {
fail();
}
}
// FIXME - test getting symbols by name with outer classes and inheritance
/** Tests the symbol utilities call */
// parseString, enterAndCheck, getClassSymbol, getSymbol, getClassDecl, getMethodDecl, getVarDecl
@Test
public void testSymbolUtilities() {
start(true);
try {
IAPI m = Factory.makeAPI(new String[]{"-no-purityCheck"});
JmlCompilationUnit jcu = m.parseString("A.java",program);
int n = m.typecheck(new JmlCompilationUnit[]{jcu});
assertTrue(n == 0);
check("","");
ClassSymbol csym = m.getClassSymbol("A");
JmlClassDecl cd = m.getClassDecl(csym);
JmlClassDecl cdd = m.getClassDecl("A");
ClassSymbol csymm = m.getSymbol(cd);
assertEquals(cd,cdd);
assertEquals(csym,csymm);
assertEquals("A",csym.className().toString());
VarSymbol vsym = m.getVarSymbol(csym,"ff");
assertEquals("ff",vsym.getSimpleName().toString());
JmlVariableDecl vd = m.getVarDecl(vsym);
VarSymbol vsymm = m.getSymbol(vd);
assertEquals(vsym,vsymm);
vsym = m.getVarSymbol(csym,"notexist");
assertEquals(null,vsym);
MethodSymbol msym = m.getMethodSymbol(csym,"mm");
assertEquals("mm",msym.getSimpleName().toString());
JmlMethodDecl md = m.getMethodDecl(msym);
MethodSymbol msymm = m.getSymbol(md);
assertEquals(msym,msymm);
msym = m.getMethodSymbol(csym,"notexist");
assertEquals(null,msym);
ClassSymbol ccsym = m.getClassSymbol(csym,"B");
assertEquals("B",ccsym.getSimpleName().toString());
JmlClassDecl ccd = m.getClassDecl(ccsym);
ClassSymbol ccsymm = m.getSymbol(ccd);
assertEquals(ccsym,ccsymm);
ccsym = m.getClassSymbol(csym,"notexist");
assertEquals(null,ccsym);
PackageSymbol psym = m.getPackageSymbol("java.lang");
assertEquals("java.lang",psym.flatName().toString());
psym = m.getPackageSymbol("org.jmlspecs.lang");
assertEquals("org.jmlspecs.lang",psym.flatName().toString());
psym = m.getPackageSymbol("org.jmlspecs.annotation");
assertEquals("org.jmlspecs.annotation",psym.flatName().toString());
psym = m.getPackageSymbol("");
assertEquals("",psym.flatName().toString());
psym = m.getPackageSymbol("ZZZ");
assertEquals(null,psym);
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck // FIXME test parseAndCheck with errors
@Test
public void testParseAndCheck() {
start(true);
try {
java.io.File f = new java.io.File("test/testNoErrors/A.java");
IAPI m = Factory.makeAPI();
m.addOptions("-no-purityCheck");
m.parseAndCheck(f);
check("","");
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck
@Test
public void testParseAndCheckDuplicate() {
start(true);
try {
DiagnosticCollector<JavaFileObject> dcoll = new DiagnosticCollector<JavaFileObject>();
java.io.File f = new java.io.File("test/testNoErrors/A.java");
java.io.File ff = new java.io.File("test/testNoErrors2/A.java");
IAPI m = Factory.makeAPI(new PrintWriter(System.out),dcoll,null);
m.addOptions("-no-purityCheck");
m.parseAndCheck(f,ff); // FIXME - expect errors - check for them
check("","");
java.util.List<Diagnostic<? extends JavaFileObject>> dlist = dcoll.getDiagnostics();
int errs = dlist.size();
assertEquals(1,errs);
assertEquals("duplicate class: A",dlist.get(0).getMessage(null));
assertEquals(8,dlist.get(0).getColumnNumber());
assertEquals(1,dlist.get(0).getLineNumber());
assertEquals(7,dlist.get(0).getPosition());
assertEquals(0,dlist.get(0).getStartPosition());
assertEquals(56,dlist.get(0).getEndPosition());
assertEquals("test/testNoErrors2/A.java",dlist.get(0).getSource().getName().toString().replace('\\','/'));
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck
@Test
public void testParseAndCheckCrash2() {
start(true);
String out = "error: A class is not defined in the expected file: test\\testNoErrors\\A.java" + eol;
try {
java.io.File f = new java.io.File("test/testNoErrors/A.java");
IAPI m = Factory.makeAPI();
m.addOptions("-no-purityCheck");
m.parseAndCheck(f,f);
check("","");
} catch (Exception e) {
check("",out);
// System.out.println(e);
// e.printStackTrace(System.out);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck
@Test
public void testParseAndCheckCrash() {
start(true);
String out = "error: A class is not defined in the expected file: test\\testNoErrors\\A.java" + eol;
try {
java.io.File f = new java.io.File("test/testNoErrors/A.java");
java.io.File ff = new java.io.File("test/testNoErrors/A.java");
IAPI m = Factory.makeAPI();
m.addOptions("-no-purityCheck");
m.parseAndCheck(f,ff);
check("","");
} catch (Exception e) {
check("",out);
// System.out.println(e);
// e.printStackTrace(System.out);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck
@Test
public void testParseAndCheck1Errors() {
start(true);
try {
DiagnosticCollector<JavaFileObject> dcoll = new DiagnosticCollector<JavaFileObject>();
java.io.File f = new java.io.File("test/testSyntaxError/A.java");
IAPI m = Factory.makeAPI(
new PrintWriter(System.out),dcoll,null);
m.addOptions("-no-purityCheck");
m.parseAndCheck(f);
check("","");
java.util.List<Diagnostic<? extends JavaFileObject>> dlist = dcoll.getDiagnostics();
int errs = dlist.size();
assertEquals(3,errs);
assertEquals("<identifier> expected",dlist.get(0).getMessage(null));
assertEquals("reached end of file while parsing",dlist.get(1).getMessage(null));
assertEquals("cannot find symbol\n symbol: class asdsadads\n location: class A",dlist.get(2).getMessage(null));
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck
// uses specs in the .jml file, not the .java file, so sees no errors
@Test
public void testParseAndCheck1ErrorsA() {
start(true);
try {
DiagnosticCollector<JavaFileObject> dcoll = new DiagnosticCollector<JavaFileObject>();
java.io.File f = new java.io.File("test/testJavaErrors/A.java");
IAPI m = Factory.makeAPI(
new PrintWriter(System.out),dcoll,null,
"-specspath","test/testJavaErrors");
m.addOptions("-no-purityCheck");
m.parseAndCheck(f);
check("",""); // FIXME - this does not capture errors
java.util.List<Diagnostic<? extends JavaFileObject>> dlist = dcoll.getDiagnostics();
int errs = dlist.size();
assertEquals(0,errs);
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck
// No specspath so uses the .java file, which has an error
@Test
public void testParseAndCheck1ErrorsB() {
start(true);
try {
DiagnosticCollector<JavaFileObject> dcoll = new DiagnosticCollector<JavaFileObject>();
java.io.File f = new java.io.File("test/testJavaErrors/A.java");
IAPI m = Factory.makeAPI(
new PrintWriter(System.out),dcoll,null);
m.addOptions("-no-purityCheck");
m.parseAndCheck(f);
check("","");
java.util.List<Diagnostic<? extends JavaFileObject>> dlist = dcoll.getDiagnostics();
int errs = dlist.size();
assertEquals(1,errs);
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck
@Test
public void testParseAndCheck1ErrorsC() {
start(true);
try {
DiagnosticCollector<JavaFileObject> dcoll = new DiagnosticCollector<JavaFileObject>();
java.io.File f = new java.io.File("test/testSpecErrors/A.java");
IAPI m = Factory.makeAPI(
new PrintWriter(System.out),dcoll,null);
m.addOptions("-no-purityCheck");
//m.addOptions("-specspath","test/testSpecErrors");
m.parseAndCheck(f);
check("","");
java.util.List<Diagnostic<? extends JavaFileObject>> dlist = dcoll.getDiagnostics();
int errs = dlist.size();
assertEquals(0,errs);
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
@Test
public void testParseAndCheck1ErrorsD() {
start(true);
try {
DiagnosticCollector<JavaFileObject> dcoll = new DiagnosticCollector<JavaFileObject>();
java.io.File f = new java.io.File("test/testSpecErrors/A.java");
IAPI m = Factory.makeAPI(
new PrintWriter(System.out),dcoll,null,"-specspath","test/testSpecErrors");
m.addOptions("-no-purityCheck");
m.parseAndCheck(f);
check("","");
java.util.List<Diagnostic<? extends JavaFileObject>> dlist = dcoll.getDiagnostics();
int errs = dlist.size();
assertEquals(1,errs);
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
@Test
public void testParseAndCheck1ErrorsE() {
start(true);
try {
DiagnosticCollector<JavaFileObject> dcoll = new DiagnosticCollector<JavaFileObject>();
java.io.File f = new java.io.File("test/testSpecErrors/A.java");
IAPI m = Factory.makeAPI(
new PrintWriter(System.out),dcoll,null);
m.addOptions("-no-purityCheck");
m.addOptions("-specspath","test/testSpecErrors");
m.parseAndCheck(f);
check("","");
java.util.List<Diagnostic<? extends JavaFileObject>> dlist = dcoll.getDiagnostics();
int errs = dlist.size();
assertEquals(1,errs);
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests the parseAndCheck call */
// parseAndCheck
@Test
public void testParseAndCheck2() {
start(true);
try {
java.io.File f = new java.io.File("test/testNoErrors/A.java");
IAPI m = Factory.makeAPI();
m.addOptions("-no-purityCheck");
m.parseAndCheck(new File[]{f});
check("","");
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
// FIXME _ also test various solvers
@Test
public void testESC() {
testESC("");
}
@Test @Ignore // FIXME - boogie not implemented
public void testESCBoogie() {
testESC("-boogie");
}
/** Tests ESC */
// doESC [all variations, with and without errors]
// getClassSymbol, getMethodSymbol, getProofResult
public void testESC(String option) {
start(false);
try {
DiagnosticCollector<JavaFileObject> diags = new DiagnosticCollector<JavaFileObject>();
IAPI m = Factory.makeAPI(
new PrintWriter(System.out),
diags,
null,
option,
"-no-purityCheck");
// if (option.equals("-custom")) {
// m.addOptions("openjml.defaultProver","yices");
// } else
if (option.equals("-boogie")) {
m.addOptions("openjml.defaultProver","z3_4_4");
} else {
m.addOptions("openjml.defaultProver","z3_4_4");
}
JmlCompilationUnit jcu = m.parseString("A.java",program);
int n = m.typecheck(jcu);
assertTrue(n==0);
ClassSymbol csym = m.getClassSymbol("A");
MethodSymbol mmsym = m.getMethodSymbol(csym,"mm");
MethodSymbol msym = m.getMethodSymbol(csym,"m");
IProverResult res = m.doESC(msym);
java.util.List<Diagnostic<? extends JavaFileObject>> dlist = diags.getDiagnostics();
if (dlist.size() != 0) { // Should be none
// Print out observed errors for debugging
endCapture();
for (Diagnostic<? extends JavaFileObject> d: dlist) {
System.out.println(d.getMessage(null));
}
}
//res = m.getProofResult(msym);
assertTrue(res != null);
assertEquals(0,dlist.size());
assertEquals(IProverResult.UNSAT,res.result());
res = m.doESC(mmsym);
endCapture();
//res = m.getProofResult(mmsym);
assertTrue(res != null);
assertEquals(2,dlist.size());
assertTrue(res.result() == IProverResult.POSSIBLY_SAT || res.result() == IProverResult.SAT);
//m.addOptions("-show");
m.doESC(csym);
check("","");
assertEquals(4,dlist.size());
} catch(AssertionError e) {
throw e;
} catch (Exception e) {
check("","");
System.out.println(e);
e.printStackTrace(System.out);
assertTrue(false);
}
}
/** Tests the makeJFO... methods */
// makeJFO...
@Test
public void testUtils() {
try {
IAPI api = Factory.makeAPI();
char[] cb = new char[10000];
FileReader fr = new FileReader(new File("test/testNoErrors/A.java"));
int n = fr.read(cb,0,cb.length);
fr.close();
if (n == -1) fail("Failed to read A.java");
if (n == cb.length) fail("Buffer not large enough");
String fc = new String(cb,0,n);
JavaFileObject jfo = api.makeJFOfromFilename("test/testNoErrors/A.java");
assertEquals(JavaFileObject.Kind.SOURCE,jfo.getKind());
assertEquals(fc,jfo.getCharContent(true).toString());
jfo = api.makeJFOfromString("A.java","public class A{}");
assertEquals(JavaFileObject.Kind.SOURCE,jfo.getKind());
assertEquals("public class A{}",jfo.getCharContent(true).toString());
jfo = api.makeJFOfromString("A.jml","public class A{}");
assertEquals(JavaFileObject.Kind.OTHER,jfo.getKind());
assertEquals("public class A{}",jfo.getCharContent(true).toString());
jfo = api.makeJFOfromFile(new File("test/testNoErrors/A.java"));
assertEquals(JavaFileObject.Kind.SOURCE,jfo.getKind());
assertEquals(fc,jfo.getCharContent(true).toString());
} catch(AssertionError e) {
throw e;
} catch (Exception e) {
e.printStackTrace(System.out);
fail();
}
}
// TODO: test setProgressReporter, exec
// TODO: test enterAndCheck with multiple arguments
// TODO: test parseFiles with multiple File arguments
// TODO: test parseFiles with multiple JavaFileObject arguments
// TODO: test getBasicBlockPRogram
// TODO: test collectSuperTypes, collectSuperMethods
// TODO: test getSpecs, getAllSpecs for field, method, class
// TODO: test getting denested specs
// TODO: test prettyprint on list
// TODO: what about making mock JFO directories and specspath entries
// TODO: test getCEValue
// TODO: test copying; test different scan modes
// TODO: need a way to reset the context
// TODO: test getting specs and symbols
// TODO: test combining specs
// TODO: comments and javadoc comments
}