rspec-mocks 3.8.0 → 3.12.6
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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data/Changelog.md +170 -0
- data/README.md +9 -6
- data/lib/rspec/mocks/any_instance/chain.rb +1 -0
- data/lib/rspec/mocks/any_instance/message_chains.rb +1 -1
- data/lib/rspec/mocks/any_instance/proxy.rb +12 -3
- data/lib/rspec/mocks/any_instance/recorder.rb +6 -0
- data/lib/rspec/mocks/argument_list_matcher.rb +20 -3
- data/lib/rspec/mocks/argument_matchers.rb +2 -0
- data/lib/rspec/mocks/error_generator.rb +22 -1
- data/lib/rspec/mocks/matchers/have_received.rb +2 -2
- data/lib/rspec/mocks/matchers/receive.rb +4 -2
- data/lib/rspec/mocks/matchers/receive_message_chain.rb +2 -2
- data/lib/rspec/mocks/matchers/receive_messages.rb +1 -1
- data/lib/rspec/mocks/message_expectation.rb +86 -7
- data/lib/rspec/mocks/method_double.rb +35 -6
- data/lib/rspec/mocks/method_reference.rb +14 -2
- data/lib/rspec/mocks/minitest_integration.rb +1 -1
- data/lib/rspec/mocks/mutate_const.rb +2 -2
- data/lib/rspec/mocks/proxy.rb +50 -15
- data/lib/rspec/mocks/space.rb +1 -1
- data/lib/rspec/mocks/targets.rb +1 -1
- data/lib/rspec/mocks/verifying_double.rb +4 -10
- data/lib/rspec/mocks/verifying_message_expectation.rb +1 -0
- data/lib/rspec/mocks/verifying_proxy.rb +4 -3
- data/lib/rspec/mocks/version.rb +1 -1
- data/lib/rspec/mocks.rb +4 -1
- data.tar.gz.sig +0 -0
- metadata +23 -19
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 51d2892643ca24dce94963c553f2fdee71d55d9c3c2b2d14ba4fb2cb4ed0876a
|
4
|
+
data.tar.gz: ceb42a276b994afe0eaffe46e3a7f314393caf5ba39a5804969b955dc9f309d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d19a308278d05b7703dafc5a88ca5b897badd3e60619fce025937b2ee677e36bea53f9ff2386b4180d107ce45dc695fecb68c69e46d0a4d0ec8063126d30b5f
|
7
|
+
data.tar.gz: dd881cdd051593ef697cab19d41b760933daca59768ad12430551743936d4373c575f2cc8cfe496e955e90b3cd965d14ec1f2b097c66f63e5e35e34d720696d9
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/Changelog.md
CHANGED
@@ -1,3 +1,173 @@
|
|
1
|
+
### Development
|
2
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.12.6...3-12-maintenance)
|
3
|
+
|
4
|
+
### 3.12.6 / 2023-07-11
|
5
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.12.5...v3.12.6)
|
6
|
+
|
7
|
+
Bug Fixes:
|
8
|
+
|
9
|
+
* Fix an issue with `and_call_original` when using the `method_missing` fallback
|
10
|
+
with keyword arguments. (Igor Drozdov, #1552)
|
11
|
+
|
12
|
+
### 3.12.5 / 2023-03-30
|
13
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.12.4...v3.12.5)
|
14
|
+
|
15
|
+
Bug Fixes:
|
16
|
+
|
17
|
+
* Fix compatibility issue with Rails where active_support monkey patches `with`
|
18
|
+
when using any instance. (Lachlan Sylvester, #1540)
|
19
|
+
|
20
|
+
### 3.12.4 / 2023-03-12
|
21
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.12.3...v3.12.4)
|
22
|
+
|
23
|
+
Bug Fixes:
|
24
|
+
|
25
|
+
* Fix an issue with asserting that Array#reverse is never called. (Brad Trick, #1533)
|
26
|
+
* Fix compatibility issue with Rails where active_support monkey patches `with`.
|
27
|
+
(Jean Boussier, #1531, #1534)
|
28
|
+
|
29
|
+
### 3.12.3 / 2023-01-17
|
30
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.12.2...v3.12.3)
|
31
|
+
|
32
|
+
Bug Fixes:
|
33
|
+
|
34
|
+
* Fix keyword delegation in `send` for verifying doubles on Ruby 3.
|
35
|
+
(Charlie Honig, #1485)
|
36
|
+
|
37
|
+
### 3.12.2 / 2023-01-07
|
38
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.12.1...v3.12.2)
|
39
|
+
|
40
|
+
Bug Fixes:
|
41
|
+
|
42
|
+
* Fix implementation blocks for mocks using keyword arguments on Ruby 3.2.0.
|
43
|
+
(Adam Steel, #1508)
|
44
|
+
* Fix keyword argument assertions when mocking using `with` on Ruby 3.2.0.
|
45
|
+
(Slava Kardakov, Benoit Tigeot, Phil Pirozhkov, Benoit Daloze, #1514)
|
46
|
+
|
47
|
+
### 3.12.1 / 2022-12-10
|
48
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.12.0...v3.12.1)
|
49
|
+
|
50
|
+
Bug Fixes:
|
51
|
+
|
52
|
+
* Remove empty diff marker when a diff only contains console codes. (Jon Rowe, #1506)
|
53
|
+
* Show keyword vs hash diff marker when arguments are not `==` (Jon Rowe, #1506)
|
54
|
+
* Change check to detect frozen objects to rescue errors rather than
|
55
|
+
pre-empting by checking `frozen?` due to some objects mis-behaving.
|
56
|
+
(Keegan Roth, #1401)
|
57
|
+
* Prevent unfulfilled expectations using `expect_any_instance_of` across a class
|
58
|
+
inheritance boundary from raising rather than failing. (Jon Rowe, #1496)
|
59
|
+
* Prevent a misleading error message when using `allow(...).not_to` with
|
60
|
+
unsupported matchers. (Phil Pirozhkov, #1503)
|
61
|
+
|
62
|
+
### 3.12.0 / 2022-10-26
|
63
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.11.2...v3.12.0)
|
64
|
+
|
65
|
+
Enhancements:
|
66
|
+
|
67
|
+
* Improve diff output when diffing keyword arguments against hashes.
|
68
|
+
(Jean Boussier, #1461)
|
69
|
+
|
70
|
+
### 3.11.2 / 2022-10-25
|
71
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.11.1...v3.11.2)
|
72
|
+
|
73
|
+
Bug Fixes:
|
74
|
+
|
75
|
+
* Use the original implementation of `Class.new` to detect overridden definitions
|
76
|
+
of `new` rather than the owner, fixing detection of "double aliased" methods
|
77
|
+
in Ruby 3 and above. (Benoit Daloze, #1470, #1476)
|
78
|
+
* Support keyword argument semantics when constraining argument expectations using
|
79
|
+
`with` on Ruby 3.0+ with `instance_double` (Andrii Malyshko, #1473)
|
80
|
+
|
81
|
+
### 3.11.1 / 2022-03-31
|
82
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.11.0...v3.11.1)
|
83
|
+
|
84
|
+
Bug Fixes:
|
85
|
+
|
86
|
+
* Add extra `ruby2_keywords` calls to properly designate methods using
|
87
|
+
`*args` to pass keyword around, fixes an issue with TruffleRuby.
|
88
|
+
(Benoit Daloze, #1464)
|
89
|
+
|
90
|
+
### 3.11.0 / 2022-02-09
|
91
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.10.3...v3.11.0)
|
92
|
+
|
93
|
+
Enhancements:
|
94
|
+
|
95
|
+
* Add `and_invoke` implementation for configuring responses to `receive`
|
96
|
+
(and `receive_messages`) with multiple callable objects. (Kyle Smith, #1411)
|
97
|
+
|
98
|
+
### 3.10.3 / 2022-01-28
|
99
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.10.2...v3.10.3)
|
100
|
+
|
101
|
+
Bug Fixes:
|
102
|
+
|
103
|
+
* Suppress warning by setting `$VERBOSE` to nil. (Nobuyoshi Nakada, #1414)
|
104
|
+
* Support keyword argument semantics when constraining argument expectations using
|
105
|
+
`with` on Ruby 3.0+ (Yusuke Endoh, #1394)
|
106
|
+
|
107
|
+
### 3.10.2 / 2021-01-27
|
108
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.10.1...v3.10.2)
|
109
|
+
|
110
|
+
Bug Fixes:
|
111
|
+
|
112
|
+
* Support keyword arguments with `and_call_original` on Ruby 3.0.
|
113
|
+
(Bryan Powell, #1385)
|
114
|
+
* `RSpec::Mocks::Constant#previously_defined?` is now always a boolean.
|
115
|
+
(Phil Pirozhkov, #1397)
|
116
|
+
* Support keyword arguments on Ruby 3.0 when used with `expect_any_instance_of`
|
117
|
+
or `allow_any_instance_of` with `and_call_original`.
|
118
|
+
(Jess Hottenstein, #1407)
|
119
|
+
|
120
|
+
### 3.10.1 / 2020-12-27
|
121
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.10.0...v3.10.1)
|
122
|
+
|
123
|
+
Bug Fixes:
|
124
|
+
|
125
|
+
* Issue `ArgumentError` rather than `TypeError` when unsupported methods on
|
126
|
+
unsupported objects are attempted to be stubbed. (@zhisme, #1357)
|
127
|
+
|
128
|
+
### 3.10.0 / 2020-10-30
|
129
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.9.1...v3.10.0)
|
130
|
+
|
131
|
+
Enhancements:
|
132
|
+
* Add the ability to set a custom error generator in `MessageExpectation`.
|
133
|
+
This will allow rspec-expectations to inject a custom failure message.
|
134
|
+
(Benoit Tigeot and Nicolas Zermati, #1312)
|
135
|
+
* Return the result of the block passed to `RSpec::Mocks.with_temporary_scope`
|
136
|
+
when block run. (@expeehaa, #1329)
|
137
|
+
|
138
|
+
### 3.9.1 / 2019-12-31
|
139
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.9.0...v3.9.1)
|
140
|
+
|
141
|
+
Bug Fixes:
|
142
|
+
|
143
|
+
* Trigger `RSpec::Mocks.configuration.verifying_double_callbacks` when using
|
144
|
+
`allow_any_instance_of` or `expect_any_instance_of` (Daniel Orner, #1309)
|
145
|
+
|
146
|
+
### 3.9.0 / 2019-10-07
|
147
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.8.2...v3.9.0)
|
148
|
+
|
149
|
+
Enhancements:
|
150
|
+
|
151
|
+
* Improve thread safety of message expectations by using Mutex to prevent
|
152
|
+
deadlocking errors. (Ry Biesemeyer, #1236)
|
153
|
+
* Add the ability to use `time` as an alias for `times`. For example:
|
154
|
+
`expect(Class).to receive(:method).exactly(1).time`.
|
155
|
+
(Pistos, Benoit Tigeot, #1271)
|
156
|
+
|
157
|
+
### 3.8.2 / 2019-10-02
|
158
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.8.1...v3.8.2)
|
159
|
+
|
160
|
+
* Allow `array_including` argument matchers to be nested.
|
161
|
+
(Emmanuel Delmas, #1291)
|
162
|
+
|
163
|
+
### 3.8.1 / 2019-06-13
|
164
|
+
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.8.0...v3.8.1)
|
165
|
+
|
166
|
+
Bug Fixes:
|
167
|
+
|
168
|
+
* Ensure stubbing methods does not change their visibility.
|
169
|
+
(Kevin Boschert, #1277)
|
170
|
+
|
1
171
|
### 3.8.0 / 2018-08-04
|
2
172
|
[Full Changelog](http://github.com/rspec/rspec-mocks/compare/v3.7.0...v3.8.0)
|
3
173
|
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# RSpec Mocks [](https://github.com/rspec/rspec-mocks/actions) [](https://codeclimate.com/github/rspec/rspec-mocks)
|
2
2
|
rspec-mocks is a test-double framework for rspec with support for method stubs,
|
3
3
|
fakes, and message expectations on generated test-doubles and real objects
|
4
4
|
alike.
|
@@ -8,12 +8,12 @@ alike.
|
|
8
8
|
gem install rspec # for rspec-core, rspec-expectations, rspec-mocks
|
9
9
|
gem install rspec-mocks # for rspec-mocks only
|
10
10
|
|
11
|
-
Want to run against the `
|
11
|
+
Want to run against the `main` branch? You'll need to include the dependent
|
12
12
|
RSpec repos as well. Add the following to your `Gemfile`:
|
13
13
|
|
14
14
|
```ruby
|
15
15
|
%w[rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
|
16
|
-
gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => '
|
16
|
+
gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'main'
|
17
17
|
end
|
18
18
|
```
|
19
19
|
## Contributing
|
@@ -53,7 +53,7 @@ book = instance_double("Book", :pages => 250)
|
|
53
53
|
Verifying doubles have some clever tricks to enable you to both test in
|
54
54
|
isolation without your dependencies loaded while still being able to validate
|
55
55
|
them against real objects. More detail is available in [their
|
56
|
-
documentation](https://github.com/rspec/rspec-mocks/blob/
|
56
|
+
documentation](https://github.com/rspec/rspec-mocks/blob/main/features/verifying_doubles).
|
57
57
|
|
58
58
|
Verifying doubles can also accept custom identifiers, just like double(), e.g.:
|
59
59
|
|
@@ -285,12 +285,15 @@ expect(double).to receive(:msg).with(hash_excluding(:a => 5)) # first arg is a h
|
|
285
285
|
```ruby
|
286
286
|
expect(double).to receive(:msg).once
|
287
287
|
expect(double).to receive(:msg).twice
|
288
|
+
expect(double).to receive(:msg).exactly(n).time
|
288
289
|
expect(double).to receive(:msg).exactly(n).times
|
289
290
|
expect(double).to receive(:msg).at_least(:once)
|
290
291
|
expect(double).to receive(:msg).at_least(:twice)
|
292
|
+
expect(double).to receive(:msg).at_least(n).time
|
291
293
|
expect(double).to receive(:msg).at_least(n).times
|
292
294
|
expect(double).to receive(:msg).at_most(:once)
|
293
295
|
expect(double).to receive(:msg).at_most(:twice)
|
296
|
+
expect(double).to receive(:msg).at_most(n).time
|
294
297
|
expect(double).to receive(:msg).at_most(n).times
|
295
298
|
```
|
296
299
|
|
@@ -327,7 +330,7 @@ expect(double).to receive(:msg).and_return(value)
|
|
327
330
|
expect(double).to receive(:msg).exactly(3).times.and_return(value1, value2, value3)
|
328
331
|
# returns value1 the first time, value2 the second, etc
|
329
332
|
expect(double).to receive(:msg).and_raise(error)
|
330
|
-
# error can be an instantiated object or a class
|
333
|
+
# `error` can be an instantiated object (e.g. `StandardError.new(some_arg)`) or a class (e.g. `StandardError`)
|
331
334
|
# if it is a class, it must be instantiable with no args
|
332
335
|
expect(double).to receive(:msg).and_throw(:msg)
|
333
336
|
expect(double).to receive(:msg).and_yield(values, to, yield)
|
@@ -400,7 +403,7 @@ your code.
|
|
400
403
|
## Stubbing and Hiding Constants
|
401
404
|
|
402
405
|
See the [mutating constants
|
403
|
-
README](https://github.com/rspec/rspec-mocks/blob/
|
406
|
+
README](https://github.com/rspec/rspec-mocks/blob/main/features/mutating_constants/README.md)
|
404
407
|
for info on this feature.
|
405
408
|
|
406
409
|
## Use `before(:example)`, not `before(:context)`
|
@@ -49,7 +49,7 @@ module RSpec
|
|
49
49
|
# @private
|
50
50
|
def unfulfilled_expectations
|
51
51
|
@chains_by_method_name.map do |method_name, chains|
|
52
|
-
method_name.to_s if ExpectationChain === chains.last
|
52
|
+
method_name.to_s if ExpectationChain === chains.last && !chains.last.expectation_fulfilled?
|
53
53
|
end.compact
|
54
54
|
end
|
55
55
|
|
@@ -10,7 +10,7 @@ module RSpec
|
|
10
10
|
#
|
11
11
|
# This proxy sits in front of the recorder and delegates both to it
|
12
12
|
# and to the `RSpec::Mocks::Proxy` for each already mocked or stubbed
|
13
|
-
# instance of the class, in order to
|
13
|
+
# instance of the class, in order to propagates changes to the instances.
|
14
14
|
#
|
15
15
|
# Note that unlike `RSpec::Mocks::Proxy`, this proxy class is stateless
|
16
16
|
# and is not persisted in `RSpec::Mocks.space`.
|
@@ -83,6 +83,15 @@ module RSpec
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
unless defined?(BasicObject)
|
87
|
+
class BasicObject
|
88
|
+
# Remove all methods except those expected to be defined on BasicObject
|
89
|
+
(instance_methods.map(&:to_sym) - [:__send__, :"!", :instance_eval, :==, :instance_exec, :"!=", :equal?, :__id__, :__binding__, :object_id]).each do |method|
|
90
|
+
undef_method method
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
86
95
|
# @private
|
87
96
|
# Delegates messages to each of the given targets in order to
|
88
97
|
# provide the fluent interface that is available off of message
|
@@ -91,12 +100,12 @@ module RSpec
|
|
91
100
|
# `targets` will typically contain 1 of the `AnyInstance::Recorder`
|
92
101
|
# return values and N `MessageExpectation` instances (one per instance
|
93
102
|
# of the `any_instance` klass).
|
94
|
-
class FluentInterfaceProxy
|
103
|
+
class FluentInterfaceProxy < BasicObject
|
95
104
|
def initialize(targets)
|
96
105
|
@targets = targets
|
97
106
|
end
|
98
107
|
|
99
|
-
if RUBY_VERSION.to_f > 1.8
|
108
|
+
if ::RUBY_VERSION.to_f > 1.8
|
100
109
|
def respond_to_missing?(method_name, include_private=false)
|
101
110
|
super || @targets.first.respond_to?(method_name, include_private)
|
102
111
|
end
|
@@ -21,6 +21,11 @@ module RSpec
|
|
21
21
|
@backed_up_method_owner = {}
|
22
22
|
@klass = klass
|
23
23
|
@expectation_set = false
|
24
|
+
|
25
|
+
return unless RSpec::Mocks.configuration.verify_partial_doubles?
|
26
|
+
RSpec::Mocks.configuration.verifying_double_callbacks.each do |block|
|
27
|
+
block.call(ObjectReference.for(klass))
|
28
|
+
end
|
24
29
|
end
|
25
30
|
|
26
31
|
# Initializes the recording a stub to be played back against any
|
@@ -256,6 +261,7 @@ module RSpec
|
|
256
261
|
recorder.playback!(self, method_name)
|
257
262
|
__send__(method_name, *args, &blk)
|
258
263
|
end
|
264
|
+
@klass.__send__(:ruby2_keywords, method_name) if @klass.respond_to?(:ruby2_keywords, true)
|
259
265
|
end
|
260
266
|
|
261
267
|
def mark_invoked!(method_name)
|
@@ -46,17 +46,34 @@ module RSpec
|
|
46
46
|
@expected_args = expected_args
|
47
47
|
ensure_expected_args_valid!
|
48
48
|
end
|
49
|
+
ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
|
49
50
|
|
50
51
|
# @api public
|
51
|
-
# @param [Array]
|
52
|
+
# @param [Array] actual_args
|
52
53
|
#
|
53
54
|
# Matches each element in the `expected_args` against the element in the same
|
54
55
|
# position of the arguments passed to `new`.
|
55
56
|
#
|
56
57
|
# @see #initialize
|
57
|
-
def args_match?(*
|
58
|
-
|
58
|
+
def args_match?(*actual_args)
|
59
|
+
expected_args = resolve_expected_args_based_on(actual_args)
|
60
|
+
|
61
|
+
return false if expected_args.size != actual_args.size
|
62
|
+
|
63
|
+
if RUBY_VERSION >= "3"
|
64
|
+
# If the expectation was set with keywords, while the actual method was called with a positional hash argument, they don't match.
|
65
|
+
# If the expectation was set without keywords, e.g., with({a: 1}), then it fine to call it with either foo(a: 1) or foo({a: 1}).
|
66
|
+
# This corresponds to Ruby semantics, as if the method was def foo(options).
|
67
|
+
if Hash === expected_args.last && Hash === actual_args.last
|
68
|
+
if !Hash.ruby2_keywords_hash?(actual_args.last) && Hash.ruby2_keywords_hash?(expected_args.last)
|
69
|
+
return false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Support::FuzzyMatcher.values_match?(expected_args, actual_args)
|
59
75
|
end
|
76
|
+
ruby2_keywords :args_match? if respond_to?(:ruby2_keywords, true)
|
60
77
|
|
61
78
|
# @private
|
62
79
|
# Resolves abstract arg placeholders like `no_args` and `any_args` into
|
@@ -268,11 +268,32 @@ module RSpec
|
|
268
268
|
def error_message(expectation, args_for_multiple_calls)
|
269
269
|
expected_args = format_args(expectation.expected_args)
|
270
270
|
actual_args = format_received_args(args_for_multiple_calls)
|
271
|
+
|
272
|
+
if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash?
|
273
|
+
expected_hash = expectation.expected_args.last
|
274
|
+
actual_hash = args_for_multiple_calls.last.last
|
275
|
+
if Hash === expected_hash && Hash === actual_hash &&
|
276
|
+
(Hash.ruby2_keywords_hash?(expected_hash) != Hash.ruby2_keywords_hash?(actual_hash))
|
277
|
+
|
278
|
+
actual_description = Hash.ruby2_keywords_hash?(actual_hash) ? " (keyword arguments)" : " (options hash)"
|
279
|
+
expected_description = Hash.ruby2_keywords_hash?(expected_hash) ? " (keyword arguments)" : " (options hash)"
|
280
|
+
|
281
|
+
if actual_description != expected_description
|
282
|
+
actual_args += actual_description
|
283
|
+
expected_args += expected_description
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
271
288
|
message = default_error_message(expectation, expected_args, actual_args)
|
272
289
|
|
273
290
|
if args_for_multiple_calls.one?
|
274
291
|
diff = diff_message(expectation.expected_args, args_for_multiple_calls.first)
|
275
|
-
|
292
|
+
if RSpec::Mocks.configuration.color?
|
293
|
+
message << "\nDiff:#{diff}" unless diff.gsub(/\e\[\d+m/, '').strip.empty?
|
294
|
+
else
|
295
|
+
message << "\nDiff:#{diff}" unless diff.strip.empty?
|
296
|
+
end
|
276
297
|
end
|
277
298
|
|
278
299
|
message
|
@@ -5,7 +5,7 @@ module RSpec
|
|
5
5
|
class HaveReceived
|
6
6
|
include Matcher
|
7
7
|
|
8
|
-
COUNT_CONSTRAINTS = %w[exactly at_least at_most times once twice thrice]
|
8
|
+
COUNT_CONSTRAINTS = %w[exactly at_least at_most times time once twice thrice]
|
9
9
|
ARGS_CONSTRAINTS = %w[with]
|
10
10
|
CONSTRAINTS = COUNT_CONSTRAINTS + ARGS_CONSTRAINTS + %w[ordered]
|
11
11
|
|
@@ -16,7 +16,7 @@ module RSpec
|
|
16
16
|
@subject = nil
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
19
|
+
def matcher_name
|
20
20
|
"have_received"
|
21
21
|
end
|
22
22
|
|
@@ -13,7 +13,7 @@ module RSpec
|
|
13
13
|
@recorded_customizations = []
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def matcher_name
|
17
17
|
"receive"
|
18
18
|
end
|
19
19
|
|
@@ -55,13 +55,15 @@ module RSpec
|
|
55
55
|
setup_any_instance_method_substitute(subject, :stub, block)
|
56
56
|
end
|
57
57
|
|
58
|
+
own_methods = (instance_methods - superclass.instance_methods)
|
58
59
|
MessageExpectation.public_instance_methods(false).each do |method|
|
59
|
-
next if
|
60
|
+
next if own_methods.include?(method)
|
60
61
|
|
61
62
|
define_method(method) do |*args, &block|
|
62
63
|
@recorded_customizations << ExpectationCustomization.new(method, args, block)
|
63
64
|
self
|
64
65
|
end
|
66
|
+
ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
|
65
67
|
end
|
66
68
|
|
67
69
|
private
|
@@ -13,14 +13,14 @@ module RSpec
|
|
13
13
|
@recorded_customizations = []
|
14
14
|
end
|
15
15
|
|
16
|
-
[:with, :and_return, :and_throw, :and_raise, :and_yield, :and_call_original].each do |msg|
|
16
|
+
[:with, :and_return, :and_invoke, :and_throw, :and_raise, :and_yield, :and_call_original].each do |msg|
|
17
17
|
define_method(msg) do |*args, &block|
|
18
18
|
@recorded_customizations << ExpectationCustomization.new(msg, args, block)
|
19
19
|
self
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
23
|
+
def matcher_name
|
24
24
|
"receive_message_chain"
|
25
25
|
end
|
26
26
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
RSpec::Support.require_rspec_support 'mutex'
|
2
|
+
|
1
3
|
module RSpec
|
2
4
|
module Mocks
|
3
5
|
# A message expectation that only allows concrete return values to be set
|
@@ -51,7 +53,7 @@ module RSpec
|
|
51
53
|
# etc.
|
52
54
|
#
|
53
55
|
# If the message is received more times than there are values, the last
|
54
|
-
# value is
|
56
|
+
# value is returned for every subsequent call.
|
55
57
|
#
|
56
58
|
# @return [nil] No further chaining is supported after this.
|
57
59
|
# @example
|
@@ -83,6 +85,48 @@ module RSpec
|
|
83
85
|
nil
|
84
86
|
end
|
85
87
|
|
88
|
+
# Tells the object to invoke a Proc when it receives the message. Given
|
89
|
+
# more than one value, the result of the first Proc is returned the first
|
90
|
+
# time the message is received, the result of the second Proc is returned
|
91
|
+
# the next time, etc, etc.
|
92
|
+
#
|
93
|
+
# If the message is received more times than there are Procs, the result of
|
94
|
+
# the last Proc is returned for every subsequent call.
|
95
|
+
#
|
96
|
+
# @return [nil] No further chaining is supported after this.
|
97
|
+
# @example
|
98
|
+
# allow(api).to receive(:get_foo).and_invoke(-> { raise ApiTimeout })
|
99
|
+
# api.get_foo # => raises ApiTimeout
|
100
|
+
# api.get_foo # => raises ApiTimeout
|
101
|
+
#
|
102
|
+
# allow(api).to receive(:get_foo).and_invoke(-> { raise ApiTimeout }, -> { raise ApiTimeout }, -> { :a_foo })
|
103
|
+
# api.get_foo # => raises ApiTimeout
|
104
|
+
# api.get_foo # => rasies ApiTimeout
|
105
|
+
# api.get_foo # => :a_foo
|
106
|
+
# api.get_foo # => :a_foo
|
107
|
+
# api.get_foo # => :a_foo
|
108
|
+
# # etc
|
109
|
+
def and_invoke(first_proc, *procs)
|
110
|
+
raise_already_invoked_error_if_necessary(__method__)
|
111
|
+
if negative?
|
112
|
+
raise "`and_invoke` is not supported with negative message expectations"
|
113
|
+
end
|
114
|
+
|
115
|
+
if block_given?
|
116
|
+
raise ArgumentError, "Implementation blocks aren't supported with `and_invoke`"
|
117
|
+
end
|
118
|
+
|
119
|
+
procs.unshift(first_proc)
|
120
|
+
if procs.any? { |p| !p.respond_to?(:call) }
|
121
|
+
raise ArgumentError, "Arguments to `and_invoke` must be callable."
|
122
|
+
end
|
123
|
+
|
124
|
+
@expected_received_count = [@expected_received_count, procs.size].max unless ignoring_args? || (@expected_received_count == 0 && @at_least)
|
125
|
+
self.terminal_implementation_action = AndInvokeImplementation.new(procs)
|
126
|
+
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
|
86
130
|
# Tells the object to delegate to the original unmodified method
|
87
131
|
# when it receives the message.
|
88
132
|
#
|
@@ -95,9 +139,12 @@ module RSpec
|
|
95
139
|
# counter.increment
|
96
140
|
# expect(counter.count).to eq(original_count + 1)
|
97
141
|
def and_call_original
|
98
|
-
|
99
|
-
original.call(*args, &
|
142
|
+
block = lambda do |original, *args, &b|
|
143
|
+
original.call(*args, &b)
|
100
144
|
end
|
145
|
+
block = block.ruby2_keywords if block.respond_to?(:ruby2_keywords)
|
146
|
+
|
147
|
+
wrap_original(__method__, &block)
|
101
148
|
end
|
102
149
|
|
103
150
|
# Decorates the stubbed method with the supplied block. The original
|
@@ -236,6 +283,7 @@ module RSpec
|
|
236
283
|
self.inner_implementation_action = block
|
237
284
|
self
|
238
285
|
end
|
286
|
+
alias time times
|
239
287
|
|
240
288
|
# Expect a message not to be received at all.
|
241
289
|
#
|
@@ -319,6 +367,7 @@ module RSpec
|
|
319
367
|
@argument_list_matcher = ArgumentListMatcher.new(*args)
|
320
368
|
self
|
321
369
|
end
|
370
|
+
ruby2_keywords(:with) if respond_to?(:ruby2_keywords, true)
|
322
371
|
|
323
372
|
# Expect messages to be received in a specific order.
|
324
373
|
#
|
@@ -362,7 +411,7 @@ module RSpec
|
|
362
411
|
attr_reader :message
|
363
412
|
attr_reader :orig_object
|
364
413
|
attr_writer :expected_received_count, :expected_from, :argument_list_matcher
|
365
|
-
protected :expected_received_count=, :expected_from=, :error_generator
|
414
|
+
protected :expected_received_count=, :expected_from=, :error_generator=, :implementation=
|
366
415
|
|
367
416
|
# @private
|
368
417
|
attr_reader :type
|
@@ -372,12 +421,13 @@ module RSpec
|
|
372
421
|
type=:expectation, opts={}, &implementation_block)
|
373
422
|
@type = type
|
374
423
|
@error_generator = error_generator
|
375
|
-
@error_generator.opts = opts
|
424
|
+
@error_generator.opts = error_generator.opts.merge(opts)
|
376
425
|
@expected_from = expected_from
|
377
426
|
@method_double = method_double
|
378
427
|
@orig_object = @method_double.object
|
379
428
|
@message = @method_double.method_name
|
380
429
|
@actual_received_count = 0
|
430
|
+
@actual_received_count_write_mutex = Support::Mutex.new
|
381
431
|
@expected_received_count = type == :expectation ? 1 : :any
|
382
432
|
@argument_list_matcher = ArgumentListMatcher::MATCH_ALL
|
383
433
|
@order_group = expectation_ordering
|
@@ -413,18 +463,22 @@ module RSpec
|
|
413
463
|
def matches?(message, *args)
|
414
464
|
@message == message && @argument_list_matcher.args_match?(*args)
|
415
465
|
end
|
466
|
+
ruby2_keywords :matches? if respond_to?(:ruby2_keywords, true)
|
416
467
|
|
417
468
|
def safe_invoke(parent_stub, *args, &block)
|
418
469
|
invoke_incrementing_actual_calls_by(1, false, parent_stub, *args, &block)
|
419
470
|
end
|
471
|
+
ruby2_keywords :safe_invoke if respond_to?(:ruby2_keywords, true)
|
420
472
|
|
421
473
|
def invoke(parent_stub, *args, &block)
|
422
474
|
invoke_incrementing_actual_calls_by(1, true, parent_stub, *args, &block)
|
423
475
|
end
|
476
|
+
ruby2_keywords :invoke if respond_to?(:ruby2_keywords, true)
|
424
477
|
|
425
478
|
def invoke_without_incrementing_received_count(parent_stub, *args, &block)
|
426
479
|
invoke_incrementing_actual_calls_by(0, true, parent_stub, *args, &block)
|
427
480
|
end
|
481
|
+
ruby2_keywords :invoke_without_incrementing_received_count if respond_to?(:ruby2_keywords, true)
|
428
482
|
|
429
483
|
def negative?
|
430
484
|
@expected_received_count == 0 && !@at_least
|
@@ -536,7 +590,9 @@ module RSpec
|
|
536
590
|
end
|
537
591
|
|
538
592
|
def increase_actual_received_count!
|
539
|
-
@
|
593
|
+
@actual_received_count_write_mutex.synchronize do
|
594
|
+
@actual_received_count += 1
|
595
|
+
end
|
540
596
|
end
|
541
597
|
|
542
598
|
private
|
@@ -567,8 +623,11 @@ module RSpec
|
|
567
623
|
parent_stub.invoke(nil, *args, &block)
|
568
624
|
end
|
569
625
|
ensure
|
570
|
-
@
|
626
|
+
@actual_received_count_write_mutex.synchronize do
|
627
|
+
@actual_received_count += increment
|
628
|
+
end
|
571
629
|
end
|
630
|
+
ruby2_keywords :invoke_incrementing_actual_calls_by if respond_to?(:ruby2_keywords, true)
|
572
631
|
|
573
632
|
def has_been_invoked?
|
574
633
|
@actual_received_count > 0
|
@@ -673,6 +732,24 @@ module RSpec
|
|
673
732
|
end
|
674
733
|
end
|
675
734
|
|
735
|
+
# Handles the implementation of an `and_invoke` implementation.
|
736
|
+
# @private
|
737
|
+
class AndInvokeImplementation
|
738
|
+
def initialize(procs_to_invoke)
|
739
|
+
@procs_to_invoke = procs_to_invoke
|
740
|
+
end
|
741
|
+
|
742
|
+
def call(*args, &block)
|
743
|
+
proc = if @procs_to_invoke.size > 1
|
744
|
+
@procs_to_invoke.shift
|
745
|
+
else
|
746
|
+
@procs_to_invoke.first
|
747
|
+
end
|
748
|
+
|
749
|
+
proc.call(*args, &block)
|
750
|
+
end
|
751
|
+
end
|
752
|
+
|
676
753
|
# Represents a configured implementation. Takes into account
|
677
754
|
# any number of sub-implementations.
|
678
755
|
# @private
|
@@ -684,6 +761,7 @@ module RSpec
|
|
684
761
|
action.call(*args, &block)
|
685
762
|
end.last
|
686
763
|
end
|
764
|
+
ruby2_keywords :call if respond_to?(:ruby2_keywords, true)
|
687
765
|
|
688
766
|
def present?
|
689
767
|
actions.any?
|
@@ -729,6 +807,7 @@ module RSpec
|
|
729
807
|
def call(*args, &block)
|
730
808
|
@block.call(@method, *args, &block)
|
731
809
|
end
|
810
|
+
ruby2_keywords :call if respond_to?(:ruby2_keywords, true)
|
732
811
|
|
733
812
|
private
|
734
813
|
|
@@ -2,6 +2,9 @@ module RSpec
|
|
2
2
|
module Mocks
|
3
3
|
# @private
|
4
4
|
class MethodDouble
|
5
|
+
# @private TODO: drop in favor of FrozenError in ruby 2.5+
|
6
|
+
FROZEN_ERROR_MSG = /can't modify frozen/
|
7
|
+
|
5
8
|
# @private
|
6
9
|
attr_reader :method_name, :object, :expectations, :stubs, :method_stasher
|
7
10
|
|
@@ -23,10 +26,7 @@ module RSpec
|
|
23
26
|
# handler of the object. This accounts for cases where the user has not
|
24
27
|
# correctly defined `respond_to?`, and also 1.8 which does not provide
|
25
28
|
# method handles for missing methods even if `respond_to?` is correct.
|
26
|
-
@original_implementation_callable ||= original_method ||
|
27
|
-
Proc.new do |*args, &block|
|
28
|
-
@object.__send__(:method_missing, @method_name, *args, &block)
|
29
|
-
end
|
29
|
+
@original_implementation_callable ||= original_method || method_missing_block
|
30
30
|
end
|
31
31
|
|
32
32
|
alias_method :save_original_implementation_callable!, :original_implementation_callable
|
@@ -37,6 +37,16 @@ module RSpec
|
|
37
37
|
@proxy.original_method_handle_for(method_name)
|
38
38
|
end
|
39
39
|
|
40
|
+
# @private
|
41
|
+
def method_missing_block
|
42
|
+
block = Proc.new do |*args, &b|
|
43
|
+
@object.__send__(:method_missing, @method_name, *args, &b)
|
44
|
+
end
|
45
|
+
block.ruby2_keywords if block.respond_to?(:ruby2_keywords)
|
46
|
+
|
47
|
+
block
|
48
|
+
end
|
49
|
+
|
40
50
|
# @private
|
41
51
|
def visibility
|
42
52
|
@proxy.visibility_for(@method_name)
|
@@ -59,14 +69,25 @@ module RSpec
|
|
59
69
|
return if @method_is_proxied
|
60
70
|
|
61
71
|
save_original_implementation_callable!
|
62
|
-
definition_target.class_exec(self, method_name, visibility) do |method_double, method_name, visibility|
|
72
|
+
definition_target.class_exec(self, method_name, @original_visibility || visibility) do |method_double, method_name, visibility|
|
63
73
|
define_method(method_name) do |*args, &block|
|
64
74
|
method_double.proxy_method_invoked(self, *args, &block)
|
65
75
|
end
|
76
|
+
# This can't be `if respond_to?(:ruby2_keywords, true)`,
|
77
|
+
# see https://github.com/rspec/rspec-mocks/pull/1385#issuecomment-755340298
|
78
|
+
ruby2_keywords(method_name) if Module.private_method_defined?(:ruby2_keywords)
|
66
79
|
__send__(visibility, method_name)
|
67
80
|
end
|
68
81
|
|
69
82
|
@method_is_proxied = true
|
83
|
+
rescue RuntimeError, TypeError => e
|
84
|
+
# TODO: drop in favor of FrozenError in ruby 2.5+
|
85
|
+
# RuntimeError (and FrozenError) for ruby 2.x
|
86
|
+
# TypeError for ruby 1.x
|
87
|
+
if (defined?(FrozenError) && e.is_a?(FrozenError)) || FROZEN_ERROR_MSG === e.message
|
88
|
+
raise ArgumentError, "Cannot proxy frozen objects, rspec-mocks relies on proxies for method stubbing and expectations."
|
89
|
+
end
|
90
|
+
raise
|
70
91
|
end
|
71
92
|
|
72
93
|
# The implementation of the proxied method. Subclasses may override this
|
@@ -76,10 +97,10 @@ module RSpec
|
|
76
97
|
def proxy_method_invoked(_obj, *args, &block)
|
77
98
|
@proxy.message_received method_name, *args, &block
|
78
99
|
end
|
100
|
+
ruby2_keywords :proxy_method_invoked if respond_to?(:ruby2_keywords, true)
|
79
101
|
|
80
102
|
# @private
|
81
103
|
def restore_original_method
|
82
|
-
return show_frozen_warning if object_singleton_class.frozen?
|
83
104
|
return unless @method_is_proxied
|
84
105
|
|
85
106
|
remove_method_from_definition_target
|
@@ -87,6 +108,14 @@ module RSpec
|
|
87
108
|
restore_original_visibility
|
88
109
|
|
89
110
|
@method_is_proxied = false
|
111
|
+
rescue RuntimeError, TypeError => e
|
112
|
+
# TODO: drop in favor of FrozenError in ruby 2.5+
|
113
|
+
# RuntimeError (and FrozenError) for ruby 2.x
|
114
|
+
# TypeError for ruby 1.x
|
115
|
+
if (defined?(FrozenError) && e.is_a?(FrozenError)) || FROZEN_ERROR_MSG === e.message
|
116
|
+
return show_frozen_warning
|
117
|
+
end
|
118
|
+
raise
|
90
119
|
end
|
91
120
|
|
92
121
|
# @private
|
@@ -185,11 +185,23 @@ module RSpec
|
|
185
185
|
def self.applies_to?(method_name)
|
186
186
|
return false unless method_name == :new
|
187
187
|
klass = yield
|
188
|
-
return false unless klass.respond_to?(:new, true)
|
188
|
+
return false unless ::Class === klass && klass.respond_to?(:new, true)
|
189
189
|
|
190
190
|
# We only want to apply our special logic to normal `new` methods.
|
191
191
|
# Methods that the user has monkeyed with should be left as-is.
|
192
|
-
|
192
|
+
uses_class_new?(klass)
|
193
|
+
end
|
194
|
+
|
195
|
+
if RUBY_VERSION.to_i >= 3
|
196
|
+
CLASS_NEW = ::Class.instance_method(:new)
|
197
|
+
|
198
|
+
def self.uses_class_new?(klass)
|
199
|
+
::RSpec::Support.method_handle_for(klass, :new) == CLASS_NEW.bind(klass)
|
200
|
+
end
|
201
|
+
else # Ruby 2's Method#== is too strict
|
202
|
+
def self.uses_class_new?(klass)
|
203
|
+
::RSpec::Support.method_handle_for(klass, :new).owner == ::Class
|
204
|
+
end
|
193
205
|
end
|
194
206
|
|
195
207
|
def with_signature
|
@@ -37,7 +37,7 @@ if defined?(::Minitest::Expectation)
|
|
37
37
|
# not want to here (or else we would interfere with rspec-expectations' definition).
|
38
38
|
else
|
39
39
|
# ...otherwise, define those methods now. If `rspec/expectations/minitest_integration`
|
40
|
-
# is loaded after this file, it'll
|
40
|
+
# is loaded after this file, it'll override the definition here.
|
41
41
|
Minitest::Expectation.class_eval do
|
42
42
|
include RSpec::Mocks::ExpectationTargetMethods
|
43
43
|
|
@@ -66,7 +66,7 @@ module RSpec
|
|
66
66
|
|
67
67
|
# @private
|
68
68
|
def self.unmutated(name)
|
69
|
-
previously_defined = recursive_const_defined?(name)
|
69
|
+
previously_defined = !!recursive_const_defined?(name)
|
70
70
|
rescue NameError
|
71
71
|
new(name) do |c|
|
72
72
|
c.valid_name = false
|
@@ -81,7 +81,7 @@ module RSpec
|
|
81
81
|
# Queries rspec-mocks to find out information about the named constant.
|
82
82
|
#
|
83
83
|
# @param [String] name the name of the constant
|
84
|
-
# @return [Constant] an object
|
84
|
+
# @return [Constant] an object containing information about the named
|
85
85
|
# constant.
|
86
86
|
def self.original(name)
|
87
87
|
mutator = ::RSpec::Mocks.space.constant_mutator_for(name)
|
data/lib/rspec/mocks/proxy.rb
CHANGED
@@ -9,6 +9,11 @@ module RSpec
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
unless defined?(Mutex)
|
13
|
+
Support.require_rspec_support 'mutex'
|
14
|
+
Mutex = Support::Mutex
|
15
|
+
end
|
16
|
+
|
12
17
|
# @private
|
13
18
|
def ensure_implemented(*_args)
|
14
19
|
# noop for basic proxies, see VerifyingProxy for behaviour.
|
@@ -16,15 +21,26 @@ module RSpec
|
|
16
21
|
|
17
22
|
# @private
|
18
23
|
def initialize(object, order_group, options={})
|
24
|
+
ensure_can_be_proxied!(object)
|
25
|
+
|
19
26
|
@object = object
|
20
27
|
@order_group = order_group
|
21
28
|
@error_generator = ErrorGenerator.new(object)
|
22
29
|
@messages_received = []
|
30
|
+
@messages_received_mutex = Mutex.new
|
23
31
|
@options = options
|
24
32
|
@null_object = false
|
25
33
|
@method_doubles = Hash.new { |h, k| h[k] = MethodDouble.new(@object, k, self) }
|
26
34
|
end
|
27
35
|
|
36
|
+
# @private
|
37
|
+
def ensure_can_be_proxied!(object)
|
38
|
+
return unless object.is_a?(Symbol)
|
39
|
+
|
40
|
+
msg = "Cannot proxy frozen objects. Symbols such as #{object} cannot be mocked or stubbed."
|
41
|
+
raise ArgumentError, msg
|
42
|
+
end
|
43
|
+
|
28
44
|
# @private
|
29
45
|
attr_reader :object
|
30
46
|
|
@@ -90,27 +106,31 @@ module RSpec
|
|
90
106
|
@error_generator.raise_expectation_on_unstubbed_method(expected_method_name)
|
91
107
|
end
|
92
108
|
|
93
|
-
@
|
94
|
-
|
109
|
+
@messages_received_mutex.synchronize do
|
110
|
+
@messages_received.each do |(actual_method_name, args, received_block)|
|
111
|
+
next unless expectation.matches?(actual_method_name, *args)
|
95
112
|
|
96
|
-
|
97
|
-
|
113
|
+
expectation.safe_invoke(nil)
|
114
|
+
block.call(*args, &received_block) if block
|
115
|
+
end
|
98
116
|
end
|
99
117
|
end
|
100
118
|
|
101
119
|
# @private
|
102
120
|
def check_for_unexpected_arguments(expectation)
|
103
|
-
|
121
|
+
@messages_received_mutex.synchronize do
|
122
|
+
return if @messages_received.empty?
|
104
123
|
|
105
|
-
|
124
|
+
return if @messages_received.any? { |method_name, args, _| expectation.matches?(method_name, *args) }
|
106
125
|
|
107
|
-
|
108
|
-
|
109
|
-
|
126
|
+
name_but_not_args, others = @messages_received.partition do |(method_name, args, _)|
|
127
|
+
expectation.matches_name_but_not_args(method_name, *args)
|
128
|
+
end
|
110
129
|
|
111
|
-
|
130
|
+
return if name_but_not_args.empty? && !others.empty?
|
112
131
|
|
113
|
-
|
132
|
+
expectation.raise_unexpected_message_args_error(name_but_not_args.map { |args| args[1] })
|
133
|
+
end
|
114
134
|
end
|
115
135
|
|
116
136
|
# @private
|
@@ -141,17 +161,23 @@ module RSpec
|
|
141
161
|
|
142
162
|
# @private
|
143
163
|
def reset
|
144
|
-
@
|
164
|
+
@messages_received_mutex.synchronize do
|
165
|
+
@messages_received.clear
|
166
|
+
end
|
145
167
|
end
|
146
168
|
|
147
169
|
# @private
|
148
170
|
def received_message?(method_name, *args, &block)
|
149
|
-
@
|
171
|
+
@messages_received_mutex.synchronize do
|
172
|
+
@messages_received.any? { |array| array == [method_name, args, block] }
|
173
|
+
end
|
150
174
|
end
|
151
175
|
|
152
176
|
# @private
|
153
177
|
def messages_arg_list
|
154
|
-
@
|
178
|
+
@messages_received_mutex.synchronize do
|
179
|
+
@messages_received.map { |_, args, _| args }
|
180
|
+
end
|
155
181
|
end
|
156
182
|
|
157
183
|
# @private
|
@@ -162,8 +188,11 @@ module RSpec
|
|
162
188
|
# @private
|
163
189
|
def record_message_received(message, *args, &block)
|
164
190
|
@order_group.invoked SpecificMessage.new(object, message, args)
|
165
|
-
@
|
191
|
+
@messages_received_mutex.synchronize do
|
192
|
+
@messages_received << [message, args, block]
|
193
|
+
end
|
166
194
|
end
|
195
|
+
ruby2_keywords :record_message_received if respond_to?(:ruby2_keywords, true)
|
167
196
|
|
168
197
|
# @private
|
169
198
|
def message_received(message, *args, &block)
|
@@ -196,6 +225,7 @@ module RSpec
|
|
196
225
|
@object.__send__(:method_missing, message, *args, &block)
|
197
226
|
end
|
198
227
|
end
|
228
|
+
ruby2_keywords :message_received if respond_to?(:ruby2_keywords, true)
|
199
229
|
|
200
230
|
# @private
|
201
231
|
def raise_unexpected_message_error(method_name, args)
|
@@ -245,12 +275,14 @@ module RSpec
|
|
245
275
|
expectation.matches?(method_name, *args)
|
246
276
|
end
|
247
277
|
end
|
278
|
+
ruby2_keywords :find_matching_expectation if respond_to?(:ruby2_keywords, true)
|
248
279
|
|
249
280
|
def find_almost_matching_expectation(method_name, *args)
|
250
281
|
find_best_matching_expectation_for(method_name) do |expectation|
|
251
282
|
expectation.matches_name_but_not_args(method_name, *args)
|
252
283
|
end
|
253
284
|
end
|
285
|
+
ruby2_keywords :find_almost_matching_expectation if respond_to?(:ruby2_keywords, true)
|
254
286
|
|
255
287
|
def find_best_matching_expectation_for(method_name)
|
256
288
|
first_match = nil
|
@@ -267,10 +299,12 @@ module RSpec
|
|
267
299
|
def find_matching_method_stub(method_name, *args)
|
268
300
|
method_double_for(method_name).stubs.find { |stub| stub.matches?(method_name, *args) }
|
269
301
|
end
|
302
|
+
ruby2_keywords :find_matching_method_stub if respond_to?(:ruby2_keywords, true)
|
270
303
|
|
271
304
|
def find_almost_matching_stub(method_name, *args)
|
272
305
|
method_double_for(method_name).stubs.find { |stub| stub.matches_name_but_not_args(method_name, *args) }
|
273
306
|
end
|
307
|
+
ruby2_keywords :find_almost_matching_stub if respond_to?(:ruby2_keywords, true)
|
274
308
|
end
|
275
309
|
|
276
310
|
# @private
|
@@ -326,6 +360,7 @@ module RSpec
|
|
326
360
|
end
|
327
361
|
super
|
328
362
|
end
|
363
|
+
ruby2_keywords :message_received if respond_to?(:ruby2_keywords, true)
|
329
364
|
|
330
365
|
private
|
331
366
|
|
data/lib/rspec/mocks/space.rb
CHANGED
@@ -77,9 +77,9 @@ module RSpec
|
|
77
77
|
|
78
78
|
def reset_all
|
79
79
|
proxies.each_value { |proxy| proxy.reset }
|
80
|
-
@constant_mutators.reverse.each { |mut| mut.idempotently_reset }
|
81
80
|
any_instance_recorders.each_value { |recorder| recorder.stop_all_observation! }
|
82
81
|
any_instance_recorders.clear
|
82
|
+
@constant_mutators.reverse.each { |mut| mut.idempotently_reset }
|
83
83
|
end
|
84
84
|
|
85
85
|
def register_constant_mutator(mutator)
|
data/lib/rspec/mocks/targets.rb
CHANGED
@@ -54,7 +54,7 @@ module RSpec
|
|
54
54
|
|
55
55
|
def raise_negation_unsupported(method_name, matcher)
|
56
56
|
raise NegationUnsupportedError,
|
57
|
-
"`#{expression}(...).#{method_name} #{matcher.
|
57
|
+
"`#{expression}(...).#{method_name} #{matcher.matcher_name}` is not supported since it " \
|
58
58
|
"doesn't really make sense. What would it even mean?"
|
59
59
|
end
|
60
60
|
end
|
@@ -34,27 +34,21 @@ module RSpec
|
|
34
34
|
super
|
35
35
|
end
|
36
36
|
|
37
|
-
# @private
|
38
|
-
module SilentIO
|
39
|
-
def self.method_missing(*); end
|
40
|
-
def self.respond_to?(*)
|
41
|
-
true
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
37
|
# Redefining `__send__` causes ruby to issue a warning.
|
46
|
-
old, $
|
38
|
+
old, $VERBOSE = $VERBOSE, nil
|
47
39
|
def __send__(name, *args, &block)
|
48
40
|
@__sending_message = name
|
49
41
|
super
|
50
42
|
ensure
|
51
43
|
@__sending_message = nil
|
52
44
|
end
|
53
|
-
|
45
|
+
ruby2_keywords :__send__ if respond_to?(:ruby2_keywords, true)
|
46
|
+
$VERBOSE = old
|
54
47
|
|
55
48
|
def send(name, *args, &block)
|
56
49
|
__send__(name, *args, &block)
|
57
50
|
end
|
51
|
+
ruby2_keywords :send if respond_to?(:ruby2_keywords, true)
|
58
52
|
|
59
53
|
def initialize(doubled_module, *args)
|
60
54
|
@doubled_module = doubled_module
|
@@ -57,7 +57,7 @@ module RSpec
|
|
57
57
|
# A verifying proxy mostly acts like a normal proxy, except that it
|
58
58
|
# contains extra logic to try and determine the validity of any expectation
|
59
59
|
# set on it. This includes whether or not methods have been defined and the
|
60
|
-
#
|
60
|
+
# validity of arguments on method calls.
|
61
61
|
#
|
62
62
|
# In all other ways this behaves like a normal proxy. It only adds the
|
63
63
|
# verification behaviour to specific methods then delegates to the parent
|
@@ -147,12 +147,12 @@ module RSpec
|
|
147
147
|
end
|
148
148
|
|
149
149
|
def add_expectation(*args, &block)
|
150
|
-
#
|
150
|
+
# explicit params necessary for 1.8.7 see #626
|
151
151
|
super(*args, &block).tap { |x| x.method_reference = @method_reference }
|
152
152
|
end
|
153
153
|
|
154
154
|
def add_stub(*args, &block)
|
155
|
-
#
|
155
|
+
# explicit params necessary for 1.8.7 see #626
|
156
156
|
super(*args, &block).tap { |x| x.method_reference = @method_reference }
|
157
157
|
end
|
158
158
|
|
@@ -160,6 +160,7 @@ module RSpec
|
|
160
160
|
validate_arguments!(args)
|
161
161
|
super
|
162
162
|
end
|
163
|
+
ruby2_keywords :proxy_method_invoked if respond_to?(:ruby2_keywords, true)
|
163
164
|
|
164
165
|
def validate_arguments!(actual_args)
|
165
166
|
@method_reference.with_signature do |signature|
|
data/lib/rspec/mocks/version.rb
CHANGED
data/lib/rspec/mocks.rb
CHANGED
@@ -87,12 +87,15 @@ module RSpec
|
|
87
87
|
|
88
88
|
# Call the passed block and verify mocks after it has executed. This allows
|
89
89
|
# mock usage in arbitrary places, such as a `before(:all)` hook.
|
90
|
+
#
|
91
|
+
# @return [Object] the return value from the block
|
90
92
|
def self.with_temporary_scope
|
91
93
|
setup
|
92
94
|
|
93
95
|
begin
|
94
|
-
yield
|
96
|
+
result = yield
|
95
97
|
verify
|
98
|
+
result
|
96
99
|
ensure
|
97
100
|
teardown
|
98
101
|
end
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-mocks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.12.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steven Baker
|
8
8
|
- David Chelimsky
|
9
9
|
- Myron Marston
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain:
|
13
13
|
- |
|
@@ -45,7 +45,7 @@ cert_chain:
|
|
45
45
|
ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
|
46
46
|
F3MdtaDehhjC
|
47
47
|
-----END CERTIFICATE-----
|
48
|
-
date:
|
48
|
+
date: 2023-07-11 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.12.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.12.0
|
64
64
|
- !ruby/object:Gem::Dependency
|
65
65
|
name: diff-lcs
|
66
66
|
requirement: !ruby/object:Gem::Requirement
|
@@ -85,44 +85,44 @@ dependencies:
|
|
85
85
|
name: rake
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- - "
|
88
|
+
- - ">"
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: 10.0.0
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
|
-
- - "
|
95
|
+
- - ">"
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: 10.0.0
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: cucumber
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
|
-
- - "
|
102
|
+
- - ">="
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version: 1.3
|
104
|
+
version: '1.3'
|
105
105
|
type: :development
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
|
-
- - "
|
109
|
+
- - ">="
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: 1.3
|
111
|
+
version: '1.3'
|
112
112
|
- !ruby/object:Gem::Dependency
|
113
113
|
name: aruba
|
114
114
|
requirement: !ruby/object:Gem::Requirement
|
115
115
|
requirements:
|
116
116
|
- - "~>"
|
117
117
|
- !ruby/object:Gem::Version
|
118
|
-
version:
|
118
|
+
version: '1.1'
|
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: '1.1'
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: minitest
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,8 +192,13 @@ files:
|
|
192
192
|
homepage: https://github.com/rspec/rspec-mocks
|
193
193
|
licenses:
|
194
194
|
- MIT
|
195
|
-
metadata:
|
196
|
-
|
195
|
+
metadata:
|
196
|
+
bug_tracker_uri: https://github.com/rspec/rspec-mocks/issues
|
197
|
+
changelog_uri: https://github.com/rspec/rspec-mocks/blob/v3.12.6/Changelog.md
|
198
|
+
documentation_uri: https://rspec.info/documentation/
|
199
|
+
mailing_list_uri: https://groups.google.com/forum/#!forum/rspec
|
200
|
+
source_code_uri: https://github.com/rspec/rspec-mocks
|
201
|
+
post_install_message:
|
197
202
|
rdoc_options:
|
198
203
|
- "--charset=UTF-8"
|
199
204
|
require_paths:
|
@@ -209,9 +214,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
214
|
- !ruby/object:Gem::Version
|
210
215
|
version: '0'
|
211
216
|
requirements: []
|
212
|
-
|
213
|
-
|
214
|
-
signing_key:
|
217
|
+
rubygems_version: 3.4.1
|
218
|
+
signing_key:
|
215
219
|
specification_version: 4
|
216
|
-
summary: rspec-mocks-3.
|
220
|
+
summary: rspec-mocks-3.12.6
|
217
221
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|