Added eqcmini quickcheck library to lib/
This commit is contained in:
parent
8a574db360
commit
73194d7d28
21 changed files with 2075 additions and 0 deletions
49
lib/eqc/LicenceAgreement.html
Normal file
49
lib/eqc/LicenceAgreement.html
Normal file
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<title></title>
|
||||
<meta name="Author" content="Thomas Arts">
|
||||
<meta name="Company" content="Quviq AB">
|
||||
<meta name="Generator" content="Cocoa HTML Writer">
|
||||
<meta name="CocoaVersion" content="1038.29">
|
||||
<style type="text/css">
|
||||
p.p1 {margin: 0.0px 0.0px 0.0px 14.0px; font: 17.0px 'Lucida Grande'}
|
||||
p.p2 {margin: 0.0px 0.0px 0.0px 14.0px; font: 11.0px 'Lucida Grande'; min-height: 13.0px}
|
||||
p.p3 {margin: 0.0px 0.0px 0.0px 14.0px; text-align: justify; font: 11.0px 'Lucida Grande'}
|
||||
p.p4 {margin: 0.0px 0.0px 0.0px 28.0px; text-indent: -14.0px; font: 11.0px 'Lucida Grande'; min-height: 13.0px}
|
||||
p.p5 {margin: 0.0px 0.0px 0.0px 28.0px; text-indent: -14.0px; font: 11.0px 'Lucida Grande'}
|
||||
p.p6 {margin: 0.0px 0.0px 0.0px 43.0px; text-indent: -15.0px; font: 11.0px 'Lucida Grande'}
|
||||
p.p7 {margin: 0.0px 0.0px 0.0px 43.0px; text-indent: -15.0px; font: 11.0px 'Lucida Grande'; min-height: 13.0px}
|
||||
p.p8 {margin: 0.0px 0.0px 0.0px 28.0px; text-align: justify; text-indent: -14.0px; font: 11.0px 'Lucida Grande'}
|
||||
p.p9 {margin: 0.0px 0.0px 0.0px 28.0px; text-align: justify; text-indent: -14.0px; font: 11.0px 'Lucida Grande'; min-height: 13.0px}
|
||||
p.p10 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Cambria; min-height: 14.0px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="p1"><b>QuickCheck Mini</b></p>
|
||||
<p class="p1"><b>End User License Agreement</b></p>
|
||||
<p class="p2"><br></p>
|
||||
<p class="p3"><b>This end user license agreement ("eula") is a legal agreement between you and quviq. Read it carefully before using the software. It provides a license to use the software and contains warranty information and liability disclaimers. By installing, copying, or otherwise using the software, you agree to be bound by the terms of this agreement. If you do not agree to the terms of this agreement, do not install or use the software.</b></p>
|
||||
<p class="p4"><br></p>
|
||||
<p class="p4"><br></p>
|
||||
<p class="p5"><b>1 LICENSE GRANTS</b></p>
|
||||
<p class="p4"><br></p>
|
||||
<p class="p6"><b>• Quviq</b> – Quviq AB grants you the non-exclusive right to use <b>Quviq’s</b> software program, QuickCheck Mini (the <b>"SOFTWARE"</b>).</p>
|
||||
<p class="p4"><br></p>
|
||||
<p class="p5"><b>2 LICENSE RESTRICTIONS</b></p>
|
||||
<p class="p4"><br></p>
|
||||
<p class="p6"><b>• Distribution.</b> You may freely distribute copies of the <b>SOFTWARE</b> to third parties or point them to the download location at www.quviq.com.</p>
|
||||
<p class="p6"><b>• Prohibition on Reverse Engineering, Decompilation, and Disassembly.</b> You may not reverse engineer, decompile, or disassemble the <b>SOFTWARE.</b></p>
|
||||
<p class="p6"><b>• Reservation of Rights. Quviq </b>retains all rights not expressly granted.</p>
|
||||
<p class="p7"><span class="Apple-converted-space"> </span></p>
|
||||
<p class="p5"><b>3 DISCLAIMER OF WARRANTY AND LIABILITY</b></p>
|
||||
<p class="p4"><br></p>
|
||||
<p class="p8"><b>Limited warranty.</b> The <b>SOFTWARE</b> is provided "as is", without warranty of any kind. To the maximum extent permitted by applicable law, <b>Quviq</b> hereby disclaim all warranties, either expressed or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, title, and non-infringement, with regard to the <b>SOFTWARE</b>, and the provision of or failure to provide support services. This limited warranty gives you specific legal rights. You may have others, which vary from state/jurisdiction to state/jurisdiction. </p>
|
||||
<p class="p9"><br></p>
|
||||
<p class="p8"><b>Limitation of liability.</b> To the maximum extent permitted by applicable law, in no event shall <b>Quviq</b> or its suppliers be liable for any special, incidental, indirect, or consequential damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss) arising out of the use of or inability to use the <b>SOFTWARE</b> or the provision of or failure to provide support services, even if <b>quviq</b> has been advised of the possibility of such damages. In any case, <b>Quviq’s</b> entire liability under any provision of this eula shall be limited to the amount actually paid by you for the <b>SOFTWARE</b>.</p>
|
||||
<p class="p4"><br></p>
|
||||
<p class="p10"><br></p>
|
||||
</body>
|
||||
</html>
|
1
lib/eqc/LicenceAgreement.rtf
Normal file
1
lib/eqc/LicenceAgreement.rtf
Normal file
File diff suppressed because one or more lines are too long
27
lib/eqc/README
Normal file
27
lib/eqc/README
Normal file
|
@ -0,0 +1,27 @@
|
|||
QuickCheck Mini
|
||||
|
||||
This is a fully functional stripped down version of Quviq QuickCheck.
|
||||
|
||||
QuickCheck Mini is free of charge and the latest version can be
|
||||
downloaded from Quviq's homepage. The Mini version of QuickCheck is
|
||||
intended to support individuals and open source projects in obtaining
|
||||
a better code quality without having to invest in the full version of
|
||||
QuickCheck.
|
||||
|
||||
QuickCheck Mini is installed by copying the complete directory
|
||||
eqc-.... into the Erlang library directory or by pointing to it by
|
||||
using the code:add_patha/1 function in the Erlang distribution.
|
||||
|
||||
Examples are provided to illustrate how it works.
|
||||
|
||||
You can subscribe to quickcheck-questions@quviq.com by sending
|
||||
"Subscribe" in the subject line. This is a community email list around
|
||||
the use of QuickCheck.
|
||||
|
||||
Please note that although QuickCheck Mini does not require a licence
|
||||
check with the Quviq licence server, it does check for a new version
|
||||
each time it is started, and will notify you if one is available. No
|
||||
other information is included in the request, and QuickCheck Mini will
|
||||
start regardless of whether or not the version check succeeds, but
|
||||
(because there is a short time-out) will start slightly more quickly
|
||||
when it succeeds.
|
2
lib/eqc/doc/edoc-info
Normal file
2
lib/eqc/doc/edoc-info
Normal file
|
@ -0,0 +1,2 @@
|
|||
{packages,[]}.
|
||||
{modules,[eqc,eqc_gen,eqc_symbolic]}.
|
385
lib/eqc/doc/eqc.html
Normal file
385
lib/eqc/doc/eqc.html
Normal file
|
@ -0,0 +1,385 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Module eqc</title>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
||||
<hr>
|
||||
|
||||
<h1>Module eqc</h1>
|
||||
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#types">Data Types</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>This module defines functions for writing and testing QuickCheck properties.
|
||||
|
||||
<p><b>Version:</b> 1.0.1</p>
|
||||
|
||||
<h2><a name="description">Description</a></h2>This module defines functions for writing and testing QuickCheck properties.
|
||||
Much of the interface is provided via macros (defined in <tt>eqc.hrl</tt>).
|
||||
These are documented below:
|
||||
<h2><tt>?FORALL(X,Gen,Prop)</tt></h2>
|
||||
Property that holds if <tt>Prop</tt> holds for all values <tt>X</tt> that
|
||||
can be generated by <tt>Gen</tt>. For example,
|
||||
<pre>
|
||||
prop_reverse() ->
|
||||
?FORALL(Xs,list(int()),
|
||||
lists:reverse(lists:reverse(Xs)) == Xs).
|
||||
</pre>
|
||||
Generators are defined using the module <a href="eqc_gen.html"><code>eqc_gen</code></a>.
|
||||
<h2><tt>?IMPLIES(Pre,Prop)</tt></h2>
|
||||
Property that holds if <tt>Prop</tt> holds whenever the precondition
|
||||
<tt>Pre</tt> is true. The precondition must be a boolean, but <tt>Prop</tt>
|
||||
can be any QuickCheck property. An implication is tested by discarding test
|
||||
cases which do not satisfy the precondition. This can make testing slow,
|
||||
since many more test cases may need to be generated to find 100 which
|
||||
satisfy the precondition. In the worst case, QuickCheck may not be able
|
||||
to find enough test cases that do satisfy the precondition, in which case
|
||||
the number actually found is reported. Some preconditions may also skew
|
||||
the test data badly--for example, a precondition that a list is sorted
|
||||
skews the test data towards short lists, since random longer lists are
|
||||
extremely unlikely to be sorted just by chance. <tt>?IMPLIES</tt> works
|
||||
well for preconditions which are true with a high probability, but if the
|
||||
precondition is unlikely to hold, then it is better to write a custom
|
||||
generator which generates test cases where the precondition is true.
|
||||
<h2><tt>?WHENFAIL(Action,Prop)</tt></h2><p>
|
||||
Property that is equivalent to <tt>Prop</tt>, but performs <tt>Action</tt>
|
||||
(for its side effects) when <tt>Prop</tt> fails. This can be used to
|
||||
print additional information when a test case fails.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h2><a name="types">Data Types</a></h2>
|
||||
|
||||
<h3 class="typedecl"><a name="type-counterexample">counterexample()</a></h3>
|
||||
<p><b>abstract datatype</b>: <tt>counterexample()</tt></p>
|
||||
<p>A counter-example to a QuickCheck property, which can be obtained
|
||||
using <a href="#counterexample-0"><code>counterexample/0</code></a> or <a href="#counterexample-1"><code>counterexample/1</code></a>, and used to repeat a test,
|
||||
or test a different property in the same case. Counterexamples are represented by the values
|
||||
bound by ?FORALL--for the counterexample to make sense independently, it's important that
|
||||
these were generated without side-effects.</p>
|
||||
|
||||
<h3 class="typedecl"><a name="type-print_method">print_method()</a></h3>
|
||||
<p><tt>print_method() = (list(term())) -> any()</tt></p>
|
||||
<p>A function for
|
||||
printing statistics, which is passed a list of samples and is
|
||||
expected to print statistical information about them. Print methods
|
||||
are used by <a href="#collect-3"><code>collect/3</code></a> and <a href="#aggregate-3"><code>aggregate/3</code></a>.</p>
|
||||
|
||||
<h3 class="typedecl"><a name="type-property">property()</a></h3>
|
||||
<p><b>abstract datatype</b>: <tt>property()</tt></p>
|
||||
<p>QuickCheck properties, which can either be boolean
|
||||
expressions, or constructed using the functions in this module.
|
||||
QuickCheck properties are tested using <a href="#quickcheck-1"><code>quickcheck/1</code></a>.</p>
|
||||
|
||||
<h2><a name="index">Function Index</a></h2>
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#aggregate-2">aggregate/2</a></td><td>A property logically equivalent to <tt>Prop</tt>, but which collects a list of values in
|
||||
each test, and displays the distribution of these values once
|
||||
testing is complete.</td></tr>
|
||||
<tr><td valign="top"><a href="#aggregate-3">aggregate/3</a></td><td>Like <a href="#aggregate-2"><code>aggregate/2</code></a>, but allows the user to specify how
|
||||
the collected values should be printed.</td></tr>
|
||||
<tr><td valign="top"><a href="#backtrace-0">backtrace/0</a></td><td>Displays a stack backtrace from the last exception QuickCheck caught.</td></tr>
|
||||
<tr><td valign="top"><a href="#check-2">check/2</a></td><td>Tests the property in the case given.</td></tr>
|
||||
<tr><td valign="top"><a href="#classify-3">classify/3</a></td><td>Property which is logically equivalent to <tt>Prop</tt>, but also
|
||||
classifies test cases and displays the distribution of test case classes
|
||||
when testing is complete.</td></tr>
|
||||
<tr><td valign="top"><a href="#collect-2">collect/2</a></td><td>Equivalent to <a href="#aggregate-2"><tt>aggregate([S], Prop)</tt></a>.
|
||||
</td></tr>
|
||||
<tr><td valign="top"><a href="#collect-3">collect/3</a></td><td>Equivalent to <a href="#aggregate-3"><tt>aggregate(PrintMethod, [S], Prop)</tt></a>.
|
||||
</td></tr>
|
||||
<tr><td valign="top"><a href="#counterexample-0">counterexample/0</a></td><td>Returns the last counter-example found.</td></tr>
|
||||
<tr><td valign="top"><a href="#counterexample-1">counterexample/1</a></td><td>Tests the property in the same way as <a href="#quickcheck-1"><code>quickcheck/1</code></a>, but if
|
||||
a test fails, then the failing test case is returned as a counterexample.</td></tr>
|
||||
<tr><td valign="top"><a href="#counterexamples-0">counterexamples/0</a></td><td>Returns a list of the counterexamples found by the last call
|
||||
of <code>eqc:module</code>, paired with the name of the property that failed.</td></tr>
|
||||
<tr><td valign="top"><a href="#current_counterexample-0">current_counterexample/0</a></td><td>Returns the most recent
|
||||
counterexample found by QuickCheck.</td></tr>
|
||||
<tr><td valign="top"><a href="#equals-2">equals/2</a></td><td>A property which holds if X and Y are equal...</td></tr>
|
||||
<tr><td valign="top"><a href="#fails-1">fails/1</a></td><td>A property which succeeds when its argument fails.</td></tr>
|
||||
<tr><td valign="top"><a href="#measure-3">measure/3</a></td><td>Collects the values of X while testing Prop, and if all tests
|
||||
pass, displays statistics such as the minimum, average, and maximum
|
||||
values, identified by the name Name.</td></tr>
|
||||
<tr><td valign="top"><a href="#module-1">module/1</a></td><td>Tests all the properties exported from a module, given the module name.</td></tr>
|
||||
<tr><td valign="top"><a href="#numtests-2">numtests/2</a></td><td>Property which is logically equivalent to <tt>Prop</tt>, but is
|
||||
tested <tt>N</tt> times rather than 100.</td></tr>
|
||||
<tr><td valign="top"><a href="#on_output-2">on_output/2</a></td><td>Supplies an output function to be used instead of io:format
|
||||
when QuickCheck generates output.</td></tr>
|
||||
<tr><td valign="top"><a href="#on_test-2">on_test/2</a></td><td>Attaches a function to a property which is called every time a
|
||||
test passes or fails.</td></tr>
|
||||
<tr><td valign="top"><a href="#quickcheck-1">quickcheck/1</a></td><td>Tests the property in 100 random cases, printing a counter-example
|
||||
if one is found.</td></tr>
|
||||
<tr><td valign="top"><a href="#recheck-1">recheck/1</a></td><td>Tests the property with the <i>same</i> random number seed as
|
||||
the last failing call of <a href="#quickcheck-1"><code>quickcheck/1</code></a>.</td></tr>
|
||||
<tr><td valign="top"><a href="#start-0">start/0</a></td><td>Equivalent to <a href="#start-1"><tt>start(true)</tt></a>.
|
||||
</td></tr>
|
||||
<tr><td valign="top"><a href="#start-1">start/1</a></td><td>Starts the QuickCheck server.</td></tr>
|
||||
<tr><td valign="top"><a href="#stop-0">stop/0</a></td><td>Stops the QuickCheck server.</td></tr>
|
||||
<tr><td valign="top"><a href="#version-0">version/0</a></td><td></td></tr>
|
||||
<tr><td valign="top"><a href="#with_title-1">with_title/1</a></td><td>A printing method for collected data, which displays a title
|
||||
before
|
||||
the percentages of each value in the data.</td></tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="functions">Function Details</a></h2>
|
||||
|
||||
<h3 class="function"><a name="aggregate-2">aggregate/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>aggregate(L::list(term()), Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>A property logically equivalent to <tt>Prop</tt>, but which collects a list of values in
|
||||
each test, and displays the distribution of these values once
|
||||
testing is complete. A typical use would be to aggregate the list of command names generated
|
||||
by <a href="eqc_statem.html#commands-1"><code>eqc_statem:commands/1</code></a>, in order to see how often each individual
|
||||
command appeared in generated tests:
|
||||
<pre>aggregate(command_names(Cmds), ...) </pre>
|
||||
<p>
|
||||
See also <a href="#aggregate-3"><code>aggregate/3</code></a>.
|
||||
</p></p>
|
||||
|
||||
<h3 class="function"><a name="aggregate-3">aggregate/3</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>aggregate(PrintMethod::(list(term())) -> any(), L::list(term()), Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>Like <a href="#aggregate-2"><code>aggregate/2</code></a>, but allows the user to specify how
|
||||
the collected values should be printed. The <tt>PrintMethod</tt> parameter
|
||||
is called with a sorted list of the collected data as an argument,
|
||||
and is expected to print some statistics. A predefined printing
|
||||
methods is provided to add a title to the statistics:
|
||||
<pre>aggregate(with_title(T),L,Prop)</pre>. This is useful when a property contains
|
||||
several calls to aggregate or collect.</p>
|
||||
|
||||
<h3 class="function"><a name="backtrace-0">backtrace/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>backtrace() -> ok</tt></p>
|
||||
</div><p>Displays a stack backtrace from the last exception QuickCheck caught. Note that
|
||||
this is only possible if the exception is raised in the process in which the test
|
||||
case starts. If a test case fails because of an exception in another, linked,
|
||||
process, then no backtrace is available. Calls to functions in the implementation
|
||||
of QuickCheck itself are not included in the backtrace.
|
||||
<p>If you really need to see a backtrace from a linked process, then you can do so by
|
||||
catching
|
||||
the exception yourself in that process, using erlang:get_stacktrace() to obtain the
|
||||
backtrace, and printing it yourself.</p></p>
|
||||
|
||||
<h3 class="function"><a name="check-2">check/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>check(P::<a href="#type-property">property()</a>, Values::<a href="#type-counterexample">counterexample()</a>) -> bool()</tt></p>
|
||||
</div><p>Tests the property in the case given. Counterexamples are generated by testing a
|
||||
property using <a href="#counterexample-1"><code>counterexample/1</code></a> or <a href="#counterexample-0"><code>counterexample/0</code></a>, and contain a list
|
||||
of the values bound by ?FORALL. A property tested by check should begin with the <i>same</i>
|
||||
sequence of ?FORALL s as the property from which the counterexample was generated, otherwise
|
||||
the results will be unpredictable. In particular, there is no check that the values
|
||||
in the counterexample could actually have been generated by the ?FORALL s in the property under
|
||||
test.
|
||||
<p><a href="#check-2"><code>check/2</code></a> can be used without a QuickCheck licence, allowing anyone to run
|
||||
tests that a licenced user has generated.</p></p>
|
||||
|
||||
<h3 class="function"><a name="classify-3">classify/3</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>classify(B::bool(), S::term(), Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>Property which is logically equivalent to <tt>Prop</tt>, but also
|
||||
classifies test cases and displays the distribution of test case classes
|
||||
when testing is complete. If the boolean is true then the current test case is
|
||||
labelled with the term <tt>S</tt>,
|
||||
and, after testing is complete, QuickCheck prints out the percentage of
|
||||
test cases carrying each label. This can be used to check that the space
|
||||
of possible test cases has been covered reasonably well. For example,
|
||||
classifying test cases according to the length of a list enables one to
|
||||
see whether unreasonably many lists were short. Classifying
|
||||
test cases is a way to discover skewed distributions, such as can arise
|
||||
from using <tt>?IMPLIES</tt>. It is good practice to check the distribution
|
||||
of test data using <tt>classify</tt> or <a href="#collect-2"><code>collect/2</code></a>, at least while
|
||||
properties are being developed.
|
||||
<p>
|
||||
Each test case can be labelled with any number of labels: QuickCheck then
|
||||
displays the percentage of each label in the generated
|
||||
test data.
|
||||
</p>
|
||||
<p>
|
||||
Calls of classify or collect can be nested, in which case each call
|
||||
generates its own table of distributions.
|
||||
</p></p>
|
||||
|
||||
<h3 class="function"><a name="collect-2">collect/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>collect(S::term(), Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>Equivalent to <a href="#aggregate-2"><tt>aggregate([S], Prop)</tt></a>.</p>
|
||||
|
||||
|
||||
<h3 class="function"><a name="collect-3">collect/3</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>collect(PrintMethod::(list(term())) -> any(), S::term(), Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>Equivalent to <a href="#aggregate-3"><tt>aggregate(PrintMethod, [S], Prop)</tt></a>.</p>
|
||||
|
||||
|
||||
<h3 class="function"><a name="counterexample-0">counterexample/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>counterexample() -> undefined | <a href="#type-counterexample">counterexample()</a></tt></p>
|
||||
</div><p>Returns the last counter-example found. See <a href="#counterexample-1"><code>counterexample/1</code></a>.</p>
|
||||
|
||||
<h3 class="function"><a name="counterexample-1">counterexample/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>counterexample(P::<a href="#type-property">property()</a>) -> true | <a href="#type-counterexample">counterexample()</a></tt></p>
|
||||
</div><p>Tests the property in the same way as <a href="#quickcheck-1"><code>quickcheck/1</code></a>, but if
|
||||
a test fails, then the failing test case is returned as a counterexample.</p>
|
||||
|
||||
<h3 class="function"><a name="counterexamples-0">counterexamples/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>counterexamples() -> list({atom(), <a href="#type-counterexample">counterexample()</a>})</tt></p>
|
||||
</div><p>Returns a list of the counterexamples found by the last call
|
||||
of <code>eqc:module</code>, paired with the name of the property that failed.</p>
|
||||
|
||||
<h3 class="function"><a name="current_counterexample-0">current_counterexample/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>current_counterexample() -> <a href="#type-counterexample">counterexample()</a></tt></p>
|
||||
</div><p>Returns the most recent
|
||||
counterexample found by QuickCheck. This can be used while
|
||||
QuickCheck is shrinking a failed test case to follow progress, or if
|
||||
shrinking must be interrupted, to recover the last failed test case
|
||||
that QuickCheck had found. The counterexample is fetched from a file
|
||||
in the current directory.</p>
|
||||
|
||||
<h3 class="function"><a name="equals-2">equals/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>equals(X::any(), Y::any()) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>A property which holds if X and Y are equal... and displays
|
||||
their values when a test fails.</p>
|
||||
|
||||
<h3 class="function"><a name="fails-1">fails/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>fails(P::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>A property which succeeds when its argument fails.
|
||||
Sometimes it is useful to write down properties which do <i>not</i> hold
|
||||
(even though one might expect them to). This can help prevent misconceptions.
|
||||
<tt>fails(P)</tt> is tested in the same way as <tt>P</tt>, but
|
||||
fails only if <tt>P</tt> <i>succeeds</i> 100 times. Thus
|
||||
<tt>fails(P)</tt> declares that QuickCheck should be able to find
|
||||
a counter-example to property <tt>P</tt>.</p>
|
||||
|
||||
<h3 class="function"><a name="measure-3">measure/3</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>measure(Name::atom() | string(), X::number() | list(number()), Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>Collects the values of X while testing Prop, and if all tests
|
||||
pass, displays statistics such as the minimum, average, and maximum
|
||||
values, identified by the name Name. X can also be a list of values,
|
||||
in which case all of them are included in the measurements.</p>
|
||||
|
||||
<h3 class="function"><a name="module-1">module/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>module(Mod::atom()) -> list(atom())</tt></p>
|
||||
</div><p>Tests all the properties exported from a module, given the module name.
|
||||
Any function with arity zero whose name begins with "prop_" is treated as a
|
||||
property. The result is a list of the names of the properties that
|
||||
failed. See also <a href="#module-2"><code>module/2</code></a>.</p>
|
||||
|
||||
<h3 class="function"><a name="numtests-2">numtests/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>numtests(N::<a href="#type-int">int()</a>, Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>Property which is logically equivalent to <tt>Prop</tt>, but is
|
||||
tested <tt>N</tt> times rather than 100. If numtests appears more than once
|
||||
in a property, then the outermost use takes precedence.</p>
|
||||
|
||||
<h3 class="function"><a name="on_output-2">on_output/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>on_output(Fun::(string(), list(term())) -> any(), Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>Supplies an output function to be used instead of io:format
|
||||
when QuickCheck generates output. All output generated by
|
||||
QuickCheck is passed to <tt>Fun</tt>, in the form of a format
|
||||
string and a list of terms--the same arguments expected by
|
||||
<tt>io:format</tt>. By supplying a function which does nothing,
|
||||
QuickCheck can be run silently. By supplying a function which
|
||||
writes to a file, all QuickCheck output can be saved.
|
||||
<p>Note that output generated by user code is <i>not</i> passed to
|
||||
this output function. For example, calls to io:format in the
|
||||
property, or in the code under test, will generate output in the
|
||||
shell as usual. This applies even to calls inside a
|
||||
<tt>?WHENFAIL</tt>. If you want to redirect such output also, then
|
||||
you need to modify your own code appropriately.</p>
|
||||
<p>The reason that <tt>Fun</tt> is passed a format string and
|
||||
arguments, rather than an already formatted string, is to make it
|
||||
easier to extract information from the output without parsing
|
||||
it. However, there is no guarantee that different versions of
|
||||
QuickCheck will use the same format strings and term lists--you use
|
||||
this information at your own risk, in other words.</p></p>
|
||||
|
||||
<h3 class="function"><a name="on_test-2">on_test/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>on_test(Fun::(<a href="#type-counterexample">counterexample()</a>, bool()) -> any(), Prop::<a href="#type-property">property()</a>) -> <a href="#type-property">property()</a></tt></p>
|
||||
</div><p>Attaches a function to a property which is called every time a
|
||||
test passes or fails. The arguments are the test case (a list of
|
||||
values), and a boolean indicating whether or not the test
|
||||
passed. Tests which are skipped (because of an
|
||||
<tt>?IMPLIES(false,...)</tt>) are not included.</p>
|
||||
|
||||
<h3 class="function"><a name="quickcheck-1">quickcheck/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>quickcheck(P::<a href="#type-property">property()</a>) -> bool()</tt></p>
|
||||
</div><p>Tests the property in 100 random cases, printing a counter-example
|
||||
if one is found. Initially small test cases are generated, then the
|
||||
size increases as testing progresses (see <a href="eqc_gen.html"><code>eqc_gen</code></a>, <tt>?SIZED</tt>,
|
||||
<a href="eqc_gen.html#resize-2"><code>eqc_gen:resize/2</code></a> for the way size affects test data generation).
|
||||
The result is <tt>true</tt> if all tests succeeded (or if one failed,
|
||||
and failure was expected). On success, <tt>quickcheck</tt> analyses
|
||||
the distribution of test case labels. On failure, <tt>quickcheck</tt>
|
||||
tries to simplify the counter-example found as far as possible (see <i>
|
||||
shrinking</i>, described in <a href="eqc_gen.html"><code>eqc_gen</code></a>).</p>
|
||||
|
||||
<h3 class="function"><a name="recheck-1">recheck/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>recheck(Prop::<a href="#type-property">property()</a>) -> bool()</tt></p>
|
||||
</div><p>Tests the property with the <i>same</i> random number seed as
|
||||
the last failing call of <a href="#quickcheck-1"><code>quickcheck/1</code></a>. If the property is
|
||||
the same as in that last call, then the same test case will be
|
||||
generated. Note that recheck repeats the test <i>and its
|
||||
shrinking</i>. This can be used to adjust the shrinking strategy in
|
||||
the property, then reshrink the same counterexample, perhaps to a
|
||||
better result. If you just
|
||||
want to repeat the <i>shrunk</i> test, then use
|
||||
<pre>eqc:check(Prop,eqc:counterexample())</pre> instead.
|
||||
<p><b>Note:</b> the type and behaviour of recheck changed in version 1.19.</p></p>
|
||||
|
||||
<h3 class="function"><a name="start-0">start/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>start() -> any()</tt></p>
|
||||
</div><p>Equivalent to <a href="#start-1"><tt>start(true)</tt></a>.</p>
|
||||
|
||||
|
||||
<h3 class="function"><a name="start-1">start/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>start(Force::bool()) -> pid()</tt></p>
|
||||
</div><p><p>Starts the QuickCheck server. If it is already running on this
|
||||
node, nothing is done.</p>
|
||||
|
||||
Each user can run only one instance of the QuickCheck server at a
|
||||
time. If the server is already running on another Erlang node, it
|
||||
will be terminated automatically if <tt>Force</tt> is
|
||||
<tt>true</tt>. If another instance is running, and <tt>Force</tt> is
|
||||
<tt>false</tt>, then the new instance will not start.</p>
|
||||
|
||||
<h3 class="function"><a name="stop-0">stop/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>stop() -> any()</tt></p>
|
||||
</div><p>Stops the QuickCheck server.
|
||||
QuickCheck properties are tested in the QuickCheck server process, which is
|
||||
spawned automatically when quickcheck is first called. Usually there is no
|
||||
need to stop the QuickCheck server explicitly, but if a need does arise
|
||||
then this function can be used. For example, if the shell process crashes
|
||||
and is restarted, then the QuickCheck server should be stopped and restarted
|
||||
too, since otherwise the server will crash when it attempts to write to the
|
||||
console.</p>
|
||||
|
||||
<h3 class="function"><a name="version-0">version/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>version() -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="with_title-1">with_title/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>with_title(Title::atom() | string()) -> <a href="#type-print_method">print_method()</a></tt></p>
|
||||
</div><p>A printing method for collected data, which displays a title
|
||||
before
|
||||
the percentages of each value in the data. It is intended to be
|
||||
passed to <a href="#collect-3"><code>collect/3</code></a> or <a href="#aggregate-3"><code>aggregate/3</code></a>.</p>
|
||||
<hr>
|
||||
|
||||
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
||||
<p><i>Generated by EDoc, Jun 13 2010, 13:15:30.</i></p>
|
||||
</body>
|
||||
</html>
|
342
lib/eqc/doc/eqc_gen.html
Normal file
342
lib/eqc/doc/eqc_gen.html
Normal file
|
@ -0,0 +1,342 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Module eqc_gen</title>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
||||
<hr>
|
||||
|
||||
<h1>Module eqc_gen</h1>
|
||||
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#types">Data Types</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
|
||||
This module implements QuickCheck generators.
|
||||
|
||||
<p><b>Version:</b> 1.0.1</p>
|
||||
|
||||
<h2><a name="description">Description</a></h2>
|
||||
This module implements QuickCheck generators.
|
||||
QuickCheck generators are used to generate random test data for
|
||||
QuickCheck properties. A generator specifies three things at the same
|
||||
time:
|
||||
<ul> <li> A <i>set</i> of values that can be generated,</li>
|
||||
<li> A <i>probability distribution</i> on that set,</li>
|
||||
<li> A way of <i>shrinking</i> generated values to similar,
|
||||
smaller values---used after a test fails, to enable
|
||||
QuickCheck to search for a similar, but simpler failing case.</li>
|
||||
</ul>
|
||||
QuickCheck permits constants to be used as generators for their own value,
|
||||
and also permits tuples, records, and lists containing generators to be
|
||||
used as generators for values of the same form. For example,
|
||||
<pre> {int(),bool()} </pre>
|
||||
is a generator that generates random pairs of integers and booleans.
|
||||
<p>
|
||||
Many of the functions in this module are usually used via macros, defined
|
||||
in <tt>eqc.hrl</tt>. These macros are listed here.
|
||||
<h2><tt>?LET(Pat,G1,G2)</tt></h2>
|
||||
Generates a value from <tt>G1</tt>,
|
||||
binds it to <tt>Pat</tt>, then generates a value from <tt>G2</tt>
|
||||
(which may refer to the variables bound in <tt>Pat</tt>).
|
||||
<p>The
|
||||
result is shrunk by <i>first</i> shrinking the value generated by
|
||||
<tt>G1</tt> while the test still fails, then shrinking the value
|
||||
generated by <tt>G2</tt>. It is thus better to write
|
||||
<tt>?LET({X,Y},{G1,G2},G3)</tt> than
|
||||
<tt>?LET(X,G1,?LET(Y,G2,G3))</tt> (provided <tt>G2</tt> does
|
||||
not depend on <tt>X</tt>), since in the first case shrinking can
|
||||
shrink <tt>G1</tt> a bit, shrink <tt>G2</tt>, then shrink
|
||||
<tt>G1</tt> some more, while in the second case <tt>G1</tt>
|
||||
cannot be shrunk further once shrinking <tt>G2</tt> has begun.</p>
|
||||
<h2><tt>?SIZED(Size,G)</tt></h2>
|
||||
Binds the variable <tt>Size</tt> to the current size parameter for
|
||||
generation. <tt>G</tt> may use <tt>Size</tt> in any way to control the
|
||||
size of generated data. However, as <tt>Size</tt> increases,
|
||||
the set of possible values that <tt>G</tt> can generate should also
|
||||
increase. <tt>Size</tt> is always a natural number, and increases during
|
||||
QuickCheck testing from a small value up to about 40. See also
|
||||
<a href="#resize-2"><code>resize/2</code></a> and <a href="#pick-2"><code>pick/2</code></a>.
|
||||
<h2><tt>?SUCHTHAT(X,G,P)</tt></h2>
|
||||
Generates values <tt>X</tt> from <tt>G</tt> such that the condition <tt>P</tt> is true.
|
||||
Should only be used if the probability that <tt>P</tt> holds is reasonably high for values
|
||||
generated by <tt>G</tt>--otherwise generation may be slow, and the
|
||||
distribution of generated values may be skewed. For example,
|
||||
<pre>?SUCHTHAT(Xs,list(int()),lists:sort(Xs)==Xs)</pre>
|
||||
generates predominantly very short lists, since the probability that a random longer list
|
||||
will just happen to be sorted is very low. If no value is found within 100 attempts,
|
||||
then ?SUCHTHAT exits.
|
||||
|
||||
|
||||
<h2><tt>?LETSHRINK(Pat,G1,G2)</tt></h2>
|
||||
This behaves in the same way as <tt>?LET(Pat,G1,G2)</tt>, <i>except</i>
|
||||
that <tt>G1</tt> must generate a <i>list</i> of values, and each one of these
|
||||
values is added as a possible shrinking of the result. This is intended for
|
||||
use in generating tree-like structures. For example,
|
||||
<pre>
|
||||
?LETSHRINK([L,R],[tree(),tree()],{branch,L,R})</pre>
|
||||
generates a tree node <tt>{branch,L,R}</tt>, which can shrink to either
|
||||
<tt>L</tt> or <tt>R</tt>.
|
||||
<h2><tt>?LAZY(G)</tt></h2>
|
||||
A generator equivalent to its argument, but which is always cheap to construct. To be used,
|
||||
for example, in recursive generators to avoid building a huge generator, only a small part
|
||||
of which will be used.
|
||||
</p>
|
||||
<h2><a name="types">Data Types</a></h2>
|
||||
|
||||
<h3 class="typedecl"><a name="type-box">box()</a></h3>
|
||||
<p><b>abstract datatype</b>: <tt>box(A)</tt></p>
|
||||
<p>Boxes are not supported in this version of QuickCheck.</p>
|
||||
|
||||
<h3 class="typedecl"><a name="type-gen">gen()</a></h3>
|
||||
<p><b>abstract datatype</b>: <tt>gen(A)</tt></p>
|
||||
<p>A QuickCheck generator for values of type A.
|
||||
QuickCheck generators are first-class
|
||||
values, and can be used repeatedly to generate many different values.</p>
|
||||
|
||||
<h3 class="typedecl"><a name="type-proplist">proplist()</a></h3>
|
||||
<p><tt>proplist() = list({atom(), term()})</tt></p>
|
||||
<p>A property list associating values with names.
|
||||
See the standard module <tt>proplists</tt>.</p>
|
||||
|
||||
<h2><a name="index">Function Index</a></h2>
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#binary-0">binary/0</a></td><td>Generates a binary of random size.</td></tr>
|
||||
<tr><td valign="top"><a href="#binary-1">binary/1</a></td><td>Generates a binary of a given size in bytes.</td></tr>
|
||||
<tr><td valign="top"><a href="#bitstring-0">bitstring/0</a></td><td>Generates a list of bits in a bitstring.</td></tr>
|
||||
<tr><td valign="top"><a href="#bitstring-1">bitstring/1</a></td><td>Generates a bitstring of a given size in bits.</td></tr>
|
||||
<tr><td valign="top"><a href="#bool-0">bool/0</a></td><td>Generates a random boolean.</td></tr>
|
||||
<tr><td valign="top"><a href="#char-0">char/0</a></td><td>Generates a random character.</td></tr>
|
||||
<tr><td valign="top"><a href="#choose-2">choose/2</a></td><td>Generates a number in the range M to N.</td></tr>
|
||||
<tr><td valign="top"><a href="#default-2">default/2</a></td><td>Adds a default value to a generator, to be chosen half the time.</td></tr>
|
||||
<tr><td valign="top"><a href="#elements-1">elements/1</a></td><td>Generates an element of the list argument.</td></tr>
|
||||
<tr><td valign="top"><a href="#eval-1">eval/1</a></td><td>Evaluates terms of the form <tt>{call,Module,Function,Args}</tt> anywhere in its
|
||||
argument, replacing them by the result of the corresponding function call.</td></tr>
|
||||
<tr><td valign="top"><a href="#eval-2">eval/2</a></td><td>Like <a href="#eval-1"><code>eval/1</code></a>, but also replaces symbolic variables, that is,
|
||||
terms of the form <tt>{var,V}</tt>, by their corresponding values in the
|
||||
property list.</td></tr>
|
||||
<tr><td valign="top"><a href="#frequency-1">frequency/1</a></td><td>Makes a weighted choice between the generators in its argument, such that the
|
||||
probability of choosing each generator is proportional to the weight paired with it.</td></tr>
|
||||
<tr><td valign="top"><a href="#function0-1">function0/1</a></td><td>Generates a function of no arguments with result generated by <tt>G</tt>.</td></tr>
|
||||
<tr><td valign="top"><a href="#function1-1">function1/1</a></td><td>Generates a function of one argument with result generated by <tt>G</tt>.</td></tr>
|
||||
<tr><td valign="top"><a href="#int-0">int/0</a></td><td>Generates a small integer (with absolute value bounded by the generation size).</td></tr>
|
||||
<tr><td valign="top"><a href="#is_generator-1">is_generator/1</a></td><td>Returns true if the argument is a QuickCheck generator.</td></tr>
|
||||
<tr><td valign="top"><a href="#largeint-0">largeint/0</a></td><td>Generates an integer from a large range.</td></tr>
|
||||
<tr><td valign="top"><a href="#list-1">list/1</a></td><td>Generates a list of elements generated by its argument.</td></tr>
|
||||
<tr><td valign="top"><a href="#nat-0">nat/0</a></td><td>Generates a small natural number (bounded by the generation size).</td></tr>
|
||||
<tr><td valign="top"><a href="#non_empty-1">non_empty/1</a></td><td>Make sure that the generated value is not empty.</td></tr>
|
||||
<tr><td valign="top"><a href="#noshrink-1">noshrink/1</a></td><td>Generates the same values as <tt>G</tt>, but these values are never
|
||||
shrunk.</td></tr>
|
||||
<tr><td valign="top"><a href="#oneof-1">oneof/1</a></td><td>Generates a value using a randomly chosen element of the list of generators.</td></tr>
|
||||
<tr><td valign="top"><a href="#orderedlist-1">orderedlist/1</a></td><td>Generates an ordered list of elements generated by <tt>G</tt>.</td></tr>
|
||||
<tr><td valign="top"><a href="#real-0">real/0</a></td><td>Generates a real number.</td></tr>
|
||||
<tr><td valign="top"><a href="#resize-2">resize/2</a></td><td>Binds the generation size parameter to <tt>Size</tt> within <tt>G</tt>.</td></tr>
|
||||
<tr><td valign="top"><a href="#return-1">return/1</a></td><td>Constructs a generator that always generates the value
|
||||
<tt>X</tt>.</td></tr>
|
||||
<tr><td valign="top"><a href="#sample-1">sample/1</a></td><td>Prints 11 values randomly generated by <tt>G</tt>, for sizes ranging
|
||||
from 10 to 20.</td></tr>
|
||||
<tr><td valign="top"><a href="#sampleshrink-1">sampleshrink/1</a></td><td>Prints a value generated by <tt>G</tt>, followed by one way of shrinking it.</td></tr>
|
||||
<tr><td valign="top"><a href="#shuffle-1">shuffle/1</a></td><td>Shuffles a list and shrinks to the unshuffled list.</td></tr>
|
||||
<tr><td valign="top"><a href="#vector-2">vector/2</a></td><td>Generates a list of the given length, with elements generated by <tt>G</tt>.</td></tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="functions">Function Details</a></h2>
|
||||
|
||||
<h3 class="function"><a name="binary-0">binary/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>binary() -> <a href="#type-gen">gen(binary())</a></tt></p>
|
||||
</div><p>Generates a binary of random size. The binary shrinks both in
|
||||
size as well as in content. If you consider the
|
||||
binary as a representation of a number, then each shrinking step
|
||||
will result in a smaller-or-equal number.</p>
|
||||
|
||||
<h3 class="function"><a name="binary-1">binary/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>binary(NrBytes::<a href="#type-int">int()</a>) -> <a href="#type-gen">gen(binary())</a></tt></p>
|
||||
</div><p>Generates a binary of a given size in bytes. When shrinking,
|
||||
the size is unchanged, but content shrinks like <a href="#binary-0"><code>binary/0</code></a>.</p>
|
||||
|
||||
<h3 class="function"><a name="bitstring-0">bitstring/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>bitstring() -> <a href="#type-gen">gen(<a href="#type-bitstring">bitstring()</a>)</a></tt></p>
|
||||
</div><p>Generates a list of bits in a bitstring. For Erlang release R12B and
|
||||
later.
|
||||
The bitstring shrinks both in
|
||||
size as well as in content. If you consider the
|
||||
bitstring as a representation of a number, then each shrinking step
|
||||
will result in a smaller-or-equal number.</p>
|
||||
|
||||
<h3 class="function"><a name="bitstring-1">bitstring/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>bitstring(NrBits::<a href="#type-int">int()</a>) -> <a href="#type-gen">gen(<a href="#type-bitstring">bitstring()</a>)</a></tt></p>
|
||||
</div><p>Generates a bitstring of a given size in bits. For Erlang
|
||||
release R12B and later. When shrinking,
|
||||
the size is unchanged, but content shrinks like <a href="#bitstring-0"><code>bitstring/0</code></a>.</p>
|
||||
|
||||
<h3 class="function"><a name="bool-0">bool/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>bool() -> <a href="#type-gen">gen(bool())</a></tt></p>
|
||||
</div><p>Generates a random boolean. Shrinks to false.</p>
|
||||
|
||||
<h3 class="function"><a name="char-0">char/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>char() -> <a href="#type-gen">gen(char())</a></tt></p>
|
||||
</div><p>Generates a random character. Shrinks to a, b or c.</p>
|
||||
|
||||
<h3 class="function"><a name="choose-2">choose/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>choose(M, N::integer()) -> <a href="#type-gen">gen(integer())</a></tt></p>
|
||||
</div><p>Generates a number in the range M to N.
|
||||
The result shrinks towards smaller absolute values.</p>
|
||||
|
||||
<h3 class="function"><a name="default-2">default/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>default(Default::A, G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen(A)</a></tt></p>
|
||||
</div><p>Adds a default value to a generator, to be chosen half the time. Any
|
||||
other value shrinks to the default.</p>
|
||||
|
||||
<h3 class="function"><a name="elements-1">elements/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>elements(Xs::list(A)) -> <a href="#type-gen">gen(A)</a></tt></p>
|
||||
</div><p>Generates an element of the list argument. Shrinking chooses an earlier element.</p>
|
||||
|
||||
<h3 class="function"><a name="eval-1">eval/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>eval(Term::term()) -> term()</tt></p>
|
||||
</div><p>Evaluates terms of the form <tt>{call,Module,Function,Args}</tt> anywhere in its
|
||||
argument, replacing them by the result of the corresponding function call.
|
||||
This is useful when, for example, test data is of an abstract datatype, and
|
||||
we want to know how it was generated, rather than its representation--it is
|
||||
much clearer to see that a test failed for <tt>sets:new()</tt> (that is
|
||||
<tt>{call,sets,new,[]}</tt>), for example,
|
||||
than for its representation.
|
||||
We write <tt>?FORALL(X,TGen,...eval(X)...)</tt>, where <tt>TGen</tt>
|
||||
generates terms containing calls, so that test cases are displayed in this
|
||||
form, but the actual test data is the result of evaluating the calls.</p>
|
||||
|
||||
<h3 class="function"><a name="eval-2">eval/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>eval(Env::<a href="#type-proplist">proplist()</a>, T::term()) -> term()</tt></p>
|
||||
</div><p>Like <a href="#eval-1"><code>eval/1</code></a>, but also replaces symbolic variables, that is,
|
||||
terms of the form <tt>{var,V}</tt>, by their corresponding values in the
|
||||
property list. This should be a list of pairs of atoms and values. For example,
|
||||
<tt>eval([{x,3}],{var,x})</tt> evaluates to 3.</p>
|
||||
|
||||
<h3 class="function"><a name="frequency-1">frequency/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>frequency(FGs::list({integer(), <a href="#type-gen">gen(A)</a>})) -> <a href="#type-gen">gen(A)</a></tt></p>
|
||||
</div><p>Makes a weighted choice between the generators in its argument, such that the
|
||||
probability of choosing each generator is proportional to the weight paired with it.
|
||||
The
|
||||
weights should be non-negative integers and sum to a positive value. A generator
|
||||
with a weight of zero will not be chosen.</p>
|
||||
|
||||
<h3 class="function"><a name="function0-1">function0/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>function0(G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen(() -> A)</a></tt></p>
|
||||
</div><p>Generates a function of no arguments with result generated by <tt>G</tt>.</p>
|
||||
|
||||
<h3 class="function"><a name="function1-1">function1/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>function1(G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen((term()) -> A)</a></tt></p>
|
||||
</div><p>Generates a function of one argument with result generated by <tt>G</tt>.
|
||||
The generated function is pure--will always return the same result for the same argument--
|
||||
and the result depends randomly on the argument.</p>
|
||||
|
||||
<h3 class="function"><a name="int-0">int/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>int() -> <a href="#type-gen">gen(integer())</a></tt></p>
|
||||
</div><p>Generates a small integer (with absolute value bounded by the generation size).</p>
|
||||
|
||||
<h3 class="function"><a name="is_generator-1">is_generator/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>is_generator(X::any()) -> bool()</tt></p>
|
||||
</div><p>Returns true if the argument is a QuickCheck generator.</p>
|
||||
|
||||
<h3 class="function"><a name="largeint-0">largeint/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>largeint() -> any()</tt></p>
|
||||
</div><p>Generates an integer from a large range.</p>
|
||||
|
||||
<h3 class="function"><a name="list-1">list/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>list(G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen(list(A))</a></tt></p>
|
||||
</div><p>Generates a list of elements generated by its argument. Shrinking drops elements
|
||||
from the list. The length of the list varies up to one third of the generation size parameter.</p>
|
||||
|
||||
<h3 class="function"><a name="nat-0">nat/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>nat() -> <a href="#type-gen">gen(integer())</a></tt></p>
|
||||
</div><p>Generates a small natural number (bounded by the generation size).</p>
|
||||
|
||||
<h3 class="function"><a name="non_empty-1">non_empty/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>non_empty(G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen(A)</a></tt></p>
|
||||
</div><p>Make sure that the generated value is not empty.
|
||||
For example when creating a list of integers, but the list should always
|
||||
contain at least one element <tt>non_empty(list(int()))</tt>.</p>
|
||||
|
||||
<h3 class="function"><a name="noshrink-1">noshrink/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>noshrink(G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen(A)</a></tt></p>
|
||||
</div><p>Generates the same values as <tt>G</tt>, but these values are never
|
||||
shrunk.</p>
|
||||
|
||||
<h3 class="function"><a name="oneof-1">oneof/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>oneof(Gs::list(<a href="#type-gen">gen(A)</a>)) -> <a href="#type-gen">gen(A)</a></tt></p>
|
||||
</div><p>Generates a value using a randomly chosen element of the list of generators.</p>
|
||||
|
||||
<h3 class="function"><a name="orderedlist-1">orderedlist/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>orderedlist(G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen(list(A))</a></tt></p>
|
||||
</div><p>Generates an ordered list of elements generated by <tt>G</tt>.</p>
|
||||
|
||||
<h3 class="function"><a name="real-0">real/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>real() -> <a href="#type-gen">gen(float())</a></tt></p>
|
||||
</div><p>Generates a real number.</p>
|
||||
|
||||
<h3 class="function"><a name="resize-2">resize/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>resize(Size::integer(), G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen(A)</a></tt></p>
|
||||
</div><p>Binds the generation size parameter to <tt>Size</tt> within <tt>G</tt>.
|
||||
Size should never be negative.</p>
|
||||
|
||||
<h3 class="function"><a name="return-1">return/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>return(X::A) -> <a href="#type-gen">gen(A)</a></tt></p>
|
||||
</div><p>Constructs a generator that always generates the value
|
||||
<tt>X</tt>. Most values can also be used as generators for
|
||||
themselves, making <tt>return</tt> unnecessary, but
|
||||
<tt>return(X)</tt> may be more efficient than using <tt>X</tt> as a
|
||||
generator, since when <tt>return(X)</tt> is used then QuickCheck
|
||||
does not traverse <tt>X</tt> searching for values to be intepreted
|
||||
specially.</p>
|
||||
|
||||
<h3 class="function"><a name="sample-1">sample/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>sample(G::<a href="#type-gen">gen(A)</a>) -> ok</tt></p>
|
||||
</div><p>Prints 11 values randomly generated by <tt>G</tt>, for sizes ranging
|
||||
from 10 to 20.</p>
|
||||
|
||||
<h3 class="function"><a name="sampleshrink-1">sampleshrink/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>sampleshrink(G::<a href="#type-gen">gen(A)</a>) -> ok</tt></p>
|
||||
</div><p>Prints a value generated by <tt>G</tt>, followed by one way of shrinking it.
|
||||
Each following line displays a list of values that the <i>first</i> value on the
|
||||
previous line can be shrunk to in one step. Thus the output traces the leftmost path
|
||||
through the shrinking tree.</p>
|
||||
|
||||
<h3 class="function"><a name="shuffle-1">shuffle/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>shuffle(List::list(A)) -> <a href="#type-gen">gen(list(A))</a></tt></p>
|
||||
</div><p>Shuffles a list and shrinks to the unshuffled list.</p>
|
||||
|
||||
<h3 class="function"><a name="vector-2">vector/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>vector(K::integer(), G::<a href="#type-gen">gen(A)</a>) -> <a href="#type-gen">gen(list(A))</a></tt></p>
|
||||
</div><p>Generates a list of the given length, with elements generated by <tt>G</tt>.</p>
|
||||
<hr>
|
||||
|
||||
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
||||
<p><i>Generated by EDoc, Jun 13 2010, 13:15:30.</i></p>
|
||||
</body>
|
||||
</html>
|
156
lib/eqc/doc/eqc_symbolic.html
Normal file
156
lib/eqc/doc/eqc_symbolic.html
Normal file
|
@ -0,0 +1,156 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Module eqc_symbolic</title>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
||||
<hr>
|
||||
|
||||
<h1>Module eqc_symbolic</h1>
|
||||
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
|
||||
This module implements QuickCheck generators and utility functions for
|
||||
symbolic calls.
|
||||
|
||||
<p><b>Version:</b> 1.0.1</p>
|
||||
|
||||
<h2><a name="description">Description</a></h2><p>
|
||||
This module implements QuickCheck generators and utility functions for
|
||||
symbolic calls.</p>
|
||||
|
||||
<p>In test case generation it is often an advantage to postpone calling
|
||||
functions in the subject under test. In a test one is interested in
|
||||
the actual function that is called as well as its evaluated result.
|
||||
If one would evaluate the result already at generation time, then the actual
|
||||
call is not visible in the QuickCheck counter example shown in a
|
||||
failing test.</p>
|
||||
|
||||
<p>For example, when testing a data structure like the OTP library sets.erl,
|
||||
one may need more information than just the value to detect what goes
|
||||
wrong with the following property:</p>
|
||||
|
||||
<pre>
|
||||
prop_sets() ->
|
||||
?FORALL({S1,S2},{set(),set()},
|
||||
begin
|
||||
L1 = sets:to_list(S1),
|
||||
L2 = sets:to_list(S2),
|
||||
sets:intersection(S1,S2) ==
|
||||
sets:from_list(L1--(L1--L2))
|
||||
end).
|
||||
</pre>
|
||||
|
||||
which will fail with for example the following counter example:
|
||||
<pre>
|
||||
Failed! After 132 tests.
|
||||
Shrinking.......(7 times)
|
||||
{{set,2,16,16,8,80,48,
|
||||
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
|
||||
{{[],[],[],[],[],[],[],[],[],[],[],[-15,33],[],[],[],[]}}},
|
||||
{set,3,16,16,8,80,48,
|
||||
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
|
||||
{{[0],[],[],[],[],[],[],[],[],[],[],[33,-15],[],[],[],[]}}}}
|
||||
false
|
||||
</pre>
|
||||
|
||||
We would really need to understand the internal representation of sets in order to understand which
|
||||
sets we have generated and even if we know that, we have no clue which operations were used to
|
||||
create those sets.
|
||||
This is were symbolic representations help a lot. We would create a recursive generator that
|
||||
creates symbolic sets and use the following property instead:
|
||||
<pre>
|
||||
prop_sets() ->
|
||||
?FORALL({SymbS1,SymbS2},{set(),set()},
|
||||
begin
|
||||
S1 = eval(SymbS1),
|
||||
S2 = eval(SymbS2),
|
||||
L1 = sets:to_list(S1),
|
||||
L2 = sets:to_list(S2),
|
||||
sets:intersection(S1,S2) ==
|
||||
sets:from_list(L1--(L1--L2))
|
||||
end).
|
||||
|
||||
This would then result in a more readable error message:
|
||||
Shrinking..........(10 times)
|
||||
{{call,sets,from_list,[[6,-10]]},{call,sets,from_list,[[0,-10,6]]}}
|
||||
false
|
||||
</pre>
|
||||
|
||||
Symbolic representation of function calls provides us with
|
||||
<ul>
|
||||
<li>Better readable counter examples</li>
|
||||
<li>No need to break abstraction by using clean interface to code
|
||||
under test</li>
|
||||
<li>Better possibilities for shrinking when defining generators</li>
|
||||
</ul>
|
||||
<h2><a name="index">Function Index</a></h2>
|
||||
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#defined-1">defined/1</a></td><td>Checks whether a term can be evaluated without raising an exception.</td></tr>
|
||||
<tr><td valign="top"><a href="#eval-1">eval/1</a></td><td>Evaluates terms of the form <tt>{call,Module,Function,Args}</tt> anywhere in its
|
||||
argument, replacing them by the result of the corresponding function call.</td></tr>
|
||||
<tr><td valign="top"><a href="#eval-2">eval/2</a></td><td>Like <a href="#eval-1"><code>eval/1</code></a>, but also replaces symbolic variables, that is,
|
||||
terms of the form <tt>{var,V}</tt>, by their corresponding values in the
|
||||
property list.</td></tr>
|
||||
<tr><td valign="top"><a href="#pretty_print-1">pretty_print/1</a></td><td>Pretty printing of symbolic terms.</td></tr>
|
||||
<tr><td valign="top"><a href="#pretty_print-2">pretty_print/2</a></td><td>Pretty printing of symbolic terms within given environment.</td></tr>
|
||||
<tr><td valign="top"><a href="#well_defined-1">well_defined/1</a></td><td>Generates a well defined symbolic value.</td></tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="functions">Function Details</a></h2>
|
||||
|
||||
<h3 class="function"><a name="defined-1">defined/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>defined(E::term()) -> bool()</tt></p>
|
||||
</div><p>Checks whether a term can be evaluated without raising an exception.
|
||||
Some symbolic terms may raise an exception when evaluating, e.g., division by zero would
|
||||
raise an exception, thus <tt>eval({call,erlang,'div',[1,0]})</tt> raises an exception as well.</p>
|
||||
|
||||
<h3 class="function"><a name="eval-1">eval/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>eval(Term::term()) -> term()</tt></p>
|
||||
</div><p>Evaluates terms of the form <tt>{call,Module,Function,Args}</tt> anywhere in its
|
||||
argument, replacing them by the result of the corresponding function call.
|
||||
This is useful when, for example, test data is of an abstract datatype, and
|
||||
we want to know how it was generated, rather than its representation--it is
|
||||
much clearer to see that a test failed for <tt>sets:new()</tt> (that is
|
||||
<tt>{call,sets,new,[]}</tt>), for example,
|
||||
than for its representation.
|
||||
We write <tt>?FORALL(X,TGen,...eval(X)...)</tt>, where <tt>TGen</tt>
|
||||
generates terms containing calls, so that test cases are displayed in this
|
||||
form, but the actual test data is the result of evaluating the calls.</p>
|
||||
|
||||
<h3 class="function"><a name="eval-2">eval/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>eval(Env::<a href="#type-proplist">proplist()</a>, T::term()) -> term()</tt></p>
|
||||
</div><p>Like <a href="#eval-1"><code>eval/1</code></a>, but also replaces symbolic variables, that is,
|
||||
terms of the form <tt>{var,V}</tt>, by their corresponding values in the
|
||||
property list. This should be a list of pairs of atoms and values. For example,
|
||||
<tt>eval([{x,3}],{var,x})</tt> evaluates to 3.</p>
|
||||
|
||||
<h3 class="function"><a name="pretty_print-1">pretty_print/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>pretty_print(Symb::term()) -> string()</tt></p>
|
||||
</div><p>Pretty printing of symbolic terms.
|
||||
A symbolic value like <tt>{call,sets,union,[{call,sets,new,[]},{call,sets,from_list,[[1,2]]}]}</tt>
|
||||
is transformed to the string \"sets:union(sets:new(),from_list([1,2]))\".</p>
|
||||
|
||||
<h3 class="function"><a name="pretty_print-2">pretty_print/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>pretty_print(Env::<a href="#type-proplist">proplist()</a>, Symb::term()) -> string()</tt></p>
|
||||
</div><p>Pretty printing of symbolic terms within given environment.
|
||||
Like <a href="#pretty_print-1"><code>pretty_print/1</code></a>, but also replaces symbolic variables, that is,
|
||||
terms of the form <tt>{var,V}</tt>, by their corresponding values in the
|
||||
property list. This should be a list of pairs of atoms and values. For example,
|
||||
<tt>eval([{x,3}],{var,x})</tt> is pretty printed to \"3\".</p>
|
||||
|
||||
<h3 class="function"><a name="well_defined-1">well_defined/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>well_defined(G::<a href="#type-gen">gen(A)</a>) -> A</tt></p>
|
||||
</div><p>Generates a well defined symbolic value.
|
||||
A value is well defined if evaluating it does not raise an exception.</p>
|
||||
<hr>
|
||||
|
||||
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
||||
<p><i>Generated by EDoc, Jun 13 2010, 13:15:30.</i></p>
|
||||
</body>
|
||||
</html>
|
BIN
lib/eqc/doc/erlang.png
Normal file
BIN
lib/eqc/doc/erlang.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
17
lib/eqc/doc/index.html
Normal file
17
lib/eqc/doc/index.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Overview</title>
|
||||
</head>
|
||||
<frameset cols="20%,80%">
|
||||
<frame src="modules-frame.html" name="modulesFrame" title="">
|
||||
|
||||
<frame src="overview-summary.html" name="overviewFrame" title="">
|
||||
<noframes>
|
||||
<h2>This page uses frames</h2>
|
||||
<p>Your browser does not accept frames.
|
||||
<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead.
|
||||
</p>
|
||||
</noframes>
|
||||
</frameset>
|
||||
</html>
|
14
lib/eqc/doc/modules-frame.html
Normal file
14
lib/eqc/doc/modules-frame.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Overview</title>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<h2 class="indextitle">Modules</h2>
|
||||
<table width="100%" border="0" summary="list of modules">
|
||||
<tr><td><a href="eqc.html" target="overviewFrame" class="module">eqc</a></td></tr>
|
||||
<tr><td><a href="eqc_gen.html" target="overviewFrame" class="module">eqc_gen</a></td></tr>
|
||||
<tr><td><a href="eqc_symbolic.html" target="overviewFrame" class="module">eqc_symbolic</a></td></tr></table>
|
||||
</body>
|
||||
</html>
|
53
lib/eqc/doc/overview-summary.html
Normal file
53
lib/eqc/doc/overview-summary.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>QuickCheck Mini
</title>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
||||
<h1>QuickCheck Mini
</h1>
|
||||
<p>Copyright © Quviq AB, 2006-2010.
</p>
|
||||
<p><b>Version:</b> 1.0.1
</p>
|
||||
<p>
|
||||
QuickCheck is a specification-based testing tool for Erlang. QuickCheck Mini is
|
||||
a powerful, but restricted version of QuickCheck. It is released free of charge for
|
||||
anyone interested in learning more about QuickCheck as well as for open source
|
||||
developers that want to ship their code with simple QuickCheck properties.</p>
|
||||
|
||||
<p>In order to learn more about QuickCheck, please visit http://www.quviq.com/.
|
||||
There is also a mailing list discussing QuickCheck issues, which you can subscribe to by sending an email to quickcheck-questions@quviq.com with subject "Subscribe".</p>
|
||||
|
||||
|
||||
<h2>QuickCheck</h2>
|
||||
|
||||
Programs
|
||||
are tested by writing <i>properties</i> in the source code, such as
|
||||
<pre>
|
||||
prop_reverse() ->
|
||||
?FORALL(Xs,list(int()),
|
||||
lists:reverse(lists:reverse(Xs)) == Xs).
|
||||
</pre>
|
||||
Properties are tested by calling
|
||||
<pre>
|
||||
eqc:quickcheck(prop_reverse())
|
||||
</pre><p>
|
||||
which generates 100 random test cases and checks that the property
|
||||
returns <tt>true</tt> in every case.</p>
|
||||
|
||||
<p>
|
||||
Functions for writing properties are found in module <a href="eqc.html"><code>eqc</code></a>,
|
||||
while functions for writing test data generators (such as
|
||||
<tt>list(int())</tt> above) are found in module <a href="eqc_gen.html"><code>eqc_gen</code></a>. Parts
|
||||
of the interface are provided via macros, which are defined in
|
||||
<tt>eqc.hrl</tt>--this file should be included in every module which
|
||||
uses QuickCheck. This header file also imports much of the QuickCheck
|
||||
API, so it can be used without explicit module names.
|
||||
</p>
|
||||
|
||||
|
||||
<hr>
|
||||
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
|
||||
<p><i>Generated by EDoc, Jun 13 2010, 13:15:30.</i></p>
|
||||
</body>
|
||||
</html>
|
39
lib/eqc/doc/overview.edoc
Normal file
39
lib/eqc/doc/overview.edoc
Normal file
|
@ -0,0 +1,39 @@
|
|||
@title QuickCheck Mini
|
||||
@version {@version}
|
||||
@copyright Quviq AB, 2006-2010.
|
||||
@doc
|
||||
QuickCheck is a specification-based testing tool for Erlang. QuickCheck Mini is
|
||||
a powerful, but restricted version of QuickCheck. It is released free of charge for
|
||||
anyone interested in learning more about QuickCheck as well as for open source
|
||||
developers that want to ship their code with simple QuickCheck properties.
|
||||
|
||||
In order to learn more about QuickCheck, please visit http://www.quviq.com/.
|
||||
There is also a mailing list discussing QuickCheck issues, which you can subscribe to by sending an email to quickcheck-questions@quviq.com with subject "Subscribe".
|
||||
|
||||
|
||||
<h2>QuickCheck</h2>
|
||||
|
||||
Programs
|
||||
are tested by writing <i>properties</i> in the source code, such as
|
||||
<pre>
|
||||
prop_reverse() ->
|
||||
?FORALL(Xs,list(int()),
|
||||
lists:reverse(lists:reverse(Xs)) == Xs).
|
||||
</pre>
|
||||
Properties are tested by calling
|
||||
<pre>
|
||||
eqc:quickcheck(prop_reverse())
|
||||
</pre>
|
||||
which generates 100 random test cases and checks that the property
|
||||
returns <tt>true</tt> in every case.
|
||||
|
||||
<p>
|
||||
Functions for writing properties are found in module {@link eqc},
|
||||
while functions for writing test data generators (such as
|
||||
<tt>list(int())</tt> above) are found in module {@link eqc_gen}. Parts
|
||||
of the interface are provided via macros, which are defined in
|
||||
<tt>eqc.hrl</tt>--this file should be included in every module which
|
||||
uses QuickCheck. This header file also imports much of the QuickCheck
|
||||
API, so it can be used without explicit module names.
|
||||
</p>
|
||||
|
11
lib/eqc/doc/packages-frame.html
Normal file
11
lib/eqc/doc/packages-frame.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Overview</title>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<h2 class="indextitle">Packages</h2>
|
||||
<table width="100%" border="0" summary="list of packages"></table>
|
||||
</body>
|
||||
</html>
|
55
lib/eqc/doc/stylesheet.css
Normal file
55
lib/eqc/doc/stylesheet.css
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* standard EDoc style sheet */
|
||||
body {
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||
margin-left: .25in;
|
||||
margin-right: .2in;
|
||||
margin-top: 0.2in;
|
||||
margin-bottom: 0.2in;
|
||||
color: #000000;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
h1,h2 {
|
||||
margin-left: -0.2in;
|
||||
}
|
||||
div.navbar {
|
||||
background-color: #add8e6;
|
||||
padding: 0.2em;
|
||||
}
|
||||
h2.indextitle {
|
||||
padding: 0.4em;
|
||||
background-color: #add8e6;
|
||||
}
|
||||
h3.function,h3.typedecl {
|
||||
background-color: #add8e6;
|
||||
padding-left: 1em;
|
||||
}
|
||||
div.spec {
|
||||
margin-left: 2em;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
a.module,a.package {
|
||||
text-decoration:none
|
||||
}
|
||||
a.module:hover,a.package:hover {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
ul.definitions {
|
||||
list-style-type: none;
|
||||
}
|
||||
ul.index {
|
||||
list-style-type: none;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
/*
|
||||
* Minor style tweaks
|
||||
*/
|
||||
ul {
|
||||
list-style-type: square;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td {
|
||||
padding: 3
|
||||
}
|
7
lib/eqc/ebin/eqc.app
Normal file
7
lib/eqc/ebin/eqc.app
Normal file
|
@ -0,0 +1,7 @@
|
|||
{application,eqc,
|
||||
[{mod,{eqc,[]}},
|
||||
{description,"Quviq QuickCheck Mini"},
|
||||
{vsn,"1.0.1"},
|
||||
{modules,[eqc,eqc_gen,eqc_symbolic,eqc_warn]},
|
||||
{applications,[kernel,stdlib,inets]}]}.
|
||||
|
227
lib/eqc/examples/generators_eqc.erl
Normal file
227
lib/eqc/examples/generators_eqc.erl
Normal file
|
@ -0,0 +1,227 @@
|
|||
%% This file tests that generators produce the right kind of data. It
|
||||
%% also illustrates how to write a QuickSpec specification of a
|
||||
%% datatype (such as the generator datatype).
|
||||
|
||||
-module(generators_eqc).
|
||||
-include_lib("eqc/include/eqc.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
%% Generate most combinations of generator functions, as a symbolic
|
||||
%% generator--for example:
|
||||
%% {call,oneof,[{{call,bitstring,14},{call,elements,[15]}}]}
|
||||
|
||||
%% We control the size of the symbolic generator, by limiting the
|
||||
%% nesting depth.
|
||||
|
||||
generator() ->
|
||||
?SIZED(N,generator(N)).
|
||||
|
||||
generator(0) ->
|
||||
% base case: no nested generators.
|
||||
oneof([constant(),
|
||||
binary,{call,binary,nat()},
|
||||
bitstring,{call,bitstring,nat()},
|
||||
bool,char,
|
||||
?SUCHTHAT({call,choose,Lo,Hi},
|
||||
{call,choose,int(),int()},
|
||||
Lo=<Hi),
|
||||
{call,elements,non_empty_list(constant())},
|
||||
int,largeint,nat,real]);
|
||||
generator(N) ->
|
||||
% recursive case: reduce the size of nested compound generators.
|
||||
N1 = N div 4,
|
||||
?LAZY(oneof([generator(0),compound_generator(N1)])).
|
||||
|
||||
constant() ->
|
||||
oneof([int(),atom()]).
|
||||
|
||||
atom() ->
|
||||
elements([a,b,c,d]).
|
||||
|
||||
term() ->
|
||||
?LET(G,generator(),generated_by(G)).
|
||||
|
||||
compound_generator(N) ->
|
||||
Smaller = generator(N),
|
||||
oneof([?LETSHRINK([Sm],[Smaller],?LET(Def,term(),{call,default,Sm,Def})),
|
||||
?LETSHRINK(Gs,non_empty_list(Smaller),
|
||||
{call,frequency,[{positive(),G} || G <- Gs]}),
|
||||
?LETSHRINK([Sm],[Smaller],{call,list,Sm}),
|
||||
?LETSHRINK([Sm],[Smaller],{call,orderedlist,Sm}),
|
||||
?LETSHRINK([Sm],[?SUCHTHAT(Sm,Smaller,not often_empty(Sm))],
|
||||
{call,non_empty,Sm}),
|
||||
?LETSHRINK([Sm],[Smaller],{call,noshrink,Sm}),
|
||||
?LETSHRINK(Gs,non_empty_list(Smaller),
|
||||
{call,oneof,Gs}),
|
||||
?LETSHRINK([Sm],[Smaller],{call,resize,choose(0,N),Sm}),
|
||||
?LETSHRINK(L,list(constant()),{call,shuffle,L}),
|
||||
?LETSHRINK(Gs,short_list(Smaller),
|
||||
list_to_tuple(Gs)),
|
||||
?LETSHRINK([Sm],[Smaller],{call,vector,choose(0,4),Sm})]).
|
||||
|
||||
%% To keep the size of generators under control, it is not enough to
|
||||
%% restrict nesting depth. We also want lists of arguments to oneof,
|
||||
%% frequency etc to be reasonably short.
|
||||
|
||||
short_list(G) ->
|
||||
?SIZED(Size,
|
||||
resize(Size div 3 + 1,
|
||||
list(resize(Size,G)))).
|
||||
|
||||
positive() ->
|
||||
?LET(N,nat(),N+1).
|
||||
|
||||
non_empty_list(G) ->
|
||||
non_empty(short_list(G)).
|
||||
|
||||
%% When we generate {call,non_empty,G}, we need to know that G is
|
||||
%% reasonably likely to produce a non-empty value... otherwise we may
|
||||
%% loop when we try to use this generator!
|
||||
|
||||
often_empty([]) ->
|
||||
true;
|
||||
often_empty(<<>>) ->
|
||||
true;
|
||||
often_empty({call,vector,N,G}) ->
|
||||
N==0;
|
||||
often_empty({call,binary,N}) ->
|
||||
N==0;
|
||||
often_empty({call,bitstring,N}) ->
|
||||
N==0;
|
||||
often_empty({call,noshrink,G}) ->
|
||||
often_empty(G);
|
||||
often_empty({call,oneof,Gs}) ->
|
||||
% conservative
|
||||
lists:any(fun often_empty/1,Gs);
|
||||
often_empty({call,frequency,WGs}) ->
|
||||
% conservative
|
||||
lists:any(fun often_empty/1, [G || {_,G} <- WGs]);
|
||||
often_empty({call,default,G,V}) ->
|
||||
often_empty(G) andalso often_empty(V);
|
||||
often_empty({call,resize,N,G}) ->
|
||||
N<4 orelse often_empty(G);
|
||||
often_empty({call,shuffle,L}) ->
|
||||
L==[];
|
||||
often_empty(_) ->
|
||||
false.
|
||||
|
||||
%% The values generated by a symbolic generator.
|
||||
|
||||
generated_by(A) when is_atom(A) ->
|
||||
case erlang:function_exported(eqc_gen,A,0) of
|
||||
true ->
|
||||
eqc_gen:A();
|
||||
false ->
|
||||
A
|
||||
end;
|
||||
generated_by(T) when is_tuple(T), size(T)>0 ->
|
||||
case tuple_to_list(T) of
|
||||
[call,F|Args] ->
|
||||
erlang:apply(eqc_gen,F,[generated_by(G) || G <- Args]);
|
||||
Gs ->
|
||||
list_to_tuple([generated_by(G) || G <- Gs])
|
||||
end;
|
||||
generated_by([H|T]) ->
|
||||
[generated_by(H)|generated_by(T)];
|
||||
generated_by(X) ->
|
||||
X.
|
||||
|
||||
%% Check that a generated value corresponds to its generator.
|
||||
|
||||
is(binary,B) ->
|
||||
is_binary(B);
|
||||
is({call,binary,N},B) ->
|
||||
is_binary(B) andalso size(B)==N;
|
||||
is(bitstring,B) ->
|
||||
is_bitstring(B);
|
||||
is({call,bitstring,N},B) ->
|
||||
is_bitstring(B) andalso size(B) == N div 8;
|
||||
is(bool,B) ->
|
||||
B==true orelse B==false;
|
||||
is(char,C) ->
|
||||
is_integer(C) andalso 0=<C andalso C=<255;
|
||||
is({call,choose,Lo,Hi},N) ->
|
||||
is_integer(N) andalso Lo =< N andalso N =< Hi;
|
||||
is({call,default,G,D},X) ->
|
||||
is(G,X) orelse X==D;
|
||||
is({call,elements,L},X) ->
|
||||
lists:member(X,L);
|
||||
is({call,frequency,WGs},X) ->
|
||||
lists:any(fun({_,G})->is(G,X) end,WGs);
|
||||
is(int,N) ->
|
||||
is_integer(N) andalso abs(N) =< 100;
|
||||
is(largeint,N) ->
|
||||
is_integer(N);
|
||||
is(nat,N) ->
|
||||
is_integer(N) andalso N>=0;
|
||||
is(real,N) ->
|
||||
is_float(N);
|
||||
is({call,list,G},L) ->
|
||||
is_list(L) andalso
|
||||
lists:all(fun(X)->is(G,X) end,L);
|
||||
is({call,orderedlist,G},L) ->
|
||||
is_list(L) andalso
|
||||
lists:all(fun(X)->is(G,X) end,L) andalso
|
||||
lists:sort(L) == L;
|
||||
is({call,non_empty,G},X) ->
|
||||
is(G,X) andalso X/=[] andalso X/=<<>>;
|
||||
is({call,noshrink,G},X) ->
|
||||
is(G,X);
|
||||
is({call,oneof,Gs},X) ->
|
||||
lists:any(fun(G) -> is(G,X) end,Gs);
|
||||
is({call,resize,_,G},X) ->
|
||||
is(G,X);
|
||||
is({call,shuffle,L},X) ->
|
||||
is_list(X) andalso lists:sort(X) == lists:sort(L);
|
||||
is({call,vector,N,G},V) ->
|
||||
is_list(V) andalso length(V)==N andalso
|
||||
lists:all(fun(X)->is(G,X) end,V);
|
||||
is(GT,T) when is_tuple(GT) ->
|
||||
is_tuple(T) andalso size(T)==size(GT) andalso
|
||||
lists:all(fun({G,X})->is(G,X) end,
|
||||
lists:zip(tuple_to_list(GT),
|
||||
tuple_to_list(T)));
|
||||
is(Const,X) when is_atom(Const); is_integer(Const) ->
|
||||
Const == X.
|
||||
|
||||
%% The properties.
|
||||
|
||||
%% Generate symbolic generators, and report on the distribution of
|
||||
%% generator functions used.
|
||||
prop_generator() ->
|
||||
?FORALL(G,generator(),
|
||||
aggregate(generator_types(G),true)).
|
||||
|
||||
generator_types(G) when is_tuple(G) ->
|
||||
case tuple_to_list(G) of
|
||||
[call,frequency,WArgs] ->
|
||||
[T || {_,G1} <- WArgs, T <- generator_types(G1)];
|
||||
[call,F|Args] ->
|
||||
[F|[T || A <- Args,
|
||||
T <- generator_types(A)]];
|
||||
L ->
|
||||
[T || X <- L,
|
||||
T <- generator_types(X)]
|
||||
end;
|
||||
generator_types(N) when is_integer(N) ->
|
||||
[integer_constant];
|
||||
generator_types(X) when is_float(X) ->
|
||||
[float_constant];
|
||||
generator_types(B) when is_binary(B) ->
|
||||
[binary];
|
||||
generator_types(B) when is_bitstring(B) ->
|
||||
[bitstring];
|
||||
generator_types(L) when is_list(L) ->
|
||||
[list|[T || X <- L, T <- generator_types(X)]];
|
||||
generator_types(X) ->
|
||||
[X].
|
||||
|
||||
%% For each kind of generator, use it to generate a value, and check
|
||||
%% that the value matches the generator. This tests the generators
|
||||
%% (and our generator-generators!) pretty thoroughly.
|
||||
|
||||
prop_correct_types() ->
|
||||
?FORALL(G,generator(),
|
||||
?FORALL(X,generated_by(G),is(G,X))).
|
||||
|
40
lib/eqc/examples/ip_checksum.erl
Normal file
40
lib/eqc/examples/ip_checksum.erl
Normal file
|
@ -0,0 +1,40 @@
|
|||
%%% File : ip_checksum.erl
|
||||
%%% Author : Ulf Norell <ulf.norell@quviq.com>,
|
||||
%%% Thomas Arts <thomas.arts@quviq.com>
|
||||
%%% Description : Implementation of IP checksums.
|
||||
%%% Created : 7 Jun 2010 by Ulf Norell
|
||||
-module(ip_checksum).
|
||||
|
||||
-export([checksum/1, checksum/2, sum/2, pad/2, add/2, negate/1]).
|
||||
|
||||
checksum(Bin) ->
|
||||
checksum(Bin, 16).
|
||||
|
||||
checksum(Bin, N) ->
|
||||
negate(sum(pad(Bin, N), N)).
|
||||
|
||||
% Sum a binary of N bit words in ones complement representation.
|
||||
sum(Bin, N) ->
|
||||
lists:foldl(fun(A, B) -> add(A, B) end, <<0:N>>,
|
||||
[ <<A:N>> || <<A:N>> <= Bin ]).
|
||||
|
||||
% Add two numbers in ones complement representation.
|
||||
add(A, B) ->
|
||||
N = bit_size(A),
|
||||
<<X:N>> = A,
|
||||
<<Y:N>> = B,
|
||||
Carry = (X + Y) div (1 bsl N),
|
||||
<<(X + Y + Carry):N>>.
|
||||
|
||||
%% invert all bits... as simple as that.
|
||||
negate(BitString) ->
|
||||
<< <<(1-Bit):1>> || <<Bit:1>> <= BitString >>.
|
||||
|
||||
pad(Binary, Bits) ->
|
||||
PaddingLength =
|
||||
case bit_size(Binary) rem Bits of
|
||||
0 -> 0;
|
||||
N -> Bits - N
|
||||
end,
|
||||
<<Binary/bits, 0:PaddingLength>>.
|
||||
|
218
lib/eqc/examples/ip_checksum_eqc.erl
Normal file
218
lib/eqc/examples/ip_checksum_eqc.erl
Normal file
|
@ -0,0 +1,218 @@
|
|||
%%% File : ip_checksum_eqc.erl
|
||||
%%% Author : Ulf Norell <ulf.norell@quviq.com>,
|
||||
%%% Thomas Arts <thomas.arts@quviq.com>
|
||||
%%% Description : QuickCheck properties for ip_checksum.erl
|
||||
%%% Created : 7 Jun 2010 by Ulf Norell
|
||||
-module(ip_checksum_eqc).
|
||||
|
||||
-include_lib("eqc/include/eqc.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
% == Testing IP checksum implementations ==
|
||||
|
||||
% In RFC 1071 efficient algorithms are discussed for computing the internet
|
||||
% checksum, also known as IP checksum. Whenever you implement efficient
|
||||
% algorithms, an error may sneak through.
|
||||
|
||||
% This article is meant to be used as test driven development specification for
|
||||
% anyone that wants to implement one of the algorithms of RFC 1071 or even a new
|
||||
% one to compute the IP checksum. The article can also be read as an example of
|
||||
% specifying something without revealing its implementation details; a good
|
||||
% example of using QuickCheck specifications.
|
||||
|
||||
% Whether you write your code in Erlang, C or Java, we assume that you can build
|
||||
% an interface to a module called ip_checksum.erl in which Erlang functions
|
||||
% either are the functions under test or call the functions under test.
|
||||
|
||||
% === IP Checksum ===
|
||||
|
||||
% The IP checksum is the 16 bit one's complement of the one's complement sum of
|
||||
% all 16 bit words in the header.
|
||||
|
||||
% Ones complement is a way of representing negative numbers (see
|
||||
% [http://en.wikipedia.org/wiki/Signed_number_representations#Ones.27_complement
|
||||
% WikiPedia] for more details).
|
||||
|
||||
% The IP checksum uses 16 bit words. In 16 bits you can represent the numbers 0
|
||||
% to 65535. The idea with ones complement is to use half the numbers in this
|
||||
% interval for representing negative numbers. Thus, 0 up to 32767 are the
|
||||
% positive numbers and 65535 is -0, or an alternative representation of zero.
|
||||
% The number 65534 is -1 etc. Until 32768 which is -32767. Hence the interval
|
||||
% -32767 up to 32767 can be represented.
|
||||
|
||||
% In the remainder of this article we will present properties for functions that
|
||||
% you probably would like to test. The properties are always parametrized by the
|
||||
% word size.
|
||||
|
||||
% === Utility functions ===
|
||||
|
||||
% First we define some functions that will come in handy.
|
||||
|
||||
% The maximum number that can be represented in ''N'' bits. In the ones
|
||||
% complement interpretation this will be the negative zero.
|
||||
max_int(N) ->
|
||||
(1 bsl N) - 1.
|
||||
|
||||
negative_zero(N) ->
|
||||
max_int(N).
|
||||
|
||||
% === Ones complement ===
|
||||
|
||||
% The first function we might want to check is the ones' complement of a word,
|
||||
% which in ones' complement representation corresponds to the negation. We
|
||||
% assume we have a function '''ip_checksum:negate/1''' implemented that takes a
|
||||
% bit string as input and computes its ones' complement.
|
||||
|
||||
% Looking at the specification of ones' complement representation above we can
|
||||
% see that adding the ones' complement representation of a number and the
|
||||
% representation of its negation results in the representation of -0. For
|
||||
% instance, the representation of -2 is 65533 and the representation of 2 is 2.
|
||||
% Adding these we get 65535 which is the representation of -0. We use this
|
||||
% property to test the implementation of the '''negate/2''' function.
|
||||
|
||||
prop_negate(N) ->
|
||||
?FORALL(I, choose(0, max_int(N)),
|
||||
begin
|
||||
<<CI:N>> = ip_checksum:negate(<<I:N>>),
|
||||
equals(negative_zero(N), I + CI)
|
||||
end).
|
||||
|
||||
% The property above is parameterized by the word size N. We'll want to test
|
||||
% our properties for a range of different word sizes, so we define a general
|
||||
% function to transform a parameterized property to a property choosing random
|
||||
% word sizes.
|
||||
|
||||
random_word_size(Prop) ->
|
||||
?FORALL(N, choose(1, 64), Prop(N)).
|
||||
|
||||
prop_negate() ->
|
||||
random_word_size(fun prop_negate/1).
|
||||
|
||||
% === Padding ===
|
||||
|
||||
% It is not clear from the specification presented above, but if you need to
|
||||
% compute the checksum of a list of bytes in base 16, then there should be an
|
||||
% even number of bytes. Likewise, if we would like to do ones complement in 32
|
||||
% bits base, we would need to extend a sequence of bytes such that it is
|
||||
% divisible by 4.
|
||||
|
||||
% Extending a bit string such that it is divisible by the base is called padding.
|
||||
% We assume that you implemented a padding function that added the necessary
|
||||
% bits, given a bit string. We assume this function to be implemented as
|
||||
% '''ip_checksum:pad/1''' taking a bit string as argument and returning a new
|
||||
% bit string which is an extended version with as many zero bits as needed.
|
||||
|
||||
prop_padding() ->
|
||||
random_word_size(fun prop_padding/1).
|
||||
|
||||
prop_padding(N) ->
|
||||
?FORALL(BitString, bitstring(),
|
||||
begin
|
||||
Bits = bit_size(BitString),
|
||||
<<B:Bits/bits, Padded/bits>> = ip_checksum:pad(BitString,N),
|
||||
Zeros = bit_size(Padded),
|
||||
% If this property fails we need to know what the pad function actually
|
||||
% returned in order to understand what went wrong. This is what the
|
||||
% ?WHENFAIL macro is for.
|
||||
?WHENFAIL(io:format("B = ~w\nPadded = ~w\nZeros = ~w\n",
|
||||
[B, Padded, Zeros]),
|
||||
((Bits + Zeros) rem N) == 0 andalso % the new length is divisible by N
|
||||
B == BitString andalso % we don't change the bit string
|
||||
<<0:Zeros>> == Padded andalso % we pad with zeros
|
||||
Zeros < N % we don't pad more than we have to
|
||||
)
|
||||
end).
|
||||
|
||||
% Confident that the padding function works we can write a generator for
|
||||
% correctly padded bit strings.
|
||||
padded_bitstring(N) ->
|
||||
?LET(Bits, bitstring(), ip_checksum:pad(Bits, N)).
|
||||
|
||||
% An alternative definition of this generator would not use the padding
|
||||
% function, but rather first generate the length of the bit string and then
|
||||
% pass that to the bit string generator (see below). The advantage of the former
|
||||
% definition is that it behaves better when shrinking. The version below will
|
||||
% regenerate the bit string everytime the length is getting shorter.
|
||||
padded_bitstring_2(N) ->
|
||||
?LET(Len, nat(), bitstring(N * Len)).
|
||||
|
||||
% === Ones complement sum ===
|
||||
|
||||
% The ones complement sum is computed by adding a number of words in ones
|
||||
% complement representation. We assume this function to be implemented as
|
||||
% '''ip_checksum:sum/2''' which takes a bit string as first argument and a
|
||||
% word size as second argument. We assume that padding is done outside the
|
||||
% sum function and only test that the function works for bit strings of
|
||||
% which the length is divisible by the given word size.
|
||||
|
||||
% Because of our test driven development method, we have already tested the
|
||||
% '''negate/1''' function and therefore trust this function in our property.
|
||||
% Remember that adding the representations of a number and its negation yields
|
||||
% -0. This is in fact also true if we use one's complement addition rather than
|
||||
% simply adding the representations (which is not the same thing). So if we
|
||||
% concatenate a bit string with the negation of its sum, the sum of the
|
||||
% resulting bit string should be -0 if our implementation of '''sum/2''' is
|
||||
% correct. By testing the sum function in this way we don't have to worry about
|
||||
% specifying the intricacies of ones' complement arithmetic (except for the
|
||||
% fact that X + (-X) = -0).
|
||||
|
||||
prop_sum() ->
|
||||
random_word_size(fun prop_sum/1).
|
||||
|
||||
prop_sum(N) ->
|
||||
?FORALL(Bin, padded_bitstring(N),
|
||||
begin
|
||||
Sum = ip_checksum:sum(Bin, N),
|
||||
CSum = ip_checksum:negate(Sum),
|
||||
equals(ip_checksum:sum(<<CSum/bits, Bin/bits>>, N),
|
||||
<<(negative_zero(N)):N>>)
|
||||
end).
|
||||
|
||||
% === Checksum ===
|
||||
|
||||
% After computing ones' complement sum, one has to take the ones' complement of
|
||||
% the result to compute the checksum. Of course, we have all ingredients in
|
||||
% house to do so, but in case you implement both functions as one you would
|
||||
% like to test the final result '''ip_checksum:checksum/2''' with a bit string
|
||||
% and word size as arguments.
|
||||
|
||||
% We first test that the '''checksum/2''' function takes care of padding, by
|
||||
% checking that padding the bitstring before passing it to '''checksum/2'''
|
||||
% doesn't change the result.
|
||||
|
||||
prop_checksum_pad() ->
|
||||
random_word_size(fun prop_checksum_pad/1).
|
||||
|
||||
prop_checksum_pad(N) ->
|
||||
?FORALL(Bits, bitstring(),
|
||||
equals(ip_checksum:checksum(Bits, N),
|
||||
ip_checksum:checksum(ip_checksum:pad(Bits, N), N))).
|
||||
|
||||
% We can test the '''checksum/2''' function in the same way as we tested
|
||||
% '''sum/2''' above. Taking a bit string and prepending its checksum should
|
||||
% result in a bit string whose checksum is zero. Here's why:
|
||||
%
|
||||
% % definition of checksum
|
||||
% checksum(Bits) == -sum(Bits)
|
||||
%
|
||||
% checksum(checksum(Bits) ++ Bits) == {def. of checksum}
|
||||
% -sum(-sum(Bits) ++ Bits) == {sum(Xs ++ Ys) == sum(Xs) + sum(Ys)}
|
||||
% -(-sum(Bits) + sum(Bits)) == {adding -X and X}
|
||||
% -(-0) ==
|
||||
% 0
|
||||
%
|
||||
% Note that due to padding, the property doesn't hold if we append the checksum
|
||||
% rather than prepending it.
|
||||
|
||||
prop_checksum() ->
|
||||
random_word_size(fun prop_checksum/1).
|
||||
|
||||
prop_checksum(N) ->
|
||||
?FORALL(Bin, bitstring(),
|
||||
begin
|
||||
Sum = ip_checksum:checksum(Bin, N),
|
||||
equals(ip_checksum:checksum(<<Sum/bits, Bin/bits>>, N),
|
||||
<<0:N>>)
|
||||
end).
|
||||
|
223
lib/eqc/examples/lists_eqc.erl
Normal file
223
lib/eqc/examples/lists_eqc.erl
Normal file
|
@ -0,0 +1,223 @@
|
|||
%%% File : lists_eqc.erl
|
||||
%%% Author : Thomas Arts <thomas.arts@quviq.com>
|
||||
%%% Ulf Norell <ulf.norell@quviq.com>
|
||||
%%% Description : QuickCheck tests for some functions from the lists library.
|
||||
%%% Created : 23 Mar 2010 by Thomas Arts <thomas.arts@quviq.com>
|
||||
|
||||
-module(lists_eqc).
|
||||
|
||||
-include_lib("eqc/include/eqc.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
% === Testing lists:delete/2 ===
|
||||
|
||||
% The lists:delete/2 function removes an element from a list. Here's a property
|
||||
% we might want for this function: after you've removed an element from a list
|
||||
% it's not there anymore. The corresponding QuickCheck property is:
|
||||
|
||||
prop_delete_0() ->
|
||||
?FORALL({X, Xs}, {int(), list(int())},
|
||||
not lists:member(X, lists:delete(X, Xs))).
|
||||
|
||||
% Checking this property for 100 random values and lists it might actually
|
||||
% pass.
|
||||
test_delete_0() ->
|
||||
quickcheck(prop_delete_0()).
|
||||
|
||||
% However, rerunning the property a few more times will reveal a problem:
|
||||
test_delete_0_more() ->
|
||||
quickcheck(numtests(2000,prop_delete_0())).
|
||||
|
||||
% We get output looking like this:
|
||||
% 74> lists_eqc:test_delete_0_more().
|
||||
% ............................................................................
|
||||
% ............................................................................
|
||||
% ............................................................................
|
||||
% ............................................................................
|
||||
% ....................................................Failed! After 377 tests.
|
||||
% {7,[-6,1,23,24,7,7]}
|
||||
% Shrinking..(2 times)
|
||||
% {7,[7,7]}
|
||||
% false
|
||||
% There is a problem with our specification. lists:delete/2 only removes the
|
||||
% first occurrence of the element, something our specification fails to take
|
||||
% into account.
|
||||
|
||||
% Before fixing the problem in the specification, it's worth thinking about why
|
||||
% we needed so many tests to find the bug. In order to find the bug we need to
|
||||
% generate a value and a list such that the value appears twice in the list.
|
||||
% What's the probability of that? To answer that question we can write a new
|
||||
% property:
|
||||
|
||||
prop_member_probability() ->
|
||||
?FORALL({X, Xs}, {int(), list(int())},
|
||||
collect(lists:member(X, Xs), true)).
|
||||
|
||||
% This property always succeeds, but for every test case it records whether the
|
||||
% generated value appears (even once) in the list. Running the property a large
|
||||
% number of times reveals that the probability that a random value appears in a
|
||||
% random list is around 8%. No wonder it's hard to find a test case where it
|
||||
% appears at least twice!
|
||||
|
||||
% To make it easier to find a failing case, we can change our property to only
|
||||
% look at cases where the value appears at least once in the list. To do this
|
||||
% we use the ?IMPLIES macro.
|
||||
|
||||
prop_delete_1() ->
|
||||
?FORALL({X, Xs}, {int(), list(int())},
|
||||
?IMPLIES(lists:member(X, Xs),
|
||||
not lists:member(X, lists:delete(X, Xs)))).
|
||||
|
||||
% Now the output will look something like this:
|
||||
% 102> eqc:quickcheck(lists_eqc:prop_delete_1()).
|
||||
% xxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxx.
|
||||
% .xxxxxxxxxxxxxx.xx.xxxxxxx.xxxxxxxxxxx.xxxxxxxxxxxxxxxxxxx.xxx.xxxxxxxxxxxxx
|
||||
% xxxxxxxxx.xxxxxxxxxxx.xxxxx.xxxxxxxxxxxxxxxxxxxxxx.xx.xxxxxxxxxxxx.xxxxxxxxx
|
||||
% xxxxxxxxxxxxxxxxxxxxxxxxx..xxxxx.xxxx.xxxxxxxxx.xxxxxFailed! After 22 tests.
|
||||
% {1,[31,35,35,34,-21,-13,7,1,2,1,-35,2]}
|
||||
% Shrinking.....(5 times)
|
||||
% {1,[1,1]}
|
||||
% false
|
||||
% The 'x's represent test cases that were discarded because they didn't satisfy
|
||||
% the condition of the ?IMPLIES.
|
||||
|
||||
% Now that we have a property that fails reliably we can use it to document our
|
||||
% misconception about the behaviour of lists:delete/2. The fails/1 function
|
||||
% takes a property that is expected to fail and fails it doesn't.
|
||||
|
||||
prop_delete_2() ->
|
||||
fails(
|
||||
?FORALL({X, Xs}, {int(), list(int())},
|
||||
?IMPLIES(lists:member(X, Xs),
|
||||
not lists:member(X, lists:delete(X, Xs))))).
|
||||
|
||||
% Let's fix the specification. One possibility would be to count the number of
|
||||
% occurrences of the value we're removing before and after calling
|
||||
% lists:delete/2, but we can write a more precise specification quite elegantly:
|
||||
|
||||
prop_delete_3() ->
|
||||
?FORALL({Xs, X, Ys}, {list(int()), int(), list(int())},
|
||||
?IMPLIES(not lists:member(X, Xs),
|
||||
equals(lists:delete(X, Xs ++ [X] ++ Ys),
|
||||
Xs ++ Ys))).
|
||||
|
||||
% The equals function compares its arguments for equality and, if they're not
|
||||
% equal, prints the arguments. This lets us see what lists:delete actually
|
||||
% returned in the case we get a failing test case. Try removing the ?IMPLIES
|
||||
% and run the property to see what it looks like.
|
||||
|
||||
% === Testing lists:seq/3 ===
|
||||
|
||||
% The lists:seq/2 function has recently changed in Erlang. The new
|
||||
% specification allows lists:seq(1,0) and returns [] in that case. Copying the
|
||||
% specification from the manual still reveals an error
|
||||
% eqc:quickcheck(lists_eqc:prop_seq0()) due to the fact that a special case is
|
||||
% overlooked. The fix is in prop_seq().
|
||||
|
||||
% This is the property according to the documentation. This property fails with
|
||||
% a badarith exception on the test case {0, 0, 0}. The problem is that the
|
||||
% specification of the length is not correct for increment 0.
|
||||
prop_seq0() ->
|
||||
?FORALL({From,To,Incr},{int(),int(),int()},
|
||||
case catch lists:seq(From,To,Incr) of
|
||||
{'EXIT',_} ->
|
||||
(To < From-Incr andalso Incr > 0) orelse
|
||||
(To > From-Incr andalso Incr < 0) orelse
|
||||
(Incr==0 andalso From /= To);
|
||||
List ->
|
||||
is_list(List) andalso
|
||||
length(List) == (To-From+Incr) div Incr
|
||||
end).
|
||||
|
||||
% This is the property as it holds.
|
||||
prop_seq() ->
|
||||
?FORALL({From,To,Incr},{int(),int(),int()},
|
||||
case catch lists:seq(From,To,Incr) of
|
||||
{'EXIT',_} ->
|
||||
(To < From-Incr andalso Incr > 0) orelse
|
||||
(To > From-Incr andalso Incr < 0) orelse
|
||||
(Incr==0 andalso From /= To);
|
||||
List when Incr /= 0 ->
|
||||
is_list(List) andalso
|
||||
length(List) == (To-From+Incr) div Incr;
|
||||
List when Incr == 0 ->
|
||||
length(List) == 1
|
||||
end).
|
||||
|
||||
% This is probably how one would like seq to behave.
|
||||
prop_seq_wish(Seq) ->
|
||||
?FORALL({From,To,Incr},{int(),int(),int()},
|
||||
case catch Seq(From,To,Incr) of
|
||||
[] -> Incr > 0 andalso From > To orelse
|
||||
Incr < 0 andalso From < To;
|
||||
[_] when Incr == 0 -> From == To;
|
||||
List when Incr /= 0 andalso is_list(List) ->
|
||||
length(List) == (To-From+Incr) div Incr;
|
||||
{'EXIT', _} ->
|
||||
Incr == 0 andalso From /= To;
|
||||
_ ->
|
||||
false
|
||||
end).
|
||||
|
||||
prop_seq_wish() ->
|
||||
prop_seq_wish(fun lists:seq/3).
|
||||
|
||||
% Here is a reference implementation satisfying prop_seq_wish.
|
||||
seq(From, To, 0) when From /= To ->
|
||||
exit("seq: increment 0");
|
||||
seq(From, From, _Incr) ->
|
||||
[From];
|
||||
seq(From, To, Incr) when From > To andalso Incr > 0 ->
|
||||
[];
|
||||
seq(From, To, Incr) when From < To andalso Incr < 0 ->
|
||||
[];
|
||||
seq(From, To, Incr) ->
|
||||
[From | seq(From + Incr, To, Incr)].
|
||||
|
||||
prop_seq_wish_granted() ->
|
||||
prop_seq_wish(fun seq/3).
|
||||
|
||||
% The previous properties only specifies the length of the result of
|
||||
% lists:seq/3. We also want to make sure that it contains the right elements.
|
||||
% In particular, if lists:seq(From, To, Incr) returns a non-empty list, the
|
||||
% first element of the list should be From, and the difference between adjacent
|
||||
% elements should be Incr. We've already tested that the list has the right
|
||||
% number of elements so we don't have to worry about when the list ends.
|
||||
|
||||
% First some helper functions:
|
||||
|
||||
% We're only interested in non-empty results of seq/3.
|
||||
is_cons([_|_]) -> true;
|
||||
is_cons(_) -> false.
|
||||
|
||||
% We want to look at the difference between adjacent elements.
|
||||
diff_adjacent([X,Y|Xs]) ->
|
||||
[Y - X|diff_adjacent([Y|Xs])];
|
||||
diff_adjacent(_) ->
|
||||
[].
|
||||
|
||||
% We use ?IMPLIES to ignore the cases when lists:seq does not return a
|
||||
% non-empty list. To make sure we still get interesting test cases we collect
|
||||
% the lengths of the results and the increments we've chosen.
|
||||
prop_seq_elements() ->
|
||||
?FORALL({From, To, Incr}, {int(), int(), int()},
|
||||
begin
|
||||
Seq = (catch lists:seq(From, To, Incr)),
|
||||
?IMPLIES(is_cons(Seq),
|
||||
begin
|
||||
Adj = diff_adjacent(Seq),
|
||||
?WHENFAIL(io:format("Seq = ~w\nAdj = ~w", [Seq, Adj]),
|
||||
% When you have several collects in the same property you can give them
|
||||
% names using collect/3 and with_title/1 to distinguish them.
|
||||
% We divide the actual numbers by 5 to reduce the number of different
|
||||
% values collected.
|
||||
collect(with_title(lengths), length(Seq) div 5,
|
||||
collect(with_title(incr), Incr div 5,
|
||||
hd(Seq) == From andalso
|
||||
lists:all(fun(D) -> D == Incr end, Adj)
|
||||
))
|
||||
)
|
||||
end)
|
||||
end).
|
||||
|
146
lib/eqc/examples/sets_eqc.erl
Normal file
146
lib/eqc/examples/sets_eqc.erl
Normal file
|
@ -0,0 +1,146 @@
|
|||
%%% File : sets_eqc.erl
|
||||
%%% Author : Thomas Arts <thomas.arts@quviq.com>
|
||||
%%% Description : QuickCheck properties for sets.erl
|
||||
%%% Based on "Testing Data Structures with QuickCheck"
|
||||
%%% Created : 24 Mar 2010 by Thomas Arts
|
||||
|
||||
-module(sets_eqc).
|
||||
|
||||
-include_lib("eqc/include/eqc.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
%% Create a generator for the opaque type "set". The generator will generate
|
||||
%% symbolic calls which when evaluated computes a set. Each symbolic call has
|
||||
%% the form {call, Module, Function, Arguments} and are evaluated using the
|
||||
%% function eval/1.
|
||||
|
||||
%% To avoid generating infinite symbolic representations we pass the size
|
||||
%% parameter to the generator and use it to make sure we stop eventually.
|
||||
|
||||
set(G) ->
|
||||
?SIZED(Size,well_defined(set(Size,G))).
|
||||
|
||||
set(0,G) ->
|
||||
oneof([{call,sets,new,[]},
|
||||
{call,sets,from_list,[list(G)]}]);
|
||||
set(N,G) ->
|
||||
frequency(
|
||||
[{5,set(0,G)},
|
||||
{3, ?LAZY(?LETSHRINK([Set],[set(N-1,G)],
|
||||
{call,sets,add_element,[G, Set]}))},
|
||||
{1, ?LAZY(?LETSHRINK([Set],[set(N-1,G)],
|
||||
{call,sets,del_element,[G, Set]}))},
|
||||
{1, ?LAZY(?LETSHRINK([Set1,Set2],[set(N div 2,G),set(N div 2,G)],
|
||||
{call,sets,union,[Set1, Set2]}))},
|
||||
{1, ?LAZY(?LETSHRINK(Sets,list(set(N div 3,G)),
|
||||
{call,sets,union,[Sets]}))},
|
||||
{1, ?LAZY(?LETSHRINK([Set1,Set2],[set(N div 2,G),set(N div 2,G)],
|
||||
{call,sets,intersection,[Set1, Set2]}))},
|
||||
{1, ?LAZY(?LETSHRINK(Sets,?LET(L,nat(),vector(L+1,set(N div (L+1),G))),
|
||||
{call,sets,intersection,[Sets]}))},
|
||||
{1, ?LAZY(?LETSHRINK([Set1,Set2],[set(N div 2,G),set(N div 2,G)],
|
||||
{call,sets,subtract,[Set1, Set2]}))},
|
||||
{1, ?LAZY(?LETSHRINK([Set],[set(N div 2,G)],
|
||||
{call,sets,filter,[function1(bool()), Set]}))}]).
|
||||
|
||||
%% The next step is to define a model interpretation, i.e. a simplified,
|
||||
%% obviously correct implementation of the data type. In this case we use
|
||||
%% usorted lists.
|
||||
|
||||
model(S) ->
|
||||
lists:sort(sets:to_list(S)).
|
||||
|
||||
%% Define the set operations on the model.
|
||||
|
||||
madd_element(E,S) ->
|
||||
lists:usort([E|S]).
|
||||
|
||||
mdel_element(E,S) ->
|
||||
S -- [E].
|
||||
|
||||
msize(S) ->
|
||||
length(S).
|
||||
|
||||
mis_element(E,S) ->
|
||||
lists:member(E,S).
|
||||
|
||||
munion(Ss) ->
|
||||
lists:usort(lists:append(Ss)).
|
||||
|
||||
mintersection(Sets) ->
|
||||
[ E || E <- lists:usort(lists:append(Sets)),
|
||||
lists:all(fun(Set) -> lists:member(E,Set) end, Sets)].
|
||||
|
||||
mis_disjoint(S1,S2) ->
|
||||
mintersection([S1,S2]) == [].
|
||||
|
||||
mfilter(Pred,S) ->
|
||||
[ E || E <- S, Pred(E)].
|
||||
|
||||
%% Define one property for each operation. We parameterize the properties on
|
||||
%% the generator for the elements. To make it easy to run the properties we
|
||||
%% also define special versions that use integers.
|
||||
|
||||
%% Each property have the same basic form: we check that a given operation
|
||||
%% on sets has the same behaviour as the corresponding model operation.
|
||||
|
||||
prop_create() -> prop_create(int()).
|
||||
prop_create(G) ->
|
||||
?FORALL(Set,set(G),
|
||||
sets:is_set(eval(Set))).
|
||||
|
||||
prop_add_element() -> prop_add_element(int()).
|
||||
prop_add_element(G) ->
|
||||
?FORALL({E,Set},{G,set(G)},
|
||||
model(sets:add_element(E,eval(Set))) == madd_element(E,model(eval(Set)))).
|
||||
|
||||
prop_del_element() -> prop_del_element(int()).
|
||||
prop_del_element(G) ->
|
||||
?FORALL({E,Set},{G,set(G)},
|
||||
model(sets:del_element(E,eval(Set))) == mdel_element(E,model(eval(Set)))).
|
||||
|
||||
|
||||
prop_union2() -> prop_union2(int()).
|
||||
prop_union2(G) ->
|
||||
?FORALL({Set1,Set2},{set(G),set(G)},
|
||||
model(sets:union(eval(Set1),eval(Set2))) == munion([model(eval(Set1)),model(eval(Set2))])).
|
||||
|
||||
prop_union() -> prop_union(int()).
|
||||
prop_union(G) ->
|
||||
?FORALL(Sets,list(set(G)),
|
||||
model(sets:union(eval(Sets))) == munion([model(Set) || Set<-eval(Sets)])).
|
||||
|
||||
prop_intersection2() -> prop_intersection2(int()).
|
||||
prop_intersection2(G) ->
|
||||
?FORALL({Set1,Set2},{set(G),set(G)},
|
||||
model(sets:intersection(eval(Set1),eval(Set2))) ==
|
||||
mintersection([model(eval(Set1)),model(eval(Set2))])).
|
||||
|
||||
|
||||
prop_intersection() -> prop_intersection(int()).
|
||||
prop_intersection(G) ->
|
||||
?FORALL(Sets,eqc_gen:non_empty(list(set(G))),
|
||||
model(sets:intersection(eval(Sets))) == mintersection([model(Set) || Set<-eval(Sets)])).
|
||||
|
||||
prop_size() -> prop_size(int()).
|
||||
prop_size(G) ->
|
||||
?FORALL(Set,set(G),
|
||||
sets:size(eval(Set)) == msize(model(eval(Set)))).
|
||||
|
||||
prop_is_element() -> prop_is_element(int()).
|
||||
prop_is_element(G) ->
|
||||
?FORALL({E,Set},{G,set(G)},
|
||||
sets:is_element(E,eval(Set)) == mis_element(E,model(eval(Set)))).
|
||||
|
||||
prop_is_disjoint() -> prop_is_disjoint(int()).
|
||||
prop_is_disjoint(G) ->
|
||||
?FORALL({Set1,Set2},{set(G),set(G)},
|
||||
sets:is_disjoint(eval(Set1),eval(Set2)) == mis_disjoint(model(eval(Set1)),model(eval(Set2)))).
|
||||
|
||||
prop_filter() -> prop_filter(int()).
|
||||
prop_filter(G) ->
|
||||
?FORALL({Pred,Set},{function1(bool()),set(G)},
|
||||
model(sets:filter(Pred,eval(Set))) == mfilter(Pred,model(eval(Set)))).
|
||||
|
||||
|
63
lib/eqc/include/eqc.hrl
Normal file
63
lib/eqc/include/eqc.hrl
Normal file
|
@ -0,0 +1,63 @@
|
|||
% Generated file--see release:make()
|
||||
% eqc_macros.hrl
|
||||
-define(DELAY(X),fun()->X end).
|
||||
-define(FORCE(X),(X)()).
|
||||
-define(LET(X,E,E2),eqc_gen:bind(E,fun(X)->E2 end)).
|
||||
-define(SIZED(S,G),eqc_gen:sized(fun(S)->G end)).
|
||||
-define(SUCHTHAT(X,G,P),eqc_gen:suchthat(G,fun(X)->P end)).
|
||||
-define(SUCHTHATMAYBE(X,G,P),eqc_gen:suchthatmaybe(G,fun(X)->P end)).
|
||||
-define(SHRINK(G,Gs),eqc_gen:shrinkwith(G,?DELAY(Gs))).
|
||||
-define(LETSHRINK(Es,Gs,E), eqc_gen:letshrink(Gs,fun(Es) -> E end)).
|
||||
-define(LAZY(G),eqc_gen:lazy(?DELAY(G))).
|
||||
-define(IMPLIES(Pre,Prop),eqc:implies(Pre,??Pre,?DELAY(Prop))).
|
||||
-define(FORALL(X,Gen,Prop),eqc:forall(Gen,fun(X)->Prop end)).
|
||||
-define(WHENFAIL(Action,Prop),eqc:whenfail(fun(_) -> Action end,?LAZY(Prop))).
|
||||
-define(TRAPEXIT(E),eqc:trapexit(?DELAY(E))).
|
||||
-define(TIMEOUT(Limit,Prop),eqc:timeout(Limit,?LAZY(Prop))).
|
||||
-define(ALWAYS(N,P),eqc:always(N,?DELAY(P))).
|
||||
-define(SOMETIMES(N,P),eqc:sometimes(N,?DELAY(P))).
|
||||
% eqc_imports.hrl
|
||||
-import(eqc_gen,
|
||||
[pick/1,pick/2,
|
||||
includeif/2,return/1,applygen/2,
|
||||
noshrink/1,shrinkings/1,shrinking_path/2,
|
||||
timeout/2,
|
||||
resize/2,
|
||||
parameter/1, parameter/2, with_parameter/3, with_parameters/2,
|
||||
choose/2,
|
||||
shuffle/1,
|
||||
sample/1, sampleshrink/1,
|
||||
oneof/1, frequency/1,
|
||||
non_empty/1,
|
||||
elements/1, growingelements/1, list/1, shrink_list/1, vector/2,
|
||||
function0/1, function1/1, function2/1, function3/1, function4/1,
|
||||
bool/0, maybe/1, char/0, int/0, shrink_int/3, nat/0, largeint/0,
|
||||
real/0, orderedlist/1,
|
||||
binary/0, binary/1, bitstring/0, bitstring/1,
|
||||
default/2, weighted_default/2,
|
||||
seal/1,open/1,peek/1,
|
||||
fault/2, fault_rate/3, more_faulty/2, less_faulty/2, no_faults/1,
|
||||
prop_shrinks_without_duplicates/1, shrink_without_duplicates/1,
|
||||
is_generator/1]).
|
||||
|
||||
-import(eqc_symbolic,
|
||||
[eval/1,eval/2,defined/1,well_defined/1,pretty_print/1,pretty_print/2]).
|
||||
|
||||
-import(eqc,[equals/2,
|
||||
fails/1,
|
||||
conjunction/1,
|
||||
collect/2,collect/3,classify/3,aggregate/2,aggregate/3,measure/3,
|
||||
%distribution/0,
|
||||
with_title/1,
|
||||
%print_distribution/1,
|
||||
numtests/2,
|
||||
on_output/2,
|
||||
on_test/2,
|
||||
quickcheck/1,
|
||||
counterexample/0,counterexample/1,
|
||||
current_counterexample/0,
|
||||
module/1,
|
||||
check/2,
|
||||
recheck/1]).
|
||||
|
||||
-compile({parse_transform,eqc_warn}).
|
Reference in a new issue