rspec-core 2.99.0 → 3.0.0

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 (216) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +1 -0
  4. data/Changelog.md +339 -1
  5. data/License.txt +1 -0
  6. data/README.md +19 -37
  7. data/exe/rspec +2 -23
  8. data/lib/rspec/core/backport_random.rb +336 -0
  9. data/lib/rspec/core/backtrace_formatter.rb +70 -0
  10. data/lib/rspec/core/configuration.rb +479 -577
  11. data/lib/rspec/core/configuration_options.rb +71 -54
  12. data/lib/rspec/core/drb.rb +111 -0
  13. data/lib/rspec/core/dsl.rb +86 -18
  14. data/lib/rspec/core/example.rb +267 -119
  15. data/lib/rspec/core/example_group.rb +381 -393
  16. data/lib/rspec/core/filter_manager.rb +133 -114
  17. data/lib/rspec/core/flat_map.rb +18 -0
  18. data/lib/rspec/core/formatters/base_formatter.rb +51 -125
  19. data/lib/rspec/core/formatters/base_text_formatter.rb +34 -286
  20. data/lib/rspec/core/formatters/console_codes.rb +24 -1
  21. data/lib/rspec/core/formatters/deprecation_formatter.rb +25 -26
  22. data/lib/rspec/core/formatters/documentation_formatter.rb +27 -25
  23. data/lib/rspec/core/formatters/helpers.rb +14 -36
  24. data/lib/rspec/core/formatters/html_formatter.rb +58 -65
  25. data/lib/rspec/core/formatters/html_printer.rb +12 -18
  26. data/lib/rspec/core/formatters/json_formatter.rb +54 -31
  27. data/lib/rspec/core/formatters/profile_formatter.rb +67 -0
  28. data/lib/rspec/core/formatters/progress_formatter.rb +11 -15
  29. data/lib/rspec/core/formatters/snippet_extractor.rb +22 -11
  30. data/lib/rspec/core/formatters.rb +90 -43
  31. data/lib/rspec/core/hooks.rb +325 -270
  32. data/lib/rspec/core/memoized_helpers.rb +45 -156
  33. data/lib/rspec/core/metadata.rb +284 -236
  34. data/lib/rspec/core/metadata_filter.rb +86 -0
  35. data/lib/rspec/core/mocking_adapters/flexmock.rb +29 -0
  36. data/lib/rspec/core/{mocking/with_mocha.rb → mocking_adapters/mocha.rb} +19 -16
  37. data/lib/rspec/core/mocking_adapters/null.rb +12 -0
  38. data/lib/rspec/core/mocking_adapters/rr.rb +29 -0
  39. data/lib/rspec/core/mocking_adapters/rspec.rb +30 -0
  40. data/lib/rspec/core/notifications.rb +511 -0
  41. data/lib/rspec/core/option_parser.rb +49 -74
  42. data/lib/rspec/core/ordering.rb +156 -0
  43. data/lib/rspec/core/pending.rb +94 -96
  44. data/lib/rspec/core/project_initializer/.rspec +3 -0
  45. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +78 -0
  46. data/lib/rspec/core/project_initializer.rb +24 -64
  47. data/lib/rspec/core/rake_task.rb +44 -130
  48. data/lib/rspec/core/reporter.rb +76 -59
  49. data/lib/rspec/core/ruby_project.rb +2 -1
  50. data/lib/rspec/core/runner.rb +117 -52
  51. data/lib/rspec/core/shared_context.rb +10 -10
  52. data/lib/rspec/core/shared_example_group.rb +108 -121
  53. data/lib/rspec/core/version.rb +3 -1
  54. data/lib/rspec/core/warnings.rb +40 -0
  55. data/lib/rspec/core/world.rb +66 -10
  56. data/lib/rspec/core.rb +64 -104
  57. data.tar.gz.sig +3 -0
  58. metadata +75 -322
  59. metadata.gz.sig +1 -0
  60. data/exe/autospec +0 -13
  61. data/features/Autotest.md +0 -38
  62. data/features/README.md +0 -17
  63. data/features/Upgrade.md +0 -364
  64. data/features/command_line/README.md +0 -28
  65. data/features/command_line/example_name_option.feature +0 -97
  66. data/features/command_line/exit_status.feature +0 -82
  67. data/features/command_line/format_option.feature +0 -75
  68. data/features/command_line/init.feature +0 -18
  69. data/features/command_line/line_number_appended_to_path.feature +0 -140
  70. data/features/command_line/line_number_option.feature +0 -53
  71. data/features/command_line/order.feature +0 -26
  72. data/features/command_line/pattern_option.feature +0 -49
  73. data/features/command_line/rake_task.feature +0 -122
  74. data/features/command_line/require_option.feature +0 -43
  75. data/features/command_line/ruby.feature +0 -22
  76. data/features/command_line/tag.feature +0 -98
  77. data/features/command_line/warnings_option.feature +0 -29
  78. data/features/configuration/alias_example_to.feature +0 -48
  79. data/features/configuration/backtrace_clean_patterns.feature +0 -102
  80. data/features/configuration/custom_settings.feature +0 -84
  81. data/features/configuration/default_path.feature +0 -38
  82. data/features/configuration/deprecation_stream.feature +0 -58
  83. data/features/configuration/fail_fast.feature +0 -77
  84. data/features/configuration/failure_exit_code.feature +0 -36
  85. data/features/configuration/order_and_seed.feature +0 -3
  86. data/features/configuration/output_stream.feature +0 -24
  87. data/features/configuration/pattern.feature +0 -38
  88. data/features/configuration/profile.feature +0 -220
  89. data/features/configuration/read_options_from_file.feature +0 -90
  90. data/features/configuration/run_all_when_everything_filtered.feature +0 -76
  91. data/features/configuration/show_failures_in_pending_blocks.feature +0 -61
  92. data/features/configuration/treat_symbols_as_metadata_keys_with_true_values.feature +0 -52
  93. data/features/example_groups/basic_structure.feature +0 -55
  94. data/features/example_groups/shared_context.feature +0 -74
  95. data/features/example_groups/shared_examples.feature +0 -294
  96. data/features/expectation_framework_integration/configure_expectation_framework.feature +0 -197
  97. data/features/filtering/exclusion_filters.feature +0 -138
  98. data/features/filtering/if_and_unless.feature +0 -168
  99. data/features/filtering/inclusion_filters.feature +0 -105
  100. data/features/formatters/configurable_colors.feature +0 -31
  101. data/features/formatters/custom_formatter.feature +0 -36
  102. data/features/formatters/json_formatter.feature +0 -30
  103. data/features/formatters/text_formatter.feature +0 -46
  104. data/features/helper_methods/arbitrary_methods.feature +0 -40
  105. data/features/helper_methods/let.feature +0 -50
  106. data/features/helper_methods/modules.feature +0 -149
  107. data/features/hooks/around_hooks.feature +0 -343
  108. data/features/hooks/before_and_after_hooks.feature +0 -427
  109. data/features/hooks/filtering.feature +0 -234
  110. data/features/metadata/current_example.feature +0 -56
  111. data/features/metadata/described_class.feature +0 -17
  112. data/features/metadata/user_defined.feature +0 -113
  113. data/features/mock_framework_integration/use_any_framework.feature +0 -106
  114. data/features/mock_framework_integration/use_flexmock.feature +0 -96
  115. data/features/mock_framework_integration/use_mocha.feature +0 -97
  116. data/features/mock_framework_integration/use_rr.feature +0 -98
  117. data/features/mock_framework_integration/use_rspec.feature +0 -97
  118. data/features/pending/pending_examples.feature +0 -229
  119. data/features/spec_files/arbitrary_file_suffix.feature +0 -13
  120. data/features/step_definitions/additional_cli_steps.rb +0 -49
  121. data/features/subject/attribute_of_subject.feature +0 -124
  122. data/features/subject/explicit_subject.feature +0 -101
  123. data/features/subject/implicit_subject.feature +0 -63
  124. data/features/subject/one_liner_syntax.feature +0 -71
  125. data/features/support/env.rb +0 -14
  126. data/features/support/rubinius.rb +0 -6
  127. data/lib/autotest/discover.rb +0 -10
  128. data/lib/autotest/rspec2.rb +0 -77
  129. data/lib/rspec/core/backtrace_cleaner.rb +0 -46
  130. data/lib/rspec/core/backward_compatibility.rb +0 -55
  131. data/lib/rspec/core/caller_filter.rb +0 -60
  132. data/lib/rspec/core/command_line.rb +0 -47
  133. data/lib/rspec/core/deprecated_mutable_array_proxy.rb +0 -32
  134. data/lib/rspec/core/deprecation.rb +0 -26
  135. data/lib/rspec/core/drb_command_line.rb +0 -26
  136. data/lib/rspec/core/drb_options.rb +0 -87
  137. data/lib/rspec/core/extensions/instance_eval_with_args.rb +0 -44
  138. data/lib/rspec/core/extensions/kernel.rb +0 -9
  139. data/lib/rspec/core/extensions/module_eval_with_args.rb +0 -38
  140. data/lib/rspec/core/extensions/ordered.rb +0 -27
  141. data/lib/rspec/core/formatters/text_mate_formatter.rb +0 -34
  142. data/lib/rspec/core/metadata_hash_builder.rb +0 -97
  143. data/lib/rspec/core/mocking/with_absolutely_nothing.rb +0 -11
  144. data/lib/rspec/core/mocking/with_flexmock.rb +0 -27
  145. data/lib/rspec/core/mocking/with_rr.rb +0 -27
  146. data/lib/rspec/core/mocking/with_rspec.rb +0 -27
  147. data/lib/rspec/core/shared_example_group/collection.rb +0 -45
  148. data/spec/autotest/discover_spec.rb +0 -49
  149. data/spec/autotest/failed_results_re_spec.rb +0 -45
  150. data/spec/autotest/rspec_spec.rb +0 -133
  151. data/spec/command_line/order_spec.rb +0 -204
  152. data/spec/rspec/core/backtrace_cleaner_spec.rb +0 -68
  153. data/spec/rspec/core/caller_filter_spec.rb +0 -58
  154. data/spec/rspec/core/command_line_spec.rb +0 -127
  155. data/spec/rspec/core/command_line_spec_output.txt +0 -0
  156. data/spec/rspec/core/configuration_options_spec.rb +0 -417
  157. data/spec/rspec/core/configuration_spec.rb +0 -2072
  158. data/spec/rspec/core/deprecation_spec.rb +0 -27
  159. data/spec/rspec/core/deprecations_spec.rb +0 -59
  160. data/spec/rspec/core/drb_command_line_spec.rb +0 -102
  161. data/spec/rspec/core/drb_options_spec.rb +0 -193
  162. data/spec/rspec/core/dsl_spec.rb +0 -25
  163. data/spec/rspec/core/example_group_spec.rb +0 -1337
  164. data/spec/rspec/core/example_spec.rb +0 -502
  165. data/spec/rspec/core/filter_manager_spec.rb +0 -246
  166. data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -108
  167. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +0 -524
  168. data/spec/rspec/core/formatters/console_codes_spec.rb +0 -50
  169. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +0 -263
  170. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +0 -89
  171. data/spec/rspec/core/formatters/helpers_spec.rb +0 -104
  172. data/spec/rspec/core/formatters/html_formatted.html +0 -397
  173. data/spec/rspec/core/formatters/html_formatter_spec.rb +0 -131
  174. data/spec/rspec/core/formatters/json_formatter_spec.rb +0 -115
  175. data/spec/rspec/core/formatters/progress_formatter_spec.rb +0 -30
  176. data/spec/rspec/core/formatters/snippet_extractor_spec.rb +0 -26
  177. data/spec/rspec/core/formatters/text_mate_formatted.html +0 -397
  178. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +0 -107
  179. data/spec/rspec/core/hooks_filtering_spec.rb +0 -227
  180. data/spec/rspec/core/hooks_spec.rb +0 -269
  181. data/spec/rspec/core/kernel_extensions_spec.rb +0 -9
  182. data/spec/rspec/core/memoized_helpers_spec.rb +0 -776
  183. data/spec/rspec/core/metadata_spec.rb +0 -514
  184. data/spec/rspec/core/option_parser_spec.rb +0 -297
  185. data/spec/rspec/core/pending_example_spec.rb +0 -260
  186. data/spec/rspec/core/pending_spec.rb +0 -27
  187. data/spec/rspec/core/project_initializer_spec.rb +0 -130
  188. data/spec/rspec/core/rake_task_spec.rb +0 -202
  189. data/spec/rspec/core/reporter_spec.rb +0 -167
  190. data/spec/rspec/core/resources/a_bar.rb +0 -0
  191. data/spec/rspec/core/resources/a_foo.rb +0 -0
  192. data/spec/rspec/core/resources/a_spec.rb +0 -1
  193. data/spec/rspec/core/resources/custom_example_group_runner.rb +0 -14
  194. data/spec/rspec/core/resources/formatter_specs.rb +0 -60
  195. data/spec/rspec/core/resources/utf8_encoded.rb +0 -8
  196. data/spec/rspec/core/rspec_matchers_spec.rb +0 -45
  197. data/spec/rspec/core/ruby_project_spec.rb +0 -26
  198. data/spec/rspec/core/runner_spec.rb +0 -82
  199. data/spec/rspec/core/shared_context_spec.rb +0 -114
  200. data/spec/rspec/core/shared_example_group/collection_spec.rb +0 -70
  201. data/spec/rspec/core/shared_example_group_spec.rb +0 -138
  202. data/spec/rspec/core/world_spec.rb +0 -142
  203. data/spec/rspec/core_spec.rb +0 -108
  204. data/spec/spec_helper.rb +0 -135
  205. data/spec/support/config_options_helper.rb +0 -15
  206. data/spec/support/helper_methods.rb +0 -55
  207. data/spec/support/in_sub_process.rb +0 -37
  208. data/spec/support/isolate_load_path_mutation.rb +0 -6
  209. data/spec/support/isolated_directory.rb +0 -10
  210. data/spec/support/isolated_home_directory.rb +0 -16
  211. data/spec/support/matchers.rb +0 -65
  212. data/spec/support/mathn_integration_support.rb +0 -12
  213. data/spec/support/sandboxed_mock_space.rb +0 -116
  214. data/spec/support/shared_example_groups.rb +0 -42
  215. data/spec/support/silence_dsl_deprecations.rb +0 -32
  216. data/spec/support/spec_files.rb +0 -44
@@ -1,9 +1,15 @@
1
1
  module RSpec
2
2
  module Core
3
3
  # Wrapper for an instance of a subclass of {ExampleGroup}. An instance of
4
- # `Example` is returned by the {ExampleGroup#example example} method
5
- # exposed to examples, {Hooks#before before} and {Hooks#after after} hooks,
6
- # and yielded to {Hooks#around around} hooks.
4
+ # `RSpec::Core::Example` is returned by example definition methods
5
+ # such as {ExampleGroup.it it} and is yielded to the {ExampleGroup.it it},
6
+ # {Hooks#before before}, {Hooks#after after}, {Hooks#around around},
7
+ # {MemoizedHelpers::ClassMethods#let let} and
8
+ # {MemoizedHelpers::ClassMethods#subject subject} blocks.
9
+ #
10
+ # This allows us to provide rich metadata about each individual
11
+ # example without adding tons of methods directly to the ExampleGroup
12
+ # that users may inadvertantly redefine.
7
13
  #
8
14
  # Useful for configuring logging and/or taking some action based
9
15
  # on the state of an example's metadata.
@@ -11,17 +17,17 @@ module RSpec
11
17
  # @example
12
18
  #
13
19
  # RSpec.configure do |config|
14
- # config.before do
20
+ # config.before do |example|
15
21
  # log example.description
16
22
  # end
17
23
  #
18
- # config.after do
24
+ # config.after do |example|
19
25
  # log example.description
20
26
  # end
21
27
  #
22
- # config.around do |ex|
28
+ # config.around do |example|
23
29
  # log example.description
24
- # ex.run
30
+ # example.run
25
31
  # end
26
32
  # end
27
33
  #
@@ -33,15 +39,33 @@ module RSpec
33
39
  # end
34
40
  #
35
41
  # @see ExampleGroup
42
+ # @note Example blocks are evaluated in the context of an instance
43
+ # of an `ExampleGroup`, not in the context of an instance of `Example`.
36
44
  class Example
37
45
  # @private
38
46
  #
39
47
  # Used to define methods that delegate to this example's metadata
40
- def self.delegate_to_metadata(*keys)
41
- keys.each { |key| define_method(key) { @metadata[key] } }
48
+ def self.delegate_to_metadata(key)
49
+ define_method(key) { @metadata[key] }
42
50
  end
43
51
 
44
- delegate_to_metadata :full_description, :execution_result, :file_path, :pending, :location
52
+ # @return [ExecutionResult] represents the result of running this example.
53
+ delegate_to_metadata :execution_result
54
+ # @return [String] the relative path to the file where this example was defined.
55
+ delegate_to_metadata :file_path
56
+ # @return [String] the full description (including the docstrings of
57
+ # all parent example groups).
58
+ delegate_to_metadata :full_description
59
+ # @return [String] the exact source location of this example in a form
60
+ # like `./path/to/spec.rb:17`
61
+ delegate_to_metadata :location
62
+ # @return [Boolean] flag that indicates that the example is not expected to pass.
63
+ # It will be run and will either have a pending result (if a failure occurs)
64
+ # or a failed result (if no failure occurs).
65
+ delegate_to_metadata :pending
66
+ # @return [Boolean] flag that will cause the example to not run.
67
+ # The {ExecutionResult} status will be `:pending`.
68
+ delegate_to_metadata :skip
45
69
 
46
70
  # Returns the string submitted to `example` or its aliases (e.g.
47
71
  # `specify`, `it`, etc). If no string is submitted (e.g. `it { is_expected.to
@@ -49,7 +73,9 @@ module RSpec
49
73
  # there is one, otherwise returns a message including the location of the
50
74
  # example.
51
75
  def description
52
- description = metadata[:description].to_s.empty? ? "example at #{location}" : metadata[:description]
76
+ description = metadata[:description].to_s.empty? ?
77
+ "example at #{location}" :
78
+ metadata[:description]
53
79
  RSpec.configuration.format_docstrings_block.call(description)
54
80
  end
55
81
 
@@ -71,23 +97,26 @@ module RSpec
71
97
  # running this example.
72
98
  attr_reader :example_group_instance
73
99
 
100
+ # @attr
101
+ # @private
102
+ attr_accessor :clock
103
+
74
104
  # Creates a new instance of Example.
75
- # @param example_group_class the subclass of ExampleGroup in which this Example is declared
76
- # @param description the String passed to the `it` method (or alias)
77
- # @param metadata additional args passed to `it` to be used as metadata
78
- # @param example_block the block of code that represents the example
79
- def initialize(example_group_class, description, metadata, example_block=nil)
80
- @example_group_class, @options, @example_block = example_group_class, metadata, example_block
81
- @metadata = @example_group_class.metadata.for_example(description, metadata)
82
- @example_group_instance = @exception = nil
83
- @pending_declared_in_example = false
84
- end
105
+ # @param example_group_class [Class] the subclass of ExampleGroup in which this Example is declared
106
+ # @param description [String] the String passed to the `it` method (or alias)
107
+ # @param user_metadata [Hash] additional args passed to `it` to be used as metadata
108
+ # @param example_block [Proc] the block of code that represents the example
109
+ # @api private
110
+ def initialize(example_group_class, description, user_metadata, example_block=nil)
111
+ @example_group_class = example_group_class
112
+ @example_block = example_block
113
+
114
+ @metadata = Metadata::ExampleHash.create(
115
+ @example_group_class.metadata, user_metadata, description, example_block
116
+ )
85
117
 
86
- # @deprecated access options via metadata instead
87
- def options
88
- RSpec.deprecate("`RSpec::Core::Example#options`",
89
- :replacement => "`RSpec::Core::Example#metadata`")
90
- @options
118
+ @example_group_instance = @exception = nil
119
+ @clock = RSpec::Core::Time
91
120
  end
92
121
 
93
122
  # Returns the example group class that provides the context for running
@@ -97,9 +126,10 @@ module RSpec
97
126
  end
98
127
 
99
128
  alias_method :pending?, :pending
129
+ alias_method :skipped?, :skip
100
130
 
101
131
  # @api private
102
- # instance_evals the block passed to the constructor in the context of
132
+ # instance_execs the block passed to the constructor in the context of
103
133
  # the instance of {ExampleGroup}.
104
134
  # @param example_group_instance the instance of an ExampleGroup subclass
105
135
  def run(example_group_instance, reporter)
@@ -109,17 +139,28 @@ module RSpec
109
139
  start(reporter)
110
140
 
111
141
  begin
112
- unless pending
113
- with_around_each_hooks do
142
+ if skipped?
143
+ Pending.mark_pending! self, skip
144
+ elsif !RSpec.configuration.dry_run?
145
+ with_around_example_hooks do
114
146
  begin
115
- run_before_each
116
- @example_group_instance.instance_eval_with_args(self, &@example_block)
117
- rescue Pending::SkipDeclaredInExample => e
118
- @pending_declared_in_example = e.message
147
+ run_before_example
148
+ @example_group_instance.instance_exec(self, &@example_block)
149
+
150
+ if pending?
151
+ Pending.mark_fixed! self
152
+
153
+ raise Pending::PendingExampleFixedError,
154
+ 'Expected example to fail since it is pending, but it passed.',
155
+ [location]
156
+ end
157
+ rescue Pending::SkipDeclaredInExample
158
+ # no-op, required metadata has already been set by the `skip`
159
+ # method.
119
160
  rescue Exception => e
120
161
  set_exception(e)
121
162
  ensure
122
- run_after_each
163
+ run_after_example
123
164
  end
124
165
  end
125
166
  end
@@ -130,12 +171,6 @@ module RSpec
130
171
  @example_group_instance.instance_variable_set(ivar, nil)
131
172
  end
132
173
  @example_group_instance = nil
133
-
134
- begin
135
- assign_generated_description
136
- rescue Exception => e
137
- set_exception(e, "while assigning the example description")
138
- end
139
174
  end
140
175
 
141
176
  finish(reporter)
@@ -143,66 +178,61 @@ module RSpec
143
178
  RSpec.current_example = nil
144
179
  end
145
180
 
146
- # @api private
147
- #
148
- # Wraps the example block in a Proc so it can invoked using `run` or
149
- # `call` in [around](../Hooks#around-instance_method) hooks.
150
- def self.procsy(metadata, &proc)
151
- proc.extend(Procsy).with(metadata)
152
- end
153
-
154
- # Used to extend a `Proc` with behavior that makes it look something like
155
- # an {Example} in an {Hooks#around around} hook.
156
- #
157
- # @note Procsy, itself, is not a public API, but we're documenting it
158
- # here to document how to interact with the object yielded to an
159
- # `around` hook.
181
+ # Wraps both a `Proc` and an {Example} for use in {Hooks#around
182
+ # around} hooks. In around hooks we need to yield this special
183
+ # kind of object (rather than the raw {Example}) because when
184
+ # there are multiple `around` hooks we have to wrap them recursively.
160
185
  #
161
186
  # @example
162
187
  #
163
188
  # RSpec.configure do |c|
164
- # c.around do |ex| # ex is a Proc extended with Procsy
189
+ # c.around do |ex| # Procsy which wraps the example
165
190
  # if ex.metadata[:key] == :some_value && some_global_condition
166
191
  # raise "some message"
167
192
  # end
168
193
  # ex.run # run delegates to ex.call
169
194
  # end
170
195
  # end
171
- module Procsy
172
- # The `metadata` of the {Example} instance.
173
- attr_reader :metadata
196
+ #
197
+ # @note This class also exposes the instance methods of {Example},
198
+ # proxying them through to the wrapped {Example} instance.
199
+ class Procsy
200
+ # The {Example} instance.
201
+ attr_reader :example
202
+
203
+ Example.public_instance_methods(false).each do |name|
204
+ define_method(name) { |*a, &b| @example.__send__(name, *a, &b) }
205
+ end
174
206
 
175
- # @api private
176
- # @param [Proc]
177
- # Adds a `run` method to the extended Proc, allowing it to be invoked
178
- # in an [around](../Hooks#around-instance_method) hook using either
179
- # `run` or `call`.
180
- def self.extended(proc)
181
- # @api public
182
- # Foo bar
183
- def proc.run; call; end
207
+ Proc.public_instance_methods(false).each do |name|
208
+ define_method(name) { |*a, &b| @proc.__send__(name, *a, &b) }
184
209
  end
210
+ alias run call
185
211
 
186
- # @api private
187
- def with(metadata)
188
- @metadata = metadata
189
- self
212
+ def initialize(example, &block)
213
+ @example = example
214
+ @proc = block
215
+ end
216
+
217
+ # @private
218
+ def wrap(&block)
219
+ self.class.new(example, &block)
190
220
  end
191
221
  end
192
222
 
193
223
  # @private
194
224
  def any_apply?(filters)
195
- metadata.any_apply?(filters)
225
+ MetadataFilter.any_apply?(filters, metadata)
196
226
  end
197
227
 
198
228
  # @private
199
229
  def all_apply?(filters)
200
- @metadata.all_apply?(filters) || @example_group_class.all_apply?(filters)
230
+ MetadataFilter.all_apply?(filters, metadata) || @example_group_class.all_apply?(filters)
201
231
  end
202
232
 
203
233
  # @private
204
- def around_each_hooks
205
- @around_each_hooks ||= example_group.around_each_hooks_for(self)
234
+ def around_example_hooks
235
+ @around_example_hooks ||= example_group.hooks.around_example_hooks_for(self)
206
236
  end
207
237
 
208
238
  # @private
@@ -210,26 +240,30 @@ module RSpec
210
240
  # Used internally to set an exception in an after hook, which
211
241
  # captures the exception but doesn't raise it.
212
242
  def set_exception(exception, context=nil)
213
- if @exception && context != :dont_print
214
- # An error has already been set; we don't want to override it,
215
- # but we also don't want silence the error, so let's print it.
216
- msg = <<-EOS
243
+ if pending? && !(Pending::PendingExampleFixedError === exception)
244
+ execution_result.pending_exception = exception
245
+ else
246
+ if @exception
247
+ # An error has already been set; we don't want to override it,
248
+ # but we also don't want silence the error, so let's print it.
249
+ msg = <<-EOS
217
250
 
218
- An error occurred #{context}
219
- #{exception.class}: #{exception.message}
220
- occurred at #{exception.backtrace.first}
251
+ An error occurred #{context}
252
+ #{exception.class}: #{exception.message}
253
+ occurred at #{exception.backtrace.first}
221
254
 
222
- EOS
223
- RSpec.configuration.reporter.message(msg)
224
- end
255
+ EOS
256
+ RSpec.configuration.reporter.message(msg)
257
+ end
225
258
 
226
- @exception ||= exception
259
+ @exception ||= exception
260
+ end
227
261
  end
228
262
 
229
263
  # @private
230
264
  #
231
265
  # Used internally to set an exception and fail without actually executing
232
- # the example when an exception is raised in before(:all).
266
+ # the example when an exception is raised in before(:context).
233
267
  def fail_with_exception(reporter, exception)
234
268
  start(reporter)
235
269
  set_exception(exception)
@@ -237,87 +271,201 @@ An error occurred #{context}
237
271
  end
238
272
 
239
273
  # @private
240
- def instance_eval_with_rescue(context = nil, &block)
241
- @example_group_instance.instance_eval_with_rescue(self, context, &block)
274
+ #
275
+ # Used internally to skip without actually executing the example when
276
+ # skip is used in before(:context)
277
+ def skip_with_exception(reporter, exception)
278
+ start(reporter)
279
+ Pending.mark_skipped! self, exception.argument
280
+ finish(reporter)
242
281
  end
243
282
 
244
283
  # @private
245
- def instance_eval_with_args(*args, &block)
246
- @example_group_instance.instance_eval_with_args(*args, &block)
284
+ def instance_exec_with_rescue(context, &block)
285
+ @example_group_instance.instance_exec(self, &block)
286
+ rescue Exception => e
287
+ set_exception(e, context)
288
+ end
289
+
290
+ # @private
291
+ def instance_exec(*args, &block)
292
+ @example_group_instance.instance_exec(*args, &block)
247
293
  end
248
294
 
249
295
  private
250
296
 
251
- def with_around_each_hooks(&block)
252
- if around_each_hooks.empty?
297
+ def with_around_example_hooks(&block)
298
+ if around_example_hooks.empty?
253
299
  yield
254
300
  else
255
- @example_group_class.run_around_each_hooks(self, Example.procsy(metadata, &block))
301
+ @example_group_class.hooks.run(:around, :example, self, Procsy.new(self, &block))
256
302
  end
257
303
  rescue Exception => e
258
- set_exception(e, "in an around(:each) hook")
304
+ set_exception(e, "in an `around(:example)` hook")
259
305
  end
260
306
 
261
307
  def start(reporter)
262
308
  reporter.example_started(self)
263
- record :started_at => RSpec::Core::Time.now
309
+ execution_result.started_at = clock.now
264
310
  end
265
311
 
266
312
  def finish(reporter)
313
+ pending_message = execution_result.pending_message
314
+
267
315
  if @exception
268
- record_finished 'failed', :exception => @exception
316
+ record_finished :failed
317
+ execution_result.exception = @exception
269
318
  reporter.example_failed self
270
319
  false
271
- elsif @pending_declared_in_example
272
- record_finished 'pending', :pending_message => @pending_declared_in_example
273
- reporter.example_pending self
274
- true
275
- elsif pending
276
- record_finished 'pending', :pending_message => String === pending ? pending : Pending::NO_REASON_GIVEN
320
+ elsif pending_message
321
+ record_finished :pending
322
+ execution_result.pending_message = pending_message
277
323
  reporter.example_pending self
278
324
  true
279
325
  else
280
- record_finished 'passed'
326
+ record_finished :passed
281
327
  reporter.example_passed self
282
328
  true
283
329
  end
284
330
  end
285
331
 
286
- def record_finished(status, results={})
287
- finished_at = RSpec::Core::Time.now
288
- record results.merge(:status => status, :finished_at => finished_at, :run_time => (finished_at - execution_result[:started_at]).to_f)
332
+ def record_finished(status)
333
+ execution_result.record_finished(status, clock.now)
289
334
  end
290
335
 
291
- def run_before_each
336
+ def run_before_example
292
337
  @example_group_instance.setup_mocks_for_rspec
293
- @example_group_class.run_before_each_hooks(self)
338
+ @example_group_class.hooks.run(:before, :example, self)
294
339
  end
295
340
 
296
- def run_after_each
297
- @example_group_class.run_after_each_hooks(self)
341
+ def run_after_example
342
+ @example_group_class.hooks.run(:after, :example, self)
298
343
  verify_mocks
344
+ assign_generated_description if RSpec.configuration.expecting_with_rspec?
299
345
  rescue Exception => e
300
- set_exception(e, "in an after(:each) hook")
346
+ set_exception(e, "in an `after(:example)` hook")
301
347
  ensure
302
348
  @example_group_instance.teardown_mocks_for_rspec
303
349
  end
304
350
 
305
351
  def verify_mocks
306
- @example_group_instance.verify_mocks_for_rspec
352
+ @example_group_instance.verify_mocks_for_rspec if mocks_need_verification?
307
353
  rescue Exception => e
308
- set_exception(e, :dont_print)
354
+ if pending?
355
+ execution_result.pending_fixed = false
356
+ @exception = nil
357
+ else
358
+ set_exception(e)
359
+ end
360
+ end
361
+
362
+ def mocks_need_verification?
363
+ exception.nil? || execution_result.pending_fixed?
309
364
  end
310
365
 
311
366
  def assign_generated_description
312
- return unless RSpec.configuration.expecting_with_rspec?
313
- if metadata[:description_args].empty? and !pending?
314
- metadata[:description_args] << RSpec::Matchers.generated_description
367
+ if metadata[:description].empty? && (description = RSpec::Matchers.generated_description)
368
+ metadata[:description] = description
369
+ metadata[:full_description] << description
315
370
  end
371
+ rescue Exception => e
372
+ set_exception(e, "while assigning the example description")
373
+ ensure
316
374
  RSpec::Matchers.clear_generated_description
317
375
  end
318
376
 
319
- def record(results={})
320
- execution_result.update(results)
377
+ def skip_message
378
+ if String === skip
379
+ skip
380
+ else
381
+ Pending::NO_REASON_GIVEN
382
+ end
383
+ end
384
+
385
+ # Represents the result of executing an example.
386
+ # Behaves like a hash for backwards compatibility.
387
+ class ExecutionResult
388
+ include HashImitatable
389
+
390
+ # @return [Symbol] `:passed`, `:failed` or `:pending`.
391
+ attr_accessor :status
392
+
393
+ # @return [Exception, nil] The failure, if there was one.
394
+ attr_accessor :exception
395
+
396
+ # @return [Time] When the example started.
397
+ attr_accessor :started_at
398
+
399
+ # @return [Time] When the example finished.
400
+ attr_accessor :finished_at
401
+
402
+ # @return [Float] How long the example took in seconds.
403
+ attr_accessor :run_time
404
+
405
+ # @return [String, nil] The reason the example was pending,
406
+ # or nil if the example was not pending.
407
+ attr_accessor :pending_message
408
+
409
+ # @return [Exception, nil] The exception triggered while
410
+ # executing the pending example. If no exception was triggered
411
+ # it would no longer get a status of `:pending` unless it was
412
+ # tagged with `:skip`.
413
+ attr_accessor :pending_exception
414
+
415
+ # @return [Boolean] For examples tagged with `:pending`,
416
+ # this indicates whether or not it now passes.
417
+ attr_accessor :pending_fixed
418
+
419
+ alias pending_fixed? pending_fixed
420
+
421
+ # @api private
422
+ # Records the finished status of the example.
423
+ def record_finished(status, finished_at)
424
+ self.status = status
425
+ self.finished_at = finished_at
426
+ self.run_time = (finished_at - started_at).to_f
427
+ end
428
+
429
+ private
430
+
431
+ # For backwards compatibility we present `status` as a string
432
+ # when presenting the legacy hash interface.
433
+ def hash_for_delegation
434
+ super.tap do |hash|
435
+ hash[:status] &&= status.to_s
436
+ end
437
+ end
438
+
439
+ def set_value(name, value)
440
+ value &&= value.to_sym if name == :status
441
+ super(name, value)
442
+ end
443
+
444
+ def get_value(name)
445
+ if name == :status
446
+ status.to_s if status
447
+ else
448
+ super
449
+ end
450
+ end
451
+
452
+ def issue_deprecation(method_name, *args)
453
+ RSpec.deprecate("Treating `metadata[:execution_result]` as a hash",
454
+ :replacement => "the attributes methods to access the data")
455
+ end
456
+ end
457
+ end
458
+
459
+ # @private
460
+ # Provides an execution context for before/after :suite hooks.
461
+ class SuiteHookContext < Example
462
+ def initialize
463
+ super(AnonymousExampleGroup, "", {})
464
+ end
465
+
466
+ # To ensure we don't silence errors...
467
+ def set_exception(exception, context=nil)
468
+ raise exception
321
469
  end
322
470
  end
323
471
  end