caricature 0.7.5 → 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +97 -97
- data/Rakefile +309 -310
- data/caricature.gemspec +123 -110
- data/lib/caricature/bacon/integration.rb +75 -75
- data/lib/caricature/bacon.rb +2 -2
- data/lib/caricature/clr/descriptor.rb +159 -159
- data/lib/caricature/clr/event_verification.rb +56 -56
- data/lib/caricature/clr/expectation.rb +100 -100
- data/lib/caricature/clr/isolation.rb +78 -78
- data/lib/caricature/clr/isolator.rb +252 -252
- data/lib/caricature/clr/messenger.rb +51 -49
- data/lib/caricature/clr/method_call_recorder.rb +96 -96
- data/lib/caricature/expectation.rb +1 -1
- data/lib/caricature/method_call_recorder.rb +3 -3
- data/lib/caricature/rspec/integration.rb +118 -118
- data/lib/caricature/version.rb +5 -5
- data/lib/caricature.rb +25 -25
- data/spec/bacon/integration/callback_spec.rb +156 -156
- data/spec/bacon/integration/clr_to_clr_spec.rb +325 -253
- data/spec/bacon/integration/event_spec.rb +97 -97
- data/spec/bacon/integration/indexer_spec.rb +27 -27
- data/spec/bacon/spec_helper.rb +4 -4
- data/spec/bacon/unit/descriptor_spec.rb +212 -212
- data/spec/bacon/unit/sword_spec.rb +39 -39
- data/spec/bacon/unit/verification_spec.rb +103 -103
- data/spec/bin/ClrModels.dll +0 -0
- data/spec/bin/ClrModels.dll.mdb +0 -0
- data/spec/fixtures/ExplodingCar.cs +56 -0
- data/spec/fixtures/ExposedChangedSubscriber.cs +26 -0
- data/spec/fixtures/ExposingWarrior.cs +58 -0
- data/spec/fixtures/IExplodingWarrior.cs +10 -0
- data/spec/fixtures/IExposing.cs +9 -0
- data/spec/fixtures/IExposingBridge.cs +9 -0
- data/spec/fixtures/IExposingWarrior.cs +8 -0
- data/spec/fixtures/IHaveAnIndexer.cs +8 -0
- data/spec/fixtures/IWarrior.cs +13 -0
- data/spec/fixtures/IWeapon.cs +9 -0
- data/spec/fixtures/IndexerCaller.cs +17 -0
- data/spec/fixtures/IndexerContained.cs +20 -0
- data/spec/fixtures/MyClassWithAStatic.cs +16 -0
- data/spec/fixtures/Ninja.cs +34 -0
- data/spec/fixtures/Samurai.cs +29 -0
- data/spec/fixtures/StaticCaller.cs +12 -0
- data/spec/fixtures/Sword.cs +16 -0
- data/spec/fixtures/SwordWithStatics.cs +19 -0
- data/spec/fixtures/clr_interaction.rb +61 -0
- data/spec/fixtures/dagger.rb +11 -0
- data/spec/fixtures/dagger_with_class_members.rb +11 -0
- data/spec/fixtures/sheath.rb +19 -0
- data/spec/fixtures/soldier.rb +29 -0
- data/spec/fixtures/soldier_with_class_members.rb +7 -0
- data/spec/fixtures/swift_cleanup_crew.rb +21 -0
- data/spec/fixtures/with_class_methods.rb +11 -0
- data/spec/{models → models.notused}/ClrModels.cs +241 -241
- data/spec/{models → models.notused}/ruby_models.rb +150 -150
- data/spec/rspec/integration/callback_spec.rb +156 -156
- data/spec/rspec/integration/clr_to_clr_spec.rb +254 -254
- data/spec/rspec/integration/clr_to_ruby_spec.rb +227 -227
- data/spec/rspec/integration/indexer_spec.rb +27 -27
- data/spec/rspec/integration/ruby_to_ruby_spec.rb +271 -271
- data/spec/rspec/spec_helper.rb +12 -12
- data/spec/rspec/unit/core_ext_spec.rb +87 -87
- data/spec/rspec/unit/descriptor_spec.rb +210 -210
- data/spec/rspec/unit/event_spec.rb +16 -16
- data/spec/rspec/unit/expectation_spec.rb +300 -300
- data/spec/rspec/unit/interop_spec.rb +29 -29
- data/spec/rspec/unit/isolation_spec.rb +86 -86
- data/spec/rspec/unit/isolator_spec.rb +219 -219
- data/spec/rspec/unit/messaging_spec.rb +310 -310
- data/spec/rspec/unit/method_call_spec.rb +342 -342
- data/spec/rspec/unit/sword_spec.rb +39 -39
- data/spec/rspec/unit/verification_spec.rb +103 -103
- data/spec/spec_helper.rb +16 -15
- metadata +42 -11
@@ -1,79 +1,79 @@
|
|
1
|
-
module Caricature
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
class Isolation # :nodoc:
|
6
|
-
|
7
|
-
# the event subscriptions collected at runtime
|
8
|
-
attr_reader :events
|
9
|
-
|
10
|
-
# the event subscriptions collected at runtime
|
11
|
-
def events
|
12
|
-
@events ||= {}
|
13
|
-
end
|
14
|
-
|
15
|
-
# adds an event subscription
|
16
|
-
def add_event_subscription(event_name, mode, handler)
|
17
|
-
events[mode] ||= {}
|
18
|
-
nm = event_name_for(event_name)
|
19
|
-
events[mode][nm] ||= []
|
20
|
-
events[mode][nm] << handler
|
21
|
-
end
|
22
|
-
|
23
|
-
# removes an event subscription
|
24
|
-
def remove_event_subscription(event_name, mode, handler)
|
25
|
-
((events[mode] ||= {})[event_name_for(event_name)] ||=[]).delete(handler)
|
26
|
-
end
|
27
|
-
|
28
|
-
# def add_event_expectation(name, mode, *args, &handler)
|
29
|
-
# end
|
30
|
-
|
31
|
-
def internal_create_override(method_name, mode=:instance, &block)
|
32
|
-
builder = ExpectationBuilder.new method_name
|
33
|
-
block.call builder unless block.nil?
|
34
|
-
exp = builder.build
|
35
|
-
exp.events = events[mode]
|
36
|
-
expectations.add_expectation exp, mode
|
37
|
-
exp
|
38
|
-
end
|
39
|
-
|
40
|
-
def verify_event_raise(event_name, mode= :instance, &block)
|
41
|
-
verification = EventVerification.new(event_name, recorder, mode)
|
42
|
-
block.call verification unless block.nil?
|
43
|
-
verification
|
44
|
-
end
|
45
|
-
|
46
|
-
class << self
|
47
|
-
|
48
|
-
# Creates an isolation object complete with proxy and method call recorder
|
49
|
-
# It works out which isolation it needs to create and provide and initializes the
|
50
|
-
# method call recorder
|
51
|
-
def for(subject, recorder = MethodCallRecorder.new, expectations = Expectations.new)
|
52
|
-
context = IsolatorContext.new subject, recorder, expectations
|
53
|
-
isolation_strategy = subject.clr_type? ? get_clr_isolation_strategy(subject) : RubyIsolator
|
54
|
-
|
55
|
-
isolator = isolation_strategy.for context
|
56
|
-
new(isolator, context)
|
57
|
-
isolator.isolation
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
# decides which startegy to use for mocking a CLR object.
|
63
|
-
# When the provided subject is an interface it will return a +ClrInterfaceIsolator+
|
64
|
-
# otherwise it will return a +ClrIsolator+
|
65
|
-
def get_clr_isolation_strategy(subject)
|
66
|
-
return ClrInterfaceIsolator if subject.respond_to? :class_eval and !subject.respond_to? :new
|
67
|
-
ClrIsolator
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
def event_name_for(method_name) #:nodoc:
|
74
|
-
method_name.gsub(/^(add|remove)_/, '').underscore.to_sym
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
|
1
|
+
module Caricature
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
class Isolation # :nodoc:
|
6
|
+
|
7
|
+
# the event subscriptions collected at runtime
|
8
|
+
attr_reader :events
|
9
|
+
|
10
|
+
# the event subscriptions collected at runtime
|
11
|
+
def events
|
12
|
+
@events ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# adds an event subscription
|
16
|
+
def add_event_subscription(event_name, mode, handler)
|
17
|
+
events[mode] ||= {}
|
18
|
+
nm = event_name_for(event_name)
|
19
|
+
events[mode][nm] ||= []
|
20
|
+
events[mode][nm] << handler
|
21
|
+
end
|
22
|
+
|
23
|
+
# removes an event subscription
|
24
|
+
def remove_event_subscription(event_name, mode, handler)
|
25
|
+
((events[mode] ||= {})[event_name_for(event_name)] ||=[]).delete(handler)
|
26
|
+
end
|
27
|
+
|
28
|
+
# def add_event_expectation(name, mode, *args, &handler)
|
29
|
+
# end
|
30
|
+
|
31
|
+
def internal_create_override(method_name, mode=:instance, &block)
|
32
|
+
builder = ExpectationBuilder.new method_name
|
33
|
+
block.call builder unless block.nil?
|
34
|
+
exp = builder.build
|
35
|
+
exp.events = events[mode]
|
36
|
+
expectations.add_expectation exp, mode
|
37
|
+
exp
|
38
|
+
end
|
39
|
+
|
40
|
+
def verify_event_raise(event_name, mode= :instance, &block)
|
41
|
+
verification = EventVerification.new(event_name, recorder, mode)
|
42
|
+
block.call verification unless block.nil?
|
43
|
+
verification
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
|
48
|
+
# Creates an isolation object complete with proxy and method call recorder
|
49
|
+
# It works out which isolation it needs to create and provide and initializes the
|
50
|
+
# method call recorder
|
51
|
+
def for(subject, recorder = MethodCallRecorder.new, expectations = Expectations.new)
|
52
|
+
context = IsolatorContext.new subject, recorder, expectations
|
53
|
+
isolation_strategy = subject.clr_type? ? get_clr_isolation_strategy(subject) : RubyIsolator
|
54
|
+
|
55
|
+
isolator = isolation_strategy.for context
|
56
|
+
new(isolator, context)
|
57
|
+
isolator.isolation
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# decides which startegy to use for mocking a CLR object.
|
63
|
+
# When the provided subject is an interface it will return a +ClrInterfaceIsolator+
|
64
|
+
# otherwise it will return a +ClrIsolator+
|
65
|
+
def get_clr_isolation_strategy(subject)
|
66
|
+
return ClrInterfaceIsolator if subject.respond_to? :class_eval and !subject.respond_to? :new
|
67
|
+
ClrIsolator
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def event_name_for(method_name) #:nodoc:
|
74
|
+
method_name.gsub(/^(add|remove)_/, '').underscore.to_sym
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
79
|
end
|
@@ -1,253 +1,253 @@
|
|
1
|
-
module Caricature
|
2
|
-
|
3
|
-
# Groups the methods for interception together
|
4
|
-
# this is a mix-in for the created isolations for classes
|
5
|
-
module Interception
|
6
|
-
|
7
|
-
# the class methods of this intercepting object
|
8
|
-
module ClassMethods
|
9
|
-
|
10
|
-
# Raises an event on the isolation
|
11
|
-
# You can specify the arguments in the block or as parameters
|
12
|
-
#
|
13
|
-
# Example
|
14
|
-
#
|
15
|
-
# an_isolation.class.raise_event :on_property_changed do |raiser|
|
16
|
-
# raiser.with an_isolation, System::EventArgs.empty
|
17
|
-
# end
|
18
|
-
#
|
19
|
-
# is equivalent to:
|
20
|
-
#
|
21
|
-
# an_isolation.class.raise_event :on_property_changed, an_isolation, System::EventArgs.empty
|
22
|
-
#
|
23
|
-
# or
|
24
|
-
#
|
25
|
-
# an_isolation.class.raise_event(:on_property_changed).with(an_isolation, System::EventArgs.empty)
|
26
|
-
#
|
27
|
-
# You will most likely use this method when you want to verify logic in an event handler
|
28
|
-
# You will most likely use this method when you want to verify logic in an event handler
|
29
|
-
def raise_event(event_name, *args, &block)
|
30
|
-
isolation_context.add_event_expectation event_name, :class, *args, &block
|
31
|
-
end
|
32
|
-
|
33
|
-
# Verifies whether the specified event was raised
|
34
|
-
#
|
35
|
-
# You will probably be using this method only when you're interested in whether an event has been raised
|
36
|
-
# during the course of the test you're running.
|
37
|
-
def did_raise_event?(event_name, &b)
|
38
|
-
isolation_context.verify_event_raise event_name, :class, &b
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
# Raises an event on the isolation
|
44
|
-
# You can specify the arguments in the block or as parameters
|
45
|
-
#
|
46
|
-
# Example
|
47
|
-
#
|
48
|
-
# an_isolation.raise_event :on_property_changed do |raiser|
|
49
|
-
# raiser.with an_isolation, System::EventArgs.empty
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# is equivalent to:
|
53
|
-
#
|
54
|
-
# an_isolation.raise_event :on_property_changed, an_isolation, System::EventArgs.empty
|
55
|
-
#
|
56
|
-
# or
|
57
|
-
#
|
58
|
-
# an_isolation.raise_event(:on_property_changed).with(an_isolation, System::EventArgs.empty)
|
59
|
-
#
|
60
|
-
# You will most likely use this method when you want to verify logic in an event handler
|
61
|
-
def raise_event(event_name, *args, &block)
|
62
|
-
isolation_context.add_event_expectation event_name, :instance, *args, &block
|
63
|
-
end
|
64
|
-
|
65
|
-
# Raises an event on the isolation
|
66
|
-
# You can specify the arguments in the block or as parameters
|
67
|
-
#
|
68
|
-
# Example
|
69
|
-
#
|
70
|
-
# an_isolation.raise_class_event :on_property_changed do |raiser|
|
71
|
-
# raiser.with an_isolation, System::EventArgs.empty
|
72
|
-
# end
|
73
|
-
#
|
74
|
-
# is equivalent to:
|
75
|
-
#
|
76
|
-
# an_isolation.raise_class_event :on_property_changed, an_isolation, System::EventArgs.empty
|
77
|
-
#
|
78
|
-
# or
|
79
|
-
#
|
80
|
-
# an_isolation.raise_class_event(:on_property_changed).with(an_isolation, System::EventArgs.empty)
|
81
|
-
#
|
82
|
-
# You will most likely use this method when you want to verify logic in an event handler
|
83
|
-
def raise_class_event(event_name, *args, &block)
|
84
|
-
self.class.raise_event event_name, *args, &block
|
85
|
-
end
|
86
|
-
|
87
|
-
# Verifies whether the specified event was raised
|
88
|
-
#
|
89
|
-
# You will probably be using this method only when you're interested in whether an event has been raised
|
90
|
-
# during the course of the test you're running.
|
91
|
-
def did_raise_event?(event_name, &b)
|
92
|
-
isolation_context.verify_event_raise event_name, :instance, &b
|
93
|
-
end
|
94
|
-
|
95
|
-
# Verifies whether the specified event was raised
|
96
|
-
#
|
97
|
-
# You will probably be using this method only when you're interested in whether an event has been raised
|
98
|
-
# during the course of the test you're running.
|
99
|
-
def did_raise_class_event?(event_name, &b)
|
100
|
-
self.class.did_raise_event? event_name, &b
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
# A proxy to CLR objects that records method calls.
|
106
|
-
# this implements all the public instance methods of the class when you use it in ruby code
|
107
|
-
# When you use it in a CLR class you're bound to CLR rules and it only overrides the methods
|
108
|
-
# that are marked as virtual. We also can't isolate static or sealed types at the moment.
|
109
|
-
class ClrIsolator < Isolator
|
110
|
-
|
111
|
-
|
112
|
-
# Implementation of the template method that creates
|
113
|
-
# an isolator for a class defined in a CLR language.
|
114
|
-
def initialize(context)
|
115
|
-
super
|
116
|
-
instance = nil
|
117
|
-
sklass = context.subject
|
118
|
-
unless context.subject.respond_to?(:class_eval)
|
119
|
-
sklass = context.subject.class
|
120
|
-
instance = context.subject
|
121
|
-
end
|
122
|
-
@descriptor = ClrClassDescriptor.new sklass
|
123
|
-
instance ||= sklass.new unless sklass.to_clr_type.is_abstract
|
124
|
-
build_isolation sklass, instance
|
125
|
-
end
|
126
|
-
|
127
|
-
# initializes the messaging strategy for the isolator
|
128
|
-
def initialize_messenger
|
129
|
-
@context.messenger = ClrClassMessenger.new @context.expectations, @subject
|
130
|
-
end
|
131
|
-
|
132
|
-
# builds the Isolator class for the specified subject
|
133
|
-
def create_isolation_for(subj)
|
134
|
-
members = @descriptor.instance_members
|
135
|
-
class_members = @descriptor.class_members
|
136
|
-
events = @descriptor.events
|
137
|
-
class_events = @descriptor.class_events
|
138
|
-
|
139
|
-
klass = Object.const_set(class_name(subj), Class.new(subj))
|
140
|
-
klass.class_eval do
|
141
|
-
|
142
|
-
include Interception
|
143
|
-
|
144
|
-
# access to the proxied subject
|
145
|
-
def ___super___
|
146
|
-
isolation_context.instance
|
147
|
-
end
|
148
|
-
|
149
|
-
def initialize(*args)
|
150
|
-
self
|
151
|
-
end
|
152
|
-
|
153
|
-
members.each do |mem|
|
154
|
-
nm = mem.name.to_s.to_sym
|
155
|
-
define_method nm do |*args|
|
156
|
-
b = nil
|
157
|
-
b = Proc.new { yield } if block_given?
|
158
|
-
isolation_context.send_message(nm, mem.return_type, *args, &b)
|
159
|
-
end unless nm == :to_string
|
160
|
-
end
|
161
|
-
|
162
|
-
class_members.each do |mn|
|
163
|
-
mn = mn.name.to_s.to_sym
|
164
|
-
define_cmethod mn do |*args|
|
165
|
-
b = nil
|
166
|
-
b = Proc.new { yield } if block_given?
|
167
|
-
isolation_context.send_class_message(mn, nil, *args, &b)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
evts = (events + class_events).collect do |evt|
|
172
|
-
%w(add remove).inject("") do |res, nm|
|
173
|
-
res << <<-end_event_definition
|
174
|
-
|
175
|
-
def #{"self." unless evt.instance_member?}#{nm}_#{evt.event_name}(block)
|
176
|
-
self.isolation_context.#{nm}_event_subscription('#{evt.event_name}', :#{evt.instance_member? ? "instance" : "class"}, block)
|
177
|
-
end
|
178
|
-
|
179
|
-
end_event_definition
|
180
|
-
end
|
181
|
-
|
182
|
-
end.join("\n")
|
183
|
-
|
184
|
-
klass.class_eval evts
|
185
|
-
|
186
|
-
#puts evts
|
187
|
-
|
188
|
-
end
|
189
|
-
|
190
|
-
klass
|
191
|
-
end
|
192
|
-
|
193
|
-
end
|
194
|
-
|
195
|
-
# An +Isolator+ for CLR interfaces.
|
196
|
-
# this implements all the methods that are defined on the interface.
|
197
|
-
class ClrInterfaceIsolator < Isolator
|
198
|
-
|
199
|
-
# Implementation of the template method that creates
|
200
|
-
# an isolator for an interface defined in a CLR language.
|
201
|
-
def initialize(context)
|
202
|
-
super
|
203
|
-
sklass = context.subject
|
204
|
-
@descriptor = ClrInterfaceDescriptor.new sklass
|
205
|
-
build_isolation sklass
|
206
|
-
end
|
207
|
-
|
208
|
-
# initializes the messaging strategy for the isolator
|
209
|
-
def initialize_messenger
|
210
|
-
@context.messenger = ClrInterfaceMessenger.new @context.expectations
|
211
|
-
end
|
212
|
-
|
213
|
-
# builds the actual +isolator+ for the CLR interface
|
214
|
-
def create_isolation_for(subj)
|
215
|
-
proxy_members = @descriptor.instance_members
|
216
|
-
events = @descriptor.events
|
217
|
-
|
218
|
-
klass = Object.const_set(class_name(subj), Class.new)
|
219
|
-
klass.class_eval do
|
220
|
-
|
221
|
-
include subj
|
222
|
-
include Interception
|
223
|
-
|
224
|
-
proxy_members.each do |mem|
|
225
|
-
nm = mem.name.to_s.to_sym
|
226
|
-
define_method nm do |*args|
|
227
|
-
b = nil
|
228
|
-
b = Proc.new { yield } if block_given?
|
229
|
-
isolation_context.send_message(nm, mem.return_type, *args, &b)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
|
234
|
-
end
|
235
|
-
|
236
|
-
evts = events.collect do |evt|
|
237
|
-
%w(add remove).inject("") do |res, nm|
|
238
|
-
res << <<-end_event_definition
|
239
|
-
|
240
|
-
def #{"self." unless evt.instance_member?}#{nm}_#{evt.event_name}(block)
|
241
|
-
isolation_context.#{nm}_event_subscription('#{evt.event_name}', :#{evt.instance_member? ? "instance" : "class"}, block)
|
242
|
-
end
|
243
|
-
|
244
|
-
end_event_definition
|
245
|
-
end
|
246
|
-
end.join("\n")
|
247
|
-
klass.class_eval evts
|
248
|
-
|
249
|
-
klass
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
1
|
+
module Caricature
|
2
|
+
|
3
|
+
# Groups the methods for interception together
|
4
|
+
# this is a mix-in for the created isolations for classes
|
5
|
+
module Interception
|
6
|
+
|
7
|
+
# the class methods of this intercepting object
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# Raises an event on the isolation
|
11
|
+
# You can specify the arguments in the block or as parameters
|
12
|
+
#
|
13
|
+
# Example
|
14
|
+
#
|
15
|
+
# an_isolation.class.raise_event :on_property_changed do |raiser|
|
16
|
+
# raiser.with an_isolation, System::EventArgs.empty
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# is equivalent to:
|
20
|
+
#
|
21
|
+
# an_isolation.class.raise_event :on_property_changed, an_isolation, System::EventArgs.empty
|
22
|
+
#
|
23
|
+
# or
|
24
|
+
#
|
25
|
+
# an_isolation.class.raise_event(:on_property_changed).with(an_isolation, System::EventArgs.empty)
|
26
|
+
#
|
27
|
+
# You will most likely use this method when you want to verify logic in an event handler
|
28
|
+
# You will most likely use this method when you want to verify logic in an event handler
|
29
|
+
def raise_event(event_name, *args, &block)
|
30
|
+
isolation_context.add_event_expectation event_name, :class, *args, &block
|
31
|
+
end
|
32
|
+
|
33
|
+
# Verifies whether the specified event was raised
|
34
|
+
#
|
35
|
+
# You will probably be using this method only when you're interested in whether an event has been raised
|
36
|
+
# during the course of the test you're running.
|
37
|
+
def did_raise_event?(event_name, &b)
|
38
|
+
isolation_context.verify_event_raise event_name, :class, &b
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# Raises an event on the isolation
|
44
|
+
# You can specify the arguments in the block or as parameters
|
45
|
+
#
|
46
|
+
# Example
|
47
|
+
#
|
48
|
+
# an_isolation.raise_event :on_property_changed do |raiser|
|
49
|
+
# raiser.with an_isolation, System::EventArgs.empty
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# is equivalent to:
|
53
|
+
#
|
54
|
+
# an_isolation.raise_event :on_property_changed, an_isolation, System::EventArgs.empty
|
55
|
+
#
|
56
|
+
# or
|
57
|
+
#
|
58
|
+
# an_isolation.raise_event(:on_property_changed).with(an_isolation, System::EventArgs.empty)
|
59
|
+
#
|
60
|
+
# You will most likely use this method when you want to verify logic in an event handler
|
61
|
+
def raise_event(event_name, *args, &block)
|
62
|
+
isolation_context.add_event_expectation event_name, :instance, *args, &block
|
63
|
+
end
|
64
|
+
|
65
|
+
# Raises an event on the isolation
|
66
|
+
# You can specify the arguments in the block or as parameters
|
67
|
+
#
|
68
|
+
# Example
|
69
|
+
#
|
70
|
+
# an_isolation.raise_class_event :on_property_changed do |raiser|
|
71
|
+
# raiser.with an_isolation, System::EventArgs.empty
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# is equivalent to:
|
75
|
+
#
|
76
|
+
# an_isolation.raise_class_event :on_property_changed, an_isolation, System::EventArgs.empty
|
77
|
+
#
|
78
|
+
# or
|
79
|
+
#
|
80
|
+
# an_isolation.raise_class_event(:on_property_changed).with(an_isolation, System::EventArgs.empty)
|
81
|
+
#
|
82
|
+
# You will most likely use this method when you want to verify logic in an event handler
|
83
|
+
def raise_class_event(event_name, *args, &block)
|
84
|
+
self.class.raise_event event_name, *args, &block
|
85
|
+
end
|
86
|
+
|
87
|
+
# Verifies whether the specified event was raised
|
88
|
+
#
|
89
|
+
# You will probably be using this method only when you're interested in whether an event has been raised
|
90
|
+
# during the course of the test you're running.
|
91
|
+
def did_raise_event?(event_name, &b)
|
92
|
+
isolation_context.verify_event_raise event_name, :instance, &b
|
93
|
+
end
|
94
|
+
|
95
|
+
# Verifies whether the specified event was raised
|
96
|
+
#
|
97
|
+
# You will probably be using this method only when you're interested in whether an event has been raised
|
98
|
+
# during the course of the test you're running.
|
99
|
+
def did_raise_class_event?(event_name, &b)
|
100
|
+
self.class.did_raise_event? event_name, &b
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
# A proxy to CLR objects that records method calls.
|
106
|
+
# this implements all the public instance methods of the class when you use it in ruby code
|
107
|
+
# When you use it in a CLR class you're bound to CLR rules and it only overrides the methods
|
108
|
+
# that are marked as virtual. We also can't isolate static or sealed types at the moment.
|
109
|
+
class ClrIsolator < Isolator
|
110
|
+
|
111
|
+
|
112
|
+
# Implementation of the template method that creates
|
113
|
+
# an isolator for a class defined in a CLR language.
|
114
|
+
def initialize(context)
|
115
|
+
super
|
116
|
+
instance = nil
|
117
|
+
sklass = context.subject
|
118
|
+
unless context.subject.respond_to?(:class_eval)
|
119
|
+
sklass = context.subject.class
|
120
|
+
instance = context.subject
|
121
|
+
end
|
122
|
+
@descriptor = ClrClassDescriptor.new sklass
|
123
|
+
instance ||= sklass.new unless sklass.to_clr_type.is_abstract
|
124
|
+
build_isolation sklass, instance
|
125
|
+
end
|
126
|
+
|
127
|
+
# initializes the messaging strategy for the isolator
|
128
|
+
def initialize_messenger
|
129
|
+
@context.messenger = ClrClassMessenger.new @context.expectations, @subject
|
130
|
+
end
|
131
|
+
|
132
|
+
# builds the Isolator class for the specified subject
|
133
|
+
def create_isolation_for(subj)
|
134
|
+
members = @descriptor.instance_members
|
135
|
+
class_members = @descriptor.class_members
|
136
|
+
events = @descriptor.events
|
137
|
+
class_events = @descriptor.class_events
|
138
|
+
|
139
|
+
klass = Object.const_set(class_name(subj), Class.new(subj))
|
140
|
+
klass.class_eval do
|
141
|
+
|
142
|
+
include Interception
|
143
|
+
|
144
|
+
# access to the proxied subject
|
145
|
+
def ___super___
|
146
|
+
isolation_context.instance
|
147
|
+
end
|
148
|
+
|
149
|
+
def initialize(*args)
|
150
|
+
self
|
151
|
+
end
|
152
|
+
|
153
|
+
members.each do |mem|
|
154
|
+
nm = mem.name.to_s.to_sym
|
155
|
+
define_method nm do |*args|
|
156
|
+
b = nil
|
157
|
+
b = Proc.new { yield } if block_given?
|
158
|
+
isolation_context.send_message(nm, mem.return_type, *args, &b)
|
159
|
+
end unless nm == :to_string
|
160
|
+
end
|
161
|
+
|
162
|
+
class_members.each do |mn|
|
163
|
+
mn = mn.name.to_s.to_sym
|
164
|
+
define_cmethod mn do |*args|
|
165
|
+
b = nil
|
166
|
+
b = Proc.new { yield } if block_given?
|
167
|
+
isolation_context.send_class_message(mn, nil, *args, &b)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
evts = (events + class_events).collect do |evt|
|
172
|
+
%w(add remove).inject("") do |res, nm|
|
173
|
+
res << <<-end_event_definition
|
174
|
+
|
175
|
+
def #{"self." unless evt.instance_member?}#{nm}_#{evt.event_name}(block)
|
176
|
+
self.isolation_context.#{nm}_event_subscription('#{evt.event_name}', :#{evt.instance_member? ? "instance" : "class"}, block)
|
177
|
+
end
|
178
|
+
|
179
|
+
end_event_definition
|
180
|
+
end
|
181
|
+
|
182
|
+
end.join("\n")
|
183
|
+
|
184
|
+
klass.class_eval evts
|
185
|
+
|
186
|
+
#puts evts
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
klass
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
# An +Isolator+ for CLR interfaces.
|
196
|
+
# this implements all the methods that are defined on the interface.
|
197
|
+
class ClrInterfaceIsolator < Isolator
|
198
|
+
|
199
|
+
# Implementation of the template method that creates
|
200
|
+
# an isolator for an interface defined in a CLR language.
|
201
|
+
def initialize(context)
|
202
|
+
super
|
203
|
+
sklass = context.subject
|
204
|
+
@descriptor = ClrInterfaceDescriptor.new sklass
|
205
|
+
build_isolation sklass
|
206
|
+
end
|
207
|
+
|
208
|
+
# initializes the messaging strategy for the isolator
|
209
|
+
def initialize_messenger
|
210
|
+
@context.messenger = ClrInterfaceMessenger.new @context.expectations
|
211
|
+
end
|
212
|
+
|
213
|
+
# builds the actual +isolator+ for the CLR interface
|
214
|
+
def create_isolation_for(subj)
|
215
|
+
proxy_members = @descriptor.instance_members
|
216
|
+
events = @descriptor.events
|
217
|
+
|
218
|
+
klass = Object.const_set(class_name(subj), Class.new)
|
219
|
+
klass.class_eval do
|
220
|
+
|
221
|
+
include subj
|
222
|
+
include Interception
|
223
|
+
|
224
|
+
proxy_members.each do |mem|
|
225
|
+
nm = mem.name.to_s.to_sym
|
226
|
+
define_method nm do |*args|
|
227
|
+
b = nil
|
228
|
+
b = Proc.new { yield } if block_given?
|
229
|
+
isolation_context.send_message(nm, mem.return_type, *args, &b)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
evts = events.collect do |evt|
|
237
|
+
%w(add remove).inject("") do |res, nm|
|
238
|
+
res << <<-end_event_definition
|
239
|
+
|
240
|
+
def #{"self." unless evt.instance_member?}#{nm}_#{evt.event_name}(block)
|
241
|
+
isolation_context.#{nm}_event_subscription('#{evt.event_name}', :#{evt.instance_member? ? "instance" : "class"}, block)
|
242
|
+
end
|
243
|
+
|
244
|
+
end_event_definition
|
245
|
+
end
|
246
|
+
end.join("\n")
|
247
|
+
klass.class_eval evts
|
248
|
+
|
249
|
+
klass
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
253
|
end
|