baretest 0.1.0 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +52 -0
- data/MANIFEST.txt +50 -31
- data/README.rdoc +260 -0
- data/bin/baretest +82 -24
- data/doc/baretest.rdoc +98 -0
- data/doc/mocking_stubbing_test_doubles.rdoc +5 -0
- data/doc/quickref.rdoc +261 -0
- data/doc/writing_tests.rdoc +148 -0
- data/examples/test.rake +58 -30
- data/examples/tests/irb_mode/failures.rb +26 -0
- data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
- data/examples/tests/mock_developer/test/setup.rb +57 -0
- data/examples/tests/mock_developer/test/suite/mock_demo.rb +19 -0
- data/examples/tests/overview/test.rb +89 -0
- data/examples/tests/variations/variations_01.rb +14 -0
- data/examples/tests/variations/variations_02.rb +19 -0
- data/examples/tests/variations/variations_03.rb +19 -0
- data/lib/baretest/assertion/context.rb +20 -0
- data/lib/baretest/assertion/failure.rb +22 -0
- data/lib/baretest/assertion/skip.rb +21 -0
- data/lib/{test → baretest}/assertion/support.rb +174 -39
- data/lib/baretest/assertion.rb +182 -0
- data/lib/baretest/irb_mode.rb +263 -0
- data/lib/{test/assertion/failure.rb → baretest/layout.rb} +6 -5
- data/lib/baretest/mocha.rb +18 -0
- data/lib/baretest/run/cli.rb +104 -0
- data/lib/{test → baretest}/run/errors.rb +12 -7
- data/lib/{test → baretest}/run/minimal.rb +8 -3
- data/lib/baretest/run/profile.rb +151 -0
- data/lib/{test → baretest}/run/spec.rb +10 -4
- data/lib/baretest/run/tap.rb +44 -0
- data/lib/baretest/run/xml.rb +80 -0
- data/lib/{test → baretest}/run.rb +31 -18
- data/lib/baretest/setup.rb +15 -0
- data/lib/baretest/skipped/assertion.rb +20 -0
- data/lib/baretest/skipped/suite.rb +49 -0
- data/lib/baretest/skipped.rb +15 -0
- data/lib/baretest/suite.rb +234 -0
- data/lib/baretest/utilities.rb +43 -0
- data/lib/{test → baretest}/version.rb +12 -3
- data/lib/baretest.rb +112 -0
- data/test/external/bootstraptest.rb +1 -1
- data/test/setup.rb +1 -1
- data/test/{lib/test → suite/lib/baretest}/assertion/support.rb +78 -24
- data/test/suite/lib/baretest/assertion.rb +192 -0
- data/test/{lib/test → suite/lib/baretest}/irb_mode.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/cli.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/errors.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/interactive.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/spec.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/tap.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run/xml.rb +0 -0
- data/test/{lib/test → suite/lib/baretest}/run.rb +63 -61
- data/test/{lib/test → suite/lib/baretest}/suite.rb +77 -54
- data/test/{lib/test.rb → suite/lib/baretest.rb} +37 -37
- metadata +61 -40
- data/README.markdown +0 -229
- data/examples/test.rb +0 -93
- data/lib/test/assertion.rb +0 -117
- data/lib/test/debug.rb +0 -34
- data/lib/test/irb_mode.rb +0 -104
- data/lib/test/run/cli.rb +0 -79
- data/lib/test/run/interactive.rb +0 -60
- data/lib/test/run/tap.rb +0 -32
- data/lib/test/run/xml.rb +0 -56
- data/lib/test/suite.rb +0 -95
- data/lib/test.rb +0 -118
- data/test/lib/test/assertion.rb +0 -142
- data/test/lib/test/debug.rb +0 -63
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
BareTest.suite "Variations 01" do
|
4
|
+
setup do puts "n1" end
|
5
|
+
setup do puts "n2" end
|
6
|
+
setup :a, "a1" do puts "a1" end
|
7
|
+
setup :a, "a2" do puts "a2" end
|
8
|
+
setup :b, "b1" do puts "b1" end
|
9
|
+
setup :b, "b2" do puts "b2" end
|
10
|
+
|
11
|
+
assert "variants, a: :a, b: :b" do
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
class String
|
4
|
+
def numeric?
|
5
|
+
self =~ /[+-]?(?:[1-9]\d*|0)(?:\.\d+)?(?:[eE][+-]?\d+)?/
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
BareTest.suite do
|
10
|
+
suite "Variations 02" do
|
11
|
+
setup :number, %w[123 -123 1.23 -1.23 1e3 -1e3 1e-3 -1e-3] do |number|
|
12
|
+
@number = number
|
13
|
+
end
|
14
|
+
|
15
|
+
assert ":number should be a numeric" do
|
16
|
+
@number.numeric?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
class String
|
4
|
+
def numeric?
|
5
|
+
self =~ /[+-]?(?:[1-9]\d*|0)(?:\.\d+)?(?:[eE][+-]?\d+)?/
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
BareTest.suite do
|
10
|
+
suite "Variations 02" do
|
11
|
+
setup :number, {'"123"' => "123", '"1.23"' => "1.23", '"1e3"' => "1e3"} do |number|
|
12
|
+
@number = number
|
13
|
+
end
|
14
|
+
|
15
|
+
assert ":number should be a numeric" do
|
16
|
+
@number.numeric?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
class Assertion
|
11
|
+
class Context
|
12
|
+
attr_reader :__assertion__
|
13
|
+
alias assertion __assertion__
|
14
|
+
|
15
|
+
def initialize(assertion)
|
16
|
+
@__assertion__ = assertion
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
class Assertion
|
11
|
+
|
12
|
+
# BareTest::Assertion::Failure can be raised within an assertion to indicate that the
|
13
|
+
# assertion failed. Unlike all other exceptions, this one will not set the Assertion's
|
14
|
+
# status to :error but to :failure. The exception's #message is used as
|
15
|
+
# Assertion#reason.
|
16
|
+
# Take a look at the implementation of some methods of BareTest::Assertion::Support for
|
17
|
+
# examples on how to use it.
|
18
|
+
#
|
19
|
+
class Failure < StandardError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module BareTest
|
10
|
+
class Assertion
|
11
|
+
|
12
|
+
# BareTest::Assertion::Skip can be raised within an assertion to indicate that the
|
13
|
+
# assertion is to be skipped. Unlike all other exceptions, this one will not set the Assertion's
|
14
|
+
# status to :error but to :failure. The exception's #message is used as
|
15
|
+
# Assertion#reason.
|
16
|
+
# Also see BareTest::Assertion::Support#skip
|
17
|
+
#
|
18
|
+
class Skip < StandardError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -6,51 +6,103 @@
|
|
6
6
|
|
7
7
|
|
8
8
|
|
9
|
-
require '
|
9
|
+
require 'baretest/assertion/failure'
|
10
|
+
require 'baretest/assertion/skip'
|
10
11
|
begin
|
11
12
|
require 'thread'
|
12
13
|
rescue LoadError; end # no thread support in this ruby
|
13
14
|
|
14
15
|
|
15
16
|
|
16
|
-
module
|
17
|
+
module BareTest
|
17
18
|
@touch = {}
|
19
|
+
|
18
20
|
# We don't want to litter in Assertion
|
19
|
-
# Touches are associated
|
20
|
-
|
21
|
+
# Touches are associated withx
|
22
|
+
# Used by BareTest::Assertion::Support#touch
|
23
|
+
def self.touch(assertion, thing=nil) # :nodoc:
|
21
24
|
@touch[assertion] ||= Hash.new(0)
|
22
25
|
@touch[assertion][thing] += 1
|
23
26
|
end
|
24
27
|
|
25
|
-
|
28
|
+
# Used by BareTest::Assertion::Support#touched
|
29
|
+
def self.touched(assertion, thing=nil) # :nodoc:
|
26
30
|
@touch[assertion] ||= Hash.new(0)
|
27
31
|
@touch[assertion][thing]
|
28
32
|
end
|
29
33
|
|
30
|
-
|
34
|
+
# Used by BareTest::Assertion::Support
|
35
|
+
def self.clean_touches(assertion) # :nodoc:
|
31
36
|
@touch.delete(assertion)
|
32
37
|
end
|
33
|
-
end
|
34
38
|
|
35
|
-
module Test
|
36
39
|
class Assertion
|
40
|
+
|
41
|
+
# BareTest::Assertion::Support is per default included into BareTest::Assertion.
|
42
|
+
# It provides several methods to make it easier to write assertions.
|
43
|
+
#
|
37
44
|
module Support
|
45
|
+
|
46
|
+
# Creates global setup and teardown callbacks that are needed by some of
|
47
|
+
# BareTest::Assertion::Support's methods.
|
48
|
+
#
|
38
49
|
module SetupAndTeardown
|
39
|
-
|
50
|
+
|
51
|
+
# Install the setup and teardown callbacks.
|
52
|
+
def self.extended(run_obj) # :nodoc:
|
40
53
|
run_obj.init do
|
41
54
|
suite.teardown do
|
42
|
-
|
55
|
+
::BareTest.clean_touches(self) # instance evaled, self is the assertion
|
43
56
|
end
|
44
57
|
end
|
45
58
|
end
|
46
59
|
|
47
|
-
|
60
|
+
::BareTest.extender << self
|
61
|
+
end
|
62
|
+
|
63
|
+
# FIXME: undocumented and untested
|
64
|
+
# It's really ugly. You should use a mock instead.
|
65
|
+
def yields(subject, meth, args, *expected)
|
66
|
+
subject.__send__(meth, *args) do |*actual|
|
67
|
+
current = expected.shift
|
68
|
+
return false unless actual == current
|
69
|
+
end
|
70
|
+
return expected.empty?
|
71
|
+
end
|
72
|
+
|
73
|
+
# FIXME: incomplete and untested
|
74
|
+
def throws(symbol) # :nodoc:
|
75
|
+
begin
|
76
|
+
passed = false
|
77
|
+
catch(sym) {
|
78
|
+
yield
|
79
|
+
passed = true
|
80
|
+
return false
|
81
|
+
}
|
82
|
+
passed = true
|
83
|
+
return true
|
84
|
+
rescue NameError => e
|
85
|
+
return false if e.message =~ 'uncaught throw'
|
86
|
+
raise
|
87
|
+
rescue Exception
|
88
|
+
passed = true
|
89
|
+
raise
|
90
|
+
ensure
|
91
|
+
raise ThrewSomethingElse unless passed
|
92
|
+
end
|
93
|
+
rescue ThrewSomethingElse => e
|
94
|
+
return false
|
95
|
+
end
|
96
|
+
|
97
|
+
# FIXME: incomplete and untested
|
98
|
+
def throws_nothing # :nodoc:
|
48
99
|
end
|
49
100
|
|
50
101
|
# Will raise a Failure if the given block doesn't raise or raises a different
|
51
102
|
# exception than the one provided
|
52
103
|
# You can optionally give an options :with_message, which is tested with === against
|
53
104
|
# the exception message.
|
105
|
+
#
|
54
106
|
# Examples:
|
55
107
|
# raises do raise "will work" end # => true
|
56
108
|
# raises SomeException do raise SomeException end # => true
|
@@ -58,26 +110,28 @@ module Test
|
|
58
110
|
# raises SomeException, :with_message => "bar"; raise SomeException, "bar" end # => true
|
59
111
|
# raises :with_message => /\Aknown \w+\z/; raise "known unknown" end # => true
|
60
112
|
def raises(exception_class=StandardError, opts={})
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
exception.message, opts[:with_message]
|
67
|
-
else
|
68
|
-
true
|
69
|
-
end
|
70
|
-
rescue => exception
|
71
|
-
failure "Expected block to raise #{exception_class}, but it raised #{exception.class}."
|
113
|
+
yield
|
114
|
+
rescue exception_class => exception
|
115
|
+
if opts[:with_message] && !(opts[:with_message] === exception.message) then
|
116
|
+
failure "Expected block to raise with the message %p, but the message was %p",
|
117
|
+
exception.message, opts[:with_message]
|
72
118
|
else
|
73
|
-
|
119
|
+
true
|
74
120
|
end
|
121
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
122
|
+
::Kernel.raise
|
123
|
+
rescue => exception
|
124
|
+
failure "Expected block to raise #{exception_class}, but it raised #{exception.class}."
|
125
|
+
else
|
126
|
+
failure "Expected block to raise #{exception_class}, but nothing was raised."
|
75
127
|
end
|
76
128
|
|
77
129
|
# Will raise a Failure if the given block raises.
|
78
130
|
def raises_nothing
|
79
131
|
yield
|
80
|
-
rescue
|
132
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
133
|
+
::Kernel.raise
|
134
|
+
rescue Exception => exception
|
81
135
|
failure "Expected block to raise nothing, but it raised #{exception.class}."
|
82
136
|
else
|
83
137
|
true
|
@@ -88,10 +142,15 @@ module Test
|
|
88
142
|
# of the possible rounding differences.
|
89
143
|
def within_delta(a, b, delta)
|
90
144
|
(a-b).abs < delta
|
145
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
146
|
+
::Kernel.raise
|
147
|
+
rescue Exception => e
|
148
|
+
failure "Could not compare %p with %p due to %s", a, b, e
|
91
149
|
end
|
92
150
|
|
93
151
|
# Use this method to test whether certain code (e.g. a callback) was reached.
|
94
152
|
# touch marks that it was reached, #touched tests for whether it was reached.
|
153
|
+
#
|
95
154
|
# Example:
|
96
155
|
# assert "Code in a Proc object is executed when invoking #call on it." do
|
97
156
|
# a_proc = proc { touch :executed }
|
@@ -99,12 +158,15 @@ module Test
|
|
99
158
|
# touched(:executed)
|
100
159
|
# end
|
101
160
|
def touch(thing=nil)
|
102
|
-
::
|
161
|
+
::BareTest.touch(self, thing)
|
103
162
|
end
|
104
163
|
|
164
|
+
# Used to verify that something was touched. You can also verify that something was touched
|
165
|
+
# a specific amount of times.
|
166
|
+
#
|
105
167
|
# See #touch
|
106
168
|
def touched(thing=nil, times=nil)
|
107
|
-
touched_times = ::
|
169
|
+
touched_times = ::BareTest.touched(self, thing)
|
108
170
|
if times then
|
109
171
|
unless touched_times == times then
|
110
172
|
if thing then
|
@@ -123,14 +185,18 @@ module Test
|
|
123
185
|
true
|
124
186
|
end
|
125
187
|
|
188
|
+
# Used to verify that something was not touched.
|
189
|
+
#
|
126
190
|
# See #touch
|
127
191
|
def not_touched(thing=nil)
|
128
192
|
touched(thing, 0)
|
129
193
|
end
|
130
194
|
|
131
195
|
# Uses equal? to test whether the objects are the same
|
132
|
-
#
|
133
|
-
#
|
196
|
+
#
|
197
|
+
# Can be used in either of the following ways:
|
198
|
+
# same expected, actual
|
199
|
+
# same :expected => expected, :actual => actual
|
134
200
|
def same(*args)
|
135
201
|
expected, actual, message = extract_args(args, :expected, :actual, :message)
|
136
202
|
|
@@ -142,11 +208,18 @@ module Test
|
|
142
208
|
end
|
143
209
|
end
|
144
210
|
true
|
211
|
+
|
212
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
213
|
+
::Kernel.raise
|
214
|
+
rescue Exception => e
|
215
|
+
failure "Could not compare %p with %p due to %s", expected, actual, e
|
145
216
|
end
|
146
217
|
|
147
218
|
# Uses eql? to test whether the objects are equal
|
148
|
-
#
|
149
|
-
#
|
219
|
+
#
|
220
|
+
# Can be used in either of the following ways:
|
221
|
+
# equal expected, actual
|
222
|
+
# equal :expected => expected, :actual => actual
|
150
223
|
def hash_key_equal(*args)
|
151
224
|
expected, actual, message = extract_args(args, :expected, :actual, :message)
|
152
225
|
|
@@ -158,11 +231,18 @@ module Test
|
|
158
231
|
end
|
159
232
|
end
|
160
233
|
true
|
234
|
+
|
235
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
236
|
+
::Kernel.raise
|
237
|
+
rescue Exception => e
|
238
|
+
failure "Could not compare %p with %p due to %s", expected, actual, e
|
161
239
|
end
|
162
240
|
|
163
241
|
# Uses == to test whether the objects are equal
|
164
|
-
#
|
165
|
-
#
|
242
|
+
#
|
243
|
+
# Can be used in either of the following ways:
|
244
|
+
# equal expected, actual
|
245
|
+
# equal :expected => expected, :actual => actual
|
166
246
|
def order_equal(*args)
|
167
247
|
expected, actual, message = extract_args(args, :expected, :actual, :message)
|
168
248
|
|
@@ -174,12 +254,19 @@ module Test
|
|
174
254
|
end
|
175
255
|
end
|
176
256
|
true
|
257
|
+
|
258
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
259
|
+
::Kernel.raise
|
260
|
+
rescue Exception => e
|
261
|
+
failure "Could not compare %p with %p due to %s", expected, actual, e
|
177
262
|
end
|
178
263
|
alias equal order_equal
|
179
264
|
|
180
265
|
# Uses === to test whether the objects are equal
|
181
|
-
#
|
182
|
-
#
|
266
|
+
#
|
267
|
+
# Can be used in either of the following ways:
|
268
|
+
# equal expected, actual
|
269
|
+
# equal :expected => expected, :actual => actual
|
183
270
|
def case_equal(*args)
|
184
271
|
expected, actual, message = extract_args(args, :expected, :actual, :message)
|
185
272
|
|
@@ -190,6 +277,11 @@ module Test
|
|
190
277
|
message, expected, actual
|
191
278
|
end
|
192
279
|
true
|
280
|
+
|
281
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
282
|
+
::Kernel.raise
|
283
|
+
rescue Exception => e
|
284
|
+
failure "Could not compare %p with %p due to %s", expected, actual, e
|
193
285
|
end
|
194
286
|
|
195
287
|
# To compare two collections (which must implement #each)
|
@@ -201,6 +293,7 @@ module Test
|
|
201
293
|
count = Hash.new(0)
|
202
294
|
expected.each { |element| count[element] += 1 }
|
203
295
|
actual.each { |element| count[element] -= 1 }
|
296
|
+
|
204
297
|
unless count.all? { |key, value| value.zero? } then
|
205
298
|
only_in_expected = count.select { |ele, n| n > 0 }.map { |ele, n| ele }
|
206
299
|
only_in_actual = count.select { |ele, n| n < 0 }.map { |ele, n| ele }
|
@@ -215,6 +308,11 @@ module Test
|
|
215
308
|
end
|
216
309
|
end
|
217
310
|
true
|
311
|
+
|
312
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
313
|
+
::Kernel.raise
|
314
|
+
rescue Exception => e
|
315
|
+
failure "Could not compare %p with %p due to %s", expected, actual, e
|
218
316
|
end
|
219
317
|
|
220
318
|
# Raises a Failure if the given object is not an instance of the given class
|
@@ -228,8 +326,14 @@ module Test
|
|
228
326
|
message, expected, actual, actual.class
|
229
327
|
end
|
230
328
|
true
|
329
|
+
|
330
|
+
rescue *::BareTest::Assertion::PassthroughExceptions
|
331
|
+
::Kernel.raise
|
332
|
+
rescue Exception => e
|
333
|
+
failure "Could not test whether %p is a child of %p due to %s", actual, expected, e
|
231
334
|
end
|
232
335
|
|
336
|
+
# A method to make raising failures that only optionally have a message easier.
|
233
337
|
def failure_with_optional_message(with_message, without_message, message, *args)
|
234
338
|
if message then
|
235
339
|
failure(with_message, message, *args)
|
@@ -238,13 +342,34 @@ module Test
|
|
238
342
|
end
|
239
343
|
end
|
240
344
|
|
241
|
-
# Raises Test::Assertion::Failure
|
345
|
+
# Raises Test::Assertion::Failure, which causes the Assertion to get the
|
346
|
+
# status :failure. Runs sprintf over message with *args
|
347
|
+
# Particularly useful with %p and %s.
|
348
|
+
def failure(message="Assertion failed", *args)
|
349
|
+
raise ::BareTest::Assertion::Failure, sprintf(message, *args)
|
350
|
+
end
|
351
|
+
|
352
|
+
# Raises Test::Assertion::Skip, which causes the Assertion to get the
|
353
|
+
# status :skipped. Runs sprintf over message with *args
|
242
354
|
# Particularly useful with %p and %s.
|
243
|
-
def
|
244
|
-
raise
|
355
|
+
def skip(message="Assertion was skipped", *args)
|
356
|
+
raise ::BareTest::Assertion::Skip, sprintf(message, *args)
|
245
357
|
end
|
246
358
|
|
247
359
|
private
|
360
|
+
# extract arg allows to use named or positional args
|
361
|
+
#
|
362
|
+
# Example:
|
363
|
+
# extract_args([1,2,3], :foo, :bar, :baz) # => [1,2,3]
|
364
|
+
# extract_args({:foo => 1,:bar => 2, :baz => 3}, :foo, :bar, :baz) # => [1,2,3]
|
365
|
+
#
|
366
|
+
# Usage:
|
367
|
+
# def foo(*args)
|
368
|
+
# x,y,z = extract_args(args, :x, :y, :z)
|
369
|
+
# end
|
370
|
+
# foo(1,2,3)
|
371
|
+
# foo(:x => 1, :y => 2, :z => 3) # equivalent to the one above
|
372
|
+
#
|
248
373
|
def extract_args(args, *named)
|
249
374
|
if args.size == 1 && Hash === args.first then
|
250
375
|
args.first.values_at(*named)
|
@@ -254,11 +379,21 @@ module Test
|
|
254
379
|
end
|
255
380
|
end # Support
|
256
381
|
|
257
|
-
|
382
|
+
class Context
|
383
|
+
include ::BareTest::Assertion::Support
|
384
|
+
end
|
258
385
|
end # Assertion
|
259
|
-
end #
|
386
|
+
end # BareTest
|
260
387
|
|
261
388
|
module Enumerable
|
389
|
+
|
390
|
+
# Part of BareTest - require 'baretest/assertion/support'
|
391
|
+
#
|
392
|
+
# Returns true if all elements of self occur the same amount of times in other, regardless
|
393
|
+
# of order. Uses +eql?+ to determine equality.
|
394
|
+
#
|
395
|
+
# Example:
|
396
|
+
# [2,1,3,2].equal_unordered?([3,2,2,1]) # => true
|
262
397
|
def equal_unordered?(other)
|
263
398
|
count = Hash.new(0)
|
264
399
|
other.each { |element| count[element] += 1 }
|
@@ -0,0 +1,182 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2009 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'baretest/assertion/context'
|
10
|
+
require 'baretest/assertion/failure'
|
11
|
+
require 'baretest/assertion/skip'
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
module BareTest
|
16
|
+
|
17
|
+
# Defines an assertion
|
18
|
+
# An assertion belongs to a suite and consists of a description and a block.
|
19
|
+
# To verify the assertion, the suite's (and its ancestors) setup blocks are
|
20
|
+
# executed, then the assertions block is executed and after that, the suite's
|
21
|
+
# (and ancestors) teardown blocks are invoked.
|
22
|
+
#
|
23
|
+
# An assertion has 5 possible states, see Assertion#status for a list of them.
|
24
|
+
#
|
25
|
+
# There are various helper methods in BareTest::Assertion::Support which help you
|
26
|
+
# defining nicer diagnostics or just easier ways to test common scenarios.
|
27
|
+
# The following are test helpers:
|
28
|
+
# * Kernel#raises(exception_class=StandardError)
|
29
|
+
# * Kernel#within_delta(a, b, delta)
|
30
|
+
# * Kernel#equal_unordered(a,b)
|
31
|
+
# * Enumerable#equal_unordered(other)
|
32
|
+
class Assertion
|
33
|
+
|
34
|
+
# The exceptions baretest will not rescue (NoMemoryError, SignalException, Interrupt
|
35
|
+
# and SystemExit)
|
36
|
+
PassthroughExceptions = [NoMemoryError, SignalException, Interrupt, SystemExit]
|
37
|
+
|
38
|
+
# An assertion has 5 possible states:
|
39
|
+
# :success:: The assertion passed. This means the block returned a trueish value.
|
40
|
+
# :failure:: The assertion failed. This means the block returned a falsish value.
|
41
|
+
# Alternatively it raised a Test::Failure (NOT YET IMPLEMENTED).
|
42
|
+
# The latter has the advantage that it can provide nicer diagnostics.
|
43
|
+
# :pending:: No block given to the assertion to be run
|
44
|
+
# :skipped:: If one of the parent suites is missing a dependency, its assertions
|
45
|
+
# will be skipped
|
46
|
+
# :error:: The assertion errored out. This means the block raised an exception
|
47
|
+
attr_reader :status
|
48
|
+
|
49
|
+
# If an exception occured in Assertion#execute, this will contain the
|
50
|
+
# Exception object raised.
|
51
|
+
attr_reader :exception
|
52
|
+
|
53
|
+
# The description of this assertion.
|
54
|
+
attr_reader :description
|
55
|
+
|
56
|
+
# The failure/error/skipping/pending reason.
|
57
|
+
attr_reader :reason
|
58
|
+
|
59
|
+
# The suite this assertion belongs to
|
60
|
+
attr_reader :suite
|
61
|
+
|
62
|
+
# The Context-instance the assertions setup, assert and teardown are run
|
63
|
+
attr_reader :context
|
64
|
+
|
65
|
+
# The Setup instances whose #block is to be executed before this assertion
|
66
|
+
# is ran
|
67
|
+
attr_accessor :setups
|
68
|
+
|
69
|
+
# The block specifying the assertion
|
70
|
+
attr_reader :block
|
71
|
+
|
72
|
+
# The file this assertion is specified in. Not contructed by Assertion itself.
|
73
|
+
attr_accessor :code
|
74
|
+
|
75
|
+
# The file this assertion is specified in. Not contructed by Assertion itself.
|
76
|
+
attr_accessor :file
|
77
|
+
|
78
|
+
# The line this assertion is specified on. Not contructed by Assertion itself.
|
79
|
+
attr_accessor :line
|
80
|
+
|
81
|
+
# The lines this assertion spans. Not contructed by Assertion itself.
|
82
|
+
attr_accessor :lines
|
83
|
+
|
84
|
+
# suite:: The suite the Assertion belongs to
|
85
|
+
# description:: A descriptive string about what this Assertion tests.
|
86
|
+
# &block:: The block definition. Without one, the Assertion will have a
|
87
|
+
# :pending status.
|
88
|
+
def initialize(suite, description, &block)
|
89
|
+
@suite = suite
|
90
|
+
@description = (description || "No description given")
|
91
|
+
@setups = nil
|
92
|
+
@block = block
|
93
|
+
reset
|
94
|
+
end
|
95
|
+
|
96
|
+
def reset
|
97
|
+
@status = nil
|
98
|
+
@reason = nil
|
99
|
+
@exception = nil
|
100
|
+
@context = ::BareTest::Assertion::Context.new(self)
|
101
|
+
end
|
102
|
+
|
103
|
+
def interpolated_description
|
104
|
+
setups = @setups ? @setups.select { |s| s.component } : []
|
105
|
+
if setups.empty? then
|
106
|
+
@description
|
107
|
+
else
|
108
|
+
substitutes = {}
|
109
|
+
setups.each do |setup| substitutes[setup.component] = setup.substitute end
|
110
|
+
@description.gsub(/:(?:#{substitutes.keys.join('|')})\b/) { |m|
|
111
|
+
substitutes[m[1..-1].to_sym]
|
112
|
+
}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Run all setups in the order of their nesting (outermost first, innermost last)
|
117
|
+
def setup
|
118
|
+
@setups ||= @suite ? @suite.first_component_variant : []
|
119
|
+
@setups.each do |setup| @context.instance_exec(setup.value, &setup.block) end
|
120
|
+
true
|
121
|
+
rescue *PassthroughExceptions
|
122
|
+
raise # pass through exceptions must be passed through
|
123
|
+
rescue Exception => exception
|
124
|
+
@reason = "An error occurred during setup"
|
125
|
+
@exception = exception
|
126
|
+
@status = :error
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
# Run all teardowns in the order of their nesting (innermost first, outermost last)
|
131
|
+
def teardown
|
132
|
+
@suite.ancestry_teardown.each do |teardown|
|
133
|
+
@context.instance_eval(&teardown)
|
134
|
+
end if @suite
|
135
|
+
rescue *PassthroughExceptions
|
136
|
+
raise # pass through exceptions must be passed through
|
137
|
+
rescue Exception => exception
|
138
|
+
@reason = "An error occurred during setup"
|
139
|
+
@exception = exception
|
140
|
+
@status = :error
|
141
|
+
end
|
142
|
+
|
143
|
+
# Runs the assertion and sets the status and exception
|
144
|
+
def execute(setups=nil)
|
145
|
+
@setups = setups if setups
|
146
|
+
@exception = nil
|
147
|
+
if @block then
|
148
|
+
if setup() then
|
149
|
+
# run the assertion
|
150
|
+
begin
|
151
|
+
@status = @context.instance_eval(&@block) ? :success : :failure
|
152
|
+
@reason = "Assertion failed" if @status == :failure
|
153
|
+
rescue *PassthroughExceptions
|
154
|
+
raise # pass through exceptions must be passed through
|
155
|
+
rescue ::BareTest::Assertion::Failure => failure
|
156
|
+
@status = :failure
|
157
|
+
@reason = failure.message
|
158
|
+
rescue ::BareTest::Assertion::Skip => skip
|
159
|
+
@status = :skipped
|
160
|
+
@reason = skip.message
|
161
|
+
rescue Exception => exception
|
162
|
+
@reason = "An error occurred during execution"
|
163
|
+
@exception = exception
|
164
|
+
@status = :error
|
165
|
+
end
|
166
|
+
end
|
167
|
+
teardown
|
168
|
+
else
|
169
|
+
@status = :pending
|
170
|
+
end
|
171
|
+
self
|
172
|
+
end
|
173
|
+
|
174
|
+
def to_s # :nodoc:
|
175
|
+
sprintf "%s %s", self.class, @description
|
176
|
+
end
|
177
|
+
|
178
|
+
def inspect # :nodoc:
|
179
|
+
sprintf "#<%s:%08x suite=%p %p>", self.class, object_id>>1, @suite, @description
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|