rushcheck 0.2
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/COPYING +515 -0
- data/INSTALL +14 -0
- data/LICENSE +5 -0
- data/README +49 -0
- data/Rakefile +39 -0
- data/copying.txt +23 -0
- data/data/rushcheck/doc/policy.txt +520 -0
- data/data/rushcheck/doc/rushcheck.txt +612 -0
- data/data/rushcheck/examples/printf.rb +22 -0
- data/data/rushcheck/examples/proc.rb +33 -0
- data/data/rushcheck/examples/roguetile.rb +153 -0
- data/data/rushcheck/examples/sample.rb +52 -0
- data/data/rushcheck/rdoc/classes/Arbitrary.html +148 -0
- data/data/rushcheck/rdoc/classes/Arbitrary.src/M000075.html +18 -0
- data/data/rushcheck/rdoc/classes/Assertion.html +183 -0
- data/data/rushcheck/rdoc/classes/Assertion.src/M000015.html +20 -0
- data/data/rushcheck/rdoc/classes/Assertion.src/M000016.html +45 -0
- data/data/rushcheck/rdoc/classes/Coarbitrary.html +135 -0
- data/data/rushcheck/rdoc/classes/Coarbitrary.src/M000095.html +18 -0
- data/data/rushcheck/rdoc/classes/FalseClass.html +177 -0
- data/data/rushcheck/rdoc/classes/FalseClass.src/M000018.html +18 -0
- data/data/rushcheck/rdoc/classes/FalseClass.src/M000019.html +18 -0
- data/data/rushcheck/rdoc/classes/FalseClass.src/M000020.html +18 -0
- data/data/rushcheck/rdoc/classes/Float.html +191 -0
- data/data/rushcheck/rdoc/classes/Float.src/M000047.html +21 -0
- data/data/rushcheck/rdoc/classes/Float.src/M000048.html +18 -0
- data/data/rushcheck/rdoc/classes/Float.src/M000049.html +22 -0
- data/data/rushcheck/rdoc/classes/Float.src/M000050.html +20 -0
- data/data/rushcheck/rdoc/classes/Gen.html +515 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000026.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000027.html +20 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000028.html +28 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000029.html +24 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000030.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000031.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000032.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000033.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000034.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000035.html +24 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000036.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000037.html +21 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000038.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000039.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000040.html +23 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000041.html +19 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000042.html +18 -0
- data/data/rushcheck/rdoc/classes/Gen.src/M000043.html +24 -0
- data/data/rushcheck/rdoc/classes/Guard.html +159 -0
- data/data/rushcheck/rdoc/classes/Guard.src/M000024.html +27 -0
- data/data/rushcheck/rdoc/classes/Guard.src/M000025.html +18 -0
- data/data/rushcheck/rdoc/classes/HsRandom.html +201 -0
- data/data/rushcheck/rdoc/classes/HsRandom.src/M000081.html +22 -0
- data/data/rushcheck/rdoc/classes/HsRandom.src/M000082.html +32 -0
- data/data/rushcheck/rdoc/classes/HsRandom.src/M000083.html +18 -0
- data/data/rushcheck/rdoc/classes/Integer.html +212 -0
- data/data/rushcheck/rdoc/classes/Integer.src/M000006.html +18 -0
- data/data/rushcheck/rdoc/classes/Integer.src/M000007.html +18 -0
- data/data/rushcheck/rdoc/classes/Integer.src/M000008.html +21 -0
- data/data/rushcheck/rdoc/classes/Integer.src/M000009.html +19 -0
- data/data/rushcheck/rdoc/classes/NilClass.html +177 -0
- data/data/rushcheck/rdoc/classes/NilClass.src/M000059.html +18 -0
- data/data/rushcheck/rdoc/classes/NilClass.src/M000060.html +18 -0
- data/data/rushcheck/rdoc/classes/NilClass.src/M000061.html +18 -0
- data/data/rushcheck/rdoc/classes/Property.html +174 -0
- data/data/rushcheck/rdoc/classes/Property.src/M000070.html +26 -0
- data/data/rushcheck/rdoc/classes/Property.src/M000071.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomArray.html +184 -0
- data/data/rushcheck/rdoc/classes/RandomArray.src/M000021.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomArray.src/M000022.html +35 -0
- data/data/rushcheck/rdoc/classes/RandomArray.src/M000023.html +22 -0
- data/data/rushcheck/rdoc/classes/RandomBool.html +146 -0
- data/data/rushcheck/rdoc/classes/RandomBool.src/M000079.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomBool.src/M000080.html +19 -0
- data/data/rushcheck/rdoc/classes/RandomGen.html +196 -0
- data/data/rushcheck/rdoc/classes/RandomGen.src/M000076.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomGen.src/M000077.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomGen.src/M000078.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomHash.html +197 -0
- data/data/rushcheck/rdoc/classes/RandomHash.src/M000044.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomHash.src/M000045.html +26 -0
- data/data/rushcheck/rdoc/classes/RandomHash.src/M000046.html +22 -0
- data/data/rushcheck/rdoc/classes/RandomProc.html +192 -0
- data/data/rushcheck/rdoc/classes/RandomProc.src/M000055.html +18 -0
- data/data/rushcheck/rdoc/classes/RandomProc.src/M000056.html +30 -0
- data/data/rushcheck/rdoc/classes/RandomProc.src/M000057.html +26 -0
- data/data/rushcheck/rdoc/classes/RandomProc.src/M000058.html +20 -0
- data/data/rushcheck/rdoc/classes/Result.html +214 -0
- data/data/rushcheck/rdoc/classes/Result.src/M000051.html +18 -0
- data/data/rushcheck/rdoc/classes/Result.src/M000052.html +18 -0
- data/data/rushcheck/rdoc/classes/Result.src/M000053.html +18 -0
- data/data/rushcheck/rdoc/classes/RushCheckConfig.html +240 -0
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000001.html +23 -0
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000002.html +22 -0
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000003.html +18 -0
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000004.html +38 -0
- data/data/rushcheck/rdoc/classes/RushCheckConfig.src/M000005.html +55 -0
- data/data/rushcheck/rdoc/classes/RushCheckGuard.html +118 -0
- data/data/rushcheck/rdoc/classes/SpecialString.html +151 -0
- data/data/rushcheck/rdoc/classes/SpecialString.src/M000017.html +37 -0
- data/data/rushcheck/rdoc/classes/StdGen.html +252 -0
- data/data/rushcheck/rdoc/classes/StdGen.src/M000010.html +23 -0
- data/data/rushcheck/rdoc/classes/StdGen.src/M000011.html +21 -0
- data/data/rushcheck/rdoc/classes/StdGen.src/M000012.html +21 -0
- data/data/rushcheck/rdoc/classes/StdGen.src/M000013.html +18 -0
- data/data/rushcheck/rdoc/classes/StdGen.src/M000014.html +18 -0
- data/data/rushcheck/rdoc/classes/String.html +191 -0
- data/data/rushcheck/rdoc/classes/String.src/M000066.html +24 -0
- data/data/rushcheck/rdoc/classes/String.src/M000067.html +18 -0
- data/data/rushcheck/rdoc/classes/String.src/M000068.html +25 -0
- data/data/rushcheck/rdoc/classes/String.src/M000069.html +22 -0
- data/data/rushcheck/rdoc/classes/Testable.html +281 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000084.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000085.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000088.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000089.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000090.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000092.html +18 -0
- data/data/rushcheck/rdoc/classes/Testable.src/M000094.html +18 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.html +200 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.src/M000062.html +18 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.src/M000063.html +20 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.src/M000064.html +21 -0
- data/data/rushcheck/rdoc/classes/TheStdGen.src/M000065.html +18 -0
- data/data/rushcheck/rdoc/classes/TrueClass.html +177 -0
- data/data/rushcheck/rdoc/classes/TrueClass.src/M000072.html +18 -0
- data/data/rushcheck/rdoc/classes/TrueClass.src/M000073.html +18 -0
- data/data/rushcheck/rdoc/classes/TrueClass.src/M000074.html +18 -0
- data/data/rushcheck/rdoc/created.rid +1 -0
- data/data/rushcheck/rdoc/files/rushcheck/arbitrary_rb.html +114 -0
- data/data/rushcheck/rdoc/files/rushcheck/array_rb.html +117 -0
- data/data/rushcheck/rdoc/files/rushcheck/assertion_rb.html +120 -0
- data/data/rushcheck/rdoc/files/rushcheck/bool_rb.html +120 -0
- data/data/rushcheck/rdoc/files/rushcheck/config_rb.html +109 -0
- data/data/rushcheck/rdoc/files/rushcheck/float_rb.html +118 -0
- data/data/rushcheck/rdoc/files/rushcheck/gen_rb.html +111 -0
- data/data/rushcheck/rdoc/files/rushcheck/guard_rb.html +108 -0
- data/data/rushcheck/rdoc/files/rushcheck/hash_rb.html +117 -0
- data/data/rushcheck/rdoc/files/rushcheck/integer_rb.html +118 -0
- data/data/rushcheck/rdoc/files/rushcheck/proc_rb.html +118 -0
- data/data/rushcheck/rdoc/files/rushcheck/property_rb.html +119 -0
- data/data/rushcheck/rdoc/files/rushcheck/random_rb.html +126 -0
- data/data/rushcheck/rdoc/files/rushcheck/result_rb.html +118 -0
- data/data/rushcheck/rdoc/files/rushcheck/rushcheck_rb.html +123 -0
- data/data/rushcheck/rdoc/files/rushcheck/string_rb.html +121 -0
- data/data/rushcheck/rdoc/files/rushcheck/testable_rb.html +117 -0
- data/data/rushcheck/rdoc/fr_class_index.html +51 -0
- data/data/rushcheck/rdoc/fr_file_index.html +43 -0
- data/data/rushcheck/rdoc/fr_method_index.html +121 -0
- data/data/rushcheck/rdoc/index.html +24 -0
- data/data/rushcheck/rdoc/rdoc-style.css +208 -0
- data/lib/rushcheck/arbitrary.rb +28 -0
- data/lib/rushcheck/array.rb +49 -0
- data/lib/rushcheck/assertion.rb +67 -0
- data/lib/rushcheck/bool.rb +90 -0
- data/lib/rushcheck/config.rb +98 -0
- data/lib/rushcheck/float.rb +43 -0
- data/lib/rushcheck/gen.rb +189 -0
- data/lib/rushcheck/guard.rb +27 -0
- data/lib/rushcheck/hash.rb +45 -0
- data/lib/rushcheck/integer.rb +43 -0
- data/lib/rushcheck/proc.rb +53 -0
- data/lib/rushcheck/property.rb +29 -0
- data/lib/rushcheck/random.rb +215 -0
- data/lib/rushcheck/result.rb +26 -0
- data/lib/rushcheck/rushcheck.rb +17 -0
- data/lib/rushcheck/string.rb +100 -0
- data/lib/rushcheck/testable.rb +41 -0
- metadata +238 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# = Config.rb
|
|
2
|
+
# This file is implemented for the class RushCheckConfig.
|
|
3
|
+
|
|
4
|
+
# RushCheckConfig is a class which has configurations of tests.
|
|
5
|
+
# This class is needed for several test functions.
|
|
6
|
+
class RushCheckConfig
|
|
7
|
+
|
|
8
|
+
attr_reader :max_test, :max_fail, :size, :every
|
|
9
|
+
|
|
10
|
+
def self.quick
|
|
11
|
+
new(100, 1000,
|
|
12
|
+
Proc.new{|x| x / 2 + 3},
|
|
13
|
+
Proc.new do |n, args|
|
|
14
|
+
s = n.to_s
|
|
15
|
+
s + ("\b" * s.length)
|
|
16
|
+
end)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.verbose
|
|
20
|
+
new(100, 1000,
|
|
21
|
+
Proc.new{|x| x / 2 + 3},
|
|
22
|
+
Proc.new do |n, args|
|
|
23
|
+
n.to_s + ":\n" + args.join("\n") + "\n"
|
|
24
|
+
end)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def initialize(max_test, max_fail, size, every)
|
|
28
|
+
@max_test, @max_fail, @size, @every = max_test, max_fail, size, every
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# print results of tests.
|
|
32
|
+
def done(mesg, ntest, stamps)
|
|
33
|
+
print mesg + ' ' + ntest.to_s + ' tests'
|
|
34
|
+
|
|
35
|
+
bag = stamps.compact.find_all {|x| ! x.empty?}.sort.
|
|
36
|
+
inject(Hash.new) do |r, m|
|
|
37
|
+
r[m] = r[m].nil? ? 1 : r[m] + 1
|
|
38
|
+
r
|
|
39
|
+
end.sort_by {|k, v| v}.reverse.map do |pair|
|
|
40
|
+
percentage = ((100 * pair[1]) / ntest).to_s + '%'
|
|
41
|
+
([percentage] + pair[0]).join(', ')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
mes = case bag.length
|
|
45
|
+
when 0
|
|
46
|
+
".\n"
|
|
47
|
+
when 1
|
|
48
|
+
'(' + bag[0] + ").\n"
|
|
49
|
+
else
|
|
50
|
+
".\n" + bag.join(".\n") + ".\n"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
print mes
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# execute tests
|
|
57
|
+
def tests(gen, rnd, nt=1, nf=0, stamps=[])
|
|
58
|
+
ntest, nfail = nt, nf
|
|
59
|
+
while true
|
|
60
|
+
if ntest > max_test
|
|
61
|
+
done('OK, passed', max_test, stamps)
|
|
62
|
+
tests_result = true
|
|
63
|
+
break
|
|
64
|
+
end
|
|
65
|
+
if nfail > max_fail
|
|
66
|
+
done('Arguments exhausted after ', ntest, stamps)
|
|
67
|
+
tests_result = nil
|
|
68
|
+
break
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
rnd_l, rnd_r = rnd.split
|
|
72
|
+
result = gen.generate(size.call(ntest), rnd_r)
|
|
73
|
+
message = every.call(ntest, result.arguments)
|
|
74
|
+
print message # don't puts
|
|
75
|
+
|
|
76
|
+
case result.ok
|
|
77
|
+
when nil
|
|
78
|
+
nfail += 1
|
|
79
|
+
redo
|
|
80
|
+
when true
|
|
81
|
+
stamps.push(result.stamp)
|
|
82
|
+
ntest += 1
|
|
83
|
+
redo
|
|
84
|
+
when false
|
|
85
|
+
error = "Falsifiable, after " + ntest.to_s + " tests:\n" +
|
|
86
|
+
result.arguments.join("\n")
|
|
87
|
+
puts error
|
|
88
|
+
tests_result = false
|
|
89
|
+
break
|
|
90
|
+
else
|
|
91
|
+
raise(RuntimeError, "RushCheck: illegal result")
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
tests_result
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# = float.rb
|
|
2
|
+
# an extension to Float class for RushCheck
|
|
3
|
+
|
|
4
|
+
require 'rushcheck/arbitrary'
|
|
5
|
+
require 'rushcheck/integer'
|
|
6
|
+
require 'rushcheck/random'
|
|
7
|
+
|
|
8
|
+
class Float
|
|
9
|
+
|
|
10
|
+
extend Arbitrary
|
|
11
|
+
extend HsRandom
|
|
12
|
+
|
|
13
|
+
include Coarbitrary
|
|
14
|
+
|
|
15
|
+
@@min_bound = 0.0
|
|
16
|
+
@@max_bound = 1.0
|
|
17
|
+
|
|
18
|
+
def self.arbitrary
|
|
19
|
+
Gen.new do |n, r|
|
|
20
|
+
a, b, c = (1..3).map { Integer.arbitrary.value(n, r) }
|
|
21
|
+
a + (b / (c.abs + 1))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.bound
|
|
26
|
+
[@@min_bound, @@max_bound]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.random_range(gen, lo=@@min_bound, hi=@@max_bound)
|
|
30
|
+
x, g = Integer.random(gen)
|
|
31
|
+
a, b = Integer.bound
|
|
32
|
+
r = (lo+hi/2).to_f + ((hi - lo).to_f / (b - a) * x)
|
|
33
|
+
|
|
34
|
+
[r, g]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def coarbitrary(g)
|
|
38
|
+
h = truncate
|
|
39
|
+
t = (self * (10 ** ((self - h).to_s.length - 2))).truncate
|
|
40
|
+
h.coarbitrary(t.coarbitrary(g))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# = Gen.rb
|
|
2
|
+
# This file is implemented the type class Gen in Haskell's QuickCheck.
|
|
3
|
+
# Almost all implementations are similar to Haskell's one.
|
|
4
|
+
# Therefore check also the Haskell implementation.
|
|
5
|
+
|
|
6
|
+
# Gen provides functions for generating test instances.
|
|
7
|
+
class Gen
|
|
8
|
+
|
|
9
|
+
# choose is one of primitive generators to create a random Gen object.
|
|
10
|
+
# choose returns a Gen object which generates a random value in the
|
|
11
|
+
# bound. It may useful to implement arbitrary method into your class.
|
|
12
|
+
def self.choose(lo=nil, hi=nil)
|
|
13
|
+
rand.fmap {|x| lo.class.random(x, lo, hi)[0] }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# elements is one of primitive generators to create a random Gen
|
|
17
|
+
# object. elements requires an array and returns a Gen object which
|
|
18
|
+
# generates an object in the array randomly. It may useful to
|
|
19
|
+
# implement arbitrary method into your class.
|
|
20
|
+
def self.elements(xs)
|
|
21
|
+
raise(RuntimeError, "given argument is empty") if xs.empty?
|
|
22
|
+
|
|
23
|
+
choose(0, xs.length - 1).fmap {|i| xs[i] }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# frequency is one of primitive generators to create a random Gen
|
|
27
|
+
# object. frequency requires an array of pairs and returns a Gen
|
|
28
|
+
# object. The first component of pair should be a positive Integer
|
|
29
|
+
# and the second one should be a Gen object. The integer acts as a
|
|
30
|
+
# weight for choosing random Gen object in the array. For example,
|
|
31
|
+
# frequency([[1, Gen.rand], [2, Integer.arbitrary]]) returns the
|
|
32
|
+
# random generator Gen.rand in 33%, while another random generator
|
|
33
|
+
# of Integer (Integer.arbitrary) in 67%.
|
|
34
|
+
def self.frequency(xs)
|
|
35
|
+
tot = xs.inject(0) {|r, pair| r + pair[0]}
|
|
36
|
+
raise(RuntimeError, "Illegal frequency:#{xs.inspect}") if tot == 0
|
|
37
|
+
choose(0, tot - 1).bind do |n|
|
|
38
|
+
m = n
|
|
39
|
+
xs.each do |pair|
|
|
40
|
+
if m <= pair[0]
|
|
41
|
+
then break pair[1]
|
|
42
|
+
else m -= pair[0]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# lift_array is one of primitive generators to create a randam Gen
|
|
49
|
+
# object. lift_array takes an array and a block which has a
|
|
50
|
+
# variable. The block should return a Gen object. lift_array returns
|
|
51
|
+
# a Gen object which generates an array of the result of given block
|
|
52
|
+
# for applying each member of given array.
|
|
53
|
+
def self.lift_array(ary)
|
|
54
|
+
Gen.new do |n, r|
|
|
55
|
+
r2 = r
|
|
56
|
+
ary.map do |c|
|
|
57
|
+
r1, r2 = r.split
|
|
58
|
+
yield.value(n, r1)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# oneof is /one of/ primitive generators to create a random Gen object.
|
|
64
|
+
# oneof requires an array of Gen objects, and returns a Gen object
|
|
65
|
+
# which choose a Gen object in the array randomly.
|
|
66
|
+
# It may useful to implement arbitrary method into your class.
|
|
67
|
+
def self.oneof(gens)
|
|
68
|
+
elements(gens).bind {|x| x}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# promote is the function to create a Gen object which generates a
|
|
72
|
+
# procedure (Proc). promote requires a block which takes one
|
|
73
|
+
# variable and the block should be return a Gen object.
|
|
74
|
+
# promote returns a Gen object which generate a new procedure
|
|
75
|
+
# with the given block.
|
|
76
|
+
# It may useful to implement coarbitrary method into your class.
|
|
77
|
+
def self.promote
|
|
78
|
+
new {|n, r| Proc.new {|a| yield(a).value(n, r) } }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# rand returns a Gen object which generates a random number
|
|
82
|
+
# generator.
|
|
83
|
+
def self.rand
|
|
84
|
+
new {|n, r| r}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# sized is a combinator which the programmer can use to access the
|
|
88
|
+
# size bound. It requires a block which takes a variable as an
|
|
89
|
+
# integer for size. The block should be a function which changes the
|
|
90
|
+
# size of random instances.
|
|
91
|
+
def self.sized
|
|
92
|
+
new {|n, r| yield(n).value(n, r) }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# unit is a monadic function which equals the return function in
|
|
96
|
+
# the Haskell's monad. It requires one variable and returns a Gen
|
|
97
|
+
# object which generates the given object.
|
|
98
|
+
def self.unit(x)
|
|
99
|
+
new {|n, r| x}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# vector is one of primitive generators to create a Gen object.
|
|
103
|
+
# vector takes two variables, while the first one should be class,
|
|
104
|
+
# and the second one should be length. vector returns a Gen object
|
|
105
|
+
# which generates an array whose components belongs the given class
|
|
106
|
+
# and given length.
|
|
107
|
+
def self.vector(c, len)
|
|
108
|
+
new do |n, r|
|
|
109
|
+
r2 = r
|
|
110
|
+
(1..len).map do
|
|
111
|
+
r1, r2 = r2.split
|
|
112
|
+
c.arbitrary.value(n, r1)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# to initialize Gen object, it requires a block which takes two
|
|
118
|
+
# variables. The first argument of block is assumed as an integer,
|
|
119
|
+
# and the second one is assumed as a random generator of RandomGen.
|
|
120
|
+
def initialize(&f)
|
|
121
|
+
@proc = f
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# bind is a monadic function such as Haskel's (>>=).
|
|
125
|
+
# bind takes a block which has two variables where the first one
|
|
126
|
+
# is assumed as an integer, and the second one is assumed as a
|
|
127
|
+
# random generator of RandomGen.
|
|
128
|
+
def bind
|
|
129
|
+
self.class.new do |n, r|
|
|
130
|
+
r1, r2 = r.split
|
|
131
|
+
yield(value(n, r1)).value(n, r2)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# value is a method to get the value of the internal procedure.
|
|
136
|
+
# value takes two variables where the first argument is assumed as
|
|
137
|
+
# an integer and the second one is assumed as a random generator of
|
|
138
|
+
# RandomGen.
|
|
139
|
+
def value(n, g)
|
|
140
|
+
@proc.call(n, g)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# fmap is a categorical function as same in Haskell.
|
|
144
|
+
# fmap requires a block which takes one variable.
|
|
145
|
+
def fmap
|
|
146
|
+
bind {|x| Gen.unit(yield(x)) }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# forall is a function to create a Gen object.
|
|
150
|
+
# forall requires a block which takes any variables
|
|
151
|
+
# and returns a Property object. Then forall returns
|
|
152
|
+
# a generator of the property.
|
|
153
|
+
def forall
|
|
154
|
+
bind do |*a|
|
|
155
|
+
yield(*a).property.bind do |res|
|
|
156
|
+
res.arguments.push(a.to_s)
|
|
157
|
+
Gen.unit(res)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# generate returns the random instance. generates takes two
|
|
163
|
+
# variables, where the first one should be an integer and the second
|
|
164
|
+
# should be the random number generator such as StdGen.
|
|
165
|
+
def generate(n, rnd)
|
|
166
|
+
s, r = Integer.random(rnd, 0, n)
|
|
167
|
+
value(s, r)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# resize returns another Gen object which resized by the given
|
|
171
|
+
# paramater. resize takes one variable in Integer.
|
|
172
|
+
def resize(n)
|
|
173
|
+
self.class.new {|x, r| value(n, r) }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# variant constructs a generator which transforms the random number
|
|
177
|
+
# seed. variant takes one variable which should be an
|
|
178
|
+
# Integer. variant is needed to generate rundom functions.
|
|
179
|
+
def variant(v)
|
|
180
|
+
self.class.new do |n, r|
|
|
181
|
+
g = (1..v).inject(r) do |gen, i|
|
|
182
|
+
gen, dummy = gen.split
|
|
183
|
+
gen
|
|
184
|
+
end
|
|
185
|
+
value(n, g)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# = guard.rb
|
|
2
|
+
# This provides class Guard
|
|
3
|
+
|
|
4
|
+
class RushCheckGuard < StandardError; end
|
|
5
|
+
|
|
6
|
+
# class Guard is used for RushCheck internally and many user
|
|
7
|
+
# don't care about this class.
|
|
8
|
+
class Guard
|
|
9
|
+
|
|
10
|
+
def guard_raise(c)
|
|
11
|
+
begin
|
|
12
|
+
yield
|
|
13
|
+
rescue Exception => ex
|
|
14
|
+
case ex
|
|
15
|
+
when c
|
|
16
|
+
raise RushCheckGuard
|
|
17
|
+
else
|
|
18
|
+
raise ex
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def guard
|
|
24
|
+
raise RushCheckGuard unless yield
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# = hash.rb
|
|
2
|
+
# a random generator of Hash
|
|
3
|
+
require 'rushcheck/arbitrary'
|
|
4
|
+
require 'rushcheck/gen'
|
|
5
|
+
require 'rushcheck/testable'
|
|
6
|
+
|
|
7
|
+
# RandomHash is a subclass of Hash which provides a random generator
|
|
8
|
+
# of hash. Programmer can make a subclass of RandomHash to make user
|
|
9
|
+
# defined random generator of Hash.
|
|
10
|
+
class RandomHash < Hash
|
|
11
|
+
|
|
12
|
+
extend Arbitrary
|
|
13
|
+
include Coarbitrary
|
|
14
|
+
|
|
15
|
+
# class method set_pattern takes a hash object of
|
|
16
|
+
# random pattern. For example, the following pattern
|
|
17
|
+
# pat = { 'key1' => Integer, 'key2' => String }
|
|
18
|
+
# means that an arbitrary hash is randomly generated
|
|
19
|
+
# which has two keys (say 'key1' and 'key2') and
|
|
20
|
+
# has indicated random object as its values.
|
|
21
|
+
def self.set_pattern(pat)
|
|
22
|
+
@@pat = pat
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.arbitrary
|
|
26
|
+
Gen.new do |n, r|
|
|
27
|
+
h = {}
|
|
28
|
+
r2 = r
|
|
29
|
+
@@pat.keys.each do |k|
|
|
30
|
+
r1, r2 = r2.split
|
|
31
|
+
h[k] = @@pat[k].arbitrary.value(n, r1)
|
|
32
|
+
end
|
|
33
|
+
h
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def coarbitrary(g)
|
|
38
|
+
r = g.variant(0)
|
|
39
|
+
values.each do |c|
|
|
40
|
+
r = c.coarbitrary(r.variant(1))
|
|
41
|
+
end
|
|
42
|
+
r
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# = integer.rb
|
|
2
|
+
# an extension to Integer class for RushCheck
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
require 'rushcheck/arbitrary'
|
|
6
|
+
require 'rushcheck/gen'
|
|
7
|
+
require 'rushcheck/random'
|
|
8
|
+
|
|
9
|
+
# ruby's Integer class is extended to use RushCheck library.
|
|
10
|
+
# See also HsRandom, Arbitrary and Coarbitrary.
|
|
11
|
+
class Integer
|
|
12
|
+
extend HsRandom
|
|
13
|
+
extend Arbitrary
|
|
14
|
+
include Coarbitrary
|
|
15
|
+
|
|
16
|
+
@@max_bound = 2**30 - 1
|
|
17
|
+
@@min_bound = -(2**30)
|
|
18
|
+
|
|
19
|
+
# this method is needed to include HsRandom.
|
|
20
|
+
def self.bound
|
|
21
|
+
[@@min_bound, @@max_bound]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# this method is needed to use Arbitrary.
|
|
25
|
+
def self.arbitrary
|
|
26
|
+
Gen.sized {|n| Gen.choose(-n, n) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# this method is needed to include HsRandom.
|
|
30
|
+
def self.random_range(gen, lo=@@min_bound, hi=@@max_bound)
|
|
31
|
+
raise(RuntimeError, "illegal arguments:#{lo}, #{hi}") if hi - lo + 1 == 0
|
|
32
|
+
v, g = gen.gen_next
|
|
33
|
+
|
|
34
|
+
[(v % (hi - lo + 1)) + lo, g]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# this method is needed to use Coarbitrary.
|
|
38
|
+
def coarbitrary(g)
|
|
39
|
+
m = (self >= 0) ? 2 * self : (-2) * self + 1
|
|
40
|
+
g.variant(m)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# = proc.rb
|
|
2
|
+
# The file provides a random generator of procedure.
|
|
3
|
+
# See also examples/proc.rb
|
|
4
|
+
|
|
5
|
+
require 'rushcheck/arbitrary'
|
|
6
|
+
require 'rushcheck/gen'
|
|
7
|
+
require 'rushcheck/testable'
|
|
8
|
+
|
|
9
|
+
class RandomProc < Proc
|
|
10
|
+
|
|
11
|
+
extend Arbitrary
|
|
12
|
+
include Coarbitrary
|
|
13
|
+
include Testable
|
|
14
|
+
|
|
15
|
+
def self.set_pattern(inputs, outputs)
|
|
16
|
+
@@inputs, @@outputs = inputs, outputs
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.arbitrary
|
|
20
|
+
Gen.new do |n, r|
|
|
21
|
+
Proc.new do |*args|
|
|
22
|
+
gens = if args.empty?
|
|
23
|
+
then @@outputs.map {|c| c.arbitrary }
|
|
24
|
+
else args.map do |v|
|
|
25
|
+
@@outputs.map do |c|
|
|
26
|
+
v.coarbitrary(c.arbitrary)
|
|
27
|
+
end
|
|
28
|
+
end.flatten
|
|
29
|
+
end
|
|
30
|
+
Gen.oneof(gens).value(n, r)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def coarbitrary(g)
|
|
36
|
+
Gen.new do |n, r|
|
|
37
|
+
r2 = r
|
|
38
|
+
args = @@inputs.map do |c|
|
|
39
|
+
r1, r2 = r2.split
|
|
40
|
+
c.arbitrary.value(n, r1)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
call(*args).coarbitrary(g)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def property
|
|
48
|
+
Gen.lift_array(@@inputs) {|c| c.arbitrary }.forall do |*args|
|
|
49
|
+
call(*args)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# = property.rb
|
|
2
|
+
# This file defines properties of testcase
|
|
3
|
+
# class Property is used for RushCheck internally
|
|
4
|
+
require 'rushcheck/gen'
|
|
5
|
+
require 'rushcheck/result'
|
|
6
|
+
require 'rushcheck/testable'
|
|
7
|
+
|
|
8
|
+
class Property
|
|
9
|
+
|
|
10
|
+
include Testable
|
|
11
|
+
|
|
12
|
+
attr_reader :gen
|
|
13
|
+
def initialize(obj=nil, stamp=[], arguments=[])
|
|
14
|
+
case obj
|
|
15
|
+
when nil, true, false
|
|
16
|
+
result = Result.new(obj, stamp, arguments)
|
|
17
|
+
@gen = Gen.unit(result)
|
|
18
|
+
when Gen
|
|
19
|
+
@gen = obj
|
|
20
|
+
else
|
|
21
|
+
raise(RuntimeError, "illegal arguments")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def property
|
|
26
|
+
self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|