caricature 0.7.2 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +97 -97
- data/Rakefile +310 -310
- data/caricature.gemspec +110 -106
- data/lib/caricature.rb +3 -1
- data/lib/caricature/bacon.rb +2 -2
- data/lib/caricature/bacon/integration.rb +75 -55
- data/lib/caricature/clr.rb +4 -3
- data/lib/caricature/clr/aspnet_mvc.rb +3 -3
- data/lib/caricature/clr/descriptor.rb +106 -39
- data/lib/caricature/clr/event_verification.rb +57 -0
- data/lib/caricature/clr/expectation.rb +101 -0
- data/lib/caricature/clr/isolation.rb +49 -13
- data/lib/caricature/clr/isolator.rb +141 -5
- data/lib/caricature/clr/messenger.rb +6 -0
- data/lib/caricature/clr/method_call_recorder.rb +97 -0
- data/lib/caricature/core_ext.rb +11 -0
- data/lib/{core_ext → caricature/core_ext}/array.rb +0 -0
- data/lib/{core_ext → caricature/core_ext}/class.rb +0 -0
- data/lib/{core_ext → caricature/core_ext}/hash.rb +0 -0
- data/lib/{core_ext → caricature/core_ext}/module.rb +0 -0
- data/lib/{core_ext → caricature/core_ext}/object.rb +0 -0
- data/lib/{core_ext → caricature/core_ext}/string.rb +0 -0
- data/lib/{core_ext → caricature/core_ext}/system/string.rb +0 -0
- data/lib/{core_ext → caricature/core_ext}/system/type.rb +6 -0
- data/lib/caricature/expectation.rb +108 -66
- data/lib/caricature/isolator.rb +3 -3
- data/lib/caricature/method_call_recorder.rb +32 -4
- data/lib/caricature/rspec/integration.rb +118 -77
- data/lib/caricature/version.rb +5 -5
- data/spec/bacon/integration/callback_spec.rb +156 -156
- data/spec/bacon/integration/clr_to_clr_spec.rb +1 -2
- data/spec/bacon/integration/event_spec.rb +98 -0
- data/spec/bacon/integration/indexer_spec.rb +1 -1
- data/spec/bacon/spec_helper.rb +4 -4
- data/spec/bacon/unit/descriptor_spec.rb +95 -42
- data/spec/bacon/unit/expectation_spec.rb +2 -2
- data/spec/bacon/unit/interop_spec.rb +1 -14
- data/spec/bacon/unit/isolation_spec.rb +1 -1
- data/spec/bacon/unit/isolator_spec.rb +5 -5
- data/spec/bin/ClrModels.dll +0 -0
- data/spec/models/ClrModels.cs +32 -8
- data/spec/models/ruby_models.rb +150 -150
- data/spec/rspec/integration/callback_spec.rb +156 -156
- data/spec/rspec/integration/indexer_spec.rb +1 -1
- data/spec/rspec/spec_helper.rb +12 -6
- data/spec/rspec/unit/descriptor_spec.rb +93 -42
- data/spec/rspec/unit/event_spec.rb +17 -0
- data/spec/rspec/unit/interop_spec.rb +0 -13
- data/spec/spec_helper.rb +14 -14
- metadata +20 -22
- data/lib/core_ext/core_ext.rb +0 -8
- data/spec/bin/ClrModels.dll.mdb +0 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
module Caricature
|
2
|
+
|
3
|
+
# Describes a verification of a method call.
|
4
|
+
# This corresponds kind of to an assertion
|
5
|
+
class EventVerification
|
6
|
+
|
7
|
+
# Initializes a new instance of a +Verification+
|
8
|
+
def initialize(event_name, recorder, mode=:instance)
|
9
|
+
@event_name, @args, @any_args, @recorder, @mode = event_name, [], true, recorder, mode
|
10
|
+
init_plugin
|
11
|
+
end
|
12
|
+
|
13
|
+
def init_plugin
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
# indicates whether this verification can be for any arguments
|
18
|
+
def any_args?
|
19
|
+
@any_args
|
20
|
+
end
|
21
|
+
|
22
|
+
# constrain this verification to the provided arguments
|
23
|
+
def with(*args)
|
24
|
+
@any_args = args.first.is_a?(Symbol) and args.first == :any
|
25
|
+
@args = args
|
26
|
+
# @callback = b if b
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# allow any arguments ignore the argument constraint
|
31
|
+
def allow_any_arguments
|
32
|
+
@any_args = true
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
# figure out if this argument variation matches the provided args.
|
37
|
+
def matches?(event_name, *args)
|
38
|
+
@event_name == event_name and (any_args? or @args == args)
|
39
|
+
end
|
40
|
+
|
41
|
+
def error
|
42
|
+
@recorder.event_error
|
43
|
+
end
|
44
|
+
|
45
|
+
# indicate that this method verification is successful
|
46
|
+
def successful?
|
47
|
+
a = any_args? ? [:any] : @args
|
48
|
+
begin
|
49
|
+
@recorder.event_raised?(@event_name, @mode, *a)
|
50
|
+
rescue ArgumentError
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Caricature
|
2
|
+
|
3
|
+
# Syntax for the expectation builder and expectation
|
4
|
+
# to define an event on the expectation.
|
5
|
+
module EventExpectationSyntax
|
6
|
+
|
7
|
+
# tell the expectation it needs to raise an event when this method is called
|
8
|
+
def raise_event(name, *ags, &b)
|
9
|
+
collected.merge!(:event_name => name, :event_args => ags, :event_handler => b)
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
# raises the events that has been registered on the object at runtime
|
14
|
+
def raise_subscriptions
|
15
|
+
collected[:raise_subscriptions] = true
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# Adds event support to the expectation
|
23
|
+
# this is only applicable to clr isolations and not
|
24
|
+
# to ruby isolations
|
25
|
+
class Expectation
|
26
|
+
|
27
|
+
include EventExpectationSyntax
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
# the block that will be used
|
32
|
+
def event_name
|
33
|
+
collected[:event_name]
|
34
|
+
end
|
35
|
+
|
36
|
+
# the arguments that will be used for the event
|
37
|
+
def event_args
|
38
|
+
evt_ags = collected[:event_args]
|
39
|
+
evt_ags.nil? or evt_ags.empty? ? [nil, System::EventArgs.empty] : evt_ags
|
40
|
+
end
|
41
|
+
|
42
|
+
# the block that will be used# the block that will be used
|
43
|
+
def event_handler
|
44
|
+
collected[:event_handler] || lambda { |s,e| }
|
45
|
+
end
|
46
|
+
|
47
|
+
# the events attached to the context
|
48
|
+
def events
|
49
|
+
collected[:events] ||= {}
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set the registered events for this expectation
|
53
|
+
def events=(evts)
|
54
|
+
collected[:events]=evts
|
55
|
+
end
|
56
|
+
|
57
|
+
# indicates whether this expectation has an event that needs to be raised
|
58
|
+
def raises_event?
|
59
|
+
!!collected[:event_name]
|
60
|
+
end
|
61
|
+
|
62
|
+
# indicates whether this expectation has an event handler to be called
|
63
|
+
def has_event_handler?
|
64
|
+
!!collected[:event_handler]
|
65
|
+
end
|
66
|
+
|
67
|
+
# indicates whether to raise the registered event handlers
|
68
|
+
def raises_registered?
|
69
|
+
!!collected[:raise_subscriptions]
|
70
|
+
end
|
71
|
+
|
72
|
+
def event_recorder(&b)
|
73
|
+
@event_recorder = b
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s #:nodoc:
|
77
|
+
"<Caricature::Expecation, method_name: #{method_name}, args: #{args}, error args: #{error_args}, event: #{event_name}>"
|
78
|
+
end
|
79
|
+
alias :inspect :to_s
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def do_event_raise #:nodoc:
|
84
|
+
return unless @event_recorder
|
85
|
+
@event_recorder.call event_name, event_args, event_handler
|
86
|
+
return unless raises_event?
|
87
|
+
|
88
|
+
ags = event_args
|
89
|
+
event_handler.call *ags if has_event_handler?
|
90
|
+
|
91
|
+
return unless raises_registered? or not has_event_handler?
|
92
|
+
events[event_name].each { |evt| call_handler evt, *ags }
|
93
|
+
end
|
94
|
+
|
95
|
+
def call_handler(evt, *ags)
|
96
|
+
evt.respond_to?(:call) ? evt.call(*ags) : evt.get_invocation_list.each{|ev| ev.invoke(*ags) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
ExpectationBuilder.send :include, EventExpectationSyntax
|
101
|
+
end
|
@@ -1,7 +1,48 @@
|
|
1
1
|
module Caricature
|
2
|
+
|
3
|
+
|
2
4
|
|
3
|
-
class Isolation
|
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
|
4
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
|
+
|
5
46
|
class << self
|
6
47
|
|
7
48
|
# Creates an isolation object complete with proxy and method call recorder
|
@@ -12,7 +53,7 @@ module Caricature
|
|
12
53
|
isolation_strategy = subject.clr_type? ? get_clr_isolation_strategy(subject) : RubyIsolator
|
13
54
|
|
14
55
|
isolator = isolation_strategy.for context
|
15
|
-
|
56
|
+
new(isolator, context)
|
16
57
|
isolator.isolation
|
17
58
|
end
|
18
59
|
|
@@ -26,17 +67,12 @@ module Caricature
|
|
26
67
|
ClrIsolator
|
27
68
|
end
|
28
69
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
exp = builder.build
|
36
|
-
|
37
|
-
expectations.add_expectation exp, mode
|
38
|
-
exp
|
39
|
-
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def event_name_for(method_name) #:nodoc:
|
74
|
+
method_name.gsub(/^(add|remove)_/, '').underscore.to_sym
|
75
|
+
end
|
40
76
|
|
41
77
|
end
|
42
78
|
|
@@ -1,5 +1,107 @@
|
|
1
1
|
module Caricature
|
2
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
|
+
|
3
105
|
# A proxy to CLR objects that records method calls.
|
4
106
|
# this implements all the public instance methods of the class when you use it in ruby code
|
5
107
|
# When you use it in a CLR class you're bound to CLR rules and it only overrides the methods
|
@@ -28,9 +130,11 @@ module Caricature
|
|
28
130
|
end
|
29
131
|
|
30
132
|
# builds the Isolator class for the specified subject
|
31
|
-
def
|
133
|
+
def create_isolation_for(subj)
|
32
134
|
members = @descriptor.instance_members
|
33
135
|
class_members = @descriptor.class_members
|
136
|
+
events = @descriptor.events
|
137
|
+
class_events = @descriptor.class_events
|
34
138
|
|
35
139
|
klass = Object.const_set(class_name(subj), Class.new(subj))
|
36
140
|
klass.class_eval do
|
@@ -40,10 +144,10 @@ module Caricature
|
|
40
144
|
# access to the proxied subject
|
41
145
|
def ___super___
|
42
146
|
isolation_context.instance
|
43
|
-
end
|
44
|
-
|
45
|
-
def initialize(*args)
|
46
|
-
self
|
147
|
+
end
|
148
|
+
|
149
|
+
def initialize(*args)
|
150
|
+
self
|
47
151
|
end
|
48
152
|
|
49
153
|
members.each do |mem|
|
@@ -63,6 +167,23 @@ module Caricature
|
|
63
167
|
isolation_context.send_class_message(mn, nil, *args, &b)
|
64
168
|
end
|
65
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
|
66
187
|
|
67
188
|
end
|
68
189
|
|
@@ -92,6 +213,7 @@ module Caricature
|
|
92
213
|
# builds the actual +isolator+ for the CLR interface
|
93
214
|
def create_isolation_for(subj)
|
94
215
|
proxy_members = @descriptor.instance_members
|
216
|
+
events = @descriptor.events
|
95
217
|
|
96
218
|
klass = Object.const_set(class_name(subj), Class.new)
|
97
219
|
klass.class_eval do
|
@@ -108,8 +230,22 @@ module Caricature
|
|
108
230
|
end
|
109
231
|
end
|
110
232
|
|
233
|
+
|
111
234
|
end
|
112
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
|
+
|
113
249
|
klass
|
114
250
|
end
|
115
251
|
end
|
@@ -14,6 +14,9 @@ module Caricature
|
|
14
14
|
if exp
|
15
15
|
block = exp.block || b
|
16
16
|
res = instance.__send__(method_name, *args, &block) if exp.super_before?
|
17
|
+
exp.event_recorder do |ev_nm, ev_ar, ev_h|
|
18
|
+
recorder.record_event_raise ev_nm, mode, *ev_ar, &ev_h if ev_nm
|
19
|
+
end if recorder && exp
|
17
20
|
res = exp.execute *args, &bl
|
18
21
|
res = instance.__send__(method_name, *args, &block) if !exp.super_before? and exp.call_super?
|
19
22
|
end
|
@@ -33,6 +36,9 @@ module Caricature
|
|
33
36
|
res = nil
|
34
37
|
is_value_type = return_type && return_type != System::Void.to_clr_type && return_type.is_value_type
|
35
38
|
exp = expectations.find(method_name, mode, *args)
|
39
|
+
exp.event_recorder do |ev_nm, ev_ar, ev_h|
|
40
|
+
recorder.record_event_raise ev_nm, mode, *ev_ar, &ev_h if ev_nm
|
41
|
+
end if recorder && exp
|
36
42
|
bl = record_call(method_name, mode, exp, *args, &b)
|
37
43
|
res = exp.execute *args, &bl if exp
|
38
44
|
res ||= System::Activator.create_instance(return_type) if is_value_type
|