relevance-test-spec 0.4.0.5
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/CHANGELOG +1 -0
- data/Manifest +29 -0
- data/README.rdoc +394 -0
- data/ROADMAP +1 -0
- data/Rakefile +62 -0
- data/TODO +3 -0
- data/bin/specrb +107 -0
- data/examples/stack.rb +38 -0
- data/examples/stack_spec.rb +119 -0
- data/lib/test/spec.rb +731 -0
- data/lib/test/spec/dox.rb +148 -0
- data/lib/test/spec/focused/collector-extensions.rb +22 -0
- data/lib/test/spec/focused/focused.rb +30 -0
- data/lib/test/spec/rails_helper.rb +26 -0
- data/lib/test/spec/rdox.rb +25 -0
- data/lib/test/spec/should-output.rb +49 -0
- data/lib/test/spec/version.rb +8 -0
- data/test-spec.gemspec +130 -0
- data/test/helper.rb +5 -0
- data/test/spec_dox.rb +39 -0
- data/test/spec_flexmock.rb +214 -0
- data/test/spec_focused.rb +75 -0
- data/test/spec_mocha.rb +118 -0
- data/test/spec_nestedcontexts.rb +26 -0
- data/test/spec_new_style.rb +82 -0
- data/test/spec_should-output.rb +26 -0
- data/test/spec_testspec.rb +575 -0
- data/test/spec_testspec_order.rb +26 -0
- data/test/test_testunit.rb +22 -0
- metadata +127 -0
data/TODO
ADDED
data/bin/specrb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
testrbargv = []
|
7
|
+
automatic = false
|
8
|
+
|
9
|
+
opts = OptionParser.new("", 24, ' ') { |opts|
|
10
|
+
opts.banner = "Usage: specrb [options] [files | -a] [-- untouched arguments]"
|
11
|
+
|
12
|
+
opts.separator ""
|
13
|
+
opts.separator "Ruby options:"
|
14
|
+
|
15
|
+
lineno = 1
|
16
|
+
opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line|
|
17
|
+
eval line, TOPLEVEL_BINDING, "-e", lineno
|
18
|
+
lineno += 1
|
19
|
+
}
|
20
|
+
|
21
|
+
opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
|
22
|
+
$DEBUG = true
|
23
|
+
}
|
24
|
+
opts.on("-w", "--warn", "turn warnings on for your script") {
|
25
|
+
$-w = true
|
26
|
+
}
|
27
|
+
|
28
|
+
opts.on("-I", "--include PATH",
|
29
|
+
"specify $LOAD_PATH (may be used more than once)") { |path|
|
30
|
+
$LOAD_PATH.unshift(*path.split(":"))
|
31
|
+
}
|
32
|
+
|
33
|
+
opts.on("-r", "--require LIBRARY",
|
34
|
+
"require the library, before executing your script") { |library|
|
35
|
+
require library
|
36
|
+
}
|
37
|
+
|
38
|
+
opts.separator ""
|
39
|
+
opts.separator "test/spec options:"
|
40
|
+
|
41
|
+
opts.on("-s", "--specdox", "do AgileDox-like output") {
|
42
|
+
testrbargv << "--runner=specdox"
|
43
|
+
}
|
44
|
+
opts.on("--rdox", "do AgileDox-like output with RDoc formatting") {
|
45
|
+
testrbargv << "--runner=rdox"
|
46
|
+
}
|
47
|
+
|
48
|
+
opts.on("-a", "--automatic", "gather tests from ./test/, include ./lib/") {
|
49
|
+
$LOAD_PATH.unshift "lib" if File.directory? "lib"
|
50
|
+
automatic = true
|
51
|
+
}
|
52
|
+
|
53
|
+
opts.separator ""
|
54
|
+
opts.separator "test/unit options:"
|
55
|
+
|
56
|
+
opts.on('-n', '--name NAME', String,
|
57
|
+
"runs tests matching regexp NAME") { |n|
|
58
|
+
testrbargv << "-n" << "/#{n}/"
|
59
|
+
}
|
60
|
+
|
61
|
+
opts.on('-t', '--testcase TESTCASE', String,
|
62
|
+
"runs tests in TestCases matching regexp TESTCASE") { |t|
|
63
|
+
testrbargv << "-t" << "/#{t}/"
|
64
|
+
}
|
65
|
+
|
66
|
+
opts.separator ""
|
67
|
+
opts.separator "Common options:"
|
68
|
+
|
69
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
70
|
+
puts opts
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
|
74
|
+
opts.on_tail("--version", "Show version") do
|
75
|
+
require 'test/spec'
|
76
|
+
puts "specrb #{Test::Spec::VERSION}"
|
77
|
+
exit
|
78
|
+
end
|
79
|
+
|
80
|
+
opts.parse! ARGV
|
81
|
+
}
|
82
|
+
|
83
|
+
files = ARGV
|
84
|
+
|
85
|
+
if automatic
|
86
|
+
files.concat Dir["test/test_*.rb"]
|
87
|
+
files.concat Dir["test/spec_*.rb"]
|
88
|
+
files.concat Dir["spec/spec_*.rb"]
|
89
|
+
end
|
90
|
+
|
91
|
+
if files.empty?
|
92
|
+
puts opts.banner
|
93
|
+
exit 1
|
94
|
+
end
|
95
|
+
|
96
|
+
argv = testrbargv + files
|
97
|
+
# Should use -- to separate them *but* there's a bug in
|
98
|
+
# Test::Unit::AutoRunner#process_args: arguments after -- are ignored.
|
99
|
+
# (You could also argue that it's a bug in optparse.rb).
|
100
|
+
|
101
|
+
require 'test/spec'
|
102
|
+
|
103
|
+
Test::Unit.run = false
|
104
|
+
runner = Test::Unit::AutoRunner.new true
|
105
|
+
runner.process_args(argv) ||
|
106
|
+
abort("internal error calling Test::Unit, please report a bug")
|
107
|
+
exit runner.run
|
data/examples/stack.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copied without code changes from RSpec.
|
2
|
+
|
3
|
+
class StackUnderflowError < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class StackOverflowError < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
class Stack
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@items = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def push object
|
16
|
+
raise StackOverflowError if @items.length == 10
|
17
|
+
@items.push object
|
18
|
+
end
|
19
|
+
|
20
|
+
def pop
|
21
|
+
raise StackUnderflowError if @items.empty?
|
22
|
+
@items.delete @items.last
|
23
|
+
end
|
24
|
+
|
25
|
+
def peek
|
26
|
+
raise StackUnderflowError if @items.empty?
|
27
|
+
@items.last
|
28
|
+
end
|
29
|
+
|
30
|
+
def empty?
|
31
|
+
@items.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def full?
|
35
|
+
@items.length == 10
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# Copied with minor code changes (should_xxx -> should.xxx) from RSpec.
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/test/spec'
|
4
|
+
require File.dirname(__FILE__) + "/stack"
|
5
|
+
|
6
|
+
context "A stack (in general)" do
|
7
|
+
setup do
|
8
|
+
@stack = Stack.new
|
9
|
+
["a","b","c"].each { |x| @stack.push x }
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "should add to the top when sent 'push'" do
|
13
|
+
@stack.push "d"
|
14
|
+
@stack.peek.should.equal "d"
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "should return the top item when sent 'peek'" do
|
18
|
+
@stack.peek.should.equal "c"
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "should NOT remove the top item when sent 'peek'" do
|
22
|
+
@stack.peek.should.equal "c"
|
23
|
+
@stack.peek.should.equal "c"
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "should return the top item when sent 'pop'" do
|
27
|
+
@stack.pop.should.equal "c"
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "should remove the top item when sent 'pop'" do
|
31
|
+
@stack.pop.should.equal "c"
|
32
|
+
@stack.pop.should.equal "b"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "An empty stack" do
|
37
|
+
setup do
|
38
|
+
@stack = Stack.new
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should be empty" do
|
42
|
+
@stack.should.be.empty
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "should no longer be empty after 'push'" do
|
46
|
+
@stack.push "anything"
|
47
|
+
@stack.should.not.be.empty
|
48
|
+
end
|
49
|
+
|
50
|
+
specify "should complain when sent 'peek'" do
|
51
|
+
lambda { @stack.peek }.should.raise StackUnderflowError
|
52
|
+
end
|
53
|
+
|
54
|
+
specify "should complain when sent 'pop'" do
|
55
|
+
lambda { @stack.pop }.should.raise StackUnderflowError
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "An almost empty stack (with one item)" do
|
60
|
+
setup do
|
61
|
+
@stack = Stack.new
|
62
|
+
@stack.push 3
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "should not be empty" do
|
66
|
+
@stack.should.not.be.empty
|
67
|
+
end
|
68
|
+
|
69
|
+
specify "should remain not empty after 'peek'" do
|
70
|
+
@stack.peek
|
71
|
+
@stack.should.not.be.empty
|
72
|
+
end
|
73
|
+
|
74
|
+
specify "should become empty after 'pop'" do
|
75
|
+
@stack.pop
|
76
|
+
@stack.should.be.empty
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "An almost full stack (with one item less than capacity)" do
|
81
|
+
setup do
|
82
|
+
@stack = Stack.new
|
83
|
+
(1..9).each { |i| @stack.push i }
|
84
|
+
end
|
85
|
+
|
86
|
+
specify "should not be full" do
|
87
|
+
@stack.should.not.be.full
|
88
|
+
end
|
89
|
+
|
90
|
+
specify "should become full when sent 'push'" do
|
91
|
+
@stack.push Object.new
|
92
|
+
@stack.should.be.full
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "A full stack" do
|
97
|
+
setup do
|
98
|
+
@stack = Stack.new
|
99
|
+
(1..10).each { |i| @stack.push i }
|
100
|
+
end
|
101
|
+
|
102
|
+
specify "should be full" do
|
103
|
+
@stack.should.be.full
|
104
|
+
end
|
105
|
+
|
106
|
+
specify "should remain full after 'peek'" do
|
107
|
+
@stack.peek
|
108
|
+
@stack.should.be.full
|
109
|
+
end
|
110
|
+
|
111
|
+
specify "should no longer be full after 'pop'" do
|
112
|
+
@stack.pop
|
113
|
+
@stack.should.not.be.full
|
114
|
+
end
|
115
|
+
|
116
|
+
specify "should complain on 'push'" do
|
117
|
+
lambda { @stack.push Object.new }.should.raise StackOverflowError
|
118
|
+
end
|
119
|
+
end
|
data/lib/test/spec.rb
ADDED
@@ -0,0 +1,731 @@
|
|
1
|
+
#
|
2
|
+
# test/spec -- a BDD interface for Test::Unit
|
3
|
+
#
|
4
|
+
# Copyright (C) 2006, 2007 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
|
+
require 'test/unit/collector'
|
11
|
+
require 'test/unit/collector/objectspace'
|
12
|
+
require 'test/spec/focused/collector-extensions'
|
13
|
+
|
14
|
+
class Test::Unit::AutoRunner # :nodoc:
|
15
|
+
RUNNERS[:specdox] = lambda {
|
16
|
+
require 'test/spec/dox'
|
17
|
+
Test::Unit::UI::SpecDox::TestRunner
|
18
|
+
}
|
19
|
+
|
20
|
+
RUNNERS[:rdox] = lambda {
|
21
|
+
require 'test/spec/rdox'
|
22
|
+
Test::Unit::UI::RDox::TestRunner
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
module Test # :nodoc:
|
27
|
+
end
|
28
|
+
|
29
|
+
module Test::Spec
|
30
|
+
require 'test/spec/version'
|
31
|
+
require 'test/spec/focused/focused'
|
32
|
+
require 'test/spec/rails_helper'
|
33
|
+
|
34
|
+
CONTEXTS = {} # :nodoc:
|
35
|
+
SHARED_CONTEXTS = Hash.new { |h,k| h[k] = [] } # :nodoc:
|
36
|
+
include Test::Spec::Focused
|
37
|
+
|
38
|
+
class DefinitionError < StandardError
|
39
|
+
end
|
40
|
+
|
41
|
+
class Should
|
42
|
+
include Test::Unit::Assertions
|
43
|
+
|
44
|
+
def self.deprecated_alias(to, from) # :nodoc:
|
45
|
+
define_method(to) { |*args|
|
46
|
+
warn "Test::Spec::Should##{to} is deprecated and will be removed in future versions."
|
47
|
+
__send__ from, *args
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(object, message=nil)
|
52
|
+
@object = object
|
53
|
+
@message = message
|
54
|
+
end
|
55
|
+
|
56
|
+
$TEST_SPEC_TESTCASE = nil
|
57
|
+
def add_assertion
|
58
|
+
$TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion)
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def an
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def a
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def not(*args)
|
71
|
+
case args.size
|
72
|
+
when 0
|
73
|
+
ShouldNot.new(@object, @message)
|
74
|
+
when 1
|
75
|
+
ShouldNot.new(@object, @message).pass(args.first)
|
76
|
+
else
|
77
|
+
raise ArgumentError, "#not takes zero or one argument(s)."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def messaging(message)
|
82
|
+
@message = message.to_s
|
83
|
+
self
|
84
|
+
end
|
85
|
+
alias blaming messaging
|
86
|
+
|
87
|
+
def satisfy(&block)
|
88
|
+
assert_block(@message || "satisfy block failed.") {
|
89
|
+
yield @object
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def equal(value)
|
94
|
+
assert_equal value, @object, @message
|
95
|
+
end
|
96
|
+
alias == equal
|
97
|
+
|
98
|
+
def close(value, delta)
|
99
|
+
assert_in_delta value, @object, delta, @message
|
100
|
+
end
|
101
|
+
deprecated_alias :be_close, :close
|
102
|
+
|
103
|
+
def be(*value)
|
104
|
+
case value.size
|
105
|
+
when 0
|
106
|
+
self
|
107
|
+
when 1
|
108
|
+
if CustomShould === value.first
|
109
|
+
pass value.first
|
110
|
+
else
|
111
|
+
assert_same value.first, @object, @message
|
112
|
+
end
|
113
|
+
else
|
114
|
+
raise ArgumentError, "should.be needs zero or one argument"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def match(value)
|
119
|
+
assert_match value, @object, @message
|
120
|
+
end
|
121
|
+
alias =~ match
|
122
|
+
|
123
|
+
def instance_of(klass)
|
124
|
+
assert_instance_of klass, @object, @message
|
125
|
+
end
|
126
|
+
deprecated_alias :be_an_instance_of, :instance_of
|
127
|
+
|
128
|
+
def kind_of(klass)
|
129
|
+
assert_kind_of klass, @object, @message
|
130
|
+
end
|
131
|
+
deprecated_alias :be_a_kind_of, :kind_of
|
132
|
+
|
133
|
+
def respond_to(method)
|
134
|
+
assert_respond_to @object, method, @message
|
135
|
+
end
|
136
|
+
|
137
|
+
def _raise(*args, &block)
|
138
|
+
args = [RuntimeError] if args.empty?
|
139
|
+
block ||= @object
|
140
|
+
assert_raise(*(args + [@message]), &block)
|
141
|
+
end
|
142
|
+
|
143
|
+
def throw(*args)
|
144
|
+
assert_throws(*(args + [@message]), &@object)
|
145
|
+
end
|
146
|
+
|
147
|
+
def nil
|
148
|
+
assert_nil @object, @message
|
149
|
+
end
|
150
|
+
deprecated_alias :be_nil, :nil
|
151
|
+
|
152
|
+
|
153
|
+
def include(value)
|
154
|
+
msg = build_message(@message, "<?> expected to include ?, but it didn't.",
|
155
|
+
@object, value)
|
156
|
+
assert_block(msg) { @object.include?(value) }
|
157
|
+
end
|
158
|
+
|
159
|
+
def >(value)
|
160
|
+
assert_operator @object, :>, value, @message
|
161
|
+
end
|
162
|
+
|
163
|
+
def >=(value)
|
164
|
+
assert_operator @object, :>=, value, @message
|
165
|
+
end
|
166
|
+
|
167
|
+
def <(value)
|
168
|
+
assert_operator @object, :<, value, @message
|
169
|
+
end
|
170
|
+
|
171
|
+
def <=(value)
|
172
|
+
assert_operator @object, :<=, value, @message
|
173
|
+
end
|
174
|
+
|
175
|
+
def ===(value)
|
176
|
+
assert_operator @object, :===, value, @message
|
177
|
+
end
|
178
|
+
|
179
|
+
def pass(custom)
|
180
|
+
_wrap_assertion {
|
181
|
+
assert_nothing_raised(Test::Unit::AssertionFailedError,
|
182
|
+
@message || custom.failure_message) {
|
183
|
+
assert custom.matches?(@object), @message || custom.failure_message
|
184
|
+
}
|
185
|
+
}
|
186
|
+
end
|
187
|
+
|
188
|
+
def method_missing(name, *args, &block)
|
189
|
+
# This will make raise call Kernel.raise, and self.raise call _raise.
|
190
|
+
return _raise(*args, &block) if name == :raise
|
191
|
+
|
192
|
+
if @object.respond_to?("#{name}?")
|
193
|
+
assert @object.__send__("#{name}?", *args),
|
194
|
+
"#{name}? expected to be true. #{@message}"
|
195
|
+
else
|
196
|
+
if @object.respond_to?(name)
|
197
|
+
assert @object.__send__(name, *args),
|
198
|
+
"#{name} expected to be true. #{@message}"
|
199
|
+
else
|
200
|
+
super
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
class ShouldNot
|
207
|
+
include Test::Unit::Assertions
|
208
|
+
|
209
|
+
def initialize(object, message=nil)
|
210
|
+
@object = object
|
211
|
+
@message = message
|
212
|
+
end
|
213
|
+
|
214
|
+
def add_assertion
|
215
|
+
$TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion)
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
def satisfy(&block)
|
220
|
+
assert_block(@message || "not.satisfy block succeded.") {
|
221
|
+
not yield @object
|
222
|
+
}
|
223
|
+
end
|
224
|
+
|
225
|
+
def equal(value)
|
226
|
+
assert_not_equal value, @object, @message
|
227
|
+
end
|
228
|
+
alias == equal
|
229
|
+
|
230
|
+
def be(*value)
|
231
|
+
case value.size
|
232
|
+
when 0
|
233
|
+
self
|
234
|
+
when 1
|
235
|
+
if CustomShould === value.first
|
236
|
+
pass value.first
|
237
|
+
else
|
238
|
+
assert_not_same value.first, @object, @message
|
239
|
+
end
|
240
|
+
else
|
241
|
+
Kernel.raise ArgumentError, "should.be needs zero or one argument"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def match(value)
|
246
|
+
# Icky Regexp check
|
247
|
+
assert_no_match value, @object, @message
|
248
|
+
end
|
249
|
+
alias =~ match
|
250
|
+
|
251
|
+
def _raise(*args, &block)
|
252
|
+
block ||= @object
|
253
|
+
assert_nothing_raised(*(args+[@message]), &block)
|
254
|
+
end
|
255
|
+
|
256
|
+
def throw
|
257
|
+
assert_nothing_thrown(@message, &@object)
|
258
|
+
end
|
259
|
+
|
260
|
+
def nil
|
261
|
+
assert_not_nil @object, @message
|
262
|
+
end
|
263
|
+
|
264
|
+
def be_nil
|
265
|
+
warn "Test::Spec::ShouldNot#be_nil is deprecated and will be removed in future versions."
|
266
|
+
self.nil
|
267
|
+
end
|
268
|
+
|
269
|
+
def not(*args)
|
270
|
+
case args.size
|
271
|
+
when 0
|
272
|
+
Should.new(@object, @message)
|
273
|
+
when 1
|
274
|
+
Should.new(@object, @message).pass(args.first)
|
275
|
+
else
|
276
|
+
raise ArgumentError, "#not takes zero or one argument(s)."
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def pass(custom)
|
281
|
+
_wrap_assertion {
|
282
|
+
begin
|
283
|
+
assert !custom.matches?(@object), @message || custom.failure_message
|
284
|
+
end
|
285
|
+
}
|
286
|
+
end
|
287
|
+
|
288
|
+
def method_missing(name, *args, &block)
|
289
|
+
# This will make raise call Kernel.raise, and self.raise call _raise.
|
290
|
+
return _raise(*args, &block) if name == :raise
|
291
|
+
|
292
|
+
if @object.respond_to?("#{name}?")
|
293
|
+
assert_block("#{name}? expected to be false. #{@message}") {
|
294
|
+
not @object.__send__("#{name}?", *args)
|
295
|
+
}
|
296
|
+
else
|
297
|
+
if @object.respond_to?(name)
|
298
|
+
assert_block("#{name} expected to be false. #{@message}") {
|
299
|
+
not @object.__send__("#{name}", *args)
|
300
|
+
}
|
301
|
+
else
|
302
|
+
super
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
308
|
+
|
309
|
+
class CustomShould
|
310
|
+
attr_accessor :object
|
311
|
+
|
312
|
+
def initialize(obj)
|
313
|
+
self.object = obj
|
314
|
+
end
|
315
|
+
|
316
|
+
def failure_message
|
317
|
+
"#{self.class.name} failed"
|
318
|
+
end
|
319
|
+
|
320
|
+
def matches?(*args, &block)
|
321
|
+
assumptions(*args, &block)
|
322
|
+
true
|
323
|
+
end
|
324
|
+
|
325
|
+
def assumptions(*args, &block)
|
326
|
+
raise NotImplementedError, "you need to supply a #{self.class}#matches? method"
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
class Test::Spec::TestCase
|
332
|
+
attr_reader :testcase
|
333
|
+
attr_reader :name
|
334
|
+
attr_reader :position
|
335
|
+
attr_accessor :ignore
|
336
|
+
|
337
|
+
module InstanceMethods
|
338
|
+
def setup # :nodoc:
|
339
|
+
$TEST_SPEC_TESTCASE = self
|
340
|
+
super
|
341
|
+
self.class.setups.each { |s| instance_eval(&s) }
|
342
|
+
end
|
343
|
+
|
344
|
+
def teardown # :nodoc:
|
345
|
+
super
|
346
|
+
self.class.teardowns.each { |t| instance_eval(&t) }
|
347
|
+
end
|
348
|
+
|
349
|
+
def before_all
|
350
|
+
self.class.before_all.each { |t| instance_eval(&t) }
|
351
|
+
end
|
352
|
+
|
353
|
+
def after_all
|
354
|
+
self.class.after_all.each { |t| instance_eval(&t) }
|
355
|
+
end
|
356
|
+
|
357
|
+
def initialize(name)
|
358
|
+
super name
|
359
|
+
|
360
|
+
# Don't let the default_test clutter up the results and don't
|
361
|
+
# flunk if no tests given, either.
|
362
|
+
throw :invalid_test if name.to_s == "default_test"
|
363
|
+
end
|
364
|
+
|
365
|
+
def position
|
366
|
+
self.class.position
|
367
|
+
end
|
368
|
+
|
369
|
+
def context(*args)
|
370
|
+
raise Test::Spec::DefinitionError, "context definition is not allowed inside a specify-block"
|
371
|
+
end
|
372
|
+
|
373
|
+
alias :describe :context
|
374
|
+
end
|
375
|
+
|
376
|
+
module ClassMethods
|
377
|
+
attr_accessor :count
|
378
|
+
attr_accessor :name
|
379
|
+
attr_accessor :position
|
380
|
+
attr_accessor :parent
|
381
|
+
|
382
|
+
attr_accessor :setups
|
383
|
+
attr_accessor :teardowns
|
384
|
+
|
385
|
+
attr_accessor :before_all
|
386
|
+
attr_accessor :after_all
|
387
|
+
|
388
|
+
# old-style (RSpec <1.0):
|
389
|
+
|
390
|
+
def context(name_or_class, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block)
|
391
|
+
cls_string = name_or_class.is_a?(String) ? name_or_class : name_or_class.class.to_s
|
392
|
+
superclass = Test::Spec::RailsHelper.figure_out_superclass_from_name(name_or_class, superclass)
|
393
|
+
|
394
|
+
superclass = self.superclass
|
395
|
+
|
396
|
+
if self.respond_to?(:controller_class=)
|
397
|
+
controller_klass = name.is_a?(Class) ? name : Test::Spec::RailsHelper::infer_controller_class(name)
|
398
|
+
self.controller_class = controller_klass if controller_klass
|
399
|
+
end
|
400
|
+
|
401
|
+
(Test::Spec::CONTEXTS[self.name.to_s + "\t" + cls_string] ||= klass.new(cls_string, self, superclass)).add(&block)
|
402
|
+
end
|
403
|
+
|
404
|
+
def fcontext(name, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block)
|
405
|
+
Test::Spec.set_focused_mode(true)
|
406
|
+
context(name, superclass, Test::Spec::FocusedTestCase, &block)
|
407
|
+
end
|
408
|
+
|
409
|
+
def xcontext(name, superclass=Test::Unit::TestCase, &block)
|
410
|
+
context(name, superclass, Test::Spec::DisabledTestCase, &block)
|
411
|
+
end
|
412
|
+
|
413
|
+
def specify(specname, &block)
|
414
|
+
if block.nil?
|
415
|
+
pspecify(specname)
|
416
|
+
else
|
417
|
+
self.count += 1 # Let them run in order of definition
|
418
|
+
define_method("test_spec {%s} %03d [%s]" % [name, count, specname], &block) unless Test::Spec.focused_mode?
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def undef_previous_specs
|
423
|
+
instance_methods.grep(/test_spec/).each do |meth|
|
424
|
+
undef_method meth
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def fspecify(specname, &block)
|
429
|
+
Test::Spec.set_focused_mode(true, self.name)
|
430
|
+
undef_previous_specs
|
431
|
+
self.count += 1 # Let them run in order of definition
|
432
|
+
define_method("test_spec {%s} %03d [%s]" % [name, count, specname], &block)
|
433
|
+
end
|
434
|
+
|
435
|
+
def xspecify(specname, &block)
|
436
|
+
specify specname do
|
437
|
+
@_result.add_disabled(specname)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def pspecify(specname, &block)
|
442
|
+
specify specname do
|
443
|
+
@_result.add_pending(specname)
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def setup(&block)
|
448
|
+
setups << block
|
449
|
+
end
|
450
|
+
|
451
|
+
def teardown(&block)
|
452
|
+
teardowns << block
|
453
|
+
end
|
454
|
+
|
455
|
+
def shared_context(name, &block)
|
456
|
+
Test::Spec::SHARED_CONTEXTS[self.name + "\t" + name] << block
|
457
|
+
end
|
458
|
+
|
459
|
+
def behaves_like(shared_context)
|
460
|
+
if Test::Spec::SHARED_CONTEXTS.include?(shared_context)
|
461
|
+
Test::Spec::SHARED_CONTEXTS[shared_context].each { |block|
|
462
|
+
instance_eval(&block)
|
463
|
+
}
|
464
|
+
elsif Test::Spec::SHARED_CONTEXTS.include?(self.name + "\t" + shared_context)
|
465
|
+
Test::Spec::SHARED_CONTEXTS[self.name + "\t" + shared_context].each { |block|
|
466
|
+
instance_eval(&block)
|
467
|
+
}
|
468
|
+
else
|
469
|
+
raise NameError, "Shared context #{shared_context} not found."
|
470
|
+
end
|
471
|
+
end
|
472
|
+
alias :it_should_behave_like :behaves_like
|
473
|
+
|
474
|
+
# new-style (RSpec 1.0+):
|
475
|
+
|
476
|
+
alias :describe :context
|
477
|
+
alias :fdescribe :fcontext
|
478
|
+
alias :describe_shared :shared_context
|
479
|
+
alias :it :specify
|
480
|
+
alias :they :specify
|
481
|
+
alias :xit :xspecify
|
482
|
+
alias :fit :fspecify
|
483
|
+
alias :pit :pspecify
|
484
|
+
|
485
|
+
def before(kind=:each, &block)
|
486
|
+
case kind
|
487
|
+
when :each
|
488
|
+
setup(&block)
|
489
|
+
when :all
|
490
|
+
before_all << block
|
491
|
+
else
|
492
|
+
raise ArgumentError, "invalid argument: before(#{kind.inspect})"
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
def after(kind=:each, &block)
|
497
|
+
case kind
|
498
|
+
when :each
|
499
|
+
teardown(&block)
|
500
|
+
when :all
|
501
|
+
after_all << block
|
502
|
+
else
|
503
|
+
raise ArgumentError, "invalid argument: after(#{kind.inspect})"
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
|
508
|
+
def init(name, position, parent)
|
509
|
+
self.position = position
|
510
|
+
self.parent = parent
|
511
|
+
|
512
|
+
if parent
|
513
|
+
self.name = parent.name.to_s + "\t" + name
|
514
|
+
else
|
515
|
+
self.name = name.to_s
|
516
|
+
end
|
517
|
+
|
518
|
+
self.count = 0
|
519
|
+
self.setups = []
|
520
|
+
self.teardowns = []
|
521
|
+
|
522
|
+
self.before_all = []
|
523
|
+
self.after_all = []
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
@@POSITION = 0
|
528
|
+
|
529
|
+
def initialize(name, parent=nil, superclass=Test::Unit::TestCase)
|
530
|
+
@testcase = Class.new(superclass) {
|
531
|
+
include Test::Spec::TestCase::InstanceMethods
|
532
|
+
extend Test::Spec::TestCase::ClassMethods
|
533
|
+
# p "extending onto #{self} with class #{self.class} with superclass #{superclass} and ancestors #{self.ancestors.join(",")}"
|
534
|
+
}
|
535
|
+
|
536
|
+
@@POSITION ||= 0
|
537
|
+
@@POSITION = @@POSITION + 1
|
538
|
+
@testcase.init(name, @@POSITION, parent)
|
539
|
+
end
|
540
|
+
|
541
|
+
def add(&block)
|
542
|
+
raise ArgumentError, "context needs a block" if block.nil?
|
543
|
+
|
544
|
+
@testcase.class_eval(&block)
|
545
|
+
self
|
546
|
+
end
|
547
|
+
|
548
|
+
def ignore?
|
549
|
+
@ignore == true
|
550
|
+
end
|
551
|
+
|
552
|
+
end
|
553
|
+
|
554
|
+
class Test::Spec::FocusedTestCase < Test::Spec::TestCase
|
555
|
+
|
556
|
+
def initialize(name, parent=nil, superclass=Test::Unit::TestCase)
|
557
|
+
super
|
558
|
+
end
|
559
|
+
|
560
|
+
def long_display
|
561
|
+
@name + " is in focused mode"
|
562
|
+
end
|
563
|
+
|
564
|
+
end
|
565
|
+
|
566
|
+
(Test::Spec::DisabledTestCase = Test::Spec::TestCase.dup).class_eval do
|
567
|
+
alias :test_case_initialize :initialize
|
568
|
+
|
569
|
+
def initialize(*args, &block)
|
570
|
+
test_case_initialize(*args, &block)
|
571
|
+
@testcase.instance_eval do
|
572
|
+
alias :test_case_specify :specify
|
573
|
+
|
574
|
+
def specify(specname, &block)
|
575
|
+
test_case_specify(specname) { @_result.add_disabled(specname) }
|
576
|
+
end
|
577
|
+
alias :it :specify
|
578
|
+
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
class Test::Spec::Failure < Test::Unit::Failure # :nodoc:
|
584
|
+
attr_reader :single_character_display
|
585
|
+
|
586
|
+
def initialize(attrs)
|
587
|
+
@name = attrs[:name]
|
588
|
+
@single_character_display = attrs[:single_character_display]
|
589
|
+
@long_display = attrs[:long_display]
|
590
|
+
end
|
591
|
+
|
592
|
+
def short_display
|
593
|
+
@name
|
594
|
+
end
|
595
|
+
|
596
|
+
def long_display
|
597
|
+
@long_display % @name
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
class Test::Spec::Disabled < Test::Spec::Failure # :nodoc:
|
602
|
+
def initialize(name)
|
603
|
+
super(:name => name, :single_character_display => 'D', :long_display => "Disabled: %s")
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
class Test::Spec::Empty < Test::Spec::Failure # :nodoc:
|
608
|
+
def initialize(name)
|
609
|
+
super(:name => name, :single_character_display => "", :long_display => "Empty: %s")
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
class Test::Spec::Pending < Test::Spec::Failure # :nodoc:
|
614
|
+
def initialize(name)
|
615
|
+
super(:name => name, :single_character_display => 'P', :long_display => "Pending: %s")
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
# Monkey-patch test/unit to run tests in an optionally specified order.
|
620
|
+
module Test::Unit # :nodoc:
|
621
|
+
class TestSuite # :nodoc:
|
622
|
+
undef run
|
623
|
+
|
624
|
+
def run(result, &progress_block)
|
625
|
+
sort!
|
626
|
+
|
627
|
+
yield(STARTED, name)
|
628
|
+
|
629
|
+
@tests.first.before_all if @tests.first.respond_to? :before_all
|
630
|
+
@tests.each do |test|
|
631
|
+
test.run(result, &progress_block)
|
632
|
+
end
|
633
|
+
@tests.last.after_all if @tests.last.respond_to? :after_all
|
634
|
+
yield(FINISHED, name)
|
635
|
+
end
|
636
|
+
|
637
|
+
def sort!
|
638
|
+
@tests = @tests.sort_by { |test|
|
639
|
+
test.respond_to?(:position) ? test.position : 0
|
640
|
+
}
|
641
|
+
end
|
642
|
+
|
643
|
+
def position
|
644
|
+
@tests.first.respond_to?(:position) ? @tests.first.position : 0
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
class TestResult # :nodoc:
|
649
|
+
# Records a disabled test.
|
650
|
+
def add_disabled(name)
|
651
|
+
notify_listeners(FAULT, Test::Spec::Disabled.new(name))
|
652
|
+
notify_listeners(CHANGED, self)
|
653
|
+
end
|
654
|
+
|
655
|
+
def add_pending(name)
|
656
|
+
notify_listeners(FAULT, Test::Spec::Pending.new(name))
|
657
|
+
notify_listeners(CHANGED, self)
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
|
663
|
+
# Hide Test::Spec interna in backtraces.
|
664
|
+
module Test::Unit::Util::BacktraceFilter # :nodoc:
|
665
|
+
TESTSPEC_PREFIX = __FILE__.gsub(/spec\.rb\Z/, '')
|
666
|
+
|
667
|
+
# Vendor plugins like to be loaded several times, don't recurse
|
668
|
+
# infinitely then.
|
669
|
+
unless method_defined? "testspec_filter_backtrace"
|
670
|
+
alias :testspec_filter_backtrace :filter_backtrace
|
671
|
+
end
|
672
|
+
|
673
|
+
def filter_backtrace(backtrace, prefix=nil)
|
674
|
+
if prefix.nil?
|
675
|
+
testspec_filter_backtrace(testspec_filter_backtrace(backtrace),
|
676
|
+
TESTSPEC_PREFIX)
|
677
|
+
else
|
678
|
+
testspec_filter_backtrace(backtrace, prefix)
|
679
|
+
end
|
680
|
+
end
|
681
|
+
end
|
682
|
+
|
683
|
+
|
684
|
+
#-- Global helpers
|
685
|
+
|
686
|
+
class Object
|
687
|
+
def should(*args)
|
688
|
+
case args.size
|
689
|
+
when 0
|
690
|
+
Test::Spec::Should.new(self)
|
691
|
+
when 1
|
692
|
+
Test::Spec::Should.new(self).pass(args.first)
|
693
|
+
else
|
694
|
+
raise ArgumentError, "Object#should takes zero or one argument(s)."
|
695
|
+
end
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
module Kernel
|
700
|
+
def context(name_or_class, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block) # :doc:
|
701
|
+
superclass = Test::Spec::RailsHelper.figure_out_superclass_from_name(name_or_class, superclass)
|
702
|
+
|
703
|
+
if superclass.respond_to?(:controller_class=)
|
704
|
+
controller_klass = name_or_class.is_a?(Class) ? name_or_class : Test::Spec::RailsHelper::infer_controller_class(name_or_class)
|
705
|
+
superclass.controller_class = controller_klass if controller_klass
|
706
|
+
end
|
707
|
+
|
708
|
+
(Test::Spec::CONTEXTS[name_or_class] ||= klass.new(name_or_class, nil, superclass)).add(&block)
|
709
|
+
end
|
710
|
+
|
711
|
+
def fcontext(name_or_class, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block) # :doc:
|
712
|
+
Test::Spec.set_focused_mode(true)
|
713
|
+
context(name_or_class, superclass, Test::Spec::FocusedTestCase, &block)
|
714
|
+
end
|
715
|
+
|
716
|
+
def xcontext(name_or_class, superclass=Test::Unit::TestCase, &block) # :doc:
|
717
|
+
context(name_or_class, superclass, Test::Spec::DisabledTestCase, &block)
|
718
|
+
end
|
719
|
+
|
720
|
+
def shared_context(name, &block)
|
721
|
+
Test::Spec::SHARED_CONTEXTS[name] << block
|
722
|
+
end
|
723
|
+
|
724
|
+
alias :describe :context
|
725
|
+
alias :xdescribe :xcontext
|
726
|
+
alias :describe_shared :shared_context
|
727
|
+
|
728
|
+
private :context, :xcontext, :shared_context
|
729
|
+
private :describe, :xdescribe, :describe_shared
|
730
|
+
|
731
|
+
end
|