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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82269549116ef3ac8ad256ce6deafa672865194fcdb4b1a194f21e29c6e2bff7
4
- data.tar.gz: 20f2bac3761d3b34c947cb1214b50ef3a6b27abddb9d852857f0302a0f84cd5c
3
+ metadata.gz: 30e931022769b69911776a8c64de53481785df0074e84693b5e4031c20a53bb2
4
+ data.tar.gz: 9d5f23168383bff0e8f3152d9e111ed7600ee1cefb9ccaeb6c1a0fa384dfe3b1
5
5
  SHA512:
6
- metadata.gz: 2acb4568e22713e22debbf548052112e903af5297c6ec8e8be9b9c8c2c657b79eb9c7a2c83efcf9d4366c40f7134bf77ca7eea3ba8f82dd36ac9a554a744e04e
7
- data.tar.gz: 9b88592b83c97d497774f0b47fa837c895ffabd7c0e52806d3f8c773c505110e6b1f6f1fa8ae348b1533fde353d07fa803cc1c21511d27748e61147dbd505423
6
+ metadata.gz: 50a9d24a978ca5c0e13bccb4b10343aeac24d2895692d0a2c7d3a6ab429213ede9b9406d4deca6d7cb496f91919eb38fe711ca0294eb94d26e60e4c07abb2e4b
7
+ data.tar.gz: e412bad1efb696f88065ba2adab372ef8e613ece6f70dd8bf193daeab5e3c8ea41978d3d2b3f5829c4a11c3eb3e2f01428f979d8b75f1f658dc4dcb78fdbf263
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/Changelog.md CHANGED
@@ -1,3 +1,118 @@
1
+ # 3.9.3 / 2020-09-30
2
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.2...v3.9.3)
3
+
4
+ Bug Fixes:
5
+
6
+ * Declare `ruby2_keywords` on `method_missing` for other gems. (Jon Rowe, #2731)
7
+ * Ensure custom error codes are returned from bisect runs. (Jon Rowe, #2732)
8
+ * Ensure `RSpec::Core::Configuration` predicate config methods return booleans.
9
+ (Marc-André Lafortune, #2736)
10
+ * Prevent `rspec --bisect` from generating zombie processes while executing
11
+ bisect runs. (Benoit Tigeot, Jon Rowe, #2739)
12
+ * Predicates for pending examples, (in `RSpec::Core::Example`, `#pending?`, `#skipped?` and
13
+ `#pending_fixed?`) now return boolean values rather than truthy values.
14
+ (Marc-André Lafortune, #2756, #2758)
15
+ * Exceptions which have a message which cannot be cast to a string will no longer
16
+ cause a crash. (Jon Rowe, #2761)
17
+
18
+ ### 3.9.2 / 2020-05-02
19
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.1...v3.9.2)
20
+
21
+ Bug Fixes:
22
+
23
+ * Emit a warning when `around` hook is used with `:context` scope
24
+ (Phil Pirozhkov, #2687)
25
+ * Prevent invalid implementations of `Exception#cause` from being treated as a
26
+ valid cause (and causing strange errors) in `RSpec::Core::Formatters::ExceptionPresenter`.
27
+ (Jon Rowe, #2703)
28
+ * Correctly detect patterns when `rspec_opts` is an array in `RSpec::Core::RakeTask`.
29
+ (Marc-André Lafortune, #2704)
30
+ * Make `RSpec.clear_examples` reset example counts for example groups. This fixes
31
+ an issue with re-running specs not matching ids. (Agis Anastasopoulos, #2723)
32
+
33
+ ### 3.9.1 / 2019-12-28
34
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.0...v3.9.1)
35
+
36
+ Bug Fixes:
37
+
38
+ * Prevent bisect command from blocking when number of specs exceeds file
39
+ descriptor limit on OSX or Linux. (Benoit Tigeot, #2669)
40
+ * Prevent warnings being issued on Ruby 2.7.0. (Jon Rowe, #2680)
41
+
42
+ ### 3.9.0 / 2019-10-07
43
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.2...v3.9.0)
44
+
45
+ Enhancements:
46
+
47
+ * Improve the handling of errors during loading support files, if a file
48
+ errors before loading specs, RSpec will now skip loading the specs.
49
+ (David Rodríguez, #2568)
50
+ * Add support for --example-matches to run examples by regular expression.
51
+ (Sam Joseph, Matt Rider, @okothkongo1, #2586)
52
+ * Add `did_you_mean` suggestions for file names encountering a `LoadError`
53
+ outside of examples. (@obromios, #2601)
54
+ * Add a minimalist quick fix style formatter, only outputs failures as
55
+ `file:line:message`. (Romain Tartière, #2614)
56
+ * Convert string number values to integer when used for `RSpec::Configuration#fail_fast`
57
+ (Viktor Fonic, #2634)
58
+ * Issue warning when invalid values are used for `RSpec::Configuration#fail_fast`
59
+ (Viktor Fonic, #2634)
60
+ * Add support for running the Rake task in a clean environment.
61
+ (Jon Rowe, #2632)
62
+ * Indent messages by there example group / example in the documentation formatter.
63
+ (Samuel Williams, #2649)
64
+
65
+ ### 3.8.2 / 2019-06-29
66
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.1...v3.8.2)
67
+
68
+ Bug Fixes:
69
+
70
+ * Fix `config.define_derived_metadata` so that cascades are not triggered
71
+ until metadata has been assigned to the example or example group
72
+ (Myron Marston, #2635).
73
+
74
+ ### 3.8.1 / 2019-06-13
75
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.0...v3.8.1)
76
+
77
+ Bug Fixes:
78
+
79
+ * Handle RSpec description(s) with japanese chars in CP932 encoded files.
80
+ (Benoit Tigeot, #2575)
81
+ * When defining `let` methods that overwrite an existing method, prevent
82
+ a warning being issued by removing the old definition. (Jon Rowe, #2593)
83
+ * Prevent warning on Ruby 2.6.0-rc1 (Keiji Yoshimi, #2582)
84
+ * Fix `config.define_derived_metadata` so that it supports cascades.
85
+ (Myron Marston, #2630).
86
+
87
+ ### 3.8.0 / 2018-08-04
88
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.7.1...v3.8.0)
89
+
90
+ Enhancements:
91
+
92
+ * Improve shell escaping used by `RSpec::Core::RakeTask` and `--bisect` so
93
+ that it works on `Pathname` objects. (Andrew Vit, #2479)
94
+ * Nicely format errors encountered while loading files specified
95
+ by `--require` option. (Myron Marston, #2504)
96
+ * Significantly improve the performance of `--bisect` on platforms that
97
+ support forking by replacing the shell-based runner with one that uses
98
+ forking so that RSpec and the application environment can be booted only
99
+ once, instead of once per spec run. (Myron Marston, #2511)
100
+ * Provide a configuration API to pick which bisect runner is used for
101
+ `--bisect`. Pick a runner via `config.bisect_runner = :shell` or
102
+ `config.bisect_runner = :fork` in a file loaded by a `--require`
103
+ option passed at the command line or set in `.rspec`. (Myron Marston, #2511)
104
+ * Support the [XDG Base Directory
105
+ Specification](https://specifications.freedesktop.org/basedir-spec/latest/)
106
+ for the global options file. `~/.rspec` is still supported when no
107
+ options file is found in `$XDG_CONFIG_HOME/rspec/options` (Magnus Bergmark, #2538)
108
+ * Extract `RSpec.world.prepare_example_filtering` that sets up the
109
+ example filtering for custom RSpec runners. (Oleg Pudeyev, #2552)
110
+
111
+ Bug Fixes:
112
+
113
+ * Prevent an `ArgumentError` when truncating backtraces with two identical
114
+ backtraces. (Systho, #2515, Benoit Tigeot, #2539)
115
+
1
116
  ### 3.7.1 / 2018-01-02
2
117
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.7.0...v3.7.1)
3
118
 
@@ -2046,6 +2161,7 @@ Bug fixes
2046
2161
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v2.2.0...v2.2.1)
2047
2162
 
2048
2163
  Bug fixes
2164
+
2049
2165
  * alias_method instead of override Kernel#method_missing (John Wilger)
2050
2166
  * changed --autotest to --tty in generated command (MIKAMI Yoshiyuki)
2051
2167
  * revert change to debugger (had introduced conflict with Rails)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # rspec-core [![Build Status](https://secure.travis-ci.org/rspec/rspec-core.svg?branch=master)](http://travis-ci.org/rspec/rspec-core) [![Code Climate](https://codeclimate.com/github/rspec/rspec-core.svg)](https://codeclimate.com/github/rspec/rspec-core)
1
+ # rspec-core [![Build Status](https://secure.travis-ci.org/rspec/rspec-core.svg?branch=main)](http://travis-ci.org/rspec/rspec-core) [![Code Climate](https://codeclimate.com/github/rspec/rspec-core.svg)](https://codeclimate.com/github/rspec/rspec-core)
2
2
 
3
3
  rspec-core provides the structure for writing executable examples of how your
4
4
  code should behave, and an `rspec` command with tools to constrain which
@@ -10,29 +10,15 @@ examples get run and tailor the output.
10
10
  gem install rspec-core # for rspec-core only
11
11
  rspec --help
12
12
 
13
- Want to run against the `master` branch? You'll need to include the dependent
13
+ Want to run against the `main` branch? You'll need to include the dependent
14
14
  RSpec repos as well. Add the following to your `Gemfile`:
15
15
 
16
16
  ```ruby
17
17
  %w[rspec rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
18
- gem lib, :git => "git://github.com/rspec/#{lib}.git", :branch => 'master'
18
+ gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'main'
19
19
  end
20
20
  ```
21
21
 
22
- ## Contributing
23
-
24
- Once you've set up the environment, you'll need to cd into the working
25
- directory of whichever repo you want to work in. From there you can run the
26
- specs and cucumber features, and make patches.
27
-
28
- NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
29
- can treat each RSpec repo as an independent project.
30
-
31
- * [Build details](BUILD_DETAIL.md)
32
- * [Code of Conduct](CODE_OF_CONDUCT.md)
33
- * [Detailed contributing guide](CONTRIBUTING.md)
34
- * [Development setup guide](DEVELOPMENT.md)
35
-
36
22
  ## Basic Structure
37
23
 
38
24
  RSpec uses the words "describe" and "it" so we can express concepts like a conversation:
@@ -67,7 +53,7 @@ context of an _instance_ of that class.
67
53
 
68
54
  ## Nested Groups
69
55
 
70
- You can also declare nested nested groups using the `describe` or `context`
56
+ You can also declare nested groups using the `describe` or `context`
71
57
  methods:
72
58
 
73
59
  ```ruby
@@ -376,6 +362,20 @@ Finished in 0.000379 seconds
376
362
  1 example, 0 failures
377
363
  ```
378
364
 
365
+ ## Contributing
366
+
367
+ Once you've set up the environment, you'll need to cd into the working
368
+ directory of whichever repo you want to work in. From there you can run the
369
+ specs and cucumber features, and make patches.
370
+
371
+ NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
372
+ can treat each RSpec repo as an independent project.
373
+
374
+ * [Build details](BUILD_DETAIL.md)
375
+ * [Code of Conduct](CODE_OF_CONDUCT.md)
376
+ * [Detailed contributing guide](CONTRIBUTING.md)
377
+ * [Development setup guide](DEVELOPMENT.md)
378
+
379
379
  ## Also see
380
380
 
381
381
  * [https://github.com/rspec/rspec](https://github.com/rspec/rspec)
data/lib/rspec/core.rb CHANGED
@@ -139,6 +139,7 @@ module RSpec
139
139
  module Core
140
140
  autoload :ExampleStatusPersister, "rspec/core/example_status_persister"
141
141
  autoload :Profiler, "rspec/core/profiler"
142
+ autoload :DidYouMean, "rspec/core/did_you_mean"
142
143
 
143
144
  # @private
144
145
  # This avoids issues with reporting time caused by examples that
@@ -1,62 +1,58 @@
1
- RSpec::Support.require_rspec_core "bisect/server"
2
- RSpec::Support.require_rspec_core "bisect/runner"
1
+ RSpec::Support.require_rspec_core "bisect/shell_command"
3
2
  RSpec::Support.require_rspec_core "bisect/example_minimizer"
3
+ RSpec::Support.require_rspec_core "bisect/utilities"
4
4
  RSpec::Support.require_rspec_core "formatters/bisect_progress_formatter"
5
5
 
6
6
  module RSpec
7
7
  module Core
8
8
  module Bisect
9
- # @private
10
9
  # The main entry point into the bisect logic. Coordinates among:
11
- # - Bisect::Server: Receives suite results.
12
- # - Bisect::Runner: Runs a set of examples and directs the results
13
- # to the server.
10
+ # - Bisect::ShellCommand: Generates shell commands to run spec subsets
14
11
  # - Bisect::ExampleMinimizer: Contains the core bisect logic.
15
- # - Formatters::BisectProgressFormatter: provides progress updates
16
- # to the user.
12
+ # - A bisect runner: runs a set of examples and returns the results.
13
+ # - A bisect formatter: provides progress updates to the user.
14
+ # @private
17
15
  class Coordinator
18
- def self.bisect_with(original_cli_args, configuration, formatter)
19
- new(original_cli_args, configuration, formatter).bisect
16
+ def self.bisect_with(spec_runner, original_cli_args, formatter)
17
+ new(spec_runner, original_cli_args, formatter).bisect
20
18
  end
21
19
 
22
- def initialize(original_cli_args, configuration, formatter)
23
- @original_cli_args = original_cli_args
24
- @configuration = configuration
25
- @formatter = formatter
20
+ def initialize(spec_runner, original_cli_args, formatter)
21
+ @spec_runner = spec_runner
22
+ @shell_command = ShellCommand.new(original_cli_args)
23
+ @notifier = Bisect::Notifier.new(formatter)
26
24
  end
27
25
 
28
26
  def bisect
29
- @configuration.add_formatter @formatter
30
-
31
- reporter.close_after do
32
- repro = Server.run do |server|
33
- runner = Runner.new(server, @original_cli_args)
34
- minimizer = ExampleMinimizer.new(runner, reporter)
27
+ repro = start_bisect_runner do |runner|
28
+ minimizer = ExampleMinimizer.new(@shell_command, runner, @notifier)
35
29
 
36
- gracefully_abort_on_sigint(minimizer)
37
- minimizer.find_minimal_repro
38
- minimizer.repro_command_for_currently_needed_ids
39
- end
40
-
41
- reporter.publish(:bisect_repro_command, :repro => repro)
30
+ gracefully_abort_on_sigint(minimizer)
31
+ minimizer.find_minimal_repro
32
+ minimizer.repro_command_for_currently_needed_ids
42
33
  end
43
34
 
35
+ @notifier.publish(:bisect_repro_command, :repro => repro)
36
+
44
37
  true
45
38
  rescue BisectFailedError => e
46
- reporter.publish(:bisect_failed, :failure_explanation => e.message)
39
+ @notifier.publish(:bisect_failed, :failure_explanation => e.message)
47
40
  false
41
+ ensure
42
+ @notifier.publish(:close)
48
43
  end
49
44
 
50
45
  private
51
46
 
52
- def reporter
53
- @configuration.reporter
47
+ def start_bisect_runner(&block)
48
+ klass = @spec_runner.configuration.bisect_runner_class
49
+ klass.start(@shell_command, @spec_runner, &block)
54
50
  end
55
51
 
56
52
  def gracefully_abort_on_sigint(minimizer)
57
53
  trap('INT') do
58
54
  repro = minimizer.repro_command_for_currently_needed_ids
59
- reporter.publish(:bisect_aborted, :repro => repro)
55
+ @notifier.publish(:bisect_aborted, :repro => repro)
60
56
  exit(1)
61
57
  end
62
58
  end
@@ -1,3 +1,5 @@
1
+ RSpec::Support.require_rspec_core "bisect/utilities"
2
+
1
3
  module RSpec
2
4
  module Core
3
5
  module Bisect
@@ -5,12 +7,13 @@ module RSpec
5
7
  # Contains the core bisect logic. Searches for examples we can ignore by
6
8
  # repeatedly running different subsets of the suite.
7
9
  class ExampleMinimizer
8
- attr_reader :runner, :reporter, :all_example_ids, :failed_example_ids
10
+ attr_reader :shell_command, :runner, :all_example_ids, :failed_example_ids
9
11
  attr_accessor :remaining_ids
10
12
 
11
- def initialize(runner, reporter)
12
- @runner = runner
13
- @reporter = reporter
13
+ def initialize(shell_command, runner, notifier)
14
+ @shell_command = shell_command
15
+ @runner = runner
16
+ @notifier = notifier
14
17
  end
15
18
 
16
19
  def find_minimal_repro
@@ -82,7 +85,7 @@ module RSpec
82
85
  end
83
86
 
84
87
  def repro_command_for_currently_needed_ids
85
- return runner.repro_command_from(currently_needed_ids) if remaining_ids
88
+ return shell_command.repro_command_from(currently_needed_ids) if remaining_ids
86
89
  "(Not yet enough information to provide any repro command)"
87
90
  end
88
91
 
@@ -108,7 +111,8 @@ module RSpec
108
111
  end
109
112
 
110
113
  def prep
111
- notify(:bisect_starting, :original_cli_args => runner.original_cli_args)
114
+ notify(:bisect_starting, :original_cli_args => shell_command.original_cli_args,
115
+ :bisect_runner => runner.class.name)
112
116
 
113
117
  _, duration = track_duration do
114
118
  original_results = runner.original_results
@@ -135,7 +139,7 @@ module RSpec
135
139
  ids_to_run = ids + failed_example_ids
136
140
  notify(
137
141
  :bisect_individual_run_start,
138
- :command => runner.repro_command_from(ids_to_run),
142
+ :command => shell_command.repro_command_from(ids_to_run),
139
143
  :ids_to_run => ids_to_run
140
144
  )
141
145
 
@@ -161,7 +165,7 @@ module RSpec
161
165
  end
162
166
 
163
167
  def notify(*args)
164
- reporter.publish(*args)
168
+ @notifier.publish(*args)
165
169
  end
166
170
  end
167
171
  end
@@ -0,0 +1,138 @@
1
+ require 'stringio'
2
+ RSpec::Support.require_rspec_core "formatters/base_bisect_formatter"
3
+ RSpec::Support.require_rspec_core "bisect/utilities"
4
+
5
+ module RSpec
6
+ module Core
7
+ module Bisect
8
+ # A Bisect runner that runs requested subsets of the suite by forking
9
+ # sub-processes. The main process bootstraps RSpec and the application
10
+ # environment (including preloading files specified via `--require`) so
11
+ # that the individual spec runs do not have to re-pay that cost. Each
12
+ # spec run happens in a forked process, ensuring that the spec files are
13
+ # not loaded in the main process.
14
+ #
15
+ # For most projects, bisections that use `ForkRunner` instead of
16
+ # `ShellRunner` will finish significantly faster, because the `ShellRunner`
17
+ # pays the cost of booting RSpec and the app environment on _every_ run of
18
+ # a subset. In contrast, `ForkRunner` pays that cost only once.
19
+ #
20
+ # However, not all projects can use `ForkRunner`. Obviously, on platforms
21
+ # that do not support forking (e.g. Windows), it cannot be used. In addition,
22
+ # it can cause problems for some projects that put side-effectful spec
23
+ # bootstrapping logic that should run on every spec run directly at the top
24
+ # level in a file loaded by `--require`, rather than in a `before(:suite)`
25
+ # hook. For example, consider a project that relies on some top-level logic
26
+ # in `spec_helper` to boot a Redis server for the test suite, intending the
27
+ # Redis bootstrapping to happen on every spec run. With `ShellRunner`, the
28
+ # bootstrapping logic will happen for each run of any subset of the suite,
29
+ # but for `ForkRunner`, such logic will only get run once, when the
30
+ # `RunDispatcher` boots the application environment. This might cause
31
+ # problems. The solution is for users to move the bootstrapping logic into
32
+ # a `before(:suite)` hook, or use the slower `ShellRunner`.
33
+ #
34
+ # @private
35
+ class ForkRunner
36
+ def self.start(shell_command, spec_runner)
37
+ instance = new(shell_command, spec_runner)
38
+ yield instance
39
+ ensure
40
+ instance.shutdown
41
+ end
42
+
43
+ def self.name
44
+ :fork
45
+ end
46
+
47
+ def initialize(shell_command, spec_runner)
48
+ @shell_command = shell_command
49
+ @channel = Channel.new
50
+ @run_dispatcher = RunDispatcher.new(spec_runner, @channel)
51
+ end
52
+
53
+ def run(locations)
54
+ run_descriptor = ExampleSetDescriptor.new(locations, original_results.failed_example_ids)
55
+ dispatch_run(run_descriptor)
56
+ end
57
+
58
+ def original_results
59
+ @original_results ||= dispatch_run(ExampleSetDescriptor.new(
60
+ @shell_command.original_locations, []))
61
+ end
62
+
63
+ def shutdown
64
+ @channel.close
65
+ end
66
+
67
+ private
68
+
69
+ def dispatch_run(run_descriptor)
70
+ @run_dispatcher.dispatch_specs(run_descriptor)
71
+ @channel.receive.tap do |result|
72
+ if result.is_a?(String)
73
+ raise BisectFailedError.for_failed_spec_run(result)
74
+ end
75
+ end
76
+ end
77
+
78
+ # @private
79
+ class RunDispatcher
80
+ def initialize(runner, channel)
81
+ @runner = runner
82
+ @channel = channel
83
+
84
+ @spec_output = StringIO.new
85
+
86
+ runner.configuration.tap do |c|
87
+ c.reset_reporter
88
+ c.output_stream = @spec_output
89
+ c.error_stream = @spec_output
90
+ end
91
+ end
92
+
93
+ def dispatch_specs(run_descriptor)
94
+ pid = fork { run_specs(run_descriptor) }
95
+ # We don't use Process.waitpid here as it was causing bisects to
96
+ # block due to the file descriptor limit on OSX / Linux. We need
97
+ # to detach the process to avoid having zombie processes
98
+ # consuming slots in the kernel process table during bisect runs.
99
+ Process.detach(pid)
100
+ end
101
+
102
+ private
103
+
104
+ def run_specs(run_descriptor)
105
+ $stdout = $stderr = @spec_output
106
+ formatter = CaptureFormatter.new(run_descriptor.failed_example_ids)
107
+
108
+ @runner.configuration.tap do |c|
109
+ c.files_or_directories_to_run = run_descriptor.all_example_ids
110
+ c.formatter = formatter
111
+ c.load_spec_files
112
+ end
113
+
114
+ # `announce_filters` has the side effect of implementing the logic
115
+ # that honors `config.run_all_when_everything_filtered` so we need
116
+ # to call it here. When we remove `run_all_when_everything_filtered`
117
+ # (slated for RSpec 4), we can remove this call to `announce_filters`.
118
+ @runner.world.announce_filters
119
+
120
+ @runner.run_specs(@runner.world.ordered_example_groups)
121
+ latest_run_results = formatter.results
122
+
123
+ if latest_run_results.nil? || latest_run_results.all_example_ids.empty?
124
+ @channel.send(@spec_output.string)
125
+ else
126
+ @channel.send(latest_run_results)
127
+ end
128
+ end
129
+ end
130
+
131
+ class CaptureFormatter < Formatters::BaseBisectFormatter
132
+ attr_accessor :results
133
+ alias_method :notify_results, :results=
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end