Files:
use20.m
use21.m
use22.m
mymax.m
Back to main
In general many laws hold only under certain conditions. Quickcheck provides an implication combinator to represent such conditional laws. Eg, the law
X =< Y => max x y == ycan be represented by the definition :
:- func law(int, int) = property. law(X, Y) = (X =< Y) `===>` (mymax(X, Y) `===` Y).or alternatively can be represented as :
:- func law2(int, int) = property. law2(X, Y) = is_less_equal(X, Y) `===>` (mymax(X, Y) `===` Y). :- func is_less_equal(int, int) = bool. is_less_equal(X, Y) = Bool :- (if X =< Y then Bool = yes else Bool = no ).The difference between law1 and law2 is the left argument of `===>`. (X =< Y) is of type (pred) whereas is_less_equal(X, Y) evaluates to type bool. `===>` is overloaded to take both types.
The complete use20.m:
:- module use20. :- interface. :- use_module io. :- pred main(io__state, io__state). :- mode main(di, uo) is det. %---------------------------------------------------------------------------% :- implementation. :- import_module int, list, bool. :- import_module qcheck, mymax. %---------------------------------------------------------------------------% main --> qcheck(qcheck__f(law), "testing mymax using `===>` for (pred)"), qcheck(qcheck__f(law2), "testing mymax using `===>` for bool"). :- func law(int, int) = property. law(X, Y) = (X =< Y) `===>` (mymax(X, Y) `===` Y). :- func law2(int, int) = property. law2(X, Y) = is_less_equal(X, Y) `===>` (mymax(X, Y) `===` Y). :- func is_less_equal(int, int) = bool. is_less_equal(X, Y) = Bool :- (if X =< Y then Bool = yes else Bool = no ). |
Test Description : testing mymax using `===>` for (pred) Number of test cases that succeeded : 52 Number of trivial tests : 0 Number of tests cases which failed the pre-condition : 48 Distributions of selected argument(s) : Test Description : testing mymax using `===>` for bool Number of test cases that succeeded : 52 Number of trivial tests : 0 Number of tests cases which failed the pre-condition : 48 Distributions of selected argument(s) :The default number of tests to run is 100. In the above test, 48/100 cases passed the invariant function, and none failed. However, there are 52/100 cases where the inputs failed the pre-condition.
Note that both test cases succeeded 52/100 and failed pre-condition 48/100. qcheck.m seeds the random generator on local time, if qcheck is called twice within the same second, the number generated will be the same.
The implication combinator can be compounded. For example, suppose mymax is designed that if mymax(X, Y) is called, Y will never be zero. Thus test cases with Y=0 should also be disregarded (use21.m) :
:- func law(int, int) = property. law(X, Y) = notzero(Y) `===>` ((X =< Y) `===>` (mymax(X, Y) `===` Y)). :- pred notzero(int). :- mode notzero(in) is semidet. notzero(X) :- X \= 0.
The right argument of `===>` is also overload, as shown in use22.m:
:- module use22. :- interface. :- use_module io. :- pred main(io__state, io__state). :- mode main(di, uo) is det. %---------------------------------------------------------------------------% :- implementation. :- import_module int, bool. :- import_module qcheck. %---------------------------------------------------------------------------% main --> qcheck(qcheck__f(law1), "passing property"), qcheck(qcheck__f(law2), "passing (func) = property"). :- func law1(int, int) = property. law1(X, Y) = notzero(Y) `===>` qcheck__f( (func) = ((X // Y) `===` (X // Y)) ). :- func law2(int, int) = property. law2(X, Y) = notzero(Y) `===>` ( (X // Y) `===` (X // Y) ). :- pred notzero(int). :- mode notzero(in) is semidet. notzero(X) :- X \= 0. |
The implication combinator `===>` marks a test that has failed pre-condition by inserting 'flag:condition' into the property in cases where the right argument is a property; in cases where the right argument is (func), then `===>` will just return 'property:[condition]'. If the property list contains one or more 'condition', the test result is ignored.