muack 1.2.0 → 1.5.0
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 +5 -5
- data/.travis.yml +19 -9
- data/CHANGES.md +47 -0
- data/Gemfile +0 -4
- data/README.md +162 -65
- data/Rakefile +3 -4
- data/lib/muack.rb +43 -11
- data/lib/muack/block.rb +4 -15
- data/lib/muack/block_26.rb +16 -0
- data/lib/muack/block_27.rb +16 -0
- data/lib/muack/coat.rb +1 -1
- data/lib/muack/definition.rb +4 -3
- data/lib/muack/error.rb +6 -0
- data/lib/muack/failure.rb +5 -4
- data/lib/muack/mock.rb +134 -68
- data/lib/muack/satisfying.rb +195 -0
- data/lib/muack/spy.rb +18 -4
- data/lib/muack/stub.rb +7 -6
- data/lib/muack/test.rb +42 -11
- data/lib/muack/version.rb +1 -1
- data/muack.gemspec +65 -55
- data/task/README.md +8 -8
- data/task/gemgem.rb +34 -7
- data/test/test_any_instance_of.rb +16 -2
- data/test/test_from_readme.rb +6 -8
- data/test/test_keyargs.rb +111 -0
- data/test/test_modifier.rb +6 -6
- data/test/test_prepend.rb +121 -0
- data/test/test_proxy.rb +19 -4
- data/test/{test_satisfy.rb → test_satisfying.rb} +216 -80
- data/test/test_spy.rb +149 -0
- data/test/test_stub.rb +0 -95
- data/test/test_visibility.rb +120 -0
- metadata +20 -11
- data/lib/muack/satisfy.rb +0 -100
@@ -0,0 +1,195 @@
|
|
1
|
+
|
2
|
+
require 'muack/error'
|
3
|
+
|
4
|
+
module Muack
|
5
|
+
class Satisfying < Struct.new(:api_args, :block)
|
6
|
+
def initialize args=nil, &block
|
7
|
+
super(args, block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def match actual_arg
|
11
|
+
!!block.call(actual_arg)
|
12
|
+
end
|
13
|
+
|
14
|
+
def | rhs; Satisfying::Disj.new(self, rhs); end
|
15
|
+
def & rhs; Satisfying::Conj.new(self, rhs); end
|
16
|
+
|
17
|
+
class Disj < Satisfying
|
18
|
+
def initialize lhs, rhs
|
19
|
+
@lhs, @rhs = lhs, rhs
|
20
|
+
end
|
21
|
+
|
22
|
+
def match actual_arg
|
23
|
+
@lhs.match(actual_arg) || @rhs.match(actual_arg)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s; "#{@lhs} | #{@rhs}"; end
|
27
|
+
alias_method :inspect, :to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
class Conj < Satisfying
|
31
|
+
def initialize lhs, rhs
|
32
|
+
@lhs, @rhs = lhs, rhs
|
33
|
+
end
|
34
|
+
|
35
|
+
def match actual_arg
|
36
|
+
@lhs.match(actual_arg) && @rhs.match(actual_arg)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s; "#{@lhs} & #{@rhs}"; end
|
40
|
+
alias_method :inspect, :to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
"Muack::API.#{api_name}(#{api_args.map(&:inspect).join(', ')})"
|
45
|
+
end
|
46
|
+
alias_method :inspect, :to_s
|
47
|
+
|
48
|
+
def api_name
|
49
|
+
(self.class.name || 'Unknown')[/(::)*(\w+)$/, 2].
|
50
|
+
gsub(/([A-Z][a-z]*)+?(?=[A-Z][a-z]*)/, '\\1_').downcase
|
51
|
+
end
|
52
|
+
|
53
|
+
def api_args
|
54
|
+
super || [block || method(:match)]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Anything < Satisfying
|
59
|
+
def initialize
|
60
|
+
super([])
|
61
|
+
end
|
62
|
+
|
63
|
+
def match _
|
64
|
+
true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class IsA < Satisfying
|
69
|
+
def initialize klass
|
70
|
+
super([klass])
|
71
|
+
end
|
72
|
+
|
73
|
+
def match actual_arg
|
74
|
+
actual_arg.kind_of?(api_args.first)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Matching < Satisfying
|
79
|
+
def initialize regexp
|
80
|
+
super([regexp])
|
81
|
+
end
|
82
|
+
|
83
|
+
def match actual_arg
|
84
|
+
api_args.first.match(actual_arg)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Including < Satisfying
|
89
|
+
def initialize element
|
90
|
+
super([element])
|
91
|
+
end
|
92
|
+
|
93
|
+
def match actual_arg
|
94
|
+
actual_arg.include?(api_args.first)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class Within < Satisfying
|
99
|
+
def initialize range_or_array
|
100
|
+
super([range_or_array])
|
101
|
+
end
|
102
|
+
|
103
|
+
def match actual_arg
|
104
|
+
api_args.first.include?(actual_arg)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class RespondingTo < Satisfying
|
109
|
+
def initialize *messages
|
110
|
+
super(messages)
|
111
|
+
end
|
112
|
+
|
113
|
+
def match actual_arg
|
114
|
+
api_args.all?{ |msg| actual_arg.respond_to?(msg) }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class Where < Satisfying
|
119
|
+
None = Object.new
|
120
|
+
def initialize spec
|
121
|
+
super([spec])
|
122
|
+
end
|
123
|
+
|
124
|
+
def match actual_arg, spec=api_args.first
|
125
|
+
case spec
|
126
|
+
when Hash
|
127
|
+
actual_arg.kind_of?(Hash) && match_hash(actual_arg, spec)
|
128
|
+
when Array
|
129
|
+
actual_arg.kind_of?(Array) && match_array(actual_arg, spec)
|
130
|
+
else
|
131
|
+
raise UnknownSpec.new(spec)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
def match_hash actual_arg, spec
|
137
|
+
(spec.keys | actual_arg.keys).all? do |key|
|
138
|
+
match_value(actual_arg, spec, key)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def match_array actual_arg, spec
|
143
|
+
spec.zip(actual_arg).all? do |(ev, av)|
|
144
|
+
match_value(av, ev)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def match_value av, ev, key=None
|
149
|
+
if key == None
|
150
|
+
a, e = av, ev
|
151
|
+
elsif av.key?(key) && ev.key?(key)
|
152
|
+
a, e = av[key], ev[key]
|
153
|
+
else
|
154
|
+
return false
|
155
|
+
end
|
156
|
+
|
157
|
+
case e
|
158
|
+
when Satisfying
|
159
|
+
e.match(a)
|
160
|
+
when Hash
|
161
|
+
a.kind_of?(Hash) && match_hash(a, e)
|
162
|
+
when Array
|
163
|
+
a.kind_of?(Array) && match_array(a, e)
|
164
|
+
else
|
165
|
+
e == a
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class Having < Where
|
171
|
+
def initialize subset
|
172
|
+
super(subset)
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
def match_hash actual_arg, subset
|
177
|
+
subset.each_key.all? do |key|
|
178
|
+
match_value(actual_arg, subset, key)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class Allowing < Where
|
184
|
+
def initialize superset
|
185
|
+
super(superset)
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
def match_hash actual_arg, superset
|
190
|
+
actual_arg.each_key.all? do |key|
|
191
|
+
match_value(actual_arg, superset, key)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
data/lib/muack/spy.rb
CHANGED
@@ -10,10 +10,8 @@ module Muack
|
|
10
10
|
|
11
11
|
# used for Muack::Session#verify
|
12
12
|
def __mock_verify
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
super # simulate dispatching before passing to mock to verify
|
13
|
+
__mock_dispatch_spy
|
14
|
+
super
|
17
15
|
end
|
18
16
|
|
19
17
|
# used for Muack::Session#reset, but spies never leave any track
|
@@ -21,5 +19,21 @@ module Muack
|
|
21
19
|
|
22
20
|
private
|
23
21
|
def __mock_inject_method defi; end # spies don't leave any track
|
22
|
+
|
23
|
+
# simulate dispatching before passing to mock to verify
|
24
|
+
def __mock_dispatch_spy
|
25
|
+
@stub.__mock_disps.values.flatten.each do |disp|
|
26
|
+
next unless __mock_defis.key?(disp.msg) # ignore undefined spies
|
27
|
+
|
28
|
+
defis = __mock_defis[disp.msg]
|
29
|
+
if idx = __mock_find_checked_difi(defis, disp, :index)
|
30
|
+
__mock_disps_push(defis.delete_at(idx)) # found, dispatch it
|
31
|
+
elsif defis.empty? # show called candidates
|
32
|
+
__mock_failed(disp)
|
33
|
+
else # show expected candidates
|
34
|
+
__mock_failed(disp, defis)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
24
38
|
end
|
25
39
|
end
|
data/lib/muack/stub.rb
CHANGED
@@ -14,15 +14,16 @@ module Muack
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# used for mocked object to dispatch mocked method
|
17
|
-
def __mock_dispatch
|
18
|
-
|
19
|
-
|
17
|
+
def __mock_dispatch actual_call
|
18
|
+
defis = __mock_defis[actual_call.msg]
|
19
|
+
|
20
|
+
if disp = __mock_find_checked_difi(defis, actual_call)
|
20
21
|
# our spies are interested in this
|
21
|
-
__mock_disps_push(
|
22
|
-
|
22
|
+
__mock_disps_push(actual_call)
|
23
|
+
disp
|
23
24
|
else
|
24
25
|
Mock.__send__(:raise, # Wrong argument
|
25
|
-
Unexpected.new(object,
|
26
|
+
Unexpected.new(object, defis, actual_call))
|
26
27
|
end
|
27
28
|
end
|
28
29
|
end
|
data/lib/muack/test.rb
CHANGED
@@ -2,20 +2,51 @@
|
|
2
2
|
require 'pork/auto'
|
3
3
|
require 'muack'
|
4
4
|
|
5
|
-
Pork::
|
5
|
+
Pork::Suite.include(Muack::API)
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
def
|
10
|
-
|
11
|
-
end
|
12
|
-
def
|
13
|
-
|
7
|
+
Str = String.new('Moo')
|
8
|
+
class Cls
|
9
|
+
def inspect
|
10
|
+
'obj'
|
11
|
+
end
|
12
|
+
def aloha a=0, b=1
|
13
|
+
[a, b]
|
14
|
+
end
|
15
|
+
def bonjour a: 0, b: 1
|
16
|
+
[a, b]
|
17
|
+
end
|
18
|
+
def ciao h={a: 0, b: 1}
|
19
|
+
h.values_at(:a, :b)
|
20
|
+
end
|
21
|
+
module Prepend
|
22
|
+
def prepend_aloha a=0, b=1
|
23
|
+
[a, b]
|
24
|
+
end
|
25
|
+
def prepend_bonjour a: 0, b: 1
|
26
|
+
[a, b]
|
27
|
+
end
|
28
|
+
def prepend_ciao h={a: 0, b: 1}
|
29
|
+
h.values_at(:a, :b)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
prepend Prepend
|
14
33
|
end
|
15
|
-
|
16
|
-
|
34
|
+
Obj = Cls.new
|
35
|
+
class << Obj
|
36
|
+
private def private
|
37
|
+
'pri'
|
38
|
+
end
|
39
|
+
|
40
|
+
def single_aloha a=0, b=1
|
41
|
+
[a, b]
|
42
|
+
end
|
43
|
+
def single_bonjour a: 0, b: 1
|
44
|
+
[a, b]
|
45
|
+
end
|
46
|
+
def single_ciao h={a: 0, b: 1}
|
47
|
+
h.values_at(:a, :b)
|
48
|
+
end
|
17
49
|
end
|
18
|
-
Obj.singleton_class.__send__(:private, :private)
|
19
50
|
|
20
51
|
Muack::EnsureReset = lambda{
|
21
52
|
[Obj, Str].each do |o|
|
data/lib/muack/version.rb
CHANGED
data/muack.gemspec
CHANGED
@@ -1,62 +1,72 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: muack 1.
|
2
|
+
# stub: muack 1.5.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
|
-
s.name = "muack"
|
6
|
-
s.version = "1.
|
5
|
+
s.name = "muack".freeze
|
6
|
+
s.version = "1.5.0"
|
7
7
|
|
8
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
|
-
s.require_paths = ["lib"]
|
10
|
-
s.authors = ["Lin Jen-Shin (godfat)"]
|
11
|
-
s.date = "
|
12
|
-
s.description = "Muack -- A fast, small, yet powerful mocking library.\n\nInspired by [RR][], and it's 32x times faster (750s vs 23s) than RR\nfor running [Rib][] tests.\n\n[RR]: https://github.com/rr/rr\n[Rib]: https://github.com/godfat/rib"
|
13
|
-
s.email = ["godfat (XD) godfat.org"]
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
|
+
s.require_paths = ["lib".freeze]
|
10
|
+
s.authors = ["Lin Jen-Shin (godfat)".freeze]
|
11
|
+
s.date = "2020-11-28"
|
12
|
+
s.description = "Muack -- A fast, small, yet powerful mocking library.\n\nInspired by [RR][], and it's 32x times faster (750s vs 23s) than RR\nfor running [Rib][] tests.\n\n[RR]: https://github.com/rr/rr\n[Rib]: https://github.com/godfat/rib".freeze
|
13
|
+
s.email = ["godfat (XD) godfat.org".freeze]
|
14
14
|
s.files = [
|
15
|
-
".gitignore",
|
16
|
-
".gitmodules",
|
17
|
-
".travis.yml",
|
18
|
-
"CHANGES.md",
|
19
|
-
"Gemfile",
|
20
|
-
"LICENSE",
|
21
|
-
"README.md",
|
22
|
-
"Rakefile",
|
23
|
-
"lib/muack.rb",
|
24
|
-
"lib/muack/any_instance_of.rb",
|
25
|
-
"lib/muack/block.rb",
|
26
|
-
"lib/muack/
|
27
|
-
"lib/muack/
|
28
|
-
"lib/muack/
|
29
|
-
"lib/muack/
|
30
|
-
"lib/muack/
|
31
|
-
"lib/muack/
|
32
|
-
"lib/muack/
|
33
|
-
"lib/muack/
|
34
|
-
"lib/muack/
|
35
|
-
"lib/muack/
|
36
|
-
"lib/muack/
|
37
|
-
"lib/muack/
|
38
|
-
"muack.
|
39
|
-
"
|
40
|
-
"
|
41
|
-
"
|
42
|
-
"
|
43
|
-
"test/
|
44
|
-
"test/
|
45
|
-
"test/
|
46
|
-
"test/
|
47
|
-
"test/
|
48
|
-
"test/
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
15
|
+
".gitignore".freeze,
|
16
|
+
".gitmodules".freeze,
|
17
|
+
".travis.yml".freeze,
|
18
|
+
"CHANGES.md".freeze,
|
19
|
+
"Gemfile".freeze,
|
20
|
+
"LICENSE".freeze,
|
21
|
+
"README.md".freeze,
|
22
|
+
"Rakefile".freeze,
|
23
|
+
"lib/muack.rb".freeze,
|
24
|
+
"lib/muack/any_instance_of.rb".freeze,
|
25
|
+
"lib/muack/block.rb".freeze,
|
26
|
+
"lib/muack/block_26.rb".freeze,
|
27
|
+
"lib/muack/block_27.rb".freeze,
|
28
|
+
"lib/muack/coat.rb".freeze,
|
29
|
+
"lib/muack/definition.rb".freeze,
|
30
|
+
"lib/muack/error.rb".freeze,
|
31
|
+
"lib/muack/failure.rb".freeze,
|
32
|
+
"lib/muack/mock.rb".freeze,
|
33
|
+
"lib/muack/modifier.rb".freeze,
|
34
|
+
"lib/muack/satisfying.rb".freeze,
|
35
|
+
"lib/muack/session.rb".freeze,
|
36
|
+
"lib/muack/spy.rb".freeze,
|
37
|
+
"lib/muack/stub.rb".freeze,
|
38
|
+
"lib/muack/test.rb".freeze,
|
39
|
+
"lib/muack/version.rb".freeze,
|
40
|
+
"muack.gemspec".freeze,
|
41
|
+
"task/README.md".freeze,
|
42
|
+
"task/gemgem.rb".freeze,
|
43
|
+
"test/test_any_instance_of.rb".freeze,
|
44
|
+
"test/test_coat.rb".freeze,
|
45
|
+
"test/test_from_readme.rb".freeze,
|
46
|
+
"test/test_keyargs.rb".freeze,
|
47
|
+
"test/test_mock.rb".freeze,
|
48
|
+
"test/test_modifier.rb".freeze,
|
49
|
+
"test/test_prepend.rb".freeze,
|
50
|
+
"test/test_proxy.rb".freeze,
|
51
|
+
"test/test_satisfying.rb".freeze,
|
52
|
+
"test/test_spy.rb".freeze,
|
53
|
+
"test/test_stub.rb".freeze,
|
54
|
+
"test/test_visibility.rb".freeze]
|
55
|
+
s.homepage = "https://github.com/godfat/muack".freeze
|
56
|
+
s.licenses = ["Apache-2.0".freeze]
|
57
|
+
s.rubygems_version = "3.1.4".freeze
|
58
|
+
s.summary = "Muack -- A fast, small, yet powerful mocking library.".freeze
|
53
59
|
s.test_files = [
|
54
|
-
"test/test_any_instance_of.rb",
|
55
|
-
"test/test_coat.rb",
|
56
|
-
"test/test_from_readme.rb",
|
57
|
-
"test/
|
58
|
-
"test/
|
59
|
-
"test/
|
60
|
-
"test/
|
61
|
-
"test/
|
60
|
+
"test/test_any_instance_of.rb".freeze,
|
61
|
+
"test/test_coat.rb".freeze,
|
62
|
+
"test/test_from_readme.rb".freeze,
|
63
|
+
"test/test_keyargs.rb".freeze,
|
64
|
+
"test/test_mock.rb".freeze,
|
65
|
+
"test/test_modifier.rb".freeze,
|
66
|
+
"test/test_prepend.rb".freeze,
|
67
|
+
"test/test_proxy.rb".freeze,
|
68
|
+
"test/test_satisfying.rb".freeze,
|
69
|
+
"test/test_spy.rb".freeze,
|
70
|
+
"test/test_stub.rb".freeze,
|
71
|
+
"test/test_visibility.rb".freeze]
|
62
72
|
end
|