rushcheck 0.3 → 0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/data/rushcheck/doc/policy.txt +107 -0
- data/data/rushcheck/doc/rushcheck.thtml +832 -0
- data/data/rushcheck/examples/candy.rb +6 -8
- data/data/rushcheck/examples/printf.rb +3 -3
- data/data/rushcheck/examples/proc.rb +4 -4
- data/data/rushcheck/examples/roguetile.rb +16 -16
- data/data/rushcheck/examples/sample.rb +10 -10
- data/data/rushcheck/rdoc/classes/Arbitrary.html +5 -5
- data/data/rushcheck/rdoc/classes/Arbitrary.src/M000082.html +18 -0
- data/data/rushcheck/rdoc/classes/Assertion.html +11 -11
- data/data/rushcheck/rdoc/classes/Assertion.src/M000019.html +20 -0
- data/data/rushcheck/rdoc/classes/Assertion.src/M000020.html +50 -0
- data/data/rushcheck/rdoc/classes/Coarbitrary.html +5 -5
- data/data/rushcheck/rdoc/classes/Coarbitrary.src/M000105.html +18 -0
- data/data/rushcheck/rdoc/classes/FalseClass.html +15 -15
- data/data/rushcheck/rdoc/classes/FalseClass.src/M000022.html +18 -0
- data/data/rushcheck/rdoc/classes/FalseClass.src/M000023.html +18 -0
- data/data/rushcheck/rdoc/classes/FalseClass.src/M000024.html +18 -0
- data/data/rushcheck/rdoc/classes/Float.html +20 -20
- data/data/rushcheck/rdoc/classes/Float.src/M000052.html +21 -0
- data/data/rushcheck/rdoc/classes/Float.src/M000053.html +18 -0
- data/data/rushcheck/rdoc/classes/Float.src/M000054.html +22 -0
- data/data/rushcheck/rdoc/classes/Float.src/M000055.html +20 -0
- data/data/rushcheck/rdoc/classes/Gen.html +102 -102
- data/data/rushcheck/rdoc/classes/Gen.src/M000030.html +4 -10
- data/data/rushcheck/rdoc/classes/Gen.src/M000031.html +29 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000032.html +6 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000033.html +14 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000034.html +10 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000035.html +4 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000036.html +4 -10
- data/data/rushcheck/rdoc/classes/Gen.src/M000037.html +4 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000038.html +4 -7
- data/data/rushcheck/rdoc/classes/Gen.src/M000039.html +4 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000040.html +10 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000041.html +4 -9
- data/data/rushcheck/rdoc/classes/Gen.src/M000042.html +7 -5
- data/data/rushcheck/rdoc/classes/Gen.src/M000043.html +4 -4
- data/data/rushcheck/rdoc/classes/Gen.src/M000044.html +4 -10
- data/data/rushcheck/rdoc/classes/Gen.src/M000045.html +23 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000046.html +19 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000047.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000048.html +24 -0
- data/data/rushcheck/rdoc/classes/Guard.html +10 -10
- data/data/rushcheck/rdoc/classes/Guard.src/M000028.html +27 -0
- data/data/rushcheck/rdoc/classes/Guard.src/M000029.html +18 -0
- data/data/rushcheck/rdoc/classes/HsRandom.html +20 -20
- data/data/rushcheck/rdoc/classes/HsRandom.src/M000088.html +22 -0
- data/data/rushcheck/rdoc/classes/HsRandom.src/M000089.html +32 -0
- data/data/rushcheck/rdoc/classes/HsRandom.src/M000090.html +18 -0
- data/data/rushcheck/rdoc/classes/Integer.html +20 -20
- data/data/rushcheck/rdoc/classes/Integer.src/M000010.html +18 -0
- data/data/rushcheck/rdoc/classes/Integer.src/M000011.html +18 -0
- data/data/rushcheck/rdoc/classes/Integer.src/M000012.html +21 -0
- data/data/rushcheck/rdoc/classes/Integer.src/M000013.html +19 -0
- data/data/rushcheck/rdoc/classes/NilClass.html +15 -15
- data/data/rushcheck/rdoc/classes/NilClass.src/M000064.html +18 -0
- data/data/rushcheck/rdoc/classes/NilClass.src/M000065.html +18 -0
- data/data/rushcheck/rdoc/classes/NilClass.src/M000066.html +18 -0
- data/data/rushcheck/rdoc/classes/Property.html +10 -10
- data/data/rushcheck/rdoc/classes/Property.src/M000077.html +26 -0
- data/data/rushcheck/rdoc/classes/Property.src/M000078.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomArray.html +15 -15
- data/data/rushcheck/rdoc/classes/RandomArray.src/M000025.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomArray.src/M000026.html +35 -0
- data/data/rushcheck/rdoc/classes/RandomArray.src/M000027.html +22 -0
- data/data/rushcheck/rdoc/classes/RandomBool.html +10 -10
- data/data/rushcheck/rdoc/classes/RandomBool.src/M000086.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomBool.src/M000087.html +19 -0
- data/data/rushcheck/rdoc/classes/RandomGen.html +20 -20
- data/data/rushcheck/rdoc/classes/RandomGen.src/M000083.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomGen.src/M000084.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomGen.src/M000085.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomHash.html +16 -16
- data/data/rushcheck/rdoc/classes/RandomHash.src/M000049.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomHash.src/M000050.html +26 -0
- data/data/rushcheck/rdoc/classes/RandomHash.src/M000051.html +22 -0
- data/data/rushcheck/rdoc/classes/RandomProc.html +20 -20
- data/data/rushcheck/rdoc/classes/RandomProc.src/M000060.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomProc.src/M000061.html +30 -0
- data/data/rushcheck/rdoc/classes/RandomProc.src/M000062.html +26 -0
- data/data/rushcheck/rdoc/classes/RandomProc.src/M000063.html +20 -0
- data/data/rushcheck/rdoc/classes/Result.html +19 -19
- data/data/rushcheck/rdoc/classes/Result.src/M000056.html +18 -0
- data/data/rushcheck/rdoc/classes/Result.src/M000057.html +18 -0
- data/data/rushcheck/rdoc/classes/Result.src/M000058.html +18 -0
- data/data/rushcheck/rdoc/classes/RushCheckConfig.html +41 -11
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000001.html +1 -1
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000002.html +1 -1
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000003.html +8 -4
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000004.html +4 -24
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000005.html +22 -39
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000006.html +55 -0
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000007.html +50 -0
- data/data/rushcheck/rdoc/classes/SpecialString.html +5 -5
- data/data/rushcheck/rdoc/classes/SpecialString.src/M000021.html +37 -0
- data/data/rushcheck/rdoc/classes/StdGen.html +27 -27
- data/data/rushcheck/rdoc/classes/StdGen.src/M000014.html +9 -4
- data/data/rushcheck/rdoc/classes/StdGen.src/M000015.html +21 -0
- data/data/rushcheck/rdoc/classes/StdGen.src/M000016.html +21 -0
- data/data/rushcheck/rdoc/classes/StdGen.src/M000017.html +18 -0
- data/data/rushcheck/rdoc/classes/StdGen.src/M000018.html +18 -0
- data/data/rushcheck/rdoc/classes/String.html +20 -20
- data/data/rushcheck/rdoc/classes/String.src/M000073.html +24 -0
- data/data/rushcheck/rdoc/classes/String.src/M000074.html +18 -0
- data/data/rushcheck/rdoc/classes/String.src/M000075.html +25 -0
- data/data/rushcheck/rdoc/classes/String.src/M000076.html +22 -0
- data/data/rushcheck/rdoc/classes/TestExausted.html +113 -0
- data/data/rushcheck/rdoc/classes/TestFailed.html +155 -0
- data/data/rushcheck/rdoc/classes/TestFailed.src/M000067.html +18 -0
- data/data/rushcheck/rdoc/classes/TestOk.html +113 -0
- data/data/rushcheck/rdoc/classes/TestOptions.html +180 -0
- data/data/rushcheck/rdoc/classes/TestOptions.src/M000008.html +18 -0
- data/data/rushcheck/rdoc/classes/TestOptions.src/M000009.html +18 -0
- data/data/rushcheck/rdoc/classes/TestResult.html +164 -0
- data/data/rushcheck/rdoc/classes/TestResult.src/M000068.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.html +96 -51
- data/data/rushcheck/rdoc/classes/Testable.src/M000091.html +4 -4
- data/data/rushcheck/rdoc/classes/Testable.src/M000092.html +4 -4
- data/data/rushcheck/rdoc/classes/Testable.src/M000095.html +4 -4
- data/data/rushcheck/rdoc/classes/Testable.src/M000096.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000097.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000099.html +19 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000100.html +21 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000101.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000103.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000104.html +18 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.html +20 -20
- data/data/rushcheck/rdoc/classes/TheStdGen.src/M000069.html +18 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.src/M000070.html +20 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.src/M000071.html +21 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.src/M000072.html +18 -0
- data/data/rushcheck/rdoc/classes/TrueClass.html +15 -15
- data/data/rushcheck/rdoc/classes/TrueClass.src/M000079.html +18 -0
- data/data/rushcheck/rdoc/classes/TrueClass.src/M000080.html +18 -0
- data/data/rushcheck/rdoc/classes/TrueClass.src/M000081.html +18 -0
- data/data/rushcheck/rdoc/created.rid +1 -1
- data/data/rushcheck/rdoc/files/rushcheck/config_rb.html +8 -1
- data/data/rushcheck/rdoc/files/rushcheck/testable_rb.html +3 -1
- data/data/rushcheck/rdoc/files/rushcheck/testoptions_rb.html +109 -0
- data/data/rushcheck/rdoc/files/rushcheck/testresult_rb.html +105 -0
- data/data/rushcheck/rdoc/files/rushcheck_rb.html +127 -0
- data/data/rushcheck/rdoc/fr_class_index.html +5 -0
- data/data/rushcheck/rdoc/fr_file_index.html +3 -1
- data/data/rushcheck/rdoc/fr_method_index.html +103 -94
- data/lib/rushcheck/arbitrary.rb +16 -12
- data/lib/rushcheck/array.rb +7 -6
- data/lib/rushcheck/assertion.rb +53 -50
- data/lib/rushcheck/bool.rb +26 -24
- data/lib/rushcheck/config.rb +131 -81
- data/lib/rushcheck/float.rb +4 -4
- data/lib/rushcheck/gen.rb +194 -182
- data/lib/rushcheck/guard.rb +9 -10
- data/lib/rushcheck/hash.rb +4 -3
- data/lib/rushcheck/integer.rb +11 -6
- data/lib/rushcheck/proc.rb +7 -7
- data/lib/rushcheck/property.rb +19 -15
- data/lib/rushcheck/random.rb +162 -159
- data/lib/rushcheck/result.rb +16 -12
- data/lib/rushcheck/string.rb +12 -12
- data/lib/rushcheck/testable.rb +99 -25
- data/lib/rushcheck/testoptions.rb +20 -0
- data/lib/rushcheck/testresult.rb +25 -0
- data/lib/{rushcheck/rushcheck.rb → rushcheck.rb} +2 -1
- metadata +93 -4
- data/data/rushcheck/doc/rushcheck.txt +0 -670
|
@@ -0,0 +1,832 @@
|
|
|
1
|
+
<address>
|
|
2
|
+
last-modified: 2006-10-06 Daisuke IKEGAMI <ikegami@madscientist.jp>
|
|
3
|
+
</address>
|
|
4
|
+
|
|
5
|
+
This tutorial is written in a simple markup language
|
|
6
|
+
"RedCloth3":http://whytheluckystiff.net/ruby/redcloth/.
|
|
7
|
+
This file is also dawnloadable from "rushcheck.txt":rushcheck.txt
|
|
8
|
+
and also in the distribution.
|
|
9
|
+
|
|
10
|
+
h1. Index
|
|
11
|
+
|
|
12
|
+
# <a href="#Getting start">Getting start</a>
|
|
13
|
+
## <a href="#install by RubyGems">(Option 1.) install by RubyGems</a>
|
|
14
|
+
## <a href="#using setup.rb after download source codes">(Option 2.) using setup.rb after download source codes</a>
|
|
15
|
+
# <a href="#Tutorial for writing testcase">Tutorial for writing testcase</a>
|
|
16
|
+
## <a href="#At first, we have to require the library.">At first, we have to require the library.</a>
|
|
17
|
+
## <a href="#Start writing testcases">Start writing testcases</a>
|
|
18
|
+
## <a href="#Watching the statistics">Watching the statistics</a>
|
|
19
|
+
### <a href="#trivial">'trivial'</a>
|
|
20
|
+
### <a href="#classify">'classify'</a>
|
|
21
|
+
## <a href="#With another basic classes for assertions">With another basic classes for assertions</a>
|
|
22
|
+
### <a href="#SpecialString">SpecialString</a>
|
|
23
|
+
### <a href="#Array and RandomArray">Array and RandomArray</a>
|
|
24
|
+
### <a href="#Hash and RandomHash">Hash and RandomHash</a>
|
|
25
|
+
### <a href="#Proc and RandomProc">Proc and RandomProc</a>
|
|
26
|
+
## <a href="#How to define random generators for user defined class">How to define random generators for user defined class</a>
|
|
27
|
+
### <a href="#using Gen.create">using Gen.create</a>
|
|
28
|
+
### <a href="#using Gen.bind and Gen.unit">using Gen.bind and Gen.unit</a>
|
|
29
|
+
### <a href="#using Gen.new">using Gen.new</a>
|
|
30
|
+
## <a href="#Another staffs in Gen class">Another staffs in Gen class</a>
|
|
31
|
+
### <a href="#Gen.choose">Gen.choose</a>
|
|
32
|
+
### <a href="#Gen.frequency">Gen.frequency</a>
|
|
33
|
+
### <a href="#Gen.lift_array">Gen.lift_array</a>
|
|
34
|
+
### <a href="#Gen.oneof">Gen.oneof</a>
|
|
35
|
+
### <a href="#Gen.promote">Gen.promote</a>
|
|
36
|
+
### <a href="#Gen.rand">Gen.rand</a>
|
|
37
|
+
### <a href="#Gen.sized">Gen.sized</a>
|
|
38
|
+
### <a href="#Gen.unit">Gen.unit</a>
|
|
39
|
+
### <a href="#Gen.vector">Gen.vector</a>
|
|
40
|
+
## <a href="#how to write random Proc which returns objects in YourClass">how to write random Proc which returns objects in YourClass</a>
|
|
41
|
+
# <a href="#Further information">Further information</a>
|
|
42
|
+
|
|
43
|
+
h1. <a name="Getting start">Getting start</a>
|
|
44
|
+
|
|
45
|
+
There are two ways to install RushCheck.
|
|
46
|
+
|
|
47
|
+
h2. <a name="install by RubyGems">(Option 1.) install by RubyGems</a>
|
|
48
|
+
|
|
49
|
+
You can install RushCheck easily with
|
|
50
|
+
"rubygems":http://docs.rubygems.org/.
|
|
51
|
+
|
|
52
|
+
<pre>% sudo gem install rushcheck</pre>
|
|
53
|
+
|
|
54
|
+
Done!
|
|
55
|
+
|
|
56
|
+
h2. <a name="using setup.rb after download source codes">(Option 2.) using setup.rb after download source codes.</a>
|
|
57
|
+
|
|
58
|
+
Instead, if you don't have rubygems, or like to install from source
|
|
59
|
+
codes, then you can follow the steps.
|
|
60
|
+
|
|
61
|
+
# Get the tar-ball of current release from
|
|
62
|
+
"download page":http://rubyforge.org/frs/?group_id=2027
|
|
63
|
+
# Expand it
|
|
64
|
+
# finally, type as follows
|
|
65
|
+
|
|
66
|
+
<pre>% sudo ruby setup.rb</pre>
|
|
67
|
+
|
|
68
|
+
See also the following;
|
|
69
|
+
|
|
70
|
+
<pre>% setup.rb help</pre>
|
|
71
|
+
|
|
72
|
+
h1. <a name="Tutorial for writing testcase">Tutorial for writing testcase</a>
|
|
73
|
+
|
|
74
|
+
h2. <a name="At first, we have to require the library.">At first, we have to require the library.</a>
|
|
75
|
+
|
|
76
|
+
If you have installed RushCheck using RubyGems, then you should add
|
|
77
|
+
the following two lines to your test codes.
|
|
78
|
+
|
|
79
|
+
<pre>
|
|
80
|
+
require 'rubygems'
|
|
81
|
+
require_gem 'rushcheck'
|
|
82
|
+
</pre>
|
|
83
|
+
|
|
84
|
+
Otherwise, if you have installed RushCheck by setup.rb, then
|
|
85
|
+
add the simple one line.
|
|
86
|
+
|
|
87
|
+
<pre>
|
|
88
|
+
require 'rushcheck'
|
|
89
|
+
</pre>
|
|
90
|
+
|
|
91
|
+
The following maybe useful if you don't matter whether you use
|
|
92
|
+
rubygems or not.
|
|
93
|
+
<pre>
|
|
94
|
+
begin
|
|
95
|
+
require 'rubygems'
|
|
96
|
+
require_gem 'rushcheck'
|
|
97
|
+
rescue LoadError
|
|
98
|
+
require 'rushcheck'
|
|
99
|
+
end
|
|
100
|
+
</pre>
|
|
101
|
+
|
|
102
|
+
h2. Don't forget to require also your library file if the class you want to test is included in it.
|
|
103
|
+
|
|
104
|
+
<pre>
|
|
105
|
+
require 'your_library'
|
|
106
|
+
</pre>
|
|
107
|
+
|
|
108
|
+
h2. <a name="Start writing testcases">Start writing testcases</a>
|
|
109
|
+
|
|
110
|
+
OK, then we can start to write test codes. RushCheck requires to
|
|
111
|
+
write __assertion based__ testcases. An assertion of function (or
|
|
112
|
+
method) consists of triple where inputs, guard conditions and a
|
|
113
|
+
testing property block. Here is a templete of assertion:
|
|
114
|
+
|
|
115
|
+
<pre>
|
|
116
|
+
RushCheck::Assertion.new(Class1, Class2, ...) do |var1, var2, ...|
|
|
117
|
+
# testing property block
|
|
118
|
+
# this block should return boolean value (true, false or nil)
|
|
119
|
+
# in Ruby
|
|
120
|
+
end
|
|
121
|
+
</pre>
|
|
122
|
+
|
|
123
|
+
For example, assume that we want to test the method 'sort' in
|
|
124
|
+
Array. The following assertion is a simple testcase:
|
|
125
|
+
|
|
126
|
+
<pre>
|
|
127
|
+
ast_zero =
|
|
128
|
+
RushCheck::Assertion.new() do
|
|
129
|
+
[].sort == []
|
|
130
|
+
end
|
|
131
|
+
</pre>
|
|
132
|
+
|
|
133
|
+
whether if we sort empty array the result is also empty.
|
|
134
|
+
This assertion does not have any inputs and guards but only have
|
|
135
|
+
the property block.
|
|
136
|
+
|
|
137
|
+
Let's see another example:
|
|
138
|
+
<pre>
|
|
139
|
+
ast_one =
|
|
140
|
+
RushCheck::Assertion.new(Integer) do |x|
|
|
141
|
+
[x].sort == [x]
|
|
142
|
+
end
|
|
143
|
+
</pre>
|
|
144
|
+
|
|
145
|
+
This assertion defines that we claim for any integer 'x', an array
|
|
146
|
+
[x] is not changed after sorting. We can test the property 100 times:
|
|
147
|
+
|
|
148
|
+
<pre>
|
|
149
|
+
irb> ast_one.verbose_check
|
|
150
|
+
1:
|
|
151
|
+
[-1]
|
|
152
|
+
2:
|
|
153
|
+
[-2]
|
|
154
|
+
... (snip) ...
|
|
155
|
+
99:
|
|
156
|
+
[6]
|
|
157
|
+
100:
|
|
158
|
+
[1]
|
|
159
|
+
OK, passed 100 tests.
|
|
160
|
+
true
|
|
161
|
+
irb> ast_one.check
|
|
162
|
+
OK, passed 100 tests.
|
|
163
|
+
true
|
|
164
|
+
irb>
|
|
165
|
+
</pre>
|
|
166
|
+
|
|
167
|
+
RushCheck supports random testing such as above. We will see later
|
|
168
|
+
how to change the number of test, how to change the distribution,
|
|
169
|
+
etc. Here we learned two testing methods, verbose_check and check.
|
|
170
|
+
'verbose_check' displays every instances of test, on the other hand
|
|
171
|
+
'check' does not display inputs but only the result.
|
|
172
|
+
|
|
173
|
+
Next example shows how RushCheck displays the counter example. If
|
|
174
|
+
an assertion is failed, then there is a counter example of the
|
|
175
|
+
assertion.
|
|
176
|
+
|
|
177
|
+
<pre>
|
|
178
|
+
ast_two =
|
|
179
|
+
RushCheck::Assertion.new(Integer, Integer) do |x, y|
|
|
180
|
+
[x, y].sort == [x, y]
|
|
181
|
+
end
|
|
182
|
+
</pre>
|
|
183
|
+
|
|
184
|
+
The above test is failed sometimes and we can find the result after
|
|
185
|
+
checking.
|
|
186
|
+
|
|
187
|
+
<pre>
|
|
188
|
+
irb> ast_two.check
|
|
189
|
+
Falsifiable, after 3 tests:
|
|
190
|
+
[2, -1]
|
|
191
|
+
false
|
|
192
|
+
irb>
|
|
193
|
+
</pre>
|
|
194
|
+
|
|
195
|
+
Here, the counter example [2, -1] of the assertion is appeared. In
|
|
196
|
+
fact, [2, -1].sort equals [-1, 2] and does not equal [2, -1].
|
|
197
|
+
|
|
198
|
+
Sometimes, we need several pre-conditions for tests. For example,
|
|
199
|
+
if we have a pre-condition 'x <= y' in the previous assertion, then
|
|
200
|
+
the assertion should be succeeded. We can write pre-conditions as
|
|
201
|
+
guards in the property block:
|
|
202
|
+
|
|
203
|
+
<pre>
|
|
204
|
+
ast_two_sorted =
|
|
205
|
+
RushCheck::Assertion.new(Integer, Integer) do |x, y|
|
|
206
|
+
RushCheck::guard { x <= y }
|
|
207
|
+
[x, y].sort == [x, y]
|
|
208
|
+
end
|
|
209
|
+
</pre>
|
|
210
|
+
<pre>
|
|
211
|
+
irb> ast_two_sorted.check
|
|
212
|
+
OK, passed 100 tests.
|
|
213
|
+
true
|
|
214
|
+
irb>
|
|
215
|
+
</pre>
|
|
216
|
+
|
|
217
|
+
Note that it is always assumed that the number of arguments of
|
|
218
|
+
Assertion.new must be equal to the number of variables of the block.
|
|
219
|
+
(Until ver 0.3, experimentally the number of arguments can be
|
|
220
|
+
differed, however from ver 0.4, they must be equal.)
|
|
221
|
+
The arguments of Assertion.new corresponds to the variables of block
|
|
222
|
+
one to one. We can have any number of guards in the property block.
|
|
223
|
+
If the guard property does not hold in random testing, then the test
|
|
224
|
+
is abort and try to take another random instances. We can imagine the
|
|
225
|
+
following test sequences in ast_two_sorted.
|
|
226
|
+
|
|
227
|
+
# x, y = 1, 2
|
|
228
|
+
-> guard g is passed
|
|
229
|
+
-> check the test block and succeed
|
|
230
|
+
# x, y = 3, 1
|
|
231
|
+
-> guard g is failed and abort
|
|
232
|
+
(not counted)
|
|
233
|
+
# x, y = 2, 3
|
|
234
|
+
-> ...
|
|
235
|
+
# ... (whether passed 100 tests or not)
|
|
236
|
+
|
|
237
|
+
h2. <a name="Watching the statistics">Watching the statistics</a>
|
|
238
|
+
|
|
239
|
+
In the previous section, we saw two methods 'check' and
|
|
240
|
+
'verbose_check'. Sometimes, we want to watch the statistics of
|
|
241
|
+
random testing. However 'check' shows less information, and
|
|
242
|
+
'verbose_check' is too noisy. RushCheck has several options to
|
|
243
|
+
watch the statistics.
|
|
244
|
+
|
|
245
|
+
h3. <a name="trivial">'trivial'</a>
|
|
246
|
+
|
|
247
|
+
You may not want to check the trivial case in random test. As we
|
|
248
|
+
have seen, we can ignore the trivial case using the guard
|
|
249
|
+
condition. However, on the other hand, we can watch how many
|
|
250
|
+
trivial cases are appeared in random test.
|
|
251
|
+
|
|
252
|
+
<pre>
|
|
253
|
+
ast_sort_triv =
|
|
254
|
+
RushCheck::Assertion.new(Integer, Integer) do |x, y|
|
|
255
|
+
RushCheck::guard {x <= y}
|
|
256
|
+
([x, y].sort == [x, y]).trivial{ x == y }
|
|
257
|
+
end
|
|
258
|
+
</pre>
|
|
259
|
+
<pre>
|
|
260
|
+
irb> ast_sort_triv.check
|
|
261
|
+
OK, passed 100 tests(14%, trivial).
|
|
262
|
+
true
|
|
263
|
+
</pre>
|
|
264
|
+
|
|
265
|
+
Here, we have 14% (i.e. 14 times) trivial (x == y) cases in the
|
|
266
|
+
test.
|
|
267
|
+
|
|
268
|
+
h3. <a name="classify">'classify'</a>
|
|
269
|
+
|
|
270
|
+
In addition, we can give another names to watching statistics.
|
|
271
|
+
|
|
272
|
+
<pre>
|
|
273
|
+
ast_sort_classify =
|
|
274
|
+
RushCheck::Assertion.new(Integer, Integer) do |x, y|
|
|
275
|
+
RushCheck::guard {x <= y}
|
|
276
|
+
test = ([x, y].sort == [x, y])
|
|
277
|
+
test.classify('same'){ x == y }.
|
|
278
|
+
classify('bit diff'){ (x - y).abs == 1 }
|
|
279
|
+
end
|
|
280
|
+
</pre>
|
|
281
|
+
<pre>
|
|
282
|
+
irb> ast_sort_classify.check
|
|
283
|
+
OK, passed 100 tests.
|
|
284
|
+
18%, same.
|
|
285
|
+
11%, bit diff.
|
|
286
|
+
true
|
|
287
|
+
irb>
|
|
288
|
+
</pre>
|
|
289
|
+
|
|
290
|
+
h2. <a name="With another basic classes for assertions">With another basic classes for assertions</a>
|
|
291
|
+
|
|
292
|
+
In previous sections, we have seen how to check assertions for any
|
|
293
|
+
integers. In similar way, we can define the assertions for any float
|
|
294
|
+
numbers or any string.
|
|
295
|
+
|
|
296
|
+
<pre>
|
|
297
|
+
RushCheck::Assertion.new(Float, String, ...) do |ratio, name,...|
|
|
298
|
+
# testcase
|
|
299
|
+
end
|
|
300
|
+
</pre>
|
|
301
|
+
|
|
302
|
+
RushCheck has default random generators for the following basic classes:
|
|
303
|
+
|
|
304
|
+
* Integer
|
|
305
|
+
* Float
|
|
306
|
+
* String
|
|
307
|
+
|
|
308
|
+
If you want to change the distribution of randomness, then you have
|
|
309
|
+
to write a code for generator. There are some examples for writing
|
|
310
|
+
generators. In the next section, I will introduce SpecialString
|
|
311
|
+
whose distribution differs to the default implementation of String.
|
|
312
|
+
|
|
313
|
+
Even Array, Hash and Proc are also primitive classes, however the
|
|
314
|
+
randomness of them should be changed in testing codes. Therefore,
|
|
315
|
+
RushCheck provides an abstract generators for them. Programmer need
|
|
316
|
+
to write a subclass of the abstract generators. Later
|
|
317
|
+
I will show you how to write a subclass of RandomArray, etc.
|
|
318
|
+
|
|
319
|
+
h3. <a name="SpecialString">SpecialString</a>
|
|
320
|
+
|
|
321
|
+
Sometimes, we want to check special characters, for example the
|
|
322
|
+
backslash '\' or unprinted characters 'ESC', 'NUL' and so on.
|
|
323
|
+
SpecialString is a subclass of String which is defined in
|
|
324
|
+
'rushcheck/string'. This library is already required in
|
|
325
|
+
'rushcheck/rushcheck' and don't need to require again.
|
|
326
|
+
|
|
327
|
+
The output of random generator of SpecialString has different
|
|
328
|
+
distribution of its of String. At String, the distribution of
|
|
329
|
+
characters are normalized. On the other hand, the distribution in
|
|
330
|
+
SpecialString is weighted and the generator provides special
|
|
331
|
+
characters more often than alphabets. In detail, the distribution is
|
|
332
|
+
as follows:
|
|
333
|
+
|
|
334
|
+
|_.the distribution of SpecialString |
|
|
335
|
+
|Alphabet |15% |
|
|
336
|
+
|Control characters|50% (such as NUL)|
|
|
337
|
+
|Number |10% |
|
|
338
|
+
|Special characters|25% (such as '\')|
|
|
339
|
+
|
|
340
|
+
Using SpecialString in assertions, it is more likely to find the
|
|
341
|
+
counter example. The following example is the famous bug which is
|
|
342
|
+
called 'malformed format bug'.
|
|
343
|
+
|
|
344
|
+
<pre>
|
|
345
|
+
malformed_format_string =
|
|
346
|
+
RushCheck::Assertion.new(String) { |s| sprintf(s); true}
|
|
347
|
+
|
|
348
|
+
malformed_format_string2 =
|
|
349
|
+
RushCheck::Assertion.new(SpecialString) { |s| sprintf(s); true}
|
|
350
|
+
</pre>
|
|
351
|
+
<pre>
|
|
352
|
+
irb> malformed_format_string.check
|
|
353
|
+
Falsifiable, after 86 tests:
|
|
354
|
+
Unexpected exception: #<ArgumentError: malformed format string - %&>
|
|
355
|
+
... snip error traces ...
|
|
356
|
+
["\n&'e!]hr(%&\031Vi\003 }ss"]
|
|
357
|
+
false
|
|
358
|
+
irb> malformed_format_string2.check
|
|
359
|
+
Falsifiable, after 15 tests:
|
|
360
|
+
Unexpected exception: #<ArgumentError: malformed format string>
|
|
361
|
+
["%\037-R"]
|
|
362
|
+
false
|
|
363
|
+
</pre>
|
|
364
|
+
|
|
365
|
+
In these results, we can see RushCheck find the counter example
|
|
366
|
+
after 86 tests with String, on the other hand, find it quickly after 15
|
|
367
|
+
tests with SpecialString.
|
|
368
|
+
|
|
369
|
+
It is easy to change the distribution in SpecialString. You can
|
|
370
|
+
define your subclass of SpecialString as follows:
|
|
371
|
+
|
|
372
|
+
<pre>
|
|
373
|
+
class YourSpecialString < SpecialString
|
|
374
|
+
@@frequency = { 'alphabet' => 1,
|
|
375
|
+
'control' => 0,
|
|
376
|
+
'number' => 0,
|
|
377
|
+
'special' => 9 }
|
|
378
|
+
end
|
|
379
|
+
</pre>
|
|
380
|
+
|
|
381
|
+
h3. <a name="Array and RandomArray">Array and RandomArray</a>
|
|
382
|
+
|
|
383
|
+
The meaning of randomness for Array must be changed in testing
|
|
384
|
+
codes. Sometimes you needs a random array of Integer, and another a
|
|
385
|
+
random array of String. So what is random array?
|
|
386
|
+
|
|
387
|
+
RushCheck provides an abstract class RandomArray for abstract random
|
|
388
|
+
generator. Programmer have to write a subclass of RandomArray as
|
|
389
|
+
follows:
|
|
390
|
+
|
|
391
|
+
<pre>
|
|
392
|
+
# for random array of integers
|
|
393
|
+
class MyRandomArray < RandomArray; end
|
|
394
|
+
MyRandomArray.set_pattern(Integer) {|ary, i| Integer}
|
|
395
|
+
</pre>
|
|
396
|
+
|
|
397
|
+
The class method set_pattern takes a variable and a block.
|
|
398
|
+
Because array is __inductive__ structure, it can be defined by the
|
|
399
|
+
basecase and the inductive step.
|
|
400
|
+
|
|
401
|
+
For example, let's consider a random array in the following pattern
|
|
402
|
+
@[Integer, String, Integer, String, ...]@
|
|
403
|
+
where it has a random Integer at the odd index and a random String at
|
|
404
|
+
the even index. Then we can write a random array with this pattern:
|
|
405
|
+
|
|
406
|
+
<pre>
|
|
407
|
+
MyRandomArray.set_pattern(Integer) do |ary, i|
|
|
408
|
+
if i % 2 == 0
|
|
409
|
+
then Integer
|
|
410
|
+
else String
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
</pre>
|
|
414
|
+
|
|
415
|
+
More complecated example? OK, let's consider a stream:
|
|
416
|
+
* the first component is Integer
|
|
417
|
+
* if the i-th component is positive integer
|
|
418
|
+
** then (i+1)-th component is String
|
|
419
|
+
** otherwise the (i+1)-th component is Integer
|
|
420
|
+
|
|
421
|
+
<pre>
|
|
422
|
+
MyRandomArray.set_pattern(Integer) do |ary, i|
|
|
423
|
+
if ary[i].kind_of?(Integer) && ary[i] >= 0
|
|
424
|
+
then String
|
|
425
|
+
else Integer
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
</pre>
|
|
429
|
+
|
|
430
|
+
In this way, we can define any random array with any pattern.
|
|
431
|
+
|
|
432
|
+
h3. <a name="Hash and RandomHash">Hash and RandomHash</a>
|
|
433
|
+
|
|
434
|
+
Hash is also primitive and not so clear what is a random hash, like
|
|
435
|
+
array. RushCheck provides an abstract random generator RandomHash,
|
|
436
|
+
and programmer can write a subclass of RandomHash.
|
|
437
|
+
|
|
438
|
+
<pre>
|
|
439
|
+
class MyRandomHash < RandomHash; end
|
|
440
|
+
pat = { 'key1' => Integer, 'key2' => String }
|
|
441
|
+
MyRandomHash.set_pattern(pat)
|
|
442
|
+
</pre>
|
|
443
|
+
|
|
444
|
+
In this example, we can get a random Hash with two keys ('key1' and
|
|
445
|
+
'key2'). Here the keys are String, but we can give any object as
|
|
446
|
+
usual in Hash. Is it clear to define random hash? I think so.
|
|
447
|
+
(If not it is clear, then the interface may be changed in future)
|
|
448
|
+
|
|
449
|
+
h3. <a name="Proc and RandomProc">Proc and RandomProc</a>
|
|
450
|
+
|
|
451
|
+
It is not difficult to create a random Proc object.
|
|
452
|
+
As we saw in the previous sections, we have to write a subclass of
|
|
453
|
+
RandomProc.
|
|
454
|
+
|
|
455
|
+
<pre>
|
|
456
|
+
class MyRandomProc < RandomProc; end
|
|
457
|
+
MyRandomProc.set_pattern([Integer], [Integer])
|
|
458
|
+
</pre>
|
|
459
|
+
|
|
460
|
+
Here, we define a random procedure which takes an integer and
|
|
461
|
+
returns an integer also. In general, Ruby's function and method can
|
|
462
|
+
be regarded as a relation. (not a function in mathematics!)
|
|
463
|
+
Therefore I think random procedures can be generated by a pair of
|
|
464
|
+
inputs and outputs.
|
|
465
|
+
|
|
466
|
+
Let's consider a simple example. In general, any functions f, g, and
|
|
467
|
+
h should satisfy the associativity property:
|
|
468
|
+
<pre>
|
|
469
|
+
for all x, f(g(h(x)) === (f . g)(h (x))
|
|
470
|
+
where f . g is a composition of functions in mathematical way
|
|
471
|
+
</pre>
|
|
472
|
+
|
|
473
|
+
<pre>
|
|
474
|
+
class Proc
|
|
475
|
+
# application
|
|
476
|
+
def **(other)
|
|
477
|
+
Proc.new do |*args|
|
|
478
|
+
res = other.call(*args)
|
|
479
|
+
call(*res)
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
class MyRandomProc < RandomProc; end
|
|
485
|
+
|
|
486
|
+
def associativity_integer
|
|
487
|
+
MyRandomProc.set_pattern([Integer], [Integer])
|
|
488
|
+
RushCheck::Assertion.new(MyRandomProc, MyRandomProc,
|
|
489
|
+
MyRandomProc, Integer) do
|
|
490
|
+
|f, g, h, x|
|
|
491
|
+
(f ** (g ** h)).call(x) == ((f ** g) ** h).call(x)
|
|
492
|
+
end.check
|
|
493
|
+
end
|
|
494
|
+
</pre>
|
|
495
|
+
|
|
496
|
+
P.S.
|
|
497
|
+
The arbitrary method is used to create a random object for test
|
|
498
|
+
instance. Then you may wonder what is the coarbitrary method?
|
|
499
|
+
The coarbitrary method is used to generate a random procedure
|
|
500
|
+
(lambda), which is one of central idea in QuickCheck.
|
|
501
|
+
|
|
502
|
+
h2. <a name="How to define random generators for user defined class">How to define random generators for user defined class</a>
|
|
503
|
+
|
|
504
|
+
h3. Understand your class. What is a random object?
|
|
505
|
+
|
|
506
|
+
To use your class in the assertion, like follows
|
|
507
|
+
<pre>
|
|
508
|
+
RushCheck::Assertion.new(YourClass) { |obj, ...| ...}
|
|
509
|
+
</pre>
|
|
510
|
+
you have to write a code which generates a random object in your
|
|
511
|
+
class. Therefore, at first we have to consider
|
|
512
|
+
__what is a random object in YourClass?__
|
|
513
|
+
|
|
514
|
+
Sometimes the answer is not unique; there may be several ways for
|
|
515
|
+
generating random objects. Like SpecialString in RushCheck, you can
|
|
516
|
+
also write an abstract random generator.
|
|
517
|
+
|
|
518
|
+
OK, after thinking about the question, we have to write a code.
|
|
519
|
+
To define random generators, we have to add a class method arbitrary
|
|
520
|
+
in YourClass.
|
|
521
|
+
|
|
522
|
+
<pre>
|
|
523
|
+
class YourClass
|
|
524
|
+
extend RushCheck::Arbitrary
|
|
525
|
+
|
|
526
|
+
def self.arbitrary
|
|
527
|
+
# override the class method arbitrary
|
|
528
|
+
...
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
</pre>
|
|
532
|
+
|
|
533
|
+
If you need to define a random proc which returns a object in
|
|
534
|
+
YourClass, you have to include Coarbitrary, also.
|
|
535
|
+
|
|
536
|
+
<pre>
|
|
537
|
+
class YourClass
|
|
538
|
+
extend RushCheck::Arbitrary
|
|
539
|
+
include RushCheck::Coarbitrary
|
|
540
|
+
|
|
541
|
+
def self.arbitrary
|
|
542
|
+
...
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
def coarbitrary(g)
|
|
546
|
+
...
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
</pre>
|
|
550
|
+
|
|
551
|
+
However, because it is little complecated to implement both
|
|
552
|
+
arbitrary and coarbitrary, let's focus how to implement arbitrary
|
|
553
|
+
first.
|
|
554
|
+
|
|
555
|
+
Let's consider the first example Candy. The Candy class requires its
|
|
556
|
+
name and its price at initialize. The name should be a String, and the
|
|
557
|
+
price Integer. The Candy class may have several instance methods, but
|
|
558
|
+
they are omitted because not important to define the random object.
|
|
559
|
+
|
|
560
|
+
<pre>
|
|
561
|
+
class Candy
|
|
562
|
+
|
|
563
|
+
def initialize(name, price)
|
|
564
|
+
raise unless price >= 0
|
|
565
|
+
@name, @price = name, price
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def foo
|
|
569
|
+
...
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def bar
|
|
573
|
+
...
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
end
|
|
577
|
+
</pre>
|
|
578
|
+
|
|
579
|
+
To write random generator, we have to look up 'initialize'.
|
|
580
|
+
Here, assume that @name belongs String and @price belongs Integer.
|
|
581
|
+
It is natural that we assumes @price should be positive.
|
|
582
|
+
|
|
583
|
+
One simple random generator for Candy:
|
|
584
|
+
|
|
585
|
+
h3. <a name="using Gen.create">(1) using Gen.create</a>
|
|
586
|
+
|
|
587
|
+
<pre>
|
|
588
|
+
class Candy
|
|
589
|
+
extend Arbitrary
|
|
590
|
+
|
|
591
|
+
def self.arbitrary
|
|
592
|
+
RushCheck::Gen.create(String, Integer) do |name, price|
|
|
593
|
+
RushCheck::guard { price >= 0 }
|
|
594
|
+
new(name, price)
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
</pre>
|
|
599
|
+
|
|
600
|
+
Gen.create takes an array of Gen object (here, [Integer.arbitrary,
|
|
601
|
+
String.arbitrary]) and a block. The block takes variables which is
|
|
602
|
+
corresponded to the array, as Assertion.new. If guard is failed,
|
|
603
|
+
then RushCheck retry to create another random instance.
|
|
604
|
+
|
|
605
|
+
Note that we can use a trick instead of the guard property.
|
|
606
|
+
<pre>
|
|
607
|
+
price = - price if price < 0 # g.guard { price >= 0 }
|
|
608
|
+
</pre>
|
|
609
|
+
In this case, this is more efficient to generate random instance
|
|
610
|
+
than with the guard. However, sometimes we don't have this kind
|
|
611
|
+
trick and we can use some guards.
|
|
612
|
+
|
|
613
|
+
Remark: from version 0.4, Gen.create is changed to require classes
|
|
614
|
+
in its argument from Gen objects.
|
|
615
|
+
|
|
616
|
+
h3. <a name="using Gen.bind and Gen.unit">(2) using Gen#bind and Gen.unit</a>
|
|
617
|
+
|
|
618
|
+
<pre>
|
|
619
|
+
class Candy
|
|
620
|
+
extend RushCheck::Arbitrary
|
|
621
|
+
|
|
622
|
+
def self.arbitrary
|
|
623
|
+
String.arbitrary.bind do |name|
|
|
624
|
+
Integer.arbitrary.bind do |price|
|
|
625
|
+
price = - price if price < 0 # trick as I described above
|
|
626
|
+
RushCheck::Gen.unit(new(name, price))
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
</pre>
|
|
632
|
+
|
|
633
|
+
Puzzled? OK, they can be readed as follows:
|
|
634
|
+
|
|
635
|
+
* take a random (arbitrary) string and call it 'name'
|
|
636
|
+
** take a random integer and call it 'price'
|
|
637
|
+
*** return a Gen object which has a new Candy(name, price)
|
|
638
|
+
|
|
639
|
+
In general, the class method arbitrary should return a Gen object.
|
|
640
|
+
Check also gen.rb in RushCheck. There are several combinators to
|
|
641
|
+
create random generators.
|
|
642
|
+
|
|
643
|
+
There are several way to implement random generators. The next
|
|
644
|
+
example is to use Gen.new without bind and unit.
|
|
645
|
+
|
|
646
|
+
h3. <a name="using Gen.new">(3) using Gen.new</a>
|
|
647
|
+
|
|
648
|
+
<pre>
|
|
649
|
+
class Candy
|
|
650
|
+
extend RushCheck::Arbitrary
|
|
651
|
+
|
|
652
|
+
def self.arbitrary
|
|
653
|
+
RushCheck::Gen.new do |n, r|
|
|
654
|
+
r2 = r
|
|
655
|
+
name, price = [String, Integer].map do |c|
|
|
656
|
+
r1, r2 = r2.split
|
|
657
|
+
c.arbitrary.value(n. r1)
|
|
658
|
+
end
|
|
659
|
+
price = - price if price < 0 # trick
|
|
660
|
+
new(name, price)
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
end
|
|
664
|
+
</pre>
|
|
665
|
+
|
|
666
|
+
This pattern is useful if your class has many valiables for
|
|
667
|
+
initialize. Because binding patterns needs much depth of method call
|
|
668
|
+
chains, it may be failed. This technique is used to avoid the stack
|
|
669
|
+
overflow. This is one difference between Haskell and Ruby.
|
|
670
|
+
|
|
671
|
+
The implementation can be understanded as follows:
|
|
672
|
+
* self.arbitrary returns a new Gen object.
|
|
673
|
+
** let n be an integer and r be a random generator.
|
|
674
|
+
** let r2 equal r
|
|
675
|
+
** name and price are both random objects where
|
|
676
|
+
*** get new two random generator r1 and r2 from old r2
|
|
677
|
+
*** assign a random value by generating 'arbitrary.value(n, r1)'
|
|
678
|
+
**** and discard the random generator r1
|
|
679
|
+
**** ...
|
|
680
|
+
|
|
681
|
+
Note that we need new random generator for each random object.
|
|
682
|
+
Here we create new random generator by spliting. If you use same
|
|
683
|
+
random generator for generating different objects, then the
|
|
684
|
+
distribution of objects are same (not generated randomly).
|
|
685
|
+
|
|
686
|
+
Because sometimes the initialize of YourClass is complecated,
|
|
687
|
+
then the random generator self.arbitrary turns to be complicated
|
|
688
|
+
also.
|
|
689
|
+
|
|
690
|
+
In next sections, I will introduce several generators in gen.rb.
|
|
691
|
+
They may be useful to create your own random genrator. See also rdoc
|
|
692
|
+
of Gen.
|
|
693
|
+
|
|
694
|
+
h3. Appendix: expensive candy.
|
|
695
|
+
|
|
696
|
+
Using Gen.create to generate random instance, if we gives another
|
|
697
|
+
guard such as
|
|
698
|
+
<pre>
|
|
699
|
+
RushCheck::guard { price >= 100000 } # very expensive candy!
|
|
700
|
+
</pre>
|
|
701
|
+
then it consumes much time to generate random instance because the
|
|
702
|
+
guard fails so many times. When RushCheck creates random instances,
|
|
703
|
+
it starts smallest as possible, then the size becomes larger in
|
|
704
|
+
repeating tests. Therefore, if the guard instance seems failed so
|
|
705
|
+
often, then we need another seeds of generators. Here is another
|
|
706
|
+
generators for expensive candy instance.
|
|
707
|
+
|
|
708
|
+
<pre>
|
|
709
|
+
lo = 100000
|
|
710
|
+
g = RushCheck::Gen.sized { |n| RushCheck::Gen.choose(lo, n + lo)}
|
|
711
|
+
xs = [String.arbitrary, g]
|
|
712
|
+
</pre>
|
|
713
|
+
See gen.rb and the following sections in details for how to get
|
|
714
|
+
another generator.
|
|
715
|
+
|
|
716
|
+
h2. <a name="Another staffs in Gen class">Another staffs in Gen class</a>
|
|
717
|
+
|
|
718
|
+
To help defining random objects in your class, there are several
|
|
719
|
+
functions in Gen class.
|
|
720
|
+
|
|
721
|
+
h3. <a name="Gen.choose">Gen.choose</a>
|
|
722
|
+
|
|
723
|
+
Gen.choose(lo, hi) returns a Gen object which generates a random
|
|
724
|
+
value in the bound.
|
|
725
|
+
|
|
726
|
+
example.
|
|
727
|
+
<pre>
|
|
728
|
+
Gen.choose(0, 10) # a generator of Integer in (0..10)
|
|
729
|
+
</pre>
|
|
730
|
+
|
|
731
|
+
h3. <a name="Gen.frequency">Gen.frequency</a>
|
|
732
|
+
|
|
733
|
+
Gen.frequency requires an array of pair of Integer and Gen objects,
|
|
734
|
+
and returns a Gen object. Gen.frequency is used to define the
|
|
735
|
+
distribution of randomness.
|
|
736
|
+
|
|
737
|
+
example.
|
|
738
|
+
<pre>
|
|
739
|
+
Gen.frequency([[3, Integer.arbitrary], [7, String.arbitrary]])
|
|
740
|
+
# return a random integer or a random string (by choosing
|
|
741
|
+
# randomly) Integer:30% String: 70%
|
|
742
|
+
</pre>
|
|
743
|
+
|
|
744
|
+
See also SpecialString.
|
|
745
|
+
|
|
746
|
+
h3. <a name="Gen.lift_array">Gen.lift_array</a>
|
|
747
|
+
|
|
748
|
+
Gen.lift_array takes an array and a block which has a variable.
|
|
749
|
+
The block should return a Gen object. lift_array returns a Gen
|
|
750
|
+
object which generates an array of the result of given block for
|
|
751
|
+
applying each member of given array.
|
|
752
|
+
|
|
753
|
+
example.
|
|
754
|
+
|
|
755
|
+
<pre>
|
|
756
|
+
class Candy
|
|
757
|
+
extend RushCheck::Arbitrary
|
|
758
|
+
|
|
759
|
+
def self.arbitrary
|
|
760
|
+
RushCheck::Gen.lift_array([Integer, String]) do |c|
|
|
761
|
+
c.arbitrary
|
|
762
|
+
end.bind do |args|
|
|
763
|
+
new(*args)
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
end
|
|
767
|
+
</pre>
|
|
768
|
+
|
|
769
|
+
h3. <a name="Gen.oneof">Gen.oneof</a>
|
|
770
|
+
|
|
771
|
+
Gen.oneof requires an array of Gen objects returns a Gen object.
|
|
772
|
+
|
|
773
|
+
example.
|
|
774
|
+
<pre>
|
|
775
|
+
Gen.oneof([Integer.arbitrary, String.arbitrary])
|
|
776
|
+
# return a random integer or a random string (by choosing
|
|
777
|
+
# randomly)
|
|
778
|
+
</pre>
|
|
779
|
+
|
|
780
|
+
h3. <a name="Gen.promote">Gen.promote</a>
|
|
781
|
+
|
|
782
|
+
Gen.promote is used to generate a random Proc object.
|
|
783
|
+
Next section I will describe how to define the random Proc object.
|
|
784
|
+
See also proc.rb in the example directory of RushCheck.
|
|
785
|
+
|
|
786
|
+
h3. <a name="Gen.rand">Gen.rand</a>
|
|
787
|
+
|
|
788
|
+
Gen.rand is a random number generator.
|
|
789
|
+
|
|
790
|
+
h3. <a name="Gen.sized">Gen.sized</a>
|
|
791
|
+
|
|
792
|
+
Gen.sized is used to change the size of random object.
|
|
793
|
+
See also some implementation in RushCheck (grep the source!)
|
|
794
|
+
|
|
795
|
+
h3. <a name="Gen.unit">Gen.unit</a>
|
|
796
|
+
|
|
797
|
+
return Gen object.
|
|
798
|
+
|
|
799
|
+
h3. <a name="Gen.vector">Gen.vector</a>
|
|
800
|
+
|
|
801
|
+
Get a vector of Gen.
|
|
802
|
+
|
|
803
|
+
example.
|
|
804
|
+
<pre>
|
|
805
|
+
Gen.vector(Integer, 3) # => Gen [Integer, Integer, Integer]
|
|
806
|
+
</pre>
|
|
807
|
+
|
|
808
|
+
h2. <a name="how to write random Proc which returns objects in YourClass">how to write random Proc which returns objects in YourClass</a>
|
|
809
|
+
|
|
810
|
+
It is complecated, and see some examples.
|
|
811
|
+
* rushcheck/bool.rb
|
|
812
|
+
* rushcheck/integer.rb
|
|
813
|
+
* rushcheck/string.rb
|
|
814
|
+
|
|
815
|
+
so on, grep 'coarbitrary'
|
|
816
|
+
|
|
817
|
+
FIXME: how to write coarbitrary
|
|
818
|
+
|
|
819
|
+
h1. <a name="Further information">Further information</a>
|
|
820
|
+
|
|
821
|
+
Webpage should have another useful information:
|
|
822
|
+
* "RushCheck Homepage http://rushcheck.rubyforge.org/":http://rushcheck.rubyforge.org/
|
|
823
|
+
|
|
824
|
+
The project page has a bug tracker and webboard.
|
|
825
|
+
* "RushCheck at Rubyforge http://rubyforge.org/projects/rushcheck/":http://rubyforge.org/projects/rushcheck/
|
|
826
|
+
|
|
827
|
+
There is no mailing list for RushCheck (now at 2006-08-08),
|
|
828
|
+
but don't hesitate to contact to the author!
|
|
829
|
+
|
|
830
|
+
Happy hacking and testing!
|
|
831
|
+
|
|
832
|
+
|