rspec-core 3.7.1 → 3.9.3

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 (46) 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 +116 -0
  5. data/README.md +18 -18
  6. data/lib/rspec/core.rb +1 -0
  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 +138 -0
  10. data/lib/rspec/core/bisect/server.rb +5 -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 +236 -79
  15. data/lib/rspec/core/configuration_options.rb +41 -4
  16. data/lib/rspec/core/did_you_mean.rb +46 -0
  17. data/lib/rspec/core/example.rb +18 -8
  18. data/lib/rspec/core/example_group.rb +33 -16
  19. data/lib/rspec/core/filter_manager.rb +1 -1
  20. data/lib/rspec/core/formatters.rb +14 -6
  21. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  22. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  23. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +29 -16
  24. data/lib/rspec/core/formatters/deprecation_formatter.rb +3 -1
  25. data/lib/rspec/core/formatters/documentation_formatter.rb +35 -3
  26. data/lib/rspec/core/formatters/exception_presenter.rb +29 -6
  27. data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
  28. data/lib/rspec/core/formatters/html_printer.rb +0 -2
  29. data/lib/rspec/core/formatters/protocol.rb +17 -17
  30. data/lib/rspec/core/formatters/syntax_highlighter.rb +19 -19
  31. data/lib/rspec/core/hooks.rb +44 -24
  32. data/lib/rspec/core/invocations.rb +9 -7
  33. data/lib/rspec/core/memoized_helpers.rb +33 -14
  34. data/lib/rspec/core/metadata.rb +2 -3
  35. data/lib/rspec/core/option_parser.rb +10 -3
  36. data/lib/rspec/core/profiler.rb +3 -1
  37. data/lib/rspec/core/rake_task.rb +22 -2
  38. data/lib/rspec/core/reporter.rb +11 -6
  39. data/lib/rspec/core/runner.rb +25 -14
  40. data/lib/rspec/core/shared_example_group.rb +5 -5
  41. data/lib/rspec/core/shell_escape.rb +2 -2
  42. data/lib/rspec/core/version.rb +1 -1
  43. data/lib/rspec/core/world.rb +14 -1
  44. metadata +25 -15
  45. metadata.gz.sig +0 -0
  46. data/lib/rspec/core/formatters/bisect_formatter.rb +0 -69
@@ -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?
@@ -38,25 +57,6 @@ module RSpec
38
57
  end
39
58
  end
40
59
 
41
- # rubocop:disable Lint/RescueException
42
- # rubocop:disable Lint/HandleExceptions
43
- def self.attempt_to_add_rspec_terms_to_coderay_keywords
44
- CodeRay::Scanners::Ruby::Patterns::IDENT_KIND.add(%w[
45
- describe context
46
- it specify
47
- before after around
48
- let subject
49
- expect allow
50
- ], :keyword)
51
- rescue Exception
52
- # Mutating CodeRay's contants like this is not a public API
53
- # and might not always work. If we cannot add our keywords
54
- # to CodeRay it is not a big deal and not worth raising an
55
- # error over, so we ignore it.
56
- end
57
- # rubocop:enable Lint/HandleExceptions
58
- # rubocop:enable Lint/RescueException
59
-
60
60
  # @private
61
61
  module CodeRayImplementation
62
62
  RESET_CODE = "\e[0m"
@@ -13,13 +13,14 @@ module RSpec
13
13
  # @overload before(scope, &block)
14
14
  # @param scope [Symbol] `:example`, `:context`, or `:suite`
15
15
  # (defaults to `:example`)
16
- # @overload before(scope, conditions, &block)
16
+ # @overload before(scope, *conditions, &block)
17
17
  # @param scope [Symbol] `:example`, `:context`, or `:suite`
18
18
  # (defaults to `:example`)
19
- # @param conditions [Hash]
20
- # constrains this hook to examples matching these conditions e.g.
19
+ # @param conditions [Array<Symbol>, Hash] constrains this hook to
20
+ # examples matching these conditions e.g.
21
21
  # `before(:example, :ui => true) { ... }` will only run with examples
22
- # or groups declared with `:ui => true`.
22
+ # or groups declared with `:ui => true`. Symbols will be transformed
23
+ # into hash entries with `true` values.
23
24
  # @overload before(conditions, &block)
24
25
  # @param conditions [Hash]
25
26
  # constrains this hook to examples matching these conditions e.g.
@@ -59,8 +60,10 @@ module RSpec
59
60
  # before(:example) # Declared in a parent group.
60
61
  # before(:example) # Declared in the current group.
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
+ # If more than one `before` is declared within any one example group, they
64
+ # are run in the order in which they are declared. Any `around` hooks will
65
+ # execute after `before` context hooks but before any `before` example
66
+ # hook regardless of where they are declared.
64
67
  #
65
68
  # ### Conditions
66
69
  #
@@ -74,11 +77,11 @@ module RSpec
74
77
  # end
75
78
  # end
76
79
  #
77
- # describe Something, :authorized => true do
80
+ # RSpec.describe Something, :authorized => true do
78
81
  # # The before hook will run in before each example in this group.
79
82
  # end
80
83
  #
81
- # describe SomethingElse do
84
+ # RSpec.describe SomethingElse do
82
85
  # it "does something", :authorized => true do
83
86
  # # The before hook will run before this example.
84
87
  # end
@@ -159,7 +162,7 @@ module RSpec
159
162
  #
160
163
  # @example before(:example) declared in an {ExampleGroup}
161
164
  #
162
- # describe Thing do
165
+ # RSpec.describe Thing do
163
166
  # before(:example) do
164
167
  # @thing = Thing.new
165
168
  # end
@@ -171,7 +174,7 @@ module RSpec
171
174
  #
172
175
  # @example before(:context) declared in an {ExampleGroup}
173
176
  #
174
- # describe Parser do
177
+ # RSpec.describe Parser do
175
178
  # before(:context) do
176
179
  # File.open(file_to_parse, 'w') do |f|
177
180
  # f.write <<-CONTENT
@@ -213,13 +216,14 @@ module RSpec
213
216
  # @overload after(scope, &block)
214
217
  # @param scope [Symbol] `:example`, `:context`, or `:suite` (defaults to
215
218
  # `:example`)
216
- # @overload after(scope, conditions, &block)
219
+ # @overload after(scope, *conditions, &block)
217
220
  # @param scope [Symbol] `:example`, `:context`, or `:suite` (defaults to
218
221
  # `:example`)
219
- # @param conditions [Hash]
220
- # constrains this hook to examples matching these conditions e.g.
222
+ # @param conditions [Array<Symbol>, Hash] constrains this hook to
223
+ # examples matching these conditions e.g.
221
224
  # `after(:example, :ui => true) { ... }` will only run with examples
222
- # or groups declared with `:ui => true`.
225
+ # or groups declared with `:ui => true`. Symbols will be transformed
226
+ # into hash entries with `true` values.
223
227
  # @overload after(conditions, &block)
224
228
  # @param conditions [Hash]
225
229
  # constrains this hook to examples matching these conditions e.g.
@@ -260,8 +264,10 @@ module RSpec
260
264
  # after(:suite) # Declared in RSpec.configure.
261
265
  #
262
266
  # This is the reverse of the order in which `before` hooks are run.
263
- # 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.
267
+ # Similarly, if more than one `after` is declared within any example
268
+ # group, they are run in reverse order of that in which they are declared.
269
+ # Also `around` hooks will run after any `after` example hooks are
270
+ # invoked but before any `after` context hooks.
265
271
  #
266
272
  # @note The `:example` and `:context` scopes are also available as
267
273
  # `:each` and `:all`, respectively. Use whichever you prefer.
@@ -288,13 +294,15 @@ module RSpec
288
294
  # @param scope [Symbol] `:example` (defaults to `:example`)
289
295
  # present for syntax parity with `before` and `after`, but
290
296
  # `:example`/`:each` is the only supported value.
291
- # @overload around(scope, conditions, &block)
297
+ # @overload around(scope, *conditions, &block)
292
298
  # @param scope [Symbol] `:example` (defaults to `:example`)
293
299
  # present for syntax parity with `before` and `after`, but
294
300
  # `:example`/`:each` is the only supported value.
295
- # @param conditions [Hash] constrains this hook to examples matching
296
- # these conditions e.g. `around(:example, :ui => true) { ... }` will
297
- # only run with examples or groups declared with `:ui => true`.
301
+ # @param conditions [Array<Symbol>, Hash] constrains this hook to
302
+ # examples matching these conditions e.g.
303
+ # `around(:example, :ui => true) { ... }` will only run with examples
304
+ # or groups declared with `:ui => true`. Symbols will be transformed
305
+ # into hash entries with `true` values.
298
306
  # @overload around(conditions, &block)
299
307
  # @param conditions [Hash] constrains this hook to examples matching
300
308
  # these conditions e.g. `around(:example, :ui => true) { ... }` will
@@ -304,7 +312,7 @@ module RSpec
304
312
  #
305
313
  # @note the syntax of `around` is similar to that of `before` and `after`
306
314
  # but the semantics are quite different. `before` and `after` hooks are
307
- # run in the context of of the examples with which they are associated,
315
+ # run in the context of the examples with which they are associated,
308
316
  # whereas `around` hooks are actually responsible for running the
309
317
  # examples. Consequently, `around` hooks do not have direct access to
310
318
  # resources that are made available within the examples and their
@@ -322,13 +330,22 @@ module RSpec
322
330
  # end
323
331
  #
324
332
  # The yielded example aliases `run` with `call`, which lets you treat it
325
- # like a `Proc`. This is especially handy when working with libaries
333
+ # like a `Proc`. This is especially handy when working with libraries
326
334
  # that manage their own setup and teardown using a block or proc syntax,
327
335
  # e.g.
328
336
  #
329
337
  # around(:example) {|ex| Database.transaction(&ex)}
330
338
  # around(:example) {|ex| FakeFS(&ex)}
331
339
  #
340
+ # ### Order
341
+ #
342
+ # The `around` hooks execute surrounding an example and its hooks.
343
+ #
344
+ # This means after any `before` context hooks, but before any `before`
345
+ # example hooks, and similarly after any `after` example hooks but before
346
+ # any `after` context hooks.
347
+ #
348
+ # They are not a synonym for `before`/`after`.
332
349
  def around(*args, &block)
333
350
  hooks.register :prepend, :around, *args, &block
334
351
  end
@@ -339,8 +356,6 @@ module RSpec
339
356
  @hooks ||= HookCollections.new(self, FilterableItemRepository::UpdateOptimized)
340
357
  end
341
358
 
342
- private
343
-
344
359
  # @private
345
360
  Hook = Struct.new(:block, :options)
346
361
 
@@ -442,6 +457,11 @@ module RSpec
442
457
  "`#{position}(:suite)` hook, registered on an example " \
443
458
  "group, will be ignored."
444
459
  return
460
+ elsif scope == :context && position == :around
461
+ # TODO: consider making this an error in RSpec 4. For SemVer reasons,
462
+ # we are only warning in RSpec 3.
463
+ RSpec.warn_with "WARNING: `around(:context)` hooks are not supported and " \
464
+ "behave like `around(:example)."
445
465
  end
446
466
 
447
467
  hook = HOOK_TYPES[position][scope].new(block, options)
@@ -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
- success ? 0 : 1
40
+ success ? 0 : runner.configuration.failure_exit_code
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
@@ -10,7 +10,7 @@ module RSpec
10
10
  # @note `subject` was contributed by Joe Ferris to support the one-liner
11
11
  # syntax embraced by shoulda matchers:
12
12
  #
13
- # describe Widget do
13
+ # RSpec.describe Widget do
14
14
  # it { is_expected.to validate_presence_of(:name) }
15
15
  # # or
16
16
  # it { should validate_presence_of(:name) }
@@ -23,7 +23,7 @@ module RSpec
23
23
  # @example
24
24
  #
25
25
  # # Explicit declaration of subject.
26
- # describe Person do
26
+ # RSpec.describe Person do
27
27
  # subject { Person.new(:birthdate => 19.years.ago) }
28
28
  # it "should be eligible to vote" do
29
29
  # subject.should be_eligible_to_vote
@@ -32,7 +32,7 @@ module RSpec
32
32
  # end
33
33
  #
34
34
  # # Implicit subject => { Person.new }.
35
- # describe Person do
35
+ # RSpec.describe Person do
36
36
  # it "should be eligible to vote" do
37
37
  # subject.should be_eligible_to_vote
38
38
  # # ^ ^ explicit reference to subject not recommended
@@ -40,7 +40,7 @@ module RSpec
40
40
  # end
41
41
  #
42
42
  # # One-liner syntax - expectation is set on the subject.
43
- # describe Person do
43
+ # RSpec.describe Person do
44
44
  # it { is_expected.to be_eligible_to_vote }
45
45
  # # or
46
46
  # it { should be_eligible_to_vote }
@@ -67,7 +67,7 @@ module RSpec
67
67
  #
68
68
  # @example
69
69
  #
70
- # describe Person do
70
+ # RSpec.describe Person do
71
71
  # it { should be_eligible_to_vote }
72
72
  # end
73
73
  #
@@ -86,7 +86,7 @@ module RSpec
86
86
  #
87
87
  # @example
88
88
  #
89
- # describe Person do
89
+ # RSpec.describe Person do
90
90
  # it { should_not be_eligible_to_vote }
91
91
  # end
92
92
  #
@@ -270,7 +270,7 @@ EOS
270
270
  #
271
271
  # @example
272
272
  #
273
- # describe Thing do
273
+ # RSpec.describe Thing do
274
274
  # let(:thing) { Thing.new }
275
275
  #
276
276
  # it "does something" do
@@ -288,7 +288,26 @@ EOS
288
288
  raise(
289
289
  "#let or #subject called with a reserved name #initialize"
290
290
  ) if :initialize == name
291
- MemoizedHelpers.module_for(self).__send__(:define_method, name, &block)
291
+ our_module = MemoizedHelpers.module_for(self)
292
+
293
+ # If we have a module clash in our helper module
294
+ # then we need to remove it to prevent a warning.
295
+ #
296
+ # Note we do not check ancestor modules (see: `instance_methods(false)`)
297
+ # as we can override them.
298
+ if our_module.instance_methods(false).include?(name)
299
+ our_module.__send__(:remove_method, name)
300
+ end
301
+ our_module.__send__(:define_method, name, &block)
302
+
303
+ # If we have a module clash in the example module
304
+ # then we need to remove it to prevent a warning.
305
+ #
306
+ # Note we do not check ancestor modules (see: `instance_methods(false)`)
307
+ # as we can override them.
308
+ if instance_methods(false).include?(name)
309
+ remove_method(name)
310
+ end
292
311
 
293
312
  # Apply the memoization. The method has been defined in an ancestor
294
313
  # module so we can use `super` here to get the value.
@@ -323,7 +342,7 @@ EOS
323
342
  # end
324
343
  # end
325
344
  #
326
- # describe Thing do
345
+ # RSpec.describe Thing do
327
346
  # after(:example) { Thing.reset_count }
328
347
  #
329
348
  # context "using let" do
@@ -379,13 +398,13 @@ EOS
379
398
  #
380
399
  # @example
381
400
  #
382
- # describe CheckingAccount, "with $50" do
401
+ # RSpec.describe CheckingAccount, "with $50" do
383
402
  # subject { CheckingAccount.new(Money.new(50, :USD)) }
384
403
  # it { is_expected.to have_a_balance_of(Money.new(50, :USD)) }
385
404
  # it { is_expected.not_to be_overdrawn }
386
405
  # end
387
406
  #
388
- # describe CheckingAccount, "with a non-zero starting balance" do
407
+ # RSpec.describe CheckingAccount, "with a non-zero starting balance" do
389
408
  # subject(:account) { CheckingAccount.new(Money.new(50, :USD)) }
390
409
  # it { is_expected.not_to be_overdrawn }
391
410
  # it "has a balance equal to the starting balance" do
@@ -433,7 +452,7 @@ EOS
433
452
  # end
434
453
  # end
435
454
  #
436
- # describe Thing do
455
+ # RSpec.describe Thing do
437
456
  # after(:example) { Thing.reset_count }
438
457
  #
439
458
  # context "using subject" do
@@ -483,9 +502,9 @@ EOS
483
502
  def self.module_for(example_group)
484
503
  get_constant_or_yield(example_group, :LetDefinitions) do
485
504
  mod = Module.new do
486
- include Module.new {
505
+ include(Module.new {
487
506
  example_group.const_set(:NamedSubjectPreventSuper, self)
488
- }
507
+ })
489
508
  end
490
509
 
491
510
  example_group.const_set(:LetDefinitions, mod)
@@ -7,7 +7,7 @@ module RSpec
7
7
  # In addition to metadata that is used internally, this also stores
8
8
  # user-supplied metadata, e.g.
9
9
  #
10
- # describe Something, :type => :ui do
10
+ # RSpec.describe Something, :type => :ui do
11
11
  # it "does something", :slow => true do
12
12
  # # ...
13
13
  # end
@@ -136,7 +136,6 @@ module RSpec
136
136
 
137
137
  populate_location_attributes
138
138
  metadata.update(user_metadata)
139
- RSpec.configuration.apply_derived_metadata_to(metadata)
140
139
  end
141
140
 
142
141
  private
@@ -169,7 +168,7 @@ module RSpec
169
168
  end
170
169
 
171
170
  def description_separator(parent_part, child_part)
172
- if parent_part.is_a?(Module) && child_part =~ /^(#|::|\.)/
171
+ if parent_part.is_a?(Module) && /^(?:#|::|\.)/.match(child_part.to_s)
173
172
  ''.freeze
174
173
  else
175
174
  ' '.freeze
@@ -22,9 +22,8 @@ module RSpec::Core
22
22
  begin
23
23
  parser(options).parse!(args)
24
24
  rescue OptionParser::InvalidOption => e
25
- failure = e.message
26
- failure << " (defined in #{source})" if source
27
- abort "#{failure}\n\nPlease use --help for a listing of valid options"
25
+ abort "#{e.message}#{" (defined in #{source})" if source}\n\n" \
26
+ "Please use --help for a listing of valid options"
28
27
  end
29
28
 
30
29
  options[:files_or_directories_to_run] = args
@@ -37,6 +36,7 @@ module RSpec::Core
37
36
  # rubocop:disable Metrics/AbcSize
38
37
  # rubocop:disable CyclomaticComplexity
39
38
  # rubocop:disable PerceivedComplexity
39
+ # rubocop:disable Metrics/BlockLength
40
40
  def parser(options)
41
41
  OptionParser.new do |parser|
42
42
  parser.summary_width = 34
@@ -111,6 +111,7 @@ module RSpec::Core
111
111
  ' [d]ocumentation (group and example names)',
112
112
  ' [h]tml',
113
113
  ' [j]son',
114
+ ' [f]ailures ("file:line:reason", suitable for editors integration)',
114
115
  ' custom formatter class name') do |o|
115
116
  options[:formatters] ||= []
116
117
  options[:formatters] << [o]
@@ -226,6 +227,11 @@ FILTERING
226
227
  (options[:full_description] ||= []) << Regexp.compile(Regexp.escape(o))
227
228
  end
228
229
 
230
+ parser.on('-E', '--example-matches REGEX', "Run examples whose full nested names match REGEX (may be",
231
+ " used more than once)") do |o|
232
+ (options[:full_description] ||= []) << Regexp.compile(o)
233
+ end
234
+
229
235
  parser.on('-t', '--tag TAG[:VALUE]',
230
236
  'Run examples with the specified tag, or exclude examples',
231
237
  'by adding ~ before the tag.',
@@ -288,6 +294,7 @@ FILTERING
288
294
  end
289
295
  end
290
296
  end
297
+ # rubocop:enable Metrics/BlockLength
291
298
  # rubocop:enable Metrics/AbcSize
292
299
  # rubocop:enable MethodLength
293
300
  # rubocop:enable CyclomaticComplexity