rspec-core 3.5.4 → 3.9.0

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