rspec-expectations 3.8.1 → 3.12.3

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 (39) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +203 -4
  4. data/README.md +35 -20
  5. data/lib/rspec/expectations/configuration.rb +15 -0
  6. data/lib/rspec/expectations/expectation_target.rb +42 -6
  7. data/lib/rspec/expectations/failure_aggregator.rb +41 -6
  8. data/lib/rspec/expectations/handler.rb +20 -8
  9. data/lib/rspec/expectations/version.rb +1 -1
  10. data/lib/rspec/matchers/aliased_matcher.rb +3 -3
  11. data/lib/rspec/matchers/built_in/all.rb +1 -0
  12. data/lib/rspec/matchers/built_in/base_matcher.rb +5 -0
  13. data/lib/rspec/matchers/built_in/be.rb +10 -107
  14. data/lib/rspec/matchers/built_in/be_instance_of.rb +5 -1
  15. data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -1
  16. data/lib/rspec/matchers/built_in/be_within.rb +2 -2
  17. data/lib/rspec/matchers/built_in/change.rb +26 -2
  18. data/lib/rspec/matchers/built_in/compound.rb +20 -1
  19. data/lib/rspec/matchers/built_in/contain_exactly.rb +10 -2
  20. data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
  21. data/lib/rspec/matchers/built_in/exist.rb +1 -1
  22. data/lib/rspec/matchers/built_in/has.rb +88 -24
  23. data/lib/rspec/matchers/built_in/have_attributes.rb +1 -1
  24. data/lib/rspec/matchers/built_in/include.rb +82 -18
  25. data/lib/rspec/matchers/built_in/output.rb +7 -0
  26. data/lib/rspec/matchers/built_in/raise_error.rb +63 -22
  27. data/lib/rspec/matchers/built_in/respond_to.rb +53 -18
  28. data/lib/rspec/matchers/built_in/throw_symbol.rb +10 -4
  29. data/lib/rspec/matchers/built_in/yield.rb +26 -83
  30. data/lib/rspec/matchers/built_in.rb +2 -1
  31. data/lib/rspec/matchers/composable.rb +1 -1
  32. data/lib/rspec/matchers/dsl.rb +29 -11
  33. data/lib/rspec/matchers/english_phrasing.rb +1 -1
  34. data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +16 -7
  35. data/lib/rspec/matchers/matcher_protocol.rb +6 -0
  36. data/lib/rspec/matchers.rb +78 -68
  37. data.tar.gz.sig +0 -0
  38. metadata +29 -24
  39. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5737c19409b8e70dee4183a783d6d0e9c45154c6
4
- data.tar.gz: 56dbd188a758b2d09d544f5f77038c563d05f206
2
+ SHA256:
3
+ metadata.gz: d167a03fcf6e4519b628fefcf03b644e6436e1f6769058d84431fab3181e5119
4
+ data.tar.gz: dccb3d8b5ed822e523989e59e897085584173d65a503be30166b9d14bba675ef
5
5
  SHA512:
6
- metadata.gz: 1af8946afaf9d3ea6e02ac7a2af209766fd31244b87d2f8dbc210f356b72e125d5c5e5e78b6b190991ce1652158502b93eb9ec75bfcfe9da605bdb269a9639ba
7
- data.tar.gz: b0314509df480db80384b8bed96cb0d478e7518a824c502fe8828787b39b4e794afbd6fa64885ebcf36a10c22b881b824c773527a8a5a673e175230ed8a77cee
6
+ metadata.gz: dc027c3d982da4f60e13924ef494fe4df964ee64ccd405eaf69a522494e23d394d0560dfa32c2007a8f43831118ad20df6480ed5692dbe70b389dfcc724e7266
7
+ data.tar.gz: 61e1c4f7ce7514869e63d24e7eb3270861ea4ad6343c34127b04f757bd80009dd599ae94be25c925b1de265fb4dc5a68f9619b9e3293de46b4aabd0cd1595dae
checksums.yaml.gz.sig CHANGED
Binary file
data/Changelog.md CHANGED
@@ -1,3 +1,204 @@
1
+ ### Development
2
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.3...3-12-maintenance)
3
+
4
+ ### 3.12.3 / 2023-04-20
5
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.2...v3.12.3)
6
+
7
+ Bug Fixes:
8
+
9
+ * Fix `include` matcher when fuzzy matching on keys with a hash-like actual which
10
+ has a non standard `key?` method which may raise.
11
+ (Jon Rowe, #1416)
12
+
13
+ ### 3.12.2 / 2023-01-07
14
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.1...v3.12.2)
15
+
16
+ Bug Fixes:
17
+
18
+ * Prevent deprecation warning when using the `exist` matcher with `Dir`.
19
+ (Steve Dierker, #1398)
20
+
21
+ ### 3.12.1 / 2022-12-16
22
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.0...v3.12.1)
23
+
24
+ Bug Fixes:
25
+
26
+ * Pass keyword arguments through to aliased (and thus negated) matchers. (Jon Rowe, #1394)
27
+ * When handling failures in an aggregated_failures block (or example) prevent
28
+ the failure list leaking out. (Maciek Rząsa, #1392)
29
+
30
+ ### 3.12.0 / 2022-10-26
31
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.11.1...v3.12.0)
32
+
33
+ Enhancements:
34
+
35
+ * Add `an_array_matching` alias for `match_array` to improve readability as an argument
36
+ matcher. (Mark Schneider, #1361)
37
+
38
+ ### 3.11.1 / 2022-09-12
39
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.11.0...v3.11.1)
40
+
41
+ Bug Fixes:
42
+
43
+ * Allow the `contain_exactly` matcher to be reused by resetting its
44
+ internals on `matches?` (@bclayman-sq, #1326)
45
+ * Using the exist matcher on `FileTest` no longer produces a deprecation warning.
46
+ (Ryo Nakamura, #1383)
47
+
48
+ ### 3.11.0 / 2022-02-09
49
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.10.2...v3.11.0)
50
+
51
+ Enhancements:
52
+
53
+ * Return `true` from `aggregate_failures` when no exception occurs. (Jon Rowe, #1225)
54
+
55
+ Deprecations:
56
+
57
+ * Print a deprecation message when using the implicit block expectation syntax.
58
+ (Phil Pirozhkov, #1139)
59
+
60
+ ### 3.10.2 / 2022-01-14
61
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.10.1...v3.10.2)
62
+
63
+ Bug Fixes:
64
+
65
+ * Fix support for dynamic matchers for expectation target checks (Phil Pirozhkov, #1294)
66
+ * Fix `expect(array).to include(hash).times`, previously this would fail due to
67
+ matching the entire array as a single hash, rather than a member of the hash.
68
+ (Slava Kardakov, #1322)
69
+ * Ensure `raise_error` matches works with the `error_highlight` option from Ruby 3.1.
70
+ (Peter Goldstein, #1339)
71
+
72
+ ### 3.10.1 / 2020-12-27
73
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.10.0...v3.10.1)
74
+
75
+ Bug Fixes:
76
+
77
+ * Allow JRuby 9.2.x.x to generate backtraces normally rather than via our
78
+ backfill workaround. (#1230, Jon Rowe)
79
+
80
+ ### 3.10.0 / 2020-10-30
81
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.9.3...v3.10.0)
82
+
83
+ Enhancements:
84
+
85
+ * Allow `include` matcher to be chained with `once`, `at_least`, etc. for simple cases.
86
+ (Marc-André Lafortune, #1168)
87
+ * Add an explicit warning when `nil` is passed to `raise_error`. (Phil Pirozhkov, #1143)
88
+ * Improve `include` matcher's composability. (Phil Pirozhkov, #1155)
89
+ * Mocks expectations can now set a custom failure message.
90
+ (Benoit Tigeot and Nicolas Zermati, #1156)
91
+ * `aggregate_failures` now shows the backtrace line for each failure. (Fabricio Bedin, #1163)
92
+ * Support multiple combinations of `yield_control` modifiers like `at_least`, `at_most`.
93
+ (Jon Rowe, #1169)
94
+ * Dynamic `have_<n>` matchers now have output consistent with other dynamic matchers.
95
+ (Marc-André Lafortune, #1195)
96
+ * New config option `strict_predicate_matchers` allows predicate matcher to be strict
97
+ (i.e. match for `true` or `false`) instead of the default (match truthy vs `false` or `nil`).
98
+ (Marc-André Lafortune, #1196)
99
+
100
+ ### 3.9.4 / 2020-10-29
101
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.9.3...v3.9.4)
102
+
103
+ Bug Fixes:
104
+
105
+ * Fix regression with `be_` and `have_` matchers and arguments implementing `to_hash`
106
+ were they would act like keywords and be cast to a hash. (Jon Rowe, #1222)
107
+
108
+ ### 3.9.3 / 2020-10-23
109
+
110
+ Bug Fixes:
111
+
112
+ * Swap the comparison of the delta vs the expected for the `be_within` matcher allowing
113
+ more complicated oobjects to be compared providing they provide `abs` and other
114
+ comparison methods. (Kelly Stannard, #1182)
115
+ * Properly format expected in the description of the `be_within` matcher. (Jon Rowe, #1185)
116
+ * Remove warning when using keyword arguments with `be_` and `have_` matchers on 2.7.x
117
+ (Jon Rowe, #1187)
118
+ * Prevent formatting a single hash as a list of key value pairs in default failure messages
119
+ for custom matches (fixes formatting in `EnglishPhrasing#list`). (Robert Eshleman, #1193)
120
+ * Prevent errors from causing false positives when using `be <operator>` comparison, e.g.
121
+ `expect(1).not_to be < 'a'` will now correctly fail rather than pass. (Jon Rowe, #1208)
122
+
123
+
124
+ ### 3.9.2 / 2020-05-08
125
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.9.1...v3.9.2)
126
+
127
+ Bug Fixes:
128
+
129
+ * Issue a proper `ArgumentError` when invalid arguments are given to `yield_control`
130
+ modifiers such as `at_least` et al. (Marc-André Lafortune, #1167)
131
+ * Prevent Ruby 2.7 keyword arguments warning from being issued by custom
132
+ matcher definitions. (Jon Rowe, #1176)
133
+
134
+ ### 3.9.1 / 2020-03-13
135
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.9.0...v3.9.1)
136
+
137
+ Bug Fixes:
138
+
139
+ * Issue an improved warning when using `respond_to(...).with(n).arguments` and ignore
140
+ the warning when using with `have_attributes(...)`. (Jon Rowe, #1164)
141
+
142
+ ### 3.9.0 / 2019-10-08
143
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.6...v3.9.0)
144
+
145
+ Enhancements:
146
+
147
+ * The `respond_to` matcher now uses the signature from `initialize` to validate checks
148
+ for `new` (unless `new` is non standard). (Jon Rowe, #1072)
149
+ * Generated descriptions for matchers now use `is expected to` rather than `should` in
150
+ line with our preferred DSL. (Pete Johns, #1080, rspec/rspec-core#2572)
151
+ * Add the ability to re-raise expectation errors when matching
152
+ with `match_when_negated` blocks. (Jon Rowe, #1130)
153
+ * Add a warning when an empty diff is produce due to identical inspect output.
154
+ (Benoit Tigeot, #1126)
155
+
156
+ ### 3.8.6 / 2019-10-07
157
+
158
+ Bug Fixes:
159
+
160
+ * Revert #1125 due to the change being incompatible with our semantic versioning
161
+ policy.
162
+
163
+ ### 3.8.5 / 2019-10-02
164
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.4...v3.8.5)
165
+
166
+ Bug Fixes:
167
+
168
+ * Prevent unsupported implicit block expectation syntax from being used.
169
+ (Phil Pirozhkov, #1125)
170
+
171
+ ### 3.8.4 / 2019-06-10
172
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.3...v3.8.4)
173
+
174
+ Bug Fixes:
175
+
176
+ * Prevent false negatives when checking objects for the methods required to run the
177
+ the `be_an_instance_of` and `be_kind_of` matchers. (Nazar Matus, #1112)
178
+
179
+ ### 3.8.3 / 2019-04-20
180
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.2...v3.8.3)
181
+
182
+ Bug Fixes:
183
+
184
+ * Prevent composed `all` matchers from leaking into their siblings leading to duplicate
185
+ failures. (Jamie English, #1086)
186
+ * Prevent objects which change their hash on comparison from failing change checks.
187
+ (Phil Pirozhkov, #1100)
188
+ * Issue an `ArgumentError` rather than a `NoMethodError` when `be_an_instance_of` and
189
+ `be_kind_of` matchers encounter objects not supporting those methods.
190
+ (Taichi Ishitani, #1107)
191
+
192
+ ### 3.8.2 / 2018-10-09
193
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.1...v3.8.2)
194
+
195
+ Bug Fixes:
196
+
197
+ * Change `include` matcher to rely on a `respond_to?(:include?)` check rather than a direct
198
+ Hash comparison before calling `to_hash` to convert to a hash. (Jordan Owens, #1073)
199
+ * Prevent unexpected call stack jumps from causing an obscure error (`IndexError`), and
200
+ replace that error with a proper informative message. (Jon Rowe, #1076)
201
+
1
202
  ### 3.8.1 / 2018-08-06
2
203
  [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.0...v3.8.1)
3
204
 
@@ -139,10 +340,8 @@ Enhancements:
139
340
  can cause uses of `super` to trigger infinite recursion. (Myron Marston, #816)
140
341
  * Stop rescuing `NoMemoryError`, `SignalExcepetion`, `Interrupt` and
141
342
  `SystemExit`. It is dangerous to interfere with these. (Myron Marston, #845)
142
- * Add `#with_captures` to the
143
- [match matcher](https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/match-matcher)
144
- which allows a user to specify expected captures when matching a regex
145
- against a string. (Sam Phippen, #848)
343
+ * Add `#with_captures` to the match matcher which allows a user to specify expected
344
+ captures when matching a regex against a string. (Sam Phippen, #848)
146
345
  * Always print compound failure messages in the multi-line form. Trying
147
346
  to print it all on a single line didn't read very well. (Myron Marston, #859)
148
347
 
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # RSpec Expectations [![Build Status](https://secure.travis-ci.org/rspec/rspec-expectations.svg?branch=master)](http://travis-ci.org/rspec/rspec-expectations) [![Code Climate](https://codeclimate.com/github/rspec/rspec-expectations.svg)](https://codeclimate.com/github/rspec/rspec-expectations)
1
+ # RSpec Expectations [![Build Status](https://github.com/rspec/rspec-expectations/workflows/RSpec%20CI/badge.svg)](https://github.com/rspec/rspec-expectations/actions) [![Code Climate](https://codeclimate.com/github/rspec/rspec-expectations.svg)](https://codeclimate.com/github/rspec/rspec-expectations)
2
2
 
3
3
  RSpec::Expectations lets you express expected outcomes on an object in an
4
4
  example.
@@ -15,12 +15,12 @@ rspec-core and rspec-mocks):
15
15
 
16
16
  gem install rspec
17
17
 
18
- Want to run against the `master` branch? You'll need to include the dependent
18
+ Want to run against the `main` branch? You'll need to include the dependent
19
19
  RSpec repos as well. Add the following to your `Gemfile`:
20
20
 
21
21
  ```ruby
22
22
  %w[rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
23
- gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'master'
23
+ gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'main'
24
24
  end
25
25
  ```
26
26
 
@@ -175,30 +175,45 @@ expect(1..10).to cover(3)
175
175
  ### Collection membership
176
176
 
177
177
  ```ruby
178
- expect(actual).to include(expected)
178
+ # exact order, entire collection
179
+ expect(actual).to eq(expected)
180
+
181
+ # exact order, partial collection (based on an exact position)
179
182
  expect(actual).to start_with(expected)
180
183
  expect(actual).to end_with(expected)
181
184
 
182
- expect(actual).to contain_exactly(individual, items)
183
- # ...which is the same as:
184
- expect(actual).to match_array(expected_array)
185
+ # any order, entire collection
186
+ expect(actual).to match_array(expected)
187
+
188
+ # You can also express this by passing the expected elements
189
+ # as individual arguments
190
+ expect(actual).to contain_exactly(expected_element1, expected_element2)
191
+
192
+ # any order, partial collection
193
+ expect(actual).to include(expected)
185
194
  ```
186
195
 
187
196
  #### Examples
188
197
 
189
198
  ```ruby
190
- expect([1, 2, 3]).to include(1)
191
- expect([1, 2, 3]).to include(1, 2)
192
- expect([1, 2, 3]).to start_with(1)
193
- expect([1, 2, 3]).to start_with(1, 2)
194
- expect([1, 2, 3]).to end_with(3)
195
- expect([1, 2, 3]).to end_with(2, 3)
196
- expect({:a => 'b'}).to include(:a => 'b')
197
- expect("this string").to include("is str")
198
- expect("this string").to start_with("this")
199
- expect("this string").to end_with("ring")
200
- expect([1, 2, 3]).to contain_exactly(2, 3, 1)
201
- expect([1, 2, 3]).to match_array([3, 2, 1])
199
+ expect([1, 2, 3]).to eq([1, 2, 3]) # Order dependent equality check
200
+ expect([1, 2, 3]).to include(1) # Exact ordering, partial collection matches
201
+ expect([1, 2, 3]).to include(2, 3) #
202
+ expect([1, 2, 3]).to start_with(1) # As above, but from the start of the collection
203
+ expect([1, 2, 3]).to start_with(1, 2) #
204
+ expect([1, 2, 3]).to end_with(3) # As above but from the end of the collection
205
+ expect([1, 2, 3]).to end_with(2, 3) #
206
+ expect({:a => 'b'}).to include(:a => 'b') # Matching within hashes
207
+ expect("this string").to include("is str") # Matching within strings
208
+ expect("this string").to start_with("this") #
209
+ expect("this string").to end_with("ring") #
210
+ expect([1, 2, 3]).to contain_exactly(2, 3, 1) # Order independent matches
211
+ expect([1, 2, 3]).to match_array([3, 2, 1]) #
212
+
213
+ # Order dependent compound matchers
214
+ expect(
215
+ [{:a => 'hash'},{:a => 'another'}]
216
+ ).to match([a_hash_including(:a => 'hash'), a_hash_including(:a => 'another')])
202
217
  ```
203
218
 
204
219
  ## `should` syntax
@@ -212,7 +227,7 @@ actual.should be > 3
212
227
  [1, 2, 3].should_not include 4
213
228
  ```
214
229
 
215
- See [detailed information on the `should` syntax and its usage.](https://github.com/rspec/rspec-expectations/blob/master/Should.md)
230
+ See [detailed information on the `should` syntax and its usage.](https://github.com/rspec/rspec-expectations/blob/main/Should.md)
216
231
 
217
232
  ## Compound Matcher Expressions
218
233
 
@@ -28,6 +28,7 @@ module RSpec
28
28
 
29
29
  def initialize
30
30
  @on_potential_false_positives = :warn
31
+ @strict_predicate_matchers = false
31
32
  end
32
33
 
33
34
  # Configures the supported syntax.
@@ -185,6 +186,20 @@ module RSpec
185
186
  @on_potential_false_positives = behavior
186
187
  end
187
188
 
189
+ # Configures RSpec to check predicate matchers to `be(true)` / `be(false)` (strict),
190
+ # or `be_truthy` / `be_falsey` (not strict).
191
+ # Historically, the default was `false`, but `true` is recommended.
192
+ def strict_predicate_matchers=(flag)
193
+ raise ArgumentError, "Pass `true` or `false`" unless flag == true || flag == false
194
+ @strict_predicate_matchers = flag
195
+ end
196
+
197
+ attr_reader :strict_predicate_matchers
198
+
199
+ def strict_predicate_matchers?
200
+ @strict_predicate_matchers
201
+ end
202
+
188
203
  # Indicates what RSpec will do about matcher use which will
189
204
  # potentially cause false positives in tests, generally you want to
190
205
  # avoid such scenarios so this defaults to `true`.
@@ -42,7 +42,7 @@ module RSpec
42
42
  elsif block
43
43
  raise ArgumentError, "You cannot pass both an argument and a block to `expect`."
44
44
  else
45
- new(value)
45
+ ValueExpectationTarget.new(value)
46
46
  end
47
47
  end
48
48
 
@@ -57,7 +57,7 @@ module RSpec
57
57
  # expect { perform }.to raise_error
58
58
  # @param [Matcher]
59
59
  # matcher
60
- # @param [String or Proc] message optional message to display when the expectation fails
60
+ # @param [String, Proc] message optional message to display when the expectation fails
61
61
  # @return [Boolean] true if the expectation succeeds (else raises)
62
62
  # @see RSpec::Matchers
63
63
  def to(matcher=nil, message=nil, &block)
@@ -70,7 +70,7 @@ module RSpec
70
70
  # expect(value).not_to eq(5)
71
71
  # @param [Matcher]
72
72
  # matcher
73
- # @param [String or Proc] message optional message to display when the expectation fails
73
+ # @param [String, Proc] message optional message to display when the expectation fails
74
74
  # @return [Boolean] false if the negative expectation succeeds (else raises)
75
75
  # @see RSpec::Matchers
76
76
  def not_to(matcher=nil, message=nil, &block)
@@ -90,6 +90,44 @@ module RSpec
90
90
  include InstanceMethods
91
91
  end
92
92
 
93
+ # @private
94
+ # Validates the provided matcher to ensure it supports block
95
+ # expectations, in order to avoid user confusion when they
96
+ # use a block thinking the expectation will be on the return
97
+ # value of the block rather than the block itself.
98
+ class ValueExpectationTarget < ExpectationTarget
99
+ def to(matcher=nil, message=nil, &block)
100
+ enforce_value_expectation(matcher)
101
+ super
102
+ end
103
+
104
+ def not_to(matcher=nil, message=nil, &block)
105
+ enforce_value_expectation(matcher)
106
+ super
107
+ end
108
+
109
+ private
110
+
111
+ def enforce_value_expectation(matcher)
112
+ return if supports_value_expectations?(matcher)
113
+
114
+ RSpec.deprecate(
115
+ "expect(value).to #{RSpec::Support::ObjectFormatter.format(matcher)}",
116
+ :message =>
117
+ "The implicit block expectation syntax is deprecated, you should pass " \
118
+ "a block rather than an argument to `expect` to use the provided " \
119
+ "block expectation matcher or the matcher must implement " \
120
+ "`supports_value_expectations?`. e.g `expect { value }.to " \
121
+ "#{RSpec::Support::ObjectFormatter.format(matcher)}` not " \
122
+ "`expect(value).to #{RSpec::Support::ObjectFormatter.format(matcher)}`"
123
+ )
124
+ end
125
+
126
+ def supports_value_expectations?(matcher)
127
+ !matcher.respond_to?(:supports_value_expectations?) || matcher.supports_value_expectations?
128
+ end
129
+ end
130
+
93
131
  # @private
94
132
  # Validates the provided matcher to ensure it supports block
95
133
  # expectations, in order to avoid user confusion when they
@@ -118,9 +156,7 @@ module RSpec
118
156
  end
119
157
 
120
158
  def supports_block_expectations?(matcher)
121
- matcher.supports_block_expectations?
122
- rescue NoMethodError
123
- false
159
+ matcher.respond_to?(:supports_block_expectations?) && matcher.supports_block_expectations?
124
160
  end
125
161
  end
126
162
  end
@@ -4,6 +4,21 @@ module RSpec
4
4
  class FailureAggregator
5
5
  attr_reader :block_label, :metadata
6
6
 
7
+ # @private
8
+ class AggregatedFailure
9
+ # @private
10
+ MESSAGE =
11
+ 'AggregatedFailure: This method caused a failure which has been ' \
12
+ 'suppressed to be aggregated into our failure report by returning ' \
13
+ 'this value, further errors can be ignored.'
14
+
15
+ def inspect
16
+ MESSAGE
17
+ end
18
+ end
19
+
20
+ AGGREGATED_FAILURE = AggregatedFailure.new
21
+
7
22
  def aggregate
8
23
  RSpec::Support.with_failure_notifier(self) do
9
24
  begin
@@ -48,14 +63,16 @@ module RSpec
48
63
  @seen_source_ids[source_id] = true
49
64
  assign_backtrace(failure) unless failure.backtrace
50
65
  failures << failure
66
+
67
+ AGGREGATED_FAILURE
51
68
  end
52
69
 
53
70
  private
54
71
 
55
- if RSpec::Support::Ruby.jruby?
56
- # On JRuby, `caller` and `raise` produce different backtraces with regards to `.java`
57
- # stack frames. It's important that we use `raise` for JRuby to produce a backtrace
58
- # that has a continuous common section with the raised `MultipleExpectationsNotMetError`,
72
+ if RSpec::Support::Ruby.jruby? && RSpec::Support::Ruby.jruby_version < '9.2.0.0'
73
+ # On JRuby 9.1.x.x and before, `caller` and `raise` produce different backtraces with
74
+ # regards to `.java` stack frames. It's important that we use `raise` for JRuby to produce
75
+ # a backtrace that has a continuous common section with the raised `MultipleExpectationsNotMetError`,
59
76
  # so that rspec-core's truncation logic can work properly on it to list the backtrace
60
77
  # relative to the `aggregate_failures` block.
61
78
  def assign_backtrace(failure)
@@ -80,7 +97,7 @@ module RSpec
80
97
  all_errors = failures + other_errors
81
98
 
82
99
  case all_errors.size
83
- when 0 then return nil
100
+ when 0 then return true
84
101
  when 1 then RSpec::Support.notify_failure all_errors.first
85
102
  else RSpec::Support.notify_failure MultipleExpectationsNotMetError.new(self)
86
103
  end
@@ -150,11 +167,29 @@ module RSpec
150
167
  def enumerated(exceptions, index_offset)
151
168
  exceptions.each_with_index.map do |exception, index|
152
169
  index += index_offset
153
- formatted_message = yield exception
170
+ formatted_message = "#{yield exception}\n#{format_backtrace(exception.backtrace).first}"
154
171
  "#{index_label index}#{indented formatted_message, index}"
155
172
  end
156
173
  end
157
174
 
175
+ def exclusion_patterns
176
+ patterns = %w[/lib\d*/ruby/ bin/ exe/rspec /lib/bundler/ /exe/bundle:]
177
+ patterns << "org/jruby/" if RSpec::Support::Ruby.jruby?
178
+ patterns.map! { |s| Regexp.new(s.gsub('/', File::SEPARATOR)) }
179
+ end
180
+
181
+ def format_backtrace(backtrace)
182
+ backtrace.map { |l| backtrace_line(l) }.compact.tap { |filtered| filtered.concat backtrace if filtered.empty? }
183
+ end
184
+
185
+ def backtrace_line(line)
186
+ return if [Regexp.union(RSpec::CallerFilter::IGNORE_REGEX, *exclusion_patterns)].any? { |p| line =~ p }
187
+
188
+ # It changes the current path that is relative to
189
+ # system root to be relative to the project root.
190
+ line.sub(/(\A|\s)#{File.expand_path('.')}(#{File::SEPARATOR}|\s|\Z)/, '\\1.\\2'.freeze).sub(/\A([^:]+:\d+)$/, '\\1'.freeze)
191
+ end
192
+
158
193
  def enumerated_failures
159
194
  enumerated(failures, 0, &:message)
160
195
  end
@@ -44,15 +44,21 @@ module RSpec
44
44
 
45
45
  # @private
46
46
  class PositiveExpectationHandler
47
- def self.handle_matcher(actual, initial_matcher, message=nil, &block)
48
- ExpectationHelper.with_matcher(self, initial_matcher, message) do |matcher|
47
+ def self.handle_matcher(actual, initial_matcher, custom_message=nil, &block)
48
+ ExpectationHelper.with_matcher(self, initial_matcher, custom_message) do |matcher|
49
49
  return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) unless initial_matcher
50
- matcher.matches?(actual, &block) || ExpectationHelper.handle_failure(matcher, message, :failure_message)
50
+
51
+ match_result = matcher.matches?(actual, &block)
52
+ if custom_message && match_result.respond_to?(:error_generator)
53
+ match_result.error_generator.opts[:message] = custom_message
54
+ end
55
+
56
+ match_result || ExpectationHelper.handle_failure(matcher, custom_message, :failure_message)
51
57
  end
52
58
  end
53
59
 
54
60
  def self.verb
55
- "should"
61
+ 'is expected to'
56
62
  end
57
63
 
58
64
  def self.should_method
@@ -66,10 +72,16 @@ module RSpec
66
72
 
67
73
  # @private
68
74
  class NegativeExpectationHandler
69
- def self.handle_matcher(actual, initial_matcher, message=nil, &block)
70
- ExpectationHelper.with_matcher(self, initial_matcher, message) do |matcher|
75
+ def self.handle_matcher(actual, initial_matcher, custom_message=nil, &block)
76
+ ExpectationHelper.with_matcher(self, initial_matcher, custom_message) do |matcher|
71
77
  return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) unless initial_matcher
72
- does_not_match?(matcher, actual, &block) || ExpectationHelper.handle_failure(matcher, message, :failure_message_when_negated)
78
+
79
+ negated_match_result = does_not_match?(matcher, actual, &block)
80
+ if custom_message && negated_match_result.respond_to?(:error_generator)
81
+ negated_match_result.error_generator.opts[:message] = custom_message
82
+ end
83
+
84
+ negated_match_result || ExpectationHelper.handle_failure(matcher, custom_message, :failure_message_when_negated)
73
85
  end
74
86
  end
75
87
 
@@ -82,7 +94,7 @@ module RSpec
82
94
  end
83
95
 
84
96
  def self.verb
85
- "should not"
97
+ 'is expected not to'
86
98
  end
87
99
 
88
100
  def self.should_method
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Expectations
3
3
  # @private
4
4
  module Version
5
- STRING = '3.8.1'
5
+ STRING = '3.12.3'
6
6
  end
7
7
  end
8
8
  end
@@ -99,14 +99,14 @@ module RSpec
99
99
  # by going through the effort of defining a negated matcher.
100
100
  #
101
101
  # However, if the override didn't actually change anything, then we
102
- # should return the opposite failure message instead -- the overriden
102
+ # should return the opposite failure message instead -- the overridden
103
103
  # message is going to be confusing if we return it as-is, as it represents
104
104
  # the non-negated failure message for a negated match (or vice versa).
105
105
  def optimal_failure_message(same, inverted)
106
106
  if DefaultFailureMessages.has_default_failure_messages?(@base_matcher)
107
107
  base_message = @base_matcher.__send__(same)
108
- overriden = @description_block.call(base_message)
109
- return overriden if overriden != base_message
108
+ overridden = @description_block.call(base_message)
109
+ return overridden if overridden != base_message
110
110
  end
111
111
 
112
112
  @base_matcher.__send__(inverted)
@@ -73,6 +73,7 @@ module RSpec
73
73
 
74
74
  def initialize_copy(other)
75
75
  @matcher = @matcher.clone
76
+ @failed_objects = @failed_objects.clone
76
77
  super
77
78
  end
78
79
 
@@ -78,6 +78,11 @@ module RSpec
78
78
  false
79
79
  end
80
80
 
81
+ # @private
82
+ def supports_value_expectations?
83
+ true
84
+ end
85
+
81
86
  # @api private
82
87
  def expects_call_stack_jump?
83
88
  false