rspec-core 3.0.0.beta1 → 3.0.0.beta2

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