rspec-core 2.99.0.beta2 → 2.99.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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