rspec-core 2.14.8 → 2.99.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +8 -8
  2. data/Changelog.md +54 -8
  3. data/features/command_line/order.feature +5 -8
  4. data/features/configuration/custom_settings.feature +10 -10
  5. data/features/configuration/deprecation_stream.feature +3 -3
  6. data/features/configuration/read_options_from_file.feature +1 -1
  7. data/features/example_groups/shared_examples.feature +2 -2
  8. data/features/hooks/around_hooks.feature +1 -1
  9. data/features/metadata/current_example.feature +43 -4
  10. data/features/metadata/user_defined.feature +12 -12
  11. data/lib/autotest/rspec2.rb +60 -56
  12. data/lib/rspec/core.rb +40 -2
  13. data/lib/rspec/core/caller_filter.rb +55 -0
  14. data/lib/rspec/core/command_line.rb +2 -2
  15. data/lib/rspec/core/configuration.rb +201 -13
  16. data/lib/rspec/core/deprecation.rb +2 -7
  17. data/lib/rspec/core/example.rb +5 -8
  18. data/lib/rspec/core/example_group.rb +101 -17
  19. data/lib/rspec/core/filter_manager.rb +2 -2
  20. data/lib/rspec/core/formatters/deprecation_formatter.rb +173 -15
  21. data/lib/rspec/core/formatters/text_mate_formatter.rb +0 -12
  22. data/lib/rspec/core/hooks.rb +1 -1
  23. data/lib/rspec/core/memoized_helpers.rb +49 -17
  24. data/lib/rspec/core/metadata.rb +1 -1
  25. data/lib/rspec/core/option_parser.rb +8 -3
  26. data/lib/rspec/core/pending.rb +14 -10
  27. data/lib/rspec/core/rake_task.rb +30 -6
  28. data/lib/rspec/core/runner.rb +9 -0
  29. data/lib/rspec/core/shared_example_group.rb +11 -9
  30. data/lib/rspec/core/shared_example_group/collection.rb +3 -1
  31. data/lib/rspec/core/version.rb +1 -2
  32. data/spec/command_line/order_spec.rb +4 -4
  33. data/spec/rspec/core/backtrace_cleaner_spec.rb +10 -10
  34. data/spec/rspec/core/caller_filter_spec.rb +58 -0
  35. data/spec/rspec/core/command_line_spec.rb +1 -0
  36. data/spec/rspec/core/configuration_options_spec.rb +6 -6
  37. data/spec/rspec/core/configuration_spec.rb +285 -52
  38. data/spec/rspec/core/deprecation_spec.rb +10 -29
  39. data/spec/rspec/core/deprecations_spec.rb +0 -14
  40. data/spec/rspec/core/example_group_spec.rb +74 -56
  41. data/spec/rspec/core/example_spec.rb +54 -17
  42. data/spec/rspec/core/filter_manager_spec.rb +2 -2
  43. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +156 -52
  44. data/spec/rspec/core/formatters/html_formatter_spec.rb +1 -1
  45. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +1 -2
  46. data/spec/rspec/core/hooks_spec.rb +2 -0
  47. data/spec/rspec/core/memoized_helpers_spec.rb +154 -113
  48. data/spec/rspec/core/metadata_spec.rb +25 -25
  49. data/spec/rspec/core/option_parser_spec.rb +19 -1
  50. data/spec/rspec/core/project_initializer_spec.rb +4 -4
  51. data/spec/rspec/core/rake_task_spec.rb +25 -4
  52. data/spec/rspec/core/shared_context_spec.rb +4 -4
  53. data/spec/rspec/core/shared_example_group_spec.rb +1 -1
  54. data/spec/rspec/core_spec.rb +36 -2
  55. data/spec/spec_helper.rb +3 -0
  56. data/spec/support/helper_methods.rb +16 -1
  57. data/spec/support/shared_example_groups.rb +1 -0
  58. data/spec/support/silence_dsl_deprecations.rb +32 -0
  59. metadata +10 -7
  60. data/spec/rspec/core/formatters/text_mate_formatted-2.1.0.html +0 -425
@@ -2,7 +2,7 @@ require_rspec = if defined?(require_relative)
2
2
  lambda do |path|
3
3
  require_relative path
4
4
  end
5
- else
5
+ else # for 1.8.7
6
6
  lambda do |path|
7
7
  require "rspec/#{path}"
8
8
  end
@@ -11,6 +11,7 @@ end
11
11
  require 'set'
12
12
  require 'time'
13
13
  require 'rbconfig'
14
+ require_rspec['core/caller_filter']
14
15
  require_rspec['core/filter_manager']
15
16
  require_rspec['core/dsl']
16
17
  require_rspec['core/extensions/kernel']
@@ -94,7 +95,7 @@ DEPRECATION WARNING
94
95
  * RSpec.configuration with a block is deprecated and has no effect.
95
96
  * please use RSpec.configure with a block instead.
96
97
 
97
- Called from #{caller(0)[1]}
98
+ Called from #{CallerFilter.first_non_rspec_line}
98
99
  *****************************************************************
99
100
 
100
101
  WARNING
@@ -126,6 +127,37 @@ WARNING
126
127
  world.example_groups.clear
127
128
  end
128
129
 
130
+ # The example being executed.
131
+ #
132
+ # The primary audience for this method is library authors who need access
133
+ # to the example currently being executed and also want to support all
134
+ # versions of RSpec 2 and 3.
135
+ #
136
+ # @example
137
+ #
138
+ # RSpec.configure do |c|
139
+ # # context.example is deprecated, but RSpec.current_example is not
140
+ # # available until RSpec 3.0.
141
+ # fetch_current_example = RSpec.respond_to?(:current_example) ?
142
+ # proc { RSpec.current_example } : proc { |context| context.example }
143
+ #
144
+ # c.before(:each) do
145
+ # example = fetch_current_example.call(self)
146
+ #
147
+ # # ...
148
+ # end
149
+ # end
150
+ #
151
+ def self.current_example
152
+ Thread.current[:_rspec_current_example]
153
+ end
154
+
155
+ # Set the current example being executed.
156
+ # @api private
157
+ def self.current_example=(example)
158
+ Thread.current[:_rspec_current_example] = example
159
+ end
160
+
129
161
  # @private
130
162
  def self.windows_os?
131
163
  RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/
@@ -141,6 +173,12 @@ WARNING
141
173
  define_method(:now,&::Time.method(:now))
142
174
  end
143
175
  end
176
+
177
+ # @private path to executable file
178
+ def self.path_to_executable
179
+ File.expand_path('../../../exe/rspec', __FILE__)
180
+ end
181
+
144
182
  end
145
183
 
146
184
  MODULES_TO_AUTOLOAD = {
@@ -0,0 +1,55 @@
1
+ module RSpec
2
+ # Consistent implementation for "cleaning" the caller method to strip out
3
+ # non-rspec lines. This enables errors to be reported at the call site in
4
+ # the code using the library, which is far more useful than the particular
5
+ # internal method that raised an error.
6
+ class CallerFilter
7
+
8
+ RSPEC_LIBS = %w[
9
+ core
10
+ mocks
11
+ expectations
12
+ matchers
13
+ rails
14
+ ]
15
+
16
+ ADDITIONAL_TOP_LEVEL_FILES = %w[ autorun ]
17
+
18
+ LIB_REGEX = %r{/lib/rspec/(#{(RSPEC_LIBS + ADDITIONAL_TOP_LEVEL_FILES).join('|')})(\.rb|/)}
19
+
20
+ if RUBY_VERSION >= '2.0.0'
21
+ def self.first_non_rspec_line
22
+ # `caller` is an expensive method that scales linearly with the size of
23
+ # the stack. The performance hit for fetching it in chunks is small,
24
+ # and since the target line is probably near the top of the stack, the
25
+ # overall improvement of a chunked search like this is significant.
26
+ #
27
+ # See benchmarks/caller.rb for measurements.
28
+
29
+ # Initial value here is mostly arbitrary, but is chosen to give good
30
+ # performance on the common case of creating a double.
31
+ increment = 5
32
+ i = 1
33
+ line = nil
34
+
35
+ while !line
36
+ stack = caller(i, increment)
37
+ raise "No non-lib lines in stack" unless stack
38
+
39
+ line = stack.find { |l| l !~ LIB_REGEX }
40
+
41
+ i += increment
42
+ increment *= 2 # The choice of two here is arbitrary.
43
+ end
44
+
45
+ line
46
+ end
47
+ else
48
+ # Earlier rubies do not support the two argument form of `caller`. This
49
+ # fallback is logically the same, but slower.
50
+ def self.first_non_rspec_line
51
+ caller.find { |line| line !~ LIB_REGEX }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -17,12 +17,12 @@ module RSpec
17
17
  # @param [IO] out
18
18
  def run(err, out)
19
19
  @configuration.error_stream = err
20
- @configuration.output_stream ||= out
20
+ @configuration.output_stream = out if @configuration.output_stream == $stdout
21
21
  @options.configure(@configuration)
22
22
  @configuration.load_spec_files
23
23
  @world.announce_filters
24
24
 
25
- @configuration.reporter.report(@world.example_count, @configuration.randomize? ? @configuration.seed : nil) do |reporter|
25
+ @configuration.reporter.report(@world.example_count, @configuration.send(:_randomize?) ? @configuration.seed : nil) do |reporter|
26
26
  begin
27
27
  @configuration.run_hook(:before, :suite)
28
28
  @world.example_groups.ordered.map {|g| g.run(reporter)}.all? ? 0 : @configuration.failure_exit_code
@@ -1,7 +1,7 @@
1
1
  require 'fileutils'
2
2
  require 'rspec/core/backtrace_cleaner'
3
3
  require 'rspec/core/ruby_project'
4
- require 'rspec/core/formatters/deprecation_formatter.rb'
4
+ require 'rspec/core/formatters/deprecation_formatter'
5
5
 
6
6
  module RSpec
7
7
  module Core
@@ -104,10 +104,6 @@ module RSpec
104
104
  # The exit code to return if there are any failures (default: 1).
105
105
  add_setting :failure_exit_code
106
106
 
107
- # Determines the order in which examples are run (default: OS standard
108
- # load order for files, declaration order for groups and examples).
109
- define_reader :order
110
-
111
107
  # Indicates files configured to be required
112
108
  define_reader :requires
113
109
 
@@ -116,11 +112,53 @@ module RSpec
116
112
 
117
113
  # Default: `$stdout`.
118
114
  # Also known as `output` and `out`
119
- add_setting :output_stream, :alias_with => [:output, :out]
115
+ define_reader :output_stream
116
+ def output_stream=(value)
117
+ if @reporter && !value.equal?(@output_stream)
118
+ warn "RSpec's reporter has already been initialized with " +
119
+ "#{output_stream.inspect} as the output stream, so your change to "+
120
+ "`output_stream` will be ignored. You should configure it earlier for " +
121
+ "it to take effect. (Called from #{CallerFilter.first_non_rspec_line})"
122
+ else
123
+ @output_stream = value
124
+ end
125
+ end
126
+
127
+ # @deprecated use RSpec::Core::Configuration#output_stream instead.
128
+ def output
129
+ RSpec.deprecate("RSpec::Core::Configuration#output", :replacement => "RSpec::Core::Configuration#output_stream")
130
+ output_stream
131
+ end
132
+
133
+ # @deprecated use RSpec::Core::Configuration#output_stream= instead.
134
+ def output=(value)
135
+ RSpec.deprecate("RSpec::Core::Configuration#output=", :replacement => "RSpec::Core::Configuration#output_stream=")
136
+ self.output_stream = value
137
+ end
138
+
139
+ # @deprecated use RSpec::Core::Configuration#output_stream instead.
140
+ def out
141
+ RSpec.deprecate("RSpec::Core::Configuration#out", :replacement => "RSpec::Core::Configuration#output_stream")
142
+ output_stream
143
+ end
144
+
145
+ # @deprecated use RSpec::Core::Configuration#output_stream= instead.
146
+ def out=(value)
147
+ RSpec.deprecate("RSpec::Core::Configuration#out=", :replacement => "RSpec::Core::Configuration#output_stream=")
148
+ self.output_stream = value
149
+ end
120
150
 
121
151
  # Load files matching this pattern (default: `'**/*_spec.rb'`)
122
152
  add_setting :pattern, :alias_with => :filename_pattern
123
153
 
154
+ def pattern= value
155
+ if @spec_files_loaded
156
+ Kernel.warn "WARNING: Configuring `pattern` to #{value} has no effect since RSpec has already loaded the spec files. Called from #{CallerFilter.first_non_rspec_line}"
157
+ end
158
+ @pattern = value
159
+ end
160
+ alias :filename_pattern= :pattern=
161
+
124
162
  # Report the times for the slowest examples (default: `false`).
125
163
  # Use this to specify the number of examples to include in the profile.
126
164
  add_setting :profile_examples
@@ -170,6 +208,14 @@ module RSpec
170
208
  # end
171
209
  add_setting :treat_symbols_as_metadata_keys_with_true_values
172
210
 
211
+ def treat_symbols_as_metadata_keys_with_true_values=(value)
212
+ unless value
213
+ RSpec.deprecate("RSpec.configuration.treat_symbols_as_metadata_keys_with_true_values = false")
214
+ end
215
+
216
+ @treat_symbols_as_metadata_keys_with_true_values = value
217
+ end
218
+
173
219
  # @private
174
220
  add_setting :tty
175
221
  # @private
@@ -190,13 +236,17 @@ module RSpec
190
236
  @files_to_run = []
191
237
  @formatters = []
192
238
  @color = false
239
+ @order = nil
193
240
  @pattern = '**/*_spec.rb'
194
241
  @failure_exit_code = 1
242
+ @spec_files_loaded = false
195
243
 
196
244
  @backtrace_cleaner = BacktraceCleaner.new
197
245
 
198
246
  @default_path = 'spec'
199
247
  @deprecation_stream = $stderr
248
+ @output_stream = $stdout
249
+ @reporter = nil
200
250
  @filter_manager = FilterManager.new
201
251
  @preferred_options = {}
202
252
  @seed = srand % 0xFFFF
@@ -226,6 +276,7 @@ module RSpec
226
276
 
227
277
  # @private
228
278
  def reset
279
+ @spec_files_loaded = false
229
280
  @reporter = nil
230
281
  @formatters.clear
231
282
  end
@@ -516,6 +567,18 @@ module RSpec
516
567
  end
517
568
 
518
569
  def debug=(bool)
570
+ if bool
571
+ # Usually this is called automatically by the --debug CLI option, so the
572
+ # deprecation message doesn't mention `RSpec::Core::Configuration#debug=`
573
+ RSpec.deprecate("RSpec's built-in debugger support",
574
+ :replacement => "a CLI option like `-rruby-debug` or `-rdebugger`")
575
+ else
576
+ # ...but the only way to call this with a false value is to
577
+ # call it directly, so here we mention the method name.
578
+ # There's no replacement for it since it's a no-op, though.
579
+ RSpec.deprecate("RSpec::Core::Configuration#debug=")
580
+ end
581
+
519
582
  return unless bool
520
583
  begin
521
584
  require 'ruby-debug'
@@ -537,6 +600,9 @@ EOM
537
600
  end
538
601
 
539
602
  def debug?
603
+ RSpec.deprecate("RSpec::Core::Configuration#debug?",
604
+ :replacement => "defined?(Debugger)")
605
+
540
606
  !!defined?(Debugger)
541
607
  end
542
608
 
@@ -574,7 +640,7 @@ EOM
574
640
  custom_formatter(formatter_to_use) ||
575
641
  (raise ArgumentError, "Formatter '#{formatter_to_use}' unknown - maybe you meant 'documentation' or 'progress'?.")
576
642
 
577
- paths << output if paths.empty?
643
+ paths << output_stream if paths.empty?
578
644
  formatters << formatter_class.new(*paths.map {|p| String === p ? file_at(p) : p})
579
645
  end
580
646
 
@@ -894,6 +960,7 @@ EOM
894
960
  # @private
895
961
  def load_spec_files
896
962
  files_to_run.uniq.each {|f| load File.expand_path(f) }
963
+ @spec_files_loaded = true
897
964
  raise_if_rspec_1_is_loaded
898
965
  end
899
966
 
@@ -930,8 +997,28 @@ EOM
930
997
  order_and_seed_from_order(type)
931
998
  end
932
999
 
1000
+ # Determines the order in which examples are run (default: OS standard
1001
+ # load order for files, declaration order for groups and examples).
1002
+ def order
1003
+ RSpec.warn_deprecation(
1004
+ "RSpec::Core::Configuration#order is deprecated with no replacement. " +
1005
+ "In RSpec 3 individal example groups can use a particular ordering, " +
1006
+ "so `order` is no longer a global property of the entire suite. " +
1007
+ "Called from #{CallerFilter.first_non_rspec_line}."
1008
+ )
1009
+
1010
+ value_for(:order, @order)
1011
+ end
1012
+
933
1013
  def randomize?
934
- order.to_s.match(/rand/)
1014
+ RSpec.warn_deprecation(
1015
+ "RSpec::Core::Configuration#randomize? is deprecated with no replacement. " +
1016
+ "In RSpec 3 individal example groups can use a particular ordering, " +
1017
+ "so `randomize?` is no longer a binary property of the entire suite. " +
1018
+ "Called from #{CallerFilter.first_non_rspec_line}."
1019
+ )
1020
+
1021
+ value_for(:order, @order).to_s.match(/rand/)
935
1022
  end
936
1023
 
937
1024
  # @private
@@ -959,6 +1046,7 @@ EOM
959
1046
  # @see #order=
960
1047
  # @see #seed=
961
1048
  def order_examples(&block)
1049
+ RSpec.deprecate("RSpec::Configuration#order_examples", :replacement => "RSpec::Configuration#register_ordering(:global)")
962
1050
  @example_ordering_block = block
963
1051
  @order = "custom" unless built_in_orderer?(block)
964
1052
  end
@@ -982,6 +1070,7 @@ EOM
982
1070
  # @see #order=
983
1071
  # @see #seed=
984
1072
  def order_groups(&block)
1073
+ RSpec.deprecate("RSpec::Configuration#order_groups", :replacement => "RSpec::Configuration#register_ordering(:global)")
985
1074
  @group_ordering_block = block
986
1075
  @order = "custom" unless built_in_orderer?(block)
987
1076
  end
@@ -1009,6 +1098,46 @@ EOM
1009
1098
  order_examples(&block)
1010
1099
  end
1011
1100
 
1101
+ # In RSpec 3, this registers a named ordering strategy that can later be
1102
+ # used to order an example group's subgroups by adding
1103
+ # `:order => <name>` metadata to the example group.
1104
+ #
1105
+ # In RSpec 2.99, only `register_ordering(:global)` is supported,
1106
+ # to set the global ordering.
1107
+ #
1108
+ # @param name [Symbol] The name of the ordering.
1109
+ # @yield Block that will order the given examples or example groups
1110
+ # @yieldparam list [Array<RSpec::Core::Example>, Array<RSpec::Core::ExampleGropu>] The examples or groups to order
1111
+ # @yieldreturn [Array<RSpec::Core::Example>, Array<RSpec::Core::ExampleGroup>] The re-ordered examples or groups
1112
+ #
1113
+ # @example
1114
+ # RSpec.configure do |rspec|
1115
+ # rspec.register_ordering :reverse do |list|
1116
+ # list.reverse
1117
+ # end
1118
+ # end
1119
+ #
1120
+ # describe MyClass, :order => :reverse do
1121
+ # # ...
1122
+ # end
1123
+ #
1124
+ # @note Pass the symbol `:global` to set the ordering strategy that
1125
+ # will be used to order the top-level example groups and any example
1126
+ # groups that do not have declared `:order` metadata.
1127
+ def register_ordering(name, &block)
1128
+ unless name == :global
1129
+ raise ArgumentError,
1130
+ "Ordering name `#{name.inspect}` given, `:global` expected. " +
1131
+ "RSpec 3 will support named orderings (that can be used for " +
1132
+ "individual example groups) but 2.99 only supports using this " +
1133
+ "to set the global order."
1134
+ end
1135
+
1136
+ @group_ordering_block = block
1137
+ @example_ordering_block = block
1138
+ @order = "custom"
1139
+ end
1140
+
1012
1141
  # Set Ruby warnings on or off
1013
1142
  def warnings= value
1014
1143
  $VERBOSE = !!value
@@ -1018,8 +1147,59 @@ EOM
1018
1147
  $VERBOSE
1019
1148
  end
1020
1149
 
1150
+ # Exposes the current running example via the named
1151
+ # helper method. RSpec 2.x exposed this via `example`,
1152
+ # but in RSpec 3.0, the example is instead exposed via
1153
+ # an arg yielded to `it`, `before`, `let`, etc. However,
1154
+ # some extension gems (such as Capybara) depend on the
1155
+ # RSpec 2.x's `example` method, so this config option
1156
+ # can be used to maintain compatibility.
1157
+ #
1158
+ # @param method_name [Symbol] the name of the helper method
1159
+ #
1160
+ # @example
1161
+ #
1162
+ # RSpec.configure do |rspec|
1163
+ # rspec.expose_current_running_example_as :example
1164
+ # end
1165
+ #
1166
+ # describe MyClass do
1167
+ # before do
1168
+ # # `example` can be used here because of the above config.
1169
+ # do_something if example.metadata[:type] == "foo"
1170
+ # end
1171
+ # end
1172
+ def expose_current_running_example_as(method_name)
1173
+ ExposeCurrentExample.module_eval do
1174
+ extend RSpec::SharedContext
1175
+ let(method_name) { |ex| ex }
1176
+ end
1177
+
1178
+ include ExposeCurrentExample
1179
+ end
1180
+
1181
+ module ExposeCurrentExample; end
1182
+
1183
+ # Turns deprecation warnings into errors, in order to surface
1184
+ # the full backtrace of the call site. This can be useful when
1185
+ # you need more context to address a deprecation than the
1186
+ # single-line call site normally provided.
1187
+ #
1188
+ # @example
1189
+ #
1190
+ # RSpec.configure do |rspec|
1191
+ # rspec.raise_errors_for_deprecations!
1192
+ # end
1193
+ def raise_errors_for_deprecations!
1194
+ self.deprecation_stream = Formatters::DeprecationFormatter::RaiseErrorStream.new
1195
+ end
1196
+
1021
1197
  private
1022
1198
 
1199
+ def _randomize?
1200
+ value_for(:order, @order).to_s.match(/rand/)
1201
+ end
1202
+
1023
1203
  def get_files_to_run(paths)
1024
1204
  paths.map do |path|
1025
1205
  path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
@@ -1140,7 +1320,8 @@ MESSAGE
1140
1320
  end
1141
1321
 
1142
1322
  def order_and_seed_from_seed(value)
1143
- order_groups_and_examples(&RANDOM_ORDERING)
1323
+ @group_ordering_block = RANDOM_ORDERING
1324
+ @example_ordering_block = RANDOM_ORDERING
1144
1325
  @order, @seed = 'rand', value.to_i
1145
1326
  [@order, @seed]
1146
1327
  end
@@ -1155,11 +1336,18 @@ MESSAGE
1155
1336
  @order = order
1156
1337
  @seed = seed = seed.to_i if seed
1157
1338
 
1158
- if randomize?
1159
- order_groups_and_examples(&RANDOM_ORDERING)
1160
- elsif order == 'default'
1339
+ if order.to_s.match(/rand/)
1340
+ @group_ordering_block = RANDOM_ORDERING
1341
+ @example_ordering_block = RANDOM_ORDERING
1342
+ elsif %w[ default defined ].include?(order)
1343
+ if order == 'default'
1344
+ RSpec.deprecate("RSpec::Core::Configuration#order = 'default'",
1345
+ :replacement => "RSpec::Core::Configuration#order = 'defined'")
1346
+ end
1347
+
1161
1348
  @order, @seed = nil, nil
1162
- order_groups_and_examples(&DEFAULT_ORDERING)
1349
+ @group_ordering_block = DEFAULT_ORDERING
1350
+ @example_ordering_block = DEFAULT_ORDERING
1163
1351
  end
1164
1352
 
1165
1353
  return order, seed