caricature 0.7.2 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
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