muack 1.1.1 → 1.1.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/.travis.yml +3 -3
- data/CHANGES.md +10 -0
- data/Gemfile +1 -1
- data/README.md +43 -9
- data/lib/muack.rb +5 -0
- data/lib/muack/any_instance_of.rb +4 -0
- data/lib/muack/coat.rb +16 -0
- data/lib/muack/failure.rb +1 -1
- data/lib/muack/mock.rb +13 -11
- data/lib/muack/session.rb +16 -10
- data/lib/muack/test.rb +3 -10
- data/lib/muack/version.rb +1 -1
- data/muack.gemspec +7 -4
- data/task/gemgem.rb +1 -5
- data/test/test_any_instance_of.rb +25 -27
- data/test/test_coat.rb +48 -0
- data/test/test_from_readme.rb +3 -3
- data/test/test_mock.rb +64 -90
- data/test/test_modifier.rb +17 -17
- data/test/test_proxy.rb +20 -24
- data/test/test_satisfy.rb +97 -179
- data/test/test_stub.rb +50 -74
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa29c09257f78580be72e3872fc7d3ef05650e02
|
4
|
+
data.tar.gz: 222e4d730c838c6f76d701c0505b41f7b3476d1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e539ea17a87076e48f85d980ad7e2c58afb91c8c627af09f05266a2811ecf2d22efb7adbc49f117c240ffca3c34a5e95229457ab2d82a7e8174a132aa17798e
|
7
|
+
data.tar.gz: 3b2de41a40ab1134c0952ec763423a0a07b0967ce180b076e129ecde0063ddc05853e278cf6b5fb2d0bb36ecb7ac6d612f3471bd3abefa0ff69a8b79fe0660e4
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## Muack 1.1.2 -- 2014-11-07
|
4
|
+
|
5
|
+
* Introduced `Muack::API.coat`.
|
6
|
+
See [README.md](README.md#coats) for explanation.
|
7
|
+
|
8
|
+
* `Muack::Session` is no longer a hash. Hope no one is trying to store
|
9
|
+
anything into it so this change would break nothing.
|
10
|
+
|
11
|
+
* `Muack::Failure` is no longer an Exception, but a StandardError.
|
12
|
+
|
3
13
|
## Muack 1.1.1 -- 2014-05-21
|
4
14
|
|
5
15
|
It's no longer necessary to make spy the last call. Below now works:
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -33,27 +33,27 @@ Muack is much simpler and thus much faster and much more consistent.
|
|
33
33
|
|
34
34
|
## SYNOPSIS:
|
35
35
|
|
36
|
-
Here's a quick example using [
|
36
|
+
Here's a quick example using [Pork][].
|
37
37
|
|
38
38
|
``` ruby
|
39
|
-
require '
|
39
|
+
require 'pork/auto'
|
40
40
|
require 'muack'
|
41
41
|
|
42
|
-
|
42
|
+
include Muack::API
|
43
43
|
|
44
44
|
describe 'Hello' do
|
45
45
|
before{ Muack.reset }
|
46
46
|
after { Muack.verify }
|
47
47
|
|
48
|
-
|
48
|
+
would 'say world!' do
|
49
49
|
str = 'Hello'
|
50
50
|
mock(str).say('!'){ |arg| "World#{arg}" }
|
51
|
-
str.say('!').should.
|
51
|
+
str.say('!').should.eq 'World!'
|
52
52
|
end
|
53
53
|
end
|
54
54
|
```
|
55
55
|
|
56
|
-
[
|
56
|
+
[Pork]: https://github.com/godfat/pork
|
57
57
|
|
58
58
|
### Overview
|
59
59
|
|
@@ -71,14 +71,15 @@ Let's explain them one by one.
|
|
71
71
|
|
72
72
|
### Mocks
|
73
73
|
|
74
|
-
There are also
|
74
|
+
There are also 4 different kinds of mocks in Muack, which are:
|
75
75
|
|
76
76
|
* Mocks
|
77
77
|
* Stubs
|
78
78
|
* Spies
|
79
|
+
* Coats
|
79
80
|
|
80
|
-
You could think of _mocks_ are sort of _stubs_ combined with _spies_.
|
81
|
-
the inequation:
|
81
|
+
You could think of _mocks_ are sort of _stubs_ combined with _spies_.
|
82
|
+
Here's the inequation: (we'll talk about _coats_ later)
|
82
83
|
|
83
84
|
mock >= stub + spy
|
84
85
|
|
@@ -183,6 +184,39 @@ p name.to_s # 'str'
|
|
183
184
|
p Muack.verify # true
|
184
185
|
```
|
185
186
|
|
187
|
+
### Coats
|
188
|
+
|
189
|
+
Now we could talk about coats. It's a kind of mocks but it would wear out
|
190
|
+
instead of raising an exception when it's called more than expected times.
|
191
|
+
This is useful when we want to restore the original behaviour of a
|
192
|
+
particular method at some point. The problem is that we can't simply
|
193
|
+
call the original method because it's already mocked! We could workaround
|
194
|
+
this by using `Muack.verify` or `Muack.reset` at some point, or let _coats_
|
195
|
+
handle that.
|
196
|
+
|
197
|
+
Here's an example with _coats_:
|
198
|
+
|
199
|
+
``` ruby
|
200
|
+
coat(Time).now{ Time.at(0) }.times(2)
|
201
|
+
|
202
|
+
p Time.now.to_i == 0 # true
|
203
|
+
p Time.now.to_i == 0 # true
|
204
|
+
p Time.now.to_i > 0 # true
|
205
|
+
p Muack.verify # true
|
206
|
+
```
|
207
|
+
|
208
|
+
Without _coats_ we might end up with:
|
209
|
+
|
210
|
+
``` ruby
|
211
|
+
mock(Time).now{ Time.at(0) }
|
212
|
+
mock(Time).now{ Muack.verify(Time); Time.at(0) }
|
213
|
+
|
214
|
+
p Time.now.to_i == 0 # true
|
215
|
+
p Time.now.to_i == 0 # true
|
216
|
+
p Time.now.to_i > 0 # true
|
217
|
+
p Muack.verify # true
|
218
|
+
```
|
219
|
+
|
186
220
|
#### Anonymous mode
|
187
221
|
|
188
222
|
Sometimes we just want to stub something without a concrete object in mind.
|
data/lib/muack.rb
CHANGED
@@ -31,6 +31,11 @@ module Muack
|
|
31
31
|
if block_given? then yield(ret) else ret end
|
32
32
|
end
|
33
33
|
|
34
|
+
def coat obj=Object.new
|
35
|
+
ret = Muack.session.coat(obj)
|
36
|
+
if block_given? then yield(ret) else ret end
|
37
|
+
end
|
38
|
+
|
34
39
|
def spy obj
|
35
40
|
ret = Muack.session.spy(obj)
|
36
41
|
if block_given? then yield(ret) else ret end
|
data/lib/muack/coat.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
require 'muack/mock'
|
3
|
+
|
4
|
+
module Muack
|
5
|
+
class Coat < Mock
|
6
|
+
# used for mocked object to dispatch mocked method
|
7
|
+
def __mock_dispatch msg, actual_args
|
8
|
+
defi = super
|
9
|
+
if __mock_defis[defi.msg].empty?
|
10
|
+
__mock_reset_method(defi)
|
11
|
+
__mock_injected.delete(defi.msg)
|
12
|
+
end
|
13
|
+
defi
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/muack/failure.rb
CHANGED
data/lib/muack/mock.rb
CHANGED
@@ -112,17 +112,7 @@ module Muack
|
|
112
112
|
|
113
113
|
# used for Muack::Session#reset
|
114
114
|
def __mock_reset
|
115
|
-
__mock_injected.each_value
|
116
|
-
object.singleton_class.module_eval do
|
117
|
-
remove_method(defi.msg)
|
118
|
-
# restore original method
|
119
|
-
if instance_methods(false).include?(defi.original_method) ||
|
120
|
-
private_instance_methods(false).include?(defi.original_method)
|
121
|
-
alias_method(defi.msg, defi.original_method)
|
122
|
-
remove_method(defi.original_method)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
115
|
+
__mock_injected.each_value{ |defi| __mock_reset_method(defi) }
|
126
116
|
end
|
127
117
|
|
128
118
|
protected # get warnings for private attributes
|
@@ -136,6 +126,18 @@ module Muack
|
|
136
126
|
__mock_inject_mock_method(target, defi, privilege)
|
137
127
|
end
|
138
128
|
|
129
|
+
def __mock_reset_method defi
|
130
|
+
object.singleton_class.module_eval do
|
131
|
+
remove_method(defi.msg)
|
132
|
+
# restore original method
|
133
|
+
if instance_methods(false).include?(defi.original_method) ||
|
134
|
+
private_instance_methods(false).include?(defi.original_method)
|
135
|
+
alias_method(defi.msg, defi.original_method)
|
136
|
+
remove_method(defi.original_method)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
139
141
|
def self.store_original_method klass, defi
|
140
142
|
privilege = if klass.instance_methods(false).include?(defi.msg)
|
141
143
|
:public # TODO: forget about protected methods?
|
data/lib/muack/session.rb
CHANGED
@@ -1,24 +1,29 @@
|
|
1
1
|
|
2
2
|
require 'muack/mock'
|
3
3
|
require 'muack/stub'
|
4
|
+
require 'muack/coat'
|
4
5
|
require 'muack/spy'
|
5
6
|
require 'muack/any_instance_of'
|
6
7
|
|
7
8
|
module Muack
|
8
|
-
class Session
|
9
|
-
|
10
|
-
def
|
11
|
-
|
9
|
+
class Session
|
10
|
+
attr_reader :data
|
11
|
+
def initialize; @data = {}; end
|
12
|
+
|
13
|
+
def mock obj; data["mk #{obj.__id__}"] ||= Mock.new(obj) ; end
|
14
|
+
def stub obj; data["sb #{obj.__id__}"] ||= Stub.new(obj) ; end
|
15
|
+
def coat obj; data["co #{obj.__id__}"] ||= Coat.new(obj) ; end
|
16
|
+
def spy obj; data["sy #{obj.__id__}"] ||= Spy .new(stub(obj)); end
|
12
17
|
|
13
18
|
def any_instance_of kls
|
14
|
-
|
19
|
+
data["ai #{kls.__id__}"] ||= AnyInstanceOf.new(kls)
|
15
20
|
end
|
16
21
|
|
17
22
|
def verify obj=nil
|
18
23
|
if obj
|
19
24
|
with(obj, :[]).all?(&:__mock_verify)
|
20
25
|
else
|
21
|
-
each_value.all?(&:__mock_verify)
|
26
|
+
data.each_value.all?(&:__mock_verify)
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
@@ -26,15 +31,16 @@ module Muack
|
|
26
31
|
if obj
|
27
32
|
with(obj, :delete).each(&:__mock_reset)
|
28
33
|
else
|
29
|
-
|
30
|
-
|
31
|
-
clear
|
34
|
+
data.reverse_each{ |_, m| m.__mock_reset } # reverse_each_value?
|
35
|
+
data.clear
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
35
39
|
private
|
36
40
|
def with obj, meth
|
37
|
-
%w[mk sb sy].map{ |k|
|
41
|
+
%w[mk sb co sy ai].map{ |k|
|
42
|
+
data.__send__(meth, "#{k} #{obj.__id__}")
|
43
|
+
}.compact
|
38
44
|
end
|
39
45
|
end
|
40
46
|
end
|
data/lib/muack/test.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
|
2
|
-
require '
|
2
|
+
require 'pork/auto'
|
3
3
|
require 'muack'
|
4
4
|
|
5
|
-
|
6
|
-
Bacon::Context.__send__(:include, Muack::API)
|
5
|
+
Pork::Executor.__send__(:include, Muack::API)
|
7
6
|
|
8
7
|
Obj = Object.new
|
9
8
|
Str = 'Moo'
|
@@ -22,12 +21,6 @@ Muack::EnsureReset = lambda{
|
|
22
21
|
[Obj, Str].each do |o|
|
23
22
|
o.methods.select{ |m|
|
24
23
|
m.to_s.start_with?('__muack_mock') || m.to_s.start_with?('say')
|
25
|
-
}.should.empty
|
24
|
+
}.should.empty?
|
26
25
|
end
|
27
26
|
}
|
28
|
-
|
29
|
-
module Kernel
|
30
|
-
def eq? rhs
|
31
|
-
self == rhs
|
32
|
-
end
|
33
|
-
end
|
data/lib/muack/version.rb
CHANGED
data/muack.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: muack 1.1.
|
2
|
+
# stub: muack 1.1.2 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "muack"
|
6
|
-
s.version = "1.1.
|
6
|
+
s.version = "1.1.2"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib"]
|
10
10
|
s.authors = ["Lin Jen-Shin (godfat)"]
|
11
|
-
s.date = "2014-
|
11
|
+
s.date = "2014-11-07"
|
12
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
13
|
s.email = ["godfat (XD) godfat.org"]
|
14
14
|
s.files = [
|
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
"lib/muack.rb",
|
24
24
|
"lib/muack/any_instance_of.rb",
|
25
25
|
"lib/muack/block.rb",
|
26
|
+
"lib/muack/coat.rb",
|
26
27
|
"lib/muack/definition.rb",
|
27
28
|
"lib/muack/error.rb",
|
28
29
|
"lib/muack/failure.rb",
|
@@ -38,6 +39,7 @@ Gem::Specification.new do |s|
|
|
38
39
|
"task/README.md",
|
39
40
|
"task/gemgem.rb",
|
40
41
|
"test/test_any_instance_of.rb",
|
42
|
+
"test/test_coat.rb",
|
41
43
|
"test/test_from_readme.rb",
|
42
44
|
"test/test_mock.rb",
|
43
45
|
"test/test_modifier.rb",
|
@@ -46,10 +48,11 @@ Gem::Specification.new do |s|
|
|
46
48
|
"test/test_stub.rb"]
|
47
49
|
s.homepage = "https://github.com/godfat/muack"
|
48
50
|
s.licenses = ["Apache License 2.0"]
|
49
|
-
s.rubygems_version = "2.
|
51
|
+
s.rubygems_version = "2.4.2"
|
50
52
|
s.summary = "Muack -- A fast, small, yet powerful mocking library."
|
51
53
|
s.test_files = [
|
52
54
|
"test/test_any_instance_of.rb",
|
55
|
+
"test/test_coat.rb",
|
53
56
|
"test/test_from_readme.rb",
|
54
57
|
"test/test_mock.rb",
|
55
58
|
"test/test_modifier.rb",
|
data/task/gemgem.rb
CHANGED
@@ -34,7 +34,7 @@ module Gemgem
|
|
34
34
|
s.executables = bin_files
|
35
35
|
end
|
36
36
|
spec_create.call(spec)
|
37
|
-
spec.homepage
|
37
|
+
spec.homepage ||= "https://github.com/godfat/#{spec.name}"
|
38
38
|
self.spec = spec
|
39
39
|
end
|
40
40
|
|
@@ -227,10 +227,6 @@ end # of gem namespace
|
|
227
227
|
desc 'Run tests'
|
228
228
|
task :test do
|
229
229
|
next if Gemgem.test_files.empty?
|
230
|
-
|
231
|
-
require 'bacon'
|
232
|
-
Bacon.extend(Bacon::TestUnitOutput)
|
233
|
-
Bacon.summary_on_exit
|
234
230
|
Gemgem.test_files.each{ |file| require "#{Gemgem.dir}/#{file[0..-4]}" }
|
235
231
|
end
|
236
232
|
|
@@ -4,7 +4,7 @@ require 'muack/test'
|
|
4
4
|
describe Muack::AnyInstanceOf do
|
5
5
|
klass = Class.new{ def f; 0; end; private; def g; 1; end }
|
6
6
|
|
7
|
-
|
7
|
+
would 'mock any_instance_of' do
|
8
8
|
any_instance_of(klass){ |inst| mock(inst).say{ true } }
|
9
9
|
obj = klass.new
|
10
10
|
obj.say .should.eq true
|
@@ -13,7 +13,7 @@ describe Muack::AnyInstanceOf do
|
|
13
13
|
obj.respond_to?(:say).should.eq false
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
would 'mock any_instance_of with instance_exec' do
|
17
17
|
any_instance_of(klass){ |inst|
|
18
18
|
mock(inst).say.returns(:instance_exec => true){ f } }
|
19
19
|
obj = klass.new
|
@@ -22,7 +22,7 @@ describe Muack::AnyInstanceOf do
|
|
22
22
|
obj.respond_to?(:say).should.eq false
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
would 'proxy any_instance_of' do
|
26
26
|
any_instance_of(klass){ |inst| mock(inst).f }
|
27
27
|
obj = klass.new
|
28
28
|
obj.f .should.eq 0
|
@@ -30,7 +30,7 @@ describe Muack::AnyInstanceOf do
|
|
30
30
|
obj.f .should.eq 0
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
would 'proxy any_instance_of for private methods' do
|
34
34
|
any_instance_of(klass){ |inst| mock(inst).g.peek_return{|i|i+1} }
|
35
35
|
obj = klass.new
|
36
36
|
obj.__send__(:g).should.eq 2
|
@@ -38,7 +38,7 @@ describe Muack::AnyInstanceOf do
|
|
38
38
|
obj.__send__(:g).should.eq 1
|
39
39
|
end
|
40
40
|
|
41
|
-
|
41
|
+
would 'proxy any_instance_of with peek_return' do
|
42
42
|
any_instance_of(klass){ |inst| mock(inst).f.peek_return{|i|i+1} }
|
43
43
|
obj = klass.new
|
44
44
|
obj.f .should.eq 1
|
@@ -46,7 +46,7 @@ describe Muack::AnyInstanceOf do
|
|
46
46
|
obj.f .should.eq 0
|
47
47
|
end
|
48
48
|
|
49
|
-
|
49
|
+
would 'proxy with multiple any_instance_of call' do
|
50
50
|
any_instance_of(klass){ |inst| mock(inst).f.peek_return{ |i| i+1 } }
|
51
51
|
any_instance_of(klass){ |inst| mock(inst).f.peek_return{ |i| i+2 } }
|
52
52
|
obj = klass.new
|
@@ -56,7 +56,7 @@ describe Muack::AnyInstanceOf do
|
|
56
56
|
obj.f.should.eq 0
|
57
57
|
end
|
58
58
|
|
59
|
-
|
59
|
+
would 'mock with multiple any_instance_of call' do
|
60
60
|
any_instance_of(klass){ |inst| mock(inst).f(is_a(Fixnum)){ |i| i+1 } }
|
61
61
|
any_instance_of(klass){ |inst| mock(inst).f(is_a(Fixnum)){ |i| i+2 } }
|
62
62
|
obj = klass.new
|
@@ -66,14 +66,14 @@ describe Muack::AnyInstanceOf do
|
|
66
66
|
obj.f.should.eq 0
|
67
67
|
end
|
68
68
|
|
69
|
-
|
69
|
+
would 'share the same counts for different instances' do
|
70
70
|
times = 2
|
71
71
|
any_instance_of(klass){ |inst| mock(inst).f{0}.times(times) }
|
72
72
|
times.times{ klass.new.f.should.eq 0 }
|
73
73
|
Muack.verify.should.eq true
|
74
74
|
end
|
75
75
|
|
76
|
-
|
76
|
+
would 'stub proxy with any_instance_of and spy' do
|
77
77
|
any_instance_of(klass){ |inst| stub(inst).f.peek_return{ |i| i+3 } }
|
78
78
|
obj = klass.new
|
79
79
|
obj.f.should.eq 3
|
@@ -83,35 +83,33 @@ describe Muack::AnyInstanceOf do
|
|
83
83
|
obj.f.should.eq 0
|
84
84
|
end
|
85
85
|
|
86
|
-
|
86
|
+
would 'stub with any_instance_of and spy under satisfied' do
|
87
87
|
any_instance_of(klass){ |inst| stub(inst).f{ 5 } }
|
88
88
|
obj = klass.new
|
89
89
|
obj.f.should.eq 5
|
90
90
|
spy(any_instance_of(klass)).f.times(2)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
91
|
+
|
92
|
+
e = should.raise(Muack::Expected){ Muack.verify }
|
93
|
+
expected = /Muack::API\.any_instance_of\(.+?\)\.f\(\)/
|
94
|
+
e.expected .should =~ expected
|
95
|
+
e.expected_times.should.eq 2
|
96
|
+
e.actual_times .should.eq 1
|
97
|
+
|
99
98
|
obj.f.should.eq 0
|
100
99
|
end
|
101
100
|
|
102
|
-
|
101
|
+
would 'stub with any_instance_of and spy over satisfied' do
|
103
102
|
any_instance_of(klass){ |inst| stub(inst).f{ 2 } }
|
104
103
|
obj = klass.new
|
105
104
|
2.times{ obj.f.should.eq 2 }
|
106
105
|
spy(any_instance_of(klass)).f
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
106
|
+
|
107
|
+
e = should.raise(Muack::Expected){ Muack.verify }
|
108
|
+
expected = /Muack::API\.any_instance_of\(.+?\)\.f\(\)/
|
109
|
+
e.expected .should =~ expected
|
110
|
+
e.expected_times.should.eq 1
|
111
|
+
e.actual_times .should.eq 2
|
112
|
+
|
115
113
|
obj.f.should.eq 0
|
116
114
|
end
|
117
115
|
end
|