rspec-core 3.0.4 → 3.12.2

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 (85) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +2 -1
  5. data/Changelog.md +888 -2
  6. data/{License.txt → LICENSE.md} +6 -5
  7. data/README.md +165 -24
  8. data/lib/rspec/autorun.rb +1 -0
  9. data/lib/rspec/core/backtrace_formatter.rb +19 -20
  10. data/lib/rspec/core/bisect/coordinator.rb +62 -0
  11. data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
  12. data/lib/rspec/core/bisect/fork_runner.rb +138 -0
  13. data/lib/rspec/core/bisect/server.rb +61 -0
  14. data/lib/rspec/core/bisect/shell_command.rb +126 -0
  15. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  16. data/lib/rspec/core/bisect/utilities.rb +69 -0
  17. data/lib/rspec/core/configuration.rb +1287 -246
  18. data/lib/rspec/core/configuration_options.rb +95 -35
  19. data/lib/rspec/core/did_you_mean.rb +46 -0
  20. data/lib/rspec/core/drb.rb +21 -12
  21. data/lib/rspec/core/dsl.rb +10 -6
  22. data/lib/rspec/core/example.rb +305 -113
  23. data/lib/rspec/core/example_group.rb +431 -223
  24. data/lib/rspec/core/example_status_persister.rb +235 -0
  25. data/lib/rspec/core/filter_manager.rb +86 -115
  26. data/lib/rspec/core/flat_map.rb +6 -4
  27. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  28. data/lib/rspec/core/formatters/base_formatter.rb +14 -116
  29. data/lib/rspec/core/formatters/base_text_formatter.rb +18 -21
  30. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  31. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
  32. data/lib/rspec/core/formatters/console_codes.rb +29 -18
  33. data/lib/rspec/core/formatters/deprecation_formatter.rb +16 -16
  34. data/lib/rspec/core/formatters/documentation_formatter.rb +49 -16
  35. data/lib/rspec/core/formatters/exception_presenter.rb +525 -0
  36. data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
  37. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  38. data/lib/rspec/core/formatters/helpers.rb +45 -15
  39. data/lib/rspec/core/formatters/html_formatter.rb +33 -28
  40. data/lib/rspec/core/formatters/html_printer.rb +30 -20
  41. data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
  42. data/lib/rspec/core/formatters/json_formatter.rb +18 -9
  43. data/lib/rspec/core/formatters/profile_formatter.rb +10 -9
  44. data/lib/rspec/core/formatters/progress_formatter.rb +5 -4
  45. data/lib/rspec/core/formatters/protocol.rb +182 -0
  46. data/lib/rspec/core/formatters/snippet_extractor.rb +113 -82
  47. data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
  48. data/lib/rspec/core/formatters.rb +81 -41
  49. data/lib/rspec/core/hooks.rb +314 -244
  50. data/lib/rspec/core/invocations.rb +87 -0
  51. data/lib/rspec/core/memoized_helpers.rb +161 -51
  52. data/lib/rspec/core/metadata.rb +132 -61
  53. data/lib/rspec/core/metadata_filter.rb +224 -64
  54. data/lib/rspec/core/minitest_assertions_adapter.rb +6 -3
  55. data/lib/rspec/core/mocking_adapters/flexmock.rb +4 -2
  56. data/lib/rspec/core/mocking_adapters/mocha.rb +11 -9
  57. data/lib/rspec/core/mocking_adapters/null.rb +2 -0
  58. data/lib/rspec/core/mocking_adapters/rr.rb +3 -1
  59. data/lib/rspec/core/mocking_adapters/rspec.rb +3 -1
  60. data/lib/rspec/core/notifications.rb +192 -206
  61. data/lib/rspec/core/option_parser.rb +174 -69
  62. data/lib/rspec/core/ordering.rb +48 -35
  63. data/lib/rspec/core/output_wrapper.rb +29 -0
  64. data/lib/rspec/core/pending.rb +25 -33
  65. data/lib/rspec/core/profiler.rb +34 -0
  66. data/lib/rspec/core/project_initializer/.rspec +0 -2
  67. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +59 -39
  68. data/lib/rspec/core/project_initializer.rb +5 -3
  69. data/lib/rspec/core/rake_task.rb +99 -55
  70. data/lib/rspec/core/reporter.rb +128 -15
  71. data/lib/rspec/core/ruby_project.rb +14 -6
  72. data/lib/rspec/core/runner.rb +96 -45
  73. data/lib/rspec/core/sandbox.rb +37 -0
  74. data/lib/rspec/core/set.rb +54 -0
  75. data/lib/rspec/core/shared_example_group.rb +133 -43
  76. data/lib/rspec/core/shell_escape.rb +49 -0
  77. data/lib/rspec/core/test_unit_assertions_adapter.rb +4 -4
  78. data/lib/rspec/core/version.rb +1 -1
  79. data/lib/rspec/core/warnings.rb +6 -6
  80. data/lib/rspec/core/world.rb +172 -68
  81. data/lib/rspec/core.rb +66 -21
  82. data.tar.gz.sig +0 -0
  83. metadata +93 -69
  84. metadata.gz.sig +0 -0
  85. data/lib/rspec/core/backport_random.rb +0 -336
@@ -1,12 +1,12 @@
1
1
  require 'erb'
2
2
  require 'shellwords'
3
- require 'set'
4
3
 
5
4
  module RSpec
6
5
  module Core
7
6
  # Responsible for utilizing externally provided configuration options,
8
- # whether via the command line, `.rspec`, `~/.rspec`, `.rspec-local`
9
- # or a custom options file.
7
+ # whether via the command line, `.rspec`, `~/.rspec`,
8
+ # `$XDG_CONFIG_HOME/rspec/options`, `.rspec-local` or a custom options
9
+ # file.
10
10
  class ConfigurationOptions
11
11
  # @param args [Array<String>] command line arguments
12
12
  def initialize(args)
@@ -36,34 +36,39 @@ module RSpec
36
36
  # @return [Hash] the final merged options, drawn from all external sources
37
37
  attr_reader :options
38
38
 
39
+ # @return [Array<String>] the original command-line arguments
40
+ attr_reader :args
41
+
39
42
  private
40
43
 
41
44
  def organize_options
42
45
  @filter_manager_options = []
43
46
 
44
- @options = (file_options << command_line_options << env_options).each { |opts|
47
+ @options = (file_options << command_line_options << env_options).each do |opts|
45
48
  @filter_manager_options << [:include, opts.delete(:inclusion_filter)] if opts.key?(:inclusion_filter)
46
49
  @filter_manager_options << [:exclude, opts.delete(:exclusion_filter)] if opts.key?(:exclusion_filter)
47
- }.inject(:libs => [], :requires => []) { |hash, opts|
48
- hash.merge(opts) { |key, oldval, newval|
50
+ end
51
+
52
+ @options = @options.inject(:libs => [], :requires => []) do |hash, opts|
53
+ hash.merge(opts) do |key, oldval, newval|
49
54
  [:libs, :requires].include?(key) ? oldval + newval : newval
50
- }
51
- }
55
+ end
56
+ end
52
57
  end
53
58
 
54
- UNFORCED_OPTIONS = [
59
+ UNFORCED_OPTIONS = Set.new([
55
60
  :requires, :profile, :drb, :libs, :files_or_directories_to_run,
56
61
  :full_description, :full_backtrace, :tty
57
- ].to_set
62
+ ])
58
63
 
59
- UNPROCESSABLE_OPTIONS = [:formatters].to_set
64
+ UNPROCESSABLE_OPTIONS = Set.new([:formatters])
60
65
 
61
66
  def force?(key)
62
67
  !UNFORCED_OPTIONS.include?(key)
63
68
  end
64
69
 
65
70
  def order(keys)
66
- OPTIONS_ORDER.reverse.each do |key|
71
+ OPTIONS_ORDER.reverse_each do |key|
67
72
  keys.unshift(key) if keys.delete(key)
68
73
  end
69
74
  keys
@@ -80,17 +85,24 @@ module RSpec
80
85
 
81
86
  # `files_or_directories_to_run` uses `default_path` so it must be
82
87
  # set before it.
83
- :default_path,
84
-
85
- # These must be set before `requires` to support checking `config.files_to_run`
86
- # from within `spec_helper.rb` when a `-rspec_helper` option is used.
87
- :files_or_directories_to_run, :pattern,
88
-
89
- # In general, we want to require the specified files as early as possible.
90
- # The `--require` option is specifically intended to allow early requires.
91
- # For later requires, they can just put the require in their spec files, but
92
- # `--require` provides a unique opportunity for users to instruct RSpec to
93
- # load an extension file early for maximum flexibility.
88
+ :default_path, :only_failures,
89
+
90
+ # These must be set before `requires` to support checking
91
+ # `config.files_to_run` from within `spec_helper.rb` when a
92
+ # `-rspec_helper` option is used.
93
+ :files_or_directories_to_run, :pattern, :exclude_pattern,
94
+
95
+ # Necessary so that the `--seed` option is applied before requires,
96
+ # in case required files do something with the provided seed.
97
+ # (such as seed global randomization with it).
98
+ :order,
99
+
100
+ # In general, we want to require the specified files as early as
101
+ # possible. The `--require` option is specifically intended to allow
102
+ # early requires. For later requires, they can just put the require in
103
+ # their spec files, but `--require` provides a unique opportunity for
104
+ # users to instruct RSpec to load an extension file early for maximum
105
+ # flexibility.
94
106
  :requires
95
107
  ]
96
108
 
@@ -107,15 +119,24 @@ module RSpec
107
119
  end
108
120
 
109
121
  def file_options
110
- custom_options_file ? [custom_options] : [global_options, project_options, local_options]
122
+ if custom_options_file
123
+ [custom_options]
124
+ else
125
+ [global_options, project_options, local_options]
126
+ end
111
127
  end
112
128
 
113
129
  def env_options
114
- ENV["SPEC_OPTS"] ? Parser.parse(Shellwords.split(ENV["SPEC_OPTS"])) : {}
130
+ return {} unless ENV['SPEC_OPTS']
131
+
132
+ parse_args_ignoring_files_or_dirs_to_run(
133
+ Shellwords.split(ENV["SPEC_OPTS"]),
134
+ "ENV['SPEC_OPTS']"
135
+ )
115
136
  end
116
137
 
117
138
  def command_line_options
118
- @command_line_options ||= Parser.parse(@args).merge :files_or_directories_to_run => @args
139
+ @command_line_options ||= Parser.parse(@args)
119
140
  end
120
141
 
121
142
  def custom_options
@@ -135,7 +156,14 @@ module RSpec
135
156
  end
136
157
 
137
158
  def options_from(path)
138
- Parser.parse(args_from_options_file(path))
159
+ args = args_from_options_file(path)
160
+ parse_args_ignoring_files_or_dirs_to_run(args, path)
161
+ end
162
+
163
+ def parse_args_ignoring_files_or_dirs_to_run(args, source)
164
+ options = Parser.parse(args, source)
165
+ options.delete(:files_or_directories_to_run)
166
+ options
139
167
  end
140
168
 
141
169
  def args_from_options_file(path)
@@ -145,7 +173,11 @@ module RSpec
145
173
  end
146
174
 
147
175
  def options_file_as_erb_string(path)
148
- ERB.new(File.read(path), nil, '-').result(binding)
176
+ if RUBY_VERSION >= '2.6'
177
+ ERB.new(File.read(path), :trim_mode => '-').result(binding)
178
+ else
179
+ ERB.new(File.read(path), nil, '-').result(binding)
180
+ end
149
181
  end
150
182
 
151
183
  def custom_options_file
@@ -153,21 +185,49 @@ module RSpec
153
185
  end
154
186
 
155
187
  def project_options_file
156
- ".rspec"
188
+ "./.rspec"
157
189
  end
158
190
 
159
191
  def local_options_file
160
- ".rspec-local"
192
+ "./.rspec-local"
161
193
  end
162
194
 
163
195
  def global_options_file
164
- begin
165
- File.join(File.expand_path("~"), ".rspec")
166
- rescue ArgumentError
167
- RSpec.warning "Unable to find ~/.rspec because the HOME environment variable is not set"
168
- nil
196
+ xdg_options_file_if_exists || home_options_file_path
197
+ end
198
+
199
+ def xdg_options_file_if_exists
200
+ path = xdg_options_file_path
201
+ if path && File.exist?(path)
202
+ path
203
+ end
204
+ end
205
+
206
+ def home_options_file_path
207
+ File.join(File.expand_path("~"), ".rspec")
208
+ rescue ArgumentError
209
+ # :nocov:
210
+ RSpec.warning "Unable to find ~/.rspec because the HOME environment variable is not set"
211
+ nil
212
+ # :nocov:
213
+ end
214
+
215
+ def xdg_options_file_path
216
+ xdg_config_home = resolve_xdg_config_home
217
+ if xdg_config_home
218
+ File.join(xdg_config_home, "rspec", "options")
169
219
  end
170
220
  end
221
+
222
+ def resolve_xdg_config_home
223
+ File.expand_path(ENV.fetch("XDG_CONFIG_HOME", "~/.config"))
224
+ rescue ArgumentError
225
+ # :nocov:
226
+ # On Ruby 2.4, `File.expand("~")` works even if `ENV['HOME']` is not set.
227
+ # But on earlier versions, it fails.
228
+ nil
229
+ # :nocov:
230
+ end
171
231
  end
172
232
  end
173
233
  end
@@ -0,0 +1,46 @@
1
+ module RSpec
2
+ module Core
3
+ # @private
4
+ # Wrapper around Ruby's `DidYouMean::SpellChecker` when available to provide file name suggestions.
5
+ class DidYouMean
6
+ attr_reader :relative_file_name
7
+
8
+ def initialize(relative_file_name)
9
+ @relative_file_name = relative_file_name
10
+ end
11
+
12
+ if defined?(::DidYouMean::SpellChecker)
13
+ # provide probable suggestions
14
+ def call
15
+ checker = ::DidYouMean::SpellChecker.new(:dictionary => Dir["spec/**/*.rb"])
16
+ probables = checker.correct(relative_file_name.sub('./', ''))[0..2]
17
+ return '' unless probables.any?
18
+
19
+ formats probables
20
+ end
21
+ else
22
+ # return a hint if API for ::DidYouMean::SpellChecker not supported
23
+ def call
24
+ "\nHint: Install the `did_you_mean` gem in order to provide suggestions for similarly named files."
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def formats(probables)
31
+ rspec_format = probables.map { |s, _| "rspec ./#{s}" }
32
+ red_font(top_and_tail rspec_format)
33
+ end
34
+
35
+ def top_and_tail(rspec_format)
36
+ spaces = ' ' * 20
37
+ rspec_format.insert(0, ' - Did you mean?').join("\n#{spaces}") + "\n"
38
+ end
39
+
40
+ def red_font(mytext)
41
+ colorizer = ::RSpec::Core::Formatters::ConsoleCodes
42
+ colorizer.wrap mytext, :failure
43
+ end
44
+ end
45
+ end
46
+ end
@@ -41,6 +41,8 @@ module RSpec
41
41
  def options
42
42
  argv = []
43
43
  argv << "--color" if @submitted_options[:color]
44
+ argv << "--force-color" if @submitted_options[:color_mode] == :on
45
+ argv << "--no-color" if @submitted_options[:color_mode] == :off
44
46
  argv << "--profile" if @submitted_options[:profile_examples]
45
47
  argv << "--backtrace" if @submitted_options[:full_backtrace]
46
48
  argv << "--tty" if @submitted_options[:tty]
@@ -49,6 +51,7 @@ module RSpec
49
51
  argv << "--order" << @submitted_options[:order] if @submitted_options[:order]
50
52
 
51
53
  add_failure_exit_code(argv)
54
+ add_error_exit_code(argv)
52
55
  add_full_description(argv)
53
56
  add_filter(argv, :inclusion, @filter_manager.inclusions)
54
57
  add_filter(argv, :exclusion, @filter_manager.exclusions)
@@ -60,20 +63,26 @@ module RSpec
60
63
  end
61
64
 
62
65
  def add_failure_exit_code(argv)
63
- if @submitted_options[:failure_exit_code]
64
- argv << "--failure-exit-code" << @submitted_options[:failure_exit_code].to_s
65
- end
66
+ return unless @submitted_options[:failure_exit_code]
67
+
68
+ argv << "--failure-exit-code" << @submitted_options[:failure_exit_code].to_s
69
+ end
70
+
71
+ def add_error_exit_code(argv)
72
+ return unless @submitted_options[:error_exit_code]
73
+
74
+ argv << "--error-exit-code" << @submitted_options[:error_exit_code].to_s
66
75
  end
67
76
 
68
77
  def add_full_description(argv)
69
- if @submitted_options[:full_description]
70
- # The argument to --example is regexp-escaped before being stuffed
71
- # into a regexp when received for the first time (see OptionParser).
72
- # Hence, merely grabbing the source of this regexp will retain the
73
- # backslashes, so we must remove them.
74
- @submitted_options[:full_description].each do |description|
75
- argv << "--example" << description.source.delete('\\')
76
- end
78
+ return unless @submitted_options[:full_description]
79
+
80
+ # The argument to --example is regexp-escaped before being stuffed
81
+ # into a regexp when received for the first time (see OptionParser).
82
+ # Hence, merely grabbing the source of this regexp will retain the
83
+ # backslashes, so we must remove them.
84
+ @submitted_options[:full_description].each do |description|
85
+ argv << "--example" << description.source.delete('\\')
77
86
  end
78
87
  end
79
88
 
@@ -82,7 +91,7 @@ module RSpec
82
91
  def add_filter(argv, name, hash)
83
92
  hash.each_pair do |k, v|
84
93
  next if CONDITIONAL_FILTERS.include?(k)
85
- tag = name == :inclusion ? k.to_s : "~#{k}"
94
+ tag = name == :inclusion ? k.to_s : "~#{k}".dup
86
95
  tag << ":#{v}" if v.is_a?(String)
87
96
  argv << "--tag" << tag
88
97
  end unless hash.empty?
@@ -8,7 +8,7 @@ module RSpec
8
8
  # By default the methods `describe`, `context` and `example_group`
9
9
  # are exposed. These methods define a named context for one or
10
10
  # more examples. The given block is evaluated in the context of
11
- # a generated subclass of {RSpec::Core::ExampleGroup}
11
+ # a generated subclass of {RSpec::Core::ExampleGroup}.
12
12
  #
13
13
  # ## Examples:
14
14
  #
@@ -35,10 +35,14 @@ module RSpec
35
35
 
36
36
  # @private
37
37
  def self.expose_example_group_alias(name)
38
+ return if example_group_aliases.include?(name)
39
+
38
40
  example_group_aliases << name
39
41
 
40
42
  (class << RSpec; self; end).__send__(:define_method, name) do |*args, &example_group_block|
41
- RSpec.world.register RSpec::Core::ExampleGroup.__send__(name, *args, &example_group_block)
43
+ group = RSpec::Core::ExampleGroup.__send__(name, *args, &example_group_block)
44
+ RSpec.world.record(group)
45
+ group
42
46
  end
43
47
 
44
48
  expose_example_group_alias_globally(name) if exposed_globally?
@@ -49,7 +53,7 @@ module RSpec
49
53
  attr_accessor :top_level
50
54
  end
51
55
 
52
- # Adds the describe method to Module and the top level binding
56
+ # Adds the describe method to Module and the top level binding.
53
57
  # @api private
54
58
  def self.expose_globally!
55
59
  return if exposed_globally?
@@ -61,7 +65,7 @@ module RSpec
61
65
  @exposed_globally = true
62
66
  end
63
67
 
64
- # Removes the describe method from Module and the top level binding
68
+ # Removes the describe method from Module and the top level binding.
65
69
  # @api private
66
70
  def self.remove_globally!
67
71
  return unless exposed_globally?
@@ -76,6 +80,7 @@ module RSpec
76
80
  # @private
77
81
  def self.expose_example_group_alias_globally(method_name)
78
82
  change_global_dsl do
83
+ remove_method(method_name) if method_defined?(method_name)
79
84
  define_method(method_name) { |*a, &b| ::RSpec.__send__(method_name, *a, &b) }
80
85
  end
81
86
  end
@@ -85,10 +90,9 @@ module RSpec
85
90
  (class << top_level; self; end).class_exec(&changes)
86
91
  Module.class_exec(&changes)
87
92
  end
88
-
89
93
  end
90
94
  end
91
95
  end
92
96
 
93
- # capture main without an eval
97
+ # Capture main without an eval.
94
98
  ::RSpec::Core::DSL.top_level = self