package org.jmlspecs.openjmltest.testcases; import org.jmlspecs.openjmltest.TCBase; import org.junit.Test; public class typechecking extends TCBase { @Override public void setUp() throws Exception { // noCollectDiagnostics = true; // jmldebug = true; useSystemSpecs = true; super.setUp(); main.addOptions("-no-purityCheck"); //main.addOptions("-jmldebug"); } /** Test something very simple with no errors*/ @Test public void testSomeJava() { // main.addOptions("-verbose"); helpTC("import org.jmlspecs.lang.JMLDataGroup; class A { public A(){} }"); } /** Test something very simple with no errors*/ @Test public void testSomeJavaB() { helpTC(" class A {}"); } /** Test a particular error*/ @Test public void testSomeJavaBrace() { helpTC(" class A {} }" ,"/TEST.java:1: class, interface, or enum expected",13,12,12,12 // FIXME - end position may not be useful - should be 13? ); } /** Test scanning something very simple */ @Test public void testSomeJava2() { helpTC(" class A { int k = true; }", "/TEST.java:1: incompatible types: boolean cannot be converted to int",20); } /** Test scanning something very simple */ @Test public void testSomeJML() { helpTC(" class A { int k; boolean b; void m() { \n//@ assert k;\n}}", "/TEST.java:2: incompatible types: int cannot be converted to boolean",12); } @Test public void testTypeArgs() { helpTC(" class A { int k; boolean b; <T> int mm() {} void m() { int t = this.<Integer>mm(); \n//@ assert <Object>\\old(k);\n}}" ,"/TEST.java:2: illegal start of expression",20 ); } @Test public void testOld1() { helpTC(" class A { int k; boolean b; void m() { \n//@ assert \\old;\n}}", "/TEST.java:2: A \\old expression must have an argument list",12); } @Test public void testOld2() { helpTC(" class A { int k; boolean b; void m() { \n//@ assert \\old();\n}}", "/TEST.java:2: A \\old expression expects just 1 or 2 argument, not 0",16); } @Test public void testOld2a() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\pre();\n}}", "/A.java:2: A \\pre expression expects just 1 argument, not 0",16); } @Test public void testOld3() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\old(k);\n}}", "/A.java:2: incompatible types: int cannot be converted to boolean",16); } @Test public void testOld4() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\old(b);\n}}"); } @Test public void testOld5() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\pre(b,k);\n}}", "/A.java:2: A \\pre expression expects just 1 argument, not 2",16 ,"/A.java:2: There is no label named k",19); } @Test public void testOld6() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\old(b,5);\n}}", "/A.java:2: The second argument of an \\old expression must be a simple identifier that is a label",19); } @Test public void testOld7() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\old(b,k);\n}}" ,"/A.java:2: There is no label named k",19); } @Test public void testOld8() { helpTCF("A.java"," class A { int k; boolean b; //@ requires \\old(b); \n void m() { }}", "/A.java:1: A \\old token with no label may not be present in a requires clause",48); } @Test public void testOld9() { helpTCF("A.java"," class A { int k; boolean b; //@ ensures \\old(b,k); \n void m() { }}", "/A.java:1: A \\old token with a label may not be present in a ensures clause",47); } @Test public void testOld10() { helpTCF("A.java"," class A { int k; boolean b; //@ requires \\pre(b); \n void m() { }}", "/A.java:1: A \\pre token may not be present in a requires clause",48); } @Test public void testOld11() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n k: k=1;\n //@ assert \\old(b,k);\n}}" ); } @Test public void testOld12() { helpTCF("A.java"," class A { boolean b; void m() { \n k: {};\n //@ assert \\old(b,k);\n}}" ); } @Test public void testMax() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\max(\\lockset);\n}}", "/A.java:2: incompatible types: java.lang.Object cannot be converted to boolean",16); } @Test public void testMax1() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\max;\n}}", "/A.java:2: illegal start of type",16); } @Test public void testMax2() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\max();\n}}", "/A.java:2: A \\max expression expects just 1 argument, not 0",16); } @Test public void testMax3() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\max(k);\n}}", "/A.java:2: A \\max function expects an argument of type org.jmlspecs.lang.JMLSetType<E> rather than int",17, "/A.java:2: incompatible types: java.lang.Object cannot be converted to boolean",16 ); } @Test public void testMax5() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\max(b,k);\n}}", "/A.java:2: A \\max expression expects just 1 argument, not 2",16, "/A.java:2: A \\max function expects an argument of type org.jmlspecs.lang.JMLSetType<E> rather than boolean",17, "/A.java:2: incompatible types: java.lang.Object cannot be converted to boolean",16); } @Test public void testInvariantFor1() { helpTCF("A.java","public class A { int k; Integer i; void m() { \n//@ assert \\invariant_for(i);\n}}" ); } @Test public void testInvariantFor2() { helpTCF("A.java","public class A { int k; Integer i; void m() { \n//@ assert \\invariant_for(k);\n}}" ,"/A.java:2: The argument of \\invariant_for must be of reference type", 27 ); } @Test public void testInvariantFor3() { helpTCF("A.java","public class A { int k; Integer i; void m() { \n//@ assert \\invariant_for(A);\n}}" ); } @Test public void testInvariantFor4() { helpTCF("A.java","public class A { int k; Integer i; void m() { \n//@ assert \\invariant_for();\n}}" ); } @Test public void testInvariantFor5() { helpTCF("A.java","public class A { int k; Integer i; void m() { \n//@ assert \\invariant_for(Integer,k);\n}}" ,"/A.java:2: The argument of \\invariant_for must be of reference type", 35 ); } @Test public void testInvariantFor6() { main.addOptions("-strictJML"); helpTCF("A.java","public class A { int k; Integer i; void m() { \n//@ assert \\invariant_for(Integer,k);\n}}" ,"/A.java:2: A \\invariant_for expression expects just 1 argument, not 2", 26 ,"/A.java:2: The argument of \\invariant_for must be of reference type", 27 ,"/A.java:2: The argument of \\invariant_for must be of reference type", 35 ); } @Test public void testInvariantFor6a() { helpTCF("A.java","public class A { int k; Integer i; void m() { \n//@ assert \\invariant_for(Integer,k);\n}}" ,"/A.java:2: The argument of \\invariant_for must be of reference type", 35 ); } @Test public void testInvariantFor7() { main.addOptions("-strictJML"); helpTCF("A.java","public class A { int k; Integer i; void m() { \n//@ assert \\invariant_for();\n}}" ,"/A.java:2: A \\invariant_for expression expects just 1 argument, not 0", 26 ); } @Test public void testType() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(A,k);\n}}" ,"/A.java:2: More than one argument or otherwise ill-formed type expression as argument of \\type",19 ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType2() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type();\n}}" ,"/A.java:2: illegal start of type",18 ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType3() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(b);\n}}" ,"/A.java:2: cannot find symbol\n symbol: class b\n location: class A",18 ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType4() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(true);\n}}" ,"/A.java:2: illegal start of type",18 ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType5() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(int);\n}}" ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType6() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(int[][]);\n}}" ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType7() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(Object);\n}}" ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType8() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(java.lang.Object);\n}}" ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType9() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(java.lang.Object[][]);\n}}" ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType10() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(A);\n}}" ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType11() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(void);\n}}" ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testType12() { helpTCF("A.java"," class A { int k; boolean b; void m() { \n//@ assert \\type(Void);\n}}" ,"/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",17 ); } @Test public void testTypeof() { helpTCF("A.java"," class A { int k; Boolean b; void m() { \n//@ assert \\typeof(b);\n}}", "/A.java:2: incompatible types: \\TYPE cannot be converted to boolean",19); } @Test public void testResult() { helpTC(" class A { int k; Boolean b; void m() { \n//@ assert \\result;\n}}" ,"/TEST.java:2: A \\result expression may not be used in the specification of a method that returns void",13 ,"/TEST.java:2: A \\result expression may not be in a assert clause",13 ); } @Test public void testResult3() { helpTCF("A.java"," public class A { int k; Boolean b;\n //@ ensures \\result;\n void m() { \n}}", "/A.java:2: A \\result expression may not be used in the specification of a method that returns void",15); } @Test public void testResult4() { helpTC(" class A { int k; Boolean b;\n //@ assert \\result;\n void m() { \n}}", "/TEST.java:2: The token assert is illegal or not implemented for a type or method clause (JmlParser.classOrInterfaceBodyDeclaration)",6); } @Test public void testResult2() { String s = " class A { int k; Boolean b;\n/*@ ensures \\result == 1; */\nboolean m() { \n return true;\n}}"; helpTCF("A.java",s, "/A.java:2: incomparable types: boolean and int",21); } @Test public void testResult5() { String s = " class A { int k; Boolean b;\n/*@ ensures \\result == 1; */\n void m() { }}"; helpTCF("A.java",s, "/A.java:2: A \\result expression may not be used in the specification of a method that returns void",14); } /** Tests an input that gave bugs once before */ @Test public void testMisc1() { helpTC(" class A { /*@ ensures \\result ; */\nboolean m() { \n//@ return true;\n}}" ,"/TEST.java:3: Expected a declaration or a JML construct inside the JML annotation here", 5 ); } @Test public void testMisc1b() { helpTC(" class A { /*@ ensures \\result ; */\nboolean m() { \n//@ int t;\n}}" ,"/TEST.java:3: A local declaration within a JML annotation must be ghost", 9 // FIXME - better position ); } @Test public void testJmlTypes() { helpTCF("A.java","public class A { int i; /*@ ghost \\TYPE t; */ } "); //OK } @Test public void testJmlTypes0() { helpTCF("A.java","public class A { int i,j; /*@ ghost \\TYPE t,tt; */ } "); //OK } @Test public void testJmlTypes1() { helpTCF("A.java","public class A { /*@ ghost \\bigint i; model \\real r; ghost \\TYPE t; */ } "); //OK } /** Missing model or ghost modifier */ @Test public void testJmlTypes2() { helpTCF("A.java","public class A { int i; /*@ \\TYPE t; */ } ", "/A.java:1: A declaration within a JML annotation must be either ghost or model",37); } /** Wrong position model or ghost modifier */ @Test public void testJmlTypes3() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A { @Ghost int i; } ", "/A.java:1: A Java declaration (not within a JML annotation) may not be either ghost or model",64); } @Test public void testJmlTypes4() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A { /*@ @Ghost int i; */ } "); //OK } @Test public void testSubtype() { // OK helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */Class c;\n//@ensures t <: t;\nvoid m() {}}"); } @Test public void testSubtype2() { // OK helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */ Class c;\n//@ensures c <: c;\nvoid m() {}}"); } @Test public void testSubtype2a() { // OK helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */ Class<Object> c;\n//@ensures c <: c;\nvoid m() {}}"); } @Test public void testSubtype2b() { // OK helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */ Class<? extends Object> c;\n//@ensures c <: c;\nvoid m() {}}"); } @Test public void testSubtype3() { // OK expectedExit = 0; helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */ Class<Object> c;\n//@ensures t <: \\typeof(o);\nvoid m() {}}" ); } @Test public void testSubtype4() { // OK expectedExit = 0; helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */ Class<Object> c;\n//@ensures o.getClass() <: Object.class;\nvoid m() {}}" //,"/A.java:2: warning: A non-pure method is being called where it is not permitted: getClass()",22 ); } @Test public void testSubtype5() { helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */ Class<Object> c;\n//@ensures JML.erasure(t) <: c;\nvoid m() {}}"); } @Test public void testSubtype6() { helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */ Class<Object> c;\n//@ensures t <: 5;\nvoid m() {}}", "/A.java:2: The type of the arguments of the subtype operator (<:) must be either \\TYPE or java.lang.Class, not int",17); } @Test public void testSubtype7() { helpTCF("A.java","public class A { Object o; /*@ ghost \\TYPE t; */ Class<Object> c;\n//@ensures true <: c;\nvoid m() {}}", "/A.java:2: The type of the arguments of the subtype operator (<:) must be either \\TYPE or java.lang.Class, not boolean",12); } @Test public void testErasure1() { helpTCF("A.java","public class A { Object o; //@ ghost \\TYPE t = \\type(java.lang.Integer);\n}" ); } @Test public void testErasure2() { helpTCF("A.java","public class A { Object o; //@ ghost \\TYPE t = \\type(java.util.List);\n}" ,"/A.java:1: The argument of a \\type construct must be a fully parameterized type: java.util.List",53 ); } @Test public void testErasure3() { helpTCF("A.java","public class A { Object o; //@ ghost \\TYPE t = \\type(java.util.List<Integer>);\n}" ); } @Test public void testErasure4() { helpTCF("A.java","public class A { Object o; //@ ghost Class<?> t = \\erasure(\\type(java.lang.Integer));\n}" ); } @Test public void testErasure5() { helpTCF("A.java","public class A { Object o; //@ ghost Class<?> t = \\erasure(\\type(java.util.List));\n}" ); } @Test public void testErasure6() { helpTCF("A.java","public class A { Object o; //@ ghost Class<?> t = \\erasure(\\type(java.util.List<Integer>));\n}" ); } @Test public void testMisplacedResult() { helpTCF("A.java","public class A { \n//@requires \\result == 0;\n int m() {return 0;}}", "/A.java:2: A \\result expression may not be in a requires clause",14); } @Test public void testSetComp() { helpTCF("A.java","public class A { \n java.util.Collection c; //@ invariant new JMLSetType { Integer i | c.contains(i) && i<10}; \n \n }" //,"/A.java:2: warning: A non-pure method is being called where it is not permitted: contains(java.lang.Object)",79 // FIXME ,"/A.java:2: incompatible types: org.jmlspecs.lang.JMLSetType cannot be converted to boolean",55 ); } // Testing scopes in method specs @Test public void testSetCompA() { helpTCF("A.java","public class A { \n java.util.Collection c; //@ requires new JMLSetType { Integer i | c.contains(i) && i<10}; \n void m() {} \n }" //,"/A.java:2: warning: A non-pure method is being called where it is not permitted: contains(java.lang.Object)",78 // FIXME ,"/A.java:2: incompatible types: org.jmlspecs.lang.JMLSetType cannot be converted to boolean",54 ); } @Test public void testQuantifierA() { helpTCF("A.java","public class A { \n Object i; //@ ghost Object j; \n //@ requires m( (\\exists int i; 0 < i && i <10; m(i)) ); \n/*@pure*/boolean m(int k) { return false; }\n }", "/A.java:3: incompatible types: boolean cannot be converted to int",18); } @Test public void testSetCompB() { helpTCF("A.java","public class A { \n java.util.Collection c; //@ ghost int k = new JMLSetType { Integer i | c.contains(i) && i<10}; \n void m() {} \n }" ,"/A.java:2: incompatible types: org.jmlspecs.lang.JMLSetType cannot be converted to int",59 ); } @Test public void testSetCompB3() { helpTCF("A.java","public class A { boolean p; \n java.util.Collection c; //@ ghost Object k = new JMLSetType { Integer i | c.contains(i) && p<10}; \n void m() {} \n }" ,"/A.java:2: bad operand types for binary operator '<'\n first type: boolean\n second type: int",94 ); } @Test public void testSetCompB2() { helpTCF("A.java","public class A { \n java.util.Collection c; //@ ghost Object k = new JMLSetType { Integer i | c.contains(i) && i<10}; \n void m() {} \n }" ); } @Test public void testQuantifierB() { helpTCF("A.java","public class A { \n //@ ghost Object j = m( (\\exists int i; 0 < i && i <10; m(i)) ); \nboolean m(int k) { return false; }\n }", "/A.java:2: incompatible types: boolean cannot be converted to int",27); } @Test public void testQuantifierB2() { helpTCF("A.java","public class A { \n //@ ghost Object j = m( (\\exists int i; 0 < i && i <10; m(i)) ); \nboolean m(boolean k) { return false; } boolean m(int p) { return false; }\n }" ); } @Test public void testQuantifierB3() { helpTCF("A.java","public class A { \n //@ ghost Object j = m( (\\exists int i; 0 < i && i <10; m(i)) ); \nboolean m(boolean k) { return false; } \n }" ,"/A.java:2: incompatible types: int cannot be converted to boolean",61 ); } // Looking for a name in the outer scope @Test public void testQuantifierB4() { helpTCF("A.java","public class A { boolean p; \n //@ ghost boolean j = ( (\\exists int i; 0 < i && i <10; m(p)) ); \nboolean m(int k) { return false; } \n }" ,"/A.java:2: incompatible types: boolean cannot be converted to int",61 ); } // testing scopes in local initializers @Test public void testSetCompC() { helpTCF("A.java","public class A { \n java.util.Collection c; void m() { //@ ghost int k = new JMLSetType { Integer i | c.contains(i) && i<10}; \n} \n }" ,"/A.java:2: incompatible types: org.jmlspecs.lang.JMLSetType cannot be converted to int",71 ); } @Test public void testSetCompC3() { helpTCF("A.java","public class A { \n java.util.Collection c; void m() { boolean p; //@ ghost Object k = new JMLSetType { Integer i | c.contains(i) && p<10}; \n} \n }" ,"/A.java:2: bad operand types for binary operator '<'\n first type: boolean\n second type: int",117 ); } @Test public void testSetCompC2() { helpTCF("A.java","public class A { \n java.util.Collection c; void m() { //@ ghost Object k = new JMLSetType { Integer i | c.contains(i) && i<10}; \n} \n }" ); } @Test public void testQuantifierC() { helpTCF("A.java","public class A { \n boolean m(int k) { //@ ghost Object j = m( (\\exists int i; 0 < i && i <10; m(i)) ); \n return false; }\n }", "/A.java:2: incompatible types: boolean cannot be converted to int",46 ); } @Test public void testQuantifierC2() { helpTCF("A.java","public class A { \n boolean m(int k) { //@ ghost boolean j = ( (\\exists int i; 0 < i && i <10; m(i)) ); \n return false; }\n }" ); } @Test public void testQuantifierC3() { helpTCF("A.java","public class A { \n boolean m(int k) { boolean p ; //@ ghost boolean j = ( (\\exists int i; 0 < i && i <10; m(p)) ); \n return false; }\n }", "/A.java:2: incompatible types: boolean cannot be converted to int",92 ); } // testing scopes in JML statements @Test public void testSetCompD() { helpTCF("A.java","public class A {//@ ghost Object k; \n java.util.Collection c; void m() { //@ set k = new JMLSetType { Integer i | c.contains(i) && i<10}; \n} \n }" ); } @Test public void testQuantifierD() { helpTCF("A.java","public class A { //@ ghost int j;\n \n boolean m(int k) { //@ set j = m( (\\exists int i; 0 < i && i <10; m(i)) ); \n return false; }\n }", "/A.java:3: incompatible types: boolean cannot be converted to int",37); } @Test public void testQuantifier() { helpTCF("A.java","public class A { \n Object i; //@ ghost Object j; \n /*@pure*/ boolean m(int i) { return false; }\n//@ invariant m( (\\exists int i; 0 < i && i <10; m(i)) ); \n }", "/A.java:4: incompatible types: boolean cannot be converted to int",18); } @Test public void testQuantifier1() { helpTCF("A.java","public class A { \n Object i; //@ ghost Object j; \n /*@pure*/ boolean m(int i) { return false; }\n//@ invariant m( (\\forall int i; 0 < i && i <10; m(i)) ); \n }", "/A.java:4: incompatible types: boolean cannot be converted to int",18); } @Test public void testQuantifier2() { helpTCF("A.java","public class A { \n Object i; //@ ghost Object j; \n /*@pure*/ boolean m(int i) { return false; }\n//@ invariant (\\num_of int i; 0 < i && i <10; m(i)) ; \n }", "/A.java:4: incompatible types: int cannot be converted to boolean",16); } @Test public void testQuantifier3() { helpTCF("A.java","public class A { \n Object i; //@ ghost Object j; \n boolean m(int i) { return false; }\n//@ invariant (\\max long i; 0 < i && i <10; i) ; \n }", "/A.java:4: incompatible types: long cannot be converted to boolean",16); } @Test public void testQuantifier4() { helpTCF("A.java","public class A { \n Object i; //@ ghost Object j; \n boolean m(float i) { return false; }\n//@ invariant (\\sum long i; 0 < i && i <10; i) ; \n }", "/A.java:4: incompatible types: long cannot be converted to boolean",16); } @Test public void testQuantifier5() { helpTCF("A.java","public class A { \n Object i; //@ ghost Object j; \n boolean m(double i) { return false; }\n//@ invariant (\\product long i,k; 0 < i && k <10; i) ; \n }", "/A.java:4: incompatible types: long cannot be converted to boolean",16); } @Test public void testQuantifier6() { helpTCF("A.java","public class A { \n Object i; Object q = i; //@ ghost Object j; \n boolean m(double i) { return false; }\n//@ invariant (\\product long i; j; i) ; \n }", "/A.java:4: incompatible types: java.lang.Object cannot be converted to boolean",33, "/A.java:4: incompatible types: long cannot be converted to boolean",16); } @Test public void testQuantifier7() { helpTCF("A.java","public class A { \n Object i; Object j; \n boolean m(double i) { return false; }\n//@ invariant (\\product long i; 0 < j && i <10; i) ; \n }", "/A.java:4: bad operand types for binary operator '<'\n first type: int\n second type: java.lang.Object",35, "/A.java:4: incompatible types: long cannot be converted to boolean",16); } @Test public void testQuantifierInv() { helpTCF("A.java","public class A { \n //@ invariant (\\exists int i; 0 < i && i <10; i > -1) ; \n //@ static invariant (\\exists int i; 0 < i && i <10; i > -1) ; \n void m() {}}" ); } @Test public void testQuantifierInv1() { helpTCF("A.java","public class A { int m; static int s; \n //@ invariant (\\exists int i; 0 < i && i <10; i > m) ; \n //@ static invariant (\\exists int i; 0 < i && i <10; i > m) ; \n void m() {}}" ,"/A.java:3: non-static variable m cannot be referenced from a static context",60 ); } @Test public void testQuantifierInv2() { helpTCF("A.java","public class A { int m; static int s; \n //@ static invariant (\\exists int i; 0 < i && i <10; i > s) ; \n //@ static invariant (\\exists int i; 0 < i && i <10; i > s) ; \n void m() {}}" ); } @Test public void testQuantifierInit() { helpTCF("A.java","public class A { int m; static int s; \n //@ ghost boolean b = (\\exists int i; 0 < i && i <10; i > m) ; \n //@ static ghost boolean bb = (\\exists int i; 0 < i && i <10; i > m) ; \n //@ requires b && bb;\n void m() {}}" ,"/A.java:3: non-static variable m cannot be referenced from a static context",69 ); } @Test public void testQuantifierInit1() { helpTCF("A.java","public class A { int m; static int s; \n //@ ghost boolean b = (\\exists int i; 0 < i && i <10; i > s) ; \n //@ static ghost boolean bb = (\\exists int i; 0 < i && i <10; i > s) ; \n //@ requires b && bb;\n void m() {}}" ); } @Test public void testQuantifierReq() { helpTCF("A.java","public class A { \n //@ requires (\\exists int i; 0 < i && i <10; i > -1) ; \n void m() {}}" ); } @Test public void testQuantifierReq2() { helpTCF("A.java","public class A { \n //@ requires (\\exists int i; 0 < i && i <10; i > -1) ; \n static void m() {}}" ); } @Test public void testLet() { helpTCF("A.java","public class A { void m() { //@ assert (\\let int i = 0; i != 0); \n}}" ); } @Test public void testLet2() { helpTCF("A.java","public class A { void m() { //@ assert 0 == (\\let int i = 0, int j = 2; i - j); \n}}" ); } @Test public void testLet3() { helpTCF("A.java","public class A { void m() { //@ assert (\\let int i = 0; i); \n}}" ,"/A.java:1: incompatible types: int cannot be converted to boolean",41); } @Test public void testLet4() { helpTCF("A.java","public class A { void m() { //@ assert (\\let int i; i==0); \n}}" ,"/A.java:1: = expected",51); } @Test public void testLet5() { helpTCF("A.java","public class A { void m() { boolean i; //@ assert (\\let int i=0; i==0); \n i = true; }}" ,"/A.java:1: variable i is already defined in method m()",61 ); } @Test public void testLet6() { helpTCF("A.java","public class A { void m(boolean i) { //@ assert (\\let int i=0; i==0); \n i = true; }}" ,"/A.java:1: variable i is already defined in method m(boolean)",60 ); } @Test public void testLet7() { helpTCF("A.java","public class A { boolean i; //@ invariant (\\let int i=0; i==0); \n }" ); } @Test public void testLet8() { helpTCF("A.java","public class A { void m(int j) { //@ assert (\\let int i=0; i==j); \n }}" ); } @Test public void testLet9() { helpTCF("A.java","public class A { int j; //@ invariant (\\let int i=0; i==j); \n }" ); } @Test public void testLet10() { helpTCF("A.java","public class A { void m(boolean j) { //@ assert (\\let int i=0; i==j); \n }}" ,"/A.java:1: incomparable types: int and boolean",66); } @Test public void testLet11() { helpTCF("A.java","public class A { boolean j; //@ invariant (\\let int i=0; i==j); \n }" ,"/A.java:1: incomparable types: int and boolean",59); } @Test public void testSame() { helpTCF("A.java","public class A { //@ requires i; also requires \\same; \n boolean m(boolean i) { return false; }\n}" ); } @Test public void testSame1() { helpTCF("A.java","public class A { //@ requires 1+\\same; \n boolean m(double i) { return false; }\n}", "/A.java:1: bad operand types for binary operator '+'\n first type: int\n second type: boolean",32); } @Test public void testSame2() { // FIXME - should not allow \same inside expressions helpTCF("A.java","public class A { //@ requires i; also requires !\\same; \n boolean m(boolean i) { return false; }\n}" ); } @Test public void testSame3() { // FIXME - should not allow \same without previous preconditions helpTCF("A.java","public class A { //@ requires \\same; \n boolean m(double i) { return false; }\n}" ); } @Test public void testSame4() { helpTCF("A.java","public class A { //@ ensures \\same; \n boolean m(double i) { return false; }\n}" ,"/A.java:1: A \\same token may only be used in requires clauses",30 ); } // @Test public void testLockCompare() { // expectedExit = 0; // helpTCF("A.java","public class A { Object o,oo; //@ invariant o < oo; \n }" // ,"/A.java:1: warning: Operators < and <= are deprecated as lock comparisons - use <# and <#= instead",47 // ); // } @Test public void testLockCompareX() { helpTCF("A.java","public class A { Integer o,oo; //@ invariant o < oo; \n }" ); } // @Test public void testLockCompare1() { // expectedExit = 0; // helpTCF("A.java","public class A { Object o,oo; //@ invariant o <= oo; \n }" // ,"/A.java:1: warning: Operators < and <= are deprecated as lock comparisons - use <# and <#= instead",47 // ); // } @Test public void testLockCompare1X() { helpTCF("A.java","public class A { Integer o,oo; //@ invariant o <= oo; \n }" ); } @Test public void testLockCompare2() { helpTCF("A.java","public class A { Object o,oo; int i; //@ invariant o < true; \n }" ,"/A.java:1: bad operand types for binary operator '<'\n first type: java.lang.Object\n second type: boolean",54 ); } @Test public void testLockCompare2X() { helpTCF("A.java","public class A { Integer o,oo; int i; //@ invariant o < 5; \n }" ); } @Test public void testLockCompare2Y() { helpTCF("A.java","public class A { Object o,oo; int i; //@ invariant o < 5; \n }" ,"/A.java:1: bad operand types for binary operator '<'\n first type: java.lang.Object\n second type: int",54 ); } @Test public void testLockCompare3() { helpTCF("A.java","public class A { Object o,oo; boolean b = o <= oo; \n }" ,"/A.java:1: bad operand types for binary operator '<='\n first type: java.lang.Object\n second type: java.lang.Object",45 ); } @Test public void testLockCompare4() { helpTCF("A.java","public class A { Object o,oo; boolean b = o <= oo; \n }" ,"/A.java:1: bad operand types for binary operator '<='\n first type: java.lang.Object\n second type: java.lang.Object",45 ); } @Test public void testLockCompareA() { helpTCF("A.java","public class A { Object o,oo; //@ invariant o <# oo; \n }" ); } @Test public void testLockCompare1A() { helpTCF("A.java","public class A { Object o,oo; //@ invariant o <#= oo; \n }" ); } @Test public void testFreshBad() { helpTCF("A.java","public class A { Object o,oo; //@ invariant \\fresh(o); \n }" ,"/A.java:1: A \\fresh expression may not be in a invariant clause",52 ); } @Test public void testFreshWeirdError() { helpTCF("WeirdError.java", "public class WeirdError {\n" + " public Foo getFoo() { return null; }\n" + "}\n" ,"/WeirdError.java:2: cannot find symbol\n symbol: class Foo\n location: class WeirdError",9 // ,"/WeirdError.java:2: A \\result expression may not be used in the specification of a method that returns void",14 ); } @Test public void testFresh() { helpTCF("A.java","public class A { Object o,oo; //@ ensures \\fresh(o); \n void m() {} \n }" ); } @Test public void testFresh2() { helpTCF("A.java","public class A { Object o,oo; //@ ensures \\fresh(o,oo); \n void m() {} \n }" ); } @Test public void testFresh3() { helpTCF("A.java","public class A { Object o,oo; //@ ensures \\fresh(); \n void m() {} \n }" ); } @Test public void testFresh4() { helpTCF("A.java","public class A { int i; Object o,oo; //@ ensures \\fresh(i); \n void m() {} \n }" ,"/A.java:1: The argument of \\fresh must be of reference type",59 ); } @Test public void testFresh5() { helpTCF("A.java","public class A { int i; Object o,oo; //@ ensures \\fresh(o) + 1 == 0; \n void m() {} \n }" ,"/A.java:1: bad operand types for binary operator '+'\n first type: boolean\n second type: int",62 ); } @Test public void testFresh5Bad() { helpTCF("A.java","public class A { int i; Object o,oo; //@ ghost boolean k = \\fresh(o); \n }" ,"/A.java:1: A \\fresh expression may not be in a jml declaration clause",67 ); } @Test public void testOnlyAssigned() { helpTCF("A.java","public class A { Object o,oo; //@ invariant \\only_assigned(o) || \\only_accessed(o) || \\only_captured(o) || \\not_assigned(o) || \\not_modified(o); \n }" ,"/A.java:1: A \\only_assigned expression may not be in a invariant clause",46 ,"/A.java:1: A \\only_accessed expression may not be in a invariant clause",67 ,"/A.java:1: A \\only_captured expression may not be in a invariant clause",88 ,"/A.java:1: A \\not_assigned expression may not be in a invariant clause",109 ,"/A.java:1: A \\not_modified expression may not be in a invariant clause",129 ); } @Test public void testOnlyAssigned1() { helpTCF("A.java","public class A { Object o,oo; //@ ensures \\only_assigned(o) || \\only_accessed(o) || \\only_captured(o) || \\not_assigned(o) || \\not_modified(o); \n void m() {} \n }" ); } @Test public void testOnlyAssigned2() { helpTCF("A.java","public class A { int i; Object o,oo; //@ ghost boolean k = \\only_assigned(o) || \\only_accessed(o) || \\only_captured(o) || \\not_assigned(o) || \\not_modified(o); \n }" ,"/A.java:1: A \\only_assigned expression may not be in a jml declaration clause",61 ,"/A.java:1: A \\only_accessed expression may not be in a jml declaration clause",82 ,"/A.java:1: A \\only_captured expression may not be in a jml declaration clause",103 ,"/A.java:1: A \\not_assigned expression may not be in a jml declaration clause",124 ,"/A.java:1: A \\not_modified expression may not be in a jml declaration clause",144 ); } @Test public void testInformalComment() { helpTCF("A.java","public class A {\n //@ invariant (* stuff *);\n //@ ghost int k = (* stuff *); \n }" ,"/A.java:3: incompatible types: boolean cannot be converted to int",20 ); } @Test public void testId() { helpTCF("A.java","public class A {\n //@ public model int duration; \n }" ,"/A.java:2: Expected an identifier, found a JML keyword instead: duration",23 ); } // The following are situations that are not yet handled properly. // That is because model imports are treated just like normal imports, // so they can lead to incorrect name resolution in the Java code. // No errors but should have one: the use of List in the declaration of n should fail. @Test public void testModelImport1() { helpTCF("A.java","//@ model import java.util.List;\n public class A {\n //@ ghost List k;\n List n; \n }" ); } // This should fail for the ghost declaration but not for the Java declaration @Test public void testModelImport2() { helpTCF("A.java","import java.awt.*; //@ model import java.util.*;\n public class A {\n //@ ghost List k;\n List n; \n }" ,"/A.java:3: reference to List is ambiguous\n both interface java.util.List in java.util and class java.awt.List in java.awt match",12 ,"/A.java:4: reference to List is ambiguous\n both interface java.util.List in java.util and class java.awt.List in java.awt match",2 ); } // This should fail for the Java declaration but not for the ghost declaration @Test public void testModelImport3() { helpTCF("A.java","import java.awt.*; import java.util.*;\n//@ model import java.util.List;\n public class A {\n //@ ghost List k;\n List n; \n }" ); } @Test public void testOKImport1() { helpTCF("A.java","import java.util.*;\n public class A {\n List n; \n }" ); } @Test public void testBadModelImport1() { helpTCF("A.java","//@ import java.util.List;\n public class A {\n //@ ghost List k;\n List n; \n }" ,"/A.java:1: An import statement in a JML comment must have a model modifier",5 ); } @Test public void testBadModelImport2() { helpTCF("A.java","/*@ model */ import java.util.List;\n public class A {\n \n }" ,"/A.java:1: A model import declaration must be completely within a JML comment",14,13,13,34 ); } @Test public void testBadModelImport2a() { helpTCF("A.java","/*@ model */ public class A {\n \n }" ,"/A.java:1: A Java declaration (not within a JML annotation) may not be either ghost or model",22 ); } @Test public void testBadModelImport3() { // FIXME - could be a better error message helpTCF("A.java","/*@ model import */ java.util.List;\n public class A {\n \n }" ,"/A.java:1: Expected an identifier, found a JML keyword instead: <JMLEND>",18 ,"/A.java:1: '.' expected",20 ,"/A.java:1: package <error>.java.util does not exist",30 ,"/A.java:1: package <error>.java.util does not exist",30 ); } // Bug: 3366092 @Test public void testEnum1() { helpTCF("A.java","public class A {\n enum E { X {} }; \n }" ); } // Bug: 3366092 @Test public void testEnum2() { helpTCF("A.java","public class A {\n enum E { X {}; } \n }" ); } // Bug: 3241186 @Test public void testEnum3() { helpTCF("A.java","public class A {\n public enum X { Y; X(){}; } \n }" ); } // Bug: 3241186 @Test public void testEnum3a() { helpTCF("A.java","public class A {\n public enum X { Y; public X(){}; } \n }" ,"/A.java:2: modifier public not allowed here",29 ); } // Bug: 3241186 @Test public void testEnum3b() { helpTCF("A.java","public class A {\n public enum X { Y; protected X(){}; } \n }" ,"/A.java:2: modifier protected not allowed here",32 ); } // Bug: 3241186 @Test public void testEnum3c() { helpTCF("A.java","public class A {\n public enum X { Y; private X(){}; } \n }" ); } // Bug: 3421143 @Test public void testEnum4() { helpTCF("A.java","public class A {\n public enum X { Y; public X m() { for (X c: values()) break; return Y; } } \n }" ); } // Bug: 3373400 @Test public void testBug4() { helpTCF("A.java","interface A<V> { /*@ instance ghost V r; @*/ \n }" ); } // Bug: 3377329 @Test public void testBug5() { helpTCF("A.java","public class A {\n" +" public void test1(Object[] blub) {\n" +" //@ loop_invariant 0<=i && i <= blub.length;\n" +" for(int i=0; i< blub.length; i++) {\n" +" /*@nullable @*/ Object b = blub[i];\n" +" if (b == null)\n" +" continue;\n" +" }\n" +" }\n" +" public void test2(Object[] blub) {\n" +" for(Object b : blub) {\n" +" if (b == null)\n" +" continue;\n" +" }\n" +" }\n" +"}" ); } // Bug: 3377329 @Test public void testBug5a() { helpTCF("A.java","public class A {\n" +" public void test1(Object[] blub) {\n" +" //@ loop_invariant 0<=i && i <= blub.length;\n" +" for(int i=0; i< blub.length; i++) {\n" +" /*@nullable @*/ Object b = blub[i];\n" +" if (b == null)\n" +" break;\n" +" }\n" +" }\n" +" public void test2(Object[] blub) {\n" +" for(Object b : blub) {\n" +" if (b == null)\n" +" break;\n" +" }\n" +" }\n" +"}" ); } // Bug: 3388690 @Test public void testBug6() { helpTCF("Test.java","public class Test {\n" +"private final int my_height; /*@ in height; @*/\n" +" /*@ public model int height;\n" +" in_redundantly height;\n" +" public invariant 0 < height;\n" +" public constraint \\old(height) == height;\n" +" private represents height = my_height;\n" +" private invariant 0 < my_height;\n" +" @*/\n" +" public Test() {\n" +" my_height = 1;\n" +" }\n" +"}\n" ); } @Test public void testBug6a() { helpTCF("Test.java","public class Test {\n" +"private final int my_height; /*@ in height; @*/\n" +" /*@ public model int height;\n" +" in_redundantly height2;\n" +" @*/\n" +" /*@ public model int height2;\n" +" in_redundantly height;\n" +" @*/\n" +" public Test() {\n" +" my_height = 1;\n" +" }\n" +"}\n" ,"/Test.java:2: This field participates in a circular datagroup inclusion chain: my_height",19 ,"/Test.java:3: This field participates in a circular datagroup inclusion chain: height",24 ,"/Test.java:6: This field participates in a circular datagroup inclusion chain: height2",24 ); } @Test public void typeserr() { helpTCF("A.java", "class A { //@ ghost boolean b4 = \\type(java.util.Map<java.util.List<?>,?>) <: \\type(java.util.List<?>);\n}" ,"/A.java:1: Wildcards are not allowed within \\type expressions: java.util.Map<java.util.List<?>, ?>",69 ,"/A.java:1: Wildcards are not allowed within \\type expressions: java.util.Map<java.util.List<?>, ?>",72 ,"/A.java:1: Wildcards are not allowed within \\type expressions: java.util.List<?>",100 ); } @Test public void testSwitchWithStrings() { helpTCF("A.java"," class A { public void m(String s) { switch (s) { case \"David\": case \"Cok\": System.out.println(\"me\"); break; default: System.out.println(\"not me\"); } } }" ); } // FIXME - does not appear to be working yet // @Test public void testDiamondGenerics() { // helpTCF("A.java","public class A { java.util.List<Integer> list = new java.util.LinkedList<>(); } }" // ); // } @Test public void testMultiCatch() { helpTCF("A.java","public class A { public void m(int i) { try { if (i == 0) throw new ArrayIndexOutOfBoundsException(); if (i == 1) throw new NullPointerException(); } catch ( final ArrayIndexOutOfBoundsException | NullPointerException e) {} } }" ); } @Test public void testTryWithResources() { helpTCF("A.java","import java.io.*; public class A { public void m(int i) { try ( FileReader r = new FileReader(\"\") ) { } catch (final IOException e) {} finally {} } }" ); } @Test public void testJmlLabelExpression() { helpTCF("TestJava.java","package tt; \n" +"public class TestJava { \n" +" public int m1bad(boolean b, int k) {\n" +" int j = 0;\n" +" //@ ghost boolean bb = (\\forall int i; 0<=i && i <=4; 0!=(\\lbl LBL i));\n" +" return 1;\n" +" }\n" +"}" ,"/TestJava.java:5: A JML label expression may not be within a quantified or set-comprehension expression",63 ); } @Test public void testSpecCaseVisibility() { expectedExit = 0; // Only warnings helpTCF("TestJava.java","package tt; \n" +"public class TestJava { \n" +" //@ public behavior requires true;\n" +" public void m1p() {\n" +" }\n" +" //@ protected behavior requires true;\n" +" public void m1r() {\n" +" }\n" +" //@ behavior requires true;\n" +" public void m1k() {\n" +" }\n" +" //@ private behavior requires true;\n" +" public void m1v() {\n" +" }\n" +" //@ requires true;\n" +" public void m1() {\n" +" }\n" +" //@ public behavior requires true;\n" // Warning +" protected void m2p() {\n" +" }\n" +" //@ protected behavior requires true;\n" +" protected void m2r() {\n" +" }\n" +" //@ behavior requires true;\n" +" protected void m2k() {\n" +" }\n" +" //@ private behavior requires true;\n" +" protected void m2v() {\n" +" }\n" +" //@ requires true;\n" +" protected void m2() {\n" +" }\n" +" //@ public behavior requires true;\n" // Warning +" private void m3p() {\n" +" }\n" +" //@ protected behavior requires true;\n" // Warning +" private void m3r() {\n" +" }\n" +" //@ behavior requires true;\n" // Warning +" private void m3k() {\n" +" }\n" +" //@ private behavior requires true;\n" +" private void m3v() {\n" +" }\n" +" //@ requires true;\n" +" private void m3() {\n" +" }\n" +" //@ public behavior requires true;\n" // Warning +" void m4p() {\n" +" }\n" +" //@ protected behavior requires true;\n" // Warning +" void m4r() {\n" +" }\n" +" //@ behavior requires true;\n" +" void m4k() {\n" +" }\n" +" //@ private behavior requires true;\n" +" void m4v() {\n" +" }\n" +" //@ requires true;\n" +" void m4() {\n" +" }\n" +"}" ,"/TestJava.java:18: warning: There is no point to a specification case having more visibility than its method",7 ,"/TestJava.java:33: warning: There is no point to a specification case having more visibility than its method",7 ,"/TestJava.java:36: warning: There is no point to a specification case having more visibility than its method",7 ,"/TestJava.java:39: warning: There is no point to a specification case having more visibility than its method",7 ,"/TestJava.java:48: warning: There is no point to a specification case having more visibility than its method",7 ,"/TestJava.java:51: warning: There is no point to a specification case having more visibility than its method",7 ); } }