rspec-expectations 3.2.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +55 -4
  5. data/README.md +1 -1
  6. data/lib/rspec/expectations.rb +13 -1
  7. data/lib/rspec/expectations/configuration.rb +17 -0
  8. data/lib/rspec/expectations/expectation_target.rb +3 -9
  9. data/lib/rspec/expectations/fail_with.rb +1 -3
  10. data/lib/rspec/expectations/failure_aggregator.rb +194 -0
  11. data/lib/rspec/expectations/minitest_integration.rb +13 -0
  12. data/lib/rspec/expectations/version.rb +1 -1
  13. data/lib/rspec/matchers.rb +59 -5
  14. data/lib/rspec/matchers/built_in/base_matcher.rb +56 -7
  15. data/lib/rspec/matchers/built_in/be.rb +25 -15
  16. data/lib/rspec/matchers/built_in/be_between.rb +1 -1
  17. data/lib/rspec/matchers/built_in/be_within.rb +2 -2
  18. data/lib/rspec/matchers/built_in/contain_exactly.rb +12 -8
  19. data/lib/rspec/matchers/built_in/eq.rb +3 -38
  20. data/lib/rspec/matchers/built_in/eql.rb +2 -2
  21. data/lib/rspec/matchers/built_in/equal.rb +3 -3
  22. data/lib/rspec/matchers/built_in/exist.rb +2 -2
  23. data/lib/rspec/matchers/built_in/has.rb +3 -1
  24. data/lib/rspec/matchers/built_in/have_attributes.rb +5 -4
  25. data/lib/rspec/matchers/built_in/include.rb +44 -19
  26. data/lib/rspec/matchers/built_in/match.rb +9 -1
  27. data/lib/rspec/matchers/built_in/operators.rb +14 -5
  28. data/lib/rspec/matchers/built_in/output.rb +9 -2
  29. data/lib/rspec/matchers/built_in/raise_error.rb +64 -22
  30. data/lib/rspec/matchers/built_in/respond_to.rb +2 -3
  31. data/lib/rspec/matchers/built_in/satisfy.rb +7 -9
  32. data/lib/rspec/matchers/built_in/start_or_end_with.rb +3 -1
  33. data/lib/rspec/matchers/built_in/throw_symbol.rb +1 -1
  34. data/lib/rspec/matchers/built_in/yield.rb +7 -5
  35. data/lib/rspec/matchers/composable.rb +5 -4
  36. data/lib/rspec/matchers/dsl.rb +19 -6
  37. data/lib/rspec/matchers/english_phrasing.rb +42 -0
  38. data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +2 -8
  39. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  40. data/lib/rspec/matchers/matcher_delegator.rb +2 -0
  41. metadata +9 -7
  42. metadata.gz.sig +0 -0
  43. data/lib/rspec/matchers/pretty.rb +0 -77
@@ -12,7 +12,6 @@ module RSpec
12
12
  # strongly recommend that you do not base your custom matchers on this
13
13
  # class. If/when this changes, we will announce it and remove this warning.
14
14
  class BaseMatcher
15
- include RSpec::Matchers::Pretty
16
15
  include RSpec::Matchers::Composable
17
16
 
18
17
  # @api private
@@ -53,11 +52,12 @@ module RSpec
53
52
  end
54
53
 
55
54
  # @api private
56
- # Generates a "pretty" description using the logic in {Pretty}.
55
+ # Generates a description using {EnglishPhrasing}.
57
56
  # @return [String]
58
57
  def description
59
- return name_to_sentence unless defined?(@expected)
60
- "#{name_to_sentence}#{to_sentence @expected}"
58
+ desc = EnglishPhrasing.split_words(self.class.matcher_name)
59
+ desc << EnglishPhrasing.list(@expected) if defined?(@expected)
60
+ desc
61
61
  end
62
62
 
63
63
  # @api private
@@ -80,21 +80,70 @@ module RSpec
80
80
  false
81
81
  end
82
82
 
83
+ # @private
84
+ def expected_formatted
85
+ RSpec::Support::ObjectFormatter.format(@expected)
86
+ end
87
+
88
+ # @private
89
+ def actual_formatted
90
+ RSpec::Support::ObjectFormatter.format(@actual)
91
+ end
92
+
93
+ # @private
94
+ def self.matcher_name
95
+ @matcher_name ||= underscore(name.split("::").last)
96
+ end
97
+
98
+ # @private
99
+ # Borrowed from ActiveSupport.
100
+ def self.underscore(camel_cased_word)
101
+ word = camel_cased_word.to_s.dup
102
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
103
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
104
+ word.tr!("-", "_")
105
+ word.downcase!
106
+ word
107
+ end
108
+ private_class_method :underscore
109
+
83
110
  private
84
111
 
85
112
  def assert_ivars(*expected_ivars)
86
113
  return unless (expected_ivars - present_ivars).any?
87
- raise "#{self.class.name} needs to supply#{to_sentence expected_ivars}"
114
+ ivar_list = EnglishPhrasing.list(expected_ivars)
115
+ raise "#{self.class.name} needs to supply#{ivar_list}"
88
116
  end
89
117
 
90
118
  if RUBY_VERSION.to_f < 1.9
119
+ # :nocov:
91
120
  def present_ivars
92
121
  instance_variables.map { |v| v.to_sym }
93
122
  end
123
+ # :nocov:
94
124
  else
95
125
  alias present_ivars instance_variables
96
126
  end
97
127
 
128
+ # @private
129
+ module HashFormatting
130
+ # `{ :a => 5, :b => 2 }.inspect` produces:
131
+ #
132
+ # {:a=>5, :b=>2}
133
+ #
134
+ # ...but it looks much better as:
135
+ #
136
+ # {:a => 5, :b => 2}
137
+ #
138
+ # This is idempotent and safe to run on a string multiple times.
139
+ def improve_hash_formatting(inspect_string)
140
+ inspect_string.gsub(/(\S)=>(\S)/, '\1 => \2')
141
+ end
142
+ module_function :improve_hash_formatting
143
+ end
144
+
145
+ include HashFormatting
146
+
98
147
  # @api private
99
148
  # Provides default implementations of failure messages, based on the `description`.
100
149
  module DefaultFailureMessages
@@ -104,7 +153,7 @@ module RSpec
104
153
  # you often only need to override `description`.
105
154
  # @return [String]
106
155
  def failure_message
107
- "expected #{actual.inspect} to #{description}"
156
+ "expected #{description_of @actual} to #{description}"
108
157
  end
109
158
 
110
159
  # @api private
@@ -113,7 +162,7 @@ module RSpec
113
162
  # you often only need to override `description`.
114
163
  # @return [String]
115
164
  def failure_message_when_negated
116
- "expected #{actual.inspect} not to #{description}"
165
+ "expected #{description_of @actual} not to #{description}"
117
166
  end
118
167
 
119
168
  # @private
@@ -8,13 +8,13 @@ module RSpec
8
8
  # @api private
9
9
  # @return [String]
10
10
  def failure_message
11
- "expected: truthy value\n got: #{actual.inspect}"
11
+ "expected: truthy value\n got: #{actual_formatted}"
12
12
  end
13
13
 
14
14
  # @api private
15
15
  # @return [String]
16
16
  def failure_message_when_negated
17
- "expected: falsey value\n got: #{actual.inspect}"
17
+ "expected: falsey value\n got: #{actual_formatted}"
18
18
  end
19
19
 
20
20
  private
@@ -31,13 +31,13 @@ module RSpec
31
31
  # @api private
32
32
  # @return [String]
33
33
  def failure_message
34
- "expected: falsey value\n got: #{actual.inspect}"
34
+ "expected: falsey value\n got: #{actual_formatted}"
35
35
  end
36
36
 
37
37
  # @api private
38
38
  # @return [String]
39
39
  def failure_message_when_negated
40
- "expected: truthy value\n got: #{actual.inspect}"
40
+ "expected: truthy value\n got: #{actual_formatted}"
41
41
  end
42
42
 
43
43
  private
@@ -54,7 +54,7 @@ module RSpec
54
54
  # @api private
55
55
  # @return [String]
56
56
  def failure_message
57
- "expected: nil\n got: #{actual.inspect}"
57
+ "expected: nil\n got: #{actual_formatted}"
58
58
  end
59
59
 
60
60
  # @api private
@@ -83,15 +83,15 @@ module RSpec
83
83
  end
84
84
 
85
85
  def inspected_args
86
- @args.map { |a| a.inspect }
86
+ @args.map { |a| RSpec::Support::ObjectFormatter.format(a) }
87
87
  end
88
88
 
89
89
  def expected_to_sentence
90
- split_words(@expected)
90
+ EnglishPhrasing.split_words(@expected)
91
91
  end
92
92
 
93
93
  def args_to_sentence
94
- to_sentence(@args)
94
+ EnglishPhrasing.list(@args)
95
95
  end
96
96
  end
97
97
 
@@ -108,13 +108,13 @@ module RSpec
108
108
  # @api private
109
109
  # @return [String]
110
110
  def failure_message
111
- "expected #{@actual.inspect} to evaluate to true"
111
+ "expected #{actual_formatted} to evaluate to true"
112
112
  end
113
113
 
114
114
  # @api private
115
115
  # @return [String]
116
116
  def failure_message_when_negated
117
- "expected #{@actual.inspect} to evaluate to false"
117
+ "expected #{actual_formatted} to evaluate to false"
118
118
  end
119
119
 
120
120
  [:==, :<, :<=, :>=, :>, :===, :=~].each do |operator|
@@ -149,13 +149,13 @@ module RSpec
149
149
  # @api private
150
150
  # @return [String]
151
151
  def failure_message
152
- "expected: #{@operator} #{@expected.inspect}\n got: #{@operator.to_s.gsub(/./, ' ')} #{@actual.inspect}"
152
+ "expected: #{@operator} #{expected_formatted}\n got: #{@operator.to_s.gsub(/./, ' ')} #{actual_formatted}"
153
153
  end
154
154
 
155
155
  # @api private
156
156
  # @return [String]
157
157
  def failure_message_when_negated
158
- message = "`expect(#{@actual.inspect}).not_to be #{@operator} #{@expected.inspect}`"
158
+ message = "`expect(#{actual_formatted}).not_to be #{@operator} #{expected_formatted}`"
159
159
  if [:<, :>, :<=, :>=].include?(@operator)
160
160
  message + " not only FAILED, it is a bit confusing."
161
161
  else
@@ -220,9 +220,11 @@ module RSpec
220
220
 
221
221
  # support 1.8.7, evaluate once at load time for performance
222
222
  if String === methods.first
223
+ # :nocov:
223
224
  def private_predicate?
224
225
  @actual.private_methods.include? predicate.to_s
225
226
  end
227
+ # :nocov:
226
228
  else
227
229
  def private_predicate?
228
230
  @actual.private_methods.include? predicate
@@ -252,19 +254,27 @@ module RSpec
252
254
  end
253
255
 
254
256
  def prefix_to_sentence
255
- split_words(@prefix)
257
+ EnglishPhrasing.split_words(@prefix)
256
258
  end
257
259
 
258
260
  def failure_message_expecting(value)
259
261
  validity_message ||
260
- "expected `#{@actual.inspect}.#{predicate}#{args_to_s}` to return #{value}, got #{@predicate_matches.inspect}"
262
+ "expected `#{actual_formatted}.#{predicate}#{args_to_s}` to return #{value}, got #{description_of @predicate_matches}"
261
263
  end
262
264
 
263
265
  def validity_message
264
266
  return nil if predicate_accessible?
265
267
 
266
268
  msg = "expected #{@actual} to respond to `#{predicate}`"
267
- msg << " but `#{predicate}` is a private method" if private_predicate?
269
+
270
+ if private_predicate?
271
+ msg << " but `#{predicate}` is a private method"
272
+ elsif predicate == :true?
273
+ msg << " or perhaps you meant `be true` or `be_truthy`"
274
+ elsif predicate == :false?
275
+ msg << " or perhaps you meant `be false` or `be_falsey`"
276
+ end
277
+
268
278
  msg
269
279
  end
270
280
  end
@@ -55,7 +55,7 @@ module RSpec
55
55
  # @api private
56
56
  # @return [String]
57
57
  def description
58
- "be between #{@min.inspect} and #{@max.inspect} (#{@mode})"
58
+ "be between #{description_of @min} and #{description_of @max} (#{@mode})"
59
59
  end
60
60
 
61
61
  private
@@ -38,13 +38,13 @@ module RSpec
38
38
  # @api private
39
39
  # @return [String]
40
40
  def failure_message
41
- "expected #{@actual.inspect} to #{description}#{not_numeric_clause}"
41
+ "expected #{actual_formatted} to #{description}#{not_numeric_clause}"
42
42
  end
43
43
 
44
44
  # @api private
45
45
  # @return [String]
46
46
  def failure_message_when_negated
47
- "expected #{@actual.inspect} not to #{description}"
47
+ "expected #{actual_formatted} not to #{description}"
48
48
  end
49
49
 
50
50
  # @api private
@@ -9,27 +9,29 @@ module RSpec
9
9
  # @return [String]
10
10
  def failure_message
11
11
  if Array === actual
12
- message = "expected collection contained: #{safe_sort(surface_descriptions_in expected).inspect}\n"
13
- message += "actual collection contained: #{safe_sort(actual).inspect}\n"
14
- message += "the missing elements were: #{safe_sort(surface_descriptions_in missing_items).inspect}\n" unless missing_items.empty?
15
- message += "the extra elements were: #{safe_sort(extra_items).inspect}\n" unless extra_items.empty?
12
+ message = "expected collection contained: #{description_of(safe_sort(surface_descriptions_in expected))}\n"
13
+ message += "actual collection contained: #{description_of(safe_sort(actual))}\n"
14
+ message += "the missing elements were: #{description_of(safe_sort(surface_descriptions_in missing_items))}\n" unless missing_items.empty?
15
+ message += "the extra elements were: #{description_of(safe_sort(extra_items))}\n" unless extra_items.empty?
16
16
  message
17
17
  else
18
18
  "expected a collection that can be converted to an array with " \
19
- "`#to_ary` or `#to_a`, but got #{actual.inspect}"
19
+ "`#to_ary` or `#to_a`, but got #{actual_formatted}"
20
20
  end
21
21
  end
22
22
 
23
23
  # @api private
24
24
  # @return [String]
25
25
  def failure_message_when_negated
26
- "expected #{actual.inspect} not to contain exactly#{to_sentence(surface_descriptions_in expected)}"
26
+ list = EnglishPhrasing.list(surface_descriptions_in(expected))
27
+ "expected #{actual_formatted} not to contain exactly#{list}"
27
28
  end
28
29
 
29
30
  # @api private
30
31
  # @return [String]
31
32
  def description
32
- "contain exactly#{to_sentence(surface_descriptions_in expected)}"
33
+ list = EnglishPhrasing.list(surface_descriptions_in(expected))
34
+ "contain exactly#{list}"
33
35
  end
34
36
 
35
37
  private
@@ -58,7 +60,9 @@ module RSpec
58
60
  end
59
61
 
60
62
  def safe_sort(array)
61
- array.sort rescue array
63
+ array.sort
64
+ rescue Exception
65
+ array
62
66
  end
63
67
 
64
68
  def missing_items
@@ -8,19 +8,19 @@ module RSpec
8
8
  # @api private
9
9
  # @return [String]
10
10
  def failure_message
11
- "\nexpected: #{format_object(expected)}\n got: #{format_object(actual)}\n\n(compared using ==)\n"
11
+ "\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using ==)\n"
12
12
  end
13
13
 
14
14
  # @api private
15
15
  # @return [String]
16
16
  def failure_message_when_negated
17
- "\nexpected: value != #{format_object(expected)}\n got: #{format_object(actual)}\n\n(compared using ==)\n"
17
+ "\nexpected: value != #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using ==)\n"
18
18
  end
19
19
 
20
20
  # @api private
21
21
  # @return [String]
22
22
  def description
23
- "#{name_to_sentence} #{@expected.inspect}"
23
+ "eq #{expected_formatted}"
24
24
  end
25
25
 
26
26
  # @api private
@@ -34,41 +34,6 @@ module RSpec
34
34
  def match(expected, actual)
35
35
  actual == expected
36
36
  end
37
-
38
- def format_object(object)
39
- if Time === object
40
- format_time(object)
41
- elsif defined?(DateTime) && DateTime === object
42
- format_date_time(object)
43
- elsif defined?(BigDecimal) && BigDecimal === object
44
- "#{object.to_s 'F'} (#{object.inspect})"
45
- else
46
- object.inspect
47
- end
48
- end
49
-
50
- TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
51
-
52
- if Time.method_defined?(:nsec)
53
- def format_time(time)
54
- time.strftime("#{TIME_FORMAT}.#{"%09d" % time.nsec} %z")
55
- end
56
- else # for 1.8.7
57
- def format_time(time)
58
- time.strftime("#{TIME_FORMAT}.#{"%06d" % time.usec} %z")
59
- end
60
- end
61
-
62
- DATE_TIME_FORMAT = "%a, %d %b %Y %H:%M:%S.%N %z"
63
- # ActiveSupport sometimes overrides inspect. If `ActiveSupport` is
64
- # defined use a custom format string that includes more time precision.
65
- def format_date_time(date_time)
66
- if defined?(ActiveSupport)
67
- date_time.strftime(DATE_TIME_FORMAT)
68
- else
69
- date_time.inspect
70
- end
71
- end
72
37
  end
73
38
  end
74
39
  end
@@ -8,13 +8,13 @@ module RSpec
8
8
  # @api private
9
9
  # @return [String]
10
10
  def failure_message
11
- "\nexpected: #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n"
11
+ "\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using eql?)\n"
12
12
  end
13
13
 
14
14
  # @api private
15
15
  # @return [String]
16
16
  def failure_message_when_negated
17
- "\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n"
17
+ "\nexpected: value != #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using eql?)\n"
18
18
  end
19
19
 
20
20
  # @api private
@@ -48,14 +48,14 @@ MESSAGE
48
48
 
49
49
  def actual_inspected
50
50
  if LITERAL_SINGLETONS.include?(actual)
51
- actual.inspect
51
+ actual_formatted
52
52
  else
53
53
  inspect_object(actual)
54
54
  end
55
55
  end
56
56
 
57
57
  def simple_failure_message
58
- "\nexpected #{expected.inspect}\n got #{actual_inspected}\n"
58
+ "\nexpected #{expected_formatted}\n got #{actual_inspected}\n"
59
59
  end
60
60
 
61
61
  def detailed_failure_message
@@ -73,7 +73,7 @@ MESSAGE
73
73
  end
74
74
 
75
75
  def inspect_object(o)
76
- "#<#{o.class}:#{o.object_id}> => #{o.inspect}"
76
+ "#<#{o.class}:#{o.object_id}> => #{RSpec::Support::ObjectFormatter.format(o)}"
77
77
  end
78
78
  end
79
79
  end
@@ -28,13 +28,13 @@ module RSpec
28
28
  # @api private
29
29
  # @return [String]
30
30
  def failure_message
31
- "expected #{@actual.inspect} to exist#{@test.validity_message}"
31
+ "expected #{actual_formatted} to exist#{@test.validity_message}"
32
32
  end
33
33
 
34
34
  # @api private
35
35
  # @return [String]
36
36
  def failure_message_when_negated
37
- "expected #{@actual.inspect} not to exist#{@test.validity_message}"
37
+ "expected #{actual_formatted} not to exist#{@test.validity_message}"
38
38
  end
39
39
 
40
40
  # @api private
@@ -49,9 +49,11 @@ module RSpec
49
49
 
50
50
  # support 1.8.7, evaluate once at load time for performance
51
51
  if String === methods.first
52
+ # :nocov:
52
53
  def private_predicate?
53
54
  @actual.private_methods.include? predicate.to_s
54
55
  end
56
+ # :nocov:
55
57
  else
56
58
  def private_predicate?
57
59
  @actual.private_methods.include? predicate
@@ -80,7 +82,7 @@ module RSpec
80
82
 
81
83
  def args_description
82
84
  return nil if @args.empty?
83
- @args.map { |arg| arg.inspect }.join(', ')
85
+ @args.map { |arg| RSpec::Support::ObjectFormatter.format(arg) }.join(', ')
84
86
  end
85
87
 
86
88
  def failure_message_args_description