rspec-core 3.8.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 (84) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.document +5 -0
  5. data/.yardopts +8 -0
  6. data/Changelog.md +2243 -0
  7. data/LICENSE.md +26 -0
  8. data/README.md +384 -0
  9. data/exe/rspec +4 -0
  10. data/lib/rspec/autorun.rb +3 -0
  11. data/lib/rspec/core.rb +185 -0
  12. data/lib/rspec/core/backtrace_formatter.rb +65 -0
  13. data/lib/rspec/core/bisect/coordinator.rb +62 -0
  14. data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
  15. data/lib/rspec/core/bisect/fork_runner.rb +134 -0
  16. data/lib/rspec/core/bisect/server.rb +61 -0
  17. data/lib/rspec/core/bisect/shell_command.rb +126 -0
  18. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  19. data/lib/rspec/core/bisect/utilities.rb +58 -0
  20. data/lib/rspec/core/configuration.rb +2308 -0
  21. data/lib/rspec/core/configuration_options.rb +233 -0
  22. data/lib/rspec/core/drb.rb +113 -0
  23. data/lib/rspec/core/dsl.rb +98 -0
  24. data/lib/rspec/core/example.rb +656 -0
  25. data/lib/rspec/core/example_group.rb +889 -0
  26. data/lib/rspec/core/example_status_persister.rb +235 -0
  27. data/lib/rspec/core/filter_manager.rb +231 -0
  28. data/lib/rspec/core/flat_map.rb +20 -0
  29. data/lib/rspec/core/formatters.rb +269 -0
  30. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  31. data/lib/rspec/core/formatters/base_formatter.rb +70 -0
  32. data/lib/rspec/core/formatters/base_text_formatter.rb +75 -0
  33. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  34. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
  35. data/lib/rspec/core/formatters/console_codes.rb +68 -0
  36. data/lib/rspec/core/formatters/deprecation_formatter.rb +223 -0
  37. data/lib/rspec/core/formatters/documentation_formatter.rb +70 -0
  38. data/lib/rspec/core/formatters/exception_presenter.rb +508 -0
  39. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  40. data/lib/rspec/core/formatters/helpers.rb +110 -0
  41. data/lib/rspec/core/formatters/html_formatter.rb +153 -0
  42. data/lib/rspec/core/formatters/html_printer.rb +414 -0
  43. data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
  44. data/lib/rspec/core/formatters/json_formatter.rb +102 -0
  45. data/lib/rspec/core/formatters/profile_formatter.rb +68 -0
  46. data/lib/rspec/core/formatters/progress_formatter.rb +29 -0
  47. data/lib/rspec/core/formatters/protocol.rb +182 -0
  48. data/lib/rspec/core/formatters/snippet_extractor.rb +134 -0
  49. data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
  50. data/lib/rspec/core/hooks.rb +624 -0
  51. data/lib/rspec/core/invocations.rb +87 -0
  52. data/lib/rspec/core/memoized_helpers.rb +554 -0
  53. data/lib/rspec/core/metadata.rb +498 -0
  54. data/lib/rspec/core/metadata_filter.rb +255 -0
  55. data/lib/rspec/core/minitest_assertions_adapter.rb +31 -0
  56. data/lib/rspec/core/mocking_adapters/flexmock.rb +31 -0
  57. data/lib/rspec/core/mocking_adapters/mocha.rb +57 -0
  58. data/lib/rspec/core/mocking_adapters/null.rb +14 -0
  59. data/lib/rspec/core/mocking_adapters/rr.rb +31 -0
  60. data/lib/rspec/core/mocking_adapters/rspec.rb +32 -0
  61. data/lib/rspec/core/notifications.rb +521 -0
  62. data/lib/rspec/core/option_parser.rb +309 -0
  63. data/lib/rspec/core/ordering.rb +158 -0
  64. data/lib/rspec/core/output_wrapper.rb +29 -0
  65. data/lib/rspec/core/pending.rb +165 -0
  66. data/lib/rspec/core/profiler.rb +34 -0
  67. data/lib/rspec/core/project_initializer.rb +48 -0
  68. data/lib/rspec/core/project_initializer/.rspec +1 -0
  69. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +100 -0
  70. data/lib/rspec/core/rake_task.rb +168 -0
  71. data/lib/rspec/core/reporter.rb +257 -0
  72. data/lib/rspec/core/ruby_project.rb +53 -0
  73. data/lib/rspec/core/runner.rb +199 -0
  74. data/lib/rspec/core/sandbox.rb +37 -0
  75. data/lib/rspec/core/set.rb +54 -0
  76. data/lib/rspec/core/shared_context.rb +55 -0
  77. data/lib/rspec/core/shared_example_group.rb +269 -0
  78. data/lib/rspec/core/shell_escape.rb +49 -0
  79. data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
  80. data/lib/rspec/core/version.rb +9 -0
  81. data/lib/rspec/core/warnings.rb +40 -0
  82. data/lib/rspec/core/world.rb +275 -0
  83. metadata +292 -0
  84. metadata.gz.sig +0 -0
@@ -0,0 +1,309 @@
1
+ # http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html
2
+ require 'optparse'
3
+
4
+ module RSpec::Core
5
+ # @private
6
+ class Parser
7
+ def self.parse(args, source=nil)
8
+ new(args).parse(source)
9
+ end
10
+
11
+ attr_reader :original_args
12
+
13
+ def initialize(original_args)
14
+ @original_args = original_args
15
+ end
16
+
17
+ def parse(source=nil)
18
+ return { :files_or_directories_to_run => [] } if original_args.empty?
19
+ args = original_args.dup
20
+
21
+ options = args.delete('--tty') ? { :tty => true } : {}
22
+ begin
23
+ parser(options).parse!(args)
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"
28
+ end
29
+
30
+ options[:files_or_directories_to_run] = args
31
+ options
32
+ end
33
+
34
+ private
35
+
36
+ # rubocop:disable MethodLength
37
+ # rubocop:disable Metrics/AbcSize
38
+ # rubocop:disable CyclomaticComplexity
39
+ # rubocop:disable PerceivedComplexity
40
+ def parser(options)
41
+ OptionParser.new do |parser|
42
+ parser.summary_width = 34
43
+
44
+ parser.banner = "Usage: rspec [options] [files or directories]\n\n"
45
+
46
+ parser.on('-I PATH', 'Specify PATH to add to $LOAD_PATH (may be used more than once).') do |dirs|
47
+ options[:libs] ||= []
48
+ options[:libs].concat(dirs.split(File::PATH_SEPARATOR))
49
+ end
50
+
51
+ parser.on('-r', '--require PATH', 'Require a file.') do |path|
52
+ options[:requires] ||= []
53
+ options[:requires] << path
54
+ end
55
+
56
+ parser.on('-O', '--options PATH', 'Specify the path to a custom options file.') do |path|
57
+ options[:custom_options_file] = path
58
+ end
59
+
60
+ parser.on('--order TYPE[:SEED]', 'Run examples by the specified order type.',
61
+ ' [defined] examples and groups are run in the order they are defined',
62
+ ' [rand] randomize the order of groups and examples',
63
+ ' [random] alias for rand',
64
+ ' [random:SEED] e.g. --order random:123') do |o|
65
+ options[:order] = o
66
+ end
67
+
68
+ parser.on('--seed SEED', Integer, 'Equivalent of --order rand:SEED.') do |seed|
69
+ options[:order] = "rand:#{seed}"
70
+ end
71
+
72
+ parser.on('--bisect[=verbose]', 'Repeatedly runs the suite in order to isolate the failures to the ',
73
+ ' smallest reproducible case.') do |argument|
74
+ options[:bisect] = argument || true
75
+ options[:runner] = RSpec::Core::Invocations::Bisect.new
76
+ end
77
+
78
+ parser.on('--[no-]fail-fast[=COUNT]', 'Abort the run after a certain number of failures (1 by default).') do |argument|
79
+ if argument == true
80
+ value = 1
81
+ elsif argument == false || argument == 0
82
+ value = false
83
+ else
84
+ begin
85
+ value = Integer(argument)
86
+ rescue ArgumentError
87
+ RSpec.warning "Expected an integer value for `--fail-fast`, got: #{argument.inspect}", :call_site => nil
88
+ end
89
+ end
90
+ set_fail_fast(options, value)
91
+ end
92
+
93
+ parser.on('--failure-exit-code CODE', Integer,
94
+ 'Override the exit code used when there are failing specs.') do |code|
95
+ options[:failure_exit_code] = code
96
+ end
97
+
98
+ parser.on('-X', '--[no-]drb', 'Run examples via DRb.') do |use_drb|
99
+ options[:drb] = use_drb
100
+ options[:runner] = RSpec::Core::Invocations::DRbWithFallback.new if use_drb
101
+ end
102
+
103
+ parser.on('--drb-port PORT', 'Port to connect to the DRb server.') do |o|
104
+ options[:drb_port] = o.to_i
105
+ end
106
+
107
+ parser.separator("\n **** Output ****\n\n")
108
+
109
+ parser.on('-f', '--format FORMATTER', 'Choose a formatter.',
110
+ ' [p]rogress (default - dots)',
111
+ ' [d]ocumentation (group and example names)',
112
+ ' [h]tml',
113
+ ' [j]son',
114
+ ' custom formatter class name') do |o|
115
+ options[:formatters] ||= []
116
+ options[:formatters] << [o]
117
+ end
118
+
119
+ parser.on('-o', '--out FILE',
120
+ 'Write output to a file instead of $stdout. This option applies',
121
+ ' to the previously specified --format, or the default format',
122
+ ' if no format is specified.'
123
+ ) do |o|
124
+ options[:formatters] ||= [['progress']]
125
+ options[:formatters].last << o
126
+ end
127
+
128
+ parser.on('--deprecation-out FILE', 'Write deprecation warnings to a file instead of $stderr.') do |file|
129
+ options[:deprecation_stream] = file
130
+ end
131
+
132
+ parser.on('-b', '--backtrace', 'Enable full backtrace.') do |_o|
133
+ options[:full_backtrace] = true
134
+ end
135
+
136
+ parser.on('-c', '--color', '--colour', '') do |_o|
137
+ # flag will be excluded from `--help` output because it is deprecated
138
+ options[:color] = true
139
+ options[:color_mode] = :automatic
140
+ end
141
+
142
+ parser.on('--force-color', '--force-colour', 'Force the output to be in color, even if the output is not a TTY') do |_o|
143
+ if options[:color_mode] == :off
144
+ abort "Please only use one of `--force-color` and `--no-color`"
145
+ end
146
+ options[:color_mode] = :on
147
+ end
148
+
149
+ parser.on('--no-color', '--no-colour', 'Force the output to not be in color, even if the output is a TTY') do |_o|
150
+ if options[:color_mode] == :on
151
+ abort "Please only use one of --force-color and --no-color"
152
+ end
153
+ options[:color_mode] = :off
154
+ end
155
+
156
+ parser.on('-p', '--[no-]profile [COUNT]',
157
+ 'Enable profiling of examples and list the slowest examples (default: 10).') do |argument|
158
+ options[:profile_examples] = if argument.nil?
159
+ true
160
+ elsif argument == false
161
+ false
162
+ else
163
+ begin
164
+ Integer(argument)
165
+ rescue ArgumentError
166
+ RSpec.warning "Non integer specified as profile count, separate " \
167
+ "your path from options with -- e.g. " \
168
+ "`rspec --profile -- #{argument}`",
169
+ :call_site => nil
170
+ true
171
+ end
172
+ end
173
+ end
174
+
175
+ parser.on('--dry-run', 'Print the formatter output of your suite without',
176
+ ' running any examples or hooks') do |_o|
177
+ options[:dry_run] = true
178
+ end
179
+
180
+ parser.on('-w', '--warnings', 'Enable ruby warnings') do
181
+ $VERBOSE = true
182
+ end
183
+
184
+ parser.separator <<-FILTERING
185
+
186
+ **** Filtering/tags ****
187
+
188
+ In addition to the following options for selecting specific files, groups, or
189
+ examples, you can select individual examples by appending the line number(s) to
190
+ the filename:
191
+
192
+ rspec path/to/a_spec.rb:37:87
193
+
194
+ You can also pass example ids enclosed in square brackets:
195
+
196
+ rspec path/to/a_spec.rb[1:5,1:6] # run the 5th and 6th examples/groups defined in the 1st group
197
+
198
+ FILTERING
199
+
200
+ parser.on('--only-failures', "Filter to just the examples that failed the last time they ran.") do
201
+ configure_only_failures(options)
202
+ end
203
+
204
+ parser.on("-n", "--next-failure", "Apply `--only-failures` and abort after one failure.",
205
+ " (Equivalent to `--only-failures --fail-fast --order defined`)") do
206
+ configure_only_failures(options)
207
+ set_fail_fast(options, 1)
208
+ options[:order] ||= 'defined'
209
+ end
210
+
211
+ parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec/**/*_spec.rb").') do |o|
212
+ if options[:pattern]
213
+ options[:pattern] += ',' + o
214
+ else
215
+ options[:pattern] = o
216
+ end
217
+ end
218
+
219
+ parser.on('--exclude-pattern PATTERN',
220
+ 'Load files except those matching pattern. Opposite effect of --pattern.') do |o|
221
+ options[:exclude_pattern] = o
222
+ end
223
+
224
+ parser.on('-e', '--example STRING', "Run examples whose full nested names include STRING (may be",
225
+ " used more than once)") do |o|
226
+ (options[:full_description] ||= []) << Regexp.compile(Regexp.escape(o))
227
+ end
228
+
229
+ parser.on('-t', '--tag TAG[:VALUE]',
230
+ 'Run examples with the specified tag, or exclude examples',
231
+ 'by adding ~ before the tag.',
232
+ ' - e.g. ~slow',
233
+ ' - TAG is always converted to a symbol') do |tag|
234
+ filter_type = tag =~ /^~/ ? :exclusion_filter : :inclusion_filter
235
+
236
+ name, value = tag.gsub(/^(~@|~|@)/, '').split(':', 2)
237
+ name = name.to_sym
238
+
239
+ parsed_value = case value
240
+ when nil then true # The default value for tags is true
241
+ when 'true' then true
242
+ when 'false' then false
243
+ when 'nil' then nil
244
+ when /^:/ then value[1..-1].to_sym
245
+ when /^\d+$/ then Integer(value)
246
+ when /^\d+.\d+$/ then Float(value)
247
+ else
248
+ value
249
+ end
250
+
251
+ add_tag_filter(options, filter_type, name, parsed_value)
252
+ end
253
+
254
+ parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can',
255
+ ' be a path to a file or a directory).') do |path|
256
+ options[:default_path] = path
257
+ end
258
+
259
+ parser.separator("\n **** Utility ****\n\n")
260
+
261
+ parser.on('--init', 'Initialize your project with RSpec.') do |_cmd|
262
+ options[:runner] = RSpec::Core::Invocations::InitializeProject.new
263
+ end
264
+
265
+ parser.on('-v', '--version', 'Display the version.') do
266
+ options[:runner] = RSpec::Core::Invocations::PrintVersion.new
267
+ end
268
+
269
+ # These options would otherwise be confusing to users, so we forcibly
270
+ # prevent them from executing.
271
+ #
272
+ # * --I is too similar to -I.
273
+ # * -d was a shorthand for --debugger, which is removed, but now would
274
+ # trigger --default-path.
275
+ invalid_options = %w[-d --I]
276
+
277
+ hidden_options = invalid_options + %w[-c]
278
+
279
+ parser.on_tail('-h', '--help', "You're looking at it.") do
280
+ options[:runner] = RSpec::Core::Invocations::PrintHelp.new(parser, hidden_options)
281
+ end
282
+
283
+ # This prevents usage of the invalid_options.
284
+ invalid_options.each do |option|
285
+ parser.on(option) do
286
+ raise OptionParser::InvalidOption.new
287
+ end
288
+ end
289
+ end
290
+ end
291
+ # rubocop:enable Metrics/AbcSize
292
+ # rubocop:enable MethodLength
293
+ # rubocop:enable CyclomaticComplexity
294
+ # rubocop:enable PerceivedComplexity
295
+
296
+ def add_tag_filter(options, filter_type, tag_name, value=true)
297
+ (options[filter_type] ||= {})[tag_name] = value
298
+ end
299
+
300
+ def set_fail_fast(options, value)
301
+ options[:fail_fast] = value
302
+ end
303
+
304
+ def configure_only_failures(options)
305
+ options[:only_failures] = true
306
+ add_tag_filter(options, :inclusion_filter, :last_run_status, 'failed')
307
+ end
308
+ end
309
+ end
@@ -0,0 +1,158 @@
1
+ module RSpec
2
+ module Core
3
+ # @private
4
+ module Ordering
5
+ # @private
6
+ # The default global ordering (defined order).
7
+ class Identity
8
+ def order(items)
9
+ items
10
+ end
11
+ end
12
+
13
+ # @private
14
+ # Orders items randomly.
15
+ class Random
16
+ def initialize(configuration)
17
+ @configuration = configuration
18
+ @used = false
19
+ end
20
+
21
+ def used?
22
+ @used
23
+ end
24
+
25
+ def order(items)
26
+ @used = true
27
+
28
+ seed = @configuration.seed.to_s
29
+ items.sort_by { |item| jenkins_hash_digest(seed + item.id) }
30
+ end
31
+
32
+ private
33
+
34
+ # http://en.wikipedia.org/wiki/Jenkins_hash_function
35
+ # Jenkins provides a good distribution and is simpler than MD5.
36
+ # It's a bit slower than MD5 (primarily because `Digest::MD5` is
37
+ # implemented in C) but has the advantage of not requiring us
38
+ # to load another part of stdlib, which we try to minimize.
39
+ def jenkins_hash_digest(string)
40
+ hash = 0
41
+
42
+ string.each_byte do |byte|
43
+ hash += byte
44
+ hash &= MAX_32_BIT
45
+ hash += ((hash << 10) & MAX_32_BIT)
46
+ hash &= MAX_32_BIT
47
+ hash ^= hash >> 6
48
+ end
49
+
50
+ hash += ((hash << 3) & MAX_32_BIT)
51
+ hash &= MAX_32_BIT
52
+ hash ^= hash >> 11
53
+ hash += ((hash << 15) & MAX_32_BIT)
54
+ hash &= MAX_32_BIT
55
+ hash
56
+ end
57
+
58
+ MAX_32_BIT = 4_294_967_295
59
+ end
60
+
61
+ # @private
62
+ # Orders items based on a custom block.
63
+ class Custom
64
+ def initialize(callable)
65
+ @callable = callable
66
+ end
67
+
68
+ def order(list)
69
+ @callable.call(list)
70
+ end
71
+ end
72
+
73
+ # @private
74
+ # Stores the different ordering strategies.
75
+ class Registry
76
+ def initialize(configuration)
77
+ @configuration = configuration
78
+ @strategies = {}
79
+
80
+ register(:random, Random.new(configuration))
81
+
82
+ identity = Identity.new
83
+ register(:defined, identity)
84
+
85
+ # The default global ordering is --defined.
86
+ register(:global, identity)
87
+ end
88
+
89
+ def fetch(name, &fallback)
90
+ @strategies.fetch(name, &fallback)
91
+ end
92
+
93
+ def register(sym, strategy)
94
+ @strategies[sym] = strategy
95
+ end
96
+
97
+ def used_random_seed?
98
+ @strategies[:random].used?
99
+ end
100
+ end
101
+
102
+ # @private
103
+ # Manages ordering configuration.
104
+ #
105
+ # @note This is not intended to be used externally. Use
106
+ # the APIs provided by `RSpec::Core::Configuration` instead.
107
+ class ConfigurationManager
108
+ attr_reader :seed, :ordering_registry
109
+
110
+ def initialize
111
+ @ordering_registry = Registry.new(self)
112
+ @seed = rand(0xFFFF)
113
+ @seed_forced = false
114
+ @order_forced = false
115
+ end
116
+
117
+ def seed_used?
118
+ ordering_registry.used_random_seed?
119
+ end
120
+
121
+ def seed=(seed)
122
+ return if @seed_forced
123
+ register_ordering(:global, ordering_registry.fetch(:random))
124
+ @seed = seed.to_i
125
+ end
126
+
127
+ def order=(type)
128
+ order, seed = type.to_s.split(':')
129
+ @seed = seed.to_i if seed
130
+
131
+ ordering_name = if order.include?('rand')
132
+ :random
133
+ elsif order == 'defined'
134
+ :defined
135
+ end
136
+
137
+ register_ordering(:global, ordering_registry.fetch(ordering_name)) if ordering_name
138
+ end
139
+
140
+ def force(hash)
141
+ if hash.key?(:seed)
142
+ self.seed = hash[:seed]
143
+ @seed_forced = true
144
+ @order_forced = true
145
+ elsif hash.key?(:order)
146
+ self.order = hash[:order]
147
+ @order_forced = true
148
+ end
149
+ end
150
+
151
+ def register_ordering(name, strategy=Custom.new(Proc.new { |l| yield l }))
152
+ return if @order_forced && name == :global
153
+ ordering_registry.register(name, strategy)
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end