package org.jmlspecs.openjmltest.testcases;
import org.jmlspecs.openjmltest.TCBase;
import org.junit.Ignore;
import org.junit.Test;
public class QuerySecret extends TCBase {
@Override
public void setUp() throws Exception {
// noCollectDiagnostics = true;
// jmldebug = true;
super.setUp();
}
// FIXME - there still is a problem in that annotations are checked more than once - we have to comment out the error message to avoid repeated error messages
@Test
public void testOK1() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Query(\"q\") int m() { return 0; } \n" +
"} \n"
);
}
@Test
public void testBadParse() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Query(\"q\",\"r\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: annotation values must be of the form 'name=value'",10
,"/A.java:4: annotation values must be of the form 'name=value'",14
);
}
@Test
public void testBadParse2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Query(v=\"q\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: cannot find symbol\n symbol: method v()\n location: @interface org.jmlspecs.annotation.Query",12
);
}
@Test
public void testBadParse3() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Query(9) int m() { return 0; } \n" +
"} \n"
,"/A.java:4: incompatible types: int cannot be converted to java.lang.String",10
);
}
@Test
public void testBadParse4() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Query(value=\"q\",value=\"r\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: duplicate element 'value' in annotation @org.jmlspecs.annotation.Query.",20
);
}
@Test
public void testConstantExpression() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Query(value=\"q\"+\"r\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: There is no field or datagroup named qr in the class or its super types",15
);
}
@Test
public void testOKnamed() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Query(value=\"q\") int m() { return 0; } \n" +
"} \n"
);
}
@Test
public void testNotModel() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" JMLDataGroup q;\n" +
" @Query(\"q\") int m() { return 0; } \n" +
"} \n"
//,"/A.java:4: A datagroup must be declared model",10 // OK
);
}
@Test
public void testSNotModel() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" JMLDataGroup q;\n" +
" @Secret(\"q\") int m() { return 0; } \n" +
"} \n"
//,"/A.java:4: A datagroup must be declared model",11
);
}
@Test
public void testOtherDeclOK() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ model int q;\n" +
" @Query(\"q\") int m() { return 0; } \n" +
"} \n"
);
}
@Test
public void testSOtherDeclOK() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ model int q;\n" +
" @Secret(\"q\") int m() { return 0; } \n" +
"} \n"
);
}
/** Can be query for an inherited deata group */
@Test
public void testOK2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"class B { /*@ public model JMLDataGroup q; */ }\n" +
"public class A extends B { \n" +
" @Query(\"q\") int m() { return 0; } \n" +
"} \n"
);
}
/** A named data group must exist */
@Test
public void testNoDG() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //JMLDataGroup q;\n" +
" @Query(\"q\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: There is no field or datagroup named q in the class or its super types",10
);
}
/** A named data group may not be in an enclosing class */
@Test
public void testNoDG2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A {\n" +
" //@ public model JMLDataGroup q;\n" +
" public class X { \n" +
" @Query(\"q\") int m() { return 0; } \n" +
" }\n" +
"} \n"
,"/A.java:5: There is no field or datagroup named q in the class or its super types",12
);
}
/** A default existent datagroup */
@Test
public void testOK3() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup m;\n" +
" @Query int m() { return 0; } \n" +
"} \n"
);
}
/** A default non-existent datagroup */
@Test
public void testOK4() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Query int m() { return 0; } \n" +
"} \n"
);
}
@Test
public void testSOK1() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(\"q\") int m() { return 0; } \n" +
"} \n"
);
}
@Test
public void testSBadParse() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(\"q\",\"r\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: annotation values must be of the form 'name=value'",11
,"/A.java:4: annotation values must be of the form 'name=value'",15
,"/A.java:4: A secret annotation on a method must have exactly one argument",3
);
}
@Test
public void testSBadParse2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(v=\"q\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: cannot find symbol\n symbol: method v()\n location: @interface org.jmlspecs.annotation.Secret",13
);
}
@Test
public void testSBadParse3() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(9) int m() { return 0; } \n" +
"} \n"
,"/A.java:4: incompatible types: int cannot be converted to java.lang.String",11
);
}
@Test
public void testSBadParse4() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(value=\"q\",value=\"r\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: duplicate element 'value' in annotation @org.jmlspecs.annotation.Secret.",21
);
}
@Test
public void testSOKnamed() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(value=\"q\") int m() { return 0; } \n" +
"} \n"
);
}
/** Can be query for an inherited deata group */
@Test
public void testSOK2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"class B { /*@ public model JMLDataGroup q; */ }\n" +
"public class A extends B { \n" +
" @Secret(\"q\") int m() { return 0; } \n" +
"} \n"
);
}
/** A named data group must exist */
@Test
public void testSNoDG() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //JMLDataGroup q;\n" +
" @Secret(\"q\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: There is no field or datagroup named q in the class or its super types",11
);
}
/** A named data group may not be in an enclosing class */
@Test
public void testSNoDG2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A {\n" +
" //@ public model JMLDataGroup q;\n" +
" public class X { \n" +
" @Secret(\"q\") int m() { return 0; } \n" +
" }\n" +
"} \n"
,"/A.java:5: There is no field or datagroup named q in the class or its super types",13
);
}
/** A default existent datagroup */
@Test
public void testSOK3() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup m;\n" +
" @Secret int m() { return 0; } \n" +
"} \n"
,"/A.java:4: A secret annotation on a method must have exactly one argument",3
);
}
/** A default non-existent datagroup */
@Test
public void testSOK4() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Query int m() { return 0; } \n" +
"} \n"
);
}
/** Same datagroup */
@Test
public void testSameDG() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Query @Secret(\"m\") int m() { return 0; } \n" +
"} \n"
,"/A.java:3: A method may not be both secret and query for the same datagroup",3
);
}
@Test
public void testNoOuter() {
helpTCF("Outer.java",
"import org.jmlspecs.annotation.*;\n" +
"public class Outer { int p; \n" +
"static public class A { \n" +
" @Query @Secret(\"p\") int m() { return 0; } \n" +
"}\n" +
" public class B { \n" +
" @Query @Secret(\"p\") int m() { return 0; } \n" +
"}\n" +
"} \n"
,"/Outer.java:4: There is no field or datagroup named p in the class or its super types",18
,"/Outer.java:7: There is no field or datagroup named p in the class or its super types",18
);
}
@Test
public void testSuper() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
" public class A extends B { \n" +
" @Query @Secret(\"p\") int m() { return 0; } \n" +
"}\n" +
" class B { \n" +
" int p; \n" +
"} \n"
);
}
@Test
public void testInterface() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
" public class A implements B { \n" +
" @Query @Secret(\"p\") int m() { return 0; } \n" +
"}\n" +
" interface B { \n" +
" //@ instance model int p; \n" +
"} \n"
);
}
// Secret no longer allows a default
// /** Same datagroup */
// @Test
// public void testSameDG1() {
// helpTCF("A.java",
// "import org.jmlspecs.annotation.*;\n" +
// "public class A { \n" +
// " @Secret @Query(\"m\") int m() { return 0; } \n" +
// "} \n"
// ,"/A.java:3: There is no model field or datagroup named m in the class or its super types",18
// );
// }
/** Same datagroup */
@Test
public void testSameDG2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Secret(\"m\") @Query int m() { return 0; } \n" +
"} \n"
,"/A.java:3: A method may not be both secret and query for the same datagroup",16
);
}
/** Same datagroup */
@Test
public void testSameDG3() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Secret(\"m\") @Query(\"m\") int m() { return 0; } \n" +
"} \n"
,"/A.java:3: There is no field or datagroup named m in the class or its super types",23
,"/A.java:3: There is no field or datagroup named m in the class or its super types",11
);
}
/** Same datagroup */
@Test
public void testSameDGOK() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(\"q\") @Query int m() { return 0; } \n" +
"} \n"
);
}
/** Same datagroup */
@Test
public void testSameDGOK2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup m;\n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(\"m\") @Query(\"q\") int m() { return 0; } \n" +
"} \n"
);
}
/** Same datagroup */
@Test
public void testSameDGOK3() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q,r;\n" +
" @Secret(\"r\") @Query(\"q\") int m() { return 0; } \n" +
"} \n"
);
}
/** Same datagroup */
@Test
public void testSameDG4() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret(\"q\") @Query(\"q\") int m() { return 0; } \n" +
"} \n"
,"/A.java:4: A method may not be both secret and query for the same datagroup",16
);
}
@Test
public void testFOK1() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public secret model JMLDataGroup q;\n" +
" @Secret int m; //@ in q; \n" +
"} \n"
);
}
/** Secret, but not in a datagroup */
@Test
public void testFNotIn() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret int m; \n" +
"} \n"
//,"/A.java:4: A secret field must be a model field or in a secret datagroup",15
);
}
/** Secret, but not in a datagroup */
@Test
public void testFInNonSecret() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" @Secret int m; //@ in q; \n" +
"} \n"
,"/A.java:4: A datagroup for a secret field must be secret",22
);
}
/** Not secret but in a secret datagroup */
@Test
public void testFInSecret() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public secret model JMLDataGroup q;\n" +
" int m; //@ in q; \n" +
"} \n"
,"/A.java:4: A datagroup for a non-secret field must be non-secret",14
);
}
/** Not secret but in a secret datagroup */
@Test
public void testFInSecret2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public secret model JMLDataGroup q;\n" +
" //@ model int m; //@ in q; \n" +
"} \n"
,"/A.java:4: A datagroup for a non-secret field must be non-secret",24
);
}
/** OK - model fields are their own datagroups */
@Test
public void testFNotInButModel() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model JMLDataGroup q;\n" +
" //@ secret model int m; \n" +
"} \n"
);
}
/** Valid argument, but not for a field */
@Test
public void testFBadParse() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Secret(\"q\") int m; \n" +
"} \n"
,"/A.java:3: A secret declaration for a field may not have arguments",11
//,"/A.java:3: A secret field must be a model field or in a secret datagroup",20
);
}
/** Invalid argument, also not for field */
@Test
public void testFBadParse2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Secret(v=\"q\") int m; \n" +
"} \n"
,"/A.java:3: cannot find symbol\n symbol: method v()\n location: @interface org.jmlspecs.annotation.Secret",13
,"/A.java:3: A secret declaration for a field may not have arguments",12
);
}
/** Invalid argument, aslo not for field */
@Test
public void testFBadParse3() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Secret(9) int m; \n" +
"} \n"
,"/A.java:3: incompatible types: int cannot be converted to java.lang.String",11
,"/A.java:3: A secret declaration for a field may not have arguments",11
//,"/A.java:3: A secret field must be a model field or in a secret datagroup",18 // FIXME
);
}
/** Valid argument, but not for a field */
@Test
public void testFBadParse4() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" @Secret(value=\"q\") int m; \n" +
"} \n"
,"/A.java:3: A secret declaration for a field may not have arguments",16
//,"/A.java:3: A secret field must be a model field or in a secret datagroup",26
);
}
/** OK - standard use */
@Test
public void testRepresents() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ secret public model int i;\n" +
" //@ secret public model int j; in i; \n" +
" //@ secret public represents i = j; \n" +
"} \n"
);
}
/** Differently secret expression */
@Test
public void testRepresents0() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ secret public model int i;\n" +
" //@ secret public model int j;\n" +
" //@ secret public represents i = j; \n" +
"} \n"
,"/A.java:5: A field may not be read in a secret context unless it is in the same secret datagroup: j not in i",36
);
}
/** Secret id with non-secret represents */
@Test
public void testRepresents1() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ secret public model int i;\n" +
" //@ public represents i = 0; \n" +
"} \n"
,"/A.java:4: A represents clause and its identifier must both be secret or both not be secret",14
);
}
/** Secret represents with non-secret id */
@Test
public void testRepresents2() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model int i;\n" +
" //@ secret public represents i = 0; \n" +
"} \n"
,"/A.java:4: A represents clause and its identifier must both be secret or both not be secret",21
);
}
/** Secret on represents may not have an argument */
@Test
public void testRepresents3() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ secret public model int i;\n" +
" //@ @Secret(\"i\") public represents i = 0; \n" +
"} \n"
,"/A.java:4: A secret declaration for a represents clause may not have arguments",15
);
}
/** testing secret in non-secret represents expression */
@Test
public void testRepresents5() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ secret public model int j;\n" +
" //@ public model int i;\n" +
" //@ public represents i = j; \n" +
"} \n"
,"/A.java:5: Secret fields may not be read in non-secret context: j",29
);
}
/** no secret in invariant */
@Test
public void testInvariant() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ secret public model int j;\n" +
" //@ public invariant j == 0;\n" +
" //@ public constraint j == 0;\n" +
"} \n"
,"/A.java:4: Secret fields may not be read in non-secret context: j",24
,"/A.java:5: Secret fields may not be read in non-secret context: j",25
);
}
@Test
public void testMethodCall() {
helpTCF("A.java",
"import org.jmlspecs.annotation.*;\n" +
"public class A { \n" +
" //@ public model int i;\n" +
" //@ public model int j;\n" +
" //@ @Query(\"i\") \n" +
" public int nq() { \n" +
" mq();\n" + // OK
" mqq();\n" + // BAD
" ms();\n" + // OK
" mo();\n" + // BAD
" mp();\n" + // OK
" mss(); return 0;\n" + // BAD
" }\n" +
" //@ @Secret(\"i\") \n" +
" public int ns() { \n" +
" mq();\n" + // OK
" mqq();\n" + // BAD
" ms();\n" + // OK
" mo();\n" + // BAD
" mss(); return 0;\n" + // BAD
" }\n" +
" public int no() { \n" +
" mq();\n" + // OK
" mqq();\n" + // OK
" ms();\n" + // BAD
" mo();\n" + // OK
" mss(); return 0;\n" + // BAD
" }\n" +
" @Secret(\"i\") void ms() {}\n" +
" @Secret(\"j\") void mss() {}\n" +
" @Query(\"i\") void mq() {}\n" +
" @Query(\"j\") void mqq() {}\n" +
" void mo() {}\n" +
" @Pure void mp() {}\n" +
"} \n"
,"/A.java:8: A method called by a query or secret method must belong to the same datagroup",6
,"/A.java:10: A method called by a query or secret method must belong to the same datagroup",6
,"/A.java:12: A method called by a query or secret method must belong to the same datagroup",6
,"/A.java:17: A method called by a query or secret method must belong to the same datagroup",6
,"/A.java:19: A method called by a query or secret method must belong to the same datagroup",6
,"/A.java:20: A method called by a query or secret method must belong to the same datagroup",6
,"/A.java:25: A non-secret, non-query method may not call a secret method",6
,"/A.java:27: A non-secret, non-query method may not call a secret method",6
);
}
}