rspec-core 2.9.0 → 2.10.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 (33) hide show
  1. data/.yardopts +4 -1
  2. data/Changelog.md +20 -0
  3. data/README.md +10 -4
  4. data/features/command_line/format_option.feature +1 -1
  5. data/features/expectation_framework_integration/configure_expectation_framework.feature +20 -7
  6. data/features/hooks/around_hooks.feature +1 -1
  7. data/features/hooks/before_and_after_hooks.feature +5 -5
  8. data/features/hooks/filtering.feature +2 -2
  9. data/features/pending/pending_examples.feature +2 -2
  10. data/lib/rspec/core/configuration_options.rb +4 -3
  11. data/lib/rspec/core/example.rb +37 -22
  12. data/lib/rspec/core/example_group.rb +18 -20
  13. data/lib/rspec/core/formatters/base_formatter.rb +2 -8
  14. data/lib/rspec/core/formatters/base_text_formatter.rb +13 -4
  15. data/lib/rspec/core/hooks.rb +120 -77
  16. data/lib/rspec/core/let.rb +14 -6
  17. data/lib/rspec/core/metadata.rb +10 -2
  18. data/lib/rspec/core/subject.rb +34 -13
  19. data/lib/rspec/core/version.rb +1 -1
  20. data/lib/rspec/core/world.rb +0 -4
  21. data/spec/rspec/core/configuration_options_spec.rb +8 -2
  22. data/spec/rspec/core/drb_options_spec.rb +1 -1
  23. data/spec/rspec/core/example_group_spec.rb +2 -2
  24. data/spec/rspec/core/example_spec.rb +39 -16
  25. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +17 -7
  26. data/spec/rspec/core/hooks_spec.rb +117 -10
  27. data/spec/rspec/core/metadata_spec.rb +13 -3
  28. data/spec/rspec/core/pending_example_spec.rb +3 -2
  29. data/spec/rspec/core/subject_spec.rb +2 -0
  30. data/spec/spec_helper.rb +1 -0
  31. data/spec/support/config_options_helper.rb +0 -3
  32. data/spec/support/helper_methods.rb +5 -0
  33. metadata +153 -142
data/.yardopts CHANGED
@@ -1,3 +1,6 @@
1
- --no-private
2
1
  --exclude features
2
+ --no-private
3
3
  --markup markdown
4
+ -
5
+ Changelog.md
6
+ License.txt
data/Changelog.md CHANGED
@@ -1,3 +1,23 @@
1
+ ### 2.10.0 / 2012-05-03
2
+ [full changelog](http://github.com/rspec/rspec-core/compare/v2.9.0...v2.10.0)
3
+
4
+ Enhancements
5
+
6
+ * Add `prepend_before` and `append_after` hooks (preethiramdev)
7
+ * intended for extension libs
8
+ * restores rspec-1 behavior
9
+ * Reporting of profiled examples (moro)
10
+ * Report the total amount of time taken for the top slowest examples.
11
+ * Report what percentage the slowest examples took from the total runtime.
12
+
13
+ Bug fixes
14
+
15
+ * Properly parse `SPEC_OPTS` options.
16
+ * `example.description` returns the location of the example if there is no
17
+ explicit description or matcher-generated description.
18
+ * RDoc fixes (Grzegorz Świrski)
19
+ * Do not modify example ancestry when dumping errors (Michael Grosser)
20
+
1
21
  ### 2.9.0 / 2012-03-17
2
22
  [full changelog](http://github.com/rspec/rspec-core/compare/v2.8.0...v2.9.0)
3
23
 
data/README.md CHANGED
@@ -154,11 +154,17 @@ end
154
154
  When you install the rspec-core gem, it installs the `rspec` executable,
155
155
  which you'll use to run rspec. The `rspec` comes with many useful options.
156
156
  Run `rspec --help` to see the complete list.
157
- ## see also
158
157
 
159
- * [http://github.com/rspec/rspec](http://github.com/rspec/rspec)
160
- * [http://github.com/rspec/rspec-expectations](http://github.com/rspec/rspec-expectations)
161
- * [http://github.com/rspec/rspec-mocks](http://github.com/rspec/rspec-mocks)
158
+ ## store command line options `.rspec`
159
+
160
+ You can store command line options in a `.rspec` file in the project's root
161
+ directory, and the `rspec` command will read them as though you typed them on
162
+ the command line.
163
+
164
+ ## autotest integration
165
+
166
+ rspec-core ships with an Autotest extension, which is loaded automatically if
167
+ there is a `.rspec` file in the project's root directory.
162
168
 
163
169
  ## get started
164
170
 
@@ -46,7 +46,7 @@ Feature: --format option
46
46
  """
47
47
 
48
48
  Scenario: progress bar format (default)
49
- When I run `rspec example_spec.rb`
49
+ When I run `rspec --format progress example_spec.rb`
50
50
  Then the output should contain ".F*"
51
51
 
52
52
  Scenario: documentation format
@@ -29,7 +29,7 @@ Feature: configure expectation framework
29
29
  When I run `rspec example_spec.rb`
30
30
  Then the examples should all pass
31
31
 
32
- Scenario: configure test/unit assertions
32
+ Scenario: configure test/unit assertions (passing examples)
33
33
  Given a file named "example_spec.rb" with:
34
34
  """
35
35
  RSpec.configure do |config|
@@ -45,12 +45,25 @@ Feature: configure expectation framework
45
45
  end
46
46
  """
47
47
  When I run `rspec example_spec.rb`
48
- Then the output should contain "2 examples, 1 failure"
49
- And the output should contain:
50
- """
51
- NotImplementedError:
52
- Generated descriptions are only supported when you use rspec-expectations.
53
- """
48
+ Then the output should contain "2 examples, 0 failures"
49
+
50
+ Scenario: configure test/unit assertions (failing examples)
51
+ Given a file named "example_spec.rb" with:
52
+ """
53
+ RSpec.configure do |config|
54
+ config.expect_with :stdlib
55
+ end
56
+
57
+ describe 5 do
58
+ it "is greater than 6 (no it isn't!)" do
59
+ assert 5 > 6, "errantly expected 5 to be greater than 5"
60
+ end
61
+
62
+ specify { assert 5 > 6 }
63
+ end
64
+ """
65
+ When I run `rspec example_spec.rb`
66
+ Then the output should contain "2 examples, 2 failures"
54
67
 
55
68
  Scenario: configure rspec/expecations AND test/unit assertions
56
69
  Given a file named "example_spec.rb" with:
@@ -165,7 +165,7 @@ Feature: around hooks
165
165
  end
166
166
  end
167
167
  """
168
- When I run `rspec example_spec.rb`
168
+ When I run `rspec --format progress example_spec.rb`
169
169
  Then the output should contain:
170
170
  """
171
171
  before all
@@ -227,7 +227,7 @@ Feature: before and after hooks
227
227
  end
228
228
  end
229
229
  """
230
- When I run `rspec ensure_block_order_spec.rb`
230
+ When I run `rspec --format progress ensure_block_order_spec.rb`
231
231
  Then the output should contain:
232
232
  """
233
233
  before all
@@ -272,7 +272,7 @@ Feature: before and after hooks
272
272
  end
273
273
  end
274
274
  """
275
- When I run `rspec configuration_spec.rb`
275
+ When I run `rspec --format progress configuration_spec.rb`
276
276
  Then the output should contain:
277
277
  """
278
278
  before suite
@@ -313,7 +313,7 @@ Feature: before and after hooks
313
313
 
314
314
  end
315
315
  """
316
- When I run `rspec before_and_after_all_spec.rb`
316
+ When I run `rspec --format progress before_and_after_all_spec.rb`
317
317
  Then the examples should all pass
318
318
  And the output should contain:
319
319
  """
@@ -323,7 +323,7 @@ Feature: before and after hooks
323
323
  outer after all
324
324
  """
325
325
 
326
- When I run `rspec before_and_after_all_spec.rb:14`
326
+ When I run `rspec --format progress before_and_after_all_spec.rb:14`
327
327
  Then the examples should all pass
328
328
  And the output should contain:
329
329
  """
@@ -333,7 +333,7 @@ Feature: before and after hooks
333
333
  outer after all
334
334
  """
335
335
 
336
- When I run `rspec before_and_after_all_spec.rb:6`
336
+ When I run `rspec --format progress before_and_after_all_spec.rb:6`
337
337
  Then the examples should all pass
338
338
  And the output should contain:
339
339
  """
@@ -182,7 +182,7 @@ Feature: filters
182
182
  end
183
183
  end
184
184
  """
185
- When I run `rspec filter_after_all_hooks_spec.rb`
185
+ When I run `rspec --format progress filter_after_all_hooks_spec.rb`
186
186
  Then the examples should all pass
187
187
  And the output should contain:
188
188
  """
@@ -216,7 +216,7 @@ Feature: filters
216
216
  it("", :around_each) { puts "example 4" }
217
217
  end
218
218
  """
219
- When I run `rspec less_verbose_metadata_filter.rb`
219
+ When I run `rspec --format progress less_verbose_metadata_filter.rb`
220
220
  Then the examples should all pass
221
221
  And the output should contain:
222
222
  """
@@ -127,7 +127,7 @@ Feature: pending examples
127
127
  """
128
128
  an example
129
129
  checks something
130
- (PENDING: No reason given)
130
+ example at ./pending_with_no_docstring_spec.rb:5 (PENDING: No reason given)
131
131
  """
132
132
 
133
133
  Scenario: pending with no docstring using documentation formatter
@@ -149,7 +149,7 @@ Feature: pending examples
149
149
  """
150
150
  an example
151
151
  checks something
152
- (PENDING: No reason given)
152
+ example at ./pending_with_no_docstring_spec.rb:5 (PENDING: No reason given)
153
153
  """
154
154
 
155
155
  Scenario: conditionally pending examples
@@ -1,4 +1,5 @@
1
1
  require 'erb'
2
+ require 'shellwords'
2
3
 
3
4
  module RSpec
4
5
  module Core
@@ -16,7 +17,7 @@ module RSpec
16
17
  config.filter_manager = filter_manager
17
18
 
18
19
  order(options.keys, :libs, :requires, :default_path, :pattern).each do |key|
19
- force?(key) ? config.force(key => options[key]) : config.send("#{key}=", options[key])
20
+ force?(key) ? config.force(key => options[key]) : config.send("#{key}=", options[key])
20
21
  end
21
22
 
22
23
  formatters.each {|pair| config.add_formatter(*pair) } if formatters
@@ -70,7 +71,7 @@ module RSpec
70
71
  end
71
72
 
72
73
  def env_options
73
- ENV["SPEC_OPTS"] ? Parser.parse!(ENV["SPEC_OPTS"].split) : {}
74
+ ENV["SPEC_OPTS"] ? Parser.parse!(Shellwords.split(ENV["SPEC_OPTS"])) : {}
74
75
  end
75
76
 
76
77
  def command_line_options
@@ -96,7 +97,7 @@ module RSpec
96
97
  def args_from_options_file(path)
97
98
  return [] unless path && File.exist?(path)
98
99
  config_string = options_file_as_erb_string(path)
99
- config_string.split(/\n+/).map {|l| l.split}.flatten
100
+ config_string.split(/\n+/).map {|l| l.shellsplit}.flatten
100
101
  end
101
102
 
102
103
  def options_file_as_erb_string(path)
@@ -12,12 +12,19 @@ module RSpec
12
12
  #
13
13
  # Used to define methods that delegate to this example's metadata
14
14
  def self.delegate_to_metadata(*keys)
15
- keys.each do |key|
16
- define_method(key) {@metadata[key]}
17
- end
15
+ keys.each { |key| define_method(key) { @metadata[key] } }
18
16
  end
19
17
 
20
- delegate_to_metadata :description, :full_description, :execution_result, :file_path, :pending, :location
18
+ delegate_to_metadata :full_description, :execution_result, :file_path, :pending, :location
19
+
20
+ # Returns the string submitted to `example` or its aliases (e.g.
21
+ # `specify`, `it`, etc). If no string is submitted (e.g. `it { should
22
+ # do_something }`) it returns the message generated by the matcher if
23
+ # there is one, otherwise returns a message including the location of the
24
+ # example.
25
+ def description
26
+ metadata[:description].to_s.empty? ? "example at #{location}" : metadata[:description]
27
+ end
21
28
 
22
29
  # @attr_reader
23
30
  #
@@ -74,7 +81,7 @@ module RSpec
74
81
 
75
82
  begin
76
83
  unless pending
77
- with_around_hooks do
84
+ with_around_each_hooks do
78
85
  begin
79
86
  run_before_each
80
87
  @example_group_instance.instance_eval(&@example_block)
@@ -110,7 +117,7 @@ module RSpec
110
117
  # Wraps the example block in a Proc so it can invoked using `run` or
111
118
  # `call` in [around](../Hooks#around-instance_method) hooks.
112
119
  def self.procsy(metadata, &proc)
113
- Proc.new(&proc).extend(Procsy).with(metadata)
120
+ proc.extend(Procsy).with(metadata)
114
121
  end
115
122
 
116
123
  # @private
@@ -144,8 +151,8 @@ module RSpec
144
151
  end
145
152
 
146
153
  # @private
147
- def around_hooks
148
- @around_hooks ||= example_group.around_hooks_for(self)
154
+ def around_each_hooks
155
+ @around_each_hooks ||= example_group.around_each_hooks_for(self)
149
156
  end
150
157
 
151
158
  # @private
@@ -166,13 +173,28 @@ module RSpec
166
173
  finish(reporter)
167
174
  end
168
175
 
176
+ # @private
177
+ def instance_eval(&block)
178
+ @example_group_instance.instance_eval(&block)
179
+ end
180
+
181
+ # @private
182
+ def instance_eval_with_rescue(&block)
183
+ @example_group_instance.instance_eval_with_rescue(&block)
184
+ end
185
+
186
+ # @private
187
+ def instance_eval_with_args(*args, &block)
188
+ @example_group_instance.instance_eval_with_args(*args, &block)
189
+ end
190
+
169
191
  private
170
192
 
171
- def with_around_hooks(&block)
172
- if around_hooks.empty?
193
+ def with_around_each_hooks(&block)
194
+ if around_each_hooks.empty?
173
195
  yield
174
196
  else
175
- @example_group_class.run_around_each_hooks(self, Example.procsy(metadata, &block)).call
197
+ @example_group_class.run_around_each_hooks(self, Example.procsy(metadata, &block))
176
198
  end
177
199
  end
178
200
 
@@ -225,23 +247,16 @@ module RSpec
225
247
  end
226
248
 
227
249
  def assign_auto_description
228
- if description.empty? and !pending?
229
- if RSpec.configuration.expecting_with_rspec?
230
- metadata[:description] = RSpec::Matchers.generated_description
231
- RSpec::Matchers.clear_generated_description
232
- else
233
- raise NotImplementedError.new(
234
- "Generated descriptions are only supported when you use rspec-expectations. " +
235
- "You must give every example an explicit description."
236
- )
237
- end
250
+ return unless RSpec.configuration.expecting_with_rspec?
251
+ if metadata[:description].empty? and !pending?
252
+ metadata[:description] = RSpec::Matchers.generated_description
238
253
  end
254
+ RSpec::Matchers.clear_generated_description
239
255
  end
240
256
 
241
257
  def record(results={})
242
258
  execution_result.update(results)
243
259
  end
244
-
245
260
  end
246
261
  end
247
262
  end
@@ -247,6 +247,19 @@ module RSpec
247
247
  args.unshift(symbol_description) if symbol_description
248
248
  @metadata = RSpec::Core::Metadata.new(superclass_metadata).process(*args)
249
249
  world.configure_group(self)
250
+ [:before, :after, :around].each do |_when|
251
+ RSpec.configuration.hooks[_when][:each].each do |hook|
252
+ unless ancestors.any? {|a| a.hooks[_when][:each].include? hook }
253
+ hooks[_when][:each] << hook # each's get filtered later per example
254
+ end
255
+ end
256
+ next if _when == :around # no around(:all) hooks
257
+ RSpec.configuration.hooks[_when][:all].each do |hook|
258
+ unless ancestors.any? {|a| a.hooks[_when][:all].include? hook }
259
+ hooks[_when][:all] << hook if hook.options_apply?(self)
260
+ end
261
+ end
262
+ end
250
263
  end
251
264
 
252
265
  # @private
@@ -264,7 +277,6 @@ module RSpec
264
277
 
265
278
  # @private
266
279
  def self.assign_before_all_ivars(ivars, example_group_instance)
267
- return if ivars.empty?
268
280
  ivars.each { |ivar, val| example_group_instance.instance_variable_set(ivar, val) }
269
281
  end
270
282
 
@@ -272,30 +284,23 @@ module RSpec
272
284
  def self.run_before_all_hooks(example_group_instance)
273
285
  return if descendant_filtered_examples.empty?
274
286
  assign_before_all_ivars(superclass.before_all_ivars, example_group_instance)
275
- world.run_hook_filtered(:before, :all, self, example_group_instance)
276
- run_hook!(:before, :all, example_group_instance)
287
+ run_hook(:before, :all, example_group_instance)
277
288
  store_before_all_ivars(example_group_instance)
278
289
  end
279
290
 
280
291
  # @private
281
292
  def self.run_around_each_hooks(example, initial_procsy)
282
- example.around_hooks.reverse.inject(initial_procsy) do |procsy, around_hook|
283
- Example.procsy(procsy.metadata) do
284
- example.example_group_instance.instance_eval_with_args(procsy, &around_hook)
285
- end
286
- end
293
+ run_hook(:around, :each, example, initial_procsy)
287
294
  end
288
295
 
289
296
  # @private
290
297
  def self.run_before_each_hooks(example)
291
- world.run_hook_filtered(:before, :each, self, example.example_group_instance, example)
292
- ancestors.reverse.each { |ancestor| ancestor.run_hook(:before, :each, example.example_group_instance) }
298
+ run_hook(:before, :each, example)
293
299
  end
294
300
 
295
301
  # @private
296
302
  def self.run_after_each_hooks(example)
297
- ancestors.each { |ancestor| ancestor.run_hook(:after, :each, example.example_group_instance) }
298
- world.run_hook_filtered(:after, :each, self, example.example_group_instance, example)
303
+ run_hook(:after, :each, example)
299
304
  end
300
305
 
301
306
  # @private
@@ -304,7 +309,7 @@ module RSpec
304
309
  assign_before_all_ivars(before_all_ivars, example_group_instance)
305
310
 
306
311
  begin
307
- run_hook!(:after, :all, example_group_instance)
312
+ run_hook(:after, :all, example_group_instance)
308
313
  rescue => e
309
314
  # TODO: come up with a better solution for this.
310
315
  RSpec.configuration.reporter.message <<-EOS
@@ -315,13 +320,6 @@ An error occurred in an after(:all) hook.
315
320
 
316
321
  EOS
317
322
  end
318
-
319
- world.run_hook_filtered(:after, :all, self, example_group_instance)
320
- end
321
-
322
- # @private
323
- def self.around_hooks_for(example)
324
- world.find_hook(:around, :each, self, example) + ancestors.reverse.inject([]){|l,a| l + a.find_hook(:around, :each, self, example)}
325
323
  end
326
324
 
327
325
  # Runs all the examples in this group
@@ -12,13 +12,6 @@ module RSpec
12
12
  attr_reader :example_count, :pending_count, :failure_count
13
13
  attr_reader :failed_examples, :pending_examples
14
14
 
15
- def self.relative_path(line)
16
- line = line.sub(File.expand_path("."), ".")
17
- line = line.sub(/\A([^:]+:\d+)$/, '\\1')
18
- return nil if line == '-e:1'
19
- line
20
- end
21
-
22
15
  def initialize(output)
23
16
  @output = output || StringIO.new
24
17
  @example_count = @pending_count = @failure_count = 0
@@ -123,7 +116,7 @@ module RSpec
123
116
 
124
117
  def backtrace_line(line)
125
118
  return nil if configuration.cleaned_from_backtrace?(line)
126
- self.class.relative_path(line)
119
+ RSpec::Core::Metadata::relative_path(line)
127
120
  end
128
121
 
129
122
  def read_failed_line(exception, example)
@@ -141,6 +134,7 @@ module RSpec
141
134
  end
142
135
 
143
136
  def find_failed_line(backtrace, path)
137
+ path = File.expand_path(path)
144
138
  backtrace.detect { |line|
145
139
  match = line.match(/(.+?):(\d+)(|:\d+)/)
146
140
  match && match[1].downcase == path.downcase