I am looking for test cases for Alloy. Test cases can be written in Alloy. For example, the following is a test of some integer operations. During the build, we run all these tests and verify their expected outcomes. (expect 0 is no solution).
It would be nice to have test cases for all of Alloy’'s operations to make sure that any changes in the code won’t affect the results.
--option noOverflow=false
--option.noOvflw_* noOverflow=true
sig NonInt {}
equal: run { 1=1 } expect 1
equal2: run { all n : Int | n = n } expect 1
equal3: run { some n : Int | n = 1 } expect 1
unequal: run { 1!=1 } expect 0
plus: run { 1.plus[1]=2 } for 4 int expect 1
xplus: run { 1.plus[1]!=2 } for 4 int expect 0
minus: run { 1.minus[1]=0 } for 4 int expect 1
xminus: run { 1.minus[1]!=0 } for 4 int expect 0
div: run { 4.div[2]=2 } for 4 int expect 1
xdiv: run { 4.div[2]!=2 } for 4 int expect 0
div_min: run { 4.div[-2]=-2 } for 4 int expect 1
xdiv_min: run { 4.div[-2]!=-2 } for 4 int expect 0
mul: run { 4.mul[2]=8 } for 5 int expect 1
xmul: run { 4.mul[2]!=8 } for 5 int expect 0
mul_min: run { 4.mul[-2]=-8 } for 5 int expect 1
xmul_min: run { 4.mul[-2]!=-8 } for 5 int expect 0
max_4: run { 7 in Int and -8 in Int } for 4 int expect 1
// TODO this fails but I think it should fail to compile
// noOvflw_max_4_9: run { 9 in Int } for 4 int expect 0
// xmax_4: run { 9 not in Int } for 4 int expect 1
max_5: run { 15 in Int and -16 in Int } for 5 int expect 1
max_6: run { 31 in Int and -32 in Int } for 6 int expect 1
max_7: run { 63 in Int and -64 in Int } for 7 int expect 1
max_8: run { 127 in Int and -128 in Int } for 8 int expect 1
max_9: run { 255 in Int and -256 in Int } for 9 int expect 1
intinuniv: run { all n : Int | n in univ } for 4 int expect 1
intinident: run { all n : Int | n->n in iden } for 4 int expect 1
inset: run { 1 in { n : Int | n = n } } for 4 int expect 1
inset2: run { 1 in (-1+0+1+2) } for 4 int expect 1
noother: run { no n : Int | n in NonInt } for 4 int expect 1
noOvflw_plus: run { 6.plus[6]=-4 } for 4 int expect 0
okOverflow: run { 6.plus[6]=-4 } for 4 int expect 1
pred solvesum[x,y,z : Int ] {
x.plus[y] = z
}
solvesum_0: run { some x,y,z : Int | solvesum[x,y,z] } for 4 int expect 1
solvesum_1: run { some x,y,z : Int | solvesum[x,y,z] and x > y and y > z } for 4 int expect 1
So don’t ask what Alloy can do for you, ask what you can do for Alloy! Nice task when you got a few minutes.
You can just post them here in this topic. I promise to give them a like!
Personally, but I am open for disagreement, I’d like the test cases to be more direct. You use Object,File,Dir, and Root but you actually don’t have their semantics. I feel your pain, for test cases you need atoms …
Although integers are not recommended in Alloy, they do have the huge advantage that you got lots of atoms that you directly use in your code. I think (but maybe someone else can weigh in) that although Int’s have some special semantics, for set operations they are really treated as atoms. So personally I think we should take advantage of this.
So my attempt to test the relational operators would look like:
let s1 = (1+2+3)
let s2 = (4+5+6)
let s3 = (3+4)
let neg = { n : Int | n < 0 }
let pos = { n : Int | n > 0 }
let s4 = (s1 -> s2)
run union { s1 + s2 = (1+2+3+4+5+6) } expect 1
run intersection_no { s1 & s2 = none } expect 1
run intersection_one { s1 & s3 = 3 } expect 1
run intersection_one { s1 & s3 = 3 } expect 1
run intersection_parent { Int & s1 = s1 } expect 1
run differencee { s1 - s3 = 1+2 } expect 1
run complete { Int - neg = 0 + pos } for 4 int expect 1
run block_join { s4[s1] = s2 } expect 1
run dot_join { s1.s4 = s2 } expect 1
Now you are using check with expect 0. Is there a logical difference?
The thing that I felt was odd was that the model did not have behavior defined for File, Root, Dir, etc. So the names implied something that wasn’t there, which confused me initially. I also had to look very carefully at your testcases to see if the expected outcome was correct.
That said, it is always a problem to get your hand on atoms in Alloy since you immediately get a lot of semantics involved. One way is to use a predicate:
sig Atom {}
pred union( disj a, b, c, d, e, f, g, h, i, j : Atom ) { a+b = b+a }
run union for 10 Atom expect 1
But that extra code seems rather ungrateful to the 16 integers we always get for free
Yeah, I am not sure really why run feels better in this case … A check tests if there is a counter example, I am struggling a bit to see how it maps to a test case? Finding or not funding a counter example depends on the test case? Since they are logically equivalent I think the ‘positive’ run is easier to understand, but I am open to be convinced otherwise?
I hope I am not putting you off … I am struggling how to do this in this world between Java & Alloy. Since there are very few test cases today, I’d like to get start the best we can. But I do not claim any expertise how to best do this.
Hi Peter,
here are some tests which we have used when developing Electrum/Alloy 6. Most of these identities come from the SPOT tool documentation.
// modules raises warnings
----------------------------------------------------------------------
var sig V {}
t6: run { eventually V != V' } expect 1
t8: run { always V = V' } expect 1
t10: run { always eventually V = V' and always eventually V != V' } expect 1
----------------------------------------------------------------------
var lone sig W {}
t15: check { always lone W } expect 0
t17: run { eventually (some x: W | eventually some y: W | x != y) } expect 1
t19: run { some x: W | always W in x } expect 1
----------------------------------------------------------------------
var some sig Y {}
t24: check { always some Y } expect 0
t26: run { some x: Z | always Z in x } expect 1
----------------------------------------------------------------------
var one sig Z {}
t31: check { always lone Z } expect 0
t33: check { always some Z } expect 0
t35: check { always one Z } expect 0
t37: run { eventually (some x: Z | eventually some y: Z | x != y) } expect 1
t39: run { some x: Z | always Z in x } expect 1
----------------------------------------------------------------------
var sig A {}
var sig B, C extends A {}
t46: check { always B in A } expect 0
t48: check { always C in A } expect 0
t50: check {
always all x: B, y: C | always (x not in C and y not in B)
} expect 0
----------------------------------------------------------------------
var abstract sig D {}
var sig E, F extends D {}
t59: check { always D in E + F } expect 0
t61: check { always E in D } expect 0
t63: check { always F in D } expect 0
t65: check {
always all x: E, y: F | always (x not in F and y not in E)
} expect 0
----------------------------------------------------------------------
var sig G, H, I, J {}
pred p { some G }
pred q { some H }
pred r { some I }
pred s { some J }
pred tt { G = G }
pred ff { G != G }
t81: check { (always after p) iff (after always p) } expect 0
t83: check { always p iff not (eventually not p) } expect 0
t85: check { after ff iff ff } expect 0
t87: check { eventually ff iff ff } expect 0
t89: check { (after p until q and r) iff (((after p) until q) and r) } expect 0
t91: check { (after tt) iff tt } expect 0
t92: check { (always ff) iff ff } expect 0
t94: check { (eventually tt) iff tt } expect 0
t95: check { (eventually eventually ff) iff eventually ff } expect 0
t97: check { (always tt) iff tt } expect 0
t98: check { (always always ff) iff always ff } expect 0
t100: check { (p until tt) iff tt } expect 0
t101: check { (ff until p) iff p } expect 0
t102: check { (p until ff) iff ff } expect 0
t103: check { (p until p) iff p } expect 0
t104: check { (tt until p) iff eventually p } expect 0
t105: check { ((after p) until (after q)) iff after (p until q) } expect 0
t107: check { (p releases q) iff not ((not p) until (not q)) } expect 0
t108: check { (p releases tt) iff tt } expect 0
t109: check { (p releases ff) iff ff } expect 0
t110: check { (tt releases p) iff p } expect 0
t111: check { (p releases p) iff p } expect 0
t112: check { (ff releases p) iff always p } expect 0
t113: check { (p releases q) iff (q and (p or after (p releases q))) } expect 0
t115: check { (after eventually always p) iff eventually always p } expect 0
t116: check { (after always eventually p) iff always eventually p } expect 0
t117: check { (after eventually p) iff eventually after p } expect 0
t119: check { (eventually (p until q)) iff eventually q } expect 0
t120: check { (eventually always (p and after q)) iff eventually always (p and q) } expect 0
t121: check { (eventually always (p and always q)) iff eventually always (p and q) } expect 0
t122: check { (eventually always (p or always q)) iff eventually (always p or always q) } expect 0
t123: check { (eventually always (p and eventually q)) iff ((eventually always p) and always eventually q) } expect 0
t124: check { (eventually always (p or eventually q)) iff ((eventually always p) or always eventually q) } expect 0
t126: check { (always eventually (p or after q)) iff always eventually (p or q) } expect 0
t127: check { (always eventually (p or eventually q)) iff always eventually (p or q) } expect 0
t128: check { (always eventually (p and eventually q)) iff always (eventually p and eventually q) } expect 0
t129: check { (always eventually (p and always q)) iff ((always eventually p) and eventually always q) } expect 0
t130: check { (always eventually (p or always q)) iff ((always eventually p) or eventually always q) } expect 0
t132: check { (p until always p) iff always p } expect 0
t133: check { (p releases (eventually p)) iff eventually p } expect 0
t136: check { (eventually always p and eventually always q) iff eventually always (p and q) } expect 0
t137: check { (after p and after q) iff after (p and q) } expect 0
t138: check { (after p and eventually always q) iff after (p and eventually always q) } expect 0
t139: check { ((p until q) and (r until q)) iff ((p and r) until q) } expect 0
t140: check { ((p releases q) and (p releases r)) iff (p releases (q and r)) } expect 0
t141: check { ((p until q) or (p until r)) iff (p until (q or r)) } expect 0
t142: check { ((p releases q) or (r releases q)) iff ((p or r) releases q) } expect 0
t144: check { ((always q) or (p releases q)) iff (p releases q) } expect 0
t147: check { ((after p) releases (after q)) iff after (p releases q) } expect 0
t149: check { (always (p releases q)) iff always q } expect 0
t151: check { eventually always once p iff eventually p } expect 0
t153: check { eventually (p and (q since r)) iff eventually (r and (p or after (q until (q and p)))) } expect 0
We’ve done some work with “unit” test cases for Alloy that we have then used for mutation testing/fault localization/repair. It follows the predicate route you motioned and it is designed to outline a specific instance and then you would use a command to say if the instance should be allowed or prevented by some formulas in the model.
For example, for a singly linked list model with a List, Node, header, and link, we’d outline the following:
pred three_node_list {
some l0 : List | some disj n0, n1, n2 : Node {
List = l0
Node = n0 + n1 + n2
header = l0->n0
link = n0->n1 + n1->n2
}
}