rspec-core 3.0.4 → 3.1.0

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