mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 02:43:40 +00:00
Estimated hours taken: 2 The following change was made by Peter Moulder <pmoulder@csse.monash.edu.au>. extras/quickcheck/tutes/*.html: Many HTML fixes. (Previously there were enough problems that it made more sense to read them as plain text files than with a web browser.) The files now pass through weblint (cleanly) and tidy (only `table lacks "summary" attribute' warnings remain). A small number of textual changes, and also a couple of <!-- XXX ... --> comments where I suspect the text should be changed.
179 lines
5.5 KiB
HTML
179 lines
5.5 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<title>QuickCheck</title>
|
|
</head>
|
|
<body>
|
|
<h1>QuickCheck Tutorial 2</h1>
|
|
|
|
<p>
|
|
Files:
|
|
<a href="use20.m">use20.m</a>
|
|
<a href="use21.m">use21.m</a>
|
|
<a href="use22.m">use22.m</a>
|
|
<a href="mymax.m">mymax.m</a>
|
|
<br>
|
|
<a href="index.html">Back to main</a>
|
|
|
|
<h2>Conditional law</h2>
|
|
|
|
<p>
|
|
In general many laws hold only under certain conditions. Quickcheck provides
|
|
an implication combinator to represent such conditional laws. Eg, the law
|
|
<pre>
|
|
X =< Y => max x y == y
|
|
</pre>
|
|
can be represented by the definition :
|
|
<pre>
|
|
:- func law(int, int) = property.
|
|
law(X, Y) = (X =< Y) `===>` (mymax(X, Y) `===` Y).
|
|
</pre>
|
|
or alternatively can be represented as :
|
|
<pre>
|
|
:- 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
|
|
).
|
|
</pre>
|
|
The difference between law1 and law2 is the left argument of `===>`.
|
|
<samp>(X =< Y)</samp> is of type (pred) whereas
|
|
<samp>is_less_equal(X, Y)</samp> evaluates to type bool.
|
|
`===>` is overloaded to take both types.
|
|
|
|
|
|
<p>
|
|
The complete use20.m:
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0" summary="use20.m source code"><tr><td><pre>
|
|
:- 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
|
|
).
|
|
</pre></tr></table>
|
|
After running the program, test statistics will be something like:
|
|
<pre>
|
|
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) :
|
|
</pre>
|
|
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.
|
|
|
|
<p>
|
|
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.
|
|
|
|
<p>
|
|
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) :
|
|
<pre>
|
|
:- 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.
|
|
</pre>
|
|
|
|
<p>
|
|
The right argument of `===>` is also overload, as shown in use22.m:
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0" summary="use22.m source code"><tr><td><pre>
|
|
:- 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.
|
|
</pre></tr></table>
|
|
The difference between law1/2 and law2/2 is the right argument of `===>`.
|
|
law1/2 passed (func), while law2/2 passed property. In law2/2, (X // Y) is
|
|
always evaluated, which will cause error if Y is zero. However, in law1/2
|
|
(X // Y) is not evaluated if `===>`'s left argument is 'bool:no' or
|
|
'(pred):failure'.
|
|
|
|
<p>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.
|
|
</body>
|
|
</html>
|