mocktail 0.0.2 → 0.0.3
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/CHANGELOG.md +9 -0
- data/Gemfile.lock +1 -1
- data/lib/mocktail/handles_dry_call/validates_arguments.rb +2 -23
- data/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb +40 -15
- data/lib/mocktail/raises_neato_no_method_error.rb +79 -0
- data/lib/mocktail/share/creates_identifier.rb +13 -0
- data/lib/mocktail/{verifies_call/raises_verification_error → share}/stringifies_call.rb +16 -7
- data/lib/mocktail/simulates_argument_error/cleans_backtrace.rb +15 -0
- data/lib/mocktail/simulates_argument_error/reconciles_args_with_params.rb +20 -0
- data/lib/mocktail/simulates_argument_error/recreates_message.rb +29 -0
- data/lib/mocktail/simulates_argument_error/transforms_params.rb +32 -0
- data/lib/mocktail/simulates_argument_error.rb +30 -0
- data/lib/mocktail/value/signature.rb +36 -0
- data/lib/mocktail/value.rb +1 -0
- data/lib/mocktail/verifies_call/raises_verification_error.rb +1 -1
- data/lib/mocktail/version.rb +1 -1
- data/lib/mocktail.rb +2 -0
- metadata +11 -4
- data/lib/mocktail/share/simulates_argument_error.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e719e2144c3da8a2569e2ef5e7cf2c78d054625011fcf0bdf8f98f300bdcd805
|
4
|
+
data.tar.gz: 3635b7210ac6d5a7c05c4000f100ac1e07f4c8d5de7de81586e41f3b81e11ce5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d84b7964c5fbe14e3ef2a8a881c1c328f0f4c37cbde2d1423965016fe26f153c6801032c5aa4a7018db6d98924aecbb031e3e473992178bb9d5fe46e53ac2ea5
|
7
|
+
data.tar.gz: 384e42b818b92ace165e975dafd1482e00a46fc3be4c4abf0bb54e2ff648f29da1b338a8845be5c64e1878abf738e4061345083c0e952206380119ecb82729cf
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# 0.0.3
|
2
|
+
|
3
|
+
* Implement method_missing on all mocked instance methods to print out useful
|
4
|
+
information, like the target type, the attempted call, an example method
|
5
|
+
definition that would match the call (for paint-by-numbers-like TDD), and
|
6
|
+
did_you_mean gem integration of similar method names in case it was just a
|
7
|
+
miss
|
8
|
+
* Cleans artificially-generated argument errors of gem-internal backtraces
|
9
|
+
|
1
10
|
# 0.0.2
|
2
11
|
|
3
12
|
* Drop Ruby 2.7 support. Unbeknownst to me (since I developed mocktail using
|
data/Gemfile.lock
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require_relative "../share/simulates_argument_error"
|
2
|
-
|
3
1
|
module Mocktail
|
4
2
|
class ValidatesArguments
|
5
3
|
def self.disable!
|
@@ -30,28 +28,9 @@ module Mocktail
|
|
30
28
|
def validate(dry_call)
|
31
29
|
return if self.class.disabled?
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
}.partition { |type, _|
|
36
|
-
[:req, :opt, :rest].include?(type)
|
37
|
-
}
|
38
|
-
|
39
|
-
unless args_match?(arg_params, dry_call.args) &&
|
40
|
-
kwargs_match?(kwarg_params, dry_call.kwargs)
|
41
|
-
raise @simulates_argument_error.simulate(arg_params, dry_call.args, kwarg_params, dry_call.kwargs)
|
31
|
+
if (error = @simulates_argument_error.simulate(dry_call))
|
32
|
+
raise error
|
42
33
|
end
|
43
34
|
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def args_match?(arg_params, args)
|
48
|
-
args.size >= arg_params.count { |type, _| type == :req } &&
|
49
|
-
(arg_params.any? { |type, _| type == :rest } || args.size <= arg_params.size)
|
50
|
-
end
|
51
|
-
|
52
|
-
def kwargs_match?(kwarg_params, kwargs)
|
53
|
-
kwarg_params.select { |type, _| type == :keyreq }.all? { |_, name| kwargs.key?(name) } &&
|
54
|
-
(kwarg_params.any? { |type, _| type == :keyrest } || kwargs.keys.all? { |name| kwarg_params.any? { |_, key| name == key } })
|
55
|
-
end
|
56
35
|
end
|
57
36
|
end
|
@@ -2,13 +2,13 @@ module Mocktail
|
|
2
2
|
class DeclaresDryClass
|
3
3
|
def initialize
|
4
4
|
@handles_dry_call = HandlesDryCall.new
|
5
|
+
@raises_neato_no_method_error = RaisesNeatoNoMethodError.new
|
5
6
|
end
|
6
7
|
|
7
8
|
def declare(type)
|
8
|
-
type_type = type_of(type)
|
9
9
|
instance_methods = instance_methods_on(type)
|
10
10
|
dry_class = Class.new(Object) {
|
11
|
-
include type if
|
11
|
+
include type if type.instance_of?(Module)
|
12
12
|
|
13
13
|
def initialize(*args, **kwargs, &blk)
|
14
14
|
end
|
@@ -18,15 +18,19 @@ module Mocktail
|
|
18
18
|
}
|
19
19
|
alias_method :kind_of?, :is_a?
|
20
20
|
|
21
|
-
if
|
21
|
+
if type.instance_of?(Class)
|
22
22
|
define_method :instance_of?, ->(thing) {
|
23
23
|
type == thing
|
24
24
|
}
|
25
25
|
end
|
26
26
|
}
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
# These have special implementations, but if the user defines
|
29
|
+
# any of them on the object itself, then they'll be replaced with normal
|
30
|
+
# mocked methods. YMMV
|
31
|
+
add_stringify_methods!(dry_class, :to_s, type, instance_methods)
|
32
|
+
add_stringify_methods!(dry_class, :inspect, type, instance_methods)
|
33
|
+
define_method_missing_errors!(dry_class, type, instance_methods)
|
30
34
|
|
31
35
|
define_double_methods!(dry_class, type, instance_methods)
|
32
36
|
|
@@ -43,7 +47,7 @@ module Mocktail
|
|
43
47
|
singleton: false,
|
44
48
|
double: self,
|
45
49
|
original_type: type,
|
46
|
-
dry_type:
|
50
|
+
dry_type: dry_class,
|
47
51
|
method: method,
|
48
52
|
original_method: type.instance_method(method),
|
49
53
|
args: args,
|
@@ -54,7 +58,7 @@ module Mocktail
|
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
57
|
-
def add_stringify_methods!(dry_class, method_name, type,
|
61
|
+
def add_stringify_methods!(dry_class, method_name, type, instance_methods)
|
58
62
|
dry_class.define_singleton_method method_name, -> {
|
59
63
|
if (id_matches = super().match(/:([0-9a-fx]+)>$/))
|
60
64
|
"#<Class #{"including module " if type.instance_of?(Module)}for mocktail of #{type.name}:#{id_matches[1]}>"
|
@@ -74,20 +78,41 @@ module Mocktail
|
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
77
|
-
def
|
78
|
-
if
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
81
|
+
def define_method_missing_errors!(dry_class, type, instance_methods)
|
82
|
+
return if instance_methods.include?(:method_missing)
|
83
|
+
|
84
|
+
raises_neato_no_method_error = @raises_neato_no_method_error
|
85
|
+
dry_class.define_method :method_missing, ->(name, *args, **kwargs, &block) {
|
86
|
+
raises_neato_no_method_error.call(
|
87
|
+
Call.new(
|
88
|
+
singleton: false,
|
89
|
+
double: self,
|
90
|
+
original_type: type,
|
91
|
+
dry_type: self.class,
|
92
|
+
method: name,
|
93
|
+
original_method: nil,
|
94
|
+
args: args,
|
95
|
+
kwargs: kwargs,
|
96
|
+
block: block
|
97
|
+
)
|
98
|
+
)
|
99
|
+
}
|
83
100
|
end
|
84
101
|
|
85
102
|
def instance_methods_on(type)
|
86
|
-
type.instance_methods
|
87
|
-
|
103
|
+
methods = type.instance_methods + [
|
104
|
+
(:respond_to_missing? if type.private_method_defined?(:respond_to_missing?))
|
105
|
+
].compact
|
106
|
+
|
107
|
+
methods.reject { |m|
|
108
|
+
ignore?(type, m)
|
88
109
|
}
|
89
110
|
end
|
90
111
|
|
112
|
+
def ignore?(type, method_name)
|
113
|
+
ignored_ancestors.include?(type.instance_method(method_name).owner)
|
114
|
+
end
|
115
|
+
|
91
116
|
def ignored_ancestors
|
92
117
|
Object.ancestors
|
93
118
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require_relative "share/stringifies_call"
|
2
|
+
require_relative "share/creates_identifier"
|
3
|
+
|
4
|
+
module Mocktail
|
5
|
+
class RaisesNeatoNoMethodError
|
6
|
+
def initialize
|
7
|
+
@stringifies_call = StringifiesCall.new
|
8
|
+
@creates_identifier = CreatesIdentifier.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(call)
|
12
|
+
raise NoMethodError.new <<~MSG
|
13
|
+
No method `#{call.original_type.name}##{call.method}' exists for call:
|
14
|
+
|
15
|
+
#{@stringifies_call.stringify(call, anonymous_blocks: true, always_parens: true)}
|
16
|
+
|
17
|
+
Need to define the method? Here's a sample definition:
|
18
|
+
|
19
|
+
def #{call.method}#{params(call)}
|
20
|
+
end
|
21
|
+
#{corrections(call)}
|
22
|
+
MSG
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def params(call)
|
28
|
+
return if (params_lists = [
|
29
|
+
params_list(call.args),
|
30
|
+
kwparams_list(call.kwargs),
|
31
|
+
block_param(call.block)
|
32
|
+
].compact).empty?
|
33
|
+
|
34
|
+
"(#{params_lists.join(", ")})"
|
35
|
+
end
|
36
|
+
|
37
|
+
def params_list(args)
|
38
|
+
return if args.empty?
|
39
|
+
|
40
|
+
count_repeats(args.map { |arg|
|
41
|
+
@creates_identifier.create(arg, default: "arg")
|
42
|
+
}).join(", ")
|
43
|
+
end
|
44
|
+
|
45
|
+
def kwparams_list(kwargs)
|
46
|
+
return if kwargs.empty?
|
47
|
+
|
48
|
+
kwargs.keys.map { |key| "#{key}:" }.join(", ")
|
49
|
+
end
|
50
|
+
|
51
|
+
def block_param(block)
|
52
|
+
return if block.nil?
|
53
|
+
|
54
|
+
"&blk"
|
55
|
+
end
|
56
|
+
|
57
|
+
def count_repeats(identifiers)
|
58
|
+
identifiers.map.with_index { |id, i|
|
59
|
+
if (preceding_matches = identifiers[0...i].count { |other_id| id == other_id }) > 0
|
60
|
+
"#{id}#{preceding_matches + 1}"
|
61
|
+
else
|
62
|
+
id
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def corrections(call)
|
68
|
+
return if (corrections = DidYouMean::SpellChecker.new(dictionary: call.original_type.instance_methods).correct(call.method)).empty?
|
69
|
+
|
70
|
+
<<~MSG
|
71
|
+
|
72
|
+
There #{corrections.size == 1 ? "is" : "are"} also #{corrections.size} similar method#{"s" if corrections.size != 1} on #{call.original_type.name}.
|
73
|
+
|
74
|
+
Did you mean?
|
75
|
+
#{corrections.map { |c| " #{c}" }.join("\n")}
|
76
|
+
MSG
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Mocktail
|
2
|
+
class CreatesIdentifier
|
3
|
+
def create(s, default: "identifier", max_length: 24)
|
4
|
+
id = s.to_s.downcase.gsub(/[^\w\s]/, "").gsub(/^\d+/, "")[0...max_length].strip.gsub(/\s+/, "_")
|
5
|
+
|
6
|
+
if id.empty?
|
7
|
+
default
|
8
|
+
else
|
9
|
+
id
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,18 +1,22 @@
|
|
1
1
|
module Mocktail
|
2
2
|
class StringifiesCall
|
3
|
-
def stringify(call)
|
4
|
-
"#{call.method}#{args_to_s(call)}#{blockify(call.block)}"
|
3
|
+
def stringify(call, anonymous_blocks: false, always_parens: false)
|
4
|
+
"#{call.method}#{args_to_s(call, parens: always_parens)}#{blockify(call.block, anonymous: anonymous_blocks)}"
|
5
5
|
end
|
6
6
|
|
7
7
|
private
|
8
8
|
|
9
|
-
def args_to_s(call)
|
10
|
-
|
9
|
+
def args_to_s(call, parens: true)
|
10
|
+
args_lists = [
|
11
11
|
argify(call.args),
|
12
12
|
kwargify(call.kwargs),
|
13
13
|
lambdafy(call.block)
|
14
|
-
].compact
|
14
|
+
].compact
|
15
|
+
|
16
|
+
if !args_lists.empty?
|
15
17
|
"(#{args_lists.join(", ")})"
|
18
|
+
elsif parens
|
19
|
+
"()"
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
@@ -31,9 +35,14 @@ module Mocktail
|
|
31
35
|
"&lambda[#{source_locationify(block)}]"
|
32
36
|
end
|
33
37
|
|
34
|
-
def blockify(block)
|
38
|
+
def blockify(block, anonymous:)
|
35
39
|
return unless block && !block.lambda?
|
36
|
-
|
40
|
+
|
41
|
+
if anonymous
|
42
|
+
" {…}"
|
43
|
+
else
|
44
|
+
" { Proc at #{source_locationify(block)} }"
|
45
|
+
end
|
37
46
|
end
|
38
47
|
|
39
48
|
def source_locationify(block)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Mocktail
|
2
|
+
class CleansBacktrace
|
3
|
+
BASE_PATH = (Pathname.new(__FILE__) + "../../..").to_s
|
4
|
+
|
5
|
+
def clean(error)
|
6
|
+
raise error
|
7
|
+
rescue => e
|
8
|
+
e.tap do |e|
|
9
|
+
e.set_backtrace(e.backtrace.drop_while { |frame|
|
10
|
+
frame.start_with?(BASE_PATH)
|
11
|
+
})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Mocktail
|
2
|
+
class ReconcilesArgsWithParams
|
3
|
+
def reconcile(signature)
|
4
|
+
args_match?(signature.positional_params, signature.positional_args) &&
|
5
|
+
kwargs_match?(signature.keyword_params, signature.keyword_args)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def args_match?(arg_params, args)
|
11
|
+
args.size >= arg_params.required.size &&
|
12
|
+
(arg_params.rest? || args.size <= arg_params.allowed.size)
|
13
|
+
end
|
14
|
+
|
15
|
+
def kwargs_match?(kwarg_params, kwargs)
|
16
|
+
kwarg_params.required.all? { |name| kwargs.key?(name) } &&
|
17
|
+
(kwarg_params.rest? || kwargs.keys.all? { |name| kwarg_params.allowed.include?(name) })
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Mocktail
|
2
|
+
class RecreatesMessage
|
3
|
+
def recreate(signature)
|
4
|
+
req_args = signature.positional_params.required.size
|
5
|
+
allowed_args = signature.positional_params.allowed.size
|
6
|
+
rest_args = signature.positional_params.rest?
|
7
|
+
req_kwargs = signature.keyword_params.required
|
8
|
+
|
9
|
+
if signature.positional_args.size < req_args || (!rest_args && signature.positional_args.size > allowed_args)
|
10
|
+
expected_desc = if rest_args
|
11
|
+
"#{req_args}+"
|
12
|
+
elsif allowed_args != req_args
|
13
|
+
"#{req_args}..#{allowed_args}"
|
14
|
+
else
|
15
|
+
req_args.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
"wrong number of arguments (given #{signature.positional_args.size}, expected #{expected_desc}#{"; required keyword#{"s" if req_kwargs.size > 1}: #{req_kwargs.join(", ")}" unless req_kwargs.empty?})"
|
19
|
+
|
20
|
+
elsif !(missing_kwargs = req_kwargs.reject { |name| signature.keyword_args.key?(name) }).empty?
|
21
|
+
"missing keyword#{"s" if missing_kwargs.size > 1}: #{missing_kwargs.map { |name| name.inspect }.join(", ")}"
|
22
|
+
elsif !(unknown_kwargs = signature.keyword_args.keys.reject { |name| signature.keyword_params.all.include?(name) }).empty?
|
23
|
+
"unknown keyword#{"s" if unknown_kwargs.size > 1}: #{unknown_kwargs.map { |name| name.inspect }.join(", ")}"
|
24
|
+
else
|
25
|
+
"unknown cause (this is probably a bug in Mocktail)"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mocktail
|
2
|
+
class TransformsParams
|
3
|
+
def transform(dry_call)
|
4
|
+
params = dry_call.original_method.parameters
|
5
|
+
|
6
|
+
Signature.new(
|
7
|
+
positional_params: Params.new(
|
8
|
+
all: params.select { |type, _|
|
9
|
+
[:req, :opt, :rest].include?(type)
|
10
|
+
}.map { |_, name| name },
|
11
|
+
required: params.select { |t, _| t == :req }.map { |_, n| n },
|
12
|
+
optional: params.select { |t, _| t == :opt }.map { |_, n| n },
|
13
|
+
rest: params.find { |type, _| type == :rest } & [1]
|
14
|
+
),
|
15
|
+
positional_args: dry_call.args,
|
16
|
+
|
17
|
+
keyword_params: Params.new(
|
18
|
+
all: params.select { |type, _|
|
19
|
+
[:keyreq, :key, :keyrest].include?(type)
|
20
|
+
}.map { |_, name| name },
|
21
|
+
required: params.select { |t, _| t == :keyreq }.map { |_, n| n },
|
22
|
+
optional: params.select { |t, _| t == :key }.map { |_, n| n },
|
23
|
+
rest: params.find { |type, _| type == :keyrest } & [1]
|
24
|
+
),
|
25
|
+
keyword_args: dry_call.kwargs,
|
26
|
+
|
27
|
+
block_param: params.find { |type, _| type == :block } & [1],
|
28
|
+
block_arg: dry_call.block
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative "simulates_argument_error/transforms_params"
|
2
|
+
require_relative "simulates_argument_error/reconciles_args_with_params"
|
3
|
+
require_relative "simulates_argument_error/recreates_message"
|
4
|
+
require_relative "simulates_argument_error/cleans_backtrace"
|
5
|
+
require_relative "share/stringifies_call"
|
6
|
+
|
7
|
+
module Mocktail
|
8
|
+
class SimulatesArgumentError
|
9
|
+
def initialize
|
10
|
+
@transforms_params = TransformsParams.new
|
11
|
+
@reconciles_args_with_params = ReconcilesArgsWithParams.new
|
12
|
+
@recreates_message = RecreatesMessage.new
|
13
|
+
@cleans_backtrace = CleansBacktrace.new
|
14
|
+
@stringifies_call = StringifiesCall.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def simulate(dry_call)
|
18
|
+
signature = @transforms_params.transform(dry_call)
|
19
|
+
|
20
|
+
unless @reconciles_args_with_params.reconcile(signature)
|
21
|
+
@cleans_backtrace.clean(
|
22
|
+
ArgumentError.new([
|
23
|
+
@recreates_message.recreate(signature),
|
24
|
+
"[Mocktail call: `#{@stringifies_call.stringify(dry_call)}']"
|
25
|
+
].join(" "))
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mocktail
|
2
|
+
class Signature < Struct.new(
|
3
|
+
:positional_params,
|
4
|
+
:positional_args,
|
5
|
+
:keyword_params,
|
6
|
+
:keyword_args,
|
7
|
+
:block_param,
|
8
|
+
:block_arg,
|
9
|
+
keyword_init: true
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
class Params < Struct.new(
|
14
|
+
:all,
|
15
|
+
:required,
|
16
|
+
:optional,
|
17
|
+
:rest,
|
18
|
+
keyword_init: true
|
19
|
+
)
|
20
|
+
|
21
|
+
def initialize(**params)
|
22
|
+
super
|
23
|
+
self.all ||= []
|
24
|
+
self.required ||= []
|
25
|
+
self.optional ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
def allowed
|
29
|
+
required + optional
|
30
|
+
end
|
31
|
+
|
32
|
+
def rest?
|
33
|
+
!!rest
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/mocktail/value.rb
CHANGED
@@ -3,6 +3,7 @@ require_relative "value/call"
|
|
3
3
|
require_relative "value/demo_config"
|
4
4
|
require_relative "value/double"
|
5
5
|
require_relative "value/matcher_registry"
|
6
|
+
require_relative "value/signature"
|
6
7
|
require_relative "value/stubbing"
|
7
8
|
require_relative "value/top_shelf"
|
8
9
|
require_relative "value/type_replacement"
|
data/lib/mocktail/version.rb
CHANGED
data/lib/mocktail.rb
CHANGED
@@ -6,11 +6,13 @@ require_relative "mocktail/imitates_type"
|
|
6
6
|
require_relative "mocktail/initializes_mocktail"
|
7
7
|
require_relative "mocktail/matcher_presentation"
|
8
8
|
require_relative "mocktail/matchers"
|
9
|
+
require_relative "mocktail/raises_neato_no_method_error"
|
9
10
|
require_relative "mocktail/registers_matcher"
|
10
11
|
require_relative "mocktail/registers_stubbing"
|
11
12
|
require_relative "mocktail/replaces_next"
|
12
13
|
require_relative "mocktail/replaces_type"
|
13
14
|
require_relative "mocktail/resets_state"
|
15
|
+
require_relative "mocktail/simulates_argument_error"
|
14
16
|
require_relative "mocktail/value"
|
15
17
|
require_relative "mocktail/verifies_call"
|
16
18
|
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: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -53,6 +53,7 @@ files:
|
|
53
53
|
- lib/mocktail/matchers/not.rb
|
54
54
|
- lib/mocktail/matchers/numeric.rb
|
55
55
|
- lib/mocktail/matchers/that.rb
|
56
|
+
- lib/mocktail/raises_neato_no_method_error.rb
|
56
57
|
- lib/mocktail/records_demonstration.rb
|
57
58
|
- lib/mocktail/registers_matcher.rb
|
58
59
|
- lib/mocktail/registers_stubbing.rb
|
@@ -61,14 +62,21 @@ files:
|
|
61
62
|
- lib/mocktail/replaces_type/redefines_new.rb
|
62
63
|
- lib/mocktail/replaces_type/redefines_singleton_methods.rb
|
63
64
|
- lib/mocktail/resets_state.rb
|
65
|
+
- lib/mocktail/share/creates_identifier.rb
|
64
66
|
- lib/mocktail/share/determines_matching_calls.rb
|
65
|
-
- lib/mocktail/share/
|
67
|
+
- lib/mocktail/share/stringifies_call.rb
|
68
|
+
- lib/mocktail/simulates_argument_error.rb
|
69
|
+
- lib/mocktail/simulates_argument_error/cleans_backtrace.rb
|
70
|
+
- lib/mocktail/simulates_argument_error/reconciles_args_with_params.rb
|
71
|
+
- lib/mocktail/simulates_argument_error/recreates_message.rb
|
72
|
+
- lib/mocktail/simulates_argument_error/transforms_params.rb
|
66
73
|
- lib/mocktail/value.rb
|
67
74
|
- lib/mocktail/value/cabinet.rb
|
68
75
|
- lib/mocktail/value/call.rb
|
69
76
|
- lib/mocktail/value/demo_config.rb
|
70
77
|
- lib/mocktail/value/double.rb
|
71
78
|
- lib/mocktail/value/matcher_registry.rb
|
79
|
+
- lib/mocktail/value/signature.rb
|
72
80
|
- lib/mocktail/value/stubbing.rb
|
73
81
|
- lib/mocktail/value/top_shelf.rb
|
74
82
|
- lib/mocktail/value/type_replacement.rb
|
@@ -76,7 +84,6 @@ files:
|
|
76
84
|
- lib/mocktail/verifies_call/finds_verifiable_calls.rb
|
77
85
|
- lib/mocktail/verifies_call/raises_verification_error.rb
|
78
86
|
- lib/mocktail/verifies_call/raises_verification_error/gathers_calls_of_method.rb
|
79
|
-
- lib/mocktail/verifies_call/raises_verification_error/stringifies_call.rb
|
80
87
|
- lib/mocktail/version.rb
|
81
88
|
- mocktail.gemspec
|
82
89
|
homepage: https://github.com/testdouble/mocktail
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Mocktail
|
2
|
-
class SimulatesArgumentError
|
3
|
-
def simulate(arg_params, args, kwarg_params, kwargs)
|
4
|
-
req_args = arg_params.count { |type, _| type == :req }
|
5
|
-
opt_args = arg_params.count { |type, _| type == :opt }
|
6
|
-
rest_args = arg_params.any? { |type, _| type == :rest }
|
7
|
-
req_kwargs = kwarg_params.select { |type, _| type == :keyreq }
|
8
|
-
|
9
|
-
allowed_args = req_args + opt_args
|
10
|
-
msg = if args.size < req_args || (!rest_args && args.size > allowed_args)
|
11
|
-
expected_desc = if rest_args
|
12
|
-
"#{req_args}+"
|
13
|
-
elsif allowed_args != req_args
|
14
|
-
"#{req_args}..#{allowed_args}"
|
15
|
-
else
|
16
|
-
req_args.to_s
|
17
|
-
end
|
18
|
-
|
19
|
-
"wrong number of arguments (given #{args.size}, expected #{expected_desc}#{"; required keyword#{"s" if req_kwargs.size > 1}: #{req_kwargs.map { |_, name| name }.join(", ")}" unless req_kwargs.empty?})"
|
20
|
-
|
21
|
-
elsif !(missing_kwargs = req_kwargs.reject { |_, name| kwargs.key?(name) }).empty?
|
22
|
-
"missing keyword#{"s" if missing_kwargs.size > 1}: #{missing_kwargs.map { |_, name| name.inspect }.join(", ")}"
|
23
|
-
end
|
24
|
-
|
25
|
-
ArgumentError.new(msg)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|