pangel-testy 0.5.0
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/README +296 -0
- data/README.tmpl +68 -0
- data/Rakefile +60 -0
- data/TODO +4 -0
- data/gen_readme.rb +43 -0
- data/lib/testy.rb +173 -0
- data/pangel-testy.gemspec +52 -0
- data/samples/a.rb +21 -0
- data/samples/b.rb +26 -0
- data/samples/c.rb +56 -0
- data/samples/d.rb +34 -0
- metadata +85 -0
data/README
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
NAME
|
2
|
+
testy.rb
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
a minimalist BDD testing framework for ruby that's mad at the world and
|
6
|
+
plans to kick its ass by ruthlessly removing lines of testing framework
|
7
|
+
code
|
8
|
+
|
9
|
+
SYNOPSIS
|
10
|
+
Testy.testing 'your code' do
|
11
|
+
test 'some behaviour' do |t|
|
12
|
+
ultimate = Ultimate.new
|
13
|
+
t.check :name, :expect => 42, :actual => ultimate.answer
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
GIT
|
18
|
+
open http://github.com/ahoward/testy/tree/master
|
19
|
+
git clone git://github.com/ahoward/testy.git
|
20
|
+
|
21
|
+
PRINCIPLES AND GOALS
|
22
|
+
. it.should.not.merely.be.a.unit.testing.with.a.clever.dsl
|
23
|
+
|
24
|
+
. testing should not require learning a framework. ruby is a great
|
25
|
+
framework so testy uses it instead, requiring programmers learn exactly 2
|
26
|
+
new method calls
|
27
|
+
|
28
|
+
. testing loc should not dwarf those of the application
|
29
|
+
|
30
|
+
. testing framework loc should not dwarf those of the application
|
31
|
+
|
32
|
+
. testing frameworks should *never* alter ruby built-ins nor add methods to
|
33
|
+
Object, Kernel, .et al
|
34
|
+
|
35
|
+
. the output of tests should be machine parsable for reporting and ci tools
|
36
|
+
to easily integrate with
|
37
|
+
|
38
|
+
. the output of tests should be beautiful so that humans can read it
|
39
|
+
|
40
|
+
. the shape of the test file should not insult the programmer so that tests
|
41
|
+
can double as sample code
|
42
|
+
|
43
|
+
. the testing framework should never alter exception semantics
|
44
|
+
|
45
|
+
. hi-jacking at_exit sucks ass
|
46
|
+
|
47
|
+
. the exit status of running a test suite should indicate the degree of its
|
48
|
+
failure state (testy returns the percent of failed tests using a non-zero
|
49
|
+
exit status)
|
50
|
+
|
51
|
+
. sample code should easily be able to double as a test suite, including
|
52
|
+
its output
|
53
|
+
|
54
|
+
. testing should improve your code and help your users, not make you want to
|
55
|
+
kill yourself
|
56
|
+
|
57
|
+
. using a format that aligns in terminal is sanity saving when comparing
|
58
|
+
output
|
59
|
+
|
60
|
+
. testing frameworks should provide as few shortcuts for making brittle
|
61
|
+
tightly coupled tests as possible
|
62
|
+
|
63
|
+
. test suites should be able to be created, manipulated, have their output
|
64
|
+
streamed to different ports, and even tested themselves - they should be
|
65
|
+
plain ol objects under the hood
|
66
|
+
|
67
|
+
SAMPLES
|
68
|
+
|
69
|
+
<========< samples/a.rb >========>
|
70
|
+
|
71
|
+
~ > cat samples/a.rb
|
72
|
+
|
73
|
+
# simple use of testy involves simply writing code, and recording the result
|
74
|
+
# you expect against the actual result
|
75
|
+
#
|
76
|
+
# notice that the output is very pretty and that the exitstatus is 0 when all
|
77
|
+
# tests pass
|
78
|
+
#
|
79
|
+
require 'testy'
|
80
|
+
|
81
|
+
Testy.testing 'the kick-ass-ed-ness of testy' do
|
82
|
+
|
83
|
+
test 'the ultimate answer to life' do |result|
|
84
|
+
list = []
|
85
|
+
|
86
|
+
list << 42
|
87
|
+
result.check :a, :expect => 42, :actual => list.first
|
88
|
+
|
89
|
+
list << 42.0
|
90
|
+
result.check :b, 42.0, list.last
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
~ > ruby samples/a.rb #=> exitstatus=0
|
96
|
+
|
97
|
+
---
|
98
|
+
the kick-ass-ed-ness of testy:
|
99
|
+
the ultimate answer to life:
|
100
|
+
success:
|
101
|
+
a: 42
|
102
|
+
b: 42.0
|
103
|
+
|
104
|
+
|
105
|
+
<========< samples/b.rb >========>
|
106
|
+
|
107
|
+
~ > cat samples/b.rb
|
108
|
+
|
109
|
+
# testy will handle unexpected results and exceptions thrown in your code in
|
110
|
+
# exactly the same way - by reporting on them in a beautiful fashion and
|
111
|
+
# continuing to run other tests. notice, however, that an unexpected result
|
112
|
+
# or raised exception will cause a non-zero exitstatus (the percent of tests
|
113
|
+
# that failed) for the suite as a whole. also note that previously
|
114
|
+
# accumulated expect/actual pairs are still reported on in the error report.
|
115
|
+
#
|
116
|
+
require 'testy'
|
117
|
+
|
118
|
+
Testy.testing 'the exception handling of testy' do
|
119
|
+
|
120
|
+
test 'raising an exception' do |result|
|
121
|
+
list = []
|
122
|
+
|
123
|
+
list << 42
|
124
|
+
result.check :a, :expect => 42, :actual => list.first
|
125
|
+
|
126
|
+
list.method_that_does_not_exist
|
127
|
+
end
|
128
|
+
|
129
|
+
test 'returning unexpected results' do |result|
|
130
|
+
result.check 'a', 42, 42
|
131
|
+
result.check :b, :expect => 'forty-two', :actual => 42.0
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
~ > ruby samples/b.rb #=> exitstatus=100
|
137
|
+
|
138
|
+
---
|
139
|
+
the exception handling of testy:
|
140
|
+
raising an exception:
|
141
|
+
failure:
|
142
|
+
error:
|
143
|
+
class: NoMethodError
|
144
|
+
message: undefined method `method_that_does_not_exist' for [42]:Array
|
145
|
+
backtrace:
|
146
|
+
- samples/b.rb:18:in `call'
|
147
|
+
- ./lib/testy.rb:130
|
148
|
+
- ./lib/testy.rb:113:in `instance_eval'
|
149
|
+
- ./lib/testy.rb:113
|
150
|
+
- /home/adri/.rvm/gems/ruby-1.8.7-p249/gems/orderedhash-0.0.6/lib/orderedhash.rb:65:in `each'
|
151
|
+
- /home/adri/.rvm/gems/ruby-1.8.7-p249/gems/orderedhash-0.0.6/lib/orderedhash.rb:65:in `each'
|
152
|
+
- ./lib/testy.rb:108
|
153
|
+
- ./lib/testy.rb:78:in `call'
|
154
|
+
- ./lib/testy.rb:78:in `context'
|
155
|
+
- ./lib/testy.rb:102:in `run'
|
156
|
+
- ./lib/testy.rb:167:in `testing'
|
157
|
+
- samples/b.rb:10
|
158
|
+
expect:
|
159
|
+
a: 42
|
160
|
+
actual:
|
161
|
+
a: 42
|
162
|
+
returning unexpected results:
|
163
|
+
failure:
|
164
|
+
expect:
|
165
|
+
a: 42
|
166
|
+
b: forty-two
|
167
|
+
actual:
|
168
|
+
a: 42
|
169
|
+
b: 42.0
|
170
|
+
|
171
|
+
|
172
|
+
<========< samples/c.rb >========>
|
173
|
+
|
174
|
+
~ > cat samples/c.rb
|
175
|
+
|
176
|
+
# in some cases you may not even want to make test assertions and simply
|
177
|
+
# provide example code which should run without error, with testy it's not
|
178
|
+
# only easy to do this but the commanline supports --list to see which samples
|
179
|
+
# can be run and running a single or multiple tests based on name or pattern.
|
180
|
+
# notice that, when no assertions are made using 'result.check' the output of
|
181
|
+
# the test becomes the expected *and* actual and is therefore shown in the
|
182
|
+
# output as yaml. of course, if your samples have errors they are reported in
|
183
|
+
# the normal fashion and the tests will fail.
|
184
|
+
#
|
185
|
+
#
|
186
|
+
require 'testy'
|
187
|
+
|
188
|
+
Testy.testing 'some samplz for you' do
|
189
|
+
test 'foo sample' do
|
190
|
+
list = 1,2
|
191
|
+
list.last + list.first
|
192
|
+
end
|
193
|
+
|
194
|
+
test 'bar sample' do
|
195
|
+
list = 1,2
|
196
|
+
list.shift * list.pop
|
197
|
+
end
|
198
|
+
|
199
|
+
test 'foobar sample' do
|
200
|
+
list = 1,2
|
201
|
+
eval(list.reverse.join) * 2
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# here are some examples of using the command line arguments on the above test
|
206
|
+
#
|
207
|
+
# cfp:~/src/git/testy > ruby samples/c.rb --list
|
208
|
+
# ---
|
209
|
+
# - foo sample
|
210
|
+
# - bar sample
|
211
|
+
# - foobar sample
|
212
|
+
#
|
213
|
+
# cfp:~/src/git/testy > ruby samples/c.rb foobar
|
214
|
+
# ---
|
215
|
+
# some samplz for you:
|
216
|
+
# foobar sample:
|
217
|
+
# success: 42
|
218
|
+
#
|
219
|
+
# cfp:~/src/git/testy > ruby samples/c.rb foo
|
220
|
+
# ---
|
221
|
+
# some samplz for you:
|
222
|
+
# foo sample:
|
223
|
+
# success: 3
|
224
|
+
# foobar sample:
|
225
|
+
# success: 42
|
226
|
+
#
|
227
|
+
# cfp:~/src/git/testy > ruby samples/c.rb bar
|
228
|
+
# ---
|
229
|
+
# some samplz for you:
|
230
|
+
# bar sample:
|
231
|
+
# success: 2
|
232
|
+
|
233
|
+
~ > ruby samples/c.rb #=> exitstatus=0
|
234
|
+
|
235
|
+
---
|
236
|
+
some samplz for you:
|
237
|
+
foo sample:
|
238
|
+
success: 3
|
239
|
+
bar sample:
|
240
|
+
success: 2
|
241
|
+
foobar sample:
|
242
|
+
success: 42
|
243
|
+
|
244
|
+
|
245
|
+
<========< samples/d.rb >========>
|
246
|
+
|
247
|
+
~ > cat samples/d.rb
|
248
|
+
|
249
|
+
# of course testy includes smartly inherited contexts and context sensitive
|
250
|
+
# setup and teardown methods which stack as well.
|
251
|
+
#
|
252
|
+
require 'testy'
|
253
|
+
|
254
|
+
Testy.testing 'your bitchin lib' do
|
255
|
+
context 'A' do
|
256
|
+
setup{ @list = [40] }
|
257
|
+
|
258
|
+
test 'foo' do
|
259
|
+
@list << 2
|
260
|
+
@list.first + @list.last
|
261
|
+
end
|
262
|
+
|
263
|
+
test 'bar' do |t|
|
264
|
+
t.check :list, @list, [40]
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'B' do
|
268
|
+
setup{ @list << 2 }
|
269
|
+
test(:bar){ @list.join.delete('0') }
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
# the context name is applied to the test name, so you can selectively run
|
276
|
+
# groups of tests from the command line
|
277
|
+
#
|
278
|
+
# cfp:~/src/git/testy > ruby -I lib samples/d.rb 'A - B'
|
279
|
+
# ---
|
280
|
+
# your bitchin lib:
|
281
|
+
# A - B - bar:
|
282
|
+
# success: "42"
|
283
|
+
|
284
|
+
~ > ruby samples/d.rb #=> exitstatus=0
|
285
|
+
|
286
|
+
---
|
287
|
+
your bitchin lib:
|
288
|
+
A - foo:
|
289
|
+
success: 42
|
290
|
+
A - bar:
|
291
|
+
success:
|
292
|
+
list:
|
293
|
+
- 40
|
294
|
+
A - B - bar:
|
295
|
+
success: "42"
|
296
|
+
|
data/README.tmpl
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
NAME
|
2
|
+
testy.rb
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
a minimalist BDD testing framework for ruby that's mad at the world and
|
6
|
+
plans to kick its ass by ruthlessly removing lines of testing framework
|
7
|
+
code
|
8
|
+
|
9
|
+
SYNOPSIS
|
10
|
+
Testy.testing 'your code' do
|
11
|
+
test 'some behaviour' do |t|
|
12
|
+
ultimate = Ultimate.new
|
13
|
+
t.check :name, :expect => 42, :actual => ultimate.answer
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
GIT
|
18
|
+
open http://github.com/ahoward/testy/tree/master
|
19
|
+
git clone git://github.com/ahoward/testy.git
|
20
|
+
|
21
|
+
PRINCIPLES AND GOALS
|
22
|
+
. it.should.not.merely.be.a.unit.testing.with.a.clever.dsl
|
23
|
+
|
24
|
+
. testing should not require learning a framework. ruby is a great
|
25
|
+
framework so testy uses it instead, requiring programmers learn exactly 2
|
26
|
+
new method calls
|
27
|
+
|
28
|
+
. testing loc should not dwarf those of the application
|
29
|
+
|
30
|
+
. testing framework loc should not dwarf those of the application
|
31
|
+
|
32
|
+
. testing frameworks should *never* alter ruby built-ins nor add methods to
|
33
|
+
Object, Kernel, .et al
|
34
|
+
|
35
|
+
. the output of tests should be machine parsable for reporting and ci tools
|
36
|
+
to easily integrate with
|
37
|
+
|
38
|
+
. the output of tests should be beautiful so that humans can read it
|
39
|
+
|
40
|
+
. the shape of the test file should not insult the programmer so that tests
|
41
|
+
can double as sample code
|
42
|
+
|
43
|
+
. the testing framework should never alter exception semantics
|
44
|
+
|
45
|
+
. hi-jacking at_exit sucks ass
|
46
|
+
|
47
|
+
. the exit status of running a test suite should indicate the degree of its
|
48
|
+
failure state (testy returns the percent of failed tests using a non-zero
|
49
|
+
exit status)
|
50
|
+
|
51
|
+
. sample code should easily be able to double as a test suite, including
|
52
|
+
its output
|
53
|
+
|
54
|
+
. testing should improve your code and help your users, not make you want to
|
55
|
+
kill yourself
|
56
|
+
|
57
|
+
. using a format that aligns in terminal is sanity saving when comparing
|
58
|
+
output
|
59
|
+
|
60
|
+
. testing frameworks should provide as few shortcuts for making brittle
|
61
|
+
tightly coupled tests as possible
|
62
|
+
|
63
|
+
. test suites should be able to be created, manipulated, have their output
|
64
|
+
streamed to different ports, and even tested themselves - they should be
|
65
|
+
plain ol objects under the hood
|
66
|
+
|
67
|
+
SAMPLES
|
68
|
+
@samples
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "pangel-testy"
|
8
|
+
gem.version = "0.5.0"
|
9
|
+
gem.platform = Gem::Platform::RUBY
|
10
|
+
gem.summary = %Q{testy}
|
11
|
+
gem.description = %Q{a minimalist BDD testing framework for ruby that's mad at the world and plans to kick its ass by ruthlessly removing lines of testing framework code.}
|
12
|
+
|
13
|
+
gem.has_rdoc = true
|
14
|
+
gem.add_dependency 'orderedhash'
|
15
|
+
|
16
|
+
gem.email = "ara.t.howard@gmail.com"
|
17
|
+
gem.homepage = "http://github.com/pangel/testy"
|
18
|
+
gem.authors = ["Ara T. Howard"]
|
19
|
+
|
20
|
+
# gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
21
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
begin
|
36
|
+
require 'rcov/rcovtask'
|
37
|
+
Rcov::RcovTask.new do |test|
|
38
|
+
test.libs << 'test'
|
39
|
+
test.pattern = 'test/**/test_*.rb'
|
40
|
+
test.verbose = true
|
41
|
+
end
|
42
|
+
rescue LoadError
|
43
|
+
task :rcov do
|
44
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
task :test => :check_dependencies
|
49
|
+
|
50
|
+
task :default => :test
|
51
|
+
|
52
|
+
require 'rake/rdoctask'
|
53
|
+
Rake::RDocTask.new do |rdoc|
|
54
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
55
|
+
|
56
|
+
rdoc.rdoc_dir = 'rdoc'
|
57
|
+
rdoc.title = "mygem #{version}"
|
58
|
+
rdoc.rdoc_files.include('README*')
|
59
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
60
|
+
end
|
data/TODO
ADDED
data/gen_readme.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
$VERBOSE=nil
|
6
|
+
|
7
|
+
def indent s, n = 2
|
8
|
+
ws = ' ' * n
|
9
|
+
s.gsub %r/^/, ws
|
10
|
+
end
|
11
|
+
|
12
|
+
template = IO::read 'README.tmpl'
|
13
|
+
|
14
|
+
samples = ''
|
15
|
+
prompt = '~ > '
|
16
|
+
|
17
|
+
Dir['sample*/*'].sort.each do |sample|
|
18
|
+
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
19
|
+
|
20
|
+
cmd = "cat #{ sample }"
|
21
|
+
samples << indent(prompt + cmd, 2) << "\n\n"
|
22
|
+
samples << indent(`#{ cmd }`, 4) << "\n"
|
23
|
+
|
24
|
+
cmd = "ruby #{ sample }"
|
25
|
+
#samples << indent(prompt + cmd, 2) << "\n\n"
|
26
|
+
|
27
|
+
cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -Ilib #{ sample })'"
|
28
|
+
out = `#{ cmd } 2>&1`
|
29
|
+
#samples << indent(`#{ cmd } 2>&1`, 4) << "\n"
|
30
|
+
|
31
|
+
exitstatus = " #=> exitstatus=#{ $?.exitstatus }"
|
32
|
+
cmd = "ruby #{ sample }"
|
33
|
+
samples << indent(prompt + cmd + exitstatus, 2) << "\n\n"
|
34
|
+
samples << indent(out, 4) << "\n"
|
35
|
+
|
36
|
+
#samples << indent("\n#{ prompt } #{ $?.exitstatus } ### exitstatus\n")
|
37
|
+
end
|
38
|
+
|
39
|
+
#samples.gsub! %r/^/, ' '
|
40
|
+
|
41
|
+
readme = template.gsub %r/^\s*@samples\s*$/, samples
|
42
|
+
open('README', 'w'){|fd| fd.write readme}
|
43
|
+
print readme
|
data/lib/testy.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'orderedhash'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Testy
|
6
|
+
def Testy.version() '0.5.0' end
|
7
|
+
|
8
|
+
class Test
|
9
|
+
class BadResult < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
class OrderedHash < ::OrderedHash
|
13
|
+
def with_string_keys
|
14
|
+
oh = self.class.new
|
15
|
+
each_pair{|key, val| oh[key.to_s] = val}
|
16
|
+
oh
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Result
|
21
|
+
attr_accessor :expect
|
22
|
+
attr_accessor :actual
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@expect = OrderedHash.new
|
26
|
+
@actual = OrderedHash.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def check(name, *args)
|
30
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
31
|
+
value = args.size==0 ? (options[:expect]||options['expect']) : args.shift
|
32
|
+
expect[name.to_s] = value
|
33
|
+
value = args.size==0 ? (options[:actual]||options['actual']) : args.shift
|
34
|
+
actual[name.to_s] = value
|
35
|
+
end
|
36
|
+
|
37
|
+
def ok?
|
38
|
+
expect === actual
|
39
|
+
end
|
40
|
+
|
41
|
+
def empty?
|
42
|
+
expect.empty? and actual.empty?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_accessor :name
|
47
|
+
attr_accessor :tests
|
48
|
+
attr_accessor :block
|
49
|
+
attr_accessor :contexts
|
50
|
+
|
51
|
+
def initialize(*args, &block)
|
52
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
53
|
+
@name = args.first || options[:name] || options['name']
|
54
|
+
@tests = OrderedHash.new
|
55
|
+
@contexts = OrderedHash.new
|
56
|
+
@block = block
|
57
|
+
end
|
58
|
+
|
59
|
+
def test(name, &block)
|
60
|
+
name = [contexts.values.map{|context| context.name}, name].flatten.compact.join(' - ')
|
61
|
+
@tests[name] = [context, block]
|
62
|
+
end
|
63
|
+
|
64
|
+
def size
|
65
|
+
@tests.size
|
66
|
+
end
|
67
|
+
|
68
|
+
class Context
|
69
|
+
[:name, :block, :setup, :teardown].each{|name| attr_accessor name}
|
70
|
+
def initialize(name = nil, setup = lambda{}, teardown = lambda{}, &block)
|
71
|
+
@name, @setup, @teardown, @block = name, setup, teardown, block
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def context(name = nil, &block)
|
76
|
+
if block
|
77
|
+
@contexts[name] = Context.new(name, &block)
|
78
|
+
block.call
|
79
|
+
else
|
80
|
+
@contexts.values.last
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def setup(&block)
|
85
|
+
context.setup = block
|
86
|
+
end
|
87
|
+
|
88
|
+
def teardown(&block)
|
89
|
+
context.teardown = block
|
90
|
+
end
|
91
|
+
|
92
|
+
def list
|
93
|
+
instance_eval(&@block) if @block
|
94
|
+
tests.map{|kv| kv.first.to_s}
|
95
|
+
end
|
96
|
+
|
97
|
+
def run(*args)
|
98
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
99
|
+
port = options[:port]||options['port']||STDOUT
|
100
|
+
selectors = options[:selectors]||options['selectors']||[]
|
101
|
+
|
102
|
+
context do
|
103
|
+
instance_eval(&@block) if @block
|
104
|
+
|
105
|
+
report = OrderedHash.new
|
106
|
+
failures = 0
|
107
|
+
|
108
|
+
tests.each do |name, context_and_block|
|
109
|
+
next unless selectors.any?{|selector| selector===name} unless selectors.empty?
|
110
|
+
|
111
|
+
result = Result.new
|
112
|
+
|
113
|
+
dup.instance_eval do
|
114
|
+
context, block = context_and_block
|
115
|
+
|
116
|
+
contexts = []
|
117
|
+
tests.each do |n, cb|
|
118
|
+
c, b = cb
|
119
|
+
break if context==c
|
120
|
+
contexts << c
|
121
|
+
end
|
122
|
+
contexts << context
|
123
|
+
|
124
|
+
report[name] =
|
125
|
+
begin
|
126
|
+
value =
|
127
|
+
begin
|
128
|
+
contexts.each{|context| instance_eval(&context.setup)}
|
129
|
+
(class << self;self;end).module_eval{ define_method(:call, &block) }
|
130
|
+
call(result)
|
131
|
+
ensure
|
132
|
+
contexts.reverse.each{|context| instance_eval(&context.teardown)}
|
133
|
+
end
|
134
|
+
raise BadResult, name unless result.ok?
|
135
|
+
value = result.actual.with_string_keys unless result.empty?
|
136
|
+
begin; value.to_yaml; rescue; value=true; end
|
137
|
+
{'success' => value}
|
138
|
+
rescue Object => e
|
139
|
+
failures += 1
|
140
|
+
failure = OrderedHash.new
|
141
|
+
unless e.is_a?(BadResult)
|
142
|
+
error = OrderedHash.new
|
143
|
+
error['class'] = e.class.name
|
144
|
+
error['message'] = e.message.to_s
|
145
|
+
error['backtrace'] = e.backtrace||[]
|
146
|
+
failure['error'] = error
|
147
|
+
end
|
148
|
+
failure['expect'] = result.expect.with_string_keys
|
149
|
+
failure['actual'] = result.actual.with_string_keys
|
150
|
+
{'failure' => failure}
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
port << {name => report}.to_yaml
|
155
|
+
failures
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def Testy.testing(*args, &block)
|
161
|
+
list = ARGV.delete('--list')||ARGV.delete('-l')
|
162
|
+
selectors = ARGV.map{|arg| eval(arg =~ %r|^/.*| ? arg : "/^#{ Regexp.escape(arg) }/")}
|
163
|
+
test = Test.new(*args, &block)
|
164
|
+
if list
|
165
|
+
y test.list
|
166
|
+
else
|
167
|
+
failures = test.run(:selectors => selectors)
|
168
|
+
size = test.size
|
169
|
+
pct_failed = size==0 || failures==0 ? 0 : [ ((failures/size.to_f)*100).to_i, 1 ].max
|
170
|
+
exit(pct_failed)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{pangel-testy}
|
8
|
+
s.version = "0.5.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ara T. Howard"]
|
12
|
+
s.date = %q{2010-03-17}
|
13
|
+
s.description = %q{a minimalist BDD testing framework for ruby that's mad at the world and plans to kick its ass by ruthlessly removing lines of testing framework code.}
|
14
|
+
s.email = %q{ara.t.howard@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README",
|
17
|
+
"README.tmpl",
|
18
|
+
"TODO"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
"README",
|
22
|
+
"README.tmpl",
|
23
|
+
"Rakefile",
|
24
|
+
"TODO",
|
25
|
+
"gen_readme.rb",
|
26
|
+
"lib/testy.rb",
|
27
|
+
"pangel-testy.gemspec",
|
28
|
+
"samples/a.rb",
|
29
|
+
"samples/b.rb",
|
30
|
+
"samples/c.rb",
|
31
|
+
"samples/d.rb"
|
32
|
+
]
|
33
|
+
s.homepage = %q{http://github.com/pangel/testy}
|
34
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.3.6}
|
37
|
+
s.summary = %q{testy}
|
38
|
+
|
39
|
+
if s.respond_to? :specification_version then
|
40
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_runtime_dependency(%q<orderedhash>, [">= 0"])
|
45
|
+
else
|
46
|
+
s.add_dependency(%q<orderedhash>, [">= 0"])
|
47
|
+
end
|
48
|
+
else
|
49
|
+
s.add_dependency(%q<orderedhash>, [">= 0"])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
data/samples/a.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# simple use of testy involves simply writing code, and recording the result
|
2
|
+
# you expect against the actual result
|
3
|
+
#
|
4
|
+
# notice that the output is very pretty and that the exitstatus is 0 when all
|
5
|
+
# tests pass
|
6
|
+
#
|
7
|
+
require 'testy'
|
8
|
+
|
9
|
+
Testy.testing 'the kick-ass-ed-ness of testy' do
|
10
|
+
|
11
|
+
test 'the ultimate answer to life' do |result|
|
12
|
+
list = []
|
13
|
+
|
14
|
+
list << 42
|
15
|
+
result.check :a, :expect => 42, :actual => list.first
|
16
|
+
|
17
|
+
list << 42.0
|
18
|
+
result.check :b, 42.0, list.last
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/samples/b.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# testy will handle unexpected results and exceptions thrown in your code in
|
2
|
+
# exactly the same way - by reporting on them in a beautiful fashion and
|
3
|
+
# continuing to run other tests. notice, however, that an unexpected result
|
4
|
+
# or raised exception will cause a non-zero exitstatus (the percent of tests
|
5
|
+
# that failed) for the suite as a whole. also note that previously
|
6
|
+
# accumulated expect/actual pairs are still reported on in the error report.
|
7
|
+
#
|
8
|
+
require 'testy'
|
9
|
+
|
10
|
+
Testy.testing 'the exception handling of testy' do
|
11
|
+
|
12
|
+
test 'raising an exception' do |result|
|
13
|
+
list = []
|
14
|
+
|
15
|
+
list << 42
|
16
|
+
result.check :a, :expect => 42, :actual => list.first
|
17
|
+
|
18
|
+
list.method_that_does_not_exist
|
19
|
+
end
|
20
|
+
|
21
|
+
test 'returning unexpected results' do |result|
|
22
|
+
result.check 'a', 42, 42
|
23
|
+
result.check :b, :expect => 'forty-two', :actual => 42.0
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/samples/c.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# in some cases you may not even want to make test assertions and simply
|
2
|
+
# provide example code which should run without error, with testy it's not
|
3
|
+
# only easy to do this but the commanline supports --list to see which samples
|
4
|
+
# can be run and running a single or multiple tests based on name or pattern.
|
5
|
+
# notice that, when no assertions are made using 'result.check' the output of
|
6
|
+
# the test becomes the expected *and* actual and is therefore shown in the
|
7
|
+
# output as yaml. of course, if your samples have errors they are reported in
|
8
|
+
# the normal fashion and the tests will fail.
|
9
|
+
#
|
10
|
+
#
|
11
|
+
require 'testy'
|
12
|
+
|
13
|
+
Testy.testing 'some samplz for you' do
|
14
|
+
test 'foo sample' do
|
15
|
+
list = 1,2
|
16
|
+
list.last + list.first
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'bar sample' do
|
20
|
+
list = 1,2
|
21
|
+
list.shift * list.pop
|
22
|
+
end
|
23
|
+
|
24
|
+
test 'foobar sample' do
|
25
|
+
list = 1,2
|
26
|
+
eval(list.reverse.join) * 2
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# here are some examples of using the command line arguments on the above test
|
31
|
+
#
|
32
|
+
# cfp:~/src/git/testy > ruby samples/c.rb --list
|
33
|
+
# ---
|
34
|
+
# - foo sample
|
35
|
+
# - bar sample
|
36
|
+
# - foobar sample
|
37
|
+
#
|
38
|
+
# cfp:~/src/git/testy > ruby samples/c.rb foobar
|
39
|
+
# ---
|
40
|
+
# some samplz for you:
|
41
|
+
# foobar sample:
|
42
|
+
# success: 42
|
43
|
+
#
|
44
|
+
# cfp:~/src/git/testy > ruby samples/c.rb foo
|
45
|
+
# ---
|
46
|
+
# some samplz for you:
|
47
|
+
# foo sample:
|
48
|
+
# success: 3
|
49
|
+
# foobar sample:
|
50
|
+
# success: 42
|
51
|
+
#
|
52
|
+
# cfp:~/src/git/testy > ruby samples/c.rb bar
|
53
|
+
# ---
|
54
|
+
# some samplz for you:
|
55
|
+
# bar sample:
|
56
|
+
# success: 2
|
data/samples/d.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# of course testy includes smartly inherited contexts and context sensitive
|
2
|
+
# setup and teardown methods which stack as well.
|
3
|
+
#
|
4
|
+
require 'testy'
|
5
|
+
|
6
|
+
Testy.testing 'your bitchin lib' do
|
7
|
+
context 'A' do
|
8
|
+
setup{ @list = [40] }
|
9
|
+
|
10
|
+
test 'foo' do
|
11
|
+
@list << 2
|
12
|
+
@list.first + @list.last
|
13
|
+
end
|
14
|
+
|
15
|
+
test 'bar' do |t|
|
16
|
+
t.check :list, @list, [40]
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'B' do
|
20
|
+
setup{ @list << 2 }
|
21
|
+
test(:bar){ @list.join.delete('0') }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# the context name is applied to the test name, so you can selectively run
|
28
|
+
# groups of tests from the command line
|
29
|
+
#
|
30
|
+
# cfp:~/src/git/testy > ruby -I lib samples/d.rb 'A - B'
|
31
|
+
# ---
|
32
|
+
# your bitchin lib:
|
33
|
+
# A - B - bar:
|
34
|
+
# success: "42"
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pangel-testy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 5
|
8
|
+
- 0
|
9
|
+
version: 0.5.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ara T. Howard
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-03-17 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: orderedhash
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
description: a minimalist BDD testing framework for ruby that's mad at the world and plans to kick its ass by ruthlessly removing lines of testing framework code.
|
33
|
+
email: ara.t.howard@gmail.com
|
34
|
+
executables: []
|
35
|
+
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files:
|
39
|
+
- README
|
40
|
+
- README.tmpl
|
41
|
+
- TODO
|
42
|
+
files:
|
43
|
+
- README
|
44
|
+
- README.tmpl
|
45
|
+
- Rakefile
|
46
|
+
- TODO
|
47
|
+
- gen_readme.rb
|
48
|
+
- lib/testy.rb
|
49
|
+
- pangel-testy.gemspec
|
50
|
+
- samples/a.rb
|
51
|
+
- samples/b.rb
|
52
|
+
- samples/c.rb
|
53
|
+
- samples/d.rb
|
54
|
+
has_rdoc: true
|
55
|
+
homepage: http://github.com/pangel/testy
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options:
|
60
|
+
- --charset=UTF-8
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.3.6
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: testy
|
84
|
+
test_files: []
|
85
|
+
|