mocktail 1.2.0 → 1.2.2
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/.standard.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +20 -14
- data/README.md +4 -5
- data/bin/m +29 -0
- data/lib/mocktail/imitates_type/makes_double/declares_dry_class/reconstructs_call.rb +47 -0
- data/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb +26 -16
- data/lib/mocktail/raises_neato_no_method_error.rb +1 -1
- data/lib/mocktail/replaces_next.rb +1 -1
- data/lib/mocktail/share/determines_matching_calls.rb +1 -0
- data/lib/mocktail/simulates_argument_error/transforms_params.rb +17 -5
- data/lib/mocktail/stringifies_method_signature.rb +45 -0
- data/lib/mocktail/value/signature.rb +4 -1
- data/lib/mocktail/version.rb +1 -1
- data/lib/mocktail.rb +1 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d2944636158dbc47b6da4246d28303f274e2740b7d61ccf3359ff1ce668ab40
|
4
|
+
data.tar.gz: ea0aa33b02f8f9dac5be81bf6a5a394d181f078127a7b9e22fb55d5c30c85808
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15456b62e2fe1157c17b694c9c8d83d1fa42fa64f4cc3a3aa998a3d21ccf8ae13320694ed3ed1ac500a1636210ae9b153b1070fa427ed9dfd04e5a43b29d56b6
|
7
|
+
data.tar.gz: 193f8fca67cfb78fc2eefc21b0c70cf5f9ddb9028b0ff948472c119ea0350dda587a4a150e7b8cc283ed9cfe4f8e451a323f9517517d73dbfd84a20cedfce2ed
|
data/.standard.yml
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby_version:
|
1
|
+
ruby_version: 3.0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# 1.2.2
|
2
|
+
|
3
|
+
* As promised in 1.2.1, there were bugs. [#19](https://github.com/testdouble/mocktail/pull/19)
|
4
|
+
|
5
|
+
# 1.2.1
|
6
|
+
|
7
|
+
* Adds support for faking methods that use options hashes that are called with
|
8
|
+
and without curly braces [#17](https://github.com/testdouble/mocktail/pull/17)
|
9
|
+
(This is a sweeping change and there will probably be bugs.)
|
10
|
+
|
1
11
|
# 1.2.0
|
2
12
|
|
3
13
|
* Introduce the Mocktail.calls() API https://github.com/testdouble/mocktail/pull/16
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mocktail (1.2.
|
4
|
+
mocktail (1.2.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -9,30 +9,35 @@ GEM
|
|
9
9
|
ast (2.4.2)
|
10
10
|
coderay (1.1.3)
|
11
11
|
docile (1.4.0)
|
12
|
+
json (2.6.2)
|
13
|
+
m (1.6.1)
|
14
|
+
method_source (>= 0.6.7)
|
15
|
+
rake (>= 0.9.2.2)
|
12
16
|
method_source (1.0.0)
|
13
|
-
minitest (5.
|
17
|
+
minitest (5.16.3)
|
14
18
|
parallel (1.22.1)
|
15
|
-
parser (3.1.2.
|
19
|
+
parser (3.1.2.1)
|
16
20
|
ast (~> 2.4.1)
|
17
21
|
pry (0.14.1)
|
18
22
|
coderay (~> 1.1)
|
19
23
|
method_source (~> 1.0)
|
20
24
|
rainbow (3.1.1)
|
21
25
|
rake (13.0.6)
|
22
|
-
regexp_parser (2.
|
26
|
+
regexp_parser (2.6.0)
|
23
27
|
rexml (3.2.5)
|
24
|
-
rubocop (1.
|
28
|
+
rubocop (1.39.0)
|
29
|
+
json (~> 2.3)
|
25
30
|
parallel (~> 1.10)
|
26
|
-
parser (>= 3.1.
|
31
|
+
parser (>= 3.1.2.1)
|
27
32
|
rainbow (>= 2.2.2, < 4.0)
|
28
33
|
regexp_parser (>= 1.8, < 3.0)
|
29
|
-
rexml
|
30
|
-
rubocop-ast (>= 1.
|
34
|
+
rexml (>= 3.2.5, < 4.0)
|
35
|
+
rubocop-ast (>= 1.23.0, < 2.0)
|
31
36
|
ruby-progressbar (~> 1.7)
|
32
37
|
unicode-display_width (>= 1.4.0, < 3.0)
|
33
|
-
rubocop-ast (1.
|
38
|
+
rubocop-ast (1.23.0)
|
34
39
|
parser (>= 3.1.1.0)
|
35
|
-
rubocop-performance (1.
|
40
|
+
rubocop-performance (1.15.0)
|
36
41
|
rubocop (>= 1.7.0, < 2.0)
|
37
42
|
rubocop-ast (>= 0.4.0)
|
38
43
|
ruby-progressbar (1.11.0)
|
@@ -42,16 +47,17 @@ GEM
|
|
42
47
|
simplecov_json_formatter (~> 0.1)
|
43
48
|
simplecov-html (0.12.3)
|
44
49
|
simplecov_json_formatter (0.1.4)
|
45
|
-
standard (1.
|
46
|
-
rubocop (= 1.
|
47
|
-
rubocop-performance (= 1.
|
48
|
-
unicode-display_width (2.
|
50
|
+
standard (1.18.0)
|
51
|
+
rubocop (= 1.39.0)
|
52
|
+
rubocop-performance (= 1.15.0)
|
53
|
+
unicode-display_width (2.3.0)
|
49
54
|
|
50
55
|
PLATFORMS
|
51
56
|
arm64-darwin-20
|
52
57
|
ruby
|
53
58
|
|
54
59
|
DEPENDENCIES
|
60
|
+
m
|
55
61
|
minitest
|
56
62
|
mocktail!
|
57
63
|
pry
|
data/README.md
CHANGED
@@ -814,11 +814,10 @@ which call site produced the unexpected `nil` value.
|
|
814
814
|
### Mocktail.calls
|
815
815
|
|
816
816
|
When practicing test-driven development, you may want to ensure that a
|
817
|
-
dependency wasn't called at all
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
were called.
|
817
|
+
dependency wasn't called at all. To provide a terse way to express this,
|
818
|
+
Mocktail offers a top-level `calls(double, method_name = nil)` method that
|
819
|
+
returns an array of the calls to the mock (optionally filtered to a
|
820
|
+
particular method name) in the order they were called.
|
822
821
|
|
823
822
|
Suppose you were writing a test of this method for example:
|
824
823
|
|
data/bin/m
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'm' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("m", "m")
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Mocktail
|
2
|
+
class ReconstructsCall
|
3
|
+
def reconstruct(double:, call_binding:, default_args:, dry_class:, type:, method:, original_method:, signature:)
|
4
|
+
Call.new(
|
5
|
+
singleton: false,
|
6
|
+
double: double,
|
7
|
+
original_type: type,
|
8
|
+
dry_type: dry_class,
|
9
|
+
method: method,
|
10
|
+
original_method: original_method,
|
11
|
+
args: args_for(signature, call_binding, default_args),
|
12
|
+
kwargs: kwargs_for(signature, call_binding, default_args),
|
13
|
+
block: call_binding.local_variable_get(signature.block_param || ::Mocktail::Signature::DEFAULT_BLOCK_PARAM)
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def args_for(signature, call_binding, default_args)
|
20
|
+
arg_names, rest_name = non_default_args(signature.positional_params, default_args)
|
21
|
+
|
22
|
+
arg_values = arg_names.map { |p| call_binding.local_variable_get(p) }
|
23
|
+
rest_value = call_binding.local_variable_get(rest_name) if rest_name
|
24
|
+
|
25
|
+
arg_values + (rest_value || [])
|
26
|
+
end
|
27
|
+
|
28
|
+
def kwargs_for(signature, call_binding, default_args)
|
29
|
+
kwarg_names, kwrest_name = non_default_args(signature.keyword_params, default_args)
|
30
|
+
|
31
|
+
kwarg_values = kwarg_names.to_h { |p| [p, call_binding.local_variable_get(p)] }
|
32
|
+
kwrest_value = call_binding.local_variable_get(kwrest_name) if kwrest_name
|
33
|
+
|
34
|
+
kwarg_values.merge(kwrest_value || {})
|
35
|
+
end
|
36
|
+
|
37
|
+
def non_default_args(params, default_args)
|
38
|
+
named_args = params.allowed
|
39
|
+
.reject { |p| default_args&.key?(p) }
|
40
|
+
rest_arg = if params.rest && !default_args&.key?(params.rest)
|
41
|
+
params.rest
|
42
|
+
end
|
43
|
+
|
44
|
+
[named_args, rest_arg]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,8 +1,11 @@
|
|
1
|
+
require_relative "declares_dry_class/reconstructs_call"
|
2
|
+
|
1
3
|
module Mocktail
|
2
4
|
class DeclaresDryClass
|
3
5
|
def initialize
|
4
|
-
@handles_dry_call = HandlesDryCall.new
|
5
6
|
@raises_neato_no_method_error = RaisesNeatoNoMethodError.new
|
7
|
+
@transforms_params = TransformsParams.new
|
8
|
+
@stringifies_method_signature = StringifiesMethodSignature.new
|
6
9
|
end
|
7
10
|
|
8
11
|
def declare(type, instance_methods)
|
@@ -39,24 +42,31 @@ module Mocktail
|
|
39
42
|
private
|
40
43
|
|
41
44
|
def define_double_methods!(dry_class, type, instance_methods)
|
42
|
-
handles_dry_call = @handles_dry_call
|
43
45
|
instance_methods.each do |method|
|
44
46
|
dry_class.undef_method(method) if dry_class.method_defined?(method)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
original_method: type.instance_method(method),
|
55
|
-
args: args,
|
56
|
-
kwargs: kwargs,
|
57
|
-
block: block
|
58
|
-
))
|
47
|
+
parameters = type.instance_method(method).parameters
|
48
|
+
signature = @transforms_params.transform(Call.new, params: parameters)
|
49
|
+
method_signature = @stringifies_method_signature.stringify(signature)
|
50
|
+
__mocktail_closure = {
|
51
|
+
dry_class: dry_class,
|
52
|
+
type: type,
|
53
|
+
method: method,
|
54
|
+
original_method: type.instance_method(method),
|
55
|
+
signature: signature
|
59
56
|
}
|
57
|
+
|
58
|
+
dry_class.define_method method,
|
59
|
+
eval(<<-RUBBY, binding, __FILE__, __LINE__ + 1) # standard:disable Security/Eval
|
60
|
+
->#{method_signature} do
|
61
|
+
::Mocktail::Debug.guard_against_mocktail_accidentally_calling_mocks_if_debugging!
|
62
|
+
::Mocktail::HandlesDryCall.new.handle(::Mocktail::ReconstructsCall.new.reconstruct(
|
63
|
+
double: self,
|
64
|
+
call_binding: __send__(:binding),
|
65
|
+
default_args: (__send__(:binding).local_variable_defined?(:__mocktail_default_args) ? __send__(:binding).local_variable_get(:__mocktail_default_args) : {}),
|
66
|
+
**__mocktail_closure
|
67
|
+
))
|
68
|
+
end
|
69
|
+
RUBBY
|
60
70
|
end
|
61
71
|
end
|
62
72
|
|
@@ -71,7 +71,7 @@ module Mocktail
|
|
71
71
|
|
72
72
|
<<~MSG
|
73
73
|
|
74
|
-
There #{corrections.size == 1 ? "is" : "are"} also #{corrections.size} similar method#{"s" if corrections.size != 1} on #{call.original_type.name}.
|
74
|
+
There #{(corrections.size == 1) ? "is" : "are"} also #{corrections.size} similar method#{"s" if corrections.size != 1} on #{call.original_type.name}.
|
75
75
|
|
76
76
|
Did you mean?
|
77
77
|
#{corrections.map { |c| " #{c}" }.join("\n")}
|
@@ -2,8 +2,8 @@ require_relative "../share/bind"
|
|
2
2
|
|
3
3
|
module Mocktail
|
4
4
|
class TransformsParams
|
5
|
-
def transform(dry_call)
|
6
|
-
params =
|
5
|
+
def transform(dry_call, params: dry_call.original_method.parameters)
|
6
|
+
params = name_unnamed_params(params)
|
7
7
|
|
8
8
|
Signature.new(
|
9
9
|
positional_params: Params.new(
|
@@ -12,7 +12,7 @@ module Mocktail
|
|
12
12
|
}.map { |_, name| name },
|
13
13
|
required: params.select { |t, _| Bind.call(t, :==, :req) }.map { |_, n| n },
|
14
14
|
optional: params.select { |t, _| Bind.call(t, :==, :opt) }.map { |_, n| n },
|
15
|
-
rest: params.find { |t, _| Bind.call(t, :==, :rest) }
|
15
|
+
rest: params.find { |t, _| Bind.call(t, :==, :rest) }&.last
|
16
16
|
),
|
17
17
|
positional_args: dry_call.args,
|
18
18
|
|
@@ -22,13 +22,25 @@ module Mocktail
|
|
22
22
|
}.map { |_, name| name },
|
23
23
|
required: params.select { |t, _| Bind.call(t, :==, :keyreq) }.map { |_, n| n },
|
24
24
|
optional: params.select { |t, _| Bind.call(t, :==, :key) }.map { |_, n| n },
|
25
|
-
rest: params.find { |t, _| Bind.call(t, :==, :keyrest) }
|
25
|
+
rest: params.find { |t, _| Bind.call(t, :==, :keyrest) }&.last
|
26
26
|
),
|
27
27
|
keyword_args: dry_call.kwargs,
|
28
28
|
|
29
|
-
block_param: params.find { |t, _| Bind.call(t, :==, :block) }
|
29
|
+
block_param: params.find { |t, _| Bind.call(t, :==, :block) }&.last,
|
30
30
|
block_arg: dry_call.block
|
31
31
|
)
|
32
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def name_unnamed_params(params)
|
37
|
+
params.map.with_index { |param, i|
|
38
|
+
if param.size == 1
|
39
|
+
param + ["unnamed_arg_#{i + 1}"]
|
40
|
+
else
|
41
|
+
param
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
33
45
|
end
|
34
46
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Mocktail
|
2
|
+
class StringifiesMethodSignature
|
3
|
+
def stringify(signature)
|
4
|
+
positional_params = positional(signature)
|
5
|
+
keyword_params = keyword(signature)
|
6
|
+
block_param = block(signature)
|
7
|
+
|
8
|
+
"(#{[positional_params, keyword_params, block_param].compact.join(", ")})"
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def positional(signature)
|
14
|
+
params = signature.positional_params.all.map do |name|
|
15
|
+
if signature.positional_params.allowed.include?(name)
|
16
|
+
"#{name} = ((__mocktail_default_args ||= {})[:#{name}] = nil)"
|
17
|
+
elsif signature.positional_params.rest == name
|
18
|
+
"*#{(name == :*) ? Signature::DEFAULT_REST_ARGS : name}"
|
19
|
+
end
|
20
|
+
end.compact
|
21
|
+
|
22
|
+
params.join(", ") if params.any?
|
23
|
+
end
|
24
|
+
|
25
|
+
def keyword(signature)
|
26
|
+
params = signature.keyword_params.all.map do |name|
|
27
|
+
if signature.keyword_params.allowed.include?(name)
|
28
|
+
"#{name}: ((__mocktail_default_args ||= {})[:#{name}] = nil)"
|
29
|
+
elsif signature.keyword_params.rest == name
|
30
|
+
"**#{(name == :**) ? Signature::DEFAULT_REST_KWARGS : name}"
|
31
|
+
end
|
32
|
+
end.compact
|
33
|
+
|
34
|
+
params.join(", ") if params.any?
|
35
|
+
end
|
36
|
+
|
37
|
+
def block(signature)
|
38
|
+
if signature.block_param && signature.block_param != :&
|
39
|
+
"&#{signature.block_param}"
|
40
|
+
else
|
41
|
+
"&#{Signature::DEFAULT_BLOCK_PARAM}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -8,6 +8,9 @@ module Mocktail
|
|
8
8
|
:block_arg,
|
9
9
|
keyword_init: true
|
10
10
|
)
|
11
|
+
DEFAULT_REST_ARGS = "args"
|
12
|
+
DEFAULT_REST_KWARGS = "kwargs"
|
13
|
+
DEFAULT_BLOCK_PARAM = "blk"
|
11
14
|
end
|
12
15
|
|
13
16
|
class Params < Struct.new(
|
@@ -26,7 +29,7 @@ module Mocktail
|
|
26
29
|
end
|
27
30
|
|
28
31
|
def allowed
|
29
|
-
required
|
32
|
+
all.select { |name| required.include?(name) || optional.include?(name) }
|
30
33
|
end
|
31
34
|
|
32
35
|
def rest?
|
data/lib/mocktail/version.rb
CHANGED
data/lib/mocktail.rb
CHANGED
@@ -17,6 +17,7 @@ require_relative "mocktail/replaces_next"
|
|
17
17
|
require_relative "mocktail/replaces_type"
|
18
18
|
require_relative "mocktail/resets_state"
|
19
19
|
require_relative "mocktail/simulates_argument_error"
|
20
|
+
require_relative "mocktail/stringifies_method_signature"
|
20
21
|
require_relative "mocktail/value"
|
21
22
|
require_relative "mocktail/verifies_call"
|
22
23
|
require_relative "mocktail/version"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mocktail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -27,6 +27,7 @@ files:
|
|
27
27
|
- README.md
|
28
28
|
- Rakefile
|
29
29
|
- bin/console
|
30
|
+
- bin/m
|
30
31
|
- bin/rake
|
31
32
|
- bin/setup
|
32
33
|
- lib/mocktail.rb
|
@@ -47,6 +48,7 @@ files:
|
|
47
48
|
- lib/mocktail/imitates_type/ensures_imitation_support.rb
|
48
49
|
- lib/mocktail/imitates_type/makes_double.rb
|
49
50
|
- lib/mocktail/imitates_type/makes_double/declares_dry_class.rb
|
51
|
+
- lib/mocktail/imitates_type/makes_double/declares_dry_class/reconstructs_call.rb
|
50
52
|
- lib/mocktail/imitates_type/makes_double/gathers_fakeable_instance_methods.rb
|
51
53
|
- lib/mocktail/initializes_mocktail.rb
|
52
54
|
- lib/mocktail/matcher_presentation.rb
|
@@ -79,6 +81,7 @@ files:
|
|
79
81
|
- lib/mocktail/simulates_argument_error/reconciles_args_with_params.rb
|
80
82
|
- lib/mocktail/simulates_argument_error/recreates_message.rb
|
81
83
|
- lib/mocktail/simulates_argument_error/transforms_params.rb
|
84
|
+
- lib/mocktail/stringifies_method_signature.rb
|
82
85
|
- lib/mocktail/value.rb
|
83
86
|
- lib/mocktail/value/cabinet.rb
|
84
87
|
- lib/mocktail/value/call.rb
|