rspec-core 3.0.4 → 3.1.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 (55) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +67 -0
  5. data/lib/rspec/core.rb +3 -1
  6. data/lib/rspec/core/backtrace_formatter.rb +13 -10
  7. data/lib/rspec/core/configuration.rb +123 -57
  8. data/lib/rspec/core/configuration_options.rb +12 -12
  9. data/lib/rspec/core/drb.rb +11 -11
  10. data/lib/rspec/core/dsl.rb +0 -1
  11. data/lib/rspec/core/example.rb +39 -12
  12. data/lib/rspec/core/example_group.rb +31 -98
  13. data/lib/rspec/core/filter_manager.rb +16 -17
  14. data/lib/rspec/core/formatters.rb +14 -13
  15. data/lib/rspec/core/formatters/base_formatter.rb +8 -113
  16. data/lib/rspec/core/formatters/base_text_formatter.rb +3 -5
  17. data/lib/rspec/core/formatters/console_codes.rb +1 -2
  18. data/lib/rspec/core/formatters/deprecation_formatter.rb +2 -3
  19. data/lib/rspec/core/formatters/documentation_formatter.rb +3 -4
  20. data/lib/rspec/core/formatters/helpers.rb +5 -6
  21. data/lib/rspec/core/formatters/html_formatter.rb +20 -19
  22. data/lib/rspec/core/formatters/html_printer.rb +6 -5
  23. data/lib/rspec/core/formatters/json_formatter.rb +3 -2
  24. data/lib/rspec/core/formatters/profile_formatter.rb +0 -2
  25. data/lib/rspec/core/formatters/progress_formatter.rb +4 -4
  26. data/lib/rspec/core/formatters/protocol.rb +163 -0
  27. data/lib/rspec/core/formatters/snippet_extractor.rb +7 -6
  28. data/lib/rspec/core/hooks.rb +25 -10
  29. data/lib/rspec/core/memoized_helpers.rb +7 -5
  30. data/lib/rspec/core/metadata.rb +29 -30
  31. data/lib/rspec/core/metadata_filter.rb +66 -66
  32. data/lib/rspec/core/minitest_assertions_adapter.rb +1 -1
  33. data/lib/rspec/core/mocking_adapters/flexmock.rb +3 -1
  34. data/lib/rspec/core/mocking_adapters/mocha.rb +3 -1
  35. data/lib/rspec/core/mocking_adapters/null.rb +2 -0
  36. data/lib/rspec/core/mocking_adapters/rr.rb +3 -1
  37. data/lib/rspec/core/mocking_adapters/rspec.rb +3 -1
  38. data/lib/rspec/core/notifications.rb +36 -29
  39. data/lib/rspec/core/option_parser.rb +29 -25
  40. data/lib/rspec/core/ordering.rb +8 -9
  41. data/lib/rspec/core/pending.rb +6 -8
  42. data/lib/rspec/core/project_initializer.rb +4 -2
  43. data/lib/rspec/core/project_initializer/.rspec +0 -1
  44. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +37 -26
  45. data/lib/rspec/core/rake_task.rb +37 -19
  46. data/lib/rspec/core/reporter.rb +13 -16
  47. data/lib/rspec/core/ruby_project.rb +2 -2
  48. data/lib/rspec/core/runner.rb +11 -14
  49. data/lib/rspec/core/shared_example_group.rb +14 -13
  50. data/lib/rspec/core/test_unit_assertions_adapter.rb +1 -1
  51. data/lib/rspec/core/version.rb +1 -1
  52. data/lib/rspec/core/warnings.rb +4 -4
  53. data/lib/rspec/core/world.rb +22 -24
  54. metadata +6 -5
  55. metadata.gz.sig +0 -0
@@ -27,12 +27,14 @@ module RSpec
27
27
  end
28
28
 
29
29
  def print_example_passed(description, run_time)
30
- formatted_run_time = sprintf("%.5f", run_time)
30
+ formatted_run_time = "%.5f" % run_time
31
31
  @output.puts " <dd class=\"example passed\"><span class=\"passed_spec_name\">#{h(description)}</span><span class='duration'>#{formatted_run_time}s</span></dd>"
32
32
  end
33
33
 
34
- def print_example_failed(pending_fixed, description, run_time, failure_id, exception, extra_content, escape_backtrace = false)
35
- formatted_run_time = sprintf("%.5f", run_time)
34
+ # rubocop:disable Style/ParameterLists
35
+ def print_example_failed(pending_fixed, description, run_time, failure_id, exception, extra_content, escape_backtrace=false)
36
+ # rubocop:enable Style/ParameterLists
37
+ formatted_run_time = "%.5f" % run_time
36
38
 
37
39
  @output.puts " <dd class=\"example #{pending_fixed ? 'pending_fixed' : 'failed'}\">"
38
40
  @output.puts " <span class=\"failed_spec_name\">#{h(description)}</span>"
@@ -60,7 +62,7 @@ module RSpec
60
62
  totals << "#{failure_count} failure#{'s' unless failure_count == 1}"
61
63
  totals << ", #{pending_count} pending" if pending_count > 0
62
64
 
63
- formatted_duration = sprintf("%.5f", duration)
65
+ formatted_duration = "%.5f" % duration
64
66
 
65
67
  @output.puts "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{formatted_duration} seconds</strong>\";</script>"
66
68
  @output.puts "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
@@ -395,7 +397,6 @@ EOF
395
397
  </head>
396
398
  <body>
397
399
  EOF
398
-
399
400
  end
400
401
  end
401
402
  end
@@ -32,7 +32,8 @@ module RSpec
32
32
  def stop(notification)
33
33
  @output_hash[:examples] = notification.examples.map do |example|
34
34
  format_example(example).tap do |hash|
35
- if e=example.exception
35
+ e = example.exception
36
+ if e
36
37
  hash[:exception] = {
37
38
  :class => e.class.name,
38
39
  :message => e.message,
@@ -43,7 +44,7 @@ module RSpec
43
44
  end
44
45
  end
45
46
 
46
- def close(notification)
47
+ def close(_notification)
47
48
  output.write @output_hash.to_json
48
49
  output.close if IO === output && output != $stdout
49
50
  end
@@ -3,7 +3,6 @@ RSpec::Support.require_rspec_core "formatters/console_codes"
3
3
  module RSpec
4
4
  module Core
5
5
  module Formatters
6
-
7
6
  # @api private
8
7
  # Formatter for providing profile output
9
8
  class ProfileFormatter
@@ -60,7 +59,6 @@ module RSpec
60
59
  def bold(text)
61
60
  ConsoleCodes.wrap(text, :bold)
62
61
  end
63
-
64
62
  end
65
63
  end
66
64
  end
@@ -7,19 +7,19 @@ module RSpec
7
7
  class ProgressFormatter < BaseTextFormatter
8
8
  Formatters.register self, :example_passed, :example_pending, :example_failed, :start_dump
9
9
 
10
- def example_passed(notification)
10
+ def example_passed(_notification)
11
11
  output.print ConsoleCodes.wrap('.', :success)
12
12
  end
13
13
 
14
- def example_pending(notification)
14
+ def example_pending(_notification)
15
15
  output.print ConsoleCodes.wrap('*', :pending)
16
16
  end
17
17
 
18
- def example_failed(notification)
18
+ def example_failed(_notification)
19
19
  output.print ConsoleCodes.wrap('F', :failure)
20
20
  end
21
21
 
22
- def start_dump(notification)
22
+ def start_dump(_notification)
23
23
  output.puts
24
24
  end
25
25
  end
@@ -0,0 +1,163 @@
1
+ module RSpec
2
+ module Core
3
+ module Formatters
4
+ # This class isn't loaded at runtime but serves to document all of the
5
+ # notifications implemented as part of the standard interface. The
6
+ # reporter will issue these during a normal test suite run, but a
7
+ # formatter will only receive those notifications it has registered
8
+ # itself to receive. To register a formatter call:
9
+ #
10
+ # `::RSpec::Core::Formatters.register class, :list, :of, :notifications`
11
+ #
12
+ # e.g.
13
+ #
14
+ # `::RSpec::Core::Formatters.register self, :start, :example_started`
15
+ #
16
+ # @see RSpec::Core::Formatters::BaseFormatter
17
+ # @see RSpec::Core::Formatters::BaseTextFormatter
18
+ # @see RSpec::Core::Reporter
19
+ class Protocol
20
+ # @method initialize
21
+ # @api public
22
+ #
23
+ # @param output [IO] the formatter output
24
+
25
+ # @method start
26
+ # @api public
27
+ # @group Suite Notifications
28
+ #
29
+ # This method is invoked before any examples are run, right after
30
+ # they have all been collected. This can be useful for special
31
+ # formatters that need to provide progress on feedback (graphical ones).
32
+ #
33
+ # This will only be invoked once, and the next one to be invoked
34
+ # is {#example_group_started}.
35
+ #
36
+ # @param notification [StartNotification]
37
+
38
+ # @method example_group_started
39
+ # @api public
40
+ # @group Group Notifications
41
+ #
42
+ # This method is invoked at the beginning of the execution of each example group.
43
+ #
44
+ # The next method to be invoked after this is {#example_passed},
45
+ # {#example_pending}, or {#example_group_finished}.
46
+ #
47
+ # @param notification [GroupNotification] containing example_group subclass of `RSpec::Core::ExampleGroup`
48
+
49
+ # @method example_group_finished
50
+ # @api public
51
+ # @group Group Notifications
52
+ #
53
+ # Invoked at the end of the execution of each example group.
54
+ #
55
+ # @param notification [GroupNotification] containing example_group subclass of `RSpec::Core::ExampleGroup`
56
+
57
+ # @method example_started
58
+ # @api public
59
+ # @group Example Notifications
60
+ #
61
+ # Invoked at the beginning of the execution of each example.
62
+ #
63
+ # @param notification [ExampleNotification] containing example subclass of `RSpec::Core::Example`
64
+
65
+ # @method example_passed
66
+ # @api public
67
+ # @group Example Notifications
68
+ #
69
+ # Invoked when an example passes.
70
+ #
71
+ # @param notification [ExampleNotification] containing example subclass of `RSpec::Core::Example`
72
+
73
+ # @method example_pending
74
+ # @api public
75
+ # @group Example Notifications
76
+ #
77
+ # Invoked when an example is pending.
78
+ #
79
+ # @param notification [ExampleNotification] containing example subclass of `RSpec::Core::Example`
80
+
81
+ # @method example_failed
82
+ # @api public
83
+ # @group Example Notifications
84
+ #
85
+ # Invoked when an example fails.
86
+ #
87
+ # @param notification [ExampleNotification] containing example subclass of `RSpec::Core::Example`
88
+
89
+ # @method message
90
+ # @api public
91
+ # @group Suite Notifications
92
+ #
93
+ # Used by the reporter to send messages to the output stream.
94
+ #
95
+ # @param notification [MessageNotification] containing message
96
+
97
+ # @method stop
98
+ # @api public
99
+ # @group Suite Notifications
100
+ #
101
+ # Invoked after all examples have executed, before dumping post-run reports.
102
+ #
103
+ # @param notification [NullNotification]
104
+
105
+ # @method start_dump
106
+ # @api public
107
+ # @group Suite Notifications
108
+ #
109
+ # This method is invoked after all of the examples have executed. The next method
110
+ # to be invoked after this one is {#dump_failures}
111
+ # (BaseTextFormatter then calls {#dump_failure} once for each failed example.)
112
+ #
113
+ # @param notification [NullNotification]
114
+
115
+ # @method dump_failures
116
+ # @api public
117
+ # @group Suite Notifications
118
+ #
119
+ # Dumps detailed information about each example failure.
120
+ #
121
+ # @param notification [NullNotification]
122
+
123
+ # @method dump_summary
124
+ # @api public
125
+ # @group Suite Notifications
126
+ #
127
+ # This method is invoked after the dumping of examples and failures. Each parameter
128
+ # is assigned to a corresponding attribute.
129
+ #
130
+ # @param summary [SummaryNotification] containing duration, example_count,
131
+ # failure_count and pending_count
132
+
133
+ # @method dump_profile
134
+ # @api public
135
+ # @group Suite Notifications
136
+ #
137
+ # This method is invoked after the dumping the summary if profiling is
138
+ # enabled.
139
+ #
140
+ # @param profile [ProfileNotification] containing duration, slowest_examples
141
+ # and slowest_example_groups
142
+
143
+ # @method dump_pending
144
+ # @api public
145
+ # @group Suite Notifications
146
+ #
147
+ # Outputs a report of pending examples. This gets invoked
148
+ # after the summary if option is set to do so.
149
+ #
150
+ # @param notification [NullNotification]
151
+
152
+ # @method close
153
+ # @api public
154
+ # @group Suite Notifications
155
+ #
156
+ # Invoked at the very end, `close` allows the formatter to clean
157
+ # up resources, e.g. open streams, etc.
158
+ #
159
+ # @param notification [NullNotification]
160
+ end
161
+ end
162
+ end
163
+ end
@@ -21,10 +21,12 @@ module RSpec
21
21
 
22
22
  begin
23
23
  require 'coderay'
24
+ # rubocop:disable Style/ClassVars
24
25
  @@converter = CoderayConverter.new
25
26
  rescue LoadError
26
27
  @@converter = NullConverter.new
27
28
  end
29
+ # rubocop:enable Style/ClassVars
28
30
 
29
31
  # @api private
30
32
  #
@@ -50,8 +52,8 @@ module RSpec
50
52
  # @see #lines_around
51
53
  def snippet_for(error_line)
52
54
  if error_line =~ /(.*):(\d+)/
53
- file = $1
54
- line = $2.to_i
55
+ file = Regexp.last_match[1]
56
+ line = Regexp.last_match[2].to_i
55
57
  [lines_around(file, line), line]
56
58
  else
57
59
  ["# Couldn't get snippet for #{error_line}", 1]
@@ -68,8 +70,8 @@ module RSpec
68
70
  def lines_around(file, line)
69
71
  if File.file?(file)
70
72
  lines = File.read(file).split("\n")
71
- min = [0, line-3].max
72
- max = [line+1, lines.length-1].min
73
+ min = [0, line - 3].max
74
+ max = [line + 1, lines.length - 1].min
73
75
  selected_lines = []
74
76
  selected_lines.join("\n")
75
77
  lines[min..max].join("\n")
@@ -90,13 +92,12 @@ module RSpec
90
92
  def post_process(highlighted, offending_line)
91
93
  new_lines = []
92
94
  highlighted.split("\n").each_with_index do |line, i|
93
- new_line = "<span class=\"linenum\">#{offending_line+i-2}</span>#{line}"
95
+ new_line = "<span class=\"linenum\">#{offending_line + i - 2}</span>#{line}"
94
96
  new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
95
97
  new_lines << new_line
96
98
  end
97
99
  new_lines.join("\n")
98
100
  end
99
-
100
101
  end
101
102
  end
102
103
  end
@@ -320,7 +320,8 @@ module RSpec
320
320
  # @private
321
321
  # Holds the various registered hooks.
322
322
  def hooks
323
- @hooks ||= HookCollections.new(self,
323
+ @hooks ||= HookCollections.new(
324
+ self,
324
325
  :around => { :example => AroundHookCollection.new },
325
326
  :before => { :example => HookCollection.new, :context => HookCollection.new, :suite => HookCollection.new },
326
327
  :after => { :example => HookCollection.new, :context => HookCollection.new, :suite => HookCollection.new }
@@ -374,7 +375,23 @@ EOS
374
375
  end
375
376
 
376
377
  # @private
377
- AroundHook = Hook
378
+ class AroundHook < Hook
379
+ def execute_with(example, procsy)
380
+ example.instance_exec(procsy, &block)
381
+ return if procsy.executed?
382
+ Pending.mark_skipped!(example, "#{hook_description} did not execute the example")
383
+ end
384
+
385
+ if Proc.method_defined?(:source_location)
386
+ def hook_description
387
+ "around hook at #{Metadata.relative_path(block.source_location.join(':'))}"
388
+ end
389
+ else
390
+ def hook_description
391
+ "around hook"
392
+ end
393
+ end
394
+ end
378
395
 
379
396
  # @private
380
397
  class BaseHookCollection
@@ -383,7 +400,7 @@ EOS
383
400
  end
384
401
 
385
402
  attr_reader :hooks
386
- protected :hooks
403
+ protected :hooks
387
404
 
388
405
  alias append push
389
406
  alias prepend unshift
@@ -397,7 +414,7 @@ EOS
397
414
  class HookCollection < BaseHookCollection
398
415
  def for(example_or_group)
399
416
  self.class.
400
- new(hooks.select {|hook| hook.options_apply?(example_or_group)}).
417
+ new(hooks.select { |hook| hook.options_apply?(example_or_group) }).
401
418
  with(example_or_group)
402
419
  end
403
420
 
@@ -407,14 +424,14 @@ EOS
407
424
  end
408
425
 
409
426
  def run
410
- hooks.each {|h| h.run(@example)}
427
+ hooks.each { |h| h.run(@example) }
411
428
  end
412
429
  end
413
430
 
414
431
  # @private
415
432
  class AroundHookCollection < BaseHookCollection
416
433
  def for(example, initial_procsy=nil)
417
- self.class.new(hooks.select {|hook| hook.options_apply?(example)}).
434
+ self.class.new(hooks.select { |hook| hook.options_apply?(example) }).
418
435
  with(example, initial_procsy)
419
436
  end
420
437
 
@@ -426,9 +443,7 @@ EOS
426
443
 
427
444
  def run
428
445
  hooks.inject(@initial_procsy) do |procsy, around_hook|
429
- procsy.wrap do
430
- @example.instance_exec(procsy, &around_hook.block)
431
- end
446
+ procsy.wrap { around_hook.execute_with(@example, procsy) }
432
447
  end.call
433
448
  end
434
449
  end
@@ -502,7 +517,7 @@ EOS
502
517
  def process(host, globals, position, scope)
503
518
  globals[position][scope].each do |hook|
504
519
  next unless scope == :example || hook.options_apply?(host)
505
- next if host.parent_groups.any? {|a| a.hooks[position][scope].include?(hook)}
520
+ next if host.parent_groups.any? { |a| a.hooks[position][scope].include?(hook) }
506
521
  self[position][scope] << hook
507
522
  end
508
523
  end
@@ -145,12 +145,12 @@ module RSpec
145
145
  end
146
146
  end
147
147
 
148
- def self.fetch(key, &block)
148
+ def self.fetch(key, &_block)
149
149
  description = if key == :subject
150
- "subject"
151
- else
152
- "let declaration `#{key}`"
153
- end
150
+ "subject"
151
+ else
152
+ "let declaration `#{key}`"
153
+ end
154
154
 
155
155
  raise <<-EOS
156
156
  #{description} accessed in #{article} #{hook_expression} hook at:
@@ -310,6 +310,8 @@ EOS
310
310
  # implicitly in one-liners and explicitly using an intention revealing
311
311
  # name.
312
312
  #
313
+ # When given a `name`, calling `super` in the block is not supported.
314
+ #
313
315
  # @param name [String,Symbol] used to define an accessor with an
314
316
  # intention revealing name
315
317
  # @param block defines the value to be returned by `subject` in examples
@@ -46,9 +46,7 @@ module RSpec
46
46
  def self.build_hash_from(args, warn_about_example_group_filtering=false)
47
47
  hash = args.last.is_a?(Hash) ? args.pop : {}
48
48
 
49
- while args.last.is_a?(Symbol)
50
- hash[args.pop] = true
51
- end
49
+ hash[args.pop] = true while args.last.is_a?(Symbol)
52
50
 
53
51
  if warn_about_example_group_filtering && hash.key?(:example_group)
54
52
  RSpec.deprecate("Filtering by an `:example_group` subhash",
@@ -95,13 +93,15 @@ module RSpec
95
93
  private
96
94
 
97
95
  def populate_location_attributes
98
- file_path, line_number = if backtrace = user_metadata.delete(:caller)
99
- file_path_and_line_number_from(backtrace)
100
- elsif block.respond_to?(:source_location)
101
- block.source_location
102
- else
103
- file_path_and_line_number_from(caller)
104
- end
96
+ backtrace = user_metadata.delete(:caller)
97
+
98
+ file_path, line_number = if backtrace
99
+ file_path_and_line_number_from(backtrace)
100
+ elsif block.respond_to?(:source_location)
101
+ block.source_location
102
+ else
103
+ file_path_and_line_number_from(caller)
104
+ end
105
105
 
106
106
  file_path = Metadata.relative_path(file_path)
107
107
  metadata[:file_path] = file_path
@@ -110,7 +110,7 @@ module RSpec
110
110
  end
111
111
 
112
112
  def file_path_and_line_number_from(backtrace)
113
- first_caller_from_outside_rspec = backtrace.detect { |l| l !~ CallerFilter::LIB_REGEX }
113
+ first_caller_from_outside_rspec = backtrace.find { |l| l !~ CallerFilter::LIB_REGEX }
114
114
  first_caller_from_outside_rspec ||= backtrace.first
115
115
  /(.+?):(\d+)(?:|:\d+)/.match(first_caller_from_outside_rspec).captures
116
116
  end
@@ -131,22 +131,21 @@ module RSpec
131
131
 
132
132
  def ensure_valid_user_keys
133
133
  RESERVED_KEYS.each do |key|
134
- if user_metadata.has_key?(key)
135
- raise <<-EOM.gsub(/^\s+\|/, '')
136
- |#{"*"*50}
137
- |:#{key} is not allowed
138
- |
139
- |RSpec reserves some hash keys for its own internal use,
140
- |including :#{key}, which is used on:
141
- |
142
- | #{CallerFilter.first_non_rspec_line}.
143
- |
144
- |Here are all of RSpec's reserved hash keys:
145
- |
146
- | #{RESERVED_KEYS.join("\n ")}
147
- |#{"*"*50}
148
- EOM
149
- end
134
+ next unless user_metadata.key?(key)
135
+ raise <<-EOM.gsub(/^\s+\|/, '')
136
+ |#{"*" * 50}
137
+ |:#{key} is not allowed
138
+ |
139
+ |RSpec reserves some hash keys for its own internal use,
140
+ |including :#{key}, which is used on:
141
+ |
142
+ | #{CallerFilter.first_non_rspec_line}.
143
+ |
144
+ |Here are all of RSpec's reserved hash keys:
145
+ |
146
+ | #{RESERVED_KEYS.join("\n ")}
147
+ |#{"*" * 50}
148
+ EOM
150
149
  end
151
150
  end
152
151
  end
@@ -217,8 +216,8 @@ module RSpec
217
216
  # sets this thread local to silence the warning here since it would be so confusing.
218
217
  unless RSpec.thread_local_metadata[:silence_metadata_example_group_deprecations]
219
218
  RSpec.deprecate("The `:example_group` key in an example group's metadata hash",
220
- :replacement => "the example group's hash directly for the " +
221
- "computed keys and `:parent_example_group` to access the parent " +
219
+ :replacement => "the example group's hash directly for the " \
220
+ "computed keys and `:parent_example_group` to access the parent " \
222
221
  "example group metadata")
223
222
  end
224
223
 
@@ -357,7 +356,7 @@ module RSpec
357
356
  to_h
358
357
  end
359
358
 
360
- def issue_deprecation(method_name, *args)
359
+ def issue_deprecation(_method_name, *_args)
361
360
  # no-op by default: subclasses can override
362
361
  end
363
362