baretest 0.2.4 → 0.4.0.pre1

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