rspec-core 3.7.1 → 3.9.3

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