rspec-core 2.9.0 → 2.10.0

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