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.
Files changed (52) hide show
  1. data/README.rdoc +97 -97
  2. data/Rakefile +310 -310
  3. data/caricature.gemspec +110 -106
  4. data/lib/caricature.rb +3 -1
  5. data/lib/caricature/bacon.rb +2 -2
  6. data/lib/caricature/bacon/integration.rb +75 -55
  7. data/lib/caricature/clr.rb +4 -3
  8. data/lib/caricature/clr/aspnet_mvc.rb +3 -3
  9. data/lib/caricature/clr/descriptor.rb +106 -39
  10. data/lib/caricature/clr/event_verification.rb +57 -0
  11. data/lib/caricature/clr/expectation.rb +101 -0
  12. data/lib/caricature/clr/isolation.rb +49 -13
  13. data/lib/caricature/clr/isolator.rb +141 -5
  14. data/lib/caricature/clr/messenger.rb +6 -0
  15. data/lib/caricature/clr/method_call_recorder.rb +97 -0
  16. data/lib/caricature/core_ext.rb +11 -0
  17. data/lib/{core_ext → caricature/core_ext}/array.rb +0 -0
  18. data/lib/{core_ext → caricature/core_ext}/class.rb +0 -0
  19. data/lib/{core_ext → caricature/core_ext}/hash.rb +0 -0
  20. data/lib/{core_ext → caricature/core_ext}/module.rb +0 -0
  21. data/lib/{core_ext → caricature/core_ext}/object.rb +0 -0
  22. data/lib/{core_ext → caricature/core_ext}/string.rb +0 -0
  23. data/lib/{core_ext → caricature/core_ext}/system/string.rb +0 -0
  24. data/lib/{core_ext → caricature/core_ext}/system/type.rb +6 -0
  25. data/lib/caricature/expectation.rb +108 -66
  26. data/lib/caricature/isolator.rb +3 -3
  27. data/lib/caricature/method_call_recorder.rb +32 -4
  28. data/lib/caricature/rspec/integration.rb +118 -77
  29. data/lib/caricature/version.rb +5 -5
  30. data/spec/bacon/integration/callback_spec.rb +156 -156
  31. data/spec/bacon/integration/clr_to_clr_spec.rb +1 -2
  32. data/spec/bacon/integration/event_spec.rb +98 -0
  33. data/spec/bacon/integration/indexer_spec.rb +1 -1
  34. data/spec/bacon/spec_helper.rb +4 -4
  35. data/spec/bacon/unit/descriptor_spec.rb +95 -42
  36. data/spec/bacon/unit/expectation_spec.rb +2 -2
  37. data/spec/bacon/unit/interop_spec.rb +1 -14
  38. data/spec/bacon/unit/isolation_spec.rb +1 -1
  39. data/spec/bacon/unit/isolator_spec.rb +5 -5
  40. data/spec/bin/ClrModels.dll +0 -0
  41. data/spec/models/ClrModels.cs +32 -8
  42. data/spec/models/ruby_models.rb +150 -150
  43. data/spec/rspec/integration/callback_spec.rb +156 -156
  44. data/spec/rspec/integration/indexer_spec.rb +1 -1
  45. data/spec/rspec/spec_helper.rb +12 -6
  46. data/spec/rspec/unit/descriptor_spec.rb +93 -42
  47. data/spec/rspec/unit/event_spec.rb +17 -0
  48. data/spec/rspec/unit/interop_spec.rb +0 -13
  49. data/spec/spec_helper.rb +14 -14
  50. metadata +20 -22
  51. data/lib/core_ext/core_ext.rb +0 -8
  52. 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
- isolation = new(isolator, context)
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
- protected
31
-
32
- def internal_create_override(method_name, mode=:instance, &block)
33
- builder = ExpectationBuilder.new method_name
34
- block.call builder unless block.nil?
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 create_isolation_for(subj)
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