rspec-core 3.0.0.beta1 → 3.0.0.beta2

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 (145) hide show
  1. data.tar.gz.sig +0 -0
  2. data/Changelog.md +137 -0
  3. data/README.md +2 -2
  4. data/exe/rspec +2 -23
  5. data/features/README.md +1 -5
  6. data/features/command_line/README.md +7 -10
  7. data/features/command_line/exit_status.feature +1 -1
  8. data/features/command_line/format_option.feature +1 -1
  9. data/features/command_line/init.feature +40 -1
  10. data/features/command_line/line_number_option.feature +2 -2
  11. data/features/command_line/ruby.feature +5 -4
  12. data/features/configuration/enable_global_dsl.feature +54 -0
  13. data/features/example_groups/aliasing.feature +48 -0
  14. data/features/example_groups/basic_structure.feature +1 -1
  15. data/features/expectation_framework_integration/configure_expectation_framework.feature +1 -1
  16. data/features/filtering/if_and_unless.feature +0 -30
  17. data/features/formatters/custom_formatter.feature +32 -0
  18. data/features/formatters/regression_tests.feature +95 -0
  19. data/features/hooks/around_hooks.feature +1 -0
  20. data/features/hooks/before_and_after_hooks.feature +2 -2
  21. data/features/mock_framework_integration/use_flexmock.feature +11 -13
  22. data/features/mock_framework_integration/use_mocha.feature +11 -13
  23. data/features/mock_framework_integration/use_rr.feature +11 -13
  24. data/features/mock_framework_integration/use_rspec.feature +11 -13
  25. data/features/pending_and_skipped_examples/README.md +3 -0
  26. data/features/pending_and_skipped_examples/pending_examples.feature +118 -0
  27. data/features/pending_and_skipped_examples/skipped_examples.feature +106 -0
  28. data/features/step_definitions/additional_cli_steps.rb +34 -0
  29. data/features/subject/explicit_subject.feature +1 -1
  30. data/features/subject/one_liner_syntax.feature +71 -0
  31. data/lib/rspec/core.rb +6 -14
  32. data/lib/rspec/core/backtrace_formatter.rb +16 -4
  33. data/lib/rspec/core/command_line.rb +2 -3
  34. data/lib/rspec/core/configuration.rb +114 -125
  35. data/lib/rspec/core/configuration_options.rb +32 -18
  36. data/lib/rspec/core/dsl.rb +80 -18
  37. data/lib/rspec/core/example.rb +84 -33
  38. data/lib/rspec/core/example_group.rb +95 -43
  39. data/lib/rspec/core/filter_manager.rb +31 -40
  40. data/lib/rspec/core/formatters.rb +137 -0
  41. data/lib/rspec/core/formatters/base_formatter.rb +28 -41
  42. data/lib/rspec/core/formatters/base_text_formatter.rb +26 -37
  43. data/lib/rspec/core/formatters/deprecation_formatter.rb +48 -27
  44. data/lib/rspec/core/formatters/documentation_formatter.rb +27 -22
  45. data/lib/rspec/core/formatters/html_formatter.rb +48 -56
  46. data/lib/rspec/core/formatters/html_printer.rb +11 -18
  47. data/lib/rspec/core/formatters/json_formatter.rb +18 -22
  48. data/lib/rspec/core/formatters/legacy_formatter.rb +227 -0
  49. data/lib/rspec/core/formatters/progress_formatter.rb +7 -10
  50. data/lib/rspec/core/hooks.rb +250 -217
  51. data/lib/rspec/core/memoized_helpers.rb +43 -9
  52. data/lib/rspec/core/mocking_adapters/flexmock.rb +29 -0
  53. data/lib/rspec/core/{mocking/with_mocha.rb → mocking_adapters/mocha.rb} +19 -16
  54. data/lib/rspec/core/mocking_adapters/null.rb +12 -0
  55. data/lib/rspec/core/mocking_adapters/rr.rb +28 -0
  56. data/lib/rspec/core/mocking_adapters/rspec.rb +30 -0
  57. data/lib/rspec/core/notifications.rb +100 -0
  58. data/lib/rspec/core/option_parser.rb +11 -18
  59. data/lib/rspec/core/pending.rb +78 -47
  60. data/lib/rspec/core/project_initializer.rb +2 -49
  61. data/lib/rspec/core/project_initializer/dot_rspec +3 -0
  62. data/lib/rspec/core/project_initializer/spec_helper.rb +82 -0
  63. data/lib/rspec/core/rake_task.rb +5 -14
  64. data/lib/rspec/core/reporter.rb +24 -32
  65. data/lib/rspec/core/ruby_project.rb +1 -1
  66. data/lib/rspec/core/runner.rb +14 -4
  67. data/lib/rspec/core/shared_example_group.rb +40 -13
  68. data/lib/rspec/core/version.rb +1 -1
  69. data/spec/command_line/order_spec.rb +15 -15
  70. data/spec/rspec/core/backtrace_formatter_spec.rb +15 -1
  71. data/spec/rspec/core/command_line_spec.rb +18 -17
  72. data/spec/rspec/core/configuration_options_spec.rb +57 -34
  73. data/spec/rspec/core/configuration_spec.rb +162 -184
  74. data/spec/rspec/core/drb_command_line_spec.rb +5 -7
  75. data/spec/rspec/core/drb_options_spec.rb +2 -2
  76. data/spec/rspec/core/dsl_spec.rb +79 -15
  77. data/spec/rspec/core/example_group_spec.rb +253 -39
  78. data/spec/rspec/core/example_spec.rb +149 -33
  79. data/spec/rspec/core/filter_manager_spec.rb +9 -26
  80. data/spec/rspec/core/formatters/base_formatter_spec.rb +2 -5
  81. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +42 -145
  82. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +64 -34
  83. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +15 -28
  84. data/spec/rspec/core/formatters/helpers_spec.rb +2 -2
  85. data/spec/rspec/core/formatters/{html_formatted-1.8.7.html → html_formatted-2.1.0.html} +22 -44
  86. data/spec/rspec/core/formatters/{html_formatted-1.8.7-jruby.html → html_formatted.html} +30 -49
  87. data/spec/rspec/core/formatters/html_formatter_spec.rb +35 -19
  88. data/spec/rspec/core/formatters/json_formatter_spec.rb +42 -40
  89. data/spec/rspec/core/formatters/legacy_formatter_spec.rb +137 -0
  90. data/spec/rspec/core/formatters/progress_formatter_spec.rb +38 -25
  91. data/spec/rspec/core/formatters/snippet_extractor_spec.rb +1 -1
  92. data/spec/rspec/core/formatters_spec.rb +120 -0
  93. data/spec/rspec/core/hooks_filtering_spec.rb +1 -1
  94. data/spec/rspec/core/hooks_spec.rb +13 -2
  95. data/spec/rspec/core/memoized_helpers_spec.rb +17 -8
  96. data/spec/rspec/core/metadata_spec.rb +3 -3
  97. data/spec/rspec/core/option_parser_spec.rb +53 -46
  98. data/spec/rspec/core/ordering_spec.rb +4 -4
  99. data/spec/rspec/core/pending_example_spec.rb +23 -126
  100. data/spec/rspec/core/pending_spec.rb +8 -0
  101. data/spec/rspec/core/project_initializer_spec.rb +8 -41
  102. data/spec/rspec/core/rake_task_spec.rb +15 -4
  103. data/spec/rspec/core/random_spec.rb +1 -1
  104. data/spec/rspec/core/reporter_spec.rb +50 -37
  105. data/spec/rspec/core/resources/formatter_specs.rb +9 -11
  106. data/spec/rspec/core/rspec_matchers_spec.rb +1 -1
  107. data/spec/rspec/core/ruby_project_spec.rb +3 -3
  108. data/spec/rspec/core/runner_spec.rb +65 -23
  109. data/spec/rspec/core/shared_context_spec.rb +4 -4
  110. data/spec/rspec/core/shared_example_group/collection_spec.rb +1 -1
  111. data/spec/rspec/core/shared_example_group_spec.rb +20 -11
  112. data/spec/rspec/core/warnings_spec.rb +1 -1
  113. data/spec/rspec/core/world_spec.rb +10 -10
  114. data/spec/rspec/core_spec.rb +2 -2
  115. data/spec/spec_helper.rb +12 -24
  116. data/spec/support/config_options_helper.rb +1 -3
  117. data/spec/support/formatter_support.rb +83 -0
  118. data/spec/support/isolate_load_path_mutation.rb +1 -2
  119. data/spec/support/isolated_directory.rb +1 -1
  120. data/spec/support/isolated_home_directory.rb +1 -1
  121. data/spec/support/legacy_formatter_using_sub_classing_example.rb +87 -0
  122. data/spec/support/matchers.rb +20 -0
  123. data/spec/support/mathn_integration_support.rb +2 -2
  124. data/spec/support/old_style_formatter_example.rb +69 -0
  125. data/spec/support/shared_example_groups.rb +1 -1
  126. data/spec/support/spec_files.rb +3 -3
  127. metadata +192 -69
  128. metadata.gz.sig +3 -1
  129. checksums.yaml +0 -15
  130. checksums.yaml.gz.sig +0 -2
  131. data/features/configuration/show_failures_in_pending_blocks.feature +0 -61
  132. data/features/pending/pending_examples.feature +0 -229
  133. data/features/subject/implicit_receiver.feature +0 -29
  134. data/lib/rspec/core/mocking/with_absolutely_nothing.rb +0 -11
  135. data/lib/rspec/core/mocking/with_flexmock.rb +0 -27
  136. data/lib/rspec/core/mocking/with_rr.rb +0 -27
  137. data/lib/rspec/core/mocking/with_rspec.rb +0 -27
  138. data/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html +0 -477
  139. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +0 -425
  140. data/spec/rspec/core/formatters/html_formatted-1.9.3-jruby.html +0 -416
  141. data/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html +0 -477
  142. data/spec/rspec/core/formatters/html_formatted-1.9.3.html +0 -419
  143. data/spec/rspec/core/formatters/html_formatted-2.0.0.html +0 -425
  144. data/spec/support/in_sub_process.rb +0 -37
  145. data/spec/support/sandboxed_mock_space.rb +0 -100
@@ -5,31 +5,24 @@ module RSpec
5
5
  module Core
6
6
  # @private
7
7
  class ConfigurationOptions
8
- attr_reader :options
9
-
10
8
  def initialize(args)
11
- @args = args.map {|a|
12
- a.sub("default_path", "default-path").sub("line_number", "line-number")
13
- }
9
+ @args = args.dup
14
10
  end
15
11
 
16
12
  def configure(config)
17
13
  config.filter_manager = filter_manager
18
14
 
19
- config.libs = options[:libs] || []
20
- config.setup_load_path_and_require(options[:requires] || [])
21
-
22
15
  process_options_into config
23
16
  load_formatters_into config
24
17
  end
25
18
 
26
- def parse_options
27
- @options = (file_options << command_line_options << env_options).
19
+ def options
20
+ @options ||= (file_options << command_line_options << env_options).
28
21
  each {|opts|
29
22
  filter_manager.include opts.delete(:inclusion_filter) if opts.has_key?(:inclusion_filter)
30
23
  filter_manager.exclude opts.delete(:exclusion_filter) if opts.has_key?(:exclusion_filter)
31
24
  }.
32
- inject {|h, opts|
25
+ inject(:libs => [], :requires => []) {|h, opts|
33
26
  h.merge(opts) {|k, oldval, newval|
34
27
  [:libs, :requires].include?(k) ? oldval + newval : newval
35
28
  }
@@ -51,24 +44,45 @@ module RSpec
51
44
  :line_numbers, :full_description, :full_backtrace, :tty
52
45
  ].to_set
53
46
 
54
- UNPROCESSABLE_OPTIONS = [:libs, :formatters, :requires].to_set
47
+ UNPROCESSABLE_OPTIONS = [:formatters].to_set
55
48
 
56
49
  def force?(key)
57
50
  !UNFORCED_OPTIONS.include?(key)
58
51
  end
59
52
 
60
- def order(keys, *ordered)
61
- ordered.reverse.each do |key|
53
+ def order(keys)
54
+ OPTIONS_ORDER.reverse.each do |key|
62
55
  keys.unshift(key) if keys.delete(key)
63
56
  end
64
57
  keys
65
58
  end
66
59
 
60
+ OPTIONS_ORDER = [
61
+ # load paths depend on nothing, but must be set before `requires`
62
+ # to support load-path-relative requires.
63
+ :libs,
64
+
65
+ # `files_or_directories_to_run` uses `default_path` so it must be
66
+ # set before it.
67
+ :default_path,
68
+
69
+ # must be set before `requires` to support checking `config.files_to_run`
70
+ # from within `spec_helper.rb` when a `-rspec_helper` option is used.
71
+ :files_or_directories_to_run,
72
+
73
+ # In general, we want to require the specified files as early as possible.
74
+ # The `--require` option is specifically intended to allow early requires.
75
+ # For later requires, they can just put the require in their spec files, but
76
+ # `--require` provides a unique opportunity for users to instruct RSpec to
77
+ # load an extension file early for maximum flexibility.
78
+ :requires
79
+ ]
80
+
67
81
  def process_options_into(config)
68
82
  opts = options.reject { |k, _| UNPROCESSABLE_OPTIONS.include? k }
69
83
 
70
- order(opts.keys, :default_path, :pattern).each do |key|
71
- force?(key) ? config.force(key => opts[key]) : config.send("#{key}=", opts[key])
84
+ order(opts.keys).each do |key|
85
+ force?(key) ? config.force(key => opts[key]) : config.__send__("#{key}=", opts[key])
72
86
  end
73
87
  end
74
88
 
@@ -81,11 +95,11 @@ module RSpec
81
95
  end
82
96
 
83
97
  def env_options
84
- ENV["SPEC_OPTS"] ? Parser.parse!(Shellwords.split(ENV["SPEC_OPTS"])) : {}
98
+ ENV["SPEC_OPTS"] ? Parser.parse(Shellwords.split(ENV["SPEC_OPTS"])) : {}
85
99
  end
86
100
 
87
101
  def command_line_options
88
- @command_line_options ||= Parser.parse!(@args).merge :files_or_directories_to_run => @args
102
+ @command_line_options ||= Parser.parse(@args).merge :files_or_directories_to_run => @args
89
103
  end
90
104
 
91
105
  def custom_options
@@ -1,26 +1,88 @@
1
1
  module RSpec
2
2
  module Core
3
- # Adds the `describe` method to the top-level namespace.
3
+ # DSL defines methods to group examples, most notably `describe`,
4
+ # and exposes them as class methods of {RSpec}. They can also be
5
+ # exposed globally (on `main` and instances of `Module`) through
6
+ # the {Configuration} option `expose_dsl_globally`.
7
+ #
8
+ # By default the methods `describe`, `context` and `example_group`
9
+ # are exposed. These methods define a named context for one or
10
+ # more examples. The given block is evaluated in the context of
11
+ # a generated subclass of {RSpec::Core::ExampleGroup}
12
+ #
13
+ # ## Examples:
14
+ #
15
+ # RSpec.describe "something" do
16
+ # context "when something is a certain way" do
17
+ # it "does something" do
18
+ # # example code goes here
19
+ # end
20
+ # end
21
+ # end
22
+ #
23
+ # @see ExampleGroup
24
+ # @see ExampleGroup.example_group
4
25
  module DSL
5
- # Generates a subclass of {ExampleGroup}
6
- #
7
- # ## Examples:
8
- #
9
- # describe "something" do
10
- # it "does something" do
11
- # # example code goes here
12
- # end
13
- # end
14
- #
15
- # @see ExampleGroup
16
- # @see ExampleGroup.describe
17
- def describe(*args, &example_group_block)
18
- RSpec::Core::ExampleGroup.describe(*args, &example_group_block).register
26
+ # @private
27
+ def self.example_group_aliases
28
+ @example_group_aliases ||= []
19
29
  end
30
+
31
+ # @private
32
+ def self.exposed_globally?
33
+ @exposed_globally ||= false
34
+ end
35
+
36
+ def self.expose_example_group_alias(name)
37
+ example_group_aliases << name
38
+
39
+ (class << RSpec; self; end).__send__(:define_method, name) do |*args, &example_group_block|
40
+ RSpec::Core::ExampleGroup.__send__(name, *args, &example_group_block).register
41
+ end
42
+
43
+ expose_example_group_alias_globally(name) if exposed_globally?
44
+ end
45
+
46
+ class << self
47
+ # @private
48
+ attr_accessor :top_level
49
+ end
50
+
51
+ # Add's the describe method to Module and the top level binding
52
+ def self.expose_globally!
53
+ return if exposed_globally?
54
+
55
+ example_group_aliases.each do |method_name|
56
+ expose_example_group_alias_globally(method_name)
57
+ end
58
+
59
+ @exposed_globally = true
60
+ end
61
+
62
+ def self.remove_globally!
63
+ return unless exposed_globally?
64
+
65
+ example_group_aliases.each do |method_name|
66
+ change_global_dsl { undef_method method_name }
67
+ end
68
+
69
+ @exposed_globally = false
70
+ end
71
+
72
+ def self.expose_example_group_alias_globally(method_name)
73
+ change_global_dsl do
74
+ define_method(method_name) { |*a, &b| ::RSpec.__send__(method_name, *a, &b) }
75
+ end
76
+ end
77
+
78
+ def self.change_global_dsl(&changes)
79
+ (class << top_level; self; end).class_exec(&changes)
80
+ Module.class_exec(&changes)
81
+ end
82
+
20
83
  end
21
84
  end
22
85
  end
23
86
 
24
- extend RSpec::Core::DSL
25
- Module.send(:include, RSpec::Core::DSL)
26
-
87
+ # capture main without an eval
88
+ ::RSpec::Core::DSL.top_level = self
@@ -41,15 +41,18 @@ module RSpec
41
41
  keys.each { |key| define_method(key) { @metadata[key] } }
42
42
  end
43
43
 
44
- delegate_to_metadata :full_description, :execution_result, :file_path, :pending, :location
44
+ delegate_to_metadata :execution_result, :file_path, :full_description,
45
+ :location, :pending, :skip
45
46
 
46
47
  # Returns the string submitted to `example` or its aliases (e.g.
47
- # `specify`, `it`, etc). If no string is submitted (e.g. `it { should
48
+ # `specify`, `it`, etc). If no string is submitted (e.g. `it { is_expected.to
48
49
  # do_something }`) it returns the message generated by the matcher if
49
50
  # there is one, otherwise returns a message including the location of the
50
51
  # example.
51
52
  def description
52
- description = metadata[:description].to_s.empty? ? "example at #{location}" : metadata[:description]
53
+ description = metadata[:description].to_s.empty? ?
54
+ "example at #{location}" :
55
+ metadata[:description]
53
56
  RSpec.configuration.format_docstrings_block.call(description)
54
57
  end
55
58
 
@@ -71,6 +74,10 @@ module RSpec
71
74
  # running this example.
72
75
  attr_reader :example_group_instance
73
76
 
77
+ # @attr_accessor
78
+ # @private
79
+ attr_accessor :clock
80
+
74
81
  # Creates a new instance of Example.
75
82
  # @param example_group_class the subclass of ExampleGroup in which this Example is declared
76
83
  # @param description the String passed to the `it` method (or alias)
@@ -80,7 +87,7 @@ module RSpec
80
87
  @example_group_class, @options, @example_block = example_group_class, metadata, example_block
81
88
  @metadata = @example_group_class.metadata.for_example(description, metadata)
82
89
  @example_group_instance = @exception = nil
83
- @pending_declared_in_example = false
90
+ @clock = RSpec::Core::Time
84
91
  end
85
92
 
86
93
  # @deprecated access options via metadata instead
@@ -95,6 +102,7 @@ module RSpec
95
102
  end
96
103
 
97
104
  alias_method :pending?, :pending
105
+ alias_method :skipped?, :skip
98
106
 
99
107
  # @api private
100
108
  # instance_evals the block passed to the constructor in the context of
@@ -107,13 +115,24 @@ module RSpec
107
115
  start(reporter)
108
116
 
109
117
  begin
110
- unless pending || RSpec.configuration.dry_run?
118
+ if skipped?
119
+ Pending.mark_pending! self, skip
120
+ elsif !RSpec.configuration.dry_run?
111
121
  with_around_each_hooks do
112
122
  begin
113
123
  run_before_each
114
124
  @example_group_instance.instance_exec(self, &@example_block)
115
- rescue Pending::PendingDeclaredInExample => e
116
- @pending_declared_in_example = e.message
125
+
126
+ if pending?
127
+ Pending.mark_fixed! self
128
+
129
+ raise Pending::PendingExampleFixedError,
130
+ 'Expected example to fail since it is pending, but it passed.',
131
+ metadata[:caller]
132
+ end
133
+ rescue Pending::SkipDeclaredInExample
134
+ # no-op, required metadata has already been set by the `skip`
135
+ # method.
117
136
  rescue Exception => e
118
137
  set_exception(e)
119
138
  ensure
@@ -190,7 +209,7 @@ module RSpec
190
209
 
191
210
  # @private
192
211
  def around_each_hooks
193
- @around_each_hooks ||= example_group.around_each_hooks_for(self)
212
+ @around_each_hooks ||= example_group.hooks.around_each_hooks_for(self)
194
213
  end
195
214
 
196
215
  # @private
@@ -198,20 +217,24 @@ module RSpec
198
217
  # Used internally to set an exception in an after hook, which
199
218
  # captures the exception but doesn't raise it.
200
219
  def set_exception(exception, context=nil)
201
- if @exception && context != :dont_print
202
- # An error has already been set; we don't want to override it,
203
- # but we also don't want silence the error, so let's print it.
204
- msg = <<-EOS
220
+ if pending?
221
+ metadata[:execution_result][:pending_exception] = exception
222
+ else
223
+ if @exception && context != :dont_print
224
+ # An error has already been set; we don't want to override it,
225
+ # but we also don't want silence the error, so let's print it.
226
+ msg = <<-EOS
205
227
 
206
- An error occurred #{context}
207
- #{exception.class}: #{exception.message}
208
- occurred at #{exception.backtrace.first}
228
+ An error occurred #{context}
229
+ #{exception.class}: #{exception.message}
230
+ occurred at #{exception.backtrace.first}
209
231
 
210
- EOS
211
- RSpec.configuration.reporter.message(msg)
212
- end
232
+ EOS
233
+ RSpec.configuration.reporter.message(msg)
234
+ end
213
235
 
214
- @exception ||= exception
236
+ @exception ||= exception
237
+ end
215
238
  end
216
239
 
217
240
  # @private
@@ -224,6 +247,16 @@ An error occurred #{context}
224
247
  finish(reporter)
225
248
  end
226
249
 
250
+ # @private
251
+ #
252
+ # Used internally to skip without actually executing the example when
253
+ # skip is used in before(:all)
254
+ def skip_with_exception(reporter, exception)
255
+ start(reporter)
256
+ Pending.mark_skipped! self, exception.argument
257
+ finish(reporter)
258
+ end
259
+
227
260
  # @private
228
261
  def instance_exec_with_rescue(context = nil, &block)
229
262
  @example_group_instance.instance_exec_with_rescue(self, context, &block)
@@ -240,7 +273,7 @@ An error occurred #{context}
240
273
  if around_each_hooks.empty?
241
274
  yield
242
275
  else
243
- @example_group_class.run_around_each_hooks(self, Procsy.new(metadata, &block))
276
+ @example_group_class.hooks.run(:around, :each, self, Procsy.new(metadata, &block))
244
277
  end
245
278
  rescue Exception => e
246
279
  set_exception(e, "in an around(:each) hook")
@@ -248,20 +281,18 @@ An error occurred #{context}
248
281
 
249
282
  def start(reporter)
250
283
  reporter.example_started(self)
251
- record :started_at => RSpec::Core::Time.now
284
+ record :started_at => clock.now
252
285
  end
253
286
 
254
287
  def finish(reporter)
288
+ pending_message = metadata[:execution_result][:pending_message]
289
+
255
290
  if @exception
256
291
  record_finished 'failed', :exception => @exception
257
292
  reporter.example_failed self
258
293
  false
259
- elsif @pending_declared_in_example
260
- record_finished 'pending', :pending_message => @pending_declared_in_example
261
- reporter.example_pending self
262
- true
263
- elsif pending
264
- record_finished 'pending', :pending_message => String === pending ? pending : Pending::NO_REASON_GIVEN
294
+ elsif pending_message
295
+ record_finished 'pending', :pending_message => pending_message
265
296
  reporter.example_pending self
266
297
  true
267
298
  else
@@ -272,17 +303,21 @@ An error occurred #{context}
272
303
  end
273
304
 
274
305
  def record_finished(status, results={})
275
- finished_at = RSpec::Core::Time.now
276
- record results.merge(:status => status, :finished_at => finished_at, :run_time => (finished_at - execution_result[:started_at]).to_f)
306
+ finished_at = clock.now
307
+ record results.merge(
308
+ :status => status,
309
+ :finished_at => finished_at,
310
+ :run_time => (finished_at - execution_result[:started_at]).to_f
311
+ )
277
312
  end
278
313
 
279
314
  def run_before_each
280
315
  @example_group_instance.setup_mocks_for_rspec
281
- @example_group_class.run_before_each_hooks(self)
316
+ @example_group_class.hooks.run(:before, :each, self)
282
317
  end
283
318
 
284
319
  def run_after_each
285
- @example_group_class.run_after_each_hooks(self)
320
+ @example_group_class.hooks.run(:after, :each, self)
286
321
  verify_mocks
287
322
  rescue Exception => e
288
323
  set_exception(e, "in an after(:each) hook")
@@ -293,20 +328,36 @@ An error occurred #{context}
293
328
  def verify_mocks
294
329
  @example_group_instance.verify_mocks_for_rspec
295
330
  rescue Exception => e
296
- set_exception(e, :dont_print)
331
+ if metadata[:execution_result][:pending_message]
332
+ metadata[:execution_result][:pending_fixed] = false
333
+ metadata[:pending] = true
334
+ @exception = nil
335
+ else
336
+ set_exception(e, :dont_print)
337
+ end
297
338
  end
298
339
 
299
340
  def assign_generated_description
300
341
  return unless RSpec.configuration.expecting_with_rspec?
301
- if metadata[:description_args].empty? and !pending?
342
+
343
+ if metadata[:description_args].empty?
302
344
  metadata[:description_args] << RSpec::Matchers.generated_description
303
345
  end
346
+
304
347
  RSpec::Matchers.clear_generated_description
305
348
  end
306
349
 
307
350
  def record(results={})
308
351
  execution_result.update(results)
309
352
  end
353
+
354
+ def skip_message
355
+ if String === skip
356
+ skip
357
+ else
358
+ Pending::NO_REASON_GIVEN
359
+ end
360
+ end
310
361
  end
311
362
  end
312
363
  end
@@ -59,13 +59,41 @@ module RSpec
59
59
  define_method(name) do |*all_args, &block|
60
60
  desc, *args = *all_args
61
61
  options = Metadata.build_hash_from(args)
62
- options.update(:pending => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
62
+ options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
63
63
  options.update(extra_options)
64
+
65
+ # Metadata inheritance normally happens in `Example#initialize`,
66
+ # but for `:pending` specifically we need it earlier.
67
+ pending_metadata = options[:pending] || metadata[:pending]
68
+
69
+ if pending_metadata
70
+ options, block = ExampleGroup.pending_metadata_and_block_for(
71
+ options.merge(:pending => pending_metadata),
72
+ block
73
+ )
74
+ end
75
+
64
76
  examples << RSpec::Core::Example.new(self, desc, options, block)
65
77
  examples.last
66
78
  end
67
79
  end
68
80
 
81
+ def pending_metadata_and_block_for(options, block)
82
+ if String === options[:pending]
83
+ reason = options[:pending]
84
+ else
85
+ options[:pending] = true
86
+ reason = RSpec::Core::Pending::NO_REASON_GIVEN
87
+ end
88
+
89
+ # This will fail if no block is provided, which is effectively the
90
+ # same as failing the example so it will be marked correctly as
91
+ # pending.
92
+ callback = Proc.new { pending(reason); instance_exec(&block) }
93
+
94
+ return options, callback
95
+ end
96
+
69
97
  # Defines an example within a group.
70
98
  # @example
71
99
  # example do
@@ -100,18 +128,21 @@ module RSpec
100
128
  # @see example
101
129
  define_example_method :fit, :focused => true, :focus => true
102
130
 
103
- # Shortcut to define an example with :pending => true
131
+ # Shortcut to define an example with :skip => 'Temporarily skipped with xexample'
104
132
  # @see example
105
- define_example_method :pending, :pending => true
106
- # Shortcut to define an example with :pending => 'Temporarily disabled with xexample'
133
+ define_example_method :xexample, :skip => 'Temporarily skipped with xexample'
134
+ # Shortcut to define an example with :skip => 'Temporarily skipped with xit'
107
135
  # @see example
108
- define_example_method :xexample, :pending => 'Temporarily disabled with xexample'
109
- # Shortcut to define an example with :pending => 'Temporarily disabled with xit'
136
+ define_example_method :xit, :skip => 'Temporarily skipped with xit'
137
+ # Shortcut to define an example with :skip => 'Temporarily skipped with xspecify'
110
138
  # @see example
111
- define_example_method :xit, :pending => 'Temporarily disabled with xit'
112
- # Shortcut to define an example with :pending => 'Temporarily disabled with xspecify'
139
+ define_example_method :xspecify, :skip => 'Temporarily skipped with xspecify'
140
+ # Shortcut to define an example with :skip => true
113
141
  # @see example
114
- define_example_method :xspecify, :pending => 'Temporarily disabled with xspecify'
142
+ define_example_method :skip, :skip => true
143
+ # Shortcut to define an example with :pending => true
144
+ # @see example
145
+ define_example_method :pending, :pending => true
115
146
 
116
147
  # Works like `alias_method :name, :example` with the added benefit of
117
148
  # assigning default metadata to the generated example.
@@ -124,13 +155,30 @@ module RSpec
124
155
  (class << self; self; end).define_example_method name, extra
125
156
  end
126
157
 
158
+ # @private
159
+ # @macro [attach] alias_example_group_to
160
+ # @scope class
161
+ # @param [String] docstring The example group doc string
162
+ # @param [Hash] metadata Additional metadata to attach to the example group
163
+ # @yield The example group definition
164
+ def alias_example_group_to(name, metadata={})
165
+ (class << self; self; end).__send__(:define_method, name) do |*args, &block|
166
+ combined_metadata = metadata.dup
167
+ combined_metadata.merge!(args.pop) if args.last.is_a? Hash
168
+ args << combined_metadata
169
+ example_group(*args, &block)
170
+ end
171
+
172
+ RSpec::Core::DSL.expose_example_group_alias(name)
173
+ end
174
+
127
175
  # @private
128
176
  # @macro [attach] define_nested_shared_group_method
129
177
  #
130
178
  # @see SharedExampleGroup
131
179
  def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
132
180
  define_method(new_name) do |name, *args, &customization_block|
133
- group = describe("#{report_label} #{name}") do
181
+ group = example_group("#{report_label} #{name}") do
134
182
  find_and_eval_shared("examples", name, *args, &customization_block)
135
183
  end
136
184
  group.metadata[:shared_group_name] = name
@@ -218,7 +266,7 @@ module RSpec
218
266
  #
219
267
  # describe "something" do # << This describe method is defined in
220
268
  # # << RSpec::Core::DSL, included in the
221
- # # << global namespace
269
+ # # << global namespace (optional)
222
270
  # before do
223
271
  # do_something_before
224
272
  # end
@@ -232,7 +280,7 @@ module RSpec
232
280
  # end
233
281
  #
234
282
  # @see DSL#describe
235
- def self.describe(*args, &example_group_block)
283
+ def self.example_group(*args, &example_group_block)
236
284
  args << {} unless args.last.is_a?(Hash)
237
285
  args.last.update(:example_group_block => example_group_block)
238
286
 
@@ -241,9 +289,31 @@ module RSpec
241
289
  child
242
290
  end
243
291
 
244
- class << self
245
- alias_method :context, :describe
246
- end
292
+ # An alias of `example_group`. Generally used when grouping
293
+ # examples by a thing you are describing (e.g. an object, class or method).
294
+ # @see example_group
295
+ alias_example_group_to :describe
296
+
297
+ # An alias of `example_group`. Generally used when grouping examples
298
+ # contextually.
299
+ # @see example_group
300
+ alias_example_group_to :context
301
+
302
+ # Shortcut to temporarily make an example group pending.
303
+ # @see example_group
304
+ alias_example_group_to :xdescribe, :skip => "Temporarily skipped with xdescribe"
305
+
306
+ # Shortcut to temporarily make an example group pending.
307
+ # @see example_group
308
+ alias_example_group_to :xcontext, :skip => "Temporarily skipped with xcontext"
309
+
310
+ # Shortcut to define an example group with `:focus` => true
311
+ # @see example_group
312
+ alias_example_group_to :fdescribe, :focus => true, :focused => true
313
+
314
+ # Shortcut to define an example group with `:focus` => true
315
+ # @see example_group
316
+ alias_example_group_to :fcontext, :focus => true, :focused => true
247
317
 
248
318
  # @private
249
319
  def self.subclass(parent, args, &example_group_block)
@@ -324,47 +394,27 @@ module RSpec
324
394
  }
325
395
  end
326
396
 
327
- # @private
328
- def self.assign_before_all_ivars(ivars, example_group_instance)
329
- ivars.each { |ivar, val| example_group_instance.instance_variable_set(ivar, val) }
330
- end
331
-
332
397
  # @private
333
398
  def self.run_before_all_hooks(example_group_instance)
334
399
  return if descendant_filtered_examples.empty?
335
400
  begin
336
- assign_before_all_ivars(superclass.before_all_ivars, example_group_instance)
401
+ set_ivars(example_group_instance, superclass.before_all_ivars)
337
402
 
338
403
  AllHookMemoizedHash::Before.isolate_for_all_hook(example_group_instance) do
339
- run_hook(:before, :all, example_group_instance)
404
+ hooks.run(:before, :all, example_group_instance)
340
405
  end
341
406
  ensure
342
407
  store_before_all_ivars(example_group_instance)
343
408
  end
344
409
  end
345
410
 
346
- # @private
347
- def self.run_around_each_hooks(example, initial_procsy)
348
- run_hook(:around, :each, example, initial_procsy)
349
- end
350
-
351
- # @private
352
- def self.run_before_each_hooks(example)
353
- run_hook(:before, :each, example)
354
- end
355
-
356
- # @private
357
- def self.run_after_each_hooks(example)
358
- run_hook(:after, :each, example)
359
- end
360
-
361
411
  # @private
362
412
  def self.run_after_all_hooks(example_group_instance)
363
413
  return if descendant_filtered_examples.empty?
364
- assign_before_all_ivars(before_all_ivars, example_group_instance)
414
+ set_ivars(example_group_instance, before_all_ivars)
365
415
 
366
416
  AllHookMemoizedHash::After.isolate_for_all_hook(example_group_instance) do
367
- run_hook(:after, :all, example_group_instance)
417
+ hooks.run(:after, :all, example_group_instance)
368
418
  end
369
419
  end
370
420
 
@@ -381,9 +431,11 @@ module RSpec
381
431
  result_for_this_group = run_examples(reporter)
382
432
  results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
383
433
  result_for_this_group && results_for_descendants
434
+ rescue Pending::SkipDeclaredInExample => ex
435
+ for_filtered_examples(reporter) {|example| example.skip_with_exception(reporter, ex) }
384
436
  rescue Exception => ex
385
437
  RSpec.wants_to_quit = true if fail_fast?
386
- fail_filtered_examples(ex, reporter)
438
+ for_filtered_examples(reporter) {|example| example.fail_with_exception(reporter, ex) }
387
439
  ensure
388
440
  run_after_all_hooks(new)
389
441
  before_all_ivars.clear
@@ -420,12 +472,12 @@ module RSpec
420
472
  end
421
473
 
422
474
  # @private
423
- def self.fail_filtered_examples(exception, reporter)
424
- filtered_examples.each { |example| example.fail_with_exception(reporter, exception) }
475
+ def self.for_filtered_examples(reporter, &block)
476
+ filtered_examples.each(&block)
425
477
 
426
478
  children.each do |child|
427
479
  reporter.example_group_started(child)
428
- child.fail_filtered_examples(exception, reporter)
480
+ child.for_filtered_examples(reporter, &block)
429
481
  reporter.example_group_finished(child)
430
482
  end
431
483
  false