muack 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +19 -9
- data/CHANGES.md +12 -0
- data/Gemfile +0 -4
- data/README.md +17 -16
- data/Rakefile +3 -4
- data/lib/muack/block.rb +4 -15
- data/lib/muack/block_26.rb +16 -0
- data/lib/muack/block_27.rb +16 -0
- data/lib/muack/coat.rb +1 -1
- data/lib/muack/definition.rb +4 -3
- data/lib/muack/failure.rb +5 -4
- data/lib/muack/mock.rb +123 -65
- data/lib/muack/spy.rb +3 -3
- data/lib/muack/stub.rb +7 -5
- data/lib/muack/test.rb +42 -11
- data/lib/muack/version.rb +1 -1
- data/muack.gemspec +65 -57
- data/task/README.md +8 -8
- data/task/gemgem.rb +29 -7
- data/test/test_any_instance_of.rb +16 -2
- data/test/test_from_readme.rb +5 -7
- data/test/test_keyargs.rb +111 -0
- data/test/test_modifier.rb +6 -6
- data/test/test_prepend.rb +121 -0
- data/test/test_proxy.rb +19 -4
- data/test/test_satisfying.rb +12 -12
- data/test/test_spy.rb +4 -4
- data/test/test_visibility.rb +120 -0
- metadata +15 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e65f1260993f94d96899086e3975500583ec077bfae332a8fd4cefc5a2c7da49
|
4
|
+
data.tar.gz: 736468eb986e1925f8f83973fec00c2142df16ca80aee9ce051bbdc255cbbfc8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3bb1281eab20185484890205696cbed1d3996ed6392b76e08297af8e742bd76a80f2e3a26fffec265848d18a5373dffd517db6d2127b4e511dfdc5a2b475937
|
7
|
+
data.tar.gz: 2c148e33b0dce444708d09a58f6364e160a926f73e5432120fa8668c7ee0dd65c83128e69723673fd6c95bb62db879b8ff3636af29c93e783954f8409a882ebd
|
data/.travis.yml
CHANGED
@@ -1,11 +1,21 @@
|
|
1
|
-
|
1
|
+
sudo: false
|
2
2
|
language: ruby
|
3
|
-
rvm:
|
4
|
-
- 2.0
|
5
|
-
- 2.1
|
6
|
-
- 2.2
|
7
|
-
- rbx-2
|
8
|
-
- jruby
|
9
3
|
|
10
|
-
install: 'bundle install --retry=3'
|
11
|
-
|
4
|
+
install: 'gem update --system; gem install bundler; bundle install --retry=3'
|
5
|
+
before_script: unset CI
|
6
|
+
script: 'ruby -vwr bundler/setup -S rake test'
|
7
|
+
|
8
|
+
matrix:
|
9
|
+
include:
|
10
|
+
- rvm: 2.4
|
11
|
+
env: RUBYOPT=--enable-frozen-string-literal
|
12
|
+
- rvm: 2.5
|
13
|
+
env: RUBYOPT=--enable-frozen-string-literal
|
14
|
+
- rvm: 2.6
|
15
|
+
env: RUBYOPT=--enable-frozen-string-literal
|
16
|
+
- rvm: 2.7
|
17
|
+
env: RUBYOPT=--enable-frozen-string-literal
|
18
|
+
- rvm: ruby-head
|
19
|
+
env: RUBYOPT=--enable-frozen-string-literal
|
20
|
+
- rvm: jruby
|
21
|
+
env: RUBYOPT=--enable-frozen-string-literal
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## Muack 1.5.0 -- 2020-11-28
|
4
|
+
|
5
|
+
### Bugs fixed
|
6
|
+
|
7
|
+
* Properly handle prepended objects
|
8
|
+
* Properly restore method visibilities for singleton methods
|
9
|
+
|
10
|
+
### Enhancement
|
11
|
+
|
12
|
+
* Eliminated any potential keyword arguments warnings to be future proof
|
13
|
+
* Some major internal restructure
|
14
|
+
|
3
15
|
## Muack 1.4.0 -- 2015-11-21
|
4
16
|
|
5
17
|
### Incompatible changes / Enhancement
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Muack [![Build Status](https://secure.travis-ci.org/godfat/muack.png?branch=master)](http://travis-ci.org/godfat/muack) [![Coverage Status](https://coveralls.io/repos/godfat/muack/badge.png
|
1
|
+
# Muack [![Build Status](https://secure.travis-ci.org/godfat/muack.png?branch=master)](http://travis-ci.org/godfat/muack) [![Coverage Status](https://coveralls.io/repos/github/godfat/muack/badge.png)](https://coveralls.io/github/godfat/muack) [![Join the chat at https://gitter.im/godfat/muack](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/godfat/muack)
|
2
2
|
|
3
3
|
by Lin Jen-Shin ([godfat](http://godfat.org))
|
4
4
|
|
@@ -7,6 +7,7 @@ by Lin Jen-Shin ([godfat](http://godfat.org))
|
|
7
7
|
* [github](https://github.com/godfat/muack)
|
8
8
|
* [rubygems](https://rubygems.org/gems/muack)
|
9
9
|
* [rdoc](http://rdoc.info/github/godfat/muack)
|
10
|
+
* [issues](https://github.com/godfat/muack/issues) (feel free to ask for support)
|
10
11
|
|
11
12
|
## DESCRIPTION:
|
12
13
|
|
@@ -25,7 +26,7 @@ Muack is much simpler and thus much faster and much more consistent.
|
|
25
26
|
|
26
27
|
## REQUIREMENTS:
|
27
28
|
|
28
|
-
* Tested with MRI (official CRuby)
|
29
|
+
* Tested with MRI (official CRuby) and JRuby.
|
29
30
|
|
30
31
|
## INSTALLATION:
|
31
32
|
|
@@ -46,7 +47,7 @@ describe 'Hello' do
|
|
46
47
|
after { Muack.verify }
|
47
48
|
|
48
49
|
would 'say world!' do
|
49
|
-
str = 'Hello'
|
50
|
+
str = 'Hello'.dup
|
50
51
|
mock(str).say('!'){ |arg| "World#{arg}" }
|
51
52
|
str.say('!').should.eq 'World!'
|
52
53
|
end
|
@@ -172,7 +173,7 @@ affecting the others. This is helpful in the cases of mocking some very
|
|
172
173
|
basic objects like Time, without causing too much side effect.
|
173
174
|
|
174
175
|
``` ruby
|
175
|
-
name = 'str'
|
176
|
+
name = 'str'.dup
|
176
177
|
stub(name).to_s{ 'hi' }
|
177
178
|
stub(Time).new { Time.at(0) }
|
178
179
|
mock(Time).now { Time.new }
|
@@ -274,7 +275,7 @@ into proxy mode we simply do not provide any block to the injected method,
|
|
274
275
|
but just name it. Here's an example:
|
275
276
|
|
276
277
|
``` ruby
|
277
|
-
str = 'str'
|
278
|
+
str = 'str'.dup
|
278
279
|
mock(str).reverse
|
279
280
|
p str.reverse # 'rts'
|
280
281
|
p Muack.verify # true
|
@@ -284,7 +285,7 @@ Note that if reverse was not called exactly once, the mock would complain.
|
|
284
285
|
We could also use stub + spy to do the same thing as well:
|
285
286
|
|
286
287
|
``` ruby
|
287
|
-
str = 'str'
|
288
|
+
str = 'str'.dup
|
288
289
|
stub(str).reverse
|
289
290
|
p str.reverse # 'rts'
|
290
291
|
spy(str).reverse
|
@@ -623,7 +624,7 @@ our own behaviour, then we already have full control of the arguments.
|
|
623
624
|
There's no points to use both. This also applies to `peek_return`.
|
624
625
|
|
625
626
|
``` ruby
|
626
|
-
str = 'ff'
|
627
|
+
str = 'ff'.dup
|
627
628
|
mock(str).to_i.with_any_args.peek_args{ |radix| radix * 2 }
|
628
629
|
p str.to_i(8) # 255
|
629
630
|
p Muack.verify # true
|
@@ -654,7 +655,7 @@ might just want to take a look at the return? Here's an example using
|
|
654
655
|
`peek_return` to modify the original return value.
|
655
656
|
|
656
657
|
``` ruby
|
657
|
-
str = 'ff'
|
658
|
+
str = 'ff'.dup
|
658
659
|
mock(str).to_i.with_any_args.peek_return{ |int| int * 2 }
|
659
660
|
p str.to_i(16) # 510
|
660
661
|
p Muack.verify # true
|
@@ -832,7 +833,7 @@ p Muack.verify # true
|
|
832
833
|
|
833
834
|
``` ruby
|
834
835
|
obj = Object.new
|
835
|
-
mock(obj).say(where(:a => is_a(
|
836
|
+
mock(obj).say(where(:a => is_a(Integer))){ |arg| arg }
|
836
837
|
p obj.say(:a => 0) # {:a => 0}
|
837
838
|
p Muack.verify # true
|
838
839
|
```
|
@@ -841,7 +842,7 @@ Note that this could be recursive.
|
|
841
842
|
|
842
843
|
``` ruby
|
843
844
|
obj = Object.new
|
844
|
-
mock(obj).say(where(:a => {:b => [is_a(
|
845
|
+
mock(obj).say(where(:a => {:b => [is_a(Integer)]})){ |arg| arg[:a] }
|
845
846
|
p obj.say(:a => {:b => [0]}) # {:b => [0]}
|
846
847
|
p Muack.verify # true
|
847
848
|
```
|
@@ -862,7 +863,7 @@ Note that this could be recursive.
|
|
862
863
|
|
863
864
|
``` ruby
|
864
865
|
obj = Object.new
|
865
|
-
mock(obj).say(having(:a => {:b => [is_a(
|
866
|
+
mock(obj).say(having(:a => {:b => [is_a(Integer)]})){ |arg| arg[:c] }
|
866
867
|
p obj.say(:a => {:b => [1]}, :c => 2) # 2
|
867
868
|
p Muack.verify # true
|
868
869
|
```
|
@@ -883,7 +884,7 @@ Note that this could be recursive.
|
|
883
884
|
|
884
885
|
``` ruby
|
885
886
|
obj = Object.new
|
886
|
-
mock(obj).say(allowing(:a => {:b => is_a(
|
887
|
+
mock(obj).say(allowing(:a => {:b => is_a(Integer), :c => 1})){ |arg| arg[:a] }
|
887
888
|
p obj.say(:a => {:b => 2}) # {:b => 2}
|
888
889
|
p Muack.verify # true
|
889
890
|
```
|
@@ -1209,8 +1210,8 @@ Or, I am happy to break legacy.
|
|
1209
1210
|
## USERS:
|
1210
1211
|
|
1211
1212
|
* [Rib][]
|
1212
|
-
* [rest-core](https://github.com/
|
1213
|
-
* [rest-more](https://github.com/
|
1213
|
+
* [rest-core](https://github.com/godfat/rest-core)
|
1214
|
+
* [rest-more](https://github.com/godfat/rest-more)
|
1214
1215
|
|
1215
1216
|
## CONTRIBUTORS:
|
1216
1217
|
|
@@ -1218,9 +1219,9 @@ Or, I am happy to break legacy.
|
|
1218
1219
|
|
1219
1220
|
## LICENSE:
|
1220
1221
|
|
1221
|
-
Apache License 2.0
|
1222
|
+
Apache License 2.0 (Apache-2.0)
|
1222
1223
|
|
1223
|
-
Copyright (c) 2013-
|
1224
|
+
Copyright (c) 2013-2020, Lin Jen-Shin (godfat)
|
1224
1225
|
|
1225
1226
|
Licensed under the Apache License, Version 2.0 (the "License");
|
1226
1227
|
you may not use this file except in compliance with the License.
|
data/Rakefile
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
|
2
2
|
begin
|
3
|
-
require "#{
|
3
|
+
require "#{__dir__}/task/gemgem"
|
4
4
|
rescue LoadError
|
5
|
-
sh 'git submodule update --init'
|
5
|
+
sh 'git submodule update --init --recursive'
|
6
6
|
exec Gem.ruby, '-S', $PROGRAM_NAME, *ARGV
|
7
7
|
end
|
8
8
|
|
9
|
-
Gemgem.init(
|
9
|
+
Gemgem.init(__dir__) do |s|
|
10
10
|
require 'muack/version'
|
11
11
|
s.name = 'muack'
|
12
12
|
s.version = Muack::VERSION
|
13
|
-
%w[].each{ |g| s.add_runtime_dependency(g) }
|
14
13
|
end
|
data/lib/muack/block.rb
CHANGED
@@ -1,17 +1,6 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
self.block, self.context = block, context
|
7
|
-
end
|
8
|
-
|
9
|
-
def call *args, &actual_block
|
10
|
-
if context # ruby: no way to pass actual_block to instance_exec
|
11
|
-
context.instance_exec(*args, &block)
|
12
|
-
else
|
13
|
-
block.call(*args, &actual_block)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
2
|
+
if RUBY_VERSION < '2.7'
|
3
|
+
require 'muack/block_26'
|
4
|
+
else
|
5
|
+
require 'muack/block_27'
|
17
6
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module Muack
|
3
|
+
class Block < Struct.new(:block, :context)
|
4
|
+
def initialize block, context=nil
|
5
|
+
super
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(*args, &block)
|
9
|
+
if context
|
10
|
+
context.instance_exec(*args, &block)
|
11
|
+
else
|
12
|
+
block.call(*args, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/muack/coat.rb
CHANGED
data/lib/muack/definition.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
|
2
2
|
module Muack
|
3
|
-
Definition =
|
4
|
-
|
5
|
-
|
3
|
+
Definition = Struct.new(:msg, :args, :returns,
|
4
|
+
:peek_args, :peek_return,
|
5
|
+
:original_method, :visibility)
|
6
|
+
ActualCall = Struct.new(:msg, :args, :block)
|
6
7
|
WithAnyArgs = Object.new
|
7
8
|
end
|
data/lib/muack/failure.rb
CHANGED
@@ -12,11 +12,12 @@ module Muack
|
|
12
12
|
|
13
13
|
class Unexpected < Failure
|
14
14
|
attr_reader :was
|
15
|
-
def initialize obj, expected_defis,
|
16
|
-
|
17
|
-
|
15
|
+
def initialize obj, expected_defis, actual_call
|
16
|
+
args = actual_call.args.map(&:inspect)
|
17
|
+
@was = "#{obj.inspect}.#{actual_call.msg}(#{args.join(', ')})"
|
18
|
+
|
18
19
|
if expected_defis.empty?
|
19
|
-
super("\nUnexpected call: #{
|
20
|
+
super("\nUnexpected call: #{was}")
|
20
21
|
else
|
21
22
|
build_expected(obj, expected_defis)
|
22
23
|
super("\nExpected: #{expected}\n but was: #{was}")
|
data/lib/muack/mock.rb
CHANGED
@@ -6,8 +6,6 @@ require 'muack/block'
|
|
6
6
|
require 'muack/error'
|
7
7
|
|
8
8
|
module Muack
|
9
|
-
EmptyBlock = proc{}
|
10
|
-
|
11
9
|
class Mock < BasicObject
|
12
10
|
attr_reader :object
|
13
11
|
def initialize object
|
@@ -24,8 +22,8 @@ module Muack
|
|
24
22
|
end
|
25
23
|
|
26
24
|
# Public API: Define mocked method
|
27
|
-
def method_missing msg, *args, &
|
28
|
-
defi = Definition.new(msg, args,
|
25
|
+
def method_missing msg, *args, &returns
|
26
|
+
defi = Definition.new(msg, args, returns)
|
29
27
|
if injected = __mock_injected[defi.msg]
|
30
28
|
defi.original_method = injected.original_method
|
31
29
|
else
|
@@ -51,42 +49,42 @@ module Muack
|
|
51
49
|
end
|
52
50
|
|
53
51
|
# used for mocked object to dispatch mocked method
|
54
|
-
def __mock_dispatch
|
55
|
-
if defi = __mock_defis[msg].shift
|
52
|
+
def __mock_dispatch actual_call
|
53
|
+
if defi = __mock_defis[actual_call.msg].shift
|
56
54
|
__mock_disps_push(defi)
|
57
|
-
if __mock_check_args(defi
|
55
|
+
if __mock_check_args(defi, actual_call)
|
58
56
|
defi
|
59
57
|
else
|
60
58
|
Mock.__send__(:raise, # Wrong argument
|
61
|
-
Unexpected.new(object, [defi],
|
59
|
+
Unexpected.new(object, [defi], actual_call))
|
62
60
|
end
|
63
61
|
else
|
64
|
-
__mock_failed(
|
62
|
+
__mock_failed(actual_call)
|
65
63
|
end
|
66
64
|
end
|
67
65
|
|
68
66
|
# used for mocked object to dispatch mocked method
|
69
|
-
def __mock_dispatch_call context, disp,
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
__mock_block_call(context, disp.returns,
|
79
|
-
args, actual_block, true)
|
80
|
-
elsif disp.original_method # proxies for singleton methods
|
81
|
-
context.__send__(disp.original_method, *args, &actual_block)
|
82
|
-
else # proxies for instance methods
|
83
|
-
# need the original context for calling `super`
|
84
|
-
# ruby: can't pass a block to yield, so we name it _yield
|
85
|
-
_yield.call(args, &actual_block)
|
86
|
-
end
|
67
|
+
def __mock_dispatch_call context, disp, actual_call, &proxy_super
|
68
|
+
# resolving arguments
|
69
|
+
call =
|
70
|
+
if disp.peek_args
|
71
|
+
args = __mock_block_call(context, disp.peek_args, actual_call)
|
72
|
+
ActualCall.new(actual_call.msg, args, actual_call.block)
|
73
|
+
else
|
74
|
+
actual_call
|
75
|
+
end
|
87
76
|
|
77
|
+
# retrieve actual return
|
78
|
+
ret =
|
79
|
+
if disp.returns
|
80
|
+
__mock_block_call(context, disp.returns, call)
|
81
|
+
else
|
82
|
+
__mock_proxy_call(context, disp, call, proxy_super)
|
83
|
+
end
|
84
|
+
|
85
|
+
# resolving return
|
88
86
|
if disp.peek_return
|
89
|
-
__mock_block_call(context, disp.peek_return, ret,
|
87
|
+
__mock_block_call(context, disp.peek_return, ret, true)
|
90
88
|
else
|
91
89
|
ret
|
92
90
|
end
|
@@ -95,9 +93,9 @@ module Muack
|
|
95
93
|
# used for Muack::Session#verify
|
96
94
|
def __mock_verify
|
97
95
|
__mock_defis.values.all?(&:empty?) || begin
|
98
|
-
msg, defis_with_same_msg = __mock_defis.find{ |_, v| v.
|
96
|
+
msg, defis_with_same_msg = __mock_defis.find{ |_, v| v.any? }
|
99
97
|
args, defis = defis_with_same_msg.group_by(&:args).first
|
100
|
-
dsize = __mock_disps[msg].
|
98
|
+
dsize = __mock_disps[msg].count{ |d| d.args == args }
|
101
99
|
Mock.__send__(:raise, # Too little times
|
102
100
|
Expected.new(object, defis.first, defis.size + dsize, dsize))
|
103
101
|
end
|
@@ -114,36 +112,46 @@ module Muack
|
|
114
112
|
private
|
115
113
|
def __mock_inject_method defi
|
116
114
|
__mock_injected[defi.msg] = defi
|
117
|
-
|
118
|
-
|
119
|
-
|
115
|
+
# a) ancestors.first is the first module in the method chain.
|
116
|
+
# it's just the singleton_class when nothing was prepended,
|
117
|
+
# otherwise the last prepended module.
|
118
|
+
# b) would be the class in AnyInstanceOf.
|
119
|
+
target = object.singleton_class.ancestors.first
|
120
|
+
Mock.store_original_method(target, defi)
|
121
|
+
__mock_inject_mock_method(target, defi)
|
120
122
|
end
|
121
123
|
|
122
124
|
def __mock_reset_method defi
|
123
|
-
object.singleton_class.module_eval do
|
125
|
+
object.singleton_class.ancestors.first.module_eval do
|
124
126
|
remove_method(defi.msg)
|
125
127
|
# restore original method
|
126
|
-
if
|
128
|
+
if public_instance_methods(false).include?(defi.original_method) ||
|
129
|
+
protected_instance_methods(false).include?(defi.original_method) ||
|
127
130
|
private_instance_methods(false).include?(defi.original_method)
|
128
131
|
alias_method(defi.msg, defi.original_method)
|
132
|
+
__send__(defi.visibility, defi.msg)
|
129
133
|
remove_method(defi.original_method)
|
130
134
|
end
|
131
135
|
end
|
132
136
|
end
|
133
137
|
|
134
138
|
def self.store_original_method klass, defi
|
135
|
-
|
136
|
-
:public
|
139
|
+
visibility = if klass.public_instance_methods(false).include?(defi.msg)
|
140
|
+
:public
|
141
|
+
elsif klass.protected_instance_methods(false).include?(defi.msg)
|
142
|
+
:protected
|
137
143
|
elsif klass.private_instance_methods(false).include?(defi.msg)
|
138
144
|
:private
|
139
145
|
end
|
140
146
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
+
if visibility # store original method
|
148
|
+
original_method = find_new_name(klass, defi.msg)
|
149
|
+
klass.__send__(:alias_method, original_method, defi.msg)
|
150
|
+
defi.original_method = original_method
|
151
|
+
defi.visibility = visibility
|
152
|
+
else
|
153
|
+
defi.visibility = :public
|
154
|
+
end
|
147
155
|
end
|
148
156
|
|
149
157
|
def self.find_new_name klass, message, level=0
|
@@ -159,50 +167,100 @@ module Muack
|
|
159
167
|
end
|
160
168
|
end
|
161
169
|
|
162
|
-
def __mock_inject_mock_method target, defi
|
170
|
+
def __mock_inject_mock_method target, defi
|
163
171
|
mock = self # remember the context
|
164
172
|
target.__send__(:define_method, defi.msg){ |*actual_args, &actual_block|
|
165
|
-
|
166
|
-
mock.
|
167
|
-
|
168
|
-
super
|
173
|
+
actual_call = ActualCall.new(defi.msg, actual_args, actual_block)
|
174
|
+
disp = mock.__mock_dispatch(actual_call)
|
175
|
+
mock.__mock_dispatch_call(self, disp, actual_call) do |call, has_kargs|
|
176
|
+
# need the original context for calling `super`
|
177
|
+
if has_kargs && kargs = call.args.last
|
178
|
+
super(*call.args[0...-1], **kargs, &call.block)
|
179
|
+
else
|
180
|
+
super(*call.args, &call.block)
|
181
|
+
end
|
169
182
|
end
|
170
183
|
}
|
171
|
-
target.__send__(
|
184
|
+
target.__send__(defi.visibility, defi.msg)
|
172
185
|
end
|
173
186
|
|
174
187
|
# used for __mock_dispatch
|
175
|
-
def __mock_failed
|
176
|
-
if expected = __mock_find_checked_difi(disps,
|
188
|
+
def __mock_failed actual_call, disps=__mock_disps[actual_call.msg]
|
189
|
+
if expected = __mock_find_checked_difi(disps, actual_call)
|
177
190
|
Mock.__send__(:raise, # Too many times
|
178
191
|
Expected.new(object, expected, disps.size, disps.size+1))
|
179
192
|
else
|
180
193
|
Mock.__send__(:raise, # Wrong argument
|
181
|
-
Unexpected.new(object, disps,
|
194
|
+
Unexpected.new(object, disps, actual_call))
|
182
195
|
end
|
183
196
|
end
|
184
197
|
|
185
198
|
# used for __mock_dispatch_call
|
186
|
-
def __mock_block_call context, block,
|
187
|
-
return unless block
|
199
|
+
def __mock_block_call context, block, actual_call, peek_return=false
|
188
200
|
# for AnyInstanceOf, we don't have the actual context at the time
|
189
201
|
# we're defining it, so we update it here
|
190
|
-
|
191
|
-
|
192
|
-
block.
|
193
|
-
|
194
|
-
|
202
|
+
if block.kind_of?(Block)
|
203
|
+
block.context = context
|
204
|
+
instance_exec_block = block.block
|
205
|
+
end
|
206
|
+
|
207
|
+
if peek_return # actual_call is the actual return in this case
|
208
|
+
block.call(actual_call, &instance_exec_block)
|
209
|
+
else
|
210
|
+
actual_block = actual_call.block || instance_exec_block
|
211
|
+
if __mock_block_with_kargs?(instance_exec_block || block) &&
|
212
|
+
kargs = actual_call.args.last
|
213
|
+
block.call(*actual_call.args[0...-1], **kargs, &actual_block)
|
214
|
+
else
|
215
|
+
block.call(*actual_call.args, &actual_block)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# used for __mock_dispatch_call
|
221
|
+
def __mock_proxy_call context, disp, call, proxy_super
|
222
|
+
if disp.original_method # proxies for singleton methods with __send__
|
223
|
+
if __mock_method_with_kargs?(context, disp.original_method) &&
|
224
|
+
kargs = call.args.last
|
225
|
+
context.__send__(
|
226
|
+
disp.original_method, *call.args[0...-1], **kargs, &call.block)
|
227
|
+
else
|
228
|
+
context.__send__(disp.original_method, *call.args, &call.block)
|
229
|
+
end
|
230
|
+
else # proxies for instance methods with super
|
231
|
+
proxy_super.call(call, __mock_super_with_kargs?(context, call.msg))
|
195
232
|
end
|
196
233
|
end
|
197
234
|
|
198
|
-
def __mock_find_checked_difi defis,
|
199
|
-
defis.public_send(meth){ |d| __mock_check_args(d
|
235
|
+
def __mock_find_checked_difi defis, actual_call, meth=:find
|
236
|
+
defis.public_send(meth){ |d| __mock_check_args(d, actual_call) }
|
237
|
+
end
|
238
|
+
|
239
|
+
def __mock_method_with_kargs? object, method_name
|
240
|
+
__mock_block_with_kargs?(
|
241
|
+
::Kernel.instance_method(:method).bind(object).call(method_name))
|
200
242
|
end
|
201
243
|
|
202
|
-
def
|
203
|
-
|
204
|
-
|
205
|
-
|
244
|
+
def __mock_super_with_kargs? object, method_name
|
245
|
+
super_method =
|
246
|
+
::Kernel.instance_method(:method).bind(object).call(method_name).
|
247
|
+
super_method
|
248
|
+
|
249
|
+
super_method && __mock_block_with_kargs?(super_method)
|
250
|
+
end
|
251
|
+
|
252
|
+
def __mock_block_with_kargs? block
|
253
|
+
# there's no Symbol#start_with? in older Ruby
|
254
|
+
block.parameters.dig(-1, 0).to_s.start_with?('key')
|
255
|
+
end
|
256
|
+
|
257
|
+
def __mock_check_args defi, actual_call
|
258
|
+
return true if defi.args.size == 1 && defi.args.first == WithAnyArgs
|
259
|
+
|
260
|
+
expected_args = defi.args
|
261
|
+
actual_args = actual_call.args
|
262
|
+
|
263
|
+
if expected_args.none?{ |arg| arg.kind_of?(Satisfying) }
|
206
264
|
expected_args == actual_args
|
207
265
|
|
208
266
|
elsif expected_args.size == actual_args.size
|