rushcheck 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. data/Rakefile +1 -1
  2. data/data/rushcheck/doc/policy.txt +107 -0
  3. data/data/rushcheck/doc/rushcheck.thtml +832 -0
  4. data/data/rushcheck/examples/candy.rb +6 -8
  5. data/data/rushcheck/examples/printf.rb +3 -3
  6. data/data/rushcheck/examples/proc.rb +4 -4
  7. data/data/rushcheck/examples/roguetile.rb +16 -16
  8. data/data/rushcheck/examples/sample.rb +10 -10
  9. data/data/rushcheck/rdoc/classes/Arbitrary.html +5 -5
  10. data/data/rushcheck/rdoc/classes/Arbitrary.src/M000082.html +18 -0
  11. data/data/rushcheck/rdoc/classes/Assertion.html +11 -11
  12. data/data/rushcheck/rdoc/classes/Assertion.src/M000019.html +20 -0
  13. data/data/rushcheck/rdoc/classes/Assertion.src/M000020.html +50 -0
  14. data/data/rushcheck/rdoc/classes/Coarbitrary.html +5 -5
  15. data/data/rushcheck/rdoc/classes/Coarbitrary.src/M000105.html +18 -0
  16. data/data/rushcheck/rdoc/classes/FalseClass.html +15 -15
  17. data/data/rushcheck/rdoc/classes/FalseClass.src/M000022.html +18 -0
  18. data/data/rushcheck/rdoc/classes/FalseClass.src/M000023.html +18 -0
  19. data/data/rushcheck/rdoc/classes/FalseClass.src/M000024.html +18 -0
  20. data/data/rushcheck/rdoc/classes/Float.html +20 -20
  21. data/data/rushcheck/rdoc/classes/Float.src/M000052.html +21 -0
  22. data/data/rushcheck/rdoc/classes/Float.src/M000053.html +18 -0
  23. data/data/rushcheck/rdoc/classes/Float.src/M000054.html +22 -0
  24. data/data/rushcheck/rdoc/classes/Float.src/M000055.html +20 -0
  25. data/data/rushcheck/rdoc/classes/Gen.html +102 -102
  26. data/data/rushcheck/rdoc/classes/Gen.src/M000030.html +4 -10
  27. data/data/rushcheck/rdoc/classes/Gen.src/M000031.html +29 -4
  28. data/data/rushcheck/rdoc/classes/Gen.src/M000032.html +6 -4
  29. data/data/rushcheck/rdoc/classes/Gen.src/M000033.html +14 -4
  30. data/data/rushcheck/rdoc/classes/Gen.src/M000034.html +10 -4
  31. data/data/rushcheck/rdoc/classes/Gen.src/M000035.html +4 -4
  32. data/data/rushcheck/rdoc/classes/Gen.src/M000036.html +4 -10
  33. data/data/rushcheck/rdoc/classes/Gen.src/M000037.html +4 -4
  34. data/data/rushcheck/rdoc/classes/Gen.src/M000038.html +4 -7
  35. data/data/rushcheck/rdoc/classes/Gen.src/M000039.html +4 -4
  36. data/data/rushcheck/rdoc/classes/Gen.src/M000040.html +10 -4
  37. data/data/rushcheck/rdoc/classes/Gen.src/M000041.html +4 -9
  38. data/data/rushcheck/rdoc/classes/Gen.src/M000042.html +7 -5
  39. data/data/rushcheck/rdoc/classes/Gen.src/M000043.html +4 -4
  40. data/data/rushcheck/rdoc/classes/Gen.src/M000044.html +4 -10
  41. data/data/rushcheck/rdoc/classes/Gen.src/M000045.html +23 -0
  42. data/data/rushcheck/rdoc/classes/Gen.src/M000046.html +19 -0
  43. data/data/rushcheck/rdoc/classes/Gen.src/M000047.html +18 -0
  44. data/data/rushcheck/rdoc/classes/Gen.src/M000048.html +24 -0
  45. data/data/rushcheck/rdoc/classes/Guard.html +10 -10
  46. data/data/rushcheck/rdoc/classes/Guard.src/M000028.html +27 -0
  47. data/data/rushcheck/rdoc/classes/Guard.src/M000029.html +18 -0
  48. data/data/rushcheck/rdoc/classes/HsRandom.html +20 -20
  49. data/data/rushcheck/rdoc/classes/HsRandom.src/M000088.html +22 -0
  50. data/data/rushcheck/rdoc/classes/HsRandom.src/M000089.html +32 -0
  51. data/data/rushcheck/rdoc/classes/HsRandom.src/M000090.html +18 -0
  52. data/data/rushcheck/rdoc/classes/Integer.html +20 -20
  53. data/data/rushcheck/rdoc/classes/Integer.src/M000010.html +18 -0
  54. data/data/rushcheck/rdoc/classes/Integer.src/M000011.html +18 -0
  55. data/data/rushcheck/rdoc/classes/Integer.src/M000012.html +21 -0
  56. data/data/rushcheck/rdoc/classes/Integer.src/M000013.html +19 -0
  57. data/data/rushcheck/rdoc/classes/NilClass.html +15 -15
  58. data/data/rushcheck/rdoc/classes/NilClass.src/M000064.html +18 -0
  59. data/data/rushcheck/rdoc/classes/NilClass.src/M000065.html +18 -0
  60. data/data/rushcheck/rdoc/classes/NilClass.src/M000066.html +18 -0
  61. data/data/rushcheck/rdoc/classes/Property.html +10 -10
  62. data/data/rushcheck/rdoc/classes/Property.src/M000077.html +26 -0
  63. data/data/rushcheck/rdoc/classes/Property.src/M000078.html +18 -0
  64. data/data/rushcheck/rdoc/classes/RandomArray.html +15 -15
  65. data/data/rushcheck/rdoc/classes/RandomArray.src/M000025.html +18 -0
  66. data/data/rushcheck/rdoc/classes/RandomArray.src/M000026.html +35 -0
  67. data/data/rushcheck/rdoc/classes/RandomArray.src/M000027.html +22 -0
  68. data/data/rushcheck/rdoc/classes/RandomBool.html +10 -10
  69. data/data/rushcheck/rdoc/classes/RandomBool.src/M000086.html +18 -0
  70. data/data/rushcheck/rdoc/classes/RandomBool.src/M000087.html +19 -0
  71. data/data/rushcheck/rdoc/classes/RandomGen.html +20 -20
  72. data/data/rushcheck/rdoc/classes/RandomGen.src/M000083.html +18 -0
  73. data/data/rushcheck/rdoc/classes/RandomGen.src/M000084.html +18 -0
  74. data/data/rushcheck/rdoc/classes/RandomGen.src/M000085.html +18 -0
  75. data/data/rushcheck/rdoc/classes/RandomHash.html +16 -16
  76. data/data/rushcheck/rdoc/classes/RandomHash.src/M000049.html +18 -0
  77. data/data/rushcheck/rdoc/classes/RandomHash.src/M000050.html +26 -0
  78. data/data/rushcheck/rdoc/classes/RandomHash.src/M000051.html +22 -0
  79. data/data/rushcheck/rdoc/classes/RandomProc.html +20 -20
  80. data/data/rushcheck/rdoc/classes/RandomProc.src/M000060.html +18 -0
  81. data/data/rushcheck/rdoc/classes/RandomProc.src/M000061.html +30 -0
  82. data/data/rushcheck/rdoc/classes/RandomProc.src/M000062.html +26 -0
  83. data/data/rushcheck/rdoc/classes/RandomProc.src/M000063.html +20 -0
  84. data/data/rushcheck/rdoc/classes/Result.html +19 -19
  85. data/data/rushcheck/rdoc/classes/Result.src/M000056.html +18 -0
  86. data/data/rushcheck/rdoc/classes/Result.src/M000057.html +18 -0
  87. data/data/rushcheck/rdoc/classes/Result.src/M000058.html +18 -0
  88. data/data/rushcheck/rdoc/classes/RushCheckConfig.html +41 -11
  89. data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000001.html +1 -1
  90. data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000002.html +1 -1
  91. data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000003.html +8 -4
  92. data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000004.html +4 -24
  93. data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000005.html +22 -39
  94. data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000006.html +55 -0
  95. data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000007.html +50 -0
  96. data/data/rushcheck/rdoc/classes/SpecialString.html +5 -5
  97. data/data/rushcheck/rdoc/classes/SpecialString.src/M000021.html +37 -0
  98. data/data/rushcheck/rdoc/classes/StdGen.html +27 -27
  99. data/data/rushcheck/rdoc/classes/StdGen.src/M000014.html +9 -4
  100. data/data/rushcheck/rdoc/classes/StdGen.src/M000015.html +21 -0
  101. data/data/rushcheck/rdoc/classes/StdGen.src/M000016.html +21 -0
  102. data/data/rushcheck/rdoc/classes/StdGen.src/M000017.html +18 -0
  103. data/data/rushcheck/rdoc/classes/StdGen.src/M000018.html +18 -0
  104. data/data/rushcheck/rdoc/classes/String.html +20 -20
  105. data/data/rushcheck/rdoc/classes/String.src/M000073.html +24 -0
  106. data/data/rushcheck/rdoc/classes/String.src/M000074.html +18 -0
  107. data/data/rushcheck/rdoc/classes/String.src/M000075.html +25 -0
  108. data/data/rushcheck/rdoc/classes/String.src/M000076.html +22 -0
  109. data/data/rushcheck/rdoc/classes/TestExausted.html +113 -0
  110. data/data/rushcheck/rdoc/classes/TestFailed.html +155 -0
  111. data/data/rushcheck/rdoc/classes/TestFailed.src/M000067.html +18 -0
  112. data/data/rushcheck/rdoc/classes/TestOk.html +113 -0
  113. data/data/rushcheck/rdoc/classes/TestOptions.html +180 -0
  114. data/data/rushcheck/rdoc/classes/TestOptions.src/M000008.html +18 -0
  115. data/data/rushcheck/rdoc/classes/TestOptions.src/M000009.html +18 -0
  116. data/data/rushcheck/rdoc/classes/TestResult.html +164 -0
  117. data/data/rushcheck/rdoc/classes/TestResult.src/M000068.html +18 -0
  118. data/data/rushcheck/rdoc/classes/Testable.html +96 -51
  119. data/data/rushcheck/rdoc/classes/Testable.src/M000091.html +4 -4
  120. data/data/rushcheck/rdoc/classes/Testable.src/M000092.html +4 -4
  121. data/data/rushcheck/rdoc/classes/Testable.src/M000095.html +4 -4
  122. data/data/rushcheck/rdoc/classes/Testable.src/M000096.html +18 -0
  123. data/data/rushcheck/rdoc/classes/Testable.src/M000097.html +18 -0
  124. data/data/rushcheck/rdoc/classes/Testable.src/M000099.html +19 -0
  125. data/data/rushcheck/rdoc/classes/Testable.src/M000100.html +21 -0
  126. data/data/rushcheck/rdoc/classes/Testable.src/M000101.html +18 -0
  127. data/data/rushcheck/rdoc/classes/Testable.src/M000103.html +18 -0
  128. data/data/rushcheck/rdoc/classes/Testable.src/M000104.html +18 -0
  129. data/data/rushcheck/rdoc/classes/TheStdGen.html +20 -20
  130. data/data/rushcheck/rdoc/classes/TheStdGen.src/M000069.html +18 -0
  131. data/data/rushcheck/rdoc/classes/TheStdGen.src/M000070.html +20 -0
  132. data/data/rushcheck/rdoc/classes/TheStdGen.src/M000071.html +21 -0
  133. data/data/rushcheck/rdoc/classes/TheStdGen.src/M000072.html +18 -0
  134. data/data/rushcheck/rdoc/classes/TrueClass.html +15 -15
  135. data/data/rushcheck/rdoc/classes/TrueClass.src/M000079.html +18 -0
  136. data/data/rushcheck/rdoc/classes/TrueClass.src/M000080.html +18 -0
  137. data/data/rushcheck/rdoc/classes/TrueClass.src/M000081.html +18 -0
  138. data/data/rushcheck/rdoc/created.rid +1 -1
  139. data/data/rushcheck/rdoc/files/rushcheck/config_rb.html +8 -1
  140. data/data/rushcheck/rdoc/files/rushcheck/testable_rb.html +3 -1
  141. data/data/rushcheck/rdoc/files/rushcheck/testoptions_rb.html +109 -0
  142. data/data/rushcheck/rdoc/files/rushcheck/testresult_rb.html +105 -0
  143. data/data/rushcheck/rdoc/files/rushcheck_rb.html +127 -0
  144. data/data/rushcheck/rdoc/fr_class_index.html +5 -0
  145. data/data/rushcheck/rdoc/fr_file_index.html +3 -1
  146. data/data/rushcheck/rdoc/fr_method_index.html +103 -94
  147. data/lib/rushcheck/arbitrary.rb +16 -12
  148. data/lib/rushcheck/array.rb +7 -6
  149. data/lib/rushcheck/assertion.rb +53 -50
  150. data/lib/rushcheck/bool.rb +26 -24
  151. data/lib/rushcheck/config.rb +131 -81
  152. data/lib/rushcheck/float.rb +4 -4
  153. data/lib/rushcheck/gen.rb +194 -182
  154. data/lib/rushcheck/guard.rb +9 -10
  155. data/lib/rushcheck/hash.rb +4 -3
  156. data/lib/rushcheck/integer.rb +11 -6
  157. data/lib/rushcheck/proc.rb +7 -7
  158. data/lib/rushcheck/property.rb +19 -15
  159. data/lib/rushcheck/random.rb +162 -159
  160. data/lib/rushcheck/result.rb +16 -12
  161. data/lib/rushcheck/string.rb +12 -12
  162. data/lib/rushcheck/testable.rb +99 -25
  163. data/lib/rushcheck/testoptions.rb +20 -0
  164. data/lib/rushcheck/testresult.rb +25 -0
  165. data/lib/{rushcheck/rushcheck.rb → rushcheck.rb} +2 -1
  166. metadata +93 -4
  167. 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
+