caricature 0.7.2 → 0.7.5
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 +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
|