grift 1.0.2 → 2.0.1
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/dependabot.yml +3 -1
- data/.github/workflows/ci.yml +12 -2
- data/.overcommit.yml +8 -0
- data/.rubocop.yml +15 -0
- data/CHANGELOG.md +48 -14
- data/Gemfile +2 -0
- data/Gemfile.lock +24 -14
- data/README.md +28 -5
- data/grift.gemspec +3 -2
- data/lib/grift/mock_method/mock_executions/mock_arguments.rb +166 -0
- data/lib/grift/mock_method/mock_executions.rb +13 -9
- data/lib/grift/mock_method.rb +51 -27
- data/lib/grift/version.rb +1 -1
- data/lib/grift.rb +1 -0
- metadata +7 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '06800e91cb7e76be9232c7cf700d99ede4ba25212ed323abd1d5a4e944de455d'
|
|
4
|
+
data.tar.gz: 2d844fc80a5edcb9eb809c4946d7ee464465e8423b7a42e2f3a4ff4657e791d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c3a2e6a02bab0921a5c91c48c5fbbf67d1a9dd0b0d50bd3c4d9dfb49d6f686623ca0c017d1d51f1df3220b4c1c83c1fd9a26070daa05c36c38d657a2476a4602
|
|
7
|
+
data.tar.gz: a7197e5fb4f7bbaf506426c9f4ed2a04733201f8a27a4f015df9af7466c9bd8563e700c2adaaef34211690c5ecf795ded15308701877bd5a0fbb6ed5278b366a
|
data/.github/dependabot.yml
CHANGED
data/.github/workflows/ci.yml
CHANGED
|
@@ -3,6 +3,7 @@ name: CI
|
|
|
3
3
|
on: push
|
|
4
4
|
|
|
5
5
|
env:
|
|
6
|
+
CI: true
|
|
6
7
|
GIT_COMMIT_SHA: ${{ github.sha }}
|
|
7
8
|
GIT_BRANCH: ${{ github.ref }}
|
|
8
9
|
|
|
@@ -26,13 +27,13 @@ jobs:
|
|
|
26
27
|
run: bundle exec rubocop --format progress
|
|
27
28
|
|
|
28
29
|
build:
|
|
29
|
-
needs: [
|
|
30
|
+
needs: [linting]
|
|
30
31
|
runs-on: ubuntu-latest
|
|
31
32
|
name: build (ruby v${{ matrix.ruby }})
|
|
32
33
|
strategy:
|
|
33
34
|
fail-fast: false
|
|
34
35
|
matrix:
|
|
35
|
-
ruby: [
|
|
36
|
+
ruby: ["2.7", "3.0", "3.1"]
|
|
36
37
|
|
|
37
38
|
steps:
|
|
38
39
|
- uses: actions/checkout@v2
|
|
@@ -44,3 +45,12 @@ jobs:
|
|
|
44
45
|
- name: Test
|
|
45
46
|
continue-on-error: ${{ matrix.experimental }}
|
|
46
47
|
run: bundle exec rake test
|
|
48
|
+
|
|
49
|
+
- name: Upload coverage to Codecov
|
|
50
|
+
uses: codecov/codecov-action@v2
|
|
51
|
+
with:
|
|
52
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
53
|
+
files: ./coverage/.resultset.json
|
|
54
|
+
name: codecov-umbrella
|
|
55
|
+
verbose: true
|
|
56
|
+
fail_ci_if_error: true
|
data/.overcommit.yml
ADDED
data/.rubocop.yml
CHANGED
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
#
|
|
10
10
|
# See https://docs.rubocop.org/rubocop/configuration
|
|
11
11
|
|
|
12
|
+
require:
|
|
13
|
+
- rubocop-minitest
|
|
14
|
+
- rubocop-packaging
|
|
15
|
+
- rubocop-performance
|
|
16
|
+
|
|
12
17
|
# General
|
|
13
18
|
AllCops:
|
|
14
19
|
NewCops: enable
|
|
@@ -119,6 +124,16 @@ Metrics/MethodLength:
|
|
|
119
124
|
Exclude:
|
|
120
125
|
- "test/**/*"
|
|
121
126
|
|
|
127
|
+
# Minitest
|
|
128
|
+
Minitest/AssertPredicate:
|
|
129
|
+
Enabled: false
|
|
130
|
+
|
|
131
|
+
Minitest/MultipleAssertions:
|
|
132
|
+
Max: 10
|
|
133
|
+
|
|
134
|
+
Minitest/RefutePredicate:
|
|
135
|
+
Enabled: false
|
|
136
|
+
|
|
122
137
|
# Naming
|
|
123
138
|
Naming/InclusiveLanguage:
|
|
124
139
|
Enabled: true
|
data/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,46 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
None
|
|
10
|
+
|
|
11
|
+
## [2.0.1](https://github.com/clarkedb/grift/releases/tag/v2.0.1) - 2022-03-27
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
* When spying on a method that takes a block, the block now gets forwarded to the original method ([#78](https://github.com/clarkedb/grift/pull/78))
|
|
16
|
+
* When mocking the implementation, if a block is not provided a `Grift::Error` is raised instead of a `LocalJumpError` ([#77](https://github.com/clarkedb/grift/pull/77))
|
|
17
|
+
|
|
18
|
+
## [2.0.0](https://github.com/clarkedb/grift/releases/tag/v2.0.0) - 2022-03-14
|
|
19
|
+
|
|
20
|
+
This version adds true keyword argument support for Ruby 3. See below for how to handle breaking changes.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
* Dropped support for Ruby 2.5 ([#69](https://github.com/clarkedb/grift/pull/69))
|
|
25
|
+
* Dropped support for Ruby 2.6 ([#72](https://github.com/clarkedb/grift/pull/72))
|
|
26
|
+
* To support keyword arguments, records of call arguments are no longer stored in simple arrays but in a custom Enumerable ([#72](https://github.com/clarkedb/grift/pull/72))
|
|
27
|
+
+ This changes the way that your tests will interact with mock calls
|
|
28
|
+
+ When before `calls` returned an array, it returns a `Grift::MockMethod::MockExecutions::MockArguments` object
|
|
29
|
+
+ Migrating to maintain previous behavior just requires appending `.args` to `calls[i]`
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
* Support for mocking private instance and class methods ([#68](https://github.com/clarkedb/grift/pull/68))
|
|
34
|
+
* Support for mocking methods that take positional and keyword arguments ([#72](https://github.com/clarkedb/grift/pull/72))
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
* When mocking protected methods, the method now remains protected while mocked and after unmocking ([#68](https://github.com/clarkedb/grift/pull/68))
|
|
39
|
+
* When mocking inherited methods, the method goes back to the ancestor's definition after unmocking ([#69](https://github.com/clarkedb/grift/pull/69))
|
|
40
|
+
* When mocking methods with keyword arugments in Ruby 3.x, no error is thrown ([#72](https://github.com/clarkedb/grift/pull/72))
|
|
41
|
+
|
|
42
|
+
## [1.1.0](https://github.com/clarkedb/grift/releases/tag/v1.1.0) - 2022-02-03
|
|
43
|
+
|
|
44
|
+
This version adds support for Ruby 3.1 and updates various dependencies.
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
* Support Ruby 3.1 ([#52](https://github.com/clarkedb/grift/pull/52))
|
|
10
49
|
|
|
11
50
|
## [1.0.2](https://github.com/clarkedb/grift/releases/tag/v1.0.2) - 2021-11-11
|
|
12
51
|
|
|
@@ -14,7 +53,7 @@ This version fixes a bug that prevented the mocking of methods defined by a clas
|
|
|
14
53
|
|
|
15
54
|
### Fixed
|
|
16
55
|
|
|
17
|
-
* Allow mocks of inherited methods
|
|
56
|
+
* Allow mocks of inherited methods ([#34](https://github.com/clarkedb/grift/pull/34))
|
|
18
57
|
|
|
19
58
|
## [1.0.1](https://github.com/clarkedb/grift/releases/tag/v1.0.1) - 2021-11-10
|
|
20
59
|
|
|
@@ -22,12 +61,7 @@ This version fixes a bug that prevented most mocking features in Grift from func
|
|
|
22
61
|
|
|
23
62
|
### Fixed
|
|
24
63
|
|
|
25
|
-
* Uses relative path for yaml config files
|
|
26
|
-
|
|
27
|
-
### Updated
|
|
28
|
-
|
|
29
|
-
* Updates `rubocop-performance`
|
|
30
|
-
* Updates `rake`
|
|
64
|
+
* Uses relative path for yaml config files ([#28](https://github.com/clarkedb/grift/pull/28))
|
|
31
65
|
|
|
32
66
|
## [1.0.0](https://github.com/clarkedb/grift/releases/tag/v1.0.0) - 2021-11-06
|
|
33
67
|
|
|
@@ -35,12 +69,12 @@ The first major version of Grift! 100% documentation and 100% code coverage.
|
|
|
35
69
|
|
|
36
70
|
### Added
|
|
37
71
|
|
|
38
|
-
* Spying on method
|
|
39
|
-
* Mocking method return values
|
|
40
|
-
* Mocking method implementation
|
|
41
|
-
* Restricted methods that cannot be mocked
|
|
42
|
-
* MiniTest Plugin to use hooks and clean up after tests
|
|
43
|
-
* Documentation!
|
|
72
|
+
* Spying on method ([#9](https://github.com/clarkedb/grift/pull/9))
|
|
73
|
+
* Mocking method return values ([#9](https://github.com/clarkedb/grift/pull/9))
|
|
74
|
+
* Mocking method implementation ([#13](https://github.com/clarkedb/grift/pull/13))
|
|
75
|
+
* Restricted methods that cannot be mocked ([#20](https://github.com/clarkedb/grift/pull/20))
|
|
76
|
+
* MiniTest Plugin to use hooks and clean up after tests ([#17](https://github.com/clarkedb/grift/pull/17))
|
|
77
|
+
* Documentation! ([#23](https://github.com/clarkedb/grift/pull/23))
|
|
44
78
|
|
|
45
79
|
## [0.1.0](https://github.com/clarkedb/grift/releases/tag/v0.1.0) - 2021-10-12
|
|
46
80
|
|
data/Gemfile
CHANGED
|
@@ -8,12 +8,14 @@ gemspec
|
|
|
8
8
|
gem 'rake', '>= 12.0'
|
|
9
9
|
|
|
10
10
|
group :development, :test do
|
|
11
|
+
gem 'codecov'
|
|
11
12
|
gem 'minitest', '>= 5.0'
|
|
12
13
|
gem 'minitest-reporters', '>= 1.4.3'
|
|
13
14
|
gem 'simplecov', '>= 0.21.2'
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
group :development, :lint do
|
|
18
|
+
gem 'overcommit'
|
|
17
19
|
gem 'rubocop'
|
|
18
20
|
gem 'rubocop-minitest'
|
|
19
21
|
gem 'rubocop-packaging', '>= 0.5'
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
grift (
|
|
4
|
+
grift (2.0.1)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
@@ -9,36 +9,44 @@ GEM
|
|
|
9
9
|
ansi (1.5.0)
|
|
10
10
|
ast (2.4.2)
|
|
11
11
|
builder (3.2.4)
|
|
12
|
+
childprocess (4.1.0)
|
|
13
|
+
codecov (0.6.0)
|
|
14
|
+
simplecov (>= 0.15, < 0.22)
|
|
12
15
|
docile (1.4.0)
|
|
13
|
-
|
|
14
|
-
minitest
|
|
16
|
+
iniparse (1.5.0)
|
|
17
|
+
minitest (5.15.0)
|
|
18
|
+
minitest-reporters (1.5.0)
|
|
15
19
|
ansi
|
|
16
20
|
builder
|
|
17
21
|
minitest (>= 5.0)
|
|
18
22
|
ruby-progressbar
|
|
23
|
+
overcommit (0.58.0)
|
|
24
|
+
childprocess (>= 0.6.3, < 5)
|
|
25
|
+
iniparse (~> 1.4)
|
|
26
|
+
rexml (~> 3.2)
|
|
19
27
|
parallel (1.21.0)
|
|
20
|
-
parser (3.
|
|
28
|
+
parser (3.1.1.0)
|
|
21
29
|
ast (~> 2.4.1)
|
|
22
|
-
rainbow (3.
|
|
30
|
+
rainbow (3.1.1)
|
|
23
31
|
rake (13.0.6)
|
|
24
|
-
regexp_parser (2.
|
|
32
|
+
regexp_parser (2.2.1)
|
|
25
33
|
rexml (3.2.5)
|
|
26
|
-
rubocop (1.
|
|
34
|
+
rubocop (1.26.0)
|
|
27
35
|
parallel (~> 1.10)
|
|
28
|
-
parser (>= 3.
|
|
36
|
+
parser (>= 3.1.0.0)
|
|
29
37
|
rainbow (>= 2.2.2, < 4.0)
|
|
30
38
|
regexp_parser (>= 1.8, < 3.0)
|
|
31
39
|
rexml
|
|
32
|
-
rubocop-ast (>= 1.
|
|
40
|
+
rubocop-ast (>= 1.16.0, < 2.0)
|
|
33
41
|
ruby-progressbar (~> 1.7)
|
|
34
42
|
unicode-display_width (>= 1.4.0, < 3.0)
|
|
35
|
-
rubocop-ast (1.
|
|
36
|
-
parser (>= 3.
|
|
37
|
-
rubocop-minitest (0.
|
|
43
|
+
rubocop-ast (1.16.0)
|
|
44
|
+
parser (>= 3.1.1.0)
|
|
45
|
+
rubocop-minitest (0.18.0)
|
|
38
46
|
rubocop (>= 0.90, < 2.0)
|
|
39
47
|
rubocop-packaging (0.5.1)
|
|
40
48
|
rubocop (>= 0.89, < 2.0)
|
|
41
|
-
rubocop-performance (1.
|
|
49
|
+
rubocop-performance (1.13.3)
|
|
42
50
|
rubocop (>= 1.7.0, < 2.0)
|
|
43
51
|
rubocop-ast (>= 0.4.0)
|
|
44
52
|
ruby-progressbar (1.11.0)
|
|
@@ -54,9 +62,11 @@ PLATFORMS
|
|
|
54
62
|
ruby
|
|
55
63
|
|
|
56
64
|
DEPENDENCIES
|
|
65
|
+
codecov
|
|
57
66
|
grift!
|
|
58
67
|
minitest (>= 5.0)
|
|
59
68
|
minitest-reporters (>= 1.4.3)
|
|
69
|
+
overcommit
|
|
60
70
|
rake (>= 12.0)
|
|
61
71
|
rubocop
|
|
62
72
|
rubocop-minitest
|
|
@@ -65,4 +75,4 @@ DEPENDENCIES
|
|
|
65
75
|
simplecov (>= 0.21.2)
|
|
66
76
|
|
|
67
77
|
BUNDLED WITH
|
|
68
|
-
2.
|
|
78
|
+
2.2.32
|
data/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[](https://rubygems.org/gems/grift)
|
|
4
4
|
[](https://rubygems.org/gems/grift)
|
|
5
5
|
[](https://github.com/clarkedb/grift/actions?query=workflow%3ACI)
|
|
6
|
+
[](https://codecov.io/gh/clarkedb/grift)
|
|
6
7
|
|
|
7
8
|
Mocking and spying in Ruby's MiniTest framework
|
|
8
9
|
|
|
@@ -77,13 +78,23 @@ my_spy.mock_implementation do |arg1, arg2|
|
|
|
77
78
|
end
|
|
78
79
|
```
|
|
79
80
|
|
|
81
|
+
or for a method taking keyword arguments:
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
my_spy = Grift.spy_on(MyClass, :my_method)
|
|
85
|
+
my_spy.mock_implementation do |arg1, arg2, **kwargs|
|
|
86
|
+
x = do_something(arg1, arg2, kwargs[:arg3], kwargs[:arg4])
|
|
87
|
+
do_something_else(x) # the last line will be returned
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
80
91
|
### Chaining
|
|
81
92
|
|
|
82
93
|
You can chain `mock_return_value` and `mock_implementation` after initializing the mock.
|
|
83
94
|
|
|
84
95
|
```ruby
|
|
85
|
-
my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |*args|
|
|
86
|
-
do_something(*args)
|
|
96
|
+
my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |*args, **kwargs|
|
|
97
|
+
do_something(*args, **kwargs)
|
|
87
98
|
end
|
|
88
99
|
#=> Grift::MockMethod object is returned
|
|
89
100
|
```
|
|
@@ -98,19 +109,31 @@ my_mock.mock.count
|
|
|
98
109
|
#=> 2
|
|
99
110
|
|
|
100
111
|
# get args for each call to the method while mocked
|
|
101
|
-
my_mock.mock.calls
|
|
102
|
-
#=> [
|
|
112
|
+
my_mock.mock.calls[0].args
|
|
113
|
+
#=> ['first_arg1', 'second_arg1']
|
|
114
|
+
|
|
115
|
+
# get kwargs for each call to the method while mocked
|
|
116
|
+
my_mock.mock.calls[0].kwargs
|
|
117
|
+
#=> { first_arg1: 'value' }
|
|
103
118
|
|
|
104
119
|
# get results (return value) for each call to the method while mocked
|
|
105
120
|
my_mock.mock.results
|
|
106
121
|
#=> ['result1', 'result2']
|
|
107
122
|
```
|
|
108
123
|
|
|
124
|
+
## Requirements
|
|
125
|
+
|
|
126
|
+
Grift supports all Ruby versions >= 2.7 (including 3.1).
|
|
127
|
+
|
|
109
128
|
## Development
|
|
110
129
|
|
|
111
130
|
After forking the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
112
131
|
|
|
113
|
-
When developing, to install Grift whith your changes onto your local machine, run `bundle exec rake install` .
|
|
132
|
+
When developing, to install Grift whith your changes onto your local machine, run `bundle exec rake install` . For those with write access: to release a new version, update the version number in `version.rb` , and then run `bundle exec rake release` , which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
133
|
+
|
|
134
|
+
### Docs
|
|
135
|
+
|
|
136
|
+
The docs are generated using YARD. To build the docs, first `gem install yard` . Then run `yardoc` to build the new docs. This is always done before a release to update the docs that get published and made available with the gem.
|
|
114
137
|
|
|
115
138
|
## Contributing
|
|
116
139
|
|
data/grift.gemspec
CHANGED
|
@@ -12,20 +12,21 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.description = "A gem for simple mocking and spying in Ruby's MiniTest framework."
|
|
13
13
|
spec.homepage = 'https://github.com/clarkedb/grift'
|
|
14
14
|
spec.license = 'MIT'
|
|
15
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 2.
|
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
|
|
16
16
|
|
|
17
17
|
spec.metadata = {
|
|
18
18
|
'bug_tracker_uri' => "#{spec.homepage}/issues",
|
|
19
19
|
'changelog_uri' => "#{spec.homepage}/blob/main/CHANGELOG.md",
|
|
20
20
|
'documentation_uri' => spec.homepage.to_s,
|
|
21
21
|
'homepage_uri' => spec.homepage.to_s,
|
|
22
|
+
'rubygems_mfa_required' => 'true',
|
|
22
23
|
'source_code_uri' => spec.homepage.to_s
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
# Specify which files should be added to the gem when it is released.
|
|
26
27
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
27
28
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
28
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|docs|spec|features)/}) }
|
|
29
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|docs|spec|features)/}) } # rubocop:disable Packaging/GemspecGit
|
|
29
30
|
end
|
|
30
31
|
spec.bindir = 'exe'
|
|
31
32
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grift
|
|
4
|
+
class MockMethod
|
|
5
|
+
class MockExecutions
|
|
6
|
+
##
|
|
7
|
+
# An immutable Enumerable that stores the arguments used in a call for {Grift::MockMethod::MockExecutions}.
|
|
8
|
+
#
|
|
9
|
+
class MockArguments
|
|
10
|
+
include Enumerable
|
|
11
|
+
|
|
12
|
+
attr_reader :args, :kwargs
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# A new instance of MockArguments.
|
|
16
|
+
#
|
|
17
|
+
# @return [Grift::MockMethod::MockExecutions::MockArguments]
|
|
18
|
+
#
|
|
19
|
+
def initialize(args: [], kwargs: {})
|
|
20
|
+
@args = args.freeze
|
|
21
|
+
@kwargs = kwargs.freeze
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# Retrieves a stored argument by an accessor. For positional arguments this would be an integer
|
|
26
|
+
# corresponding to the arguments position in the method call signature. For keyword arguments
|
|
27
|
+
# this would be the key / parameter name as a symbol or string.
|
|
28
|
+
#
|
|
29
|
+
# @example
|
|
30
|
+
# my_mock = Grift.mock(Request, :new)
|
|
31
|
+
# request = Request.new('/users', method: 'GET')
|
|
32
|
+
# #=> <Request object>
|
|
33
|
+
# my_mock.mock.calls.last[0] # integer access for positional
|
|
34
|
+
# #=> '/users'
|
|
35
|
+
# my_mock.mock.calls.last[:method] # key access for keyword
|
|
36
|
+
# #=> 'GET'
|
|
37
|
+
#
|
|
38
|
+
# @param index [Integer, Symbol, String] the accessor for the desired argument
|
|
39
|
+
#
|
|
40
|
+
# @raise [Grift::Error] exception if accessor is not a supported type
|
|
41
|
+
#
|
|
42
|
+
# @return the specified value
|
|
43
|
+
#
|
|
44
|
+
def [](index)
|
|
45
|
+
if index.instance_of?(Integer)
|
|
46
|
+
@args[index]
|
|
47
|
+
elsif index.instance_of?(Symbol)
|
|
48
|
+
@kwargs[index]
|
|
49
|
+
elsif index.instance_of?(String)
|
|
50
|
+
@kwargs[index.to_sym]
|
|
51
|
+
else
|
|
52
|
+
raise(Grift::Error, "Cannot access by type '#{index.class}'. Expected an Integer, Symbol, or String")
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
# Calls the given block once for each argument value, passing that value
|
|
58
|
+
# as a parameter.
|
|
59
|
+
#
|
|
60
|
+
# @return [void]
|
|
61
|
+
#
|
|
62
|
+
def each(&block)
|
|
63
|
+
@args.each(&block)
|
|
64
|
+
@kwargs.each_value(&block)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
##
|
|
68
|
+
# @see Enumerable#first
|
|
69
|
+
#
|
|
70
|
+
# Returns the last argument passed in the call.
|
|
71
|
+
#
|
|
72
|
+
# @example
|
|
73
|
+
# my_mock = Grift.mock(Request, :new)
|
|
74
|
+
# request = Request.new('/users', method: 'GET')
|
|
75
|
+
# #=> <Request object>
|
|
76
|
+
# my_mock.mock.calls.last.last
|
|
77
|
+
# #=> 'GET'
|
|
78
|
+
#
|
|
79
|
+
# @return [Any]
|
|
80
|
+
#
|
|
81
|
+
def last
|
|
82
|
+
@args.last || @kwargs.values.last
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
##
|
|
86
|
+
# Returns the number of arguments passed in the call.
|
|
87
|
+
#
|
|
88
|
+
# @example
|
|
89
|
+
# arr = [1, 2, 3]
|
|
90
|
+
# my_mock = Grift.mock(Array, :count)
|
|
91
|
+
# arr.count
|
|
92
|
+
# #=> 3
|
|
93
|
+
# my_mock.mock.calls.last.length
|
|
94
|
+
# #=> 0
|
|
95
|
+
# arr.count(3)
|
|
96
|
+
# #=> 1
|
|
97
|
+
# my_mock.mock.calls.last.length
|
|
98
|
+
# #=> 1
|
|
99
|
+
#
|
|
100
|
+
# @return [Integer]
|
|
101
|
+
#
|
|
102
|
+
def length
|
|
103
|
+
@args.length + @kwargs.length
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
# Returns true if the call included no arguments.
|
|
108
|
+
#
|
|
109
|
+
# @example
|
|
110
|
+
# arr = [1, 2, 3]
|
|
111
|
+
# my_mock = Grift.mock(Array, :count)
|
|
112
|
+
# arr.count
|
|
113
|
+
# #=> 3
|
|
114
|
+
# my_mock.mock.calls.last.empty?
|
|
115
|
+
# #=> true
|
|
116
|
+
# arr.count(2)
|
|
117
|
+
# #=> 1
|
|
118
|
+
# my_mock.mock.calls.last.empty?
|
|
119
|
+
# #=> false
|
|
120
|
+
#
|
|
121
|
+
# @return [Boolean] true if the no arguments were used
|
|
122
|
+
#
|
|
123
|
+
def empty?
|
|
124
|
+
@args.empty? && @kwargs.empty?
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
##
|
|
128
|
+
# Returns the keyword parameter keys passed in the call.
|
|
129
|
+
#
|
|
130
|
+
# To get the values, use {Grift::MockMethod::MockExecutions::MockArguments#values}.
|
|
131
|
+
#
|
|
132
|
+
# @example
|
|
133
|
+
# my_mock = Grift.mock(Request, :new)
|
|
134
|
+
# request = Request.new('/users', method: 'GET')
|
|
135
|
+
# #=> <Request object>
|
|
136
|
+
# my_mock.mock.calls.last.keys
|
|
137
|
+
# #=> [:method]
|
|
138
|
+
#
|
|
139
|
+
# @return [Array<Symbol>] the parameter keys
|
|
140
|
+
#
|
|
141
|
+
def keys
|
|
142
|
+
@kwargs.keys
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
##
|
|
146
|
+
# Returns the arguments passed in the call.
|
|
147
|
+
#
|
|
148
|
+
# If a keyword argument was used, then only the value will be returned.
|
|
149
|
+
# To get the keys, use {Grift::MockMethod::MockExecutions::MockArguments#keys}.
|
|
150
|
+
#
|
|
151
|
+
# @example
|
|
152
|
+
# my_mock = Grift.mock(Request, :new)
|
|
153
|
+
# request = Request.new('/users', method: 'GET')
|
|
154
|
+
# #=> <Request object>
|
|
155
|
+
# my_mock.mock.calls.last.keys
|
|
156
|
+
# #=> [:method]
|
|
157
|
+
#
|
|
158
|
+
# @return [Array] the argument values
|
|
159
|
+
#
|
|
160
|
+
def values
|
|
161
|
+
@args + @kwargs.values
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -9,7 +9,7 @@ module Grift
|
|
|
9
9
|
##
|
|
10
10
|
# A new instance of MockExecutions.
|
|
11
11
|
#
|
|
12
|
-
# @return [Grift::MockMethod::
|
|
12
|
+
# @return [Grift::MockMethod::MockExecutions]
|
|
13
13
|
#
|
|
14
14
|
def initialize
|
|
15
15
|
@executions = []
|
|
@@ -21,14 +21,14 @@ module Grift
|
|
|
21
21
|
# @example
|
|
22
22
|
# my_mock = Grift.spy_on(Number, :+)
|
|
23
23
|
# x = (3 + 4) + 5
|
|
24
|
-
# my_mock.mock.calls
|
|
24
|
+
# my_mock.mock.calls.map(&:values)
|
|
25
25
|
# #=> [[4], [5]]
|
|
26
26
|
#
|
|
27
|
-
# @return [Array<
|
|
27
|
+
# @return [Array<Grift::MockMethod::MockExecutions::MockArguments>] an array of MockArguments
|
|
28
28
|
#
|
|
29
29
|
def calls
|
|
30
30
|
@executions.map do |exec|
|
|
31
|
-
exec[:
|
|
31
|
+
exec[:arguments]
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -89,13 +89,17 @@ module Grift
|
|
|
89
89
|
# Stores an args and result pair to the executions array.
|
|
90
90
|
#
|
|
91
91
|
# @example
|
|
92
|
-
#
|
|
93
|
-
#
|
|
92
|
+
# mock_executions = Grift::MockMethod::MockExecutions.new
|
|
93
|
+
# mock_executions.store(args: [1, 1], kwargs: { test: true }, result: 2)
|
|
94
94
|
#
|
|
95
|
-
# @
|
|
95
|
+
# @param args [Array] the postitional args to store
|
|
96
|
+
# @param kwargs [Hash] the keyword args to store
|
|
97
|
+
# @param result the method result to store
|
|
98
|
+
#
|
|
99
|
+
# @return [Array] an updated array of executions
|
|
96
100
|
#
|
|
97
|
-
def store(args, result)
|
|
98
|
-
@executions.push({ args: args, result: result })
|
|
101
|
+
def store(args: [], kwargs: {}, result: nil)
|
|
102
|
+
@executions.push({ arguments: MockArguments.new(args: args, kwargs: kwargs), result: result })
|
|
99
103
|
end
|
|
100
104
|
end
|
|
101
105
|
end
|
data/lib/grift/mock_method.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Grift
|
|
|
6
6
|
# usually returns a {Grift::MockMethod}.
|
|
7
7
|
#
|
|
8
8
|
class MockMethod
|
|
9
|
-
attr_reader :true_method_cached, :klass, :method_name
|
|
9
|
+
attr_reader :true_method_cached, :klass, :method_name, :method_access
|
|
10
10
|
|
|
11
11
|
CACHE_METHOD_PREFIX = 'grift_cache'
|
|
12
12
|
private_constant :CACHE_METHOD_PREFIX
|
|
@@ -39,13 +39,13 @@ module Grift
|
|
|
39
39
|
@cache_method_name = "#{CACHE_METHOD_PREFIX}_#{method_name}".to_sym
|
|
40
40
|
|
|
41
41
|
# class methods are really instance methods of the singleton class
|
|
42
|
-
@class_method = klass.singleton_class.
|
|
42
|
+
@class_method = klass.singleton_class.method_defined?(method_name, true) ||
|
|
43
|
+
klass.singleton_class.private_method_defined?(method_name, true)
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
end
|
|
45
|
+
@method_access, @inherited = method_access_definition
|
|
46
|
+
raise(Grift::Error, "Cannot mock unknown method #{method_name} for class #{klass}") unless @method_access
|
|
47
47
|
|
|
48
|
-
if class_instance.
|
|
48
|
+
if class_instance.method_defined?(@cache_method_name)
|
|
49
49
|
raise(Grift::Error, "Cannot mock already mocked method #{method_name} for class #{klass}")
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -125,26 +125,29 @@ module Grift
|
|
|
125
125
|
# #=> '7'
|
|
126
126
|
#
|
|
127
127
|
# @example
|
|
128
|
-
# my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |first, second|
|
|
129
|
-
# [second, first]
|
|
128
|
+
# my_mock = Grift.spy_on(MyClass, :my_method).mock_implementation do |first, second, **kwargs|
|
|
129
|
+
# [second, kwargs[:third], first]
|
|
130
130
|
# end
|
|
131
|
-
# MyClass.my_method(1, 2)
|
|
132
|
-
# #=> [2, 1]
|
|
131
|
+
# MyClass.my_method(1, 2, third: 3)
|
|
132
|
+
# #=> [2, 3, 1]
|
|
133
133
|
#
|
|
134
|
-
# @return [
|
|
134
|
+
# @return [self] the mock itself
|
|
135
135
|
#
|
|
136
|
-
def mock_implementation(
|
|
136
|
+
def mock_implementation(*)
|
|
137
|
+
raise(Grift::Error, 'Must provide a block for the new implementation') unless block_given?
|
|
138
|
+
|
|
137
139
|
premock_setup
|
|
138
140
|
mock_executions = @mock_executions # required to access inside class instance block
|
|
139
141
|
|
|
140
|
-
class_instance.remove_method(@method_name) if
|
|
141
|
-
class_instance.define_method @method_name do |*args|
|
|
142
|
-
return_value =
|
|
142
|
+
class_instance.remove_method(@method_name) if !@inherited && method_defined?
|
|
143
|
+
class_instance.define_method @method_name do |*args, **kwargs|
|
|
144
|
+
return_value = yield(*args, **kwargs)
|
|
143
145
|
|
|
144
146
|
# record the args passed in the call to the method and the result
|
|
145
|
-
mock_executions.store(args, return_value)
|
|
147
|
+
mock_executions.store(args: args, result: return_value)
|
|
146
148
|
return return_value
|
|
147
149
|
end
|
|
150
|
+
class_instance.send(@method_access, @method_name)
|
|
148
151
|
|
|
149
152
|
self
|
|
150
153
|
end
|
|
@@ -162,18 +165,19 @@ module Grift
|
|
|
162
165
|
#
|
|
163
166
|
# @param return_value the value to return from the method
|
|
164
167
|
#
|
|
165
|
-
# @return [
|
|
168
|
+
# @return [self] the mock itself
|
|
166
169
|
#
|
|
167
170
|
def mock_return_value(return_value = nil)
|
|
168
171
|
premock_setup
|
|
169
172
|
mock_executions = @mock_executions # required to access inside class instance block
|
|
170
173
|
|
|
171
|
-
class_instance.remove_method(@method_name) if method_defined?
|
|
172
|
-
class_instance.define_method @method_name do |*args|
|
|
174
|
+
class_instance.remove_method(@method_name) if !@inherited && method_defined?
|
|
175
|
+
class_instance.define_method @method_name do |*args, **kwargs|
|
|
173
176
|
# record the args passed in the call to the method and the result
|
|
174
|
-
mock_executions.store(args, return_value)
|
|
177
|
+
mock_executions.store(args: args, kwargs: kwargs, result: return_value)
|
|
175
178
|
return return_value
|
|
176
179
|
end
|
|
180
|
+
class_instance.send(@method_access, @method_name)
|
|
177
181
|
|
|
178
182
|
self
|
|
179
183
|
end
|
|
@@ -210,21 +214,22 @@ module Grift
|
|
|
210
214
|
##
|
|
211
215
|
# Watches the method without mocking its impelementation or return value.
|
|
212
216
|
#
|
|
213
|
-
# @return [
|
|
217
|
+
# @return [self] the mock itself
|
|
214
218
|
#
|
|
215
219
|
def watch_method
|
|
216
220
|
premock_setup
|
|
217
221
|
mock_executions = @mock_executions # required to access inside class instance block
|
|
218
222
|
cache_method_name = @cache_method_name
|
|
219
223
|
|
|
220
|
-
class_instance.remove_method(@method_name) if method_defined?
|
|
221
|
-
class_instance.define_method @method_name do |*args|
|
|
222
|
-
return_value = send(cache_method_name, *args)
|
|
224
|
+
class_instance.remove_method(@method_name) if !@inherited && method_defined?
|
|
225
|
+
class_instance.define_method @method_name do |*args, **kwargs, &block|
|
|
226
|
+
return_value = send(cache_method_name, *args, **kwargs, &block)
|
|
223
227
|
|
|
224
228
|
# record the args passed in the call to the method and the result
|
|
225
|
-
mock_executions.store(args, return_value)
|
|
229
|
+
mock_executions.store(args: args, kwargs: kwargs, result: return_value)
|
|
226
230
|
return return_value
|
|
227
231
|
end
|
|
232
|
+
class_instance.send(@method_access, @method_name)
|
|
228
233
|
|
|
229
234
|
self
|
|
230
235
|
end
|
|
@@ -238,7 +243,7 @@ module Grift
|
|
|
238
243
|
raise(Grift::Error, 'Method is not cached') unless @true_method_cached
|
|
239
244
|
|
|
240
245
|
class_instance.remove_method(@method_name) if method_defined?
|
|
241
|
-
class_instance.alias_method(@method_name, @cache_method_name)
|
|
246
|
+
class_instance.alias_method(@method_name, @cache_method_name) unless @inherited
|
|
242
247
|
class_instance.remove_method(@cache_method_name)
|
|
243
248
|
|
|
244
249
|
@true_method_cached = false
|
|
@@ -289,7 +294,26 @@ module Grift
|
|
|
289
294
|
# @return [Boolean]
|
|
290
295
|
#
|
|
291
296
|
def method_defined?
|
|
292
|
-
class_instance.instance_methods(false).include?(@method_name)
|
|
297
|
+
class_instance.instance_methods(false).include?(@method_name) ||
|
|
298
|
+
class_instance.private_instance_methods(false).include?(@method_name)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
##
|
|
302
|
+
# Checks for the original access of the method (public, protected, private),
|
|
303
|
+
# and if that definition is inherited from an ancestor (super) class.
|
|
304
|
+
# Returns `nil` if no definition for the method is found.
|
|
305
|
+
#
|
|
306
|
+
# @return [Symbol] the method access
|
|
307
|
+
# @return [Boolean] true if the method is inherited
|
|
308
|
+
#
|
|
309
|
+
def method_access_definition
|
|
310
|
+
if class_instance.public_method_defined?(@method_name, true)
|
|
311
|
+
[:public, !class_instance.public_method_defined?(@method_name, false)]
|
|
312
|
+
elsif class_instance.protected_method_defined?(@method_name, true)
|
|
313
|
+
[:protected, !class_instance.protected_method_defined?(@method_name, false)]
|
|
314
|
+
elsif class_instance.private_method_defined?(@method_name, true)
|
|
315
|
+
[:private, !class_instance.private_method_defined?(@method_name, false)]
|
|
316
|
+
end
|
|
293
317
|
end
|
|
294
318
|
end
|
|
295
319
|
end
|
data/lib/grift/version.rb
CHANGED
data/lib/grift.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: grift
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Clark Brown
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-03-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A gem for simple mocking and spying in Ruby's MiniTest framework.
|
|
14
14
|
email:
|
|
@@ -22,6 +22,7 @@ files:
|
|
|
22
22
|
- ".github/dependabot.yml"
|
|
23
23
|
- ".github/workflows/ci.yml"
|
|
24
24
|
- ".gitignore"
|
|
25
|
+
- ".overcommit.yml"
|
|
25
26
|
- ".rubocop.yml"
|
|
26
27
|
- ".yardopts"
|
|
27
28
|
- CHANGELOG.md
|
|
@@ -40,6 +41,7 @@ files:
|
|
|
40
41
|
- lib/grift/minitest_plugin.rb
|
|
41
42
|
- lib/grift/mock_method.rb
|
|
42
43
|
- lib/grift/mock_method/mock_executions.rb
|
|
44
|
+
- lib/grift/mock_method/mock_executions/mock_arguments.rb
|
|
43
45
|
- lib/grift/mock_store.rb
|
|
44
46
|
- lib/grift/version.rb
|
|
45
47
|
homepage: https://github.com/clarkedb/grift
|
|
@@ -50,6 +52,7 @@ metadata:
|
|
|
50
52
|
changelog_uri: https://github.com/clarkedb/grift/blob/main/CHANGELOG.md
|
|
51
53
|
documentation_uri: https://github.com/clarkedb/grift
|
|
52
54
|
homepage_uri: https://github.com/clarkedb/grift
|
|
55
|
+
rubygems_mfa_required: 'true'
|
|
53
56
|
source_code_uri: https://github.com/clarkedb/grift
|
|
54
57
|
post_install_message:
|
|
55
58
|
rdoc_options: []
|
|
@@ -59,14 +62,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
59
62
|
requirements:
|
|
60
63
|
- - ">="
|
|
61
64
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: 2.
|
|
65
|
+
version: 2.7.0
|
|
63
66
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
67
|
requirements:
|
|
65
68
|
- - ">="
|
|
66
69
|
- !ruby/object:Gem::Version
|
|
67
70
|
version: '0'
|
|
68
71
|
requirements: []
|
|
69
|
-
rubygems_version: 3.
|
|
72
|
+
rubygems_version: 3.2.32
|
|
70
73
|
signing_key:
|
|
71
74
|
specification_version: 4
|
|
72
75
|
summary: Mocking and spying in MiniTest
|