spy 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +38 -0
- data/.tool-versions +1 -1
- data/CHANGELOG.md +20 -0
- data/README.md +3 -4
- data/lib/spy/call_log.rb +6 -3
- data/lib/spy/subroutine.rb +14 -26
- data/lib/spy/version.rb +1 -1
- data/spy.gemspec +1 -1
- data/test/spy/test_subroutine.rb +22 -0
- data/test/support/pen.rb +4 -0
- metadata +4 -36
- data/.travis.yml +0 -13
- data/spec/spec_helper.rb +0 -41
- data/spec/spy/and_call_original_spec.rb +0 -152
- data/spec/spy/and_yield_spec.rb +0 -123
- data/spec/spy/any_instance_spec.rb +0 -518
- data/spec/spy/hash_excluding_matcher_spec.rb +0 -63
- data/spec/spy/hash_including_matcher_spec.rb +0 -86
- data/spec/spy/mutate_const_spec.rb +0 -471
- data/spec/spy/nil_expectation_warning_spec.rb +0 -56
- data/spec/spy/null_object_mock_spec.rb +0 -79
- data/spec/spy/partial_mock_spec.rb +0 -81
- data/spec/spy/passing_argument_matchers_spec.rb +0 -140
- data/spec/spy/serialization_spec.rb +0 -116
- data/spec/spy/stash_spec.rb +0 -47
- data/spec/spy/stub_implementation_spec.rb +0 -64
- data/spec/spy/stub_spec.rb +0 -79
- data/spec/spy/to_ary_spec.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46c870bafa6e5402e585dc44ea855f5e22a8087b4c14f70fad8794b39ac425a0
|
4
|
+
data.tar.gz: c9552993d8b0e335defead206a238c0342ea461102722f6702f04ae8a823f100
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b476de3ea3a4f01a85ed3f99d51ed7c38785f67c9c7b565607e6e0edd027eeb643bc2fe43a92b8bdcfc7054e149c6e75022489bccaa3b7678f4239263152094
|
7
|
+
data.tar.gz: 16d976fa766805c685f7198fe219a55802d29a4d560ec7f984c229c751905c81fe0622a8887fc71c0c87845a48d40d283fdb4f0411d2c3ded2d72673bddfe1e1
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ "master" ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ "master" ]
|
15
|
+
|
16
|
+
permissions:
|
17
|
+
contents: read
|
18
|
+
|
19
|
+
jobs:
|
20
|
+
test:
|
21
|
+
|
22
|
+
runs-on: ubuntu-latest
|
23
|
+
strategy:
|
24
|
+
matrix:
|
25
|
+
ruby-version: ['2.7', '3.0', '3.1']
|
26
|
+
|
27
|
+
steps:
|
28
|
+
- uses: actions/checkout@v3
|
29
|
+
- name: Set up Ruby
|
30
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
31
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
32
|
+
# uses: ruby/setup-ruby@v1
|
33
|
+
uses: ruby/setup-ruby@0a29871fe2b0200a17a4497bae54fe5df0d973aa # v1.115.3
|
34
|
+
with:
|
35
|
+
ruby-version: ${{ matrix.ruby-version }}
|
36
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
37
|
+
- name: Run tests
|
38
|
+
run: bundle exec rake
|
data/.tool-versions
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby
|
1
|
+
ruby 3.1.2
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## Spy 1.0.4 (December 21th, 2022) ##
|
2
|
+
|
3
|
+
* remove usage of #present? (@ryanong)
|
4
|
+
|
5
|
+
## Spy 1.0.4 (December 21th, 2022) ##
|
6
|
+
|
7
|
+
* Hash as argument got turned into keyword arguments (@svenpl)
|
8
|
+
* drop support for ruby older than 2.7 (@ryanong)
|
9
|
+
|
10
|
+
## Spy 1.0.3 (September 15, 2022) ##
|
11
|
+
|
12
|
+
* Fix private method call errors for older ruby versions (@dylanahsmith)
|
13
|
+
* `Spy.on_instance_method` and `and_call_through` on `#to_ary-able` class causes an error (@mizukami234)
|
14
|
+
* Fix `and_return` on class method (@jfirebaugh)
|
15
|
+
|
16
|
+
## Spy 1.0.2 (January 10, 2022) ##
|
17
|
+
|
18
|
+
* Fix subroutine call with hash as last arg (@dtheo-ad)
|
19
|
+
* Ruby 2.7+ support (@casperisfine)
|
20
|
+
|
1
21
|
## Spy 1.0.1 (August 20th, 2020) ##
|
2
22
|
|
3
23
|
* Fix call_through w/ instance methods (@lreeves)
|
data/README.md
CHANGED
@@ -9,8 +9,7 @@
|
|
9
9
|
|
10
10
|
Spy is a lightweight stubbing framework with support for method spies, constant stubs, and object mocks.
|
11
11
|
|
12
|
-
Spy supports ruby 2.
|
13
|
-
For versions less than 2.1 use v0.4.5
|
12
|
+
Spy supports ruby 2.7.0+.
|
14
13
|
|
15
14
|
Spy features that were completed were tested against the rspec-mocks tests so it covers all cases that rspec-mocks does.
|
16
15
|
|
@@ -47,7 +46,7 @@ Fail faster, code faster.
|
|
47
46
|
* you can usually just check the call logs.
|
48
47
|
* if you do need to use this. It is probably a code smell. You either need to abstract your method more or add separate tests.
|
49
48
|
* you want to use dumb double, Spy has smart mocks, they are better
|
50
|
-
* you use `mock_model` and `stub_model`
|
49
|
+
* you use `mock_model` and `stub_model`
|
51
50
|
|
52
51
|
## Installation
|
53
52
|
|
@@ -87,7 +86,7 @@ Spy::Subroutine.new(book, :flamethrower).hook(force:true).and_return("burnninant
|
|
87
86
|
```
|
88
87
|
|
89
88
|
You can also stub instance methods of Classes and Modules. This is equivalent to
|
90
|
-
rspec-mock's `Module
|
89
|
+
rspec-mock's `allow_any_instance_of(Module)`
|
91
90
|
|
92
91
|
```ruby
|
93
92
|
Spy.on_instance_method(Book, :title).and_return("Cannery Row")
|
data/lib/spy/call_log.rb
CHANGED
@@ -10,6 +10,9 @@ module Spy
|
|
10
10
|
# @!attribute [r] args
|
11
11
|
# @return [Array] arguments were sent to the method
|
12
12
|
#
|
13
|
+
# @!attribute [r] kwargs
|
14
|
+
# @return [Array] keyword arguments were sent to the method
|
15
|
+
#
|
13
16
|
# @!attribute [r] block
|
14
17
|
# @return [Proc] the block that was sent to the method
|
15
18
|
#
|
@@ -17,10 +20,10 @@ module Spy
|
|
17
20
|
# @return The result of the method of being stubbed, or called through
|
18
21
|
|
19
22
|
|
20
|
-
attr_reader :object, :called_from, :args, :block, :result
|
23
|
+
attr_reader :object, :called_from, :args, :kwargs, :block, :result
|
21
24
|
|
22
|
-
def initialize(object, called_from, args, block, result)
|
23
|
-
@object, @called_from, @args, @block, @result = object, called_from, args, block, result
|
25
|
+
def initialize(object, called_from, args, kwargs, block, result)
|
26
|
+
@object, @called_from, @args, @kwargs, @block, @result = object, called_from, args, kwargs, block, result
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
data/lib/spy/subroutine.rb
CHANGED
@@ -201,26 +201,28 @@ module Spy
|
|
201
201
|
# check if the method was called with the exact arguments
|
202
202
|
# @param args Arguments that should have been sent to the method
|
203
203
|
# @return [Boolean]
|
204
|
-
def has_been_called_with?(*args, &block)
|
204
|
+
def has_been_called_with?(*args, **kwargs, &block)
|
205
205
|
raise NeverHookedError unless @was_hooked
|
206
|
-
match = block_given? ? block : proc { |call| call.args == args }
|
206
|
+
match = block_given? ? block : proc { |call| call.args == args && call.kwargs == kwargs }
|
207
207
|
calls.any?(&match)
|
208
208
|
end
|
209
209
|
|
210
210
|
# invoke that the method has been called. You really shouldn't use this
|
211
211
|
# method.
|
212
|
-
def invoke(object, args, block, called_from)
|
213
|
-
|
212
|
+
def invoke(object, args, kwargs, block, called_from)
|
213
|
+
arity = args.size
|
214
|
+
arity += 1 if !kwargs&.empty?
|
215
|
+
check_arity!(arity)
|
214
216
|
|
215
217
|
result =
|
216
218
|
if @call_through
|
217
|
-
call_plan(build_call_through_plan(object), block, *args)
|
219
|
+
call_plan(build_call_through_plan(object), block, *args, **kwargs)
|
218
220
|
elsif @plan
|
219
221
|
check_for_too_many_arguments!(@plan)
|
220
|
-
call_plan(@plan, block, *args)
|
222
|
+
call_plan(@plan, block, *args, **kwargs)
|
221
223
|
end
|
222
224
|
ensure
|
223
|
-
calls << CallLog.new(object, called_from, args, block, result)
|
225
|
+
calls << CallLog.new(object, called_from, args, kwargs, block, result)
|
224
226
|
end
|
225
227
|
|
226
228
|
# reset the call log
|
@@ -237,11 +239,12 @@ module Spy
|
|
237
239
|
# we use eval to set the spy object id as a parameter so it can be extracted
|
238
240
|
# and looked up later using `Method#parameters`
|
239
241
|
SPY_ARGS_PREFIX='__spy_args_'.freeze
|
242
|
+
SPY_KWARGS_PREFIX='__spy_kwargs_'.freeze
|
240
243
|
def override_method
|
241
244
|
eval <<-METHOD, binding, __FILE__, __LINE__ + 1
|
242
245
|
__method_spy__ = self
|
243
|
-
lambda do |*#{SPY_ARGS_PREFIX}#{self.object_id}, &block|
|
244
|
-
__method_spy__.invoke(self, #{SPY_ARGS_PREFIX}#{self.object_id}, block, caller(1)[0])
|
246
|
+
lambda do |*#{SPY_ARGS_PREFIX}#{self.object_id}, **#{SPY_KWARGS_PREFIX}#{self.object_id}, &block|
|
247
|
+
__method_spy__.invoke(self, #{SPY_ARGS_PREFIX}#{self.object_id}, #{SPY_KWARGS_PREFIX}#{self.object_id}, block, caller(1)[0])
|
245
248
|
end
|
246
249
|
METHOD
|
247
250
|
end
|
@@ -345,23 +348,8 @@ module Spy
|
|
345
348
|
end
|
346
349
|
end
|
347
350
|
|
348
|
-
def call_plan(plan, block, *args)
|
349
|
-
|
350
|
-
*prefix, last = args
|
351
|
-
plan.call(*prefix, **last, &block)
|
352
|
-
else
|
353
|
-
plan.call(*args, &block)
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
# Ruby 2.7 gives a deprecation warning about passing hash as last argument for a method
|
358
|
-
# with a double-splat operator (**), and Ruby 3 raises an ArgumentError exception.
|
359
|
-
# This checks if args has a hash as last element to extract it and pass it with double-splat to avoid an exception.
|
360
|
-
def ruby_27_last_arg_hash?(args)
|
361
|
-
last = args.last
|
362
|
-
last.instance_of?(Hash) &&
|
363
|
-
!last.empty? &&
|
364
|
-
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7.0")
|
351
|
+
def call_plan(plan, block, *args, **kwargs)
|
352
|
+
plan.call(*args, **kwargs, &block)
|
365
353
|
end
|
366
354
|
|
367
355
|
class << self
|
data/lib/spy/version.rb
CHANGED
data/spy.gemspec
CHANGED
@@ -6,7 +6,7 @@ require 'spy/version'
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "spy"
|
8
8
|
gem.version = Spy::VERSION
|
9
|
-
gem.required_ruby_version = '>= 2.
|
9
|
+
gem.required_ruby_version = '>= 2.7.0'
|
10
10
|
gem.license = 'MIT'
|
11
11
|
gem.authors = ["Ryan Ong"]
|
12
12
|
gem.email = ["ryanong@gmail.com"]
|
data/test/spy/test_subroutine.rb
CHANGED
@@ -150,6 +150,14 @@ module Spy
|
|
150
150
|
assert_equal string, result
|
151
151
|
end
|
152
152
|
|
153
|
+
def test_spy_and_call_through_with_hash_and_keyword_args
|
154
|
+
spy_on(@pen, 'hash_and_keyword_arg').and_call_through
|
155
|
+
hsh = { hello: 'world' }
|
156
|
+
|
157
|
+
assert_equal [hsh, nil], @pen.hash_and_keyword_arg(hsh)
|
158
|
+
assert_equal [hsh, 'foo'], @pen.hash_and_keyword_arg(hsh, keyword: 'foo')
|
159
|
+
end
|
160
|
+
|
153
161
|
def test_spy_and_call_through_returns_original_method_result
|
154
162
|
string = "hello world"
|
155
163
|
|
@@ -237,6 +245,20 @@ module Spy
|
|
237
245
|
assert pen_write_spy.has_been_called_with?("hello")
|
238
246
|
end
|
239
247
|
|
248
|
+
def test_has_been_called_with_kwargs
|
249
|
+
pen_write_spy = spy_on(@pen, :opt_kwargs)
|
250
|
+
refute pen_write_spy.has_been_called_with?("hello")
|
251
|
+
|
252
|
+
@pen.opt_kwargs("hello")
|
253
|
+
assert pen_write_spy.has_been_called_with?("hello")
|
254
|
+
|
255
|
+
@pen.opt_kwargs("world", opt: "hello")
|
256
|
+
assert pen_write_spy.has_been_called_with?("world", opt: "hello")
|
257
|
+
|
258
|
+
@pen.opt_kwargs("hello world", opt: "world", opt2: "hello")
|
259
|
+
assert pen_write_spy.has_been_called_with?("hello world", opt: "world", opt2: "hello")
|
260
|
+
end
|
261
|
+
|
240
262
|
def test_spy_hook_records_number_of_calls2
|
241
263
|
args = ["hello world"]
|
242
264
|
block = Proc.new {}
|
data/test/support/pen.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Ong
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -117,9 +117,9 @@ executables: []
|
|
117
117
|
extensions: []
|
118
118
|
extra_rdoc_files: []
|
119
119
|
files:
|
120
|
+
- ".github/workflows/ruby.yml"
|
120
121
|
- ".gitignore"
|
121
122
|
- ".tool-versions"
|
122
|
-
- ".travis.yml"
|
123
123
|
- ".yardopts"
|
124
124
|
- CHANGELOG.md
|
125
125
|
- Gemfile
|
@@ -139,22 +139,6 @@ files:
|
|
139
139
|
- lib/spy/nest.rb
|
140
140
|
- lib/spy/subroutine.rb
|
141
141
|
- lib/spy/version.rb
|
142
|
-
- spec/spec_helper.rb
|
143
|
-
- spec/spy/and_call_original_spec.rb
|
144
|
-
- spec/spy/and_yield_spec.rb
|
145
|
-
- spec/spy/any_instance_spec.rb
|
146
|
-
- spec/spy/hash_excluding_matcher_spec.rb
|
147
|
-
- spec/spy/hash_including_matcher_spec.rb
|
148
|
-
- spec/spy/mutate_const_spec.rb
|
149
|
-
- spec/spy/nil_expectation_warning_spec.rb
|
150
|
-
- spec/spy/null_object_mock_spec.rb
|
151
|
-
- spec/spy/partial_mock_spec.rb
|
152
|
-
- spec/spy/passing_argument_matchers_spec.rb
|
153
|
-
- spec/spy/serialization_spec.rb
|
154
|
-
- spec/spy/stash_spec.rb
|
155
|
-
- spec/spy/stub_implementation_spec.rb
|
156
|
-
- spec/spy/stub_spec.rb
|
157
|
-
- spec/spy/to_ary_spec.rb
|
158
142
|
- spy.gemspec
|
159
143
|
- test/integration/test_api.rb
|
160
144
|
- test/integration/test_class_method.rb
|
@@ -179,7 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
179
163
|
requirements:
|
180
164
|
- - ">="
|
181
165
|
- !ruby/object:Gem::Version
|
182
|
-
version: 2.
|
166
|
+
version: 2.7.0
|
183
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
168
|
requirements:
|
185
169
|
- - ">="
|
@@ -192,22 +176,6 @@ specification_version: 4
|
|
192
176
|
summary: A simple modern mocking library that uses the spy pattern and checks method's
|
193
177
|
existence and arity.
|
194
178
|
test_files:
|
195
|
-
- spec/spec_helper.rb
|
196
|
-
- spec/spy/and_call_original_spec.rb
|
197
|
-
- spec/spy/and_yield_spec.rb
|
198
|
-
- spec/spy/any_instance_spec.rb
|
199
|
-
- spec/spy/hash_excluding_matcher_spec.rb
|
200
|
-
- spec/spy/hash_including_matcher_spec.rb
|
201
|
-
- spec/spy/mutate_const_spec.rb
|
202
|
-
- spec/spy/nil_expectation_warning_spec.rb
|
203
|
-
- spec/spy/null_object_mock_spec.rb
|
204
|
-
- spec/spy/partial_mock_spec.rb
|
205
|
-
- spec/spy/passing_argument_matchers_spec.rb
|
206
|
-
- spec/spy/serialization_spec.rb
|
207
|
-
- spec/spy/stash_spec.rb
|
208
|
-
- spec/spy/stub_implementation_spec.rb
|
209
|
-
- spec/spy/stub_spec.rb
|
210
|
-
- spec/spy/to_ary_spec.rb
|
211
179
|
- test/integration/test_api.rb
|
212
180
|
- test/integration/test_class_method.rb
|
213
181
|
- test/integration/test_constant_spying.rb
|
data/.travis.yml
DELETED
data/spec/spec_helper.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
require "rspec/core"
|
2
|
-
require "rspec/matchers"
|
3
|
-
require "rspec/expectations"
|
4
|
-
require "spy"
|
5
|
-
require "pry"
|
6
|
-
require "pry-nav"
|
7
|
-
|
8
|
-
RSpec::Matchers.define :include_method do |expected|
|
9
|
-
match do |actual|
|
10
|
-
actual.map { |m| m.to_s }.include?(expected.to_s)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
RSpec.configure do |config|
|
15
|
-
config.color_enabled = true
|
16
|
-
config.order = :random
|
17
|
-
config.run_all_when_everything_filtered = true
|
18
|
-
config.treat_symbols_as_metadata_keys_with_true_values = true
|
19
|
-
config.filter_run_including :focus
|
20
|
-
config.filter_run_excluding :broken => true
|
21
|
-
config.mock_with :absolutely_nothing
|
22
|
-
|
23
|
-
config.expect_with :rspec do |expectations|
|
24
|
-
expectations.syntax = :expect
|
25
|
-
end
|
26
|
-
|
27
|
-
old_verbose = nil
|
28
|
-
config.before(:each, :silence_warnings) do
|
29
|
-
old_verbose = $VERBOSE
|
30
|
-
$VERBOSE = nil
|
31
|
-
end
|
32
|
-
|
33
|
-
config.after(:each, :silence_warnings) do
|
34
|
-
$VERBOSE = old_verbose
|
35
|
-
end
|
36
|
-
|
37
|
-
config.after(:each) do
|
38
|
-
Spy.teardown
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
@@ -1,152 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "and_call_through" do
|
4
|
-
context "on a partial mock object" do
|
5
|
-
let(:klass) do
|
6
|
-
Class.new do
|
7
|
-
def meth_1
|
8
|
-
:original
|
9
|
-
end
|
10
|
-
|
11
|
-
def meth_2(x)
|
12
|
-
yield x, :additional_yielded_arg
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.new_instance
|
16
|
-
new
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
let(:instance) { klass.new }
|
22
|
-
|
23
|
-
it 'passes the received message through to the original method' do
|
24
|
-
spy = Spy.on(instance, :meth_1).and_call_through
|
25
|
-
expect(instance.meth_1).to eq(:original)
|
26
|
-
expect(spy).to have_been_called
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'passes args and blocks through to the original method' do
|
30
|
-
spy = Spy.on(instance, :meth_2).and_call_through
|
31
|
-
value = instance.meth_2(:submitted_arg) { |a, b| [a, b] }
|
32
|
-
expect(value).to eq([:submitted_arg, :additional_yielded_arg])
|
33
|
-
expect(spy).to have_been_called
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'works for singleton methods' do
|
37
|
-
def instance.foo; :bar; end
|
38
|
-
spy = Spy.on(instance, :foo).and_call_through
|
39
|
-
expect(instance.foo).to eq(:bar)
|
40
|
-
expect(spy).to have_been_called
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'works for methods added through an extended module' do
|
44
|
-
instance.extend Module.new { def foo; :bar; end }
|
45
|
-
spy = Spy.on(instance, :foo).and_call_through
|
46
|
-
expect(instance.foo).to eq(:bar)
|
47
|
-
expect(spy).to have_been_called
|
48
|
-
end
|
49
|
-
|
50
|
-
it "works for method added through an extended module onto a class's ancestor" do
|
51
|
-
sub_sub_klass = Class.new(Class.new(klass))
|
52
|
-
klass.extend Module.new { def foo; :bar; end }
|
53
|
-
spy = Spy.on(sub_sub_klass, :foo).and_call_through
|
54
|
-
expect(sub_sub_klass.foo).to eq(:bar)
|
55
|
-
expect(spy).to have_been_called
|
56
|
-
end
|
57
|
-
|
58
|
-
it "finds the method on the most direct ancestor even if the method " +
|
59
|
-
"is available on more distant ancestors" do
|
60
|
-
klass.extend Module.new { def foo; :klass_bar; end }
|
61
|
-
sub_klass = Class.new(klass)
|
62
|
-
sub_klass.extend Module.new { def foo; :sub_klass_bar; end }
|
63
|
-
spy = Spy.on(sub_klass, :foo).and_call_through
|
64
|
-
expect(sub_klass.foo).to eq(:sub_klass_bar)
|
65
|
-
expect(spy).to have_been_called
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'works for class methods defined on a superclass' do
|
69
|
-
subclass = Class.new(klass)
|
70
|
-
spy = Spy.on(subclass, :new_instance).and_call_through
|
71
|
-
expect(subclass.new_instance).to be_a(subclass)
|
72
|
-
expect(spy).to have_been_called
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'works for class methods defined on a grandparent class' do
|
76
|
-
sub_subclass = Class.new(Class.new(klass))
|
77
|
-
spy = Spy.on(sub_subclass, :new_instance).and_call_through
|
78
|
-
expect(sub_subclass.new_instance).to be_a(sub_subclass)
|
79
|
-
expect(spy).to have_been_called
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'works for class methods defined on the Class class' do
|
83
|
-
spy = Spy.on(klass, :new).and_call_through
|
84
|
-
expect(klass.new).to be_an_instance_of(klass)
|
85
|
-
expect(spy).to have_been_called
|
86
|
-
end
|
87
|
-
|
88
|
-
it "works for instance methods defined on the object's class's superclass" do
|
89
|
-
subclass = Class.new(klass)
|
90
|
-
inst = subclass.new
|
91
|
-
spy = Spy.on(inst, :meth_1).and_call_through
|
92
|
-
expect(inst.meth_1).to eq(:original)
|
93
|
-
expect(spy).to have_been_called
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'works for aliased methods' do
|
97
|
-
klass = Class.new do
|
98
|
-
class << self
|
99
|
-
alias alternate_new new
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
spy = Spy.on(klass, :alternate_new).and_call_through
|
104
|
-
expect(klass.alternate_new).to be_an_instance_of(klass)
|
105
|
-
expect(spy).to have_been_called
|
106
|
-
end
|
107
|
-
|
108
|
-
context 'on an object that defines method_missing' do
|
109
|
-
before do
|
110
|
-
klass.class_eval do
|
111
|
-
def respond_to_missing?(name, _)
|
112
|
-
if name.to_s == "greet_jack"
|
113
|
-
true
|
114
|
-
else
|
115
|
-
super
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def method_missing(name, *args)
|
120
|
-
if name.to_s == "greet_jack"
|
121
|
-
"Hello, jack"
|
122
|
-
else
|
123
|
-
super
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'works when the method_missing definition handles the message' do
|
130
|
-
spy = Spy.on(instance, :greet_jack).and_call_through
|
131
|
-
expect(instance.greet_jack).to eq("Hello, jack")
|
132
|
-
expect(spy).to have_been_called
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'raises an error on invocation if method_missing does not handle the message' do
|
136
|
-
Spy::Subroutine.new(instance, :not_a_handled_message).hook(force: true).and_call_through
|
137
|
-
|
138
|
-
# Note: it should raise a NoMethodError (and usually does), but
|
139
|
-
# due to a weird rspec-expectations issue (see #183) it sometimes
|
140
|
-
# raises a `NameError` when a `be_xxx` predicate matcher has been
|
141
|
-
# recently used. `NameError` is the superclass of `NoMethodError`
|
142
|
-
# so this example will pass regardless.
|
143
|
-
# If/when we solve the rspec-expectations issue, this can (and should)
|
144
|
-
# be changed to `NoMethodError`.
|
145
|
-
expect {
|
146
|
-
instance.not_a_handled_message
|
147
|
-
}.to raise_error(NameError, /not_a_handled_message/)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
data/spec/spy/and_yield_spec.rb
DELETED
@@ -1,123 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Spy" do
|
4
|
-
|
5
|
-
class Foo
|
6
|
-
def method_that_accepts_a_block(&block)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:obj) { Foo.new }
|
11
|
-
|
12
|
-
describe "#and_yield" do
|
13
|
-
context "with eval context as block argument" do
|
14
|
-
|
15
|
-
it "evaluates the supplied block as it is read" do
|
16
|
-
evaluated = false
|
17
|
-
Spy.on(obj, :method_that_accepts_a_block).and_yield do |eval_context|
|
18
|
-
evaluated = true
|
19
|
-
end
|
20
|
-
expect(evaluated).to be_true
|
21
|
-
end
|
22
|
-
|
23
|
-
it "passes an eval context object to the supplied block" do
|
24
|
-
Spy.on(obj, :method_that_accepts_a_block).and_yield do |eval_context|
|
25
|
-
expect(eval_context).not_to be_nil
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
it "evaluates the block passed to the stubbed method in the context of the supplied eval context" do
|
30
|
-
expected_eval_context = nil
|
31
|
-
actual_eval_context = nil
|
32
|
-
|
33
|
-
Spy.on(obj, :method_that_accepts_a_block).and_yield do |eval_context|
|
34
|
-
expected_eval_context = eval_context
|
35
|
-
end
|
36
|
-
|
37
|
-
obj.method_that_accepts_a_block do
|
38
|
-
actual_eval_context = self
|
39
|
-
end
|
40
|
-
|
41
|
-
expect(actual_eval_context).to equal(expected_eval_context)
|
42
|
-
end
|
43
|
-
|
44
|
-
context "and no yielded arguments" do
|
45
|
-
|
46
|
-
it "passes when expectations set on the eval context are met" do
|
47
|
-
configured_eval_context = nil
|
48
|
-
context_foo_spy = nil
|
49
|
-
Spy.on(obj, :method_that_accepts_a_block).and_yield do |eval_context|
|
50
|
-
configured_eval_context = eval_context
|
51
|
-
context_foo_spy = Spy::Subroutine.new(configured_eval_context, :foo).hook(force: true)
|
52
|
-
end
|
53
|
-
|
54
|
-
obj.method_that_accepts_a_block do
|
55
|
-
foo
|
56
|
-
end
|
57
|
-
|
58
|
-
expect(context_foo_spy).to have_been_called
|
59
|
-
end
|
60
|
-
|
61
|
-
it "fails when expectations set on the eval context are not met" do
|
62
|
-
configured_eval_context = nil
|
63
|
-
context_foo_spy = nil
|
64
|
-
Spy.on(obj, :method_that_accepts_a_block).and_yield do |eval_context|
|
65
|
-
configured_eval_context = eval_context
|
66
|
-
context_foo_spy = Spy::Subroutine.new(configured_eval_context, :foo).hook(force: true)
|
67
|
-
end
|
68
|
-
|
69
|
-
obj.method_that_accepts_a_block do
|
70
|
-
# foo is not called here
|
71
|
-
end
|
72
|
-
|
73
|
-
expect(context_foo_spy).to_not have_been_called
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
context "and yielded arguments" do
|
79
|
-
|
80
|
-
it "passes when expectations set on the eval context and yielded arguments are met" do
|
81
|
-
configured_eval_context = nil
|
82
|
-
yielded_arg = Object.new
|
83
|
-
context_foo_spy = nil
|
84
|
-
Spy.on(obj, :method_that_accepts_a_block).and_yield(yielded_arg) do |eval_context|
|
85
|
-
configured_eval_context = eval_context
|
86
|
-
context_foo_spy = Spy::Subroutine.new(configured_eval_context, :foo).hook(force: true)
|
87
|
-
Spy::Subroutine.new(yielded_arg, :bar).hook(force: true)
|
88
|
-
end
|
89
|
-
|
90
|
-
obj.method_that_accepts_a_block do |obj|
|
91
|
-
obj.bar
|
92
|
-
foo
|
93
|
-
end
|
94
|
-
|
95
|
-
expect(context_foo_spy).to have_been_called
|
96
|
-
expect(Spy.get(yielded_arg, :bar)).to have_been_called
|
97
|
-
end
|
98
|
-
|
99
|
-
it "fails when expectations set on the eval context and yielded arguments are not met" do
|
100
|
-
configured_eval_context = nil
|
101
|
-
yielded_arg = Object.new
|
102
|
-
context_foo_spy = nil
|
103
|
-
Spy.on(obj, :method_that_accepts_a_block).and_yield(yielded_arg) do |eval_context|
|
104
|
-
configured_eval_context = eval_context
|
105
|
-
context_foo_spy = Spy::Subroutine.new(configured_eval_context, :foo).hook(force: true)
|
106
|
-
Spy::Subroutine.new(yielded_arg, :bar).hook(force: true)
|
107
|
-
end
|
108
|
-
|
109
|
-
obj.method_that_accepts_a_block do |obj|
|
110
|
-
# obj.bar is not called here
|
111
|
-
# foo is not called here
|
112
|
-
end
|
113
|
-
|
114
|
-
expect(context_foo_spy).to_not have_been_called
|
115
|
-
expect(Spy.get(yielded_arg, :bar)).to_not have_been_called
|
116
|
-
end
|
117
|
-
|
118
|
-
end
|
119
|
-
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|