baretest 0.2.4 → 0.4.0.pre1

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 (85) hide show
  1. data/LICENSE.txt +6 -6
  2. data/MANIFEST.txt +40 -18
  3. data/README.rdoc +8 -1
  4. data/bin/baretest +126 -118
  5. data/doc/baretest.rdoc +1 -1
  6. data/doc/mocking_stubbing_test_doubles.rdoc +31 -3
  7. data/doc/news/news-0.3.0.rdoc +7 -0
  8. data/doc/quickref.rdoc +74 -28
  9. data/doc/whats_going_on.rdoc +5 -0
  10. data/doc/writing_tests.rdoc +25 -13
  11. data/examples/components/rack-test.rb +17 -0
  12. data/examples/{tests/irb_mode → irb_mode}/failures.rb +0 -0
  13. data/examples/rake/test.rake +40 -0
  14. data/examples/tests/01_basics_I.rb +34 -0
  15. data/examples/tests/02_basics_II_helpers.rb +25 -0
  16. data/examples/tests/03_basics_III_setup_and_teardown.rb +53 -0
  17. data/examples/tests/04_advanced_I_dependencies.rb +31 -0
  18. data/examples/tests/05_advanced_II_tags.rb +12 -0
  19. data/examples/tests/06_advanced_III_requires.rb +21 -0
  20. data/examples/tests/07_advanced_IV_components.rb +48 -0
  21. data/examples/tests/08_expert_I_setup_variants.rb +46 -0
  22. data/lib/baretest.rb +142 -21
  23. data/lib/baretest/assertion.rb +83 -92
  24. data/lib/baretest/assertion/context.rb +9 -0
  25. data/lib/baretest/assertion/support.rb +88 -61
  26. data/lib/baretest/commandline.rb +268 -0
  27. data/lib/baretest/formatter.rb +58 -0
  28. data/lib/baretest/invalidselectors.rb +24 -0
  29. data/lib/baretest/irb_mode.rb +100 -58
  30. data/lib/baretest/persistence.rb +94 -0
  31. data/lib/baretest/run.rb +138 -37
  32. data/lib/baretest/run/cli.rb +97 -43
  33. data/lib/baretest/run/minimal.rb +2 -1
  34. data/lib/baretest/run/none.rb +21 -0
  35. data/lib/baretest/run/xml.rb +21 -19
  36. data/lib/baretest/setup.rb +2 -0
  37. data/lib/baretest/status.rb +93 -0
  38. data/lib/baretest/suite.rb +185 -59
  39. data/lib/baretest/uid.rb +51 -0
  40. data/lib/baretest/use/mocha.rb +24 -0
  41. data/lib/baretest/use/rack_test.rb +9 -0
  42. data/lib/baretest/use/rr.rb +17 -0
  43. data/lib/baretest/version.rb +18 -4
  44. data/lib/command.rb +36 -0
  45. data/lib/command/argument.rb +11 -0
  46. data/lib/command/decoratinghash.rb +31 -0
  47. data/lib/command/definition.rb +294 -0
  48. data/lib/command/directorynotfounderror.rb +11 -0
  49. data/lib/command/env.rb +11 -0
  50. data/lib/command/filenotfounderror.rb +11 -0
  51. data/lib/command/kernel.rb +14 -0
  52. data/lib/command/nodirectoryerror.rb +11 -0
  53. data/lib/command/nofileerror.rb +11 -0
  54. data/lib/command/option.rb +16 -0
  55. data/lib/command/parser.rb +145 -0
  56. data/lib/command/result.rb +11 -0
  57. data/lib/command/types.rb +33 -0
  58. data/lib/command/version.rb +28 -0
  59. data/test/setup.rb +3 -0
  60. data/test/suite/lib/baretest.rb +0 -178
  61. data/test/suite/lib/baretest/assertion.rb +133 -112
  62. data/test/suite/lib/baretest/assertion/context.rb +40 -0
  63. data/test/suite/lib/baretest/assertion/failure.rb +19 -0
  64. data/test/suite/lib/baretest/assertion/skip.rb +19 -0
  65. data/test/suite/lib/baretest/assertion/support.rb +366 -84
  66. data/test/suite/lib/baretest/run.rb +114 -15
  67. data/test/suite/lib/baretest/suite.rb +70 -29
  68. metadata +46 -24
  69. data/examples/test.rake +0 -65
  70. data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
  71. data/examples/tests/mock_developer/test/setup.rb +0 -57
  72. data/examples/tests/mock_developer/test/suite/mock_demo.rb +0 -19
  73. data/examples/tests/overview/test.rb +0 -89
  74. data/examples/tests/variations/variations_01.rb +0 -14
  75. data/examples/tests/variations/variations_02.rb +0 -19
  76. data/examples/tests/variations/variations_03.rb +0 -19
  77. data/lib/baretest/mocha.rb +0 -18
  78. data/lib/baretest/rr.rb +0 -16
  79. data/lib/baretest/run/errors.rb +0 -49
  80. data/lib/baretest/skipped.rb +0 -15
  81. data/lib/baretest/skipped/assertion.rb +0 -20
  82. data/lib/baretest/skipped/suite.rb +0 -49
  83. data/test/external/bootstraptest.rb +0 -5
  84. data/test/external/bootstrapwrap.rb +0 -2
  85. data/test/helper/mocks.rb +0 -0
@@ -0,0 +1,21 @@
1
+ # pretend the lib 'baretest/demo/06_advanced_requires' was already loaded
2
+ $LOADED_FEATURES << 'baretest/demo/06_advanced_requires'
3
+
4
+
5
+ # You can baretest tell that a suite depends on an external lib using the
6
+ # :requires option, it accepts either a String or an Array of strings.
7
+ BareTest.suite do
8
+ # Baretest will load all libraries mentioned in :requires via a standard
9
+ # Kernel.require upon suite definition
10
+ suite "Depends on an existing lib", :requires => 'baretest/demo/06_advanced_requires' do
11
+ assert "Succeeds because library-dependency is met" do
12
+ true
13
+ end
14
+ end
15
+
16
+ suite "Depends on a missing lib", :requires => 'baretest/demo/06_advanced_requires_missing' do
17
+ assert "Skipped because library-dependency is NOT met" do
18
+ true
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,48 @@
1
+ # This code should be in 'baretest/use/demo_component', somewhere in rubys
2
+ # $LOAD_PATH.
3
+ module DemoComponent
4
+ module DemoMethods
5
+ def demo
6
+ demo_component = @demo_component
7
+ @demo_component = :executed
8
+ same(:setup, demo_component)
9
+ end
10
+ end
11
+ end
12
+
13
+ BareTest.new_component :demo_component do
14
+ # Make our components' assertion helpers available in assertions
15
+ BareTest::Assertion::Context.send :include, DemoComponent::DemoMethods
16
+
17
+ setup do
18
+ @demo_component = :setup
19
+ end
20
+
21
+ teardown do
22
+ same(:executed, @demo_component, "@demo_component after the assertion")
23
+ end
24
+ end
25
+
26
+
27
+ BareTest.suite do
28
+ suite "Using DemoComponent", :use => :demo_component do
29
+ assert "Successful assertions must use the 'demo' method" do
30
+ demo
31
+ end
32
+
33
+ assert "Fails if 'demo' is not invoked, even if otherwise successful" do
34
+ true
35
+ end
36
+
37
+ assert "Fails if @demo_component was changed prior to calling 'demo'" do
38
+ @demo_component = :unexpected
39
+ demo
40
+ end
41
+
42
+ assert "Fails if @demo_component was changed after to calling 'demo'" do
43
+ demo
44
+ @demo_component = :unexpected
45
+ true
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,46 @@
1
+ # The thing we want to test
2
+ class String
3
+ def numeric?
4
+ self =~ /[+-]?(?:[1-9]\d*|0)(?:\.\d+)?(?:[eE][+-]?\d+)?/
5
+ end
6
+ end
7
+
8
+ BareTest.suite do
9
+ suite "Variations - Notation I" do
10
+ setup :number, '123' do |number|
11
+ @number = '123'
12
+ end
13
+
14
+ setup :number, '-123' do |number|
15
+ @number = '-123'
16
+ end
17
+
18
+ setup :number, '1.23' do |number|
19
+ @number = '1.23'
20
+ end
21
+
22
+ assert ":number should be a numeric" do
23
+ @number.numeric?
24
+ end
25
+ end
26
+
27
+ suite "Variations - Notation II" do
28
+ setup :number, %w[123 -123 1.23 -1.23 1e3 -1e3 1e-3 -1e-3] do |number|
29
+ @number = number
30
+ end
31
+
32
+ assert ":number should be a numeric" do
33
+ @number.numeric?
34
+ end
35
+ end
36
+
37
+ suite "Variations - Notation III" do
38
+ setup :number, {'"123"' => "123", '"1.23"' => "1.23", '"1e3"' => "1e3"} do |number|
39
+ @number = number
40
+ end
41
+
42
+ assert ":number should be a numeric" do
43
+ @number.numeric?
44
+ end
45
+ end
46
+ end
data/lib/baretest.rb CHANGED
@@ -7,6 +7,9 @@
7
7
 
8
8
 
9
9
  require 'baretest/assertion'
10
+ require 'baretest/commandline'
11
+ require 'baretest/formatter'
12
+ require 'baretest/invalidselectors'
10
13
  require 'baretest/irb_mode'
11
14
  require 'baretest/run'
12
15
  require 'baretest/suite'
@@ -17,7 +20,45 @@ require 'ruby/kernel'
17
20
 
18
21
 
19
22
  module BareTest
23
+ # A lookup table to test which of two states is more important
24
+ # (MoreImportantStatus[[a,b]] # => a or b)
25
+ MoreImportantStatus = {}
26
+
27
+ # All states in the order of relevance, more relevant states first
28
+ StatusOrder = :error,
29
+ :failure,
30
+ :pending,
31
+ :manually_skipped,
32
+ :dependency_missing,
33
+ :library_missing,
34
+ :component_missing,
35
+ :ignored,
36
+ :success
37
+
38
+ StatusOrder.combination(2) do |x,y|
39
+ more_important = StatusOrder.index(x) < StatusOrder.index(y) ? x : y
40
+ MoreImportantStatus[[x,y]] = more_important
41
+ MoreImportantStatus[[y,x]] = more_important
42
+ end
43
+ StatusOrder.each do |status|
44
+ MoreImportantStatus[[status,status]] = status
45
+ MoreImportantStatus[[nil,status]] = status
46
+ MoreImportantStatus[[status,nil]] = status
47
+ end
48
+
49
+ # The standard glob used by baretest to load test files
50
+ # :nodoc:
51
+ DefaultInitialPositiveGlob = 'test/{suite,unit,isolation,integration,system}/**/*.rb'
52
+
53
+ # Selectors that are valid to be passed into process_selectors
54
+ # :nodoc:
55
+ ValidStateSelectors = [:new, :success, :failure, :error, :skipped, :pending]
56
+
20
57
  class << self
58
+ # A hash of components - available via BareTest::use(name) and
59
+ # Suite#suite :use => name
60
+ attr_reader :components
61
+
21
62
  # A hash of formatters (require-string => module) to be used with Test::Run.
22
63
  attr_reader :format
23
64
 
@@ -33,6 +74,21 @@ module BareTest
33
74
  attr_reader :required_file # :nodoc:
34
75
  end
35
76
 
77
+ # Enure that the suite is run wiht a minimal version of baretest
78
+ def self.require_baretest(version)
79
+ if (version.split(".").map { |s| s.to_i } <=> BareTest::VERSION.to_a) == 0 then
80
+ abort "Requires baretest version #{version}, you have #{BareTest::VERSION}"
81
+ end
82
+ end
83
+
84
+ # Ensure that the suite is run with a minimal version of ruby
85
+ def self.require_ruby(version)
86
+ if (version.split(".").map { |s| s.to_i } <=> RUBY_VERSION.split(".").map { |s| s.to_i }) == 1 then
87
+ abort "Requires ruby version #{version}, you have #{RUBY_VERSION}"
88
+ end
89
+ end
90
+
91
+
36
92
  # Loads all files in a test directory in order to load the suites and
37
93
  # assertions. Used by the 'baretest' executable and the standard rake task.
38
94
  #
@@ -44,16 +100,20 @@ module BareTest
44
100
  def self.load_standard_test_files(opts={})
45
101
  verbose = opts.delete(:verbose)
46
102
  setup_path = opts.delete(:setup_path) || 'test/setup.rb'
103
+ lib_path = opts.delete(:lib_path) || 'test/lib'
47
104
  chdir = opts.delete(:chdir) || '.'
48
- files = opts.delete(:files) || ['test/{suite,unit,integration,system}/**/*.rb']
105
+ files = opts.delete(:files)
106
+ files = [DefaultInitialPositiveGlob] if (files.nil? || files.empty?)
49
107
  Dir.chdir(chdir) do
108
+ $LOAD_PATH.unshift(File.expand_path(lib_path)) if File.exist?(lib_path)
50
109
  load(setup_path) if File.exist?(setup_path)
51
110
  files.each do |glob|
52
111
  glob = "#{glob}/**/*.rb" if File.directory?(glob)
53
112
  Dir.glob(glob) { |path|
54
113
  helper_path = path.sub(%r{^test/(suite|unit|integration|system)/}, 'test/helper/\1/')
55
- puts(File.exist?(helper_path) ? "Loading helper file #{helper_path}" : "No helper file #{helper_path} to load") if verbose
56
- load(helper_path) if File.exist?(helper_path)
114
+ exists = (helper_path != path && File.exist?(helper_path))
115
+ puts(exists ? "Loading helper file #{helper_path}" : "No helper file #{helper_path} to load") if verbose
116
+ load(helper_path) if exists
57
117
  puts "Loading test file #{path}" if verbose
58
118
  load(path)
59
119
  }
@@ -61,10 +121,70 @@ module BareTest
61
121
  end
62
122
  end
63
123
 
124
+ # Determine which of the named states is the most important one (see
125
+ # StatusOrder)
126
+ def self.most_important_status(states)
127
+ (StatusOrder & states).first # requires Array#& to be stable (keep order of first operand)
128
+ end
129
+
130
+ # Convert an array of selectors into a hash with those selectors preprocessed
131
+ # as far as possible.
132
+ # Example:
133
+ # BareTest.process_selectors %w[-some/**/glob/*.rb %failure :tag1 -:tag2]
134
+ # # => {
135
+ # # :files => ...an array with paths...,
136
+ # # :include_tags => [:tag1],
137
+ # # :exclude_tags => [:tag2],
138
+ # # :include_states => [:failure]
139
+ # # :exclude_states => nil,
140
+ # # }
141
+ def self.process_selectors(selectors, base_directory=".", default_initial_positive_glob=nil)
142
+ files = []
143
+ include_tags = []
144
+ exclude_tags = []
145
+ include_states = []
146
+ exclude_states = []
147
+
148
+ default_initial_positive_glob ||= DefaultInitialPositiveGlob
149
+ Dir.chdir(base_directory) do
150
+ selectors.each do |selector|
151
+ case selector
152
+ when /\A-%(.*)/ then exclude_states << $1.to_sym
153
+ when /\A-:(.*)/ then exclude_tags << $1.to_sym
154
+ when /\A\+?%(.*)/ then include_states << $1.to_sym
155
+ when /\A\+?:(.*)/ then include_tags << $1.to_sym
156
+ when /\A-(.*)/ then
157
+ files = Dir[default_initial_positive_glob] if files.empty? && default_initial_positive_glob
158
+ glob = File.directory?($1) ? "#{$1}/**/*.rb" : $1
159
+ files -= Dir[glob]
160
+ when /\A\+?(.*)/ then
161
+ glob = File.directory?(selector) ? "#{selector}/**/*.rb" : selector
162
+ files |= Dir[glob]
163
+ else
164
+ raise "Should never reach else - selector: #{selector.inspect}"
165
+ end
166
+ end
167
+ files = Dir[default_initial_positive_glob] if files.empty? && default_initial_positive_glob
168
+ files.map! do |path| File.expand_path(path) end
169
+ end
170
+
171
+ invalid_states = (include_states|exclude_states)-ValidStateSelectors
172
+ raise InvalidSelectors.new(invalid_states) unless invalid_states.empty?
173
+
174
+ return {
175
+ :files => files,
176
+ :include_tags => include_tags,
177
+ :exclude_tags => exclude_tags,
178
+ :include_states => include_states.empty? ? nil : include_states,
179
+ :exclude_states => exclude_states.empty? ? nil : exclude_states
180
+ }
181
+ end
182
+
64
183
  # Initializes BareTest, is automatically called
65
184
  #
66
185
  # Needed for bootstrapped selftest
67
186
  def self.init # :nodoc:
187
+ @components = {}
68
188
  @format = {}
69
189
  @extender = []
70
190
  @toplevel_suite = BareTest::Suite.new
@@ -74,6 +194,17 @@ module BareTest
74
194
  end
75
195
  init
76
196
 
197
+ def self.component(name)
198
+ component = @components[name]
199
+ begin
200
+ require "baretest/use/#{name}"
201
+ rescue LoadError
202
+ else
203
+ component = @components[name]
204
+ end
205
+ component
206
+ end
207
+
77
208
  # If no description was given, it adds the contained assertions and suites to the toplevel suite,
78
209
  # if a description was given, a suite with the given description is created, added to the toplevel
79
210
  # suite, and all the contained assertions and suites are added to the created suite.
@@ -87,26 +218,16 @@ module BareTest
87
218
  end
88
219
  end
89
220
 
90
- # Creates a Test::Run instance, adds the assertions and suites defined in its
91
- # own block to that Test::Run instance's toplevel suite and if $PROGRAM_NAME
92
- # (aka $0) is equal to \_\_FILE__ (means the current file is the file directly
93
- # executed by ruby, and not just required/loaded/evaled by another file),
94
- # subsequently also runs that suite.
95
- def self.run_if_mainfile(description=nil, opts={}, &block)
96
- suite(description, opts, &block)
97
- if caller.first[/^[^:]*/] == $0 then # if is mainfile
98
- run(:format => ENV['FORMAT'], :interactive => ENV['INTERACTIVE'])
99
- end
221
+ # Create a new component for Suite's :use option (see BareTest::Suite::new)
222
+ def self.new_component(name, &block)
223
+ name = name.to_sym
224
+ raise ArgumentError, "Component named #{name.inspect} already exists" if @components.has_key?(name)
225
+ @components[name] = block
100
226
  end
101
227
 
102
- # Runs the toplevel suite (which usually contains all suites and assertions
103
- # defined in all loaded test files).
104
- #
105
- # Returns the Run instance.
106
- def self.run(opts=nil)
107
- runner = BareTest::Run.new(@toplevel_suite, opts)
108
- runner.run_all
109
- runner
228
+ # Shortcut for toplevel_suite.use. Preferably use the :use option instead.
229
+ def self.use(component)
230
+ @toplevel_suite.use(component)
110
231
  end
111
232
  end
112
233
 
@@ -9,6 +9,7 @@
9
9
  require 'baretest/assertion/context'
10
10
  require 'baretest/assertion/failure'
11
11
  require 'baretest/assertion/skip'
12
+ require 'baretest/status'
12
13
 
13
14
 
14
15
 
@@ -30,42 +31,16 @@ module BareTest
30
31
  # * Kernel#equal_unordered(a,b)
31
32
  # * Enumerable#equal_unordered(other)
32
33
  class Assertion
33
-
34
34
  # The exceptions baretest will not rescue (NoMemoryError, SignalException, Interrupt
35
35
  # and SystemExit)
36
36
  PassthroughExceptions = [NoMemoryError, SignalException, Interrupt, SystemExit]
37
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
38
  # The description of this assertion.
54
39
  attr_reader :description
55
40
 
56
- # The failure/error/skipping/pending reason.
57
- attr_reader :reason
58
-
59
41
  # The suite this assertion belongs to
60
42
  attr_reader :suite
61
43
 
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
44
  # The block specifying the assertion
70
45
  attr_reader :block
71
46
 
@@ -85,90 +60,106 @@ module BareTest
85
60
  # description:: A descriptive string about what this Assertion tests.
86
61
  # &block:: The block definition. Without one, the Assertion will have a
87
62
  # :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
63
+ def initialize(suite, description, opt=nil, &block)
64
+ @suite = suite
65
+ @description = (description || "No description given")
66
+ @block = block
67
+ @skipped = false
68
+ if opt then
69
+ skip_reason = opt[:skip]
70
+ skip(skip_reason == true ? "Tagged as skipped" : skip_reason) if skip_reason
71
+ end
72
+ end
73
+
74
+ # An ID, usable for persistence
75
+ def id
76
+ @id ||= [
77
+ @description,
78
+ *(@suite && @suite.ancestors.map { |suite| suite.description })
79
+ ].compact.join("\f")
94
80
  end
95
81
 
96
- def reset
97
- @status = nil
98
- @reason = nil
99
- @exception = nil
100
- @context = ::BareTest::Assertion::Context.new(self)
82
+ # Returns whether this assertion has been marked as manually skipped.
83
+ def skipped?
84
+ !!@skipped
101
85
  end
102
86
 
103
- def interpolated_description
104
- setups = @setups ? @setups.select { |s| s.component } : []
105
- if setups.empty? then
87
+ # Marks this assertion as manually skipped.
88
+ def skip(reason=nil)
89
+ @skipped ||= []
90
+ @skipped |= reason ? Array(reason) : ['Manually skipped']
91
+ end
92
+
93
+ # The description allows substitutes in the form ":identifier" and
94
+ # ":{identifier}" (the latter in case of ajanced characters that don't
95
+ # belong to the identifier, like ":{identifier}stuff").
96
+ # This method will interploate those substitutes.
97
+ # This is relevant with regards to setup variants.
98
+ def interpolated_description(substitutes)
99
+ if substitutes.empty? then
106
100
  @description
107
101
  else
108
- substitutes = {}
109
- setups.each do |setup| substitutes[setup.component] = setup.substitute end
110
102
  @description.gsub(/:(?:#{substitutes.keys.join('|')})\b/) { |m|
111
103
  substitutes[m[1..-1].to_sym]
112
104
  }
113
105
  end
114
106
  end
115
107
 
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
108
+ # Returns a Status
109
+ # Executes with_setup, then the assertions defining block, and in the end
110
+ # and_teardown. Usually with_setup and and_teardown are supplied by the
111
+ # containing suite.
112
+ def execute(with_setup=nil, and_teardown=nil)
113
+ if @skipped then
114
+ status = Status.new(self, :manually_skipped)
115
+ elsif !@block
116
+ status = Status.new(self, :pending)
117
+ else
118
+ context = ::BareTest::Assertion::Context.new(self)
119
+ status = execute_phase(:setup, context, with_setup) if with_setup
120
+ status = execute_phase(:exercise, context, @block) unless status
121
+ status = execute_phase(:teardown, context, and_teardown) unless (status || !and_teardown)
122
+ status ||= Status.new(self, :success, context)
123
+ end
129
124
 
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
125
+ status
141
126
  end
142
127
 
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
128
+ # A phase can result in either success, skip, failure or error
129
+ # Execute_phase will simply return nil upon success, all other cases
130
+ # will generate a full Status instance.
131
+ # This is for practical reasons - it means you can go through several
132
+ # phases, looking for the first non-nil one.
133
+ def execute_phase(name, context, code)
134
+ status = nil
135
+ skip_reason = nil
136
+ failure_reason = nil
137
+ exception = nil
138
+
139
+ begin
140
+ if code.is_a?(Array) then
141
+ code.each do |block| context.instance_eval(&block) end
142
+ else
143
+ unless context.instance_eval(&code)
144
+ failure_reason = "Assertion failed"
145
+ status = :failure
165
146
  end
166
147
  end
167
- teardown
168
- else
169
- @status = :pending
148
+ rescue *PassthroughExceptions
149
+ raise # passthrough-exceptions must be passed through
150
+ rescue ::BareTest::Assertion::Failure => failure
151
+ status = :failure
152
+ failure_reason = failure.message
153
+ rescue ::BareTest::Assertion::Skip => skip
154
+ status = :manually_skipped
155
+ skip_reason = skip.message
156
+ rescue Exception => exception
157
+ status = :error
158
+ failure_reason = "An error occurred during #{name}: #{exception}"
159
+ exception = exception
170
160
  end
171
- self
161
+
162
+ status && Status.new(self, status, context, skip_reason, failure_reason, exception)
172
163
  end
173
164
 
174
165
  def to_s # :nodoc: