caricature 0.7.6 → 0.7.7
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.
- data/caricature.gemspec +3 -3
- data/lib/bin/Workarounds.dll.mdb +0 -0
- data/lib/caricature.rb +25 -25
- data/lib/caricature/clr.rb +6 -6
- data/lib/caricature/clr/aspnet_mvc.rb +54 -54
- data/lib/caricature/core_ext.rb +10 -10
- data/lib/caricature/core_ext/array.rb +9 -9
- data/lib/caricature/core_ext/class.rb +31 -14
- data/lib/caricature/core_ext/hash.rb +12 -12
- data/lib/caricature/core_ext/module.rb +14 -14
- data/lib/caricature/core_ext/object.rb +76 -18
- data/lib/caricature/core_ext/string.rb +16 -16
- data/lib/caricature/core_ext/system/string.rb +20 -20
- data/lib/caricature/core_ext/system/type.rb +26 -26
- data/lib/caricature/descriptor.rb +73 -73
- data/lib/caricature/expectation.rb +264 -263
- data/lib/caricature/isolation.rb +143 -143
- data/lib/caricature/isolator.rb +302 -302
- data/lib/caricature/messenger.rb +67 -67
- data/lib/caricature/method_call_recorder.rb +228 -228
- data/lib/caricature/verification.rb +60 -60
- data/lib/caricature/version.rb +1 -1
- data/spec/bacon/integration/clr_to_clr_spec.rb +4 -4
- data/spec/bacon/integration/clr_to_ruby_spec.rb +227 -227
- data/spec/bacon/integration/event_spec.rb +2 -2
- data/spec/bacon/integration/ruby_to_ruby_spec.rb +270 -270
- data/spec/bacon/integration/syntax_spec.rb +43 -0
- data/spec/bacon/unit/core_ext_spec.rb +87 -87
- data/spec/bacon/unit/expectation_spec.rb +300 -300
- data/spec/bacon/unit/interop_spec.rb +29 -29
- data/spec/bacon/unit/isolation_spec.rb +86 -86
- data/spec/bacon/unit/isolator_spec.rb +219 -219
- data/spec/bacon/unit/messaging_spec.rb +310 -310
- data/spec/bacon/unit/method_call_spec.rb +342 -342
- data/spec/bin/ClrModels.dll.mdb +0 -0
- data/spec/rspec/unit/event_spec.rb +1 -1
- metadata +31 -11
- data/spec/models.notused/ClrModels.cs +0 -241
- data/spec/models.notused/ruby_models.rb +0 -151
data/lib/caricature/messenger.rb
CHANGED
@@ -1,68 +1,68 @@
|
|
1
|
-
module Caricature
|
2
|
-
|
3
|
-
# A base class to encapsulate method invocation
|
4
|
-
class Messenger
|
5
|
-
|
6
|
-
# contains the recorder for recording method calls
|
7
|
-
attr_accessor :recorder
|
8
|
-
|
9
|
-
# the real instance of the isolated subject
|
10
|
-
# used to forward calls in partial mocks
|
11
|
-
attr_reader :instance
|
12
|
-
|
13
|
-
# the expecations that have been set for the isolation
|
14
|
-
attr_reader :expectations
|
15
|
-
|
16
|
-
# creates a new instance of this messaging strategy
|
17
|
-
def initialize(expectations, instance=nil)
|
18
|
-
@instance, @expectations = instance, expectations
|
19
|
-
end
|
20
|
-
|
21
|
-
# deliver the message to the receiving isolation
|
22
|
-
def deliver(method_name, return_type, *args, &b)
|
23
|
-
|
24
|
-
internal_deliver(:instance, method_name, return_type, *args, &b)
|
25
|
-
end
|
26
|
-
|
27
|
-
# deliver the message to class of the receiving isolation
|
28
|
-
def deliver_to_class(method_name, return_type, *args, &b)
|
29
|
-
internal_deliver(:class, method_name, return_type, *args, &b)
|
30
|
-
end
|
31
|
-
|
32
|
-
protected
|
33
|
-
|
34
|
-
# template method for looking up the expectation and/or returning a value
|
35
|
-
def internal_deliver(mode, method_name, return_type, *args, &b)
|
36
|
-
raise NotImplementedError.new("Override in an implementing class")
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
def record_call(method_name, mode, expectation, *args, &b)
|
41
|
-
recorder.record_call method_name, mode, expectation, *args, &b if recorder
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
# Encapsulates sending messages to Ruby isolations
|
47
|
-
class RubyMessenger < Messenger
|
48
|
-
|
49
|
-
protected
|
50
|
-
|
51
|
-
# implementation of the template method for looking up the expectation and/or returning a value
|
52
|
-
def internal_deliver(mode, method_name, return_type, *args, &b)
|
53
|
-
exp = expectations.find(method_name, mode, *args)
|
54
|
-
bl = record_call(method_name, mode, exp, *args, &b)
|
55
|
-
if exp
|
56
|
-
block = exp.block || b
|
57
|
-
res = instance.__send__(method_name, *args, &block) if exp.super_before?
|
58
|
-
res = exp.execute *args, &bl
|
59
|
-
res = instance.__send__(method_name, *args, &block) if !exp.super_before? and exp.call_super?
|
60
|
-
res
|
61
|
-
else
|
62
|
-
nil
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
1
|
+
module Caricature
|
2
|
+
|
3
|
+
# A base class to encapsulate method invocation
|
4
|
+
class Messenger
|
5
|
+
|
6
|
+
# contains the recorder for recording method calls
|
7
|
+
attr_accessor :recorder
|
8
|
+
|
9
|
+
# the real instance of the isolated subject
|
10
|
+
# used to forward calls in partial mocks
|
11
|
+
attr_reader :instance
|
12
|
+
|
13
|
+
# the expecations that have been set for the isolation
|
14
|
+
attr_reader :expectations
|
15
|
+
|
16
|
+
# creates a new instance of this messaging strategy
|
17
|
+
def initialize(expectations, instance=nil)
|
18
|
+
@instance, @expectations = instance, expectations
|
19
|
+
end
|
20
|
+
|
21
|
+
# deliver the message to the receiving isolation
|
22
|
+
def deliver(method_name, return_type, *args, &b)
|
23
|
+
|
24
|
+
internal_deliver(:instance, method_name, return_type, *args, &b)
|
25
|
+
end
|
26
|
+
|
27
|
+
# deliver the message to class of the receiving isolation
|
28
|
+
def deliver_to_class(method_name, return_type, *args, &b)
|
29
|
+
internal_deliver(:class, method_name, return_type, *args, &b)
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
# template method for looking up the expectation and/or returning a value
|
35
|
+
def internal_deliver(mode, method_name, return_type, *args, &b)
|
36
|
+
raise NotImplementedError.new("Override in an implementing class")
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def record_call(method_name, mode, expectation, *args, &b)
|
41
|
+
recorder.record_call method_name, mode, expectation, *args, &b if recorder
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
# Encapsulates sending messages to Ruby isolations
|
47
|
+
class RubyMessenger < Messenger
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
# implementation of the template method for looking up the expectation and/or returning a value
|
52
|
+
def internal_deliver(mode, method_name, return_type, *args, &b)
|
53
|
+
exp = expectations.find(method_name, mode, *args)
|
54
|
+
bl = record_call(method_name, mode, exp, *args, &b)
|
55
|
+
if exp
|
56
|
+
block = exp.block || b
|
57
|
+
res = instance.__send__(method_name, *args, &block) if exp.super_before?
|
58
|
+
res = exp.execute *args, &bl
|
59
|
+
res = instance.__send__(method_name, *args, &block) if !exp.super_before? and exp.call_super?
|
60
|
+
res
|
61
|
+
else
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
68
|
end
|
@@ -1,229 +1,229 @@
|
|
1
|
-
module Caricature
|
2
|
-
|
3
|
-
class BlockCallRecording
|
4
|
-
attr_accessor :call_number
|
5
|
-
attr_reader :args
|
6
|
-
|
7
|
-
def initialize(*args)
|
8
|
-
@call_number = 1
|
9
|
-
@args = args
|
10
|
-
end
|
11
|
-
|
12
|
-
# compares one block variation to another.
|
13
|
-
# Also takes an array as an argument
|
14
|
-
def ==(other)
|
15
|
-
other = self.class.new(other) if other.respond_to?(:each)
|
16
|
-
return true if other.args.first.is_a?(Symbol) and other.args.first == :any
|
17
|
-
other.args == args
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
# A recording of an argument variation.
|
23
|
-
# Every time a method is called with different arguments
|
24
|
-
# the method call recorder will create an ArgumentVariation
|
25
|
-
# these variations are used later in the assertion
|
26
|
-
# to verify against specific argument values
|
27
|
-
class ArgumentRecording
|
28
|
-
|
29
|
-
# contains the arguments of the recorded parameters
|
30
|
-
attr_accessor :args
|
31
|
-
|
32
|
-
# contains the block for the recorded parameters
|
33
|
-
attr_accessor :block
|
34
|
-
|
35
|
-
# the number of the call that has the following parameters
|
36
|
-
attr_accessor :call_number
|
37
|
-
|
38
|
-
# the collection of block calls variations on this argument variation
|
39
|
-
attr_reader :blocks
|
40
|
-
|
41
|
-
# initializes a new instance of an argument recording.
|
42
|
-
# configures it with 1 call count and the args as an +Array+
|
43
|
-
def initialize(args=[], call_number=1, block=nil)
|
44
|
-
@args = args
|
45
|
-
@block = block
|
46
|
-
@blocks = []
|
47
|
-
@call_number = call_number
|
48
|
-
end
|
49
|
-
|
50
|
-
def add_block_variation(*args)
|
51
|
-
bv = find_block_variation(*args)
|
52
|
-
if bv.empty?
|
53
|
-
blocks << BlockCallRecording.new(*args)
|
54
|
-
else
|
55
|
-
bv.first.call_number += 1
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def find_block_variation(*args)
|
60
|
-
return @blocks if args.last.is_a?(Symbol) and args.last == :any
|
61
|
-
@blocks.select { |bv| bv.args == args }
|
62
|
-
end
|
63
|
-
|
64
|
-
# compares one argument variation to another.
|
65
|
-
# Also takes an array as an argument
|
66
|
-
def ==(other)
|
67
|
-
other = self.class.new(other) if other.respond_to?(:each)
|
68
|
-
return true if other.args.first.is_a?(Symbol) and other.args.first == :any
|
69
|
-
other.args == args
|
70
|
-
end
|
71
|
-
|
72
|
-
def to_s
|
73
|
-
"<ArgumentRecording @args=#{args}, @block= #{block}, @call_number=#{call_number}"
|
74
|
-
end
|
75
|
-
alias_method :inspect, :to_s
|
76
|
-
end
|
77
|
-
|
78
|
-
# A recording that represents a method call
|
79
|
-
# it contains argument variations that can be matched too
|
80
|
-
class MethodCallRecording
|
81
|
-
|
82
|
-
# gets or sets the method name
|
83
|
-
attr_accessor :method_name
|
84
|
-
|
85
|
-
# gets or sets the amount of times the method was called
|
86
|
-
attr_accessor :count
|
87
|
-
|
88
|
-
# gets or sets the arguments for this method call
|
89
|
-
attr_accessor :args
|
90
|
-
|
91
|
-
# gets or sets the block for this method call
|
92
|
-
attr_accessor :block
|
93
|
-
|
94
|
-
# Initializes a new instance of a method call recording
|
95
|
-
# every time a method gets called in an isolated object
|
96
|
-
# this gets stored in the method call recorder
|
97
|
-
# It expects a +method_name+ at the very least.
|
98
|
-
def initialize(method_name, count=0)
|
99
|
-
@method_name = method_name
|
100
|
-
@count = count
|
101
|
-
@variations = []
|
102
|
-
end
|
103
|
-
|
104
|
-
# add args
|
105
|
-
def args
|
106
|
-
@variations
|
107
|
-
end
|
108
|
-
|
109
|
-
# indicates if it has an argument variation
|
110
|
-
def has_argument_variations?
|
111
|
-
@variations.size > 1
|
112
|
-
end
|
113
|
-
|
114
|
-
# add an argument variation
|
115
|
-
def add_argument_variation(args, block)
|
116
|
-
variation = find_argument_variations args, nil
|
117
|
-
if variation.empty?
|
118
|
-
@variations << ArgumentRecording.new(args, @variations.size+1, block) if variation == []
|
119
|
-
else
|
120
|
-
variation.first.call_number += 1
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# finds an argument variation that matches the provided +args+
|
125
|
-
def find_argument_variations(args, block_args)
|
126
|
-
return @variations if args.first.is_a?(Symbol) and args.last == :any
|
127
|
-
return match_hash(args, block_args) if args.size == 1 and args.last.is_a?(Hash)
|
128
|
-
return @variations.select { |ar| ar.args == args } if block_args.nil?
|
129
|
-
return @variations.select { |ar| ar.args == args and ar.block } if block_args.last == :any
|
130
|
-
return @variations.select do |ar|
|
131
|
-
av = ar.args == args
|
132
|
-
# idx = 0
|
133
|
-
# ags = ar.args
|
134
|
-
# av = args.all? do |ag|
|
135
|
-
# rag = ags[idx]
|
136
|
-
# res = if ag.is_a?(Hash) and rag.is_a?(Hash)
|
137
|
-
# ag.all? { |k, v| ar.args[idx][k] == v }
|
138
|
-
# else
|
139
|
-
# ag == rag
|
140
|
-
# end
|
141
|
-
# idx += 1
|
142
|
-
# res
|
143
|
-
# end
|
144
|
-
av and not ar.find_block_variation(*block_args).empty?
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def match_hash(args, block_args)
|
149
|
-
@variations.select do |ar|
|
150
|
-
ags = ar.args.last
|
151
|
-
args.last.all? { |k, v| ags[k] == v }
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
# The recorder that will collect method calls and provides an interface for finding those recordings
|
157
|
-
class MethodCallRecorder
|
158
|
-
|
159
|
-
# gets the collection of method calls. This is a hash with the method name as key
|
160
|
-
attr_reader :method_calls
|
161
|
-
|
162
|
-
|
163
|
-
# Initializes a new instance of a method call recorder
|
164
|
-
# every time a method gets called in an isolated object
|
165
|
-
# this gets stored in the method call recorder
|
166
|
-
def initialize
|
167
|
-
@method_calls = {:instance => {}, :class => {} }
|
168
|
-
end
|
169
|
-
|
170
|
-
# records a method call or increments the count of how many times this method was called.
|
171
|
-
def record_call(method_name, mode=:instance, expectation=nil, *args, &block)
|
172
|
-
mn_sym = method_name.to_s.underscore.to_sym
|
173
|
-
method_calls[mode][mn_sym] ||= MethodCallRecording.new mn_sym.to_s
|
174
|
-
mc = method_calls[mode][mn_sym]
|
175
|
-
mc.count += 1
|
176
|
-
agc = mc.add_argument_variation args, block
|
177
|
-
b = (expectation && expectation.block) ? (expectation.block||block) : block
|
178
|
-
expectation.block = lambda do |*ags|
|
179
|
-
res = nil
|
180
|
-
res = b.call *ags if b
|
181
|
-
agc.first.add_block_variation *ags
|
182
|
-
res
|
183
|
-
end if expectation
|
184
|
-
block.nil? ? nil : (lambda { |*ags|
|
185
|
-
res = nil
|
186
|
-
res = block.call *ags if block
|
187
|
-
agc.first.add_block_variation *ags
|
188
|
-
res
|
189
|
-
})
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
def error
|
194
|
-
@error
|
195
|
-
end
|
196
|
-
|
197
|
-
# returns whether the method was actually called with the specified constraints
|
198
|
-
def was_called?(method_name, block_args, mode=:instance, *args)
|
199
|
-
mc = method_calls[mode][method_name.to_s.underscore.to_sym]
|
200
|
-
if mc
|
201
|
-
vari = mc.find_argument_variations(args, block_args)
|
202
|
-
result = vari.any? { |agv| agv == args }
|
203
|
-
return result if result
|
204
|
-
if args.size == 1 and args.last.is_a?(Hash)
|
205
|
-
result = vari.any? do |agv|
|
206
|
-
agv.args.last.is_a?(Hash) and args.last.all? { |k, v| agv.args.last[k] == v }
|
207
|
-
end
|
208
|
-
end
|
209
|
-
@error = "Arguments don't match.\nYou expected:\n#{args.join(", ")}.\nI did find the following variations:\n#{mc.args.collect {|ar| ar.args.join(', ') }.join("\nand\n")}" unless result
|
210
|
-
result
|
211
|
-
else
|
212
|
-
@error = "Couldn't find a method with name #{method_name}"
|
213
|
-
return !!mc
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
# # indexer that gives you access to the recorded method by method name
|
218
|
-
# def [](method_name)
|
219
|
-
# method_calls[:instance][method_name.to_s.to_sym]
|
220
|
-
# end
|
221
|
-
|
222
|
-
# returns the number of different methods that has been recorderd
|
223
|
-
def size
|
224
|
-
@method_calls.size
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
|
1
|
+
module Caricature
|
2
|
+
|
3
|
+
class BlockCallRecording
|
4
|
+
attr_accessor :call_number
|
5
|
+
attr_reader :args
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
@call_number = 1
|
9
|
+
@args = args
|
10
|
+
end
|
11
|
+
|
12
|
+
# compares one block variation to another.
|
13
|
+
# Also takes an array as an argument
|
14
|
+
def ==(other)
|
15
|
+
other = self.class.new(other) if other.respond_to?(:each)
|
16
|
+
return true if other.args.first.is_a?(Symbol) and other.args.first == :any
|
17
|
+
other.args == args
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
# A recording of an argument variation.
|
23
|
+
# Every time a method is called with different arguments
|
24
|
+
# the method call recorder will create an ArgumentVariation
|
25
|
+
# these variations are used later in the assertion
|
26
|
+
# to verify against specific argument values
|
27
|
+
class ArgumentRecording
|
28
|
+
|
29
|
+
# contains the arguments of the recorded parameters
|
30
|
+
attr_accessor :args
|
31
|
+
|
32
|
+
# contains the block for the recorded parameters
|
33
|
+
attr_accessor :block
|
34
|
+
|
35
|
+
# the number of the call that has the following parameters
|
36
|
+
attr_accessor :call_number
|
37
|
+
|
38
|
+
# the collection of block calls variations on this argument variation
|
39
|
+
attr_reader :blocks
|
40
|
+
|
41
|
+
# initializes a new instance of an argument recording.
|
42
|
+
# configures it with 1 call count and the args as an +Array+
|
43
|
+
def initialize(args=[], call_number=1, block=nil)
|
44
|
+
@args = args
|
45
|
+
@block = block
|
46
|
+
@blocks = []
|
47
|
+
@call_number = call_number
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_block_variation(*args)
|
51
|
+
bv = find_block_variation(*args)
|
52
|
+
if bv.empty?
|
53
|
+
blocks << BlockCallRecording.new(*args)
|
54
|
+
else
|
55
|
+
bv.first.call_number += 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_block_variation(*args)
|
60
|
+
return @blocks if args.last.is_a?(Symbol) and args.last == :any
|
61
|
+
@blocks.select { |bv| bv.args == args }
|
62
|
+
end
|
63
|
+
|
64
|
+
# compares one argument variation to another.
|
65
|
+
# Also takes an array as an argument
|
66
|
+
def ==(other)
|
67
|
+
other = self.class.new(other) if other.respond_to?(:each)
|
68
|
+
return true if other.args.first.is_a?(Symbol) and other.args.first == :any
|
69
|
+
other.args == args
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
"<ArgumentRecording @args=#{args}, @block= #{block}, @call_number=#{call_number}"
|
74
|
+
end
|
75
|
+
alias_method :inspect, :to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
# A recording that represents a method call
|
79
|
+
# it contains argument variations that can be matched too
|
80
|
+
class MethodCallRecording
|
81
|
+
|
82
|
+
# gets or sets the method name
|
83
|
+
attr_accessor :method_name
|
84
|
+
|
85
|
+
# gets or sets the amount of times the method was called
|
86
|
+
attr_accessor :count
|
87
|
+
|
88
|
+
# gets or sets the arguments for this method call
|
89
|
+
attr_accessor :args
|
90
|
+
|
91
|
+
# gets or sets the block for this method call
|
92
|
+
attr_accessor :block
|
93
|
+
|
94
|
+
# Initializes a new instance of a method call recording
|
95
|
+
# every time a method gets called in an isolated object
|
96
|
+
# this gets stored in the method call recorder
|
97
|
+
# It expects a +method_name+ at the very least.
|
98
|
+
def initialize(method_name, count=0)
|
99
|
+
@method_name = method_name
|
100
|
+
@count = count
|
101
|
+
@variations = []
|
102
|
+
end
|
103
|
+
|
104
|
+
# add args
|
105
|
+
def args
|
106
|
+
@variations
|
107
|
+
end
|
108
|
+
|
109
|
+
# indicates if it has an argument variation
|
110
|
+
def has_argument_variations?
|
111
|
+
@variations.size > 1
|
112
|
+
end
|
113
|
+
|
114
|
+
# add an argument variation
|
115
|
+
def add_argument_variation(args, block)
|
116
|
+
variation = find_argument_variations args, nil
|
117
|
+
if variation.empty?
|
118
|
+
@variations << ArgumentRecording.new(args, @variations.size+1, block) if variation == []
|
119
|
+
else
|
120
|
+
variation.first.call_number += 1
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# finds an argument variation that matches the provided +args+
|
125
|
+
def find_argument_variations(args, block_args)
|
126
|
+
return @variations if args.first.is_a?(Symbol) and args.last == :any
|
127
|
+
return match_hash(args, block_args) if args.size == 1 and args.last.is_a?(Hash)
|
128
|
+
return @variations.select { |ar| ar.args == args } if block_args.nil?
|
129
|
+
return @variations.select { |ar| ar.args == args and ar.block } if block_args.last == :any
|
130
|
+
return @variations.select do |ar|
|
131
|
+
av = ar.args == args
|
132
|
+
# idx = 0
|
133
|
+
# ags = ar.args
|
134
|
+
# av = args.all? do |ag|
|
135
|
+
# rag = ags[idx]
|
136
|
+
# res = if ag.is_a?(Hash) and rag.is_a?(Hash)
|
137
|
+
# ag.all? { |k, v| ar.args[idx][k] == v }
|
138
|
+
# else
|
139
|
+
# ag == rag
|
140
|
+
# end
|
141
|
+
# idx += 1
|
142
|
+
# res
|
143
|
+
# end
|
144
|
+
av and not ar.find_block_variation(*block_args).empty?
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def match_hash(args, block_args)
|
149
|
+
@variations.select do |ar|
|
150
|
+
ags = ar.args.last
|
151
|
+
args.last.all? { |k, v| ags[k] == v }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# The recorder that will collect method calls and provides an interface for finding those recordings
|
157
|
+
class MethodCallRecorder
|
158
|
+
|
159
|
+
# gets the collection of method calls. This is a hash with the method name as key
|
160
|
+
attr_reader :method_calls
|
161
|
+
|
162
|
+
|
163
|
+
# Initializes a new instance of a method call recorder
|
164
|
+
# every time a method gets called in an isolated object
|
165
|
+
# this gets stored in the method call recorder
|
166
|
+
def initialize
|
167
|
+
@method_calls = {:instance => {}, :class => {} }
|
168
|
+
end
|
169
|
+
|
170
|
+
# records a method call or increments the count of how many times this method was called.
|
171
|
+
def record_call(method_name, mode=:instance, expectation=nil, *args, &block)
|
172
|
+
mn_sym = method_name.to_s.underscore.to_sym
|
173
|
+
method_calls[mode][mn_sym] ||= MethodCallRecording.new mn_sym.to_s
|
174
|
+
mc = method_calls[mode][mn_sym]
|
175
|
+
mc.count += 1
|
176
|
+
agc = mc.add_argument_variation args, block
|
177
|
+
b = (expectation && expectation.block) ? (expectation.block||block) : block
|
178
|
+
expectation.block = lambda do |*ags|
|
179
|
+
res = nil
|
180
|
+
res = b.call *ags if b
|
181
|
+
agc.first.add_block_variation *ags
|
182
|
+
res
|
183
|
+
end if expectation
|
184
|
+
block.nil? ? nil : (lambda { |*ags|
|
185
|
+
res = nil
|
186
|
+
res = block.call *ags if block
|
187
|
+
agc.first.add_block_variation *ags
|
188
|
+
res
|
189
|
+
})
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
def error
|
194
|
+
@error
|
195
|
+
end
|
196
|
+
|
197
|
+
# returns whether the method was actually called with the specified constraints
|
198
|
+
def was_called?(method_name, block_args, mode=:instance, *args)
|
199
|
+
mc = method_calls[mode][method_name.to_s.underscore.to_sym]
|
200
|
+
if mc
|
201
|
+
vari = mc.find_argument_variations(args, block_args)
|
202
|
+
result = vari.any? { |agv| agv == args }
|
203
|
+
return result if result
|
204
|
+
if args.size == 1 and args.last.is_a?(Hash)
|
205
|
+
result = vari.any? do |agv|
|
206
|
+
agv.args.last.is_a?(Hash) and args.last.all? { |k, v| agv.args.last[k] == v }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
@error = "Arguments don't match.\nYou expected:\n#{args.join(", ")}.\nI did find the following variations:\n#{mc.args.collect {|ar| ar.args.join(', ') }.join("\nand\n")}" unless result
|
210
|
+
result
|
211
|
+
else
|
212
|
+
@error = "Couldn't find a method with name #{method_name}"
|
213
|
+
return !!mc
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# # indexer that gives you access to the recorded method by method name
|
218
|
+
# def [](method_name)
|
219
|
+
# method_calls[:instance][method_name.to_s.to_sym]
|
220
|
+
# end
|
221
|
+
|
222
|
+
# returns the number of different methods that has been recorderd
|
223
|
+
def size
|
224
|
+
@method_calls.size
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
229
|
end
|