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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5dc4950a038b0b14b369336c70d967455853128a
4
- data.tar.gz: 2b2dcb195a0493c6876dbeceb8d6a8adfd643283
2
+ SHA256:
3
+ metadata.gz: dfc313a9688827e1869e5e7f8a77c48e4de3dae1e5c482ff025ff1ab10d8a5f9
4
+ data.tar.gz: 778eadf545aad964419c6726a1528d437270b271e144406e0bafe66dea7145ee
5
5
  SHA512:
6
- metadata.gz: 6cffc5f291e3a7187971a0da4fc6d9900b3022717dbbc4787843510362e6876914e0785011b2e91de4d0a2d48061866b1127acba386be59d00cc157243e6d8f1
7
- data.tar.gz: 8a347a71f03c00256b9725fa300ea3fdb23999adf48f1984ce144bbbfff08d830dc5f9391a4930afe8f9ce8981efc5a1c59caea6ae5fd79fbff0498dc124b93d
6
+ metadata.gz: 4e3079c080a916da726c6f5fc09d72a80c0f91273ef2cbbe1301708eb458b86773cf336c8f1aa297c819f882ee0b55952f86692c9db0fe2c0a62af5b7a8abf2e
7
+ data.tar.gz: 90d9fb02c3de9af80b516bf2b3b76520281a0926e16ba383e9384a86a7843be0f20268daba0dd0baa9ca2cb135e58e1bc123b15f5dffd3f0a269ab854b5e3316
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,3 +1,166 @@
1
+ ### 3.9.0 / 2019-10-07
2
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.2...v3.9.0)
3
+
4
+ Enhancements:
5
+ * Improve the handling of errors during loading support files, if a file
6
+ errors before loading specs, RSpec will now skip loading the specs.
7
+ (David Rodríguez, #2568)
8
+ * Add support for --example-matches to run examples by regular expression.
9
+ (Sam Joseph, Matt Rider, @okothkongo1, #2586)
10
+ * Add `did_you_mean` suggestions for file names encountering a `LoadError`
11
+ outside of examples. (@obromios, #2601)
12
+ * Add a minimalist quick fix style formatter, only outputs failures as
13
+ `file:line:message`. (Romain Tartière, #2614)
14
+ * Convert string number values to integer when used for `RSpec::Configuration#fail_fast`
15
+ (Viktor Fonic, #2634)
16
+ * Issue warning when invalid values are used for `RSpec::Configuration#fail_fast`
17
+ (Viktor Fonic, #2634)
18
+ * Add support for running the Rake task in a clean environment.
19
+ (Jon Rowe, #2632)
20
+ * Indent messages by there example group / example in the documentation formatter.
21
+ (Samuel Williams, #2649)
22
+
23
+ ### 3.8.2 / 2019-06-29
24
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.1...v3.8.2)
25
+
26
+ Bug Fixes:
27
+
28
+ * Fix `config.define_derived_metadata` so that cascades are not triggered
29
+ until metadata has been assigned to the example or example group
30
+ (Myron Marston, #2635).
31
+
32
+ ### 3.8.1 / 2019-06-13
33
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.0...v3.8.1)
34
+
35
+ Bug Fixes:
36
+
37
+ * Handle RSpec description(s) with japanese chars in CP932 encoded files.
38
+ (Benoit Tigeot, #2575)
39
+ * When defining `let` methods that overwrite an existing method, prevent
40
+ a warning being issued by removing the old definition. (Jon Rowe, #2593)
41
+ * Prevent warning on Ruby 2.6.0-rc1 (Keiji Yoshimi, #2582)
42
+ * Fix `config.define_derived_metadata` so that it supports cascades.
43
+ (Myron Marston, #2630).
44
+
45
+ ### 3.8.0 / 2018-08-04
46
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.7.1...v3.8.0)
47
+
48
+ Enhancements:
49
+
50
+ * Improve shell escaping used by `RSpec::Core::RakeTask` and `--bisect` so
51
+ that it works on `Pathname` objects. (Andrew Vit, #2479)
52
+ * Nicely format errors encountered while loading files specified
53
+ by `--require` option. (Myron Marston, #2504)
54
+ * Significantly improve the performance of `--bisect` on platforms that
55
+ support forking by replacing the shell-based runner with one that uses
56
+ forking so that RSpec and the application environment can be booted only
57
+ once, instead of once per spec run. (Myron Marston, #2511)
58
+ * Provide a configuration API to pick which bisect runner is used for
59
+ `--bisect`. Pick a runner via `config.bisect_runner = :shell` or
60
+ `config.bisect_runner = :fork` in a file loaded by a `--require`
61
+ option passed at the command line or set in `.rspec`. (Myron Marston, #2511)
62
+ * Support the [XDG Base Directory
63
+ Specification](https://specifications.freedesktop.org/basedir-spec/latest/)
64
+ for the global options file. `~/.rspec` is still supported when no
65
+ options file is found in `$XDG_CONFIG_HOME/rspec/options` (Magnus Bergmark, #2538)
66
+ * Extract `RSpec.world.prepare_example_filtering` that sets up the
67
+ example filtering for custom RSpec runners. (Oleg Pudeyev, #2552)
68
+
69
+ Bug Fixes:
70
+
71
+ * Prevent an `ArgumentError` when truncating backtraces with two identical
72
+ backtraces. (Systho, #2515, Benoit Tigeot, #2539)
73
+
74
+ ### 3.7.1 / 2018-01-02
75
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.7.0...v3.7.1)
76
+
77
+ Bug Fixes:
78
+
79
+ * Work around duplicate config hook regression introduced
80
+ by Ruby 2.5's lazy proc allocation. (Myron Marston, #2497)
81
+
82
+ ### 3.7.0 / 2017-10-17
83
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.6.0...v3.7.0)
84
+
85
+ Enhancements:
86
+
87
+ * Add `-n` alias for `--next-failure`. (Ian Ker-Seymer, #2434)
88
+ * Improve compatibility with `--enable-frozen-string-literal` option
89
+ on Ruby 2.3+. (Pat Allan, #2425, #2427, #2437)
90
+ * Do not run `:context` hooks for example groups that have been skipped.
91
+ (Devon Estes, #2442)
92
+ * Add `errors_outside_of_examples_count` to the JSON formatter.
93
+ (Takeshi Arabiki, #2448)
94
+
95
+ Bug Fixes:
96
+
97
+ * Improve compatibility with frozen string literal flag. (#2425, Pat Allan)
98
+
99
+ ### 3.6.0 / 2017-05-04
100
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.6.0.beta2...v3.6.0)
101
+
102
+ Enhancements:
103
+
104
+ * Add seed information to JSON formatter output. (#2388, Mitsutaka Mimura)
105
+ * Include example id in the JSON formatter output. (#2369, Xavier Shay)
106
+ * Respect changes to `config.output_stream` after formatters have been
107
+ setup. (#2401, #2419, Ilya Lavrov)
108
+
109
+ Bug Fixes:
110
+
111
+ * Delay formatter loading until the last minute to allow accessing the reporter
112
+ without triggering formatter setup. (Jon Rowe, #2243)
113
+ * Ensure context hook failures running before an example can access the
114
+ reporter. (Jon Jensen, #2387)
115
+ * Multiple fixes to allow using the runner multiple times within the same
116
+ process: `RSpec.clear_examples` resets the formatter and no longer clears
117
+ shared examples, and streams can be used across multiple runs rather than
118
+ being closed after the first. (#2368, Xavier Shay)
119
+ * Prevent unexpected `example_group_finished` notifications causing an error.
120
+ (#2396, VTJamie)
121
+ * Fix bugs where `config.when_first_matching_example_defined` hooks would fire
122
+ multiple times in some cases. (Yuji Nakayama, #2400)
123
+ * Default `last_run_status` to "unknown" when the `status` field in the
124
+ persistence file contains an unrecognized value. (#2360, matrinox)
125
+ * Prevent `let` from defining an `initialize` method. (#2414, Jon Rowe)
126
+
127
+ ### 3.6.0.beta2 / 2016-12-12
128
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.6.0.beta1...v3.6.0.beta2)
129
+
130
+ Enhancements:
131
+
132
+ * Include count of errors occurring outside examples in default summaries.
133
+ (#2351, Jon Rowe)
134
+ * Warn when including shared example groups recursively. (#2356, Jon Rowe)
135
+ * Improve failure snippet syntax highlighting with CodeRay to highlight
136
+ RSpec "keywords" like `expect`. (#2358, Myron Marston)
137
+
138
+ ### 3.6.0.beta1 / 2016-10-09
139
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.5.4...v3.6.0.beta1)
140
+
141
+ Enhancements:
142
+
143
+ * Warn when duplicate shared examples definitions are loaded due to being
144
+ defined in files matching the spec pattern (e.g. `_spec.rb`) (#2278, Devon Estes)
145
+ * Improve metadata filtering so that it can match against any object
146
+ that implements `===` instead of treating regular expressions as
147
+ special. (Myron Marston, #2294)
148
+ * Improve `rspec -v` so that it prints out the versions of each part of
149
+ RSpec to prevent confusion. (Myron Marston, #2304)
150
+ * Add `config.fail_if_no_examples` option which causes RSpec to fail if
151
+ no examples are found. (Ewa Czechowska, #2302)
152
+ * Nicely format errors encountered while loading spec files.
153
+ (Myron Marston, #2323)
154
+ * Improve the API for enabling and disabling color output (Josh
155
+ Justice, #2321):
156
+ * Automatically enable color if the output is a TTY, since color is
157
+ nearly always desirable if the output can handle it.
158
+ * Introduce new CLI flag to force color on (`--force-color`), even
159
+ if the output is not a TTY. `--no-color` continues to work as well.
160
+ * Introduce `config.color_mode` for configuring the color from Ruby.
161
+ `:automatic` is the default and will produce color if the output is
162
+ a TTY. `:on` forces it on and `:off` forces it off.
163
+
1
164
  ### 3.5.4 / 2016-09-30
2
165
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.5.3...v3.5.4)
3
166
 
@@ -1863,7 +2026,7 @@ project's root directory or in your home directory:
1863
2026
 
1864
2027
  require "autotest/bundler"
1865
2028
 
1866
- Now you can just type 'autotest' on the commmand line and it will work as you expect.
2029
+ Now you can just type 'autotest' on the command line and it will work as you expect.
1867
2030
 
1868
2031
  If you don't want 'bundle exec', there is nothing you have to do.
1869
2032
 
@@ -2051,7 +2214,7 @@ Bug fixes
2051
2214
  Enhancements
2052
2215
 
2053
2216
  * implicitly require unknown formatters so you don't have to require the file
2054
- explicitly on the commmand line (Michael Grosser)
2217
+ explicitly on the command line (Michael Grosser)
2055
2218
  * add --out/-o option to assign output target
2056
2219
  * added fail_fast configuration option to abort on first failure
2057
2220
  * support a Hash subject (its([:key]) { should == value }) (Josep M. Bach)
data/README.md CHANGED
@@ -15,24 +15,10 @@ 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 => 'master'
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)
@@ -69,7 +69,7 @@ module RSpec
69
69
  # same process.
70
70
  def self.clear_examples
71
71
  world.reset
72
- configuration.reporter.reset
72
+ configuration.reset_reporter
73
73
  configuration.start_time = ::RSpec::Core::Time.now
74
74
  configuration.reset_filters
75
75
  end
@@ -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,134 @@
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 master 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
+ Process.waitpid(pid)
96
+ end
97
+
98
+ private
99
+
100
+ def run_specs(run_descriptor)
101
+ $stdout = $stderr = @spec_output
102
+ formatter = CaptureFormatter.new(run_descriptor.failed_example_ids)
103
+
104
+ @runner.configuration.tap do |c|
105
+ c.files_or_directories_to_run = run_descriptor.all_example_ids
106
+ c.formatter = formatter
107
+ c.load_spec_files
108
+ end
109
+
110
+ # `announce_filters` has the side effect of implementing the logic
111
+ # that honors `config.run_all_when_everything_filtered` so we need
112
+ # to call it here. When we remove `run_all_when_everything_filtered`
113
+ # (slated for RSpec 4), we can remove this call to `announce_filters`.
114
+ @runner.world.announce_filters
115
+
116
+ @runner.run_specs(@runner.world.ordered_example_groups)
117
+ latest_run_results = formatter.results
118
+
119
+ if latest_run_results.nil? || latest_run_results.all_example_ids.empty?
120
+ @channel.send(@spec_output.string)
121
+ else
122
+ @channel.send(latest_run_results)
123
+ end
124
+ end
125
+ end
126
+
127
+ class CaptureFormatter < Formatters::BaseBisectFormatter
128
+ attr_accessor :results
129
+ alias_method :notify_results, :results=
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end