rspec-expectations 3.3.1 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +1 -1
- data/Changelog.md +26 -0
- data/{License.txt → LICENSE.md} +5 -4
- data/README.md +18 -4
- data/lib/rspec/expectations/failure_aggregator.rb +1 -1
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/matchers.rb +28 -0
- data/lib/rspec/matchers/built_in/base_matcher.rb +6 -6
- data/lib/rspec/matchers/built_in/be.rb +1 -1
- data/lib/rspec/matchers/built_in/change.rb +30 -13
- data/lib/rspec/matchers/built_in/compound.rb +4 -25
- data/lib/rspec/matchers/built_in/contain_exactly.rb +40 -7
- data/lib/rspec/matchers/built_in/match.rb +70 -1
- data/lib/rspec/matchers/built_in/raise_error.rb +17 -5
- data/lib/rspec/matchers/built_in/yield.rb +40 -39
- data/lib/rspec/matchers/composable.rb +16 -15
- metadata +8 -8
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ecfc9ad6573cbd51308c24b96e60534b430370e8
|
4
|
+
data.tar.gz: ee7aec158266ec8c5902def9e5777d0f47a4eb18
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 747ae15f2866456d52996626be3ce0f131beac9c92ab447d865c052e9c6211b0eacac9f1c80d2140ef8185e6c1d3f45e88ac49d48c0b23346df325f00f84678c
|
7
|
+
data.tar.gz: 55853e5d95bf9019031a1652cf6d8b553d65ebea517b309514275faab04b66a2a713d07ab6021eb96df3d537a106d39bde239933722f2f76f236ae7518aa84a3
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/.document
CHANGED
data/.yardopts
CHANGED
data/Changelog.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
### 3.4.0 / 2015-11-11
|
2
|
+
[Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.1...v3.4.0)
|
3
|
+
|
4
|
+
Enhancements:
|
5
|
+
|
6
|
+
* Warn when `RSpec::Matchers` is included in a superclass after it has
|
7
|
+
already been included in a subclass on MRI 1.9, since that situation
|
8
|
+
can cause uses of `super` to trigger infinite recursion. (Myron Marston, #816)
|
9
|
+
* Stop rescuing `NoMemoryError`, `SignalExcepetion`, `Interrupt` and
|
10
|
+
`SystemExit`. It is dangerous to interfere with these. (Myron Marston, #845)
|
11
|
+
* Add `#with_captures` to the
|
12
|
+
[match matcher](https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/match-matcher)
|
13
|
+
which allows a user to specify expected captures when matching a regex
|
14
|
+
against a string. (Sam Phippen, #848)
|
15
|
+
* Always print compound failure messages in the multi-line form. Trying
|
16
|
+
to print it all on a single line didn't read very well. (Myron Marston, #859)
|
17
|
+
|
18
|
+
Bug Fixes:
|
19
|
+
|
20
|
+
* Fix failure message from dynamic predicate matchers when the object
|
21
|
+
does not respond to the predicate so that it is inspected rather
|
22
|
+
than relying upon it's `to_s` -- that way for `nil`, `"nil"` is
|
23
|
+
printed rather than an empty string. (Myron Marston, #841)
|
24
|
+
* Fix SystemStackError raised when diffing an Enumerable object
|
25
|
+
whose `#each` includes the object itself. (Yuji Nakayama, #857)
|
26
|
+
|
1
27
|
### 3.3.1 / 2015-07-15
|
2
28
|
[Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.0...v3.3.1)
|
3
29
|
|
data/{License.txt → LICENSE.md}
RENAMED
@@ -1,8 +1,9 @@
|
|
1
|
-
|
1
|
+
The MIT License (MIT)
|
2
|
+
=====================
|
2
3
|
|
3
|
-
Copyright
|
4
|
-
Copyright
|
5
|
-
Copyright
|
4
|
+
* Copyright © 2012 David Chelimsky, Myron Marston
|
5
|
+
* Copyright © 2006 David Chelimsky, The RSpec Development Team
|
6
|
+
* Copyright © 2005 Steven Baker
|
6
7
|
|
7
8
|
Permission is hereby granted, free of charge, to any person obtaining
|
8
9
|
a copy of this software and associated documentation files (the
|
data/README.md
CHANGED
@@ -27,6 +27,20 @@ Minitest, or Cucumber, you can install it directly:
|
|
27
27
|
|
28
28
|
gem install rspec-expectations
|
29
29
|
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
Once you've set up the environment, you'll need to cd into the working
|
33
|
+
directory of whichever repo you want to work in. From there you can run the
|
34
|
+
specs and cucumber features, and make patches.
|
35
|
+
|
36
|
+
NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
|
37
|
+
can treat each RSpec repo as an independent project.
|
38
|
+
|
39
|
+
- [Build details](BUILD_DETAIL.md)
|
40
|
+
- [Code of Conduct](CODE_OF_CONDUCT.md)
|
41
|
+
- [Detailed contributing guide](CONTRIBUTING.md)
|
42
|
+
- [Development setup guide](DEVELOPMENT.md)
|
43
|
+
|
30
44
|
## Basic usage
|
31
45
|
|
32
46
|
Here's an example using rspec-core:
|
@@ -283,7 +297,7 @@ end
|
|
283
297
|
|
284
298
|
## Also see
|
285
299
|
|
286
|
-
* [
|
287
|
-
* [
|
288
|
-
* [
|
289
|
-
* [
|
300
|
+
* [https://github.com/rspec/rspec](https://github.com/rspec/rspec)
|
301
|
+
* [https://github.com/rspec/rspec-core](https://github.com/rspec/rspec-core)
|
302
|
+
* [https://github.com/rspec/rspec-mocks](https://github.com/rspec/rspec-mocks)
|
303
|
+
* [https://github.com/rspec/rspec-rails](https://github.com/rspec/rspec-rails)
|
@@ -15,7 +15,7 @@ module RSpec
|
|
15
15
|
# of `failures` rather than letting it fall through and be categorized as part of
|
16
16
|
# `other_errors`.
|
17
17
|
failures << e
|
18
|
-
rescue
|
18
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
|
19
19
|
# While it is normally a bad practice to rescue `Exception`, it's important we do
|
20
20
|
# so here. It's low risk (`notify_aggregated_failures` below will re-raise the exception,
|
21
21
|
# or raise a `MultipleExpectationsNotMetError` that includes the exception), and it's
|
data/lib/rspec/matchers.rb
CHANGED
@@ -1005,5 +1005,33 @@ module RSpec
|
|
1005
1005
|
def self.is_a_describable_matcher?(obj)
|
1006
1006
|
is_a_matcher?(obj) && obj.respond_to?(:description)
|
1007
1007
|
end
|
1008
|
+
|
1009
|
+
if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9'
|
1010
|
+
# @api private
|
1011
|
+
# Note that `included` doesn't work for this because it is triggered
|
1012
|
+
# _after_ `RSpec::Matchers` is an ancestor of the inclusion host, rather
|
1013
|
+
# than _before_, like `append_features`. It's important we check this before
|
1014
|
+
# in order to find the cases where it was already previously included.
|
1015
|
+
def self.append_features(mod)
|
1016
|
+
return super if mod < self # `mod < self` indicates a re-inclusion.
|
1017
|
+
|
1018
|
+
subclasses = ObjectSpace.each_object(Class).select { |c| c < mod && c < self }
|
1019
|
+
return super unless subclasses.any?
|
1020
|
+
|
1021
|
+
subclasses.reject! { |s| subclasses.any? { |s2| s < s2 } } # Filter to the root ancestor.
|
1022
|
+
subclasses = subclasses.map { |s| "`#{s}`" }.join(", ")
|
1023
|
+
|
1024
|
+
RSpec.warning "`#{self}` has been included in a superclass (`#{mod}`) " \
|
1025
|
+
"after previously being included in subclasses (#{subclasses}), " \
|
1026
|
+
"which can trigger infinite recursion from `super` due to an MRI 1.9 bug " \
|
1027
|
+
"(https://redmine.ruby-lang.org/issues/3351). To work around this, " \
|
1028
|
+
"either upgrade to MRI 2.0+, include a dup of the module (e.g. " \
|
1029
|
+
"`include #{self}.dup`), or find a way to include `#{self}` in `#{mod}` " \
|
1030
|
+
"before it is included in subclasses (#{subclasses}). See " \
|
1031
|
+
"https://github.com/rspec/rspec-expectations/issues/814 for more info"
|
1032
|
+
|
1033
|
+
super
|
1034
|
+
end
|
1035
|
+
end
|
1008
1036
|
end
|
1009
1037
|
end
|
@@ -8,8 +8,8 @@ module RSpec
|
|
8
8
|
#
|
9
9
|
# ### Warning:
|
10
10
|
#
|
11
|
-
# This class is for internal use, and subject to change without notice.
|
12
|
-
# strongly recommend that you do not base your custom matchers on this
|
11
|
+
# This class is for internal use, and subject to change without notice.
|
12
|
+
# We 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
15
|
include RSpec::Matchers::Composable
|
@@ -92,7 +92,7 @@ module RSpec
|
|
92
92
|
|
93
93
|
# @private
|
94
94
|
def self.matcher_name
|
95
|
-
@matcher_name ||= underscore(name.split(
|
95
|
+
@matcher_name ||= underscore(name.split('::').last)
|
96
96
|
end
|
97
97
|
|
98
98
|
# @private
|
@@ -101,7 +101,7 @@ module RSpec
|
|
101
101
|
word = camel_cased_word.to_s.dup
|
102
102
|
word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
103
103
|
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
104
|
-
word.tr!(
|
104
|
+
word.tr!('-', '_')
|
105
105
|
word.downcase!
|
106
106
|
word
|
107
107
|
end
|
@@ -118,7 +118,7 @@ module RSpec
|
|
118
118
|
if RUBY_VERSION.to_f < 1.9
|
119
119
|
# :nocov:
|
120
120
|
def present_ivars
|
121
|
-
instance_variables.map
|
121
|
+
instance_variables.map(&:to_sym)
|
122
122
|
end
|
123
123
|
# :nocov:
|
124
124
|
else
|
@@ -168,7 +168,7 @@ module RSpec
|
|
168
168
|
# @private
|
169
169
|
def self.has_default_failure_messages?(matcher)
|
170
170
|
matcher.method(:failure_message).owner == self &&
|
171
|
-
|
171
|
+
matcher.method(:failure_message_when_negated).owner == self
|
172
172
|
rescue NameError
|
173
173
|
false
|
174
174
|
end
|
@@ -267,7 +267,7 @@ module RSpec
|
|
267
267
|
def validity_message
|
268
268
|
return nil if predicate_accessible?
|
269
269
|
|
270
|
-
msg = "expected #{
|
270
|
+
msg = "expected #{actual_formatted} to respond to `#{predicate}`"
|
271
271
|
|
272
272
|
if private_predicate?
|
273
273
|
msg << " but `#{predicate}` is a private method"
|
@@ -58,13 +58,15 @@ module RSpec
|
|
58
58
|
# @api private
|
59
59
|
# @return [String]
|
60
60
|
def failure_message
|
61
|
-
"expected #{@change_details.message} to have changed,
|
61
|
+
"expected #{@change_details.message} to have changed, " \
|
62
|
+
"but #{positive_failure_reason}"
|
62
63
|
end
|
63
64
|
|
64
65
|
# @api private
|
65
66
|
# @return [String]
|
66
67
|
def failure_message_when_negated
|
67
|
-
"expected #{@change_details.message} not to have changed,
|
68
|
+
"expected #{@change_details.message} not to have changed, " \
|
69
|
+
"but #{negative_failure_reason}"
|
68
70
|
end
|
69
71
|
|
70
72
|
# @api private
|
@@ -96,7 +98,8 @@ module RSpec
|
|
96
98
|
|
97
99
|
def negative_failure_reason
|
98
100
|
return "was not given a block" unless Proc === @event_proc
|
99
|
-
"did change from #{description_of @change_details.actual_before}
|
101
|
+
"did change from #{description_of @change_details.actual_before} " \
|
102
|
+
"to #{description_of @change_details.actual_after}"
|
100
103
|
end
|
101
104
|
end
|
102
105
|
|
@@ -112,7 +115,9 @@ module RSpec
|
|
112
115
|
|
113
116
|
# @private
|
114
117
|
def failure_message
|
115
|
-
"expected #{@change_details.message} to have changed
|
118
|
+
"expected #{@change_details.message} to have changed " \
|
119
|
+
"#{@relativity.to_s.tr('_', ' ')} " \
|
120
|
+
"#{description_of @expected_delta}, but #{failure_reason}"
|
116
121
|
end
|
117
122
|
|
118
123
|
# @private
|
@@ -125,12 +130,14 @@ module RSpec
|
|
125
130
|
|
126
131
|
# @private
|
127
132
|
def does_not_match?(_event_proc)
|
128
|
-
raise NotImplementedError, "`expect { }.not_to change
|
133
|
+
raise NotImplementedError, "`expect { }.not_to change " \
|
134
|
+
"{ }.#{@relativity}()` is not supported"
|
129
135
|
end
|
130
136
|
|
131
137
|
# @private
|
132
138
|
def description
|
133
|
-
"change #{@change_details.message}
|
139
|
+
"change #{@change_details.message} " \
|
140
|
+
"#{@relativity.to_s.tr('_', ' ')} #{description_of @expected_delta}"
|
134
141
|
end
|
135
142
|
|
136
143
|
# @private
|
@@ -195,23 +202,31 @@ module RSpec
|
|
195
202
|
end
|
196
203
|
|
197
204
|
def before_value_failure
|
198
|
-
"expected #{@change_details.message}
|
205
|
+
"expected #{@change_details.message} " \
|
206
|
+
"to have initially been #{description_of @expected_before}, " \
|
207
|
+
"but was #{description_of @change_details.actual_before}"
|
199
208
|
end
|
200
209
|
|
201
210
|
def after_value_failure
|
202
|
-
"expected #{@change_details.message}
|
211
|
+
"expected #{@change_details.message} " \
|
212
|
+
"to have changed to #{description_of @expected_after}, " \
|
213
|
+
"but is now #{description_of @change_details.actual_after}"
|
203
214
|
end
|
204
215
|
|
205
216
|
def did_not_change_failure
|
206
|
-
"expected #{@change_details.message}
|
217
|
+
"expected #{@change_details.message} " \
|
218
|
+
"to have changed #{change_description}, but did not change"
|
207
219
|
end
|
208
220
|
|
209
221
|
def did_change_failure
|
210
|
-
"expected #{@change_details.message} not to have changed, but
|
222
|
+
"expected #{@change_details.message} not to have changed, but " \
|
223
|
+
"did change from #{description_of @change_details.actual_before} " \
|
224
|
+
"to #{description_of @change_details.actual_after}"
|
211
225
|
end
|
212
226
|
|
213
227
|
def not_given_a_block_failure
|
214
|
-
"expected #{@change_details.message} to have changed
|
228
|
+
"expected #{@change_details.message} to have changed " \
|
229
|
+
"#{change_description}, but was not given a block"
|
215
230
|
end
|
216
231
|
end
|
217
232
|
|
@@ -235,7 +250,8 @@ module RSpec
|
|
235
250
|
# @private
|
236
251
|
def does_not_match?(event_proc)
|
237
252
|
if @description_suffix
|
238
|
-
raise NotImplementedError, "`expect { }.not_to change { }.to()`
|
253
|
+
raise NotImplementedError, "`expect { }.not_to change { }.to()` " \
|
254
|
+
"is not supported"
|
239
255
|
end
|
240
256
|
|
241
257
|
@event_proc = event_proc
|
@@ -277,7 +293,8 @@ module RSpec
|
|
277
293
|
|
278
294
|
# @private
|
279
295
|
def does_not_match?(_event_proc)
|
280
|
-
raise NotImplementedError, "`expect { }.not_to change { }.to()`
|
296
|
+
raise NotImplementedError, "`expect { }.not_to change { }.to()` " \
|
297
|
+
"is not supported"
|
281
298
|
end
|
282
299
|
|
283
300
|
private
|
@@ -24,7 +24,7 @@ module RSpec
|
|
24
24
|
# @api private
|
25
25
|
# @return [String]
|
26
26
|
def description
|
27
|
-
|
27
|
+
"#{matcher_1.description} #{conjunction} #{matcher_2.description}"
|
28
28
|
end
|
29
29
|
|
30
30
|
def supports_block_expectations?
|
@@ -84,30 +84,9 @@ module RSpec
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def compound_failure_message
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
if multiline?(message_1) || multiline?(message_2)
|
91
|
-
multiline_message(message_1, message_2)
|
92
|
-
else
|
93
|
-
singleline_message(message_1, message_2)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def multiline_message(message_1, message_2)
|
98
|
-
[
|
99
|
-
indent_multiline_message(message_1.sub(/\n+\z/, '')),
|
100
|
-
"...#{conjunction}:",
|
101
|
-
indent_multiline_message(message_2.sub(/\A\n+/, ''))
|
102
|
-
].join("\n\n")
|
103
|
-
end
|
104
|
-
|
105
|
-
def multiline?(message)
|
106
|
-
message.lines.count > 1
|
107
|
-
end
|
108
|
-
|
109
|
-
def singleline_message(message_1, message_2)
|
110
|
-
[message_1, conjunction, message_2].join(' ')
|
87
|
+
"#{indent_multiline_message(matcher_1.failure_message.sub(/\n+\z/, ''))}" \
|
88
|
+
"\n\n...#{conjunction}:" \
|
89
|
+
"\n\n#{indent_multiline_message(matcher_2.failure_message.sub(/\A\n+/, ''))}"
|
111
90
|
end
|
112
91
|
|
113
92
|
def matcher_1_matches?
|
@@ -9,11 +9,7 @@ module RSpec
|
|
9
9
|
# @return [String]
|
10
10
|
def failure_message
|
11
11
|
if Array === actual
|
12
|
-
|
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
|
-
message
|
12
|
+
generate_failure_message
|
17
13
|
else
|
18
14
|
"expected a collection that can be converted to an array with " \
|
19
15
|
"`#to_ary` or `#to_a`, but got #{actual_formatted}"
|
@@ -36,6 +32,43 @@ module RSpec
|
|
36
32
|
|
37
33
|
private
|
38
34
|
|
35
|
+
def generate_failure_message
|
36
|
+
message = expected_collection_line
|
37
|
+
message += actual_collection_line
|
38
|
+
message += missing_elements_line unless missing_items.empty?
|
39
|
+
message += extra_elements_line unless extra_items.empty?
|
40
|
+
message
|
41
|
+
end
|
42
|
+
|
43
|
+
def expected_collection_line
|
44
|
+
message_line('expected collection contained', expected, true)
|
45
|
+
end
|
46
|
+
|
47
|
+
def actual_collection_line
|
48
|
+
message_line('actual collection contained', actual)
|
49
|
+
end
|
50
|
+
|
51
|
+
def missing_elements_line
|
52
|
+
message_line('the missing elements were', missing_items, true)
|
53
|
+
end
|
54
|
+
|
55
|
+
def extra_elements_line
|
56
|
+
message_line('the extra elements were', extra_items)
|
57
|
+
end
|
58
|
+
|
59
|
+
def describe_collection(collection, surface_descriptions=false)
|
60
|
+
if surface_descriptions
|
61
|
+
"#{description_of(safe_sort(surface_descriptions_in collection))}\n"
|
62
|
+
else
|
63
|
+
"#{description_of(safe_sort(collection))}\n"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def message_line(prefix, collection, surface_descriptions=false)
|
68
|
+
"%-32s%s" % [prefix + ':',
|
69
|
+
describe_collection(collection, surface_descriptions)]
|
70
|
+
end
|
71
|
+
|
39
72
|
def match(_expected, _actual)
|
40
73
|
return false unless convert_actual_to_an_array
|
41
74
|
match_when_sorted? || (extra_items.empty? && missing_items.empty?)
|
@@ -61,7 +94,7 @@ module RSpec
|
|
61
94
|
|
62
95
|
def safe_sort(array)
|
63
96
|
array.sort
|
64
|
-
rescue
|
97
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue
|
65
98
|
array
|
66
99
|
end
|
67
100
|
|
@@ -231,7 +264,7 @@ module RSpec
|
|
231
264
|
|
232
265
|
modified_expecteds.delete(expected_index)
|
233
266
|
|
234
|
-
modified_actuals
|
267
|
+
modified_actuals = apply_pairing_to(
|
235
268
|
solution.indeterminate_actual_indexes,
|
236
269
|
actual_to_expected_matched_indexes, expected_index)
|
237
270
|
|
@@ -5,10 +5,19 @@ module RSpec
|
|
5
5
|
# Provides the implementation for `match`.
|
6
6
|
# Not intended to be instantiated directly.
|
7
7
|
class Match < BaseMatcher
|
8
|
+
def initialize(expected)
|
9
|
+
super(expected)
|
10
|
+
|
11
|
+
@expected_captures = nil
|
12
|
+
end
|
8
13
|
# @api private
|
9
14
|
# @return [String]
|
10
15
|
def description
|
11
|
-
|
16
|
+
if @expected_captures && @expected.match(actual)
|
17
|
+
"match #{surface_descriptions_in(expected).inspect} with captures #{surface_descriptions_in(@expected_captures).inspect}"
|
18
|
+
else
|
19
|
+
"match #{surface_descriptions_in(expected).inspect}"
|
20
|
+
end
|
12
21
|
end
|
13
22
|
|
14
23
|
# @api private
|
@@ -17,9 +26,17 @@ module RSpec
|
|
17
26
|
true
|
18
27
|
end
|
19
28
|
|
29
|
+
# Used to specify the captures we match against
|
30
|
+
# @return [self]
|
31
|
+
def with_captures(*captures)
|
32
|
+
@expected_captures = captures
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
20
36
|
private
|
21
37
|
|
22
38
|
def match(expected, actual)
|
39
|
+
return match_captures(expected, actual) if @expected_captures
|
23
40
|
return true if values_match?(expected, actual)
|
24
41
|
return false unless can_safely_call_match?(expected, actual)
|
25
42
|
actual.match(expected)
|
@@ -31,6 +48,58 @@ module RSpec
|
|
31
48
|
!(RSpec::Matchers.is_a_matcher?(expected) &&
|
32
49
|
(String === actual || Regexp === actual))
|
33
50
|
end
|
51
|
+
|
52
|
+
def match_captures(expected, actual)
|
53
|
+
match = actual.match(expected)
|
54
|
+
if match
|
55
|
+
match = ReliableMatchData.new(match)
|
56
|
+
if match.names.empty?
|
57
|
+
values_match?(@expected_captures, match.captures)
|
58
|
+
else
|
59
|
+
expected_matcher = @expected_captures.last
|
60
|
+
values_match?(expected_matcher, Hash[match.names.zip(match.captures)]) ||
|
61
|
+
values_match?(expected_matcher, Hash[match.names.map(&:to_sym).zip(match.captures)]) ||
|
62
|
+
values_match?(@expected_captures, match.captures)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# @api private
|
71
|
+
# Used to wrap match data and make it reliable for 1.8.7
|
72
|
+
class ReliableMatchData
|
73
|
+
def initialize(match_data)
|
74
|
+
@match_data = match_data
|
75
|
+
end
|
76
|
+
|
77
|
+
if RUBY_VERSION == "1.8.7"
|
78
|
+
# @api private
|
79
|
+
# Returns match data names for named captures
|
80
|
+
# @return Array
|
81
|
+
def names
|
82
|
+
[]
|
83
|
+
end
|
84
|
+
else
|
85
|
+
# @api private
|
86
|
+
# Returns match data names for named captures
|
87
|
+
# @return Array
|
88
|
+
def names
|
89
|
+
match_data.names
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @api private
|
94
|
+
# returns an array of captures from the match data
|
95
|
+
# @return Array
|
96
|
+
def captures
|
97
|
+
match_data.captures
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
attr_reader :match_data
|
34
103
|
end
|
35
104
|
end
|
36
105
|
end
|
@@ -5,6 +5,7 @@ module RSpec
|
|
5
5
|
# Provides the implementation for `raise_error`.
|
6
6
|
# Not intended to be instantiated directly.
|
7
7
|
# rubocop:disable ClassLength
|
8
|
+
# rubocop:disable RescueException
|
8
9
|
class RaiseError
|
9
10
|
include Composable
|
10
11
|
|
@@ -15,11 +16,14 @@ module RSpec
|
|
15
16
|
|
16
17
|
case expected_error_or_message
|
17
18
|
when nil
|
18
|
-
@expected_error
|
19
|
+
@expected_error = Exception
|
20
|
+
@expected_message = expected_message
|
19
21
|
when String
|
20
|
-
@expected_error
|
22
|
+
@expected_error = Exception
|
23
|
+
@expected_message = expected_error_or_message
|
21
24
|
else
|
22
|
-
@expected_error
|
25
|
+
@expected_error = expected_error_or_message
|
26
|
+
@expected_message = expected_message
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
@@ -42,7 +46,6 @@ module RSpec
|
|
42
46
|
@eval_block = false
|
43
47
|
@eval_block_passed = false
|
44
48
|
|
45
|
-
warn_about_bare_error if warning_about_bare_error && !negative_expectation
|
46
49
|
return false unless Proc === given_proc
|
47
50
|
|
48
51
|
begin
|
@@ -55,6 +58,7 @@ module RSpec
|
|
55
58
|
end
|
56
59
|
end
|
57
60
|
|
61
|
+
warn_about_bare_error if warning_about_bare_error && !negative_expectation
|
58
62
|
eval_block if !negative_expectation && ready_to_eval_block?
|
59
63
|
|
60
64
|
expectation_matched?
|
@@ -156,6 +160,7 @@ module RSpec
|
|
156
160
|
"will match when Ruby raises a `NoMethodError`, `NameError` or " \
|
157
161
|
"`ArgumentError`, potentially allowing the expectation to pass " \
|
158
162
|
"without even executing the method you are intending to call. " \
|
163
|
+
"#{warning}"\
|
159
164
|
"Instead consider providing a specific error class or message. " \
|
160
165
|
"This message can be supressed by setting: " \
|
161
166
|
"`RSpec::Expectations.configuration.warn_about_potential_false_positives = false`")
|
@@ -207,9 +212,16 @@ module RSpec
|
|
207
212
|
end
|
208
213
|
|
209
214
|
def raise_message_already_set
|
210
|
-
raise "`expect { }.to raise_error(message).with_message(message)` is not valid.
|
215
|
+
raise "`expect { }.to raise_error(message).with_message(message)` is not valid. " \
|
216
|
+
'The matcher only allows the expected message to be specified once'
|
217
|
+
end
|
218
|
+
|
219
|
+
def warning
|
220
|
+
warning = "Actual error raised was #{description_of(@actual_error)}. "
|
221
|
+
warning if @actual_error
|
211
222
|
end
|
212
223
|
end
|
224
|
+
# rubocop:enable RescueException
|
213
225
|
# rubocop:enable ClassLength
|
214
226
|
end
|
215
227
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
RSpec::Support.require_rspec_support
|
1
|
+
RSpec::Support.require_rspec_support 'method_signature_verifier'
|
2
2
|
|
3
3
|
module RSpec
|
4
4
|
module Matchers
|
@@ -22,7 +22,8 @@ module RSpec
|
|
22
22
|
def initialize(block)
|
23
23
|
@block = block
|
24
24
|
@used = false
|
25
|
-
self.num_yields
|
25
|
+
self.num_yields = 0
|
26
|
+
self.yielded_args = []
|
26
27
|
end
|
27
28
|
|
28
29
|
def has_block?
|
@@ -50,8 +51,8 @@ module RSpec
|
|
50
51
|
when 0 then false
|
51
52
|
else
|
52
53
|
raise "The #{matcher_name} matcher is not designed to be used with a " \
|
53
|
-
|
54
|
-
|
54
|
+
'method that yields multiple times. Use the yield_successive_args ' \
|
55
|
+
'matcher for that case.'
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
@@ -63,19 +64,19 @@ module RSpec
|
|
63
64
|
|
64
65
|
def assert_used!
|
65
66
|
return if @used
|
66
|
-
raise
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
raise 'You must pass the argument yielded to your expect block on ' \
|
68
|
+
'to the method-under-test as a block. It acts as a probe that ' \
|
69
|
+
'allows the matcher to detect whether or not the method-under-test ' \
|
70
|
+
'yields, and, if so, how many times, and what the yielded arguments ' \
|
71
|
+
'are.'
|
71
72
|
end
|
72
73
|
|
73
74
|
if RUBY_VERSION.to_f > 1.8
|
74
75
|
def assert_valid_expect_block!
|
75
76
|
block_signature = RSpec::Support::BlockSignature.new(@block)
|
76
77
|
return if RSpec::Support::StrictSignatureVerifier.new(block_signature, [self]).valid?
|
77
|
-
raise
|
78
|
-
|
78
|
+
raise 'Your expect block must accept an argument to be used with this ' \
|
79
|
+
'matcher. Pass the argument as a block on to the method you are testing.'
|
79
80
|
end
|
80
81
|
else
|
81
82
|
# :nocov:
|
@@ -190,7 +191,7 @@ module RSpec
|
|
190
191
|
end
|
191
192
|
|
192
193
|
def failure_reason
|
193
|
-
return
|
194
|
+
return ' but was not a block' unless @probe.has_block?
|
194
195
|
return '' unless @expected_yields_count
|
195
196
|
" #{human_readable_expectation_type}#{human_readable_count(@expected_yields_count)}" \
|
196
197
|
" but yielded #{human_readable_count(@probe.num_yields)}"
|
@@ -206,8 +207,8 @@ module RSpec
|
|
206
207
|
|
207
208
|
def human_readable_count(count)
|
208
209
|
case count
|
209
|
-
when 1 then
|
210
|
-
when 2 then
|
210
|
+
when 1 then 'once'
|
211
|
+
when 2 then 'twice'
|
211
212
|
else "#{count} times"
|
212
213
|
end
|
213
214
|
end
|
@@ -247,14 +248,14 @@ module RSpec
|
|
247
248
|
private
|
248
249
|
|
249
250
|
def positive_failure_reason
|
250
|
-
return
|
251
|
-
return
|
251
|
+
return 'was not a block' unless @probe.has_block?
|
252
|
+
return 'did not yield' if @probe.num_yields.zero?
|
252
253
|
"yielded with arguments: #{description_of @probe.single_yield_args}"
|
253
254
|
end
|
254
255
|
|
255
256
|
def negative_failure_reason
|
256
|
-
return
|
257
|
-
|
257
|
+
return 'was not a block' unless @probe.has_block?
|
258
|
+
'did'
|
258
259
|
end
|
259
260
|
end
|
260
261
|
|
@@ -291,7 +292,7 @@ module RSpec
|
|
291
292
|
|
292
293
|
# @private
|
293
294
|
def description
|
294
|
-
desc =
|
295
|
+
desc = 'yield with args'
|
295
296
|
desc << "(#{expected_arg_description})" unless @expected.empty?
|
296
297
|
desc
|
297
298
|
end
|
@@ -304,36 +305,36 @@ module RSpec
|
|
304
305
|
private
|
305
306
|
|
306
307
|
def positive_failure_reason
|
307
|
-
return
|
308
|
-
return
|
308
|
+
return 'was not a block' unless @probe.has_block?
|
309
|
+
return 'did not yield' if @probe.num_yields.zero?
|
309
310
|
@positive_args_failure
|
310
311
|
end
|
311
312
|
|
312
313
|
def expected_arg_description
|
313
|
-
@expected.map { |e| description_of e }.join(
|
314
|
+
@expected.map { |e| description_of e }.join(', ')
|
314
315
|
end
|
315
316
|
|
316
317
|
def negative_failure_reason
|
317
318
|
if !@probe.has_block?
|
318
|
-
|
319
|
+
'was not a block'
|
319
320
|
elsif all_args_match?
|
320
|
-
|
321
|
-
"\nexpected not: #{surface_descriptions_in(@expected).inspect}"
|
321
|
+
'yielded with expected arguments' \
|
322
|
+
"\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
|
322
323
|
"\n got: #{actual_formatted}"
|
323
324
|
else
|
324
|
-
|
325
|
+
'did'
|
325
326
|
end
|
326
327
|
end
|
327
328
|
|
328
329
|
def args_match?
|
329
330
|
if @expected.empty? # expect {...}.to yield_with_args
|
330
|
-
@positive_args_failure =
|
331
|
+
@positive_args_failure = 'yielded with no arguments' if @actual.empty?
|
331
332
|
return !@actual.empty?
|
332
333
|
end
|
333
334
|
|
334
335
|
unless (match = all_args_match?)
|
335
|
-
@positive_args_failure =
|
336
|
-
"\nexpected: #{surface_descriptions_in(@expected).inspect}"
|
336
|
+
@positive_args_failure = 'yielded with unexpected arguments' \
|
337
|
+
"\nexpected: #{surface_descriptions_in(@expected).inspect}" \
|
337
338
|
"\n got: #{actual_formatted}"
|
338
339
|
end
|
339
340
|
|
@@ -367,19 +368,19 @@ module RSpec
|
|
367
368
|
|
368
369
|
# @private
|
369
370
|
def failure_message
|
370
|
-
|
371
|
+
'expected given block to yield successively with arguments, ' \
|
372
|
+
"but #{positive_failure_reason}"
|
371
373
|
end
|
372
374
|
|
373
375
|
# @private
|
374
376
|
def failure_message_when_negated
|
375
|
-
|
377
|
+
'expected given block not to yield successively with arguments, ' \
|
378
|
+
"but #{negative_failure_reason}"
|
376
379
|
end
|
377
380
|
|
378
381
|
# @private
|
379
382
|
def description
|
380
|
-
|
381
|
-
desc << "(#{expected_arg_description})"
|
382
|
-
desc
|
383
|
+
"yield successive args(#{expected_arg_description})"
|
383
384
|
end
|
384
385
|
|
385
386
|
# @private
|
@@ -394,21 +395,21 @@ module RSpec
|
|
394
395
|
end
|
395
396
|
|
396
397
|
def expected_arg_description
|
397
|
-
@expected.map { |e| description_of e }.join(
|
398
|
+
@expected.map { |e| description_of e }.join(', ')
|
398
399
|
end
|
399
400
|
|
400
401
|
def positive_failure_reason
|
401
|
-
return
|
402
|
+
return 'was not a block' unless @probe.has_block?
|
402
403
|
|
403
|
-
|
404
|
+
'yielded with unexpected arguments' \
|
404
405
|
"\nexpected: #{surface_descriptions_in(@expected).inspect}" \
|
405
406
|
"\n got: #{actual_formatted}"
|
406
407
|
end
|
407
408
|
|
408
409
|
def negative_failure_reason
|
409
|
-
return
|
410
|
+
return 'was not a block' unless @probe.has_block?
|
410
411
|
|
411
|
-
|
412
|
+
'yielded with expected arguments' \
|
412
413
|
"\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
|
413
414
|
"\n got: #{actual_formatted}"
|
414
415
|
end
|
@@ -100,14 +100,10 @@ module RSpec
|
|
100
100
|
DescribableItem.new(item)
|
101
101
|
elsif Hash === item
|
102
102
|
Hash[surface_descriptions_in(item.to_a)]
|
103
|
-
elsif Struct === item
|
103
|
+
elsif Struct === item || unreadable_io?(item)
|
104
104
|
RSpec::Support::ObjectFormatter.format(item)
|
105
105
|
elsif should_enumerate?(item)
|
106
|
-
|
107
|
-
item.map { |subitem| surface_descriptions_in(subitem) }
|
108
|
-
rescue IOError # STDOUT is enumerable but `map` raises an error
|
109
|
-
RSpec::Support::ObjectFormatter.format(item)
|
110
|
-
end
|
106
|
+
item.map { |subitem| surface_descriptions_in(subitem) }
|
111
107
|
else
|
112
108
|
item
|
113
109
|
end
|
@@ -134,14 +130,10 @@ module RSpec
|
|
134
130
|
object.clone
|
135
131
|
elsif Hash === object
|
136
132
|
Hash[with_matchers_cloned(object.to_a)]
|
137
|
-
elsif Struct === object
|
133
|
+
elsif Struct === object || unreadable_io?(object)
|
138
134
|
object
|
139
135
|
elsif should_enumerate?(object)
|
140
|
-
|
141
|
-
object.map { |subobject| with_matchers_cloned(subobject) }
|
142
|
-
rescue IOError # STDOUT is enumerable but `map` raises an error
|
143
|
-
object
|
144
|
-
end
|
136
|
+
object.map { |subobject| with_matchers_cloned(subobject) }
|
145
137
|
else
|
146
138
|
object
|
147
139
|
end
|
@@ -157,16 +149,25 @@ module RSpec
|
|
157
149
|
# @api private
|
158
150
|
def should_enumerate?(item)
|
159
151
|
return false if String === item
|
160
|
-
Enumerable === item && !(Range === item)
|
152
|
+
Enumerable === item && !(Range === item) && item.none? { |subitem| subitem.equal?(item) }
|
161
153
|
end
|
162
154
|
# :nocov:
|
163
155
|
else
|
164
156
|
# @api private
|
165
157
|
def should_enumerate?(item)
|
166
|
-
Enumerable === item && !(Range === item)
|
158
|
+
Enumerable === item && !(Range === item) && item.none? { |subitem| subitem.equal?(item) }
|
167
159
|
end
|
168
160
|
end
|
169
|
-
|
161
|
+
|
162
|
+
# @api private
|
163
|
+
def unreadable_io?(object)
|
164
|
+
return false unless IO === object
|
165
|
+
object.each {} # STDOUT is enumerable but raises an error
|
166
|
+
false
|
167
|
+
rescue IOError
|
168
|
+
true
|
169
|
+
end
|
170
|
+
module_function :surface_descriptions_in, :should_enumerate?, :unreadable_io?
|
170
171
|
|
171
172
|
# Wraps an item in order to surface its `description` via `inspect`.
|
172
173
|
# @api private
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-expectations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steven Baker
|
@@ -45,7 +45,7 @@ cert_chain:
|
|
45
45
|
ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
|
46
46
|
F3MdtaDehhjC
|
47
47
|
-----END CERTIFICATE-----
|
48
|
-
date: 2015-
|
48
|
+
date: 2015-11-12 00:00:00.000000000 Z
|
49
49
|
dependencies:
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: rspec-support
|
@@ -53,14 +53,14 @@ dependencies:
|
|
53
53
|
requirements:
|
54
54
|
- - "~>"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: 3.
|
56
|
+
version: 3.4.0
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
59
|
version_requirements: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
61
|
- - "~>"
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 3.
|
63
|
+
version: 3.4.0
|
64
64
|
- !ruby/object:Gem::Dependency
|
65
65
|
name: diff-lcs
|
66
66
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,14 +115,14 @@ dependencies:
|
|
115
115
|
requirements:
|
116
116
|
- - "~>"
|
117
117
|
- !ruby/object:Gem::Version
|
118
|
-
version:
|
118
|
+
version: 0.6.2
|
119
119
|
type: :development
|
120
120
|
prerelease: false
|
121
121
|
version_requirements: !ruby/object:Gem::Requirement
|
122
122
|
requirements:
|
123
123
|
- - "~>"
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version:
|
125
|
+
version: 0.6.2
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: minitest
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,7 +147,7 @@ files:
|
|
147
147
|
- ".document"
|
148
148
|
- ".yardopts"
|
149
149
|
- Changelog.md
|
150
|
-
-
|
150
|
+
- LICENSE.md
|
151
151
|
- README.md
|
152
152
|
- lib/rspec/expectations.rb
|
153
153
|
- lib/rspec/expectations/configuration.rb
|
@@ -220,6 +220,6 @@ rubyforge_project:
|
|
220
220
|
rubygems_version: 2.2.2
|
221
221
|
signing_key:
|
222
222
|
specification_version: 4
|
223
|
-
summary: rspec-expectations-3.
|
223
|
+
summary: rspec-expectations-3.4.0
|
224
224
|
test_files: []
|
225
225
|
has_rdoc:
|
metadata.gz.sig
CHANGED
Binary file
|