package org.jmlspecs.openjmltest.testcases; import org.jmlspecs.openjmltest.TCBase; import org.junit.*; public class modifiers extends TCBase { @Before public void setUp() throws Exception { //noCollectDiagnostics = true; //jmldebug = true; super.setUp(); } @Test public void testClassMods() { helpTCF("t/A.java","package t; \n /*@ pure */class A{}"); } @Test public void testClassMods2() { helpTCF("t/A.java","package t; \n /*@ non_null */class A{}", "/t/A.java:2: This JML modifier is not allowed for a type declaration", 6 ); } @Test public void testClassMods3() { helpTCF("t/A.java","package t; \n static class A{}", "/t/A.java:2: modifier static not allowed here", 10); } @Test public void testClassMods4() { String s = "public class A{}"; helpTCF("A.java",s); } @Test public void testClassMods5() { String s = "protected class A{}"; helpTCF("A.java",s, "/A.java:1: modifier protected not allowed here",11 ); } @Test public void testClassMods6() { helpTCF("t/A.java","package t; \n /*@ pure pure */class A{}", "/t/A.java:2: org.jmlspecs.annotation.Pure is not a repeatable annotation type", 11); } @Test public void testClassMods7() { helpTCF("t/A.java","package t; \n /*@ pure */public class A{}"); } @Test public void testClassMods8() { helpTCF("t/A.java","package t; \n public /*@ pure */class A{}"); } @Test public void testClassMods9() { helpTCF("t/A.java","package t; import org.jmlspecs.annotation.*; \n public /*@ pure */ @Pure class A{}", "/t/A.java:2: org.jmlspecs.annotation.Pure is not a repeatable annotation type", 21); } /** Testing annotations without the import */ @Test public void testClassMods10() { helpTCF("t/A.java","package t; \n public /*@ pure */ @Pure class A{}", "/t/A.java:2: cannot find symbol\n symbol: class Pure", 22 ); } @Test public void testClassMods11() { helpTCF("A.java"," \n public /*@ non_null */ class A{}", "/A.java:2: This JML modifier is not allowed for a type declaration", 13); } @Test public void testClassMods12() { helpTCF("A.java"," \n @Deprecated public class A{}" ); } @Test public void testClassMods13() { helpTCF("A.java"," \n //@ public model class A{}"); } @Test public void testClassMods13a() { helpTCF("A.java"," \n public /*@model*/ class A{}" ,"/A.java:2: A Java declaration (not within a JML annotation) may not be either ghost or model",20); } @Test public void testClassMods14() { helpTCF("A.java","public class A{} \n //@ ghost class B{}\n class C{}", "/A.java:2: This JML modifier is not allowed for a type declaration", 13 ,"/A.java:2: A method or type declaration within a JML annotation must be model",19 ); } @Test public void testClassMods14a() { helpTCF("A.java"," \n public /*@ghost*/ class A{}", "/A.java:2: This JML modifier is not allowed for a type declaration", 12); } @Test public void testClassMods14b() { helpTCF("A.java","import org.jmlspecs.annotation.*;\n //@ @Ghost class B{}\n public class A {}", "/A.java:2: This JML modifier is not allowed for a type declaration", 7 ,"/A.java:2: A method or type declaration within a JML annotation must be model",14 ); } @Test public void testOnlyModelClass() { helpTCF("A.java","public class A {}\n //@ public model class B{}\n\n", "/A.java:2: class B is public, should be declared in a file named B.java", 19); } @Test public void testOnlyModelClass1() { helpTCF("A.java","public class A {}\n //@ class B{}\n\n", "/A.java:2: A method or type declaration within a JML annotation must be model", 6); } @Test public void testOnlyModelClass2() { helpTCF("A.java","public class A {}\n public model class B{}", "/A.java:2: class, interface, or enum expected", 9); } @Test public void testOnlyModelClass3() { helpTCF("A.java","public class A {}\n //@ model class B{}\n\n" ); } // This and the following test check that JML comments at the very end of a file // are indeed processed. There had been a bug in the OpenJDK scanner that // ignored comments at the end of a file. @Test public void testOnlyModelClass4() { helpTCF("A.java","public class A {}\n //@ public model class B{}", "/A.java:2: class B is public, should be declared in a file named B.java", 19); } @Test public void testOnlyModelClass5() { helpTCF("A.java","public class A {}\n //@ public model class B{}\n", "/A.java:2: class B is public, should be declared in a file named B.java", 19); } @Test public void testClassMods14c() { // Don't need the runtime path, since the @Ghost annotation is looked up on the classpath, // but this makes the compiler look for specs for Ghost as a binary class, and exercises a different // code path specs.setSpecsPath(new String[]{"$A","$B","$SY","../OpenJML/runtime"}); helpTCF("A.java","import org.jmlspecs.annotation.*; \n public @Ghost class A{}", "/A.java:2: This JML modifier is not allowed for a type declaration", 9); } @Test public void testClassMods14d() { // Don't need the runtime path, since the @Ghost annotation is looked up on the classpath, // but this makes the compiler look for specs for Ghost as a binary class, and exercises a different // code path specs.setSpecsPath(new String[]{"$A","$B","$SY"}); helpTCF("A.java","import org.jmlspecs.annotation.*; \n public @Ghost class A{}", "/A.java:2: This JML modifier is not allowed for a type declaration", 9); } @Test public void testClassMods15() { specs.setSpecsPath(new String[]{"$A","$B","$SY","../OpenJML/runtime"}); helpTCF("A.java","import org.jmlspecs.annotation.*; \n public @NullableByDefault class A{}" ); } @Test public void testClassMods15a() { specs.setSpecsPath(new String[]{"$A","$B","$SY","../OpenJML/runtime"}); helpTCF("A.java","import org.jmlspecs.annotation.*; \n public @NonNullByDefault class A{}" ); } @Test public void testClassMods15b() { specs.setSpecsPath(new String[]{"$A","$B","$SY","../OpenJML/runtime"}); helpTCF("A.java","public /*@nullable_by_default*/ class A{}" ); } @Test public void testClassMods15c() { specs.setSpecsPath(new String[]{"$A","$B","$SY","../OpenJML/runtime"}); helpTCF("A.java","public /*@non_null_by_default*/ class A{}" ); } @Test public void testClassMods15d() { specs.setSpecsPath(new String[]{"$A","$B","$SY","../OpenJML/runtime"}); helpTCF("A.java","public /*@nullable_by_default non_null_by_default*/ class A{}" ,"/A.java:1: A declaration may not be both non_null_by_default and nullable_by_default",11 ); } @Test public void testClassMods15e() { specs.setSpecsPath(new String[]{"$A","$B","$SY","../OpenJML/runtime"}); helpTCF("A.java","import org.jmlspecs.annotation.*; \n public @NonNullByDefault @NullableByDefault class A{}" ,"/A.java:2: A declaration may not be both non_null_by_default and nullable_by_default",27 ); } @Test public void testCUMods() { helpTCF("t/A.java","@Pure package t; import org.jmlspecs.annotation.*; \n public /*@ pure */ @Pure class A{}", "/t/A.java:1: package annotations should be in file package-info.java",1, "/t/A.java:2: org.jmlspecs.annotation.Pure is not a repeatable annotation type", 21); } @Test public void testCUMods2() { helpTCF("t/A.java","/*@ pure */ package t; import org.jmlspecs.annotation.*; \n public /*@ pure */ @Pure class A{}" ,"/t/A.java:1: package annotations should be in file package-info.java", 5 ,"/t/A.java:2: org.jmlspecs.annotation.Pure is not a repeatable annotation type",21 ); } @Test public void testCUMods3() { helpTCF("t/A.java","package t; /*@ pure */ import org.jmlspecs.annotation.*; \n public /*@ pure */ @Pure class A{}" ,"/t/A.java:1: No modifiers are allowed on an import statement", 16 ,"/t/A.java:2: org.jmlspecs.annotation.Pure is not a repeatable annotation type",21 ); } @Test public void testCUMods4() { helpTCF("t/A.java","package t; @Pure import org.jmlspecs.annotation.*; \n public /*@ pure */ @Pure class A{}" ,"/t/A.java:1: No modifiers are allowed on an import statement", 12 ,"/t/A.java:2: org.jmlspecs.annotation.Pure is not a repeatable annotation type",21 ); } @Test public void testInterface1() { helpTCF("t/A.java","package t; \n interface I { /*@ instance model int i; */ } public class A implements I { /*@ represents i = 8; */ }" ); // OK no errors } @Test public void testInterface1a() { helpTCF("t/A.java","package t; \n interface I { /*@ model int i; */ } public class A implements I { /*@ represents i = 8; */ }" ,"/t/A.java:2: A represents clause and its associated model field must both be static or both not be static",74 ,"/t/A.java:2: A represents clause must be declared in the same class as the static model field it represents",74 ); } @Test public void testInterface1b() { helpTCF("t/A.java","package t; \n interface I { /*@ instance model int i; */ } public class A implements I { /*@ static represents i = 8; */ }" ,"/t/A.java:2: A represents clause and its associated model field must both be static or both not be static",89 ); } @Test public void testInterface1c() { helpTCF("t/A.java","package t; \n interface I { /*@ model int i; */ } public class A implements I { /*@ static represents i = 8; */ }" ,"/t/A.java:2: A represents clause must be declared in the same class as the static model field it represents",80 ); } // make sure ghost fields are not final by default; should be static by default @Test public void testInterface2() { helpTCF("t/A.java","package t; \n interface I { /*@ ghost int i; */ } public class A implements I { static void m() { /*@ set i = 8; */ }}" ); // OK - no errors } // make sure that instance works @Test public void testInterface3() { helpTCF("t/A.java","package t; \n interface I { /*@ instance ghost int i; */ } public class A implements I { static void m() { /*@ set i = 8; */ }}" ,"/t/A.java:2: non-static variable i cannot be referenced from a static context",103 ); } // cannot be model and final @Test public void testInterface4() { helpTCF("t/A.java","package t; \n interface I { /*@ final model int i; */ } public class A implements I { /*@ final model int j = 0;*/ }" // ,"/t/A.java:2: A declaration may not be both model and final",26 // ,"/t/A.java:2: A declaration may not be both model and final",84 ); } @Test public void testMatchClass() { addMockFile("$A/A.jml"," class A {}"); helpTCF("A.java","public class A{}", "/$A/A.jml:1: The type A in the specification matches a Java type A with different modifiers: public", 2); } @Test public void testMatchClass2() { addMockFile("$A/A.jml","public class A<T> {}"); helpTCF("A.java","public class A<T,U>{}", "/$A/A.jml:1: The type A in the specification matches a Java type A<T,U> with a different number of type arguments", 8); } @Test public void testMatchClass3() { // FIXME - this should fail - need to compare the type parameters addMockFile("$A/A.jml","public class A<T> {}"); helpTCF("A.java","public class A<T extends java.util.List>{}");//, // "/A.java:1: The type A in the specification matches a Java type A with different modifiers: public ", 2); } @Test public void testMatchField() { addMockFile("$A/A.jml","public class A { int k; }"); helpTCF("A.java","public class A{}", "/$A/A.jml:1: The field k is a Java field (neither ghost nor model) but does not match any fields in the corresponding Java class.", 22); } @Test public void testMatchField2() { addMockFile("$A/A.jml","public class A { /*@ ghost int k; */}"); helpTCF("A.java","public class A{}"); // OK } @Test public void testMatchField2a() { addMockFile("$A/A.jml","public class A { /*@ model int k; */}"); helpTCF("A.java","public class A{}"); // OK } @Test public void testMatchField3() { addMockFile("$A/A.jml","public class A { /*@ ghost int k; */}"); helpTCF("A.java","public class A{}"); // OK } /** Missing a ghost or model modifier */ @Test public void testMatchField3a() { addMockFile("$A/A.jml","public class A { /*@ int k; */}"); helpTCF("A.java","public class A{}", "/$A/A.jml:1: A declaration within a JML annotation must be either ghost or model", 26); } @Test public void testMatchField4() { addMockFile("$A/A.jml","public class A { int k=0; }"); helpTCF("A.java","public class A{ int k; }", "/$A/A.jml:1: Field initializers are not permitted in specification files (A.k)", 24); } @Test public void testMatchField5() { addMockFile("$A/A.jml","public class A { public int k; }"); helpTCF("A.java","public class A{ protected int k; }", "/$A/A.jml:1: The field k in the specification matches a Java field A.k with different modifiers: public protected", 29); } @Test public void testMatchField6() { addMockFile("$A/A.jml","public class A { boolean k; }"); helpTCF("A.java","public class A{ int k; }" ,"/$A/A.jml:1: The field k in the specification matches a Java field A.k but they have different types: boolean vs. int",18 ,"/A.java:1: Associated declaration: /$A/A.jml:1: ",21 ); } @Test public void testMatchField7() { addMockFile("$A/A.jml","public class A { String k; }"); helpTCF("A.java","public class A{ Object k; }", "/$A/A.jml:1: The field k in the specification matches a Java field A.k but they have different types: java.lang.String vs. java.lang.Object",18 ,"/A.java:1: Associated declaration: /$A/A.jml:1: ",24 ); } @Test public void testMatchField8() { addMockFile("$A/A.jml","public class A { Object k; }"); helpTCF("A.java","public class A{ java.lang.Object k; }"); // OK } @Test public void testMatchField9() { addMockFile("$A/A.jml","public class A { Class<String> k; }"); helpTCF("A.java","public class A{ Class<Object> k; }", "/$A/A.jml:1: The field k in the specification matches a Java field A.k but they have different types: java.lang.Class<java.lang.String> vs. java.lang.Class<java.lang.Object>", 23 ,"/A.java:1: Associated declaration: /$A/A.jml:1: ",31 ); } @Test public void testMatchMethod() { addMockFile("$A/A.jml","public class A { void m(int i); }"); helpTCF("A.java","public class A{ void m(boolean i) {} void m(int i) {} }"); } @Test public void testMatchMethod1() { addMockFile("$A/A.jml","public class A { void m(int i); }"); helpTCF("A.java","public class A{ void m(boolean i) {} void m(Object i) {} }", "/$A/A.jml:1: The method A.m(int) is a Java method (neither ghost nor model) but does not match any methods in the corresponding Java class.", 23); } @Test public void testMatchMethod2() { // Should be OK addMockFile("$A/A.jml","public class A { void m(Object i); }"); helpTCF("A.java","public class A{ void m(boolean i) {} void m(java.lang.Object i) {} }"); } @Test public void testMatchMethod3() { addMockFile("$A/A.jml","public class A { void m(int i, boolean j); }"); helpTCF("A.java","public class A{ void m(boolean i) {} void m(int i) {} }", "/$A/A.jml:1: The method A.m(int,boolean) is a Java method (neither ghost nor model) but does not match any methods in the corresponding Java class.", 23); } @Test public void testMatchMethod4() { addMockFile("$A/A.jml","public class A { public void m(int i); }"); helpTCF("A.java","public class A{ void m(boolean i) {} void m(int i) { } }", "/$A/A.jml:1: The method m in the specification matches a Java method m(int) with different modifiers: public", 30 ); } @Test public void testMatchMethod5() { addMockFile("$A/A.jml","public class A { public Object m(int i); }"); helpTCF("A.java","public class A{ void m(boolean i) {} private java.lang.Object m(int i) { return null; } }", "/$A/A.jml:1: The method m in the specification matches a Java method m(int) with different modifiers: public private", 32); } @Test public void testMatchMethod6() { addMockFile("$A/A.jml","public class A { public void m(int i); }"); helpTCF("A.java","public class A{ void m(boolean i) {} public String m(int i) { return null; } }", "/$A/A.jml:1: The return types of method A.m(int) are different in the specification and java files: void vs. java.lang.String",25); } @Test public void testMatchMethod7() { addMockFile("$A/A.jml","public class A { public void m(int j, Object k); }"); helpTCF("A.java","public class A{ void m(boolean i) {} public String m(int i, Object mm) { return null; } }", "/$A/A.jml:1: The return types of method A.m(int,java.lang.Object) are different in the specification and java files: void vs. java.lang.String",25, "/$A/A.jml:1: Parameter 0 of method A.m(int,java.lang.Object) has name i in the .java file but j in the specification (they should be the same)",36, "/$A/A.jml:1: Parameter 1 of method A.m(int,java.lang.Object) has name mm in the .java file but k in the specification (they should be the same)",46 ); } @Test public void testMatchMethod8() { addMockFile("$A/A.jml","public class A { public void m() {} }"); helpTCF("A.java","public class A{ void m(boolean i) {} public void m() { } }", "/$A/A.jml:1: The specification of the method A.m() must not have a body",34); } @Test public void testTopLevelClass() { helpTCF("A.java","/*@pure nullable_by_default*/ public class A{ }" ); } @Test public void testTopLevelClass2() { helpTCF("A.java","/*@helper ghost spec_public*/ public class A{ }" ,"/A.java:1: This JML modifier is not allowed for a type declaration",4 ,"/A.java:1: This JML modifier is not allowed for a type declaration",11 ,"/A.java:1: This JML modifier is not allowed for a type declaration",17 ,"/A.java:1: warning: There is no point to a declaration being both public and spec_public",17 ); } @Test public void testTopLevelInterface() { helpTCF("A.java","/*@pure nullable_by_default*/ public interface A{ }" ); } @Test public void testTopLevelInterface2() { helpTCF("A.java","/*@helper ghost spec_protected*/ public interface A{ }" ,"/A.java:1: This JML modifier is not allowed for a type declaration",4 ,"/A.java:1: This JML modifier is not allowed for a type declaration",11 ,"/A.java:1: This JML modifier is not allowed for a type declaration",17 ,"/A.java:1: warning: There is no point to a declaration being both public and spec_protected",17 ); } @Test public void testNestedClass() { helpTCF("A.java","public class A{ /*@pure spec_public*/ private class B {}}" ); } @Test public void testNestedClass2() { helpTCF("A.java","public class A{ /*@pure spec_protected*/ private class B {}}" ); } @Test public void testNestedClass3() { helpTCF("A.java","public class A{ /*@helper ghost */ public class B {}}" ,"/A.java:1: This JML modifier is not allowed for a nested type declaration",20 ,"/A.java:1: This JML modifier is not allowed for a nested type declaration",27 //,"/A.java:1: A Java declaration (not within a JML annotation) may not be either ghost or model",27 ); } // TODO - It seems this should be allowed, but check the JML definition @Test public void testNestedClass3a() { helpTCF("A.java","public class A{ /*@nullable_by_default*/ public class B {}}" ); } @Test public void testNestedClass4() { helpTCF("A.java","public class A{ /*@spec_public spec_protected*/ private class B {}}" ,"/A.java:1: A declaration may not be both spec_public and spec_protected",32 ); } @Test public void testNestedInterface() { helpTCF("A.java","public class A{ /*@pure spec_public*/ private interface B {}}" ); } @Test public void testNestedInterface2() { helpTCF("A.java","public class A{ /*@pure spec_protected*/ private interface B {}}" ); } @Test public void testNestedInterface3() { helpTCF("A.java","public class A{ /*@helper ghost */ public interface B {}}" ,"/A.java:1: This JML modifier is not allowed for a nested type declaration",20 ,"/A.java:1: This JML modifier is not allowed for a nested type declaration",27 //,"/A.java:1: A Java declaration (not within a JML annotation) may not be either ghost or model",27 ); } // TODO - It seems this should be allowed, but check the JML definition @Test public void testNestedInterface3a() { helpTCF("A.java","public class A{ /*@nullable_by_default*/ public interface B {}}" ); } @Test public void testNestedInterface4() { helpTCF("A.java","public class A{ /*@spec_public spec_protected*/ private interface B {}}" ,"/A.java:1: A declaration may not be both spec_public and spec_protected",32 ); } @Test public void testLocalClass() { helpTCF("A.java","public class A{ void m() {\n /* @ pure */ class C {}; } }" ); } @Test public void testLocalClass1() { helpTCF("A.java","public class A{ void m() {\n /*@ model */ class C {}; } }" ,"/A.java:2: A Java declaration (not within a JML annotation) may not be either ghost or model",16 ); } @Test public void testLocalClass2() { helpTCF("A.java","public class A{ void m() {\n /*@ model class C {}*/ } }" ); } @Test public void testLocalClass2a() { helpTCF("A.java","public class A{ void m() {\n /*@ class C {};*/ } }" ,"/A.java:2: A method or type declaration within a JML annotation must be model", 14 ); } @Test public void testLocalClass3() { helpTCF("A.java","public class A{ void m() {\n /*@ helper spec_public */ class C {}; } }" ,"/A.java:2: This JML modifier is not allowed for a local type declaration",6 ,"/A.java:2: This JML modifier is not allowed for a local type declaration",13 ); } @Test public void testLocalClass4() { helpTCF("A.java","public class A{ void m() {\n /*@ ghost class C {} */ } }" ,"/A.java:2: This JML modifier is not allowed for a local type declaration",6 ,"/A.java:2: A method or type declaration within a JML annotation must be model",13 ); } @Test public void testField() { helpTCF("A.java","public class A{ /*@spec_public spec_protected*/ Object o;}" ,"/A.java:1: A declaration may not be both spec_public and spec_protected",32 ); } @Test public void testField1() { helpTCF("A.java","public class A{ /*@non_null nullable*/ Object o;}" ,"/A.java:1: A declaration may not be both non_null and nullable",29 ); } @Test public void testField2() { helpTCF("A.java","public class A{ /*@spec_public non_null instance monitored*/ Object o;}" ); } @Test public void testField3() { helpTCF("A.java","public class A{ /*@spec_protected nullable instance monitored*/ Object o;}" ); } @Test public void testField4() { helpTCF("A.java","public class A{ /*@helper*/ Object o;}" ,"/A.java:1: This JML modifier is not allowed for a field declaration",20 ); } @Test public void testGhostField() { helpTCF("A.java","public class A{ /*@ghost Object o; */}" ); } @Test public void testGhostField1() { helpTCF("A.java","public class A{ /*@ghost non_null nullable Object o; */}" ,"/A.java:1: A declaration may not be both non_null and nullable",35 ); } @Test public void testGhostField2() { helpTCF("A.java","public class A{ /*@ghost non_null instance monitored Object o; */}" ); } @Test public void testGhostField3() { helpTCF("A.java","public class A{ /*@ghost nullable instance monitored Object o; */}" ); } @Test public void testGhostField4() { helpTCF("A.java","public class A{ /*@ghost helper spec_protected Object o;*/}" ,"/A.java:1: This JML modifier is not allowed for a ghost field declaration",26 ,"/A.java:1: This JML modifier is not allowed for a ghost field declaration",33 ); } @Test public void testGhostField5() { helpTCF("A.java","public class A{ /*@ghost helper spec_public Object o;*/}" ,"/A.java:1: This JML modifier is not allowed for a ghost field declaration",26 ,"/A.java:1: This JML modifier is not allowed for a ghost field declaration",33 ); } @Test public void testModelField() { helpTCF("A.java","public class A{ /*@model ghost Object o; */}" ,"/A.java:1: This JML modifier is not allowed for a ghost field declaration",20 ); } @Test public void testModelField1() { helpTCF("A.java","public class A{ /*@model non_null nullable Object o; */}" ,"/A.java:1: A declaration may not be both non_null and nullable",35 ); } @Test public void testModelField2() { helpTCF("A.java","public class A{ /*@model non_null instance Object o; */}" ); } @Test public void testModelField3() { helpTCF("A.java","public class A{ /*@model nullable instance Object o; */}" ); } @Test public void testModelField4() { helpTCF("A.java","public class A{ /*@model helper monitored spec_public Object o;*/}" ,"/A.java:1: This JML modifier is not allowed for a model field declaration",26 ,"/A.java:1: This JML modifier is not allowed for a model field declaration",33 ,"/A.java:1: This JML modifier is not allowed for a model field declaration",43 ); } @Test public void testModelField5() { helpTCF("A.java","public class A{ /*@model helper monitored spec_protected Object o;*/}" ,"/A.java:1: This JML modifier is not allowed for a model field declaration",26 ,"/A.java:1: This JML modifier is not allowed for a model field declaration",33 ,"/A.java:1: This JML modifier is not allowed for a model field declaration",43 ); } @Test public void testMethod() { helpTCF("A.java","public class A{ /*@ pure non_null spec_protected extract */ Object m(){ return null; } }" ); } @Test public void testMethod0() { helpTCF("A.java","public class A{ /*@ pure non_null helper private extract */ Object m(){ return null; } }" ); } @Test public void testInterfaceMethod() { helpTCF("A.java","public interface A{ /*@ pure non_null spec_protected extract */ Object m(); }" ,"/A.java:1: This JML modifier is not allowed for a interface method declaration",55 ); } @Test public void testMethod2() { helpTCF("A.java","public class A{ /*@ pure nullable spec_public */ void m(){} }" ); } @Test public void testMethod2a() { helpTCF("A.java","public class A{ /*@ pure nullable helper private */ void m(){} }" ); } @Test public void testMethod3() { helpTCF("A.java","public class A{ /*@ query */ void m(){} }" ); } @Test public void testMethod4() { helpTCF("A.java","public class A{ /*@ spec_public spec_protected */ void m(){} }" ,"/A.java:1: A declaration may not be both spec_public and spec_protected",33 ); } @Test public void testMethod5() { helpTCF("A.java","public class A{ /*@ non_null nullable */ void m(){} }" ,"/A.java:1: A declaration may not be both non_null and nullable",30 ); } @Test public void testConstructor() { helpTCF("A.java","public class A{ /*@ pure spec_protected extract */ A(){} }" ); } @Test public void testConstructor0() { helpTCF("A.java","public class A{ /*@ pure extract helper private */ A(){} }" ); } @Test public void testConstructor1() { helpTCF("A.java","public class A{ /*@ pure spec_public */ A(){} }" ); } @Test public void testConstructor1a() { helpTCF("A.java","public class A{ /*@ pure helper private */ A(){} }" ); } @Test public void testConstructor3() { helpTCF("A.java","public class A{ \n/*@ instance non_null nullable */ A(){} }" ,"/A.java:2: This JML modifier is not allowed for a constructor declaration",5 ,"/A.java:2: This JML modifier is not allowed for a constructor declaration",14 ,"/A.java:2: This JML modifier is not allowed for a constructor declaration",23 ); } @Test public void testConstructor4() { helpTCF("A.java","public class A{ \n/*@ spec_public spec_protected */ A(){} }" ,"/A.java:2: A declaration may not be both spec_public and spec_protected",17 ); } @Test public void testModelMethod() { helpTCF("A.java","public class A{ /*@ model pure non_null extract Object m(){ return null; } */ }" ); } @Test public void testModelMethod0() { helpTCF("A.java","public class A{ /*@ model pure non_null extract private helper Object m(){ return null; } */ }" ); } @Test public void testInterfaceModelMethod() { helpTCF("A.java","public interface A{ /*@ model pure non_null extract Object m(); */ }" ,"/A.java:1: This JML modifier is not allowed for a interface model method declaration",45 ); } @Test public void testModelMethod1() { helpTCF("A.java","public class A{ /*@ model pure nullable void m(){} */ }" ); } @Test public void testModelMethod1a() { helpTCF("A.java","public class A{ /*@ model pure nullable private helper void m(){} */ }" ); } @Test public void testModelMethod2() { helpTCF("A.java","public class A{ /*@ model instance spec_public spec_protected void m(){}*/ }" ,"/A.java:1: This JML modifier is not allowed for a model method declaration",27 ,"/A.java:1: This JML modifier is not allowed for a model method declaration",36 ,"/A.java:1: This JML modifier is not allowed for a model method declaration",48 ); } @Test public void testModelMethod3() { helpTCF("A.java","public class A{ /*@ model non_null nullable Object m(){}*/ }" ,"/A.java:1: A declaration may not be both non_null and nullable",36 ); } @Test public void testModelMethod4() { // helpTCF("A.java","public class A{ /*@ model non_null */ Object m(){ return null;} }" ,"/A.java:1: A Java declaration (not within a JML annotation) may not be either ghost or model",47 ); } @Test public void testModelConstructor() { helpTCF("A.java","public class A{ A(int i) {} \n/*@ model pure extract A(){} */ }" ); } @Test public void testModelConstructor0() { helpTCF("A.java","public class A{ A(int i) {} \n/*@ model pure private helper extract A(){} */ }" ); } @Test public void testModelConstructor1() { helpTCF("A.java","public class A{ /*@ model pure */ A(){} }" ,"/A.java:1: A Java declaration (not within a JML annotation) may not be either ghost or model",36 ); } @Test public void testModelConstructor1a() { helpTCF("A.java","public class A{ /*@ model pure private helper */ A(){} }" ,"/A.java:1: A Java declaration (not within a JML annotation) may not be either ghost or model",50 ); } @Test public void testModelConstructor2() { helpTCF("A.java","public class A{ A(int i) {} \n/*@ model instance non_null nullable spec_public spec_protected A(){} */ }" ,"/A.java:2: This JML modifier is not allowed for a model constructor declaration",11 ,"/A.java:2: This JML modifier is not allowed for a model constructor declaration",20 ,"/A.java:2: This JML modifier is not allowed for a model constructor declaration",29 ,"/A.java:2: This JML modifier is not allowed for a model constructor declaration",38 ,"/A.java:2: This JML modifier is not allowed for a model constructor declaration",50 ); } @Test public void testFormal() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m(\n/*@ non_null */ Object o, \n/*@ nullable */ Object oo, \n/*@ non_null nullable */ Object ooo, \n/*@ spec_public */ Object oooo) {} }" ,"/A.java:5: A declaration may not be both non_null and nullable",14 ,"/A.java:6: This JML modifier is not allowed for a formal parameter",5 ); } @Test public void testLocalVar() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ non_null uninitialized */ Object o;} }" ); } @Test public void testLocalVar1() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ nullable uninitialized */ Object o;} }" ); } @Test public void testLocalVar2() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ non_null ghost */ Object o;} }" ,"/A.java:3: A Java local variable declaration (not within a JML annotation) may not be ghost",31 ); } @Test public void testLocalVar3() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ non_null ghost Object o; */} }" ); } @Test public void testLocalVar4() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ non_null nullable Object o; */} }" ,"/A.java:3: A local declaration within a JML annotation must be ghost",31 ,"/A.java:3: A declaration may not be both non_null and nullable",15 ); } @Test public void testLocalVar5() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ non_null nullable */ Object o; } }" ,"/A.java:3: A declaration may not be both non_null and nullable",15 ); } @Test public void testLocalVar6() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ helper */ Object o; } }" ,"/A.java:3: This JML modifier is not allowed for a local variable declaration",6 ); } @Test public void testLocalVar7() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ helper ghost Object o; */} }" ,"/A.java:3: This JML modifier is not allowed for a local variable declaration",6 ); } @Test public void testLocalVar8() { helpTCF("A.java","public class A{ A(int i) {} \n" + " void m() {\n /*@ Object o; */} }" ,"/A.java:3: A local declaration within a JML annotation must be ghost",15 ); } @Test public void testSpec() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ public requires true;\n" + " void m() {} }" ,"/A.java:2: No modifiers are allowed prior to a lightweight specification case",14 ); } @Test public void testSpec2() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ pure requires true;\n" + " void m() {} }" ,"/A.java:2: No modifiers are allowed prior to a lightweight specification case",12 ); } @Test public void testSpec3() { expectedExit = 0; helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ code requires true;\n" + " void m() {} }" ,"/A.java:2: warning: This code token is misplaced - it must be just prior to a behavior or example token",7 ); } @Test public void testSpec4() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ public behavior requires true;\n" + " public void m() {} }" ); // OK } @Test public void testSpec5() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ pure behavior requires true;\n" + " public void m() {} }" ,"/A.java:2: This JML modifier is not allowed for a specification case",7 ); } @Test public void testSpec6() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ private code behavior requires true;\n" + " void m() {} }" ); // OK } @Test public void testSpec7() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ public also behavior requires true;\n" + " void m() {} }" ,"/A.java:2: No modifiers are allowed prior to a also token",7 ); } @Test public void testSpec8() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ pure also behavior requires true;\n" + " void m() {} }" ,"/A.java:2: No modifiers are allowed prior to a also token",7 ); } @Test public void testSpec9() { expectedExit = 0; helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ code also behavior requires true;\n" + " void m() {} }" ,"/A.java:2: warning: This code token is misplaced - it must be just prior to a behavior or example token",7 ); } @Test public void testSpec10() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ private public behavior requires true;\n" + " void m() {} }" ,"/A.java:2: illegal combination of modifiers: public and private",22 ); } @Test public void testSpec11() { helpTCF("A.java","public class A{ A(int i) {} \n" + " //@ private spec_protected public behavior requires true;\n" + " void m() {} }" ,"/A.java:2: illegal combination of modifiers: public and private", 37 ,"/A.java:2: This JML modifier is not allowed for a specification case",15 ); } // FIXME - do we allow normal JML keywords in these contexts? @Test public void testQuantified() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ A(int i) {} \n" + // " //@ invariant (\\exists nullable Object o; o == null); \n" + // " //@ invariant (\\exists non_null Object o; o == null); \n" + " //@ invariant (\\exists final Object o; o == null); \n" + " //@ invariant (\\exists \\readonly Object o; o == null); \n" + " //@ invariant (\\exists @Nullable Object o; o == null); \n" + " //@ invariant (\\exists @Pure Object o; o == null); \n" + " }" ,"/A.java:2: No Java modifiers are allowed in a quantified expression",26 ,"/A.java:5: This JML modifier is not allowed for a quantified expression",26 ); } @Test public void testSetComp() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ A(int i) {} \n" + // " //@ invariant null != new Object { nullable Integer i | i < 10 }; \n" + // " //@ invariant null != new Object { non_null Integer i | i < 10 }; \n" + " //@ invariant null != new Object { final Integer i | i < 10 }; \n" + " //@ invariant null != new Object { @Nullable Integer i | i < 10 };\n" + " //@ invariant null != new Object { @Pure Integer i | i < 10 };\n" + " //@ invariant null != new Object { \\readonly Integer i | i < 10 }; \n" + " }" ,"/A.java:2: No Java modifiers are allowed in a set comprehension expression",36 ,"/A.java:4: This JML modifier is not allowed for a set comprehension expression",38 ); } @Test public void testForall() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ A(int i) {} \n" + // " //@ forall nullable Object o1; \n" + // " //@ forall non_null Object o2; \n" + " //@ forall \\readonly Object o3; \n" + " //@ forall @Nullable Object o4; \n" + " //@ forall @Pure Object o6; \n" + " //@ forall final Object o5; \n" + " void m() {} }" ,"/A.java:4: This JML modifier is not allowed for a local variable declaration",14 ,"/A.java:5: No Java modifiers are allowed in a method specification declaration",7 ); } @Test public void testOld() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ A(int i) {} \n" + // " //@ old nullable Object o1 = null; \n" + // " //@ old non_null Object o2 = null; \n" + " //@ old \\readonly Object o3 = null; \n" + " //@ old @Nullable Object o4 = null; \n" + " //@ old @Pure Object o6 = null; \n" + " //@ old final Object o5 = null; \n" + " void m() {} }" ,"/A.java:4: This JML modifier is not allowed for a local variable declaration",11 ,"/A.java:5: No Java modifiers are allowed in a method specification declaration",7 ); } @Test public void testInvariant() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ A(int i) {} \n" + " //@ invariant true; \n" + " //@ public invariant true; \n" + " //@ pure invariant true; \n" + " //@ private invariant true; \n" + " //@ public private invariant true; \n" + " //@ non_null invariant true; \n" + " //@ spec_public invariant true; \n" + " void m() {} }" ,"/A.java:4: This JML modifier is not allowed for a invariant clause", 7 ,"/A.java:6: illegal combination of modifiers: public and private", 22 ,"/A.java:7: This JML modifier is not allowed for a invariant clause", 7 ,"/A.java:8: This JML modifier is not allowed for a invariant clause", 7 ); } @Test public void testInvariant2() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ int m() { return 0; } \n" + " //@ invariant (new A() { int m() { return 5; } }) != null; \n" + " void p() {} }" ); } @Test public void testConstraint() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ A(int i) {} \n" + " //@ constraint true; \n" + " //@ public constraint true; \n" + " //@ pure constraint true; \n" + " //@ private constraint true; \n" + " //@ public private constraint true; \n" + " //@ non_null constraint true; \n" + " //@ spec_public constraint true; \n" + " void m() {} }" ,"/A.java:4: This JML modifier is not allowed for a constraint clause", 7 ,"/A.java:6: illegal combination of modifiers: public and private", 22 ,"/A.java:7: This JML modifier is not allowed for a constraint clause", 7 ,"/A.java:8: This JML modifier is not allowed for a constraint clause", 7 ); } @Test public void testAxiom() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ A(int i) {} \n" + " //@ axiom true; \n" + " //@ public axiom true; \n" + " //@ pure axiom true; \n" + " //@ private axiom true; \n" + " //@ public private axiom true; \n" + " //@ non_null axiom true; \n" + " //@ spec_public axiom true; \n" + " void m() {} }" ,"/A.java:3: These modifiers are not allowed here: public", 14 ,"/A.java:4: This JML modifier is not allowed for a axiom clause", 7 ,"/A.java:5: These modifiers are not allowed here: private", 15 ,"/A.java:6: These modifiers are not allowed here: public private", 22 ,"/A.java:7: This JML modifier is not allowed for a axiom clause", 7 ,"/A.java:8: This JML modifier is not allowed for a axiom clause", 7 ); } @Test public void testInitially() { helpTCF("A.java","import org.jmlspecs.annotation.*; public class A{ A(int i) {} \n" + " //@ initially true; \n" + " //@ public initially true; \n" + " //@ pure initially true; \n" + " //@ private initially true; \n" + " //@ public private initially true; \n" + " //@ non_null initially true; \n" + " //@ spec_public initially true; \n" + " //@ static initially true; \n" + " //@ instance initially true; \n" + " void m() {} }" ,"/A.java:4: This JML modifier is not allowed for a initially clause", 7 ,"/A.java:6: illegal combination of modifiers: public and private", 22 ,"/A.java:7: This JML modifier is not allowed for a initially clause", 7 ,"/A.java:8: This JML modifier is not allowed for a initially clause", 7 ); } // TODO - test type parameters // TODO - test interaction between access and spec_public/protected // TODO - test instance and interaction with static // TODO - model methods in interfaces are not implicitly abstract and may be instance // TODO - non_null, nullable must have a return type // TODO - test initializers @Test public void testBinaryMods() { addMockFile("$A/java/lang/Object.jml", "package java.lang; /*@ non_null */ public class Object {\n" +"//@ spec_public spec_protected\n" +"public boolean equals(Object o);}"); helpTCF("A.java","public class A{ A(int i) {} \n" + " boolean m() { return new Object().equals(null); } }" ,"/$A/java/lang/Object.jml:2: A declaration may not be both spec_public and spec_protected",17 ,"/$A/java/lang/Object.jml:2: warning: There is no point to a declaration being both public and spec_protected",17 ,"/$A/java/lang/Object.jml:2: warning: There is no point to a declaration being both public and spec_public",5 ,"/$A/java/lang/Object.jml:1: This JML modifier is not allowed for a type declaration",24 ); } // Checking for missing package declaration @Test public void testBinaryPackage1() { addMockFile("$A/java/lang/Object.jml", "/*@ non_null */ public class Object {\n" +"\n" +"public boolean equals(Object o);}"); helpTCF("A.java","public class A{ A(int i) {} \n" + " boolean m() { return new Object().equals(null); } }" ,"/$A/java/lang/Object.jml:1: This type declaration (Object) is not matched by a binary class",24 //,"/$A/java/lang/Object.jml:1: Specification package does not match Java package: unnamed package vs. java.lang",5 // FIXME - improve error message, here and below? ); } // Checking for incorrect package declaration @Test public void testBinaryPackage2() { addMockFile("$A/java/lang/Object.jml", " package java.utils; \n/*@ non_null */ public class Object {\n" +"//@ spec_public spec_protected\n" +"public boolean equals(Object o);}"); helpTCF("A.java","public class A{ A(int i) {} \n" + " boolean m() { return new Object().equals(null); } }" ,"/$A/java/lang/Object.jml:2: This type declaration (java.utils.Object) is not matched by a binary class",24 //,"/$A/java/lang/Object.jml:1: Specification package does not match Java package: java.utils vs. java.lang",3 ); } @Test public void testQuery() { helpTCF("t/A.java","package t; import org.jmlspecs.annotation.*; \n public class A{ @Query int m() { return 0; } }" ); checkMessages(); } @Test public void testSecret() { helpTCF("t/A.java","package t; import org.jmlspecs.annotation.*; \n public class A{ /*@ secret model int a; */ @Secret(\"a\") int m() { return 0; } }" ); } @Test public void testSecret2() { helpTCF("t/A.java","package t; import org.jmlspecs.annotation.*; \n public class A{ @Secret(\"x\") int m() { return 0; } //@ model secret int x; }" ); } @Test public void testAnnotations1() { addMockFile("$A/A.jml"," public class A {}"); expectedExit = 0; helpTCF("A.java","import org.jmlspecs.annotation.*;\n" + "public @Pure class A{}", "/A.java:2: warning: Annotations in a .java file are superseded (and ignored) by the specifications in the corresponding .jml file: class A, annotation @Pure", 8); } // TODO - the next two could use better error messages @Test public void testBadModifiers() { helpTCF("A.java","package tt; \n" +"/*@ nonnull_by_default*/ public class A { \n" // Purposely misspelled non_null_by_default +" //@ requires a[i]>0;\n" +" public void m1bad(int[] a, int i) {\n" +" }\n" +" //@ requires i >= 0 && i < a.length;\n" +" //@ requires a[i]>0;\n" +" public void m1good(int[] a, int i) {\n" +" }\n" +"}" ,"/A.java:2: Unexpected or misspelled JML token: nonnull_by_default",5 ); } @Test @Ignore // Eventually a clear error message, but too many cacading messages to check. public void testBadModifiers2() { helpTCF("A.java","package tt; \n" +"public class A { \n" +" //@ requires a[i]>0;\n" +" public void m1bad(/*@ nonnull */ int[] a, int i) {\n" // Purposely misspelled non_null +" }\n" +" //@ requires i >= 0 && i < a.length;\n" +" //@ requires a[i]>0;\n" +" public void m1good(int[] a, int i) {\n" +" }\n" +"}" ); } @Test public void testHelper1() { helpTCF("A.java","public class A{ /*@ helper */ void m(){} }" ,"/A.java:1: A helper method must be private or pure: m",21 ); } @Test public void testHelper2() { helpTCF("A.java","public class A{ /*@ helper protected */ void m(){} }" ,"/A.java:1: A helper method must be private or pure: m",21 ); } @Test public void testHelper3() { helpTCF("A.java","public class A{ /*@ helper public */ void m(){} }" ,"/A.java:1: A helper method must be private or pure: m",21 ); } @Test public void testHelper4() { helpTCF("A.java","public class A{ /*@ helper private */ void m(){} }" ); } @Test public void testHelper5() { helpTCF("A.java","public class A{ /*@ helper private spec_protected*/ void m(){} }" ,"/A.java:1: A helper method must be private or pure: m",21 ); } @Test public void testHelper6() { helpTCF("A.java","public class A{ /*@ helper private spec_public */ void m(){} }" ,"/A.java:1: A helper method must be private or pure: m",21 ); } // FIXME - also need to test this for when a .class file has a JML annotation that the spec file does not - is that tested for Java m // FIXME - these need implementing - error for the different in annotations }