baretest 0.1.0 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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