baretest 0.1.0 → 0.2.3
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/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
|