test-spec 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +0 -0
- data/Manifest.txt +11 -0
- data/README.txt +206 -0
- data/Rakefile +137 -0
- data/lib/test-spec.rb +2 -0
- data/lib/test-spec/test/spec.rb +368 -0
- data/lib/test-spec/test/spec/dox.rb +114 -0
- data/lib/test-spec/test/spec/rdox.rb +26 -0
- data/lib/test-spec/test/spec/should-output.rb +48 -0
- data/lib/test-spec/version.rb +9 -0
- data/setup.rb +1585 -0
- metadata +73 -0
data/History.txt
ADDED
File without changes
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
= test/spec, a BDD interface for Test::Unit
|
2
|
+
|
3
|
+
Copyright (C) 2006 Christian Neukirchen <mailto:chneukirchen@gmail.com>
|
4
|
+
|
5
|
+
|
6
|
+
== What is test/spec?
|
7
|
+
|
8
|
+
test/spec layers an RSpec-inspired interface on top of Test::Unit, so
|
9
|
+
you can mix TDD and BDD (Behavior-Driven Development).
|
10
|
+
|
11
|
+
test/spec is a clean-room implementation that maps most kinds of
|
12
|
+
Test::Unit assertions to a `should'-like syntax.
|
13
|
+
|
14
|
+
Consider this Test::Unit test case:
|
15
|
+
|
16
|
+
class TestFoo < Test::Unit::TestCase
|
17
|
+
def test_should_bar
|
18
|
+
assert_equal 5, 2 + 3
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
In test/spec, it looks like this:
|
23
|
+
|
24
|
+
require 'test/spec'
|
25
|
+
|
26
|
+
context "Foo" do
|
27
|
+
specify "should bar" do
|
28
|
+
(2 + 3).should.equal 5
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
test/spec does not include a mocking/stubbing-framework; use whichever
|
33
|
+
you like to. test/spec has been tested successfully with FlexMock and
|
34
|
+
Mocha.
|
35
|
+
|
36
|
+
test/spec has no dependencies outside Ruby 1.8.
|
37
|
+
|
38
|
+
|
39
|
+
== Mixing test/spec and test/unit
|
40
|
+
|
41
|
+
test/spec and Test::Unit contexts/test cases can be intermixed freely,
|
42
|
+
run in the same test and live in the same files. You can just add them
|
43
|
+
to your Rake::TestTask, too. test/spec allows you to leverage your
|
44
|
+
full existing Test::Unit infrastructure.
|
45
|
+
|
46
|
+
test/spec does not change Test::Unit with the exception of
|
47
|
+
monkey-patching Test::Unit::TestSuite to order the test cases before
|
48
|
+
running them. (This should not do any harm, but if you know a way
|
49
|
+
around it, please tell me.)
|
50
|
+
|
51
|
+
test/spec adds two global methods, Object#should and Kernel.context.
|
52
|
+
|
53
|
+
You can use <tt>assert_*</tt> freely in specify-blocks; Object#should
|
54
|
+
works in plain Test::Unit test cases, too, but they will not be counted.
|
55
|
+
|
56
|
+
|
57
|
+
== Wrapped assertions
|
58
|
+
|
59
|
+
+assert_equal+:: <tt>should.equal</tt>, <tt>should ==</tt>
|
60
|
+
+assert_not_equal+:: <tt>should.not.equal</tt>, <tt>should.not ==</tt>
|
61
|
+
+assert_same+:: <tt>should.be</tt>
|
62
|
+
+assert_not_same+:: <tt>should.not.be</tt>
|
63
|
+
+assert_nil+:: <tt>should.be.nil</tt>
|
64
|
+
+assert_not_nil+:: <tt>should.not.be.nil</tt>
|
65
|
+
+assert_in_delta+:: <tt>should.be.close</tt>
|
66
|
+
+assert_match+:: <tt>should.match</tt>, <tt>should =~</tt>
|
67
|
+
+assert_no_match+:: <tt>should.not.match</tt>, <tt>should.not =~</tt>
|
68
|
+
|
69
|
+
+assert_instance_of+:: <tt>should.be.an.instance_of</tt>
|
70
|
+
+assert_kind_of+:: <tt>should.be.a.kind_of</tt>
|
71
|
+
+assert_respond_to+:: <tt>should.respond_to</tt>
|
72
|
+
+assert_raise+:: <tt>should.raise</tt>
|
73
|
+
+assert_nothing_raised+:: <tt>should.not.raise</tt>
|
74
|
+
+assert_throws+:: <tt>should.throw</tt>
|
75
|
+
+assert_nothing_thrown+:: <tt>should.not.throw</tt>
|
76
|
+
|
77
|
+
+assert_block+:: <tt>should.satisfy</tt>
|
78
|
+
|
79
|
+
(+a+, +an+ and +be+ without arguments are optional and no-ops.)
|
80
|
+
|
81
|
+
|
82
|
+
== Additional assertions
|
83
|
+
|
84
|
+
These assertions are not included in Test::Unit, but have been added
|
85
|
+
to test/spec for convenience:
|
86
|
+
|
87
|
+
* <tt>should.not.satisfy</tt>
|
88
|
+
* <tt>should.include</tt>
|
89
|
+
* <tt>a.should.</tt>_predicate_ (works like <tt>assert
|
90
|
+
a.</tt>_predicate_<tt>?</tt>)
|
91
|
+
* <tt>a.should.be </tt>_operator_ (where _operator_ is one of <tt>></tt>, <tt>>=</tt>, <tt><</tt>, <tt><=</tt> or <tt>===</tt>)
|
92
|
+
* <tt>should.output</tt> (require test/spec/should-output)
|
93
|
+
|
94
|
+
If you write an useful general-purpose assertion, I'd like to hear of
|
95
|
+
it and may add it to the test/spec distribution.
|
96
|
+
|
97
|
+
|
98
|
+
== SpecDox and RDox
|
99
|
+
|
100
|
+
test/spec adds two additional test runners to Test::Unit, based on the
|
101
|
+
console runner but with a different output format.
|
102
|
+
|
103
|
+
SpecDox, run with <tt>--runner=specdox</tt> (or <tt>-rs</tt>) looks
|
104
|
+
like RSpec's output:
|
105
|
+
|
106
|
+
should.output
|
107
|
+
- works for print
|
108
|
+
- works for puts
|
109
|
+
- works with readline
|
110
|
+
|
111
|
+
RDox, run with <tt>--runner=rdox</tt> (or <tt>-rr</tt>) can be
|
112
|
+
included for RDoc documentation (e.g. see SPECS):
|
113
|
+
|
114
|
+
== should.output
|
115
|
+
* works for print
|
116
|
+
* works for puts
|
117
|
+
* works with readline
|
118
|
+
|
119
|
+
SpecDox and RDox work for Test::Unit too:
|
120
|
+
|
121
|
+
$ ruby -r test/spec test/testunit/test_testresult.rb -rs
|
122
|
+
|
123
|
+
Test::Unit::TC_TestResult
|
124
|
+
- fault notification
|
125
|
+
- passed?
|
126
|
+
- result changed notification
|
127
|
+
|
128
|
+
Finished in 0.106647 seconds.
|
129
|
+
|
130
|
+
3 specifications (30 requirements), 0 failures
|
131
|
+
|
132
|
+
|
133
|
+
== specrb
|
134
|
+
|
135
|
+
Since version 0.2, test/spec features a standalone test runner called
|
136
|
+
specrb. specrb is like an extended version of testrb, Test::Unit's
|
137
|
+
test runner, but has additional options. It can be used for
|
138
|
+
plain Test::Unit suites, too.
|
139
|
+
|
140
|
+
$ specrb -a -s -n should.output
|
141
|
+
|
142
|
+
should.output
|
143
|
+
- works for print
|
144
|
+
- works for puts
|
145
|
+
- works with readline
|
146
|
+
|
147
|
+
Finished in 0.162571 seconds.
|
148
|
+
|
149
|
+
3 specifications (6 requirements), 0 failures
|
150
|
+
|
151
|
+
Run <tt>specrb --help</tt> for the usage.
|
152
|
+
|
153
|
+
|
154
|
+
== History
|
155
|
+
|
156
|
+
* September 29th, 2006: First public release 0.1.
|
157
|
+
|
158
|
+
* October 18th, 2006: Second public release 0.2.
|
159
|
+
* Better, module-based implementation
|
160
|
+
* Official support for FlexMock and Mocha
|
161
|
+
* More robust Should#output
|
162
|
+
* Should#_operator_
|
163
|
+
* Nested contexts
|
164
|
+
* Standalone test/spec runner, specrb
|
165
|
+
|
166
|
+
|
167
|
+
== Contact
|
168
|
+
|
169
|
+
Please mail bugs, suggestions and patches to
|
170
|
+
<mailto:chneukirchen@gmail.com>.
|
171
|
+
|
172
|
+
Darcs repository ("darcs send" is welcome for patches):
|
173
|
+
http://chneukirchen.org/repos/testspec
|
174
|
+
|
175
|
+
|
176
|
+
== Thanks to
|
177
|
+
|
178
|
+
* Eero Saynatkari for writing <tt>should.output</tt>.
|
179
|
+
* Thomas Fuchs for script.aculo.us BDD testing which convinced me.
|
180
|
+
* Dave Astels for BDD.
|
181
|
+
* The RSpec team for API inspiration.
|
182
|
+
* Nathaniel Talbott for Test::Unit.
|
183
|
+
|
184
|
+
|
185
|
+
== Copying
|
186
|
+
|
187
|
+
Copyright (C) 2006 Christian Neukirchen <http://purl.org/net/chneukirchen>
|
188
|
+
|
189
|
+
test/spec is licensed under the same terms as Ruby itself.
|
190
|
+
|
191
|
+
Please mail bugs, feature requests or patches to the mail addresses
|
192
|
+
found above or use IRC[irc://freenode.net/#ruby-lang] to contact the
|
193
|
+
developer.
|
194
|
+
|
195
|
+
|
196
|
+
== Links
|
197
|
+
|
198
|
+
Behavior-Driven Development:: <http://behaviour-driven.org/>
|
199
|
+
RSpec:: <http://rspec.rubyforge.org/>
|
200
|
+
script.aculo.us testing:: <http://mir.aculo.us/articles/2006/08/29/bdd-style-javascript-testing>
|
201
|
+
|
202
|
+
FlexMock:: <http://onestepback.org/software/flexmock/>
|
203
|
+
Mocha:: <http://mocha.rubyforge.org/>
|
204
|
+
|
205
|
+
Christian Neukirchen:: <http://chneukirchen.org/>
|
206
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
# Rakefile for testspec. -*-ruby-*-
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
require 'rubygems'
|
6
|
+
require 'rake'
|
7
|
+
require 'rake/clean'
|
8
|
+
require 'rake/testtask'
|
9
|
+
require 'rake/packagetask'
|
10
|
+
require 'rake/gempackagetask'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
require 'rake/contrib/rubyforgepublisher'
|
13
|
+
require 'fileutils'
|
14
|
+
require 'hoe'
|
15
|
+
include FileUtils
|
16
|
+
require File.join(File.dirname(__FILE__), 'lib', 'test-spec', 'version')
|
17
|
+
|
18
|
+
AUTHOR = "Christian Neukirchen" # can also be an array of Authors
|
19
|
+
EMAIL = "chneukirchen@gmail.com"
|
20
|
+
DESCRIPTION = "Behaviour Driven Development with Test::Unit"
|
21
|
+
GEM_NAME = "test-spec" # what ppl will type to install your gem
|
22
|
+
RUBYFORGE_PROJECT = "test-spec" # The unix name for your project
|
23
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
24
|
+
RELEASE_TYPES = %w( gem ) # can use: gem, tar, zip
|
25
|
+
|
26
|
+
|
27
|
+
NAME = "test-spec"
|
28
|
+
REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
|
29
|
+
VERS = ENV['VERSION'] || (TestSpec::VERSION::STRING + (REV ? ".#{REV}" : ""))
|
30
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
31
|
+
RDOC_OPTS = ['--quiet', '--title', "test_spec documentation",
|
32
|
+
"--opname", "index.html",
|
33
|
+
"--line-numbers",
|
34
|
+
"--main", "README",
|
35
|
+
"--inline-source"]
|
36
|
+
|
37
|
+
# Generate all the Rake tasks
|
38
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
39
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
40
|
+
p.author = AUTHOR
|
41
|
+
p.description = DESCRIPTION
|
42
|
+
p.email = EMAIL
|
43
|
+
p.summary = DESCRIPTION
|
44
|
+
p.url = HOMEPATH
|
45
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
46
|
+
p.test_globs = ["test/**/*_test.rb"]
|
47
|
+
p.clean_globs = CLEAN #An array of file patterns to delete on clean.
|
48
|
+
p.extra_deps = ['flexmock','>= 0.4.3'],['mocha','>= 0.3.2']
|
49
|
+
# == Optional
|
50
|
+
#p.changes - A description of the release's latest changes.
|
51
|
+
#p.spec_extras - A hash of extra values to set in the gemspec.
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
desc "Run all the tests"
|
56
|
+
task :default => [:test]
|
57
|
+
|
58
|
+
desc "Do predistribution stuff"
|
59
|
+
task :predist => [:chmod, :changelog, :rdoc]
|
60
|
+
|
61
|
+
|
62
|
+
desc "Run all the tests"
|
63
|
+
task :test => :chmod do
|
64
|
+
ruby "bin/specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS']}"
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "Make an archive as .tar.gz"
|
68
|
+
task :dist => :test do
|
69
|
+
system "export DARCS_REPO=#{File.expand_path "."}; " +
|
70
|
+
"darcs dist -d testspec#{get_darcs_tree_version}"
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "Make binaries executable"
|
74
|
+
task :chmod do
|
75
|
+
Dir["bin/*"].each { |binary| File.chmod(0775, binary) }
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "Generate a ChangeLog"
|
79
|
+
task :changelog do
|
80
|
+
system "darcs changes --repo=#{ENV["DARCS_REPO"] || "."} >ChangeLog"
|
81
|
+
end
|
82
|
+
|
83
|
+
desc "Generate RDoc documentation"
|
84
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
85
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
86
|
+
rdoc.rdoc_dir = "rdoc"
|
87
|
+
rdoc.rdoc_files.include 'README'
|
88
|
+
rdoc.rdoc_files.include 'ROADMAP'
|
89
|
+
rdoc.rdoc_files.include 'SPECS'
|
90
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
91
|
+
end
|
92
|
+
task :rdoc => "SPECS"
|
93
|
+
|
94
|
+
desc "Generate RDox"
|
95
|
+
task "SPECS" do
|
96
|
+
ruby "bin/specrb -Ilib:test -a --rdox >SPECS"
|
97
|
+
end
|
98
|
+
|
99
|
+
begin
|
100
|
+
require 'rcov/rcovtask'
|
101
|
+
|
102
|
+
Rcov::RcovTask.new do |t|
|
103
|
+
t.test_files = FileList['test/spec_*.rb'] + ['--', '-rs'] # evil
|
104
|
+
t.verbose = true # uncomment to see the executed command
|
105
|
+
t.rcov_opts = ["--text-report", "--include-file", "^lib\\|^test"]
|
106
|
+
end
|
107
|
+
rescue LoadError
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# Helper to retrieve the "revision number" of the darcs tree.
|
112
|
+
def get_darcs_tree_version
|
113
|
+
return "" unless File.directory? "_darcs"
|
114
|
+
|
115
|
+
changes = `darcs changes`
|
116
|
+
count = 0
|
117
|
+
tag = "0.0"
|
118
|
+
|
119
|
+
changes.each("\n\n") { |change|
|
120
|
+
head, title, desc = change.split("\n", 3)
|
121
|
+
|
122
|
+
if title =~ /^ \*/
|
123
|
+
# Normal change.
|
124
|
+
count += 1
|
125
|
+
elsif title =~ /tagged (.*)/
|
126
|
+
# Tag. We look for these.
|
127
|
+
tag = $1
|
128
|
+
break
|
129
|
+
else
|
130
|
+
warn "Unparsable change: #{change}"
|
131
|
+
end
|
132
|
+
}
|
133
|
+
|
134
|
+
"-" + tag + "." + count.to_s
|
135
|
+
end
|
136
|
+
|
137
|
+
|
data/lib/test-spec.rb
ADDED
@@ -0,0 +1,368 @@
|
|
1
|
+
#
|
2
|
+
# test/spec -- a BDD interface for Test::Unit
|
3
|
+
#
|
4
|
+
# Copyright (C) 2006 Christian Neukirchen <mailto:chneukirchen@gmail.com>
|
5
|
+
#
|
6
|
+
# This work is licensed under the same terms as Ruby itself.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'test/unit'
|
10
|
+
|
11
|
+
class Test::Unit::AutoRunner # :nodoc:
|
12
|
+
RUNNERS[:specdox] = lambda {
|
13
|
+
require 'test/spec/dox'
|
14
|
+
Test::Unit::UI::SpecDox::TestRunner
|
15
|
+
}
|
16
|
+
|
17
|
+
RUNNERS[:rdox] = lambda {
|
18
|
+
require 'test/spec/rdox'
|
19
|
+
Test::Unit::UI::RDox::TestRunner
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
module Test # :nodoc:
|
24
|
+
end
|
25
|
+
|
26
|
+
module Test::Spec
|
27
|
+
VERSION = "0.1"
|
28
|
+
|
29
|
+
CONTEXTS = {}
|
30
|
+
|
31
|
+
class DefinitionError < StandardError
|
32
|
+
end
|
33
|
+
|
34
|
+
class Should
|
35
|
+
include Test::Unit::Assertions
|
36
|
+
|
37
|
+
def initialize(object)
|
38
|
+
@object = object
|
39
|
+
end
|
40
|
+
|
41
|
+
$TEST_SPEC_TESTCASE = nil
|
42
|
+
def add_assertion
|
43
|
+
$TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def an
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def a
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def not
|
56
|
+
ShouldNot.new(@object)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def satisfy(&block)
|
61
|
+
assert_block("satisfy block failed.") {
|
62
|
+
yield @object
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def equal(value)
|
67
|
+
assert_equal value, @object
|
68
|
+
end
|
69
|
+
alias == equal
|
70
|
+
|
71
|
+
def close(value, delta)
|
72
|
+
assert_in_delta value, @object, delta
|
73
|
+
end
|
74
|
+
alias be_close close
|
75
|
+
|
76
|
+
def be(*value)
|
77
|
+
case value.size
|
78
|
+
when 0
|
79
|
+
self
|
80
|
+
when 1
|
81
|
+
assert_same value.first, @object
|
82
|
+
else
|
83
|
+
raise ArgumentError, "should.be needs zero or one argument"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def match(value)
|
88
|
+
assert_match value, @object
|
89
|
+
end
|
90
|
+
alias =~ match
|
91
|
+
|
92
|
+
def instance_of(klass)
|
93
|
+
assert_instance_of klass, @object
|
94
|
+
end
|
95
|
+
alias be_an_instance_of instance_of
|
96
|
+
|
97
|
+
def kind_of(klass)
|
98
|
+
assert_kind_of klass, @object
|
99
|
+
end
|
100
|
+
alias be_a_kind_of kind_of
|
101
|
+
|
102
|
+
def respond_to(method)
|
103
|
+
assert_respond_to @object, method
|
104
|
+
end
|
105
|
+
|
106
|
+
def _raise(*args)
|
107
|
+
args = [RuntimeError] if args.empty?
|
108
|
+
assert_raise(*args, &@object)
|
109
|
+
end
|
110
|
+
|
111
|
+
def throw(*args)
|
112
|
+
assert_throws(*args, &@object)
|
113
|
+
end
|
114
|
+
|
115
|
+
def nil
|
116
|
+
assert_nil @object
|
117
|
+
end
|
118
|
+
alias be_nil nil
|
119
|
+
|
120
|
+
|
121
|
+
def include(value)
|
122
|
+
msg = build_message(nil, "<?> expected to include ?, but it didn't.",
|
123
|
+
@object, value)
|
124
|
+
assert_block(msg) { @object.include?(value) }
|
125
|
+
end
|
126
|
+
|
127
|
+
def >(value)
|
128
|
+
assert_operator @object, :>, value
|
129
|
+
end
|
130
|
+
|
131
|
+
def >=(value)
|
132
|
+
assert_operator @object, :>=, value
|
133
|
+
end
|
134
|
+
|
135
|
+
def <(value)
|
136
|
+
assert_operator @object, :<, value
|
137
|
+
end
|
138
|
+
|
139
|
+
def <=(value)
|
140
|
+
assert_operator @object, :<=, value
|
141
|
+
end
|
142
|
+
|
143
|
+
def ===(value)
|
144
|
+
assert_operator @object, :===, value
|
145
|
+
end
|
146
|
+
|
147
|
+
def method_missing(name, *args)
|
148
|
+
# This will make raise call Kernel.raise, and self.raise call _raise.
|
149
|
+
return _raise(*args) if name == :raise
|
150
|
+
|
151
|
+
if @object.respond_to?("#{name}?")
|
152
|
+
assert @object.__send__("#{name}?", *args),
|
153
|
+
"#{name}? expected to be true."
|
154
|
+
else
|
155
|
+
super
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class ShouldNot
|
161
|
+
include Test::Unit::Assertions
|
162
|
+
|
163
|
+
def initialize(object)
|
164
|
+
@object = object
|
165
|
+
end
|
166
|
+
|
167
|
+
def equal(value)
|
168
|
+
assert_not_equal value, @object
|
169
|
+
end
|
170
|
+
alias == equal
|
171
|
+
|
172
|
+
def be(*value)
|
173
|
+
case value.size
|
174
|
+
when 0
|
175
|
+
self
|
176
|
+
when 1
|
177
|
+
assert_not_same value.first, @object
|
178
|
+
else
|
179
|
+
Kernel.raise ArgumentError, "should.be needs zero or one argument"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def match(value)
|
184
|
+
# Icky Regexp check
|
185
|
+
assert_no_match value, @object
|
186
|
+
end
|
187
|
+
alias =~ match
|
188
|
+
|
189
|
+
def _raise(*args)
|
190
|
+
assert_nothing_raised(*args, &@object)
|
191
|
+
end
|
192
|
+
|
193
|
+
def throw
|
194
|
+
assert_nothing_thrown(&@object)
|
195
|
+
end
|
196
|
+
|
197
|
+
def nil
|
198
|
+
assert_not_nil @object
|
199
|
+
end
|
200
|
+
alias be_nil nil
|
201
|
+
|
202
|
+
|
203
|
+
def not
|
204
|
+
Should.new(@object)
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
def method_missing(name, *args)
|
209
|
+
# This will make raise call Kernel.raise, and self.raise call _raise.
|
210
|
+
return _raise(*args) if name == :raise
|
211
|
+
|
212
|
+
if @object.respond_to?("#{name}?")
|
213
|
+
assert_block("#{name}? expected to be false.") {
|
214
|
+
not @object.__send__("#{name}?", *args)
|
215
|
+
}
|
216
|
+
else
|
217
|
+
super
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
class Test::Spec::TestCase
|
225
|
+
attr_reader :testcase
|
226
|
+
attr_reader :name
|
227
|
+
attr_reader :position
|
228
|
+
|
229
|
+
module InstanceMethods
|
230
|
+
def setup # :nodoc:
|
231
|
+
$TEST_SPEC_TESTCASE = self
|
232
|
+
super
|
233
|
+
self.class.setups.each { |s| instance_eval(&s) }
|
234
|
+
end
|
235
|
+
|
236
|
+
def teardown # :nodoc:
|
237
|
+
super
|
238
|
+
self.class.teardowns.each { |t| instance_eval(&t) }
|
239
|
+
end
|
240
|
+
|
241
|
+
def initialize(name)
|
242
|
+
super name
|
243
|
+
|
244
|
+
# Don't let the default_test clutter up the results and don't
|
245
|
+
# flunk if no tests given, either.
|
246
|
+
throw :invalid_test if name == :default_test
|
247
|
+
end
|
248
|
+
|
249
|
+
def position
|
250
|
+
self.class.position
|
251
|
+
end
|
252
|
+
|
253
|
+
def context(*args)
|
254
|
+
raise Test::Spec::DefinitionError,
|
255
|
+
"context definition is not allowed inside a specify-block"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
module ClassMethods
|
260
|
+
attr_accessor :count
|
261
|
+
attr_accessor :name
|
262
|
+
attr_accessor :position
|
263
|
+
attr_accessor :parent
|
264
|
+
|
265
|
+
attr_accessor :setups
|
266
|
+
attr_accessor :teardowns
|
267
|
+
|
268
|
+
def context(name, &block)
|
269
|
+
(Test::Spec::CONTEXTS[self.name + "\t" + name] ||=
|
270
|
+
Test::Spec::TestCase.new(name, self)).add(&block)
|
271
|
+
end
|
272
|
+
|
273
|
+
def specify(specname, &block)
|
274
|
+
raise ArgumentError, "specify needs a block" if block.nil?
|
275
|
+
|
276
|
+
self.count += 1 # Let them run in order of definition
|
277
|
+
|
278
|
+
# TODO Changed by Jean-Michel
|
279
|
+
# define_method("test_%03d: %s" % [count, specname], &block)
|
280
|
+
define_method("test_spec {%s} %03d [%s]" % [name, count, specname], &block)
|
281
|
+
end
|
282
|
+
|
283
|
+
def setup(&block)
|
284
|
+
setups << block
|
285
|
+
end
|
286
|
+
|
287
|
+
def teardown(&block)
|
288
|
+
teardowns << block
|
289
|
+
end
|
290
|
+
|
291
|
+
def init(name, position, parent)
|
292
|
+
self.position = position
|
293
|
+
self.parent = parent
|
294
|
+
|
295
|
+
if parent
|
296
|
+
self.name = parent.name + "\t" + name
|
297
|
+
else
|
298
|
+
self.name = name
|
299
|
+
end
|
300
|
+
|
301
|
+
self.count = 0
|
302
|
+
self.setups = []
|
303
|
+
self.teardowns = []
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
@@POSITION = 0
|
308
|
+
|
309
|
+
def initialize(name, parent=nil)
|
310
|
+
@testcase = Class.new(Test::Unit::TestCase) {
|
311
|
+
include InstanceMethods
|
312
|
+
extend ClassMethods
|
313
|
+
}
|
314
|
+
|
315
|
+
@@POSITION = @@POSITION + 1
|
316
|
+
@testcase.init(name, @@POSITION, parent)
|
317
|
+
end
|
318
|
+
|
319
|
+
def add(&block)
|
320
|
+
raise ArgumentError, "context needs a block" if block.nil?
|
321
|
+
|
322
|
+
@testcase.class_eval(&block)
|
323
|
+
self
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
|
328
|
+
# Monkey-patch test/unit to run tests in an optionally specified order.
|
329
|
+
module Test::Unit # :nodoc:
|
330
|
+
class TestSuite # :nodoc:
|
331
|
+
undef run
|
332
|
+
def run(result, &progress_block)
|
333
|
+
sort!
|
334
|
+
yield(STARTED, name)
|
335
|
+
@tests.each do |test|
|
336
|
+
test.run(result, &progress_block)
|
337
|
+
end
|
338
|
+
yield(FINISHED, name)
|
339
|
+
end
|
340
|
+
|
341
|
+
def sort!
|
342
|
+
@tests = @tests.sort_by { |test|
|
343
|
+
test.respond_to?(:position) ? test.position : 0
|
344
|
+
}
|
345
|
+
end
|
346
|
+
|
347
|
+
def position
|
348
|
+
@tests.first.respond_to?(:position) ? @tests.first.position : 0
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
|
354
|
+
# Global helpers
|
355
|
+
|
356
|
+
class Object
|
357
|
+
def should
|
358
|
+
Test::Spec::Should.new(self)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
module Kernel
|
363
|
+
def context(name, &block)
|
364
|
+
(Test::Spec::CONTEXTS[name] ||= Test::Spec::TestCase.new(name)).add(&block)
|
365
|
+
end
|
366
|
+
|
367
|
+
private :context
|
368
|
+
end
|