rspec-expectations 3.2.1 → 3.3.0
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Changelog.md +55 -4
- data/README.md +1 -1
- data/lib/rspec/expectations.rb +13 -1
- data/lib/rspec/expectations/configuration.rb +17 -0
- data/lib/rspec/expectations/expectation_target.rb +3 -9
- data/lib/rspec/expectations/fail_with.rb +1 -3
- data/lib/rspec/expectations/failure_aggregator.rb +194 -0
- data/lib/rspec/expectations/minitest_integration.rb +13 -0
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/matchers.rb +59 -5
- data/lib/rspec/matchers/built_in/base_matcher.rb +56 -7
- data/lib/rspec/matchers/built_in/be.rb +25 -15
- data/lib/rspec/matchers/built_in/be_between.rb +1 -1
- data/lib/rspec/matchers/built_in/be_within.rb +2 -2
- data/lib/rspec/matchers/built_in/contain_exactly.rb +12 -8
- data/lib/rspec/matchers/built_in/eq.rb +3 -38
- data/lib/rspec/matchers/built_in/eql.rb +2 -2
- data/lib/rspec/matchers/built_in/equal.rb +3 -3
- data/lib/rspec/matchers/built_in/exist.rb +2 -2
- data/lib/rspec/matchers/built_in/has.rb +3 -1
- data/lib/rspec/matchers/built_in/have_attributes.rb +5 -4
- data/lib/rspec/matchers/built_in/include.rb +44 -19
- data/lib/rspec/matchers/built_in/match.rb +9 -1
- data/lib/rspec/matchers/built_in/operators.rb +14 -5
- data/lib/rspec/matchers/built_in/output.rb +9 -2
- data/lib/rspec/matchers/built_in/raise_error.rb +64 -22
- data/lib/rspec/matchers/built_in/respond_to.rb +2 -3
- data/lib/rspec/matchers/built_in/satisfy.rb +7 -9
- data/lib/rspec/matchers/built_in/start_or_end_with.rb +3 -1
- data/lib/rspec/matchers/built_in/throw_symbol.rb +1 -1
- data/lib/rspec/matchers/built_in/yield.rb +7 -5
- data/lib/rspec/matchers/composable.rb +5 -4
- data/lib/rspec/matchers/dsl.rb +19 -6
- data/lib/rspec/matchers/english_phrasing.rb +42 -0
- data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +2 -8
- data/lib/rspec/matchers/fail_matchers.rb +42 -0
- data/lib/rspec/matchers/matcher_delegator.rb +2 -0
- metadata +9 -7
- metadata.gz.sig +0 -0
- 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
|
55
|
+
# Generates a description using {EnglishPhrasing}.
|
57
56
|
# @return [String]
|
58
57
|
def description
|
59
|
-
|
60
|
-
|
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
|
-
|
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
|
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
|
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: #{
|
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: #{
|
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: #{
|
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: #{
|
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: #{
|
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
|
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
|
-
|
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 #{
|
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 #{
|
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} #{
|
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(#{
|
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 `#{
|
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
|
-
|
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
|
@@ -38,13 +38,13 @@ module RSpec
|
|
38
38
|
# @api private
|
39
39
|
# @return [String]
|
40
40
|
def failure_message
|
41
|
-
"expected #{
|
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 #{
|
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)
|
13
|
-
message += "actual collection contained: #{safe_sort(actual)
|
14
|
-
message += "the missing elements were: #{safe_sort(surface_descriptions_in missing_items)
|
15
|
-
message += "the extra elements were: #{safe_sort(extra_items)
|
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 #{
|
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
|
-
|
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
|
-
|
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
|
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: #{
|
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 != #{
|
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
|
-
"
|
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: #{
|
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 != #{
|
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
|
-
|
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 #{
|
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
|
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 #{
|
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 #{
|
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
|
85
|
+
@args.map { |arg| RSpec::Support::ObjectFormatter.format(arg) }.join(', ')
|
84
86
|
end
|
85
87
|
|
86
88
|
def failure_message_args_description
|