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.
Files changed (69) hide show
  1. data/LICENSE.txt +52 -0
  2. data/MANIFEST.txt +50 -31
  3. data/README.rdoc +260 -0
  4. data/bin/baretest +82 -24
  5. data/doc/baretest.rdoc +98 -0
  6. data/doc/mocking_stubbing_test_doubles.rdoc +5 -0
  7. data/doc/quickref.rdoc +261 -0
  8. data/doc/writing_tests.rdoc +148 -0
  9. data/examples/test.rake +58 -30
  10. data/examples/tests/irb_mode/failures.rb +26 -0
  11. data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
  12. data/examples/tests/mock_developer/test/setup.rb +57 -0
  13. data/examples/tests/mock_developer/test/suite/mock_demo.rb +19 -0
  14. data/examples/tests/overview/test.rb +89 -0
  15. data/examples/tests/variations/variations_01.rb +14 -0
  16. data/examples/tests/variations/variations_02.rb +19 -0
  17. data/examples/tests/variations/variations_03.rb +19 -0
  18. data/lib/baretest/assertion/context.rb +20 -0
  19. data/lib/baretest/assertion/failure.rb +22 -0
  20. data/lib/baretest/assertion/skip.rb +21 -0
  21. data/lib/{test → baretest}/assertion/support.rb +174 -39
  22. data/lib/baretest/assertion.rb +182 -0
  23. data/lib/baretest/irb_mode.rb +263 -0
  24. data/lib/{test/assertion/failure.rb → baretest/layout.rb} +6 -5
  25. data/lib/baretest/mocha.rb +18 -0
  26. data/lib/baretest/run/cli.rb +104 -0
  27. data/lib/{test → baretest}/run/errors.rb +12 -7
  28. data/lib/{test → baretest}/run/minimal.rb +8 -3
  29. data/lib/baretest/run/profile.rb +151 -0
  30. data/lib/{test → baretest}/run/spec.rb +10 -4
  31. data/lib/baretest/run/tap.rb +44 -0
  32. data/lib/baretest/run/xml.rb +80 -0
  33. data/lib/{test → baretest}/run.rb +31 -18
  34. data/lib/baretest/setup.rb +15 -0
  35. data/lib/baretest/skipped/assertion.rb +20 -0
  36. data/lib/baretest/skipped/suite.rb +49 -0
  37. data/lib/baretest/skipped.rb +15 -0
  38. data/lib/baretest/suite.rb +234 -0
  39. data/lib/baretest/utilities.rb +43 -0
  40. data/lib/{test → baretest}/version.rb +12 -3
  41. data/lib/baretest.rb +112 -0
  42. data/test/external/bootstraptest.rb +1 -1
  43. data/test/setup.rb +1 -1
  44. data/test/{lib/test → suite/lib/baretest}/assertion/support.rb +78 -24
  45. data/test/suite/lib/baretest/assertion.rb +192 -0
  46. data/test/{lib/test → suite/lib/baretest}/irb_mode.rb +0 -0
  47. data/test/{lib/test → suite/lib/baretest}/run/cli.rb +0 -0
  48. data/test/{lib/test → suite/lib/baretest}/run/errors.rb +0 -0
  49. data/test/{lib/test → suite/lib/baretest}/run/interactive.rb +0 -0
  50. data/test/{lib/test → suite/lib/baretest}/run/spec.rb +0 -0
  51. data/test/{lib/test → suite/lib/baretest}/run/tap.rb +0 -0
  52. data/test/{lib/test → suite/lib/baretest}/run/xml.rb +0 -0
  53. data/test/{lib/test → suite/lib/baretest}/run.rb +63 -61
  54. data/test/{lib/test → suite/lib/baretest}/suite.rb +77 -54
  55. data/test/{lib/test.rb → suite/lib/baretest.rb} +37 -37
  56. metadata +61 -40
  57. data/README.markdown +0 -229
  58. data/examples/test.rb +0 -93
  59. data/lib/test/assertion.rb +0 -117
  60. data/lib/test/debug.rb +0 -34
  61. data/lib/test/irb_mode.rb +0 -104
  62. data/lib/test/run/cli.rb +0 -79
  63. data/lib/test/run/interactive.rb +0 -60
  64. data/lib/test/run/tap.rb +0 -32
  65. data/lib/test/run/xml.rb +0 -56
  66. data/lib/test/suite.rb +0 -95
  67. data/lib/test.rb +0 -118
  68. data/test/lib/test/assertion.rb +0 -142
  69. 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 'test/assertion/failure'
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 Test
17
+ module BareTest
17
18
  @touch = {}
19
+
18
20
  # We don't want to litter in Assertion
19
- # Touches are associated with
20
- def self.touch(assertion, thing=nil)
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
- def self.touched(assertion, thing=nil)
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
- def self.clean_touches(assertion)
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
- def self.extended(run_obj)
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
- Test.clean_touches(self) # instance evaled, self is the assertion
55
+ ::BareTest.clean_touches(self) # instance evaled, self is the assertion
43
56
  end
44
57
  end
45
58
  end
46
59
 
47
- Test.extender << self
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
- begin
62
- yield
63
- rescue exception_class => exception
64
- if opts[:with_message] && !(opts[:with_message] === exception.message) then
65
- failure "Expected block to raise with the message %p, but the message was %p",
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
- failure "Expected block to raise #{exception_class}, but nothing was raised."
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 => exception
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
- ::Test.touch(self, thing)
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 = ::Test.touched(self, thing)
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
- # same expected, actual
133
- # same :expected => expected, :actual => actual
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
- # equal expected, actual
149
- # equal :expected => expected, :actual => actual
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
- # equal expected, actual
165
- # equal :expected => expected, :actual => actual
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
- # equal expected, actual
182
- # equal :expected => expected, :actual => actual
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 and runs sprintf over message with *args
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 failure(message, *args)
244
- raise Test::Assertion::Failure, sprintf(message, *args)
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
- include Support
382
+ class Context
383
+ include ::BareTest::Assertion::Support
384
+ end
258
385
  end # Assertion
259
- end # Test
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