caricature 0.7.5 → 0.7.6
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/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
|