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.
288 lines
8.2 KiB
HTML
288 lines
8.2 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<title>QuickCheck</title>
|
|
</head>
|
|
<body>
|
|
<p>
|
|
Files :
|
|
<a href="use31.m">use31.m</a>
|
|
<a href="use33.m">use33.m</a>
|
|
<a href="nrev.m">nrev.m</a>
|
|
<br>
|
|
<a href="index.html">Back to main</a>
|
|
|
|
<h1>QuickCheck Tutorial 3</h1>
|
|
<h2>Monitoring Test Data: <code>to_trivial/3</code></h2>
|
|
|
|
<p>
|
|
In Tutorial 1, the 3rd rule for reverse is that:
|
|
<pre>
|
|
reverse (reverse xs) = xs
|
|
</pre>
|
|
It's not much of a test if <code>xs</code> is an empty list or a list with only 1 element.
|
|
|
|
<p>
|
|
Quickcheck can label a test being trivial via the function
|
|
to_trivial/3, which does not change the meaning of a law, but it classifies
|
|
some of the test cases.
|
|
Without classifying, the invariant function could be:
|
|
<pre>
|
|
:- func testing1(list(float)) = property.
|
|
testing1(Xs) =
|
|
nrev (nrev Xs) `===` Xs.
|
|
</pre>
|
|
If the 1st argument of to_trivial/3 is equal to the 2nd argument, then that test
|
|
case will be labeled trivial by pushing <code>flag:trivial</code> into the third argument
|
|
(which is a list of flags).
|
|
testing2/1 treats empty list as trivial test.
|
|
<pre>
|
|
:- func testing2(list(float)) = property.
|
|
testing2(Xs) =
|
|
to_trivial([], Xs, nrev (nrev Xs) `===` Xs).
|
|
</pre>
|
|
Use compounded to_trivial to also classify lists of 1 element as trivial
|
|
<pre>
|
|
:- func testing3(list(float)) = property.
|
|
testing3(Xs) =
|
|
to_trivial(1,
|
|
list_length(Xs),
|
|
to_trivial([], Xs, nrev(nrev(Xs)) `===` Xs)
|
|
).
|
|
</pre>
|
|
The complete code (use31.m):
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0" summary="use31.m source code"><tr><td><pre>
|
|
:- module use31.
|
|
|
|
:- 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, nrev.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
main -->
|
|
qcheck(qcheck__f(testing1), "testing1"),
|
|
qcheck(qcheck__f(testing2), "testing2"),
|
|
qcheck(qcheck__f(testing3), "testing3").
|
|
|
|
:- func testing1(list(float)) = property.
|
|
testing1(Xs) =
|
|
nrev(nrev(Xs)) `===` Xs.
|
|
|
|
:- func testing2(list(float)) = property.
|
|
testing2(Xs) =
|
|
to_trivial([], Xs, nrev(nrev(Xs)) `===` Xs).
|
|
|
|
:- func testing3(list(float)) = property.
|
|
testing3(Xs) =
|
|
to_trivial(1,
|
|
list_length(Xs),
|
|
to_trivial([], Xs, nrev(nrev(Xs)) `===` Xs)
|
|
).
|
|
</pre></tr></table>
|
|
A sample output :
|
|
<pre>
|
|
Test Description : testing1
|
|
Number of test cases that succeeded : 100
|
|
Number of trivial tests : 0
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
|
|
Test Description : testing2
|
|
Number of test cases that succeeded : 100
|
|
Number of trivial tests : 53
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
|
|
Test Description : testing3
|
|
Number of test cases that succeeded : 100
|
|
Number of trivial tests : 75
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
</pre>
|
|
Note test1, the original, has no trivial cases. With test2, 53/100 tests have
|
|
an empty list as its input. Test3 shows 75/100 tests have either an empty list
|
|
or a list of only one element. It only tested 25/100 cases where the list is
|
|
longer than 1 element.
|
|
|
|
|
|
<h2>Monitoring Test Data: <code>`>>>`</code></h2>
|
|
|
|
<p>The combinator <code>`>>>`</code> gathers all values that are
|
|
passed to it, and prints out
|
|
a histogram of these values.
|
|
Let's use <code>`>>>`</code> to find out exactly what lists are generated for the previous
|
|
tests:
|
|
<pre>
|
|
:- func testing4(list(float)) = property.
|
|
testing4(Xs) =
|
|
list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
|
|
</pre>
|
|
|
|
<p>The combinator <code>`>>>`</code> will convert its left
|
|
argument to a univ, and push info(univ) into the property list.
|
|
|
|
<p>The complete code (use31.m):
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0" summary="use31.m source code"><tr><td><pre>
|
|
:- module use31.
|
|
|
|
:- 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, nrev.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
main -->
|
|
qcheck(qcheck__f(testing1), "testing1"),
|
|
qcheck(qcheck__f(testing2), "testing2"),
|
|
qcheck(qcheck__f(testing3), "testing3"),
|
|
qcheck(qcheck__f(testing4), "testing4").
|
|
|
|
:- func testing1(list(float)) = property.
|
|
testing1(Xs) =
|
|
nrev(nrev(Xs)) `===` Xs.
|
|
|
|
:- func testing2(list(float)) = property.
|
|
testing2(Xs) =
|
|
to_trivial([], Xs, nrev(nrev(Xs)) `===` Xs).
|
|
|
|
:- func testing3(list(float)) = property.
|
|
testing3(Xs) =
|
|
to_trivial(1,
|
|
list_length(Xs),
|
|
to_trivial([], Xs, nrev(nrev(Xs)) `===` Xs)
|
|
).
|
|
|
|
:- func testing4(list(float)) = property.
|
|
testing4(Xs) =
|
|
list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
|
|
</pre></tr></table>
|
|
A sample output :
|
|
<pre>
|
|
Test Description : testing1
|
|
Number of test cases that succeeded : 100
|
|
Number of trivial tests : 0
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
|
|
Test Description : testing2
|
|
Number of test cases that succeeded : 100
|
|
Number of trivial tests : 53
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
|
|
Test Description : testing3
|
|
Number of test cases that succeeded : 100
|
|
Number of trivial tests : 71
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
|
|
Test Description : testing4
|
|
Number of test cases that succeeded : 100
|
|
Number of trivial tests : 0
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
1 8
|
|
1 4
|
|
1 6
|
|
2 5
|
|
8 3
|
|
16 2
|
|
18 1
|
|
53 0
|
|
</pre>
|
|
The display of testing4 shows that 53 cases of length == 0
|
|
18 cases of length == 1
|
|
16 cases of length == 2
|
|
...etc...
|
|
53+18 cases = 71 cases, which were marked trivial in testing3, likewise
|
|
for testing2. The numbers will add up only if all the tests were run with
|
|
the same random number seed.
|
|
|
|
|
|
The value passed to `>>>` does not have to be the same type, and `>>>` can
|
|
be compounded like to_trivial/3, e.g. (use33.m):
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0" summary="use33.m source code"><tr><td><pre>
|
|
:- module use33.
|
|
|
|
:- 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, nrev.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
main -->
|
|
qcheck(qcheck__f(testing5), "testing5").
|
|
|
|
:- func testing5(list(float)) = property.
|
|
testing5(Xs) =
|
|
odd_even(Xs) `>>>`
|
|
(list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs)).
|
|
|
|
:- func odd_even(list(T)) = string.
|
|
:- mode odd_even(in) = out is det.
|
|
odd_even(Xs) = Y :-
|
|
(if list_length(Xs) mod 2 = 1
|
|
then
|
|
Y = "odd"
|
|
else
|
|
Y = "even"
|
|
).
|
|
</pre></tr></table>
|
|
testing5 collects the list_length, and also collect "odd" or "even"
|
|
A sample output :
|
|
<pre>
|
|
Test Description : testing5
|
|
Number of test cases that succeeded : 100
|
|
Number of trivial tests : 0
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
1 7
|
|
1 5
|
|
2 4
|
|
2 6
|
|
8 3
|
|
10 2
|
|
29 1
|
|
39 "odd"
|
|
47 0
|
|
61 "even"
|
|
</pre>
|
|
|
|
</body>
|
|
</html>
|
|
|