rspec-core 3.5.4 → 3.9.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 (64) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +165 -2
  5. data/README.md +16 -16
  6. data/lib/rspec/core.rb +2 -1
  7. data/lib/rspec/core/bisect/coordinator.rb +26 -30
  8. data/lib/rspec/core/bisect/example_minimizer.rb +12 -8
  9. data/lib/rspec/core/bisect/fork_runner.rb +134 -0
  10. data/lib/rspec/core/bisect/server.rb +10 -14
  11. data/lib/rspec/core/bisect/{runner.rb → shell_command.rb} +27 -70
  12. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  13. data/lib/rspec/core/bisect/utilities.rb +58 -0
  14. data/lib/rspec/core/configuration.rb +315 -79
  15. data/lib/rspec/core/configuration_options.rb +43 -4
  16. data/lib/rspec/core/did_you_mean.rb +46 -0
  17. data/lib/rspec/core/drb.rb +3 -1
  18. data/lib/rspec/core/example.rb +19 -12
  19. data/lib/rspec/core/example_group.rb +17 -7
  20. data/lib/rspec/core/formatters.rb +28 -11
  21. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  22. data/lib/rspec/core/formatters/base_formatter.rb +1 -1
  23. data/lib/rspec/core/formatters/base_text_formatter.rb +3 -5
  24. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  25. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +29 -16
  26. data/lib/rspec/core/formatters/console_codes.rb +7 -4
  27. data/lib/rspec/core/formatters/deprecation_formatter.rb +9 -9
  28. data/lib/rspec/core/formatters/documentation_formatter.rb +37 -4
  29. data/lib/rspec/core/formatters/exception_presenter.rb +21 -4
  30. data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
  31. data/lib/rspec/core/formatters/html_formatter.rb +4 -2
  32. data/lib/rspec/core/formatters/html_printer.rb +3 -3
  33. data/lib/rspec/core/formatters/html_snippet_extractor.rb +4 -0
  34. data/lib/rspec/core/formatters/json_formatter.rb +9 -3
  35. data/lib/rspec/core/formatters/progress_formatter.rb +1 -0
  36. data/lib/rspec/core/formatters/protocol.rb +43 -42
  37. data/lib/rspec/core/formatters/snippet_extractor.rb +1 -3
  38. data/lib/rspec/core/{source → formatters}/syntax_highlighter.rb +21 -1
  39. data/lib/rspec/core/hooks.rb +18 -10
  40. data/lib/rspec/core/invocations.rb +30 -10
  41. data/lib/rspec/core/memoized_helpers.rb +36 -14
  42. data/lib/rspec/core/metadata.rb +2 -3
  43. data/lib/rspec/core/metadata_filter.rb +29 -17
  44. data/lib/rspec/core/notifications.rb +34 -11
  45. data/lib/rspec/core/option_parser.rb +32 -4
  46. data/lib/rspec/core/output_wrapper.rb +29 -0
  47. data/lib/rspec/core/profiler.rb +3 -1
  48. data/lib/rspec/core/project_initializer/.rspec +0 -1
  49. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +1 -4
  50. data/lib/rspec/core/rake_task.rb +21 -1
  51. data/lib/rspec/core/reporter.rb +33 -16
  52. data/lib/rspec/core/runner.rb +31 -15
  53. data/lib/rspec/core/set.rb +5 -0
  54. data/lib/rspec/core/shared_example_group.rb +41 -19
  55. data/lib/rspec/core/shell_escape.rb +2 -2
  56. data/lib/rspec/core/version.rb +1 -1
  57. data/lib/rspec/core/world.rb +24 -5
  58. metadata +26 -20
  59. metadata.gz.sig +0 -0
  60. data/lib/rspec/core/formatters/bisect_formatter.rb +0 -69
  61. data/lib/rspec/core/source.rb +0 -86
  62. data/lib/rspec/core/source/location.rb +0 -13
  63. data/lib/rspec/core/source/node.rb +0 -93
  64. data/lib/rspec/core/source/token.rb +0 -87
@@ -21,9 +21,13 @@ module RSpec
21
21
  end
22
22
 
23
23
  # rubocop:disable Style/ClassVars
24
+ # @private
24
25
  @@converter = NullConverter
26
+
25
27
  begin
26
28
  require 'coderay'
29
+ RSpec::Support.require_rspec_core 'formatters/syntax_highlighter'
30
+ RSpec::Core::Formatters::SyntaxHighlighter.attempt_to_add_rspec_terms_to_coderay_keywords
27
31
  @@converter = CoderayConverter
28
32
  # rubocop:disable Lint/HandleExceptions
29
33
  rescue LoadError
@@ -6,7 +6,7 @@ module RSpec
6
6
  module Formatters
7
7
  # @private
8
8
  class JsonFormatter < BaseFormatter
9
- Formatters.register self, :message, :dump_summary, :dump_profile, :stop, :close
9
+ Formatters.register self, :message, :dump_summary, :dump_profile, :stop, :seed, :close
10
10
 
11
11
  attr_reader :output_hash
12
12
 
@@ -26,7 +26,8 @@ module RSpec
26
26
  :duration => summary.duration,
27
27
  :example_count => summary.example_count,
28
28
  :failure_count => summary.failure_count,
29
- :pending_count => summary.pending_count
29
+ :pending_count => summary.pending_count,
30
+ :errors_outside_of_examples_count => summary.errors_outside_of_examples_count
30
31
  }
31
32
  @output_hash[:summary_line] = summary.totals_line
32
33
  end
@@ -46,9 +47,13 @@ module RSpec
46
47
  end
47
48
  end
48
49
 
50
+ def seed(notification)
51
+ return unless notification.seed_used?
52
+ @output_hash[:seed] = notification.seed
53
+ end
54
+
49
55
  def close(_notification)
50
56
  output.write @output_hash.to_json
51
- output.close if IO === output && output != $stdout
52
57
  end
53
58
 
54
59
  def dump_profile(profile)
@@ -81,6 +86,7 @@ module RSpec
81
86
 
82
87
  def format_example(example)
83
88
  {
89
+ :id => example.id,
84
90
  :description => example.description,
85
91
  :full_description => example.full_description,
86
92
  :status => example.execution_result.status.to_s,
@@ -1,4 +1,5 @@
1
1
  RSpec::Support.require_rspec_core "formatters/base_text_formatter"
2
+ RSpec::Support.require_rspec_core "formatters/console_codes"
2
3
 
3
4
  module RSpec
4
5
  module Core
@@ -17,12 +17,12 @@ module RSpec
17
17
  # @see RSpec::Core::Formatters::BaseTextFormatter
18
18
  # @see RSpec::Core::Reporter
19
19
  class Protocol
20
- # @method initialize
20
+ # @method initialize(output)
21
21
  # @api public
22
22
  #
23
23
  # @param output [IO] the formatter output
24
24
 
25
- # @method start
25
+ # @method start(notification)
26
26
  # @api public
27
27
  # @group Suite Notifications
28
28
  #
@@ -33,9 +33,9 @@ module RSpec
33
33
  # This will only be invoked once, and the next one to be invoked
34
34
  # is {#example_group_started}.
35
35
  #
36
- # @param notification [StartNotification]
36
+ # @param notification [Notifications::StartNotification]
37
37
 
38
- # @method example_group_started
38
+ # @method example_group_started(notification)
39
39
  # @api public
40
40
  # @group Group Notifications
41
41
  #
@@ -45,81 +45,81 @@ module RSpec
45
45
  # The next method to be invoked after this is {#example_passed},
46
46
  # {#example_pending}, or {#example_group_finished}.
47
47
  #
48
- # @param notification [GroupNotification] containing example_group
49
- # subclass of `RSpec::Core::ExampleGroup`
48
+ # @param notification [Notifications::GroupNotification] containing example_group
49
+ # subclass of {ExampleGroup}
50
50
 
51
- # @method example_group_finished
51
+ # @method example_group_finished(notification)
52
52
  # @api public
53
53
  # @group Group Notifications
54
54
  #
55
55
  # Invoked at the end of the execution of each example group.
56
56
  #
57
- # @param notification [GroupNotification] containing example_group
58
- # subclass of `RSpec::Core::ExampleGroup`
57
+ # @param notification [Notifications::GroupNotification] containing example_group
58
+ # subclass of {ExampleGroup}
59
59
 
60
- # @method example_started
60
+ # @method example_started(notification)
61
61
  # @api public
62
62
  # @group Example Notifications
63
63
  #
64
64
  # Invoked at the beginning of the execution of each example.
65
65
  #
66
- # @param notification [ExampleNotification] containing example subclass
67
- # of `RSpec::Core::Example`
66
+ # @param notification [Notifications::ExampleNotification] containing example subclass
67
+ # of {Example}
68
68
 
69
- # @method example_finished
69
+ # @method example_finished(notification)
70
70
  # @api public
71
71
  # @group Example Notifications
72
72
  #
73
73
  # Invoked at the end of the execution of each example.
74
74
  #
75
- # @param notification [ExampleNotification] containing example subclass
76
- # of `RSpec::Core::Example`
75
+ # @param notification [Notifications::ExampleNotification] containing example subclass
76
+ # of {Example}
77
77
 
78
- # @method example_passed
78
+ # @method example_passed(notification)
79
79
  # @api public
80
80
  # @group Example Notifications
81
81
  #
82
82
  # Invoked when an example passes.
83
83
  #
84
- # @param notification [ExampleNotification] containing example subclass
85
- # of `RSpec::Core::Example`
84
+ # @param notification [Notifications::ExampleNotification] containing example subclass
85
+ # of {Example}
86
86
 
87
- # @method example_pending
87
+ # @method example_pending(notification)
88
88
  # @api public
89
89
  # @group Example Notifications
90
90
  #
91
91
  # Invoked when an example is pending.
92
92
  #
93
- # @param notification [ExampleNotification] containing example subclass
94
- # of `RSpec::Core::Example`
93
+ # @param notification [Notifications::ExampleNotification] containing example subclass
94
+ # of {Example}
95
95
 
96
- # @method example_failed
96
+ # @method example_failed(notification)
97
97
  # @api public
98
98
  # @group Example Notifications
99
99
  #
100
100
  # Invoked when an example fails.
101
101
  #
102
- # @param notification [ExampleNotification] containing example subclass
103
- # of `RSpec::Core::Example`
102
+ # @param notification [Notifications::ExampleNotification] containing example subclass
103
+ # of {Example}
104
104
 
105
- # @method message
105
+ # @method message(notification)
106
106
  # @api public
107
107
  # @group Suite Notifications
108
108
  #
109
109
  # Used by the reporter to send messages to the output stream.
110
110
  #
111
- # @param notification [MessageNotification] containing message
111
+ # @param notification [Notifications::MessageNotification] containing message
112
112
 
113
- # @method stop
113
+ # @method stop(notification)
114
114
  # @api public
115
115
  # @group Suite Notifications
116
116
  #
117
117
  # Invoked after all examples have executed, before dumping post-run
118
118
  # reports.
119
119
  #
120
- # @param notification [NullNotification]
120
+ # @param notification [Notifications::NullNotification]
121
121
 
122
- # @method start_dump
122
+ # @method start_dump(notification)
123
123
  # @api public
124
124
  # @group Suite Notifications
125
125
  #
@@ -128,53 +128,54 @@ module RSpec
128
128
  # (BaseTextFormatter then calls {#dump_failures} once for each failed
129
129
  # example).
130
130
  #
131
- # @param notification [NullNotification]
131
+ # @param notification [Notifications::NullNotification]
132
132
 
133
- # @method dump_failures
133
+ # @method dump_failures(notification)
134
134
  # @api public
135
135
  # @group Suite Notifications
136
136
  #
137
137
  # Dumps detailed information about each example failure.
138
138
  #
139
- # @param notification [NullNotification]
139
+ # @param notification [Notifications::NullNotification]
140
140
 
141
- # @method dump_summary
141
+ # @method dump_summary(summary)
142
142
  # @api public
143
143
  # @group Suite Notifications
144
144
  #
145
145
  # This method is invoked after the dumping of examples and failures.
146
146
  # Each parameter is assigned to a corresponding attribute.
147
147
  #
148
- # @param summary [SummaryNotification] containing duration,
148
+ # @param summary [Notifications::SummaryNotification] containing duration,
149
149
  # example_count, failure_count and pending_count
150
150
 
151
- # @method dump_profile
151
+ # @method dump_profile(profile)
152
152
  # @api public
153
153
  # @group Suite Notifications
154
154
  #
155
155
  # This method is invoked after the dumping the summary if profiling is
156
156
  # enabled.
157
157
  #
158
- # @param profile [ProfileNotification] containing duration,
158
+ # @param profile [Notifications::ProfileNotification] containing duration,
159
159
  # slowest_examples and slowest_example_groups
160
160
 
161
- # @method dump_pending
161
+ # @method dump_pending(notification)
162
162
  # @api public
163
163
  # @group Suite Notifications
164
164
  #
165
165
  # Outputs a report of pending examples. This gets invoked
166
166
  # after the summary if option is set to do so.
167
167
  #
168
- # @param notification [NullNotification]
168
+ # @param notification [Notifications::NullNotification]
169
169
 
170
- # @method close
170
+ # @method close(notification)
171
171
  # @api public
172
172
  # @group Suite Notifications
173
173
  #
174
- # Invoked at the very end, `close` allows the formatter to clean
175
- # up resources, e.g. open streams, etc.
174
+ # Invoked at the end of a suite run. Allows the formatter to do any
175
+ # tidying up, but be aware that formatter output streams may be used
176
+ # elsewhere so don't actually close them.
176
177
  #
177
- # @param notification [NullNotification]
178
+ # @param notification [Notifications::NullNotification]
178
179
  end
179
180
  end
180
181
  end
@@ -1,5 +1,3 @@
1
- RSpec::Support.require_rspec_core "source"
2
-
3
1
  module RSpec
4
2
  module Core
5
3
  module Formatters
@@ -17,7 +15,7 @@ module RSpec
17
15
 
18
16
  def self.source_from_file(path)
19
17
  raise NoSuchFileError unless File.exist?(path)
20
- RSpec.world.source_cache.source_from_file(path)
18
+ RSpec.world.source_from_file(path)
21
19
  end
22
20
 
23
21
  if RSpec::Support::RubyFeatures.ripper_supported?
@@ -1,6 +1,6 @@
1
1
  module RSpec
2
2
  module Core
3
- class Source
3
+ module Formatters
4
4
  # @private
5
5
  # Provides terminal syntax highlighting of code snippets
6
6
  # when coderay is available.
@@ -13,6 +13,25 @@ module RSpec
13
13
  implementation.highlight_syntax(lines)
14
14
  end
15
15
 
16
+ # rubocop:disable Lint/RescueException
17
+ # rubocop:disable Lint/HandleExceptions
18
+ def self.attempt_to_add_rspec_terms_to_coderay_keywords
19
+ CodeRay::Scanners::Ruby::Patterns::IDENT_KIND.add(%w[
20
+ describe context
21
+ it specify
22
+ before after around
23
+ let subject
24
+ expect allow
25
+ ], :keyword)
26
+ rescue Exception
27
+ # Mutating CodeRay's contants like this is not a public API
28
+ # and might not always work. If we cannot add our keywords
29
+ # to CodeRay it is not a big deal and not worth raising an
30
+ # error over, so we ignore it.
31
+ end
32
+ # rubocop:enable Lint/HandleExceptions
33
+ # rubocop:enable Lint/RescueException
34
+
16
35
  private
17
36
 
18
37
  if RSpec::Support::OS.windows?
@@ -31,6 +50,7 @@ module RSpec
31
50
  def color_enabled_implementation
32
51
  @color_enabled_implementation ||= begin
33
52
  require 'coderay'
53
+ self.class.attempt_to_add_rspec_terms_to_coderay_keywords
34
54
  CodeRayImplementation
35
55
  rescue LoadError
36
56
  NoSyntaxHighlightingImplementation
@@ -60,7 +60,8 @@ module RSpec
60
60
  # before(:example) # Declared in the current group.
61
61
  #
62
62
  # If more than one `before` is declared within any one scope, they are run
63
- # in the order in which they are declared.
63
+ # in the order in which they are declared. Any `around` hooks will execute
64
+ # later than any `before` hook regardless of scope.
64
65
  #
65
66
  # ### Conditions
66
67
  #
@@ -74,11 +75,11 @@ module RSpec
74
75
  # end
75
76
  # end
76
77
  #
77
- # describe Something, :authorized => true do
78
+ # RSpec.describe Something, :authorized => true do
78
79
  # # The before hook will run in before each example in this group.
79
80
  # end
80
81
  #
81
- # describe SomethingElse do
82
+ # RSpec.describe SomethingElse do
82
83
  # it "does something", :authorized => true do
83
84
  # # The before hook will run before this example.
84
85
  # end
@@ -159,7 +160,7 @@ module RSpec
159
160
  #
160
161
  # @example before(:example) declared in an {ExampleGroup}
161
162
  #
162
- # describe Thing do
163
+ # RSpec.describe Thing do
163
164
  # before(:example) do
164
165
  # @thing = Thing.new
165
166
  # end
@@ -171,7 +172,7 @@ module RSpec
171
172
  #
172
173
  # @example before(:context) declared in an {ExampleGroup}
173
174
  #
174
- # describe Parser do
175
+ # RSpec.describe Parser do
175
176
  # before(:context) do
176
177
  # File.open(file_to_parse, 'w') do |f|
177
178
  # f.write <<-CONTENT
@@ -261,7 +262,8 @@ module RSpec
261
262
  #
262
263
  # This is the reverse of the order in which `before` hooks are run.
263
264
  # Similarly, if more than one `after` is declared within any one scope,
264
- # they are run in reverse order of that in which they are declared.
265
+ # they are run in reverse order of that in which they are declared. Also
266
+ # `around` hooks will all have run before any after hooks are invoked.
265
267
  #
266
268
  # @note The `:example` and `:context` scopes are also available as
267
269
  # `:each` and `:all`, respectively. Use whichever you prefer.
@@ -322,13 +324,19 @@ module RSpec
322
324
  # end
323
325
  #
324
326
  # The yielded example aliases `run` with `call`, which lets you treat it
325
- # like a `Proc`. This is especially handy when working with libaries
327
+ # like a `Proc`. This is especially handy when working with libraries
326
328
  # that manage their own setup and teardown using a block or proc syntax,
327
329
  # e.g.
328
330
  #
329
331
  # around(:example) {|ex| Database.transaction(&ex)}
330
332
  # around(:example) {|ex| FakeFS(&ex)}
331
333
  #
334
+ # ### Order
335
+ #
336
+ # All `around` hooks execute immediately surrounding an example, this means
337
+ # that all `before` hooks will have run and no `after` hooks will have run yet.
338
+ #
339
+ # They are not a synonym for `before`/`after`.
332
340
  def around(*args, &block)
333
341
  hooks.register :prepend, :around, *args, &block
334
342
  end
@@ -339,8 +347,6 @@ module RSpec
339
347
  @hooks ||= HookCollections.new(self, FilterableItemRepository::UpdateOptimized)
340
348
  end
341
349
 
342
- private
343
-
344
350
  # @private
345
351
  Hook = Struct.new(:block, :options)
346
352
 
@@ -456,7 +462,9 @@ module RSpec
456
462
  return if RSpec.configuration.dry_run?
457
463
 
458
464
  if scope == :context
459
- run_owned_hooks_for(position, :context, example_or_group)
465
+ unless example_or_group.class.metadata[:skip]
466
+ run_owned_hooks_for(position, :context, example_or_group)
467
+ end
460
468
  else
461
469
  case position
462
470
  when :before then run_example_hooks_for(example_or_group, :before, :reverse_each)
@@ -26,21 +26,23 @@ module RSpec
26
26
 
27
27
  # @private
28
28
  class Bisect
29
- def call(options, _err, _out)
29
+ def call(options, err, out)
30
30
  RSpec::Support.require_rspec_core "bisect/coordinator"
31
+ runner = Runner.new(options).tap { |r| r.configure(err, out) }
32
+ formatter = bisect_formatter_klass_for(options.options[:bisect]).new(
33
+ out, runner.configuration.bisect_runner
34
+ )
31
35
 
32
36
  success = RSpec::Core::Bisect::Coordinator.bisect_with(
33
- options.args,
34
- RSpec.configuration,
35
- bisect_formatter_for(options.options[:bisect])
37
+ runner, options.args, formatter
36
38
  )
37
39
 
38
40
  success ? 0 : 1
39
41
  end
40
42
 
41
- private
43
+ private
42
44
 
43
- def bisect_formatter_for(argument)
45
+ def bisect_formatter_klass_for(argument)
44
46
  return Formatters::BisectDebugFormatter if argument == "verbose"
45
47
  Formatters::BisectProgressFormatter
46
48
  end
@@ -49,16 +51,34 @@ module RSpec
49
51
  # @private
50
52
  class PrintVersion
51
53
  def call(_options, _err, out)
52
- out.puts RSpec::Core::Version::STRING
54
+ overall_version = RSpec::Core::Version::STRING
55
+ unless overall_version =~ /[a-zA-Z]+/
56
+ overall_version = overall_version.split('.').first(2).join('.')
57
+ end
58
+
59
+ out.puts "RSpec #{overall_version}"
60
+
61
+ [:Core, :Expectations, :Mocks, :Rails, :Support].each do |const_name|
62
+ lib_name = const_name.to_s.downcase
63
+ begin
64
+ require "rspec/#{lib_name}/version"
65
+ rescue LoadError
66
+ # Not worth mentioning libs that are not installed
67
+ nil
68
+ else
69
+ out.puts " - rspec-#{lib_name} #{RSpec.const_get(const_name)::Version::STRING}"
70
+ end
71
+ end
72
+
53
73
  0
54
74
  end
55
75
  end
56
76
 
57
77
  # @private
58
- PrintHelp = Struct.new(:parser, :invalid_options) do
78
+ PrintHelp = Struct.new(:parser, :hidden_options) do
59
79
  def call(_options, _err, out)
60
- # Removing the blank invalid options from the output.
61
- out.puts parser.to_s.gsub(/^\s+(#{invalid_options.join('|')})\s*$\n/, '')
80
+ # Removing the hidden options from the output.
81
+ out.puts parser.to_s.gsub(/^\s+(#{hidden_options.join('|')})\b.*$\n/, '')
62
82
  0
63
83
  end
64
84
  end