picotest 0.0.1
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/AUTHORS +2 -0
- data/CHANGELOG +0 -0
- data/LICENSE +674 -0
- data/README +177 -0
- data/Rakefile +47 -0
- data/lib/picotest.rb +27 -0
- data/lib/picotest/autotest.rb +87 -0
- data/lib/picotest/autotest/samples.rb +63 -0
- data/lib/picotest/core.rb +231 -0
- data/lib/picotest/picomock.rb +106 -0
- data/lib/picotest/version.rb +3 -0
- data/samples/sample1.rb +46 -0
- data/samples/sample2.rb +55 -0
- data/samples/sample3.rb +23 -0
- metadata +59 -0
data/README
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
= Picotest - simple reduced tests
|
2
|
+
|
3
|
+
Picotest is a gem which allows to write complete test suites in a few lines, targeted primarily to test separated methods, algorithms or little snippets of code
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
The install is as simple as execute the well-known gem install:
|
8
|
+
|
9
|
+
sudo gem install picotest
|
10
|
+
|
11
|
+
== Known Limitations & Issues
|
12
|
+
|
13
|
+
* Reverse oracle test only can be compared using exact equals (see sqrt example)
|
14
|
+
* Metaprogramming of input/output pairs are ugly
|
15
|
+
* Oracle testing does not allow expectation test making difficult to debug failing tests
|
16
|
+
* Complete lack of RDoc
|
17
|
+
|
18
|
+
== Usage
|
19
|
+
|
20
|
+
To use picotest you should write suites using suite method, each suite is defined by a hash and an optional
|
21
|
+
description, the keys of the hash are used as input for the method and the corresponding values as expected output
|
22
|
+
|
23
|
+
For example, to specify that the method receiving 1 should return 1, receiving 4 should return 2 and receiving 9 should return 3, use the following syntax:
|
24
|
+
|
25
|
+
suite(1 => 1, 4 => 2, 9 => 3)
|
26
|
+
|
27
|
+
Or:
|
28
|
+
|
29
|
+
suite("integer sqrt", 1 => 1, 4 => 2, 9 => 3)
|
30
|
+
|
31
|
+
After that, you should specify the test:
|
32
|
+
|
33
|
+
suite("integer sqrt", 1 => 1, 4 => 2, 9 => 3).test(Math.method(:sqrt))
|
34
|
+
|
35
|
+
To run test, you should set the environment variable PICOTEST_RUN to 1
|
36
|
+
|
37
|
+
=== Environment variables
|
38
|
+
|
39
|
+
All environments are activated setting their value to 1, other values distinct from 1 will be ignored
|
40
|
+
|
41
|
+
PICOTEST_RUN enables the execution of test
|
42
|
+
PICOTEST_REPORT enables reports of test on standard output and disables Picotest::Fail exceptions when test fails
|
43
|
+
PICOTEST_AUTOTEST enables tests of picotest itself
|
44
|
+
PICOTEST_FAIL simulate failure of all tests, for picotest test purpose
|
45
|
+
|
46
|
+
== Code Examples
|
47
|
+
|
48
|
+
See samples directory under the gem root
|
49
|
+
|
50
|
+
=== Example 1: basic usage of suite and test method
|
51
|
+
|
52
|
+
class X
|
53
|
+
def foo(data)
|
54
|
+
data.split(";")[2].to_f
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
suite( "aaa;xxx;1.0;999" => 1.0, ";;3.2" => 3.2).test X.new.method(:foo)
|
59
|
+
|
60
|
+
=== Example 2: Input sets
|
61
|
+
|
62
|
+
Both -2 and 2 should evaluate to 4 on lambda{|x|x*x}
|
63
|
+
|
64
|
+
suite(_set(-2,2) => 4).test lambda{|x|x*x}
|
65
|
+
|
66
|
+
=== Example 3: Oracle testing
|
67
|
+
|
68
|
+
Using a lambda as value on the hash can be used to specify a rule to validate output-input pairs, useful for oracle testing
|
69
|
+
|
70
|
+
suite(4 => lambda{|y,x| y*y == x}).test Math.method(:sqrt)
|
71
|
+
|
72
|
+
=== Example 4: Oracle testing with input sets
|
73
|
+
|
74
|
+
This time, the validation rule must considerate the imprecision of floats and check using a error margin
|
75
|
+
|
76
|
+
suite(_set(1,2,3,4,5) => lambda{|y,x| (y*y - x).abs<0.00001}).test Math.method(:sqrt)
|
77
|
+
suite(_set(*(1..100) ) => lambda{|y,x| (y*y - x).abs<0.00001}).test Math.method(:sqrt)
|
78
|
+
|
79
|
+
=== Example 5: Reversed oracle
|
80
|
+
|
81
|
+
When valid inputs can be generated from output (i.e. float 1.0 output correspond to string "aaa;xxx;1.0;" input)
|
82
|
+
|
83
|
+
class X
|
84
|
+
def foo(data)
|
85
|
+
data.split(";")[2].to_f
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
suite( lambda{|x| ";;#{x}"} => _set(*(1..20).map(&:to_f)) ).test X.new.method(:foo)
|
90
|
+
|
91
|
+
=== Example 6: Testing methods of input objects
|
92
|
+
|
93
|
+
suite( "a b" => ["a","b"]).test :split
|
94
|
+
suite( lambda{|x|x.join " "} => _set(["a","b"], ["x","y","z","1"], ["aaa","bbb"]) ).test :split
|
95
|
+
|
96
|
+
=== Example 7: Testing multiple argument inputs
|
97
|
+
|
98
|
+
class X
|
99
|
+
def sum(*x)
|
100
|
+
x.inject{|a,b| a+b}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
suite( 1 => 1, [1,2] => 3, [1,2,3] => 6 ).test X.new.method(:sum)
|
105
|
+
suite(_set(*(1..100)) => lambda{|y,x| y == x},
|
106
|
+
_set([1,2],[3,4],[4,6],[5,6]) => lambda{|y,x1,x2| y == x1+x2},
|
107
|
+
_set([1,2,3],[3,4,5],[4,6,7],[5,6,7]) => lambda{|y,x1,x2,x3| y == x1+x2+x3}
|
108
|
+
).test X.new.method(:sum)
|
109
|
+
|
110
|
+
=== Example 8: Mocking instance variable
|
111
|
+
|
112
|
+
class X
|
113
|
+
def foo(data)
|
114
|
+
data.split(";")[@fieldno].to_f
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
suite(hash).test X.new.method(:foo).mock(:@fieldno => 2)
|
119
|
+
|
120
|
+
=== Example 9: Mocking method on receiver object
|
121
|
+
|
122
|
+
class X
|
123
|
+
attr_accessor :fieldno
|
124
|
+
def foo(data)
|
125
|
+
data.split(";")[fieldno].to_f
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
suite(hash).test X.new.method(:foo).mock(:fieldno => 2)
|
130
|
+
|
131
|
+
=== Example 10: Mock objects
|
132
|
+
|
133
|
+
class X
|
134
|
+
attr_accessor :another_object
|
135
|
+
def foo(data)
|
136
|
+
data.split(";")[another_object.fieldno].to_f
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
suite(hash).test X.new.method(:foo).mock(:another_object => mock(:fieldno => 2) )
|
141
|
+
|
142
|
+
=== Example 11: Mocking method on receiver object
|
143
|
+
|
144
|
+
class X
|
145
|
+
attr_accessor :another_object
|
146
|
+
def foo(data)
|
147
|
+
another_object.invented_here_split(data,";")[@fieldno].to_f
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# you can specify the implementatioin of methods using lambdas
|
152
|
+
suite(hash).test X.new.method(:foo).mock(
|
153
|
+
:another_object => mock(:invented_here_split => lambda{|str,sep| str.split(sep) }),
|
154
|
+
:@fieldno => 2 )
|
155
|
+
|
156
|
+
# Since :split.to_proc is equivalent to lambda{|str,sep| str.split(sep) }, you can also use:
|
157
|
+
suite(hash).test X.new.method(:foo).mock(
|
158
|
+
:another_object => mock(:invented_here_split => :split.to_proc),
|
159
|
+
:@fieldno => 2 )
|
160
|
+
|
161
|
+
|
162
|
+
=== Example 12: Exceptions
|
163
|
+
|
164
|
+
class X
|
165
|
+
def foo(a)
|
166
|
+
raise ArgumentError unless a.kind_of? Numeric
|
167
|
+
|
168
|
+
a*2
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
suite(1 => 2, 2 => 4, 3 => 6, "00" => _raise(ArgumentError)).test(X.new.method(:foo))
|
173
|
+
|
174
|
+
== Copying
|
175
|
+
|
176
|
+
Copyright (c) 2012 Dario Seminara, released under the GPL License (see LICENSE)
|
177
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require "rspec/core/rake_task"
|
7
|
+
|
8
|
+
spec = Gem::Specification.new do |s|
|
9
|
+
s.name = 'picotest'
|
10
|
+
s.version = '0.0.1'
|
11
|
+
s.author = 'Dario Seminara'
|
12
|
+
s.email = 'robertodarioseminara@gmail.com'
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
s.summary = 'Test pico framework. One-line test suite'
|
15
|
+
s.homepage = "http://github.com/tario/picotest"
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = [ 'README' ]
|
18
|
+
s.files = Dir.glob("{samples,lib}/**/*") +[ 'LICENSE', 'AUTHORS', 'README', 'Rakefile', 'CHANGELOG' ]
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Run tests'
|
22
|
+
task :test do
|
23
|
+
ENV['PICOTEST_AUTOTEST'] = '1'
|
24
|
+
ENV['PICOTEST_REPORT'] = '1'
|
25
|
+
ENV['PICOTEST_RUN'] = '1'
|
26
|
+
require "picotest"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'Generate RDoc'
|
30
|
+
Rake::RDocTask.new :rdoc do |rd|
|
31
|
+
rd.rdoc_dir = 'doc'
|
32
|
+
rd.rdoc_files.add 'lib', 'README'
|
33
|
+
rd.main = 'README'
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'Build Gem'
|
37
|
+
Rake::GemPackageTask.new spec do |pkg|
|
38
|
+
pkg.need_tar = true
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Clean up'
|
42
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
43
|
+
|
44
|
+
desc 'Clean up'
|
45
|
+
task :clobber => [ :clean ]
|
46
|
+
|
47
|
+
|
data/lib/picotest.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the picotest project, http://github.com/tario/picotest
|
4
|
+
|
5
|
+
Copyright (c) 2012 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
picotest is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
picotest is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with picotest. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "picotest/picomock"
|
22
|
+
require "picotest/version"
|
23
|
+
require "picotest/core"
|
24
|
+
require "picotest/autotest"
|
25
|
+
module Picotest
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,87 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the picotest project, http://github.com/tario/picotest
|
4
|
+
|
5
|
+
Copyright (c) 2012 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
picotest is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
picotest is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with picotest. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
# pico test testing himself
|
22
|
+
require "picotest/autotest/samples"
|
23
|
+
|
24
|
+
module Picotest
|
25
|
+
|
26
|
+
if ENV['PICOTEST_AUTOTEST'] == '1'
|
27
|
+
|
28
|
+
|
29
|
+
suite("suiteure should accept :test method", [] => lambda{|x| x.respond_to? :test}).test(method(:suite))
|
30
|
+
|
31
|
+
suite("raise Fail when tested method raises Fail",
|
32
|
+
[1] => _raise(Fail) ).test(lambda{|x|raise Fail})
|
33
|
+
|
34
|
+
failing_suite = suite("always fails", [] => lambda{|x| false})
|
35
|
+
suite("test should raise Fail when condition returns false",
|
36
|
+
[lambda{}] => _raise(Fail) ).test(failing_suite.method(:test))
|
37
|
+
|
38
|
+
suite("message of Fail should be 'Test fail: always fails' when expectation title is 'always fails'",
|
39
|
+
[lambda{}] => _raise(Fail, "Test fail: always fails") ).test(failing_suite.method(:test))
|
40
|
+
|
41
|
+
failing_suite = suite("unexpected message", [] => lambda{|x| false})
|
42
|
+
message_suiteure = suite("Should raise Fail with expected message", [lambda{}] => _raise(Fail, "Test fail: expected message") )
|
43
|
+
|
44
|
+
suite("wrong fail message should raise fail", [failing_suite.method(:test)] => _raise(Fail)).test message_suiteure.method(:test)
|
45
|
+
|
46
|
+
failing_suite = suite("always always fails", [] => lambda{|x| false})
|
47
|
+
suite("message of Fail should be 'Test fail: always always fails' when expectation title is 'always always fails'",
|
48
|
+
[lambda{}] => _raise(Fail, "Test fail: always always fails") ).test(failing_suite.method(:test))
|
49
|
+
|
50
|
+
failing_suite = suite([]=>lambda{|x|false})
|
51
|
+
suite("failing suite with lambda{|x|false} and without fail message should fail", [lambda{}]=>_raise(Fail)).
|
52
|
+
test(failing_suite.method(:test))
|
53
|
+
|
54
|
+
passing_suite = suite("should not raise",[]=>lambda{|x|true})
|
55
|
+
suite("passing suite with lambda{|x|true} should not fail", [lambda{}]=>_not_raise).
|
56
|
+
test(passing_suite.method(:test))
|
57
|
+
|
58
|
+
passing_suite = suite([]=>lambda{|x|true})
|
59
|
+
suite("passing suite with lambda{|x|true} and without fail message should not fail", [lambda{}]=>_not_raise).
|
60
|
+
test(passing_suite.method(:test))
|
61
|
+
|
62
|
+
suite("numeric assert should not fail",
|
63
|
+
[lambda{|x|x}] => _not_raise,
|
64
|
+
[lambda{|x|1}] => _not_raise,
|
65
|
+
[lambda{|x|0}] => _raise(Fail)).test(
|
66
|
+
suite([1] => 1).method(:test)
|
67
|
+
)
|
68
|
+
|
69
|
+
suite("_set([1],[2],[3]) should pass with lambda{|x| [1,2,3].include? x}",
|
70
|
+
[ lambda{|x| [1,2,3].include?(x) ? 4: nil} ] => _not_raise
|
71
|
+
).test( suite(_set([1],[2],[3]) => 4).method(:test) )
|
72
|
+
|
73
|
+
suite("_set([1],[2],[3]) should pass with lambda{|x| [1,2,3].include? x}",
|
74
|
+
[ lambda{|x| [1,2,3].include?(x) ? 4: nil} ] => _not_raise
|
75
|
+
).test( suite(_set(1,2,3) => 4).method(:test) )
|
76
|
+
|
77
|
+
class X
|
78
|
+
def foo(*x)
|
79
|
+
@bar.foo(*x)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
suite( 1 => 1, 2 => 4, 3 => 9).test( X.new.method(:foo).mock( :@bar => mock(:foo => lambda{|x|x*x} ) ))
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the picotest project, http://github.com/tario/picotest
|
4
|
+
|
5
|
+
Copyright (c) 2012 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
picotest is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
picotest is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with picotest. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
module Picotest
|
22
|
+
|
23
|
+
if ENV['PICOTEST_AUTOTEST'] == '1'
|
24
|
+
# normal test (as you could do the test)
|
25
|
+
suite("squared 1,2,3,4", [1] => 1, [2] => 4, [3] => 9, [4] => 16).test lambda{|x| x*x}
|
26
|
+
suite("negative number elevated to 2",_set([1],[-1]) => 1, _set([2],[-2]) => 4, _set([3],[-3]) => 9, _set([4],[-4]) => 16).test lambda{|x| x*x}
|
27
|
+
|
28
|
+
suite("sqrt of 1,4,9,16",[1] => 1, [4] => 2, [9] => 3, [16] => 4).test Math.method(:sqrt)
|
29
|
+
|
30
|
+
suite("sqrt of pf 1,4,9,16,25", _set(1,4,9,16,25) => lambda{|y,x| y**2==x}).test Math.method(:sqrt)
|
31
|
+
suite("sqrt of 1 to 20 elevated to 2", lambda{|x| x**2} => _set(*(1..20))).test Math.method(:sqrt)
|
32
|
+
|
33
|
+
suite("sqrt of 1 to 100",_set(*(1..100)) => lambda{|y,x| (y**2 - x.to_f).abs < 0.000000005}).test Math.method(:sqrt)
|
34
|
+
|
35
|
+
# all last four togheter
|
36
|
+
|
37
|
+
suite("sqrt", [1] => 1, [4] => 2, [9] => 3, [16] => 4,
|
38
|
+
_set(1,4,9,16,25) => lambda{|y,x| y**2==x},
|
39
|
+
lambda{|x| x**2} => _set(*(1..20)),
|
40
|
+
_set(*(1..100)) => lambda{|y,x| y**2 - x.to_f < 0.000000005} ).test(Math.method(:sqrt))
|
41
|
+
|
42
|
+
# picotest testing the test
|
43
|
+
suite(
|
44
|
+
[lambda{|x|x*x}] => _not_raise,
|
45
|
+
[lambda{|x|x**2}] => _not_raise,
|
46
|
+
[lambda{|x| case x; when 1; 1; when 2; 4; when 3; 9; when 4; 16; end}] => _not_raise,
|
47
|
+
[lambda{|x| case x; when 1; 1; when 2; 4; when 3; 9; when 4; 15; end}] => _raise(Fail)
|
48
|
+
).test(
|
49
|
+
suite([1] => 1, [2] => 4, [3] => 9, [4] => 16).method(:test)
|
50
|
+
)
|
51
|
+
|
52
|
+
# same as the previous but using another syntax
|
53
|
+
suite(
|
54
|
+
_set(
|
55
|
+
[lambda{|x|x*x}],[lambda{|x|x**2}], [lambda{|x| case x; when 1; 1; when 2; 4; when 3; 9; when 4; 16; end}]) => _not_raise,
|
56
|
+
[lambda{|x| case x; when 1; 1; when 2; 4; when 3; 9; when 4; 15; end}] => _raise(Fail)
|
57
|
+
).test(
|
58
|
+
suite([1] => 1, [2] => 4, [3] => 9, [4] => 16).method(:test)
|
59
|
+
)
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,231 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the picotest project, http://github.com/tario/picotest
|
4
|
+
|
5
|
+
Copyright (c) 2012 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
picotest is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
picotest is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with picotest. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
class Object
|
22
|
+
def to_test_proc
|
23
|
+
Picotest::ConstantTestProc.new(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_input_set
|
27
|
+
Picotest::InputSet.new([self])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Proc
|
32
|
+
def to_test_proc
|
33
|
+
Picotest::ProcTestProc.new(self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module Picotest
|
38
|
+
class ProcTestProc
|
39
|
+
attr_accessor :expectation_text
|
40
|
+
|
41
|
+
def initialize(inner_proc)
|
42
|
+
@inner_proc = inner_proc
|
43
|
+
@expectation_text = ""
|
44
|
+
end
|
45
|
+
|
46
|
+
def call(m,*i)
|
47
|
+
o = m.call(*i)
|
48
|
+
|
49
|
+
if i.size+1 == @inner_proc.arity
|
50
|
+
@inner_proc.call(o,*i)
|
51
|
+
elsif @inner_proc.arity == 1
|
52
|
+
@inner_proc.call(o)
|
53
|
+
else
|
54
|
+
raise RuntimeError, "wrong arity for lambda"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class ConstantTestProc
|
60
|
+
def initialize(const)
|
61
|
+
@const = const
|
62
|
+
end
|
63
|
+
|
64
|
+
def call(m,*i)
|
65
|
+
@const == m.call(*i)
|
66
|
+
end
|
67
|
+
|
68
|
+
def expectation_text
|
69
|
+
@const.inspect
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Fail < Exception
|
74
|
+
end
|
75
|
+
|
76
|
+
class InputSet
|
77
|
+
def initialize(array); @array = array; end
|
78
|
+
|
79
|
+
def to_input_set
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def each(&blk)
|
84
|
+
@array.each(&blk)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class RaiseAssert
|
89
|
+
attr_reader :expectation_text
|
90
|
+
def initialize(ext,&blk)
|
91
|
+
@blk = blk
|
92
|
+
@expectation_text = ext
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_test_proc
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
def call(*x)
|
100
|
+
@blk.call(*x)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Suite
|
105
|
+
def initialize(fail_message,fxtdata,position)
|
106
|
+
@fxtdata=fxtdata
|
107
|
+
@fail_message=fail_message
|
108
|
+
@position = position
|
109
|
+
|
110
|
+
@report = ENV["PICOTEST_REPORT"] == "1" ? true : false
|
111
|
+
@raise_fail = @report ? false : true
|
112
|
+
@run = ENV["PICOTEST_RUN"] == "1" ? true : false
|
113
|
+
@emulate_fail = ENV["PICOTEST_FAIL"] == "1" ? true : false
|
114
|
+
end
|
115
|
+
|
116
|
+
def test(m)
|
117
|
+
return unless @run
|
118
|
+
|
119
|
+
if m.instance_of? Method
|
120
|
+
if m.owner == Picotest::Suite
|
121
|
+
m.receiver.instance_eval{@raise_fail = true}
|
122
|
+
m.receiver.instance_eval{@emulate_fail = false}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
m = m.to_proc
|
126
|
+
|
127
|
+
test_fail = false
|
128
|
+
|
129
|
+
@fxtdata.each do |k,o|
|
130
|
+
if k.respond_to? :to_proc
|
131
|
+
oracle = k.to_proc
|
132
|
+
o.to_input_set.each do|_exp_o|
|
133
|
+
i = oracle.call(_exp_o)
|
134
|
+
_o = m.call(*i)
|
135
|
+
if not _o == _exp_o or @emulate_fail
|
136
|
+
test_fail = true
|
137
|
+
|
138
|
+
if @raise_fail
|
139
|
+
raise Picotest::Fail,'Test fail: '+@fail_message
|
140
|
+
else
|
141
|
+
|
142
|
+
location = if m.respond_to?(:source_location)
|
143
|
+
m.source_location
|
144
|
+
end
|
145
|
+
|
146
|
+
print "fail #{@fail_message}. Expected output:#{_exp_o} , received:#{_o}
|
147
|
+
suite at #{@position}
|
148
|
+
test at #{caller[0]}
|
149
|
+
#{location ? "method location at "+location.join(":") : "" }
|
150
|
+
"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
else
|
155
|
+
k.to_input_set.each do|i|
|
156
|
+
test_proc = o.to_test_proc
|
157
|
+
if not test_proc.call(m,*i) or @emulate_fail
|
158
|
+
test_fail = true
|
159
|
+
|
160
|
+
if @raise_fail
|
161
|
+
raise Picotest::Fail,'Test fail: '+@fail_message
|
162
|
+
else
|
163
|
+
|
164
|
+
location = if m.respond_to?(:source_location)
|
165
|
+
m.source_location
|
166
|
+
end
|
167
|
+
|
168
|
+
print "fail #{@fail_message}. Input: #{i.inspect}, Expected: #{test_proc.expectation_text}
|
169
|
+
suite at #{@position}
|
170
|
+
test at #{caller[0]}
|
171
|
+
#{location ? "method location at "+location.join(":") : "" }
|
172
|
+
|
173
|
+
"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
unless test_fail
|
181
|
+
print "Test sucessfull at #{caller[0]}\n" if @report
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
module GlobalMethods
|
188
|
+
def suite(*args)
|
189
|
+
if args.size==1
|
190
|
+
Suite.new("",args.first,caller[0])
|
191
|
+
else
|
192
|
+
Suite.new(args.first,args.last,caller[0])
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def _set(*args)
|
197
|
+
InputSet.new(args)
|
198
|
+
end
|
199
|
+
|
200
|
+
def _not_raise
|
201
|
+
RaiseAssert.new("not raise exception") {|m,*i|
|
202
|
+
begin
|
203
|
+
m.call(*i)
|
204
|
+
true
|
205
|
+
rescue
|
206
|
+
false
|
207
|
+
end
|
208
|
+
}
|
209
|
+
end
|
210
|
+
|
211
|
+
def _raise(expected, expected_message = nil)
|
212
|
+
RaiseAssert.new("raise #{expected}") {|m,*i|
|
213
|
+
begin
|
214
|
+
m.call(*i)
|
215
|
+
false
|
216
|
+
rescue expected => e
|
217
|
+
if expected_message
|
218
|
+
e.message == expected_message
|
219
|
+
else
|
220
|
+
true
|
221
|
+
end
|
222
|
+
end
|
223
|
+
}
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
class Object
|
229
|
+
include Picotest::GlobalMethods
|
230
|
+
end
|
231
|
+
|