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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +2 -1
- data/Changelog.md +888 -2
- data/{License.txt → LICENSE.md} +6 -5
- data/README.md +165 -24
- data/lib/rspec/autorun.rb +1 -0
- data/lib/rspec/core/backtrace_formatter.rb +19 -20
- data/lib/rspec/core/bisect/coordinator.rb +62 -0
- data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
- data/lib/rspec/core/bisect/fork_runner.rb +138 -0
- data/lib/rspec/core/bisect/server.rb +61 -0
- data/lib/rspec/core/bisect/shell_command.rb +126 -0
- data/lib/rspec/core/bisect/shell_runner.rb +73 -0
- data/lib/rspec/core/bisect/utilities.rb +69 -0
- data/lib/rspec/core/configuration.rb +1287 -246
- data/lib/rspec/core/configuration_options.rb +95 -35
- data/lib/rspec/core/did_you_mean.rb +46 -0
- data/lib/rspec/core/drb.rb +21 -12
- data/lib/rspec/core/dsl.rb +10 -6
- data/lib/rspec/core/example.rb +305 -113
- data/lib/rspec/core/example_group.rb +431 -223
- data/lib/rspec/core/example_status_persister.rb +235 -0
- data/lib/rspec/core/filter_manager.rb +86 -115
- data/lib/rspec/core/flat_map.rb +6 -4
- data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
- data/lib/rspec/core/formatters/base_formatter.rb +14 -116
- data/lib/rspec/core/formatters/base_text_formatter.rb +18 -21
- data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
- data/lib/rspec/core/formatters/console_codes.rb +29 -18
- data/lib/rspec/core/formatters/deprecation_formatter.rb +16 -16
- data/lib/rspec/core/formatters/documentation_formatter.rb +49 -16
- data/lib/rspec/core/formatters/exception_presenter.rb +525 -0
- data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
- data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
- data/lib/rspec/core/formatters/helpers.rb +45 -15
- data/lib/rspec/core/formatters/html_formatter.rb +33 -28
- data/lib/rspec/core/formatters/html_printer.rb +30 -20
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
- data/lib/rspec/core/formatters/json_formatter.rb +18 -9
- data/lib/rspec/core/formatters/profile_formatter.rb +10 -9
- data/lib/rspec/core/formatters/progress_formatter.rb +5 -4
- data/lib/rspec/core/formatters/protocol.rb +182 -0
- data/lib/rspec/core/formatters/snippet_extractor.rb +113 -82
- data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
- data/lib/rspec/core/formatters.rb +81 -41
- data/lib/rspec/core/hooks.rb +314 -244
- data/lib/rspec/core/invocations.rb +87 -0
- data/lib/rspec/core/memoized_helpers.rb +161 -51
- data/lib/rspec/core/metadata.rb +132 -61
- data/lib/rspec/core/metadata_filter.rb +224 -64
- data/lib/rspec/core/minitest_assertions_adapter.rb +6 -3
- data/lib/rspec/core/mocking_adapters/flexmock.rb +4 -2
- data/lib/rspec/core/mocking_adapters/mocha.rb +11 -9
- data/lib/rspec/core/mocking_adapters/null.rb +2 -0
- data/lib/rspec/core/mocking_adapters/rr.rb +3 -1
- data/lib/rspec/core/mocking_adapters/rspec.rb +3 -1
- data/lib/rspec/core/notifications.rb +192 -206
- data/lib/rspec/core/option_parser.rb +174 -69
- data/lib/rspec/core/ordering.rb +48 -35
- data/lib/rspec/core/output_wrapper.rb +29 -0
- data/lib/rspec/core/pending.rb +25 -33
- data/lib/rspec/core/profiler.rb +34 -0
- data/lib/rspec/core/project_initializer/.rspec +0 -2
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +59 -39
- data/lib/rspec/core/project_initializer.rb +5 -3
- data/lib/rspec/core/rake_task.rb +99 -55
- data/lib/rspec/core/reporter.rb +128 -15
- data/lib/rspec/core/ruby_project.rb +14 -6
- data/lib/rspec/core/runner.rb +96 -45
- data/lib/rspec/core/sandbox.rb +37 -0
- data/lib/rspec/core/set.rb +54 -0
- data/lib/rspec/core/shared_example_group.rb +133 -43
- data/lib/rspec/core/shell_escape.rb +49 -0
- data/lib/rspec/core/test_unit_assertions_adapter.rb +4 -4
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/warnings.rb +6 -6
- data/lib/rspec/core/world.rb +172 -68
- data/lib/rspec/core.rb +66 -21
- data.tar.gz.sig +0 -0
- metadata +93 -69
- metadata.gz.sig +0 -0
- data/lib/rspec/core/backport_random.rb +0 -336
|
@@ -4,30 +4,47 @@ require 'optparse'
|
|
|
4
4
|
module RSpec::Core
|
|
5
5
|
# @private
|
|
6
6
|
class Parser
|
|
7
|
-
def self.parse(args)
|
|
8
|
-
new.parse(
|
|
7
|
+
def self.parse(args, source=nil)
|
|
8
|
+
new(args).parse(source)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
return {} if args.empty?
|
|
11
|
+
attr_reader :original_args
|
|
13
12
|
|
|
14
|
-
|
|
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 } : {}
|
|
15
22
|
begin
|
|
16
23
|
parser(options).parse!(args)
|
|
17
24
|
rescue OptionParser::InvalidOption => e
|
|
18
|
-
abort "#{e.message}
|
|
25
|
+
abort "#{e.message}#{" (defined in #{source})" if source}\n\n" \
|
|
26
|
+
"Please use --help for a listing of valid options"
|
|
19
27
|
end
|
|
20
28
|
|
|
29
|
+
options[:files_or_directories_to_run] = args
|
|
21
30
|
options
|
|
22
31
|
end
|
|
23
32
|
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
# rubocop:disable Metrics/AbcSize
|
|
36
|
+
# rubocop:disable Metrics/MethodLength
|
|
37
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
38
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
24
39
|
def parser(options)
|
|
25
40
|
OptionParser.new do |parser|
|
|
41
|
+
parser.summary_width = 34
|
|
42
|
+
|
|
26
43
|
parser.banner = "Usage: rspec [options] [files or directories]\n\n"
|
|
27
44
|
|
|
28
|
-
parser.on('-I PATH', 'Specify PATH to add to $LOAD_PATH (may be used more than once).') do |
|
|
45
|
+
parser.on('-I PATH', 'Specify PATH to add to $LOAD_PATH (may be used more than once).') do |dirs|
|
|
29
46
|
options[:libs] ||= []
|
|
30
|
-
options[:libs]
|
|
47
|
+
options[:libs].concat(dirs.split(File::PATH_SEPARATOR))
|
|
31
48
|
end
|
|
32
49
|
|
|
33
50
|
parser.on('-r', '--require PATH', 'Require a file.') do |path|
|
|
@@ -40,10 +57,11 @@ module RSpec::Core
|
|
|
40
57
|
end
|
|
41
58
|
|
|
42
59
|
parser.on('--order TYPE[:SEED]', 'Run examples by the specified order type.',
|
|
43
|
-
' [defined]
|
|
44
|
-
' [rand]
|
|
45
|
-
' [random]
|
|
46
|
-
' [random:SEED]
|
|
60
|
+
' [defined] examples and groups are run in the order they are defined',
|
|
61
|
+
' [rand] randomize the order of groups and examples',
|
|
62
|
+
' [random] alias for rand',
|
|
63
|
+
' [random:SEED] e.g. --order random:123',
|
|
64
|
+
' [recently-modified] run the most recently modified files first') do |o|
|
|
47
65
|
options[:order] = o
|
|
48
66
|
end
|
|
49
67
|
|
|
@@ -51,45 +69,55 @@ module RSpec::Core
|
|
|
51
69
|
options[:order] = "rand:#{seed}"
|
|
52
70
|
end
|
|
53
71
|
|
|
54
|
-
parser.on('--
|
|
55
|
-
|
|
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
|
|
56
76
|
end
|
|
57
77
|
|
|
58
|
-
parser.on('--no-fail-fast', '
|
|
59
|
-
|
|
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)
|
|
60
91
|
end
|
|
61
92
|
|
|
62
|
-
parser.on('--failure-exit-code CODE', Integer,
|
|
93
|
+
parser.on('--failure-exit-code CODE', Integer,
|
|
94
|
+
'Override the exit code used when there are failing specs.') do |code|
|
|
63
95
|
options[:failure_exit_code] = code
|
|
64
96
|
end
|
|
65
97
|
|
|
66
|
-
parser.on('--
|
|
67
|
-
'
|
|
68
|
-
options[:
|
|
98
|
+
parser.on('--error-exit-code CODE', Integer,
|
|
99
|
+
'Override the exit code used when there are errors loading or running specs outside of examples.') do |code|
|
|
100
|
+
options[:error_exit_code] = code
|
|
69
101
|
end
|
|
70
102
|
|
|
71
|
-
parser.on('-X', '--[no-]drb', 'Run examples via DRb.') do |
|
|
72
|
-
options[:drb] =
|
|
103
|
+
parser.on('-X', '--[no-]drb', 'Run examples via DRb.') do |use_drb|
|
|
104
|
+
options[:drb] = use_drb
|
|
105
|
+
options[:runner] = RSpec::Core::Invocations::DRbWithFallback.new if use_drb
|
|
73
106
|
end
|
|
74
107
|
|
|
75
108
|
parser.on('--drb-port PORT', 'Port to connect to the DRb server.') do |o|
|
|
76
109
|
options[:drb_port] = o.to_i
|
|
77
110
|
end
|
|
78
111
|
|
|
79
|
-
parser.on('--init', 'Initialize your project with RSpec.') do |cmd|
|
|
80
|
-
RSpec::Support.require_rspec_core "project_initializer"
|
|
81
|
-
ProjectInitializer.new.run
|
|
82
|
-
exit
|
|
83
|
-
end
|
|
84
|
-
|
|
85
112
|
parser.separator("\n **** Output ****\n\n")
|
|
86
113
|
|
|
87
114
|
parser.on('-f', '--format FORMATTER', 'Choose a formatter.',
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
115
|
+
' [p]rogress (default - dots)',
|
|
116
|
+
' [d]ocumentation (group and example names)',
|
|
117
|
+
' [h]tml',
|
|
118
|
+
' [j]son',
|
|
119
|
+
' [f]ailures ("file:line:reason", suitable for editors integration)',
|
|
120
|
+
' custom formatter class name') do |o|
|
|
93
121
|
options[:formatters] ||= []
|
|
94
122
|
options[:formatters] << [o]
|
|
95
123
|
end
|
|
@@ -107,15 +135,32 @@ module RSpec::Core
|
|
|
107
135
|
options[:deprecation_stream] = file
|
|
108
136
|
end
|
|
109
137
|
|
|
110
|
-
parser.on('-b', '--backtrace', 'Enable full backtrace.') do |
|
|
138
|
+
parser.on('-b', '--backtrace', 'Enable full backtrace.') do |_o|
|
|
111
139
|
options[:full_backtrace] = true
|
|
112
140
|
end
|
|
113
141
|
|
|
114
|
-
parser.on('-c', '--
|
|
115
|
-
|
|
142
|
+
parser.on('-c', '--color', '--colour', '') do |_o|
|
|
143
|
+
# flag will be excluded from `--help` output because it is deprecated
|
|
144
|
+
options[:color] = true
|
|
145
|
+
options[:color_mode] = :automatic
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
parser.on('--force-color', '--force-colour', 'Force the output to be in color, even if the output is not a TTY') do |_o|
|
|
149
|
+
if options[:color_mode] == :off
|
|
150
|
+
abort "Please only use one of `--force-color` and `--no-color`"
|
|
151
|
+
end
|
|
152
|
+
options[:color_mode] = :on
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
parser.on('--no-color', '--no-colour', 'Force the output to not be in color, even if the output is a TTY') do |_o|
|
|
156
|
+
if options[:color_mode] == :on
|
|
157
|
+
abort "Please only use one of --force-color and --no-color"
|
|
158
|
+
end
|
|
159
|
+
options[:color_mode] = :off
|
|
116
160
|
end
|
|
117
161
|
|
|
118
|
-
parser.on('-p', '--[no-]profile [COUNT]',
|
|
162
|
+
parser.on('-p', '--[no-]profile [COUNT]',
|
|
163
|
+
'Enable profiling of examples and list the slowest examples (default: 10).') do |argument|
|
|
119
164
|
options[:profile_examples] = if argument.nil?
|
|
120
165
|
true
|
|
121
166
|
elsif argument == false
|
|
@@ -124,16 +169,24 @@ module RSpec::Core
|
|
|
124
169
|
begin
|
|
125
170
|
Integer(argument)
|
|
126
171
|
rescue ArgumentError
|
|
127
|
-
RSpec.warning "Non integer specified as profile count,
|
|
128
|
-
"your path from options with -- e.g. "
|
|
172
|
+
RSpec.warning "Non integer specified as profile count, separate " \
|
|
173
|
+
"your path from options with -- e.g. " \
|
|
129
174
|
"`rspec --profile -- #{argument}`",
|
|
130
|
-
|
|
175
|
+
:call_site => nil
|
|
131
176
|
true
|
|
132
177
|
end
|
|
133
178
|
end
|
|
134
179
|
end
|
|
135
180
|
|
|
181
|
+
parser.on('--dry-run', 'Print the formatter output of your suite without',
|
|
182
|
+
' running any examples or hooks') do |_o|
|
|
183
|
+
options[:dry_run] = true
|
|
184
|
+
end
|
|
185
|
+
|
|
136
186
|
parser.on('-w', '--warnings', 'Enable ruby warnings') do
|
|
187
|
+
if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
|
|
188
|
+
Warning[:deprecated] = true
|
|
189
|
+
end
|
|
137
190
|
$VERBOSE = true
|
|
138
191
|
end
|
|
139
192
|
|
|
@@ -141,23 +194,52 @@ module RSpec::Core
|
|
|
141
194
|
|
|
142
195
|
**** Filtering/tags ****
|
|
143
196
|
|
|
144
|
-
In addition to the following options for selecting specific files, groups,
|
|
145
|
-
|
|
197
|
+
In addition to the following options for selecting specific files, groups, or
|
|
198
|
+
examples, you can select individual examples by appending the line number(s) to
|
|
146
199
|
the filename:
|
|
147
200
|
|
|
148
|
-
rspec path/to/a_spec.rb:37
|
|
201
|
+
rspec path/to/a_spec.rb:37:87
|
|
202
|
+
|
|
203
|
+
You can also pass example ids enclosed in square brackets:
|
|
204
|
+
|
|
205
|
+
rspec path/to/a_spec.rb[1:5,1:6] # run the 5th and 6th examples/groups defined in the 1st group
|
|
149
206
|
|
|
150
207
|
FILTERING
|
|
151
208
|
|
|
209
|
+
parser.on('--only-failures', "Filter to just the examples that failed the last time they ran.") do
|
|
210
|
+
configure_only_failures(options)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
parser.on("-n", "--next-failure", "Apply `--only-failures` and abort after one failure.",
|
|
214
|
+
" (Equivalent to `--only-failures --fail-fast --order defined`)") do
|
|
215
|
+
configure_only_failures(options)
|
|
216
|
+
set_fail_fast(options, 1)
|
|
217
|
+
options[:order] ||= 'defined'
|
|
218
|
+
end
|
|
219
|
+
|
|
152
220
|
parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec/**/*_spec.rb").') do |o|
|
|
153
|
-
options[:pattern]
|
|
221
|
+
if options[:pattern]
|
|
222
|
+
options[:pattern] += ',' + o
|
|
223
|
+
else
|
|
224
|
+
options[:pattern] = o
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
parser.on('--exclude-pattern PATTERN',
|
|
229
|
+
'Load files except those matching pattern. Opposite effect of --pattern.') do |o|
|
|
230
|
+
options[:exclude_pattern] = o
|
|
154
231
|
end
|
|
155
232
|
|
|
156
233
|
parser.on('-e', '--example STRING', "Run examples whose full nested names include STRING (may be",
|
|
157
|
-
|
|
234
|
+
" used more than once)") do |o|
|
|
158
235
|
(options[:full_description] ||= []) << Regexp.compile(Regexp.escape(o))
|
|
159
236
|
end
|
|
160
237
|
|
|
238
|
+
parser.on('-E', '--example-matches REGEX', "Run examples whose full nested names match REGEX (may be",
|
|
239
|
+
" used more than once)") do |o|
|
|
240
|
+
(options[:full_description] ||= []) << Regexp.compile(o)
|
|
241
|
+
end
|
|
242
|
+
|
|
161
243
|
parser.on('-t', '--tag TAG[:VALUE]',
|
|
162
244
|
'Run examples with the specified tag, or exclude examples',
|
|
163
245
|
'by adding ~ before the tag.',
|
|
@@ -165,54 +247,77 @@ FILTERING
|
|
|
165
247
|
' - TAG is always converted to a symbol') do |tag|
|
|
166
248
|
filter_type = tag =~ /^~/ ? :exclusion_filter : :inclusion_filter
|
|
167
249
|
|
|
168
|
-
name,value = tag.gsub(/^(~@|~|@)/, '').split(':',2)
|
|
250
|
+
name, value = tag.gsub(/^(~@|~|@)/, '').split(':', 2)
|
|
169
251
|
name = name.to_sym
|
|
170
252
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
253
|
+
parsed_value = case value
|
|
254
|
+
when nil then true # The default value for tags is true
|
|
255
|
+
when 'true' then true
|
|
256
|
+
when 'false' then false
|
|
257
|
+
when 'nil' then nil
|
|
258
|
+
when /^:/ then value[1..-1].to_sym
|
|
259
|
+
when /^\d+$/ then Integer(value)
|
|
260
|
+
when /^\d+.\d+$/ then Float(value)
|
|
261
|
+
else
|
|
262
|
+
value
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
add_tag_filter(options, filter_type, name, parsed_value)
|
|
183
266
|
end
|
|
184
267
|
|
|
185
268
|
parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can',
|
|
186
|
-
|
|
269
|
+
' be a path to a file or a directory).') do |path|
|
|
187
270
|
options[:default_path] = path
|
|
188
271
|
end
|
|
189
272
|
|
|
190
273
|
parser.separator("\n **** Utility ****\n\n")
|
|
191
274
|
|
|
275
|
+
parser.on('--init', 'Initialize your project with RSpec.') do |_cmd|
|
|
276
|
+
options[:runner] = RSpec::Core::Invocations::InitializeProject.new
|
|
277
|
+
end
|
|
278
|
+
|
|
192
279
|
parser.on('-v', '--version', 'Display the version.') do
|
|
193
|
-
|
|
194
|
-
exit
|
|
280
|
+
options[:runner] = RSpec::Core::Invocations::PrintVersion.new
|
|
195
281
|
end
|
|
196
282
|
|
|
197
|
-
#
|
|
198
|
-
#
|
|
199
|
-
#
|
|
283
|
+
# These options would otherwise be confusing to users, so we forcibly
|
|
284
|
+
# prevent them from executing.
|
|
285
|
+
#
|
|
286
|
+
# * --I is too similar to -I.
|
|
287
|
+
# * -d was a shorthand for --debugger, which is removed, but now would
|
|
288
|
+
# trigger --default-path.
|
|
200
289
|
invalid_options = %w[-d --I]
|
|
201
290
|
|
|
291
|
+
hidden_options = invalid_options + %w[-c]
|
|
292
|
+
|
|
202
293
|
parser.on_tail('-h', '--help', "You're looking at it.") do
|
|
203
|
-
|
|
204
|
-
puts parser.to_s.gsub(/^\s+(#{invalid_options.join('|')})\s*$\n/,'')
|
|
205
|
-
exit
|
|
294
|
+
options[:runner] = RSpec::Core::Invocations::PrintHelp.new(parser, hidden_options)
|
|
206
295
|
end
|
|
207
296
|
|
|
208
|
-
#
|
|
297
|
+
# This prevents usage of the invalid_options.
|
|
209
298
|
invalid_options.each do |option|
|
|
210
299
|
parser.on(option) do
|
|
211
300
|
raise OptionParser::InvalidOption.new
|
|
212
301
|
end
|
|
213
302
|
end
|
|
214
|
-
|
|
215
303
|
end
|
|
216
304
|
end
|
|
305
|
+
# rubocop:enable Metrics/AbcSize
|
|
306
|
+
# rubocop:enable Metrics/MethodLength
|
|
307
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
308
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
309
|
+
|
|
310
|
+
def add_tag_filter(options, filter_type, tag_name, value=true)
|
|
311
|
+
(options[filter_type] ||= {})[tag_name] = value
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def set_fail_fast(options, value)
|
|
315
|
+
options[:fail_fast] = value
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def configure_only_failures(options)
|
|
319
|
+
options[:only_failures] = true
|
|
320
|
+
add_tag_filter(options, :inclusion_filter, :last_run_status, 'failed')
|
|
321
|
+
end
|
|
217
322
|
end
|
|
218
323
|
end
|
data/lib/rspec/core/ordering.rb
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Core
|
|
3
|
-
if defined?(::Random)
|
|
4
|
-
# @private
|
|
5
|
-
RandomNumberGenerator = ::Random
|
|
6
|
-
else
|
|
7
|
-
RSpec::Support.require_rspec_core "backport_random"
|
|
8
|
-
# @private
|
|
9
|
-
RandomNumberGenerator = RSpec::Core::Backports::Random
|
|
10
|
-
end
|
|
11
|
-
|
|
12
3
|
# @private
|
|
13
4
|
module Ordering
|
|
14
5
|
# @private
|
|
@@ -33,25 +24,45 @@ module RSpec
|
|
|
33
24
|
|
|
34
25
|
def order(items)
|
|
35
26
|
@used = true
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
|
|
28
|
+
seed = @configuration.seed.to_s
|
|
29
|
+
items.sort_by { |item| jenkins_hash_digest(seed + item.id) }
|
|
38
30
|
end
|
|
39
31
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
|
54
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 by modification time (most recent modified first).
|
|
63
|
+
class RecentlyModified
|
|
64
|
+
def order(list)
|
|
65
|
+
list.sort_by { |item| -File.mtime(item.metadata[:absolute_file_path]).to_i }
|
|
55
66
|
end
|
|
56
67
|
end
|
|
57
68
|
|
|
@@ -74,7 +85,8 @@ module RSpec
|
|
|
74
85
|
@configuration = configuration
|
|
75
86
|
@strategies = {}
|
|
76
87
|
|
|
77
|
-
register(:random,
|
|
88
|
+
register(:random, Random.new(configuration))
|
|
89
|
+
register(:recently_modified, RecentlyModified.new)
|
|
78
90
|
|
|
79
91
|
identity = Identity.new
|
|
80
92
|
register(:defined, identity)
|
|
@@ -123,29 +135,31 @@ module RSpec
|
|
|
123
135
|
|
|
124
136
|
def order=(type)
|
|
125
137
|
order, seed = type.to_s.split(':')
|
|
126
|
-
@seed = seed
|
|
138
|
+
@seed = seed.to_i if seed
|
|
127
139
|
|
|
128
140
|
ordering_name = if order.include?('rand')
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
141
|
+
:random
|
|
142
|
+
elsif order == 'defined'
|
|
143
|
+
:defined
|
|
144
|
+
elsif order == 'recently-modified'
|
|
145
|
+
:recently_modified
|
|
146
|
+
end
|
|
133
147
|
|
|
134
148
|
register_ordering(:global, ordering_registry.fetch(ordering_name)) if ordering_name
|
|
135
149
|
end
|
|
136
150
|
|
|
137
151
|
def force(hash)
|
|
138
|
-
if hash.
|
|
152
|
+
if hash.key?(:seed)
|
|
139
153
|
self.seed = hash[:seed]
|
|
140
154
|
@seed_forced = true
|
|
141
155
|
@order_forced = true
|
|
142
|
-
elsif hash.
|
|
156
|
+
elsif hash.key?(:order)
|
|
143
157
|
self.order = hash[:order]
|
|
144
158
|
@order_forced = true
|
|
145
159
|
end
|
|
146
160
|
end
|
|
147
161
|
|
|
148
|
-
def register_ordering(name, strategy
|
|
162
|
+
def register_ordering(name, strategy=Custom.new(Proc.new { |l| yield l }))
|
|
149
163
|
return if @order_forced && name == :global
|
|
150
164
|
ordering_registry.register(name, strategy)
|
|
151
165
|
end
|
|
@@ -153,4 +167,3 @@ module RSpec
|
|
|
153
167
|
end
|
|
154
168
|
end
|
|
155
169
|
end
|
|
156
|
-
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Core
|
|
3
|
+
# @private
|
|
4
|
+
class OutputWrapper
|
|
5
|
+
# @private
|
|
6
|
+
attr_accessor :output
|
|
7
|
+
|
|
8
|
+
# @private
|
|
9
|
+
def initialize(output)
|
|
10
|
+
@output = output
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def respond_to?(name, priv=false)
|
|
14
|
+
output.respond_to?(name, priv)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def method_missing(name, *args, &block)
|
|
18
|
+
output.send(name, *args, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Redirect calls for IO interface methods
|
|
22
|
+
IO.instance_methods(false).each do |method|
|
|
23
|
+
define_method(method) do |*args, &block|
|
|
24
|
+
output.send(method, *args, &block)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/rspec/core/pending.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Core
|
|
3
|
-
# Provides methods to mark examples as pending. These methods are available
|
|
4
|
-
# called from within any example or hook.
|
|
3
|
+
# Provides methods to mark examples as pending. These methods are available
|
|
4
|
+
# to be called from within any example or hook.
|
|
5
5
|
module Pending
|
|
6
|
-
# Raised in the middle of an example to indicate that it should be marked
|
|
6
|
+
# Raised in the middle of an example to indicate that it should be marked
|
|
7
|
+
# as skipped.
|
|
7
8
|
class SkipDeclaredInExample < StandardError
|
|
8
9
|
attr_reader :argument
|
|
9
10
|
|
|
@@ -12,8 +13,9 @@ module RSpec
|
|
|
12
13
|
end
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
# If Test::Unit is loaded, we'll use its error as baseclass, so that
|
|
16
|
-
# will report unmet RSpec expectations as failures rather than
|
|
16
|
+
# If Test::Unit is loaded, we'll use its error as baseclass, so that
|
|
17
|
+
# Test::Unit will report unmet RSpec expectations as failures rather than
|
|
18
|
+
# errors.
|
|
17
19
|
begin
|
|
18
20
|
class PendingExampleFixedError < Test::Unit::AssertionFailedError; end
|
|
19
21
|
rescue
|
|
@@ -36,7 +38,7 @@ module RSpec
|
|
|
36
38
|
# @param message [String] optional message to add to the summary report.
|
|
37
39
|
#
|
|
38
40
|
# @example
|
|
39
|
-
# describe "
|
|
41
|
+
# describe "some behaviour" do
|
|
40
42
|
# # reported as "Pending: no reason given"
|
|
41
43
|
# it "is pending with no message" do
|
|
42
44
|
# pending
|
|
@@ -50,28 +52,20 @@ module RSpec
|
|
|
50
52
|
# end
|
|
51
53
|
# end
|
|
52
54
|
#
|
|
53
|
-
# @note `
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
# end
|
|
61
|
-
#
|
|
62
|
-
# or pass `:pending => "something else getting finished"` to add a
|
|
63
|
-
# message to the summary report:
|
|
64
|
-
#
|
|
65
|
-
# it "does something", :pending => "something else getting finished" do
|
|
66
|
-
# # ...
|
|
67
|
-
# end
|
|
55
|
+
# @note When using `pending` inside an example body using this method
|
|
56
|
+
# hooks, such as `before(:example)`, have already be run. This means that
|
|
57
|
+
# a failure from the code in the `before` hook will prevent the example
|
|
58
|
+
# from being considered pending, as the example body would not be
|
|
59
|
+
# executed. If you need to consider hooks as pending as well you can use
|
|
60
|
+
# the pending metadata as an alternative, e.g.
|
|
61
|
+
# `it "does something", pending: "message"`.
|
|
68
62
|
def pending(message=nil)
|
|
69
63
|
current_example = RSpec.current_example
|
|
70
64
|
|
|
71
65
|
if block_given?
|
|
72
66
|
raise ArgumentError, <<-EOS.gsub(/^\s+\|/, '')
|
|
73
67
|
|The semantics of `RSpec::Core::Pending#pending` have changed in
|
|
74
|
-
|RSpec 3.
|
|
68
|
+
|RSpec 3. In RSpec 2.x, it caused the example to be skipped. In
|
|
75
69
|
|RSpec 3, the rest of the example is still run but is expected to
|
|
76
70
|
|fail, and will be marked as a failure (rather than as pending) if
|
|
77
71
|
|the example passes.
|
|
@@ -89,7 +83,7 @@ module RSpec
|
|
|
89
83
|
elsif current_example
|
|
90
84
|
Pending.mark_pending! current_example, message
|
|
91
85
|
else
|
|
92
|
-
raise "`pending` may not be used outside of examples, such as in "
|
|
86
|
+
raise "`pending` may not be used outside of examples, such as in " \
|
|
93
87
|
"before(:context). Maybe you want `skip`?"
|
|
94
88
|
end
|
|
95
89
|
end
|
|
@@ -116,16 +110,14 @@ module RSpec
|
|
|
116
110
|
def skip(message=nil)
|
|
117
111
|
current_example = RSpec.current_example
|
|
118
112
|
|
|
119
|
-
if current_example
|
|
120
|
-
Pending.mark_skipped! current_example, message
|
|
121
|
-
end
|
|
113
|
+
Pending.mark_skipped!(current_example, message) if current_example
|
|
122
114
|
|
|
123
115
|
raise SkipDeclaredInExample.new(message)
|
|
124
116
|
end
|
|
125
117
|
|
|
126
118
|
# @private
|
|
127
119
|
#
|
|
128
|
-
# Mark example as skipped
|
|
120
|
+
# Mark example as skipped.
|
|
129
121
|
#
|
|
130
122
|
# @param example [RSpec::Core::Example] the example to mark as skipped
|
|
131
123
|
# @param message_or_bool [Boolean, String] the message to use, or true
|
|
@@ -136,16 +128,16 @@ module RSpec
|
|
|
136
128
|
|
|
137
129
|
# @private
|
|
138
130
|
#
|
|
139
|
-
# Mark example as pending
|
|
131
|
+
# Mark example as pending.
|
|
140
132
|
#
|
|
141
133
|
# @param example [RSpec::Core::Example] the example to mark as pending
|
|
142
134
|
# @param message_or_bool [Boolean, String] the message to use, or true
|
|
143
135
|
def self.mark_pending!(example, message_or_bool)
|
|
144
136
|
message = if !message_or_bool || !(String === message_or_bool)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
137
|
+
NO_REASON_GIVEN
|
|
138
|
+
else
|
|
139
|
+
message_or_bool
|
|
140
|
+
end
|
|
149
141
|
|
|
150
142
|
example.metadata[:pending] = true
|
|
151
143
|
example.execution_result.pending_message = message
|
|
@@ -154,7 +146,7 @@ module RSpec
|
|
|
154
146
|
|
|
155
147
|
# @private
|
|
156
148
|
#
|
|
157
|
-
# Mark example as fixed
|
|
149
|
+
# Mark example as fixed.
|
|
158
150
|
#
|
|
159
151
|
# @param example [RSpec::Core::Example] the example to mark as fixed
|
|
160
152
|
def self.mark_fixed!(example)
|