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.
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
+