rspec-core 2.99.0.beta2 → 2.99.0.rc1

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/Changelog.md +122 -43
  3. data/features/command_line/line_number_option.feature +6 -11
  4. data/features/configuration/read_options_from_file.feature +2 -2
  5. data/features/expectation_framework_integration/configure_expectation_framework.feature +120 -25
  6. data/lib/autotest/discover.rb +10 -1
  7. data/lib/autotest/rspec2.rb +1 -1
  8. data/lib/rspec/core/command_line.rb +16 -5
  9. data/lib/rspec/core/configuration.rb +151 -119
  10. data/lib/rspec/core/deprecated_mutable_array_proxy.rb +32 -0
  11. data/lib/rspec/core/example.rb +3 -1
  12. data/lib/rspec/core/example_group.rb +174 -125
  13. data/lib/rspec/core/filter_manager.rb +48 -10
  14. data/lib/rspec/core/formatters.rb +137 -0
  15. data/lib/rspec/core/formatters/base_text_formatter.rb +25 -29
  16. data/lib/rspec/core/formatters/console_codes.rb +42 -0
  17. data/lib/rspec/core/formatters/deprecation_formatter.rb +14 -5
  18. data/lib/rspec/core/formatters/helpers.rb +1 -1
  19. data/lib/rspec/core/memoized_helpers.rb +2 -1
  20. data/lib/rspec/core/metadata.rb +63 -1
  21. data/lib/rspec/core/minitest_assertions_adapter.rb +28 -0
  22. data/lib/rspec/core/option_parser.rb +20 -1
  23. data/lib/rspec/core/pending.rb +26 -4
  24. data/lib/rspec/core/reporter.rb +1 -1
  25. data/lib/rspec/core/runner.rb +2 -2
  26. data/lib/rspec/core/shared_example_group.rb +11 -4
  27. data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
  28. data/lib/rspec/core/version.rb +1 -1
  29. data/lib/rspec/core/world.rb +2 -2
  30. data/spec/autotest/discover_spec.rb +38 -8
  31. data/spec/rspec/core/command_line_spec.rb +47 -29
  32. data/spec/rspec/core/configuration_options_spec.rb +1 -1
  33. data/spec/rspec/core/configuration_spec.rb +223 -37
  34. data/spec/rspec/core/example_group_spec.rb +116 -6
  35. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +24 -4
  36. data/spec/rspec/core/formatters/console_codes_spec.rb +50 -0
  37. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +20 -3
  38. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +1 -0
  39. data/spec/rspec/core/formatters/html_formatted.html +3 -4
  40. data/spec/rspec/core/formatters/html_formatter_spec.rb +10 -4
  41. data/spec/rspec/core/formatters/text_mate_formatted.html +3 -4
  42. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +9 -3
  43. data/spec/rspec/core/hooks_filtering_spec.rb +5 -5
  44. data/spec/rspec/core/memoized_helpers_spec.rb +38 -0
  45. data/spec/rspec/core/metadata_spec.rb +24 -1
  46. data/spec/rspec/core/option_parser_spec.rb +39 -2
  47. data/spec/rspec/core/pending_example_spec.rb +14 -0
  48. data/spec/rspec/core/pending_spec.rb +27 -0
  49. data/spec/rspec/core/runner_spec.rb +3 -3
  50. data/spec/rspec/core/shared_context_spec.rb +1 -1
  51. data/spec/rspec/core/shared_example_group_spec.rb +18 -0
  52. data/spec/support/helper_methods.rb +4 -0
  53. metadata +105 -106
@@ -52,4 +52,141 @@
52
52
  # @see RSpec::Core::Formatters::BaseTextFormatter
53
53
  # @see RSpec::Core::Reporter
54
54
  module RSpec::Core::Formatters
55
+ autoload :DocumentationFormatter, 'rspec/core/formatters/documentation_formatter'
56
+ autoload :HtmlFormatter, 'rspec/core/formatters/html_formatter'
57
+ autoload :ProgressFormatter, 'rspec/core/formatters/progress_formatter'
58
+ autoload :JsonFormatter, 'rspec/core/formatters/json_formatter'
59
+ autoload :TextMateFormatter, 'rspec/core/formatters/text_mate_formatter'
60
+
61
+ # @api private
62
+ #
63
+ # `RSpec::Core::Formatters::Loader` is an internal class for
64
+ # managing formatters used by a particular configuration. It is
65
+ # not expected to be used directly, but only through the configuration
66
+ # interface.
67
+ class Loader
68
+
69
+ # @api private
70
+ def initialize(reporter)
71
+ @formatters = []
72
+ @reporter = reporter
73
+ @setup = false
74
+ @default_formatter = 'progress'
75
+ end
76
+
77
+ # @return [Array] the loaded formatters
78
+ attr_reader :formatters
79
+
80
+ # @return [Reporter] the reporter
81
+ attr_reader :reporter
82
+
83
+ # @private
84
+ def setup_default(output_stream, deprecation_stream)
85
+ if @formatters.empty?
86
+ add @default_formatter, output_stream
87
+ end
88
+ unless @formatters.any? { |formatter| DeprecationFormatter === formatter }
89
+ add DeprecationFormatter, deprecation_stream, output_stream
90
+ end
91
+ @formatters.each do |formatter|
92
+ @reporter.register_listener formatter, *RSpec::Core::Reporter::NOTIFICATIONS
93
+ end
94
+ @setup = true
95
+ end
96
+
97
+ # @private
98
+ def add(formatter_to_use, *paths)
99
+ formatter_class = find_formatter(formatter_to_use)
100
+
101
+ args = paths.map { |p| p.respond_to?(:puts) ? p : file_at(p) }
102
+
103
+ formatter = formatter_class.new(*args)
104
+ if @setup
105
+ @reporter.register_listener formatter, *RSpec::Core::Reporter::NOTIFICATIONS
106
+ end
107
+ @formatters << formatter unless duplicate_formatter_exists?(formatter)
108
+
109
+ formatter
110
+ end
111
+
112
+ private
113
+
114
+ def find_formatter(formatter_to_use)
115
+ built_in_formatter(formatter_to_use) ||
116
+ custom_formatter(formatter_to_use) ||
117
+ (raise ArgumentError, "Formatter '#{formatter_to_use}' unknown - maybe you meant 'documentation' or 'progress'?.")
118
+ end
119
+
120
+ def duplicate_formatter_exists?(new_formatter)
121
+ @formatters.any? do |formatter|
122
+ formatter.class === new_formatter && formatter.output == new_formatter.output
123
+ end
124
+ end
125
+
126
+ def built_in_formatter(key)
127
+ case key.to_s
128
+ when 'd', 'doc', 'documentation'
129
+ DocumentationFormatter
130
+ when 's', 'n', 'spec', 'nested'
131
+ RSpec.deprecate "Using `#{key.to_s}` as a shortcut for the DocumentationFormatter",
132
+ :replacement => "`d`, `doc`, or `documentation`"
133
+ DocumentationFormatter
134
+ when 'h', 'html'
135
+ HtmlFormatter
136
+ when 'p', 'progress'
137
+ ProgressFormatter
138
+ when 'j', 'json'
139
+ JsonFormatter
140
+ when 't', 'textmate'
141
+ if defined?(::RSpec::Mate::Formatters::TextMateFormatter)
142
+ RSpec.deprecate "Using the text`#{key.to_s}` as a shortcut for the TextMateFormatter",
143
+ :replacement => "`::RSpec::Mate::Formatters::TextMateFormatter`"
144
+ else
145
+ RSpec.deprecate "Using rspec-core's `::RSpec::Core::TextMateFormatter`",
146
+ :replacement => "the `rspec-tmbundle` gem and it's `::RSpec::Mate::Formatters::TextMateFormatter`"
147
+ end
148
+ TextMateFormatter
149
+ end
150
+ end
151
+
152
+ def custom_formatter(formatter_ref)
153
+ if Class === formatter_ref
154
+ formatter_ref
155
+ elsif string_const?(formatter_ref)
156
+ begin
157
+ formatter_ref.gsub(/^::/,'').split('::').inject(Object) { |const,string| const.const_get string }
158
+ rescue NameError
159
+ require( path_for(formatter_ref) ) ? retry : raise
160
+ end
161
+ end
162
+ end
163
+
164
+ def string_const?(str)
165
+ str.is_a?(String) && /\A[A-Z][a-zA-Z0-9_:]*\z/ =~ str
166
+ end
167
+
168
+ def path_for(const_ref)
169
+ underscore_with_fix_for_non_standard_rspec_naming(const_ref)
170
+ end
171
+
172
+ def underscore_with_fix_for_non_standard_rspec_naming(string)
173
+ underscore(string).sub(%r{(^|/)r_spec($|/)}, '\\1rspec\\2')
174
+ end
175
+
176
+ # activesupport/lib/active_support/inflector/methods.rb, line 48
177
+ def underscore(camel_cased_word)
178
+ word = camel_cased_word.to_s.dup
179
+ word.gsub!(/::/, '/')
180
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
181
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
182
+ word.tr!("-", "_")
183
+ word.downcase!
184
+ word
185
+ end
186
+
187
+ def file_at(path)
188
+ FileUtils.mkdir_p(File.dirname(path))
189
+ File.new(path, 'w')
190
+ end
191
+ end
55
192
  end
@@ -1,5 +1,5 @@
1
1
  require 'rspec/core/formatters/base_formatter'
2
- require 'set'
2
+ require 'rspec/core/formatters/console_codes'
3
3
 
4
4
  module RSpec
5
5
  module Core
@@ -68,12 +68,12 @@ module RSpec
68
68
  # @api public
69
69
  #
70
70
  # Outputs the slowest examples and example groups in a report when using `--profile COUNT` (default 10).
71
- #
71
+ #
72
72
  def dump_profile
73
73
  dump_profile_slowest_examples
74
74
  dump_profile_slowest_example_groups
75
75
  end
76
-
76
+
77
77
  def dump_profile_slowest_examples
78
78
  number_of_examples = RSpec.configuration.profile_examples
79
79
  sorted_examples = examples.sort_by {|example|
@@ -95,7 +95,7 @@ module RSpec
95
95
 
96
96
  def dump_profile_slowest_example_groups
97
97
  number_of_examples = RSpec.configuration.profile_examples
98
- example_groups = {}
98
+ example_groups = {}
99
99
 
100
100
  examples.each do |example|
101
101
  location = example.example_group.parent_groups.last.metadata[:example_group][:location]
@@ -108,15 +108,15 @@ module RSpec
108
108
 
109
109
  # stop if we've only one example group
110
110
  return if example_groups.keys.length <= 1
111
-
111
+
112
112
  example_groups.each do |loc, hash|
113
113
  hash[:average] = hash[:total_time].to_f / hash[:count]
114
114
  end
115
-
115
+
116
116
  sorted_groups = example_groups.sort_by {|_, hash| -hash[:average]}.first(number_of_examples)
117
117
 
118
118
  output.puts "\nTop #{sorted_groups.size} slowest example groups:"
119
- sorted_groups.each do |loc, hash|
119
+ sorted_groups.each do |loc, hash|
120
120
  average = "#{failure_color(format_seconds(hash[:average]))} #{failure_color("seconds")} average"
121
121
  total = "#{format_seconds(hash[:total_time])} seconds"
122
122
  count = pluralize(hash[:count], "example")
@@ -165,41 +165,37 @@ module RSpec
165
165
  output.close if IO === output && output != $stdout
166
166
  end
167
167
 
168
- VT100_COLORS = {
169
- :black => 30,
170
- :red => 31,
171
- :green => 32,
172
- :yellow => 33,
173
- :blue => 34,
174
- :magenta => 35,
175
- :cyan => 36,
176
- :white => 37
177
- }
178
-
179
- VT100_COLOR_CODES = VT100_COLORS.values.to_set
180
-
181
- def color_code_for(code_or_symbol)
182
- if VT100_COLOR_CODES.include?(code_or_symbol)
183
- code_or_symbol
168
+ def self.const_missing(name)
169
+ base = "RSpec::Core::Formatters::"
170
+ case name
171
+ when :VT100_COLORS then
172
+ RSpec.deprecate("#{base}#{name}", :replacement => "#{base}ConsoleCodes::VT100_CODES")
173
+ RSpec::Core::Formatters::ConsoleCodes::VT100_CODES
174
+ when :VT100_COLOR_CODES then
175
+ RSpec.deprecate("#{base}#{name}", :replacement => "#{base}ConsoleCodes::VT100_CODE_VALUES")
176
+ require 'set'
177
+ RSpec::Core::Formatters::ConsoleCodes::VT100_CODES.to_set
184
178
  else
185
- VT100_COLORS.fetch(code_or_symbol) do
186
- color_code_for(:white)
187
- end
179
+ super
188
180
  end
189
181
  end
190
182
 
183
+ def color_code_for(code_or_symbol)
184
+ ConsoleCodes.console_code_for(code_or_symbol)
185
+ end
186
+
191
187
  def colorize(text, code_or_symbol)
192
- "\e[#{color_code_for(code_or_symbol)}m#{text}\e[0m"
188
+ ConsoleCodes.wrap(text, code_or_symbol)
193
189
  end
194
190
 
195
191
  protected
196
192
 
197
193
  def bold(text)
198
- color_enabled? ? "\e[1m#{text}\e[0m" : text
194
+ ConsoleCodes.wrap(text, :bold)
199
195
  end
200
196
 
201
197
  def color(text, color_code)
202
- color_enabled? ? colorize(text, color_code) : text
198
+ ConsoleCodes.wrap(text, color_code)
203
199
  end
204
200
 
205
201
  def failure_color(text)
@@ -0,0 +1,42 @@
1
+ module RSpec
2
+ module Core
3
+ module Formatters
4
+ module ConsoleCodes
5
+ VT100_CODES =
6
+ {
7
+ :black => 30,
8
+ :red => 31,
9
+ :green => 32,
10
+ :yellow => 33,
11
+ :blue => 34,
12
+ :magenta => 35,
13
+ :cyan => 36,
14
+ :white => 37,
15
+ :bold => 1,
16
+ }
17
+ VT100_CODE_VALUES = VT100_CODES.invert
18
+
19
+ module_function
20
+
21
+ def console_code_for(code_or_symbol)
22
+ if VT100_CODE_VALUES.has_key?(code_or_symbol)
23
+ code_or_symbol
24
+ else
25
+ VT100_CODES.fetch(code_or_symbol) do
26
+ console_code_for(:white)
27
+ end
28
+ end
29
+ end
30
+
31
+ def wrap(text, code_or_symbol)
32
+ if RSpec.configuration.color_enabled?
33
+ "\e[#{console_code_for(code_or_symbol)}m#{text}\e[0m"
34
+ else
35
+ text
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -57,6 +57,9 @@ module RSpec
57
57
  |deprecation warnings into errors, giving you the full backtrace.
58
58
  EOS
59
59
 
60
+ DEPRECATION_STREAM_NOTICE = "Pass `--deprecation-out` or set " +
61
+ "`config.deprecation_stream` to a file for full output."
62
+
60
63
  SpecifiedDeprecationMessage = Struct.new(:type) do
61
64
  def initialize(data)
62
65
  @message = data[:message]
@@ -64,17 +67,23 @@ module RSpec
64
67
  end
65
68
 
66
69
  def to_s
67
- @message
70
+ output_formatted @message
68
71
  end
69
72
 
70
73
  def too_many_warnings_message
71
- msg = "Too many similar deprecation messages reported, disregarding further reports."
72
- msg << " Set config.deprecation_stream to a File for full output."
74
+ msg = "Too many similar deprecation messages reported, disregarding further reports. "
75
+ msg << DEPRECATION_STREAM_NOTICE
73
76
  msg
74
77
  end
75
78
 
76
79
  private
77
80
 
81
+ def output_formatted(str)
82
+ return str unless str.lines.count > 1
83
+ separator = "#{'-' * 80}"
84
+ "#{separator}\n#{str.chomp}\n#{separator}"
85
+ end
86
+
78
87
  def deprecation_type_for(data)
79
88
  data[:message].gsub(/(\w+\/)+\w+\.rb:\d+/, '')
80
89
  end
@@ -94,8 +103,8 @@ module RSpec
94
103
  end
95
104
 
96
105
  def too_many_warnings_message
97
- msg = "Too many uses of deprecated '#{type}'."
98
- msg << " Set config.deprecation_stream to a File for full output."
106
+ msg = "Too many uses of deprecated '#{type}'. "
107
+ msg << DEPRECATION_STREAM_NOTICE
99
108
  msg
100
109
  end
101
110
  end
@@ -18,7 +18,7 @@ module RSpec
18
18
  protected
19
19
 
20
20
  def backtrace_line(line)
21
- return nil if RSpec.configuration.backtrace_cleaner.exclude?(line)
21
+ return nil if RSpec.configuration.backtrace_formatter.exclude?(line)
22
22
  RSpec::Core::Metadata::relative_path(line)
23
23
  rescue SecurityError
24
24
  nil
@@ -490,7 +490,8 @@ EOS
490
490
  # end
491
491
  def its(attribute, &block)
492
492
  RSpec.deprecate("Use of rspec-core's `its` method", :replacement => 'the rspec-its gem')
493
- describe(attribute) do
493
+
494
+ describe(attribute.to_s) do
494
495
  if Array === attribute
495
496
  let(:__its_subject) { subject[*attribute] }
496
497
  else
@@ -25,6 +25,9 @@ module RSpec
25
25
  # @see Configuration#filter_run_including
26
26
  # @see Configuration#filter_run_excluding
27
27
  class Metadata < Hash
28
+ class << self
29
+ attr_accessor :line_number_filter_deprecation_issued
30
+ end
28
31
 
29
32
  def self.relative_path(line)
30
33
  line = line.sub(File.expand_path("."), ".")
@@ -127,6 +130,30 @@ module RSpec
127
130
  include MetadataHash
128
131
 
129
132
  def described_class
133
+ warn_about_first_description_arg_behavioral_change_in_rspec_3
134
+
135
+ value_for_rspec_2 = described_class_for_rspec_2
136
+ value_for_rspec_3 = described_class_for_rspec_3
137
+
138
+ if value_for_rspec_2 != value_for_rspec_3
139
+ RSpec.warn_deprecation(<<-EOS.gsub(/^\s+\|/, ''))
140
+ |The semantics of `described_class` in a nested `describe <SomeClass>`
141
+ |example group are changing in RSpec 3. In RSpec 2.x, `described_class`
142
+ |would return the outermost described class (#{value_for_rspec_2.inspect}).
143
+ |In RSpec 3, it will return the innermost described class (#{value_for_rspec_3.inspect}).
144
+ |In general, we recommend not describing multiple classes or objects in a
145
+ |nested manner as it creates confusion.
146
+ |
147
+ |To make your code compatible with RSpec 3, change from `described_class` to a reference
148
+ |to `#{value_for_rspec_3.inspect}`, or change the arg of the inner `describe` to a string.
149
+ |(Called from #{CallerFilter.first_non_rspec_line})
150
+ EOS
151
+ end
152
+
153
+ value_for_rspec_2
154
+ end
155
+
156
+ def described_class_for_rspec_2
130
157
  container_stack.each do |g|
131
158
  [:described_class, :describes].each do |key|
132
159
  if g.has_key?(key)
@@ -144,6 +171,31 @@ module RSpec
144
171
  nil
145
172
  end
146
173
 
174
+ def described_class_for_rspec_3
175
+ container_stack.each do |g|
176
+ [:described_class, :describes].each do |key|
177
+ if g.has_key?(key)
178
+ value = g[key]
179
+ return value unless value.nil?
180
+ end
181
+ end
182
+
183
+ candidate = g[:description_args].first
184
+ return candidate unless NilClass === candidate || String === candidate || Symbol === candidate
185
+ end
186
+
187
+ nil
188
+ end
189
+
190
+ def warn_about_first_description_arg_behavioral_change_in_rspec_3
191
+ return unless behavior_change = self[:description_arg_behavior_changing_in_rspec_3]
192
+ RSpec.warn_deprecation(behavior_change.warning)
193
+ end
194
+
195
+ def first_description_arg
196
+ self[:description_args].first
197
+ end
198
+
147
199
  def full_description
148
200
  build_description_from(*container_stack.reverse.map {|a| a[:description_args]}.flatten)
149
201
  end
@@ -178,6 +230,7 @@ module RSpec
178
230
 
179
231
  self[:example_group].store(:description_args, args)
180
232
  self[:example_group].store(:caller, user_metadata.delete(:caller) || caller)
233
+ self[:example_group][:description_arg_behavior_changing_in_rspec_3] = user_metadata.delete(:description_arg_behavior_changing_in_rspec_3)
181
234
 
182
235
  update(user_metadata)
183
236
  end
@@ -200,7 +253,16 @@ module RSpec
200
253
  # @private
201
254
  def filter_applies?(key, value, metadata=self)
202
255
  return metadata.filter_applies_to_any_value?(key, value) if Array === metadata[key] && !(Proc === value)
203
- return metadata.line_number_filter_applies?(value) if key == :line_numbers
256
+
257
+ if key == :line_numbers
258
+ unless Metadata.line_number_filter_deprecation_issued
259
+ RSpec.deprecate("Filtering by `:line_numbers`",
260
+ :replacement => "filtering by `:locations`")
261
+ end
262
+
263
+ return metadata.line_number_filter_applies?(value)
264
+ end
265
+
204
266
  return metadata.location_filter_applies?(value) if key == :locations
205
267
  return metadata.filters_apply?(key, value) if Hash === value
206
268