rspec-core 3.0.4 → 3.12.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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(args)
7
+ def self.parse(args, source=nil)
8
+ new(args).parse(source)
9
9
  end
10
10
 
11
- def parse(args)
12
- return {} if args.empty?
11
+ attr_reader :original_args
13
12
 
14
- options = args.delete('--tty') ? {:tty => true} : {}
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}\n\nPlease use --help for a listing of valid options"
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 |dir|
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] << dir
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] examples and groups are run in the order they are defined',
44
- ' [rand] randomize the order of groups and examples',
45
- ' [random] alias for rand',
46
- ' [random:SEED] e.g. --order random:123') do |o|
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('--fail-fast', 'Abort the run on first failure.') do |o|
55
- options[:fail_fast] = true
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', 'Do not abort the run on first failure.') do |o|
59
- options[:fail_fast] = false
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, 'Override the exit code used when there are failing specs.') do |code|
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('--dry-run', 'Print the formatter output of your suite without',
67
- ' running any examples or hooks') do |o|
68
- options[:dry_run] = true
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 |o|
72
- options[:drb] = o
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
- ' [p]rogress (default - dots)',
89
- ' [d]ocumentation (group and example names)',
90
- ' [h]tml',
91
- ' [j]son',
92
- ' custom formatter class name') do |o|
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 |o|
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', '--[no-]color', '--[no-]colour', 'Enable color in the output.') do |o|
115
- options[:color] = o
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]', 'Enable profiling of examples and list the slowest examples (default: 10).') do |argument|
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, seperate " +
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
- :call_site => nil
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
- or examples, you can select a single example by appending the line number to
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] = o
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
- " used more than once)") do |o|
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
- options[filter_type] ||= {}
172
- options[filter_type][name] = case value
173
- when nil then true # The default value for tags is true
174
- when 'true' then true
175
- when 'false' then false
176
- when 'nil' then nil
177
- when /^:/ then value[1..-1].to_sym
178
- when /^\d+$/ then Integer(value)
179
- when /^\d+.\d+$/ then Float(value)
180
- else
181
- value
182
- end
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
- ' be a path to a file or a directory).') do |path|
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
- puts RSpec::Core::Version::STRING
194
- exit
280
+ options[:runner] = RSpec::Core::Invocations::PrintVersion.new
195
281
  end
196
282
 
197
- # these options would otherwise be confusing to users, so we forcibly prevent them from executing
198
- # --I is too similar to -I
199
- # -d was a shorthand for --debugger, which is removed, but now would trigger --default-path
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
- # removing the blank invalid options from the output
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
- # this prevents usage of the invalid_options
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
@@ -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
- rng = RandomNumberGenerator.new(@configuration.seed)
37
- shuffle items, rng
27
+
28
+ seed = @configuration.seed.to_s
29
+ items.sort_by { |item| jenkins_hash_digest(seed + item.id) }
38
30
  end
39
31
 
40
- if RUBY_VERSION > '1.9.3'
41
- def shuffle(list, rng)
42
- list.shuffle(:random => rng)
43
- end
44
- else
45
- def shuffle(list, rng)
46
- shuffled = list.dup
47
- shuffled.size.times do |i|
48
- j = i + rng.rand(shuffled.size - i)
49
- next if i == j
50
- shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
51
- end
52
-
53
- shuffled
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, Random.new(configuration))
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 = seed.to_i if seed
138
+ @seed = seed.to_i if seed
127
139
 
128
140
  ordering_name = if order.include?('rand')
129
- :random
130
- elsif order == 'defined'
131
- :defined
132
- end
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.has_key?(:seed)
152
+ if hash.key?(:seed)
139
153
  self.seed = hash[:seed]
140
154
  @seed_forced = true
141
155
  @order_forced = true
142
- elsif hash.has_key?(:order)
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 = Custom.new(Proc.new { |l| yield l }))
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
@@ -1,9 +1,10 @@
1
1
  module RSpec
2
2
  module Core
3
- # Provides methods to mark examples as pending. These methods are available to be
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 as skipped.
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 Test::Unit
16
- # will report unmet RSpec expectations as failures rather than errors.
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 "an example" do
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 `before(:example)` hooks are eval'd when you use the `pending`
54
- # method within an example. If you want to declare an example `pending`
55
- # and bypass the `before` hooks as well, you can pass `:pending => true`
56
- # to the `it` method:
57
- #
58
- # it "does something", :pending => true do
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. In RSpec 2.x, it caused the example to be skipped. In
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
- NO_REASON_GIVEN
146
- else
147
- message_or_bool
148
- end
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)