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,97 @@
1
+ module Caricature
2
+
3
+ # A recording that represents an event raise
4
+ # it contains argument variations that can be matched too
5
+ class EventRaiseRecording
6
+
7
+ # gets or sets the event name
8
+ attr_accessor :event_name
9
+
10
+ # gets or sets the amount of times the event was raised
11
+ attr_accessor :count
12
+
13
+ # gets or sets the arguments for this event raise
14
+ attr_accessor :args
15
+
16
+ # gets or sets the block for this event raise
17
+ attr_accessor :handler
18
+
19
+ # Initializes a new instance of a method call recording
20
+ # every time a method gets called in an isolated object
21
+ # this gets stored in the method call recorder
22
+ # It expects a +method_name+ at the very least.
23
+ def initialize(event_name, count=0)
24
+ @event_name = event_name
25
+ @count = count
26
+ @variations = []
27
+ end
28
+
29
+ # add args
30
+ def args
31
+ @variations
32
+ end
33
+
34
+ # indicates if it has an argument variation
35
+ def has_argument_variations?
36
+ @variations.size > 1
37
+ end
38
+
39
+ # add an argument variation
40
+ def add_argument_variation(args, block)
41
+ variation = find_argument_variations args
42
+ if variation.empty?
43
+ @variations << ArgumentRecording.new(args, @variations.size+1, block) if variation == []
44
+ else
45
+ variation.first.call_number += 1
46
+ end
47
+ end
48
+
49
+ # finds an argument variation that matches the provided +args+
50
+ def find_argument_variations(args)
51
+ return @variations if args.first.is_a?(Symbol) and args.last == :any
52
+ @variations.select { |ar| ar.args == args }
53
+ end
54
+
55
+ end
56
+
57
+ class MethodCallRecorder
58
+
59
+ def event_raises
60
+ @event_raises ||= {}
61
+ end
62
+
63
+ def record_event_raise(event_name, mode, *args, &handler)
64
+ en_sym = event_name.to_sym
65
+ event_raises[mode] ||= {}
66
+ ev = (event_raises[mode][en_sym] ||= EventRaiseRecording.new(event_name))
67
+ ev.count += 1
68
+ ev.add_argument_variation args, handler
69
+ end
70
+
71
+ def event_error
72
+ @event_error
73
+ end
74
+
75
+ # returns whether the event was actually raised with the specified constraints
76
+ def event_raised?(event_name, mode = :instance, *args)
77
+ mc = event_raises[mode][event_name.to_s.to_sym]
78
+ if mc
79
+ vari = mc.find_argument_variations(args)
80
+ result = vari.any? { |agv| agv == args }
81
+ return result if result
82
+ if args.size == 1 and args.last.is_a?(Hash)
83
+ result = vari.any? do |agv|
84
+ agv.args.last.is_a?(Hash) and args.last.all? { |k, v| agv.args.last[k] == v }
85
+ end
86
+ end
87
+ @event_error = "Event Arguments don't match for #{event_name}.\n\nYou expected:\n#{args.join(", ")}.\n\nI did find the following variations:\n#{mc.args.collect {|ar| ar.args.join(', ') }.join(' and ')}" unless result
88
+ result
89
+ else
90
+ @event_error = "Couldn't find an event with name #{event_name}"
91
+ return !!mc
92
+ end
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/core_ext/string'
2
+ require File.dirname(__FILE__) + '/core_ext/class'
3
+ require File.dirname(__FILE__) + '/core_ext/module'
4
+ require File.dirname(__FILE__) + '/core_ext/object'
5
+ require File.dirname(__FILE__) + '/core_ext/array'
6
+ require File.dirname(__FILE__) + '/core_ext/hash'
7
+
8
+ if defined? IRONRUBY_VERSION
9
+ require File.dirname(__FILE__) + '/core_ext/system/string'
10
+ require File.dirname(__FILE__) + '/core_ext/system/type'
11
+ end
@@ -16,6 +16,12 @@ module System
16
16
  self.get_properties + iface_properties.flatten
17
17
  end
18
18
 
19
+ def collect_interface_events
20
+ iface_events = []
21
+ iface_events += self.get_interfaces.collect { |t| t.collect_interface_events }
22
+ self.get_events + iface_events.flatten.uniq
23
+ end
24
+
19
25
  end
20
26
 
21
27
  end
@@ -35,58 +35,66 @@ module Caricature
35
35
  # contains the syntax for building up an expectation
36
36
  # This is shared between the +ExpecationBuilder+ and the +Expectation+
37
37
  module ExpectationSyntax
38
+
38
39
  # tell the expection which arguments it needs to respond to
39
40
  # there is a magic argument here +any+ which configures
40
41
  # the expectation to respond to any arguments
41
- def with(*args, &b)
42
- @any_args = args.first.is_a?(Symbol) and args.first == :any
43
- @args = args
44
- @callback = b unless b.nil?
42
+ def with(*ags, &b)
43
+ collected[:any_args] = ags.first.is_a?(Symbol) and ags.first == :any
44
+ collected[:args] = ags
45
+ collected[:callback] = b unless b.nil?
45
46
  self
46
47
  end
47
48
 
48
49
  # tell the expectation it nees to return this value or the value returned by the block
49
50
  # you provide to this method.
50
51
  def return(value=nil, &b)
51
- @return_value = value
52
- @return_callback = b if b
52
+ collected[:return_value] = value
53
+ collected[:return_callback] = b if b
53
54
  self
54
55
  end
55
56
 
56
57
  # Sets up arguments for the block that is being passed into the isolated method call
57
- def pass_block(*args, &b)
58
- @any_block_args = args.first.is_a?(Symbol) and args.first == :any
59
- @block_args = args
60
- @block_callback = b unless b.nil?
58
+ def pass_block(*ags, &b)
59
+ collected[:any_block_args] = ags.first.is_a?(Symbol) and args.first == :any
60
+ collected[:block_args] = ags
61
+ collected[:block_callback] = b unless b.nil?
61
62
  self
62
63
  end
63
64
 
64
65
  # tell the expectation it needs to raise an error with the specified arguments
65
66
  alias_method :actual_raise, :raise
66
67
  def raise(*args)
67
- @error_args = args
68
+ collected[:error_args] = args
68
69
  self
69
70
  end
70
-
71
+
71
72
  # tell the expecation it needs to call the super before the expectation exectution
72
73
  def super_before(&b)
73
- @super = :before
74
- @block = b if b
74
+ collected[:super] = :before
75
+ collected[:block] = b if b
75
76
  self
76
77
  end
77
-
78
+
78
79
  # tell the expectation it needs to call the super after the expecation execution
79
80
  def super_after(&b)
80
- @super = :after
81
- @block = b if b
81
+ collected[:super] = :after
82
+ collected[:block] = b if b
82
83
  self
83
84
  end
84
85
 
85
86
  # indicates whether this expectation should match with any arguments
86
87
  # or only for the specified arguments
87
88
  def any_args?
88
- @any_args
89
+ collected[:any_args]
89
90
  end
91
+
92
+
93
+ private
94
+
95
+ def collected
96
+ @collected ||= {}
97
+ end
90
98
  end
91
99
 
92
100
  # A description of an expectation.
@@ -95,106 +103,140 @@ module Caricature
95
103
 
96
104
  include ExpectationSyntax
97
105
 
98
- # gets the method_name to which this expectation needs to listen to
99
- attr_reader :method_name
100
-
101
- # the arguments that this expectation needs to be constrained by
102
- attr_reader :args
103
-
104
106
  # the error_args that this expectation will raise an error with
105
- attr_reader :error_args
107
+ def error_args
108
+ collected[:error_args]
109
+ end
106
110
 
107
111
  # the value that this expecation will return when executed
108
- attr_reader :return_value
112
+ def return_value
113
+ collected[:return_value]
114
+ end
109
115
 
110
116
  # indicator for the mode to call the super +:before+, +:after+ and +nil+
111
- attr_reader :super
112
-
117
+ def super
118
+ collected[:super]
119
+ end
120
+
113
121
  # contains the callback if one is given
114
- attr_reader :callback
122
+ def callback
123
+ collected[:callback]
124
+ end
115
125
 
116
126
  # contains the callback that is used to return the value when this expectation
117
127
  # is executed
118
- attr_reader :return_callback
128
+ def return_callback
129
+ collected[:return_callback]
130
+ end
119
131
 
120
132
  # contains the arguments that will be passed on to the block
121
- attr_reader :block_args
133
+ def block_args
134
+ collected[:block_args]
135
+ end
122
136
 
123
137
  # The block that will be used as value provider for the block in the method
124
- attr_reader :block_callback
138
+ def block_callback
139
+ collected[:block_callback]
140
+ end
125
141
 
126
142
  # the block that will be used
127
- attr_accessor :block
128
-
129
-
143
+ def block
144
+ collected[:block]
145
+ end
146
+
147
+ # sets the block callback
148
+ def block=(val)
149
+ collected[:block] = val
150
+ end
151
+
152
+ # gets the method_name to which this expectation needs to listen to
153
+ def method_name
154
+ collected[:method_name]
155
+ end
156
+
157
+ # the arguments that this expectation needs to be constrained by
158
+ def args
159
+ collected[:args]
160
+ end
161
+
130
162
  # Initializes a new instance of an expectation
131
- def initialize(*args)
132
- @method_name, @args, @error_args, @return_value, @return_callback,
133
- @super, @callback, @block_args, @block_callback, @block = *args
134
- @any_args = true
163
+ def initialize(options={})
164
+ collected[:any_args] = true
165
+ collected.merge!(options)
135
166
  end
136
-
167
+
137
168
  # indicates whether this expecation will raise an event.
138
169
  def has_error_args?
139
- !@error_args.nil?
170
+ !collected[:error_args].nil?
140
171
  end
141
172
 
142
173
  # indicates whether this expectation will return a value.
143
174
  def has_return_value?
144
- !@return_value.nil?
175
+ !collected[:return_value].nil?
145
176
  end
146
177
 
147
178
  # call the super before the expectation
148
179
  def super_before?
149
- @super == :before
180
+ collected[:super] == :before
150
181
  end
151
182
 
152
183
  # indicates whether super needs to be called somewhere
153
184
  def call_super?
154
- !@super.nil?
185
+ !collected[:super].nil?
155
186
  end
156
187
 
157
188
  # indicates whether this expecation has a callback it needs to execute
158
189
  def has_callback?
159
- !@callback.nil?
190
+ !collected[:callback].nil?
160
191
  end
161
-
192
+
162
193
  # indicates whether this expectation has a block as value provider for the method call block
163
194
  def has_block_callback?
164
- !@block_callback.nil?
195
+ !collected[:block_callback].nil?
165
196
  end
166
197
 
167
198
  # a flag to indicate it has a return value callback
168
199
  def has_return_callback?
169
- !@return_callback.nil?
200
+ !collected[:return_callback].nil?
170
201
  end
171
202
 
172
203
  # executes this expectation with its configuration
173
204
  def execute(*margs,&b)
174
- ags = any_args? ? (margs.empty? ? :any : margs) : args
175
- actual_raise *@error_args if has_error_args?
176
- callback.call(*ags) if has_callback?
177
-
178
- if b
179
- if has_block_callback?
180
- b.call(*@block_callback.call)
181
- else
182
- b.call(*@block_args)
183
- end
184
- end
205
+ ags = any_args? ? :any : (margs.empty? ? collected[:args] : margs)
206
+ do_raise_error
207
+ do_callback(ags)
208
+ do_block_callback(&b)
209
+ do_event_raise if respond_to?(:events)
185
210
 
186
- return @return_callback.call(*margs) if has_return_callback?
211
+ return collected[:return_callback].call(*margs) if has_return_callback?
187
212
  return return_value if has_return_value?
188
213
  nil
189
214
  end
190
215
 
191
- def to_s
216
+ def to_s #:nodoc:
192
217
  "<Caricature::Expecation, method_name: #{method_name}, args: #{args}, error args: #{error_args}>"
193
218
  end
194
-
195
- def inspect
196
- to_s
219
+ alias :inspect :to_s
220
+
221
+
222
+ private
223
+
224
+ def do_raise_error #:nodoc:
225
+ actual_raise *collected[:error_args] if has_error_args?
226
+ end
227
+
228
+ def do_callback(ags) #:nodoc:
229
+ callback.call(*ags) if has_callback?
197
230
  end
231
+
232
+ def do_block_callback(&b) #:nodoc:
233
+ if b
234
+ ags = has_block_callback? ? collected[:block_callback].call : collected[:block_args]
235
+ b.call(*ags)
236
+ end
237
+ end
238
+
239
+
198
240
  end
199
241
 
200
242
  # Constructs the expecation object.
@@ -207,14 +249,14 @@ module Caricature
207
249
  # this builder is passed into the block to allow only certain
208
250
  # operations in the block.
209
251
  def initialize(method_name)
210
- @method_name, @args, @any_args = method_name, [], true
252
+ @collected = { :method_name => method_name, :args => [], :any_args => true }
211
253
  end
212
254
 
213
255
 
214
256
 
215
257
  # build up the expectation with the provided arguments
216
258
  def build
217
- Expectation.new @method_name, @args, @error_args, @return_value, @return_callback, @super, @callback, @block_args, @block_callback, @block
259
+ Expectation.new collected
218
260
  end
219
261
 
220
262
  end
@@ -214,6 +214,7 @@ module Caricature
214
214
  pxy.instance_variable_set("@___context___", context)
215
215
  pxy
216
216
  end
217
+
217
218
 
218
219
  class << self
219
220
 
@@ -280,17 +281,16 @@ module Caricature
280
281
  def initialize(*args)
281
282
  self
282
283
  end
283
-
284
+
284
285
  cmembers.each do |mn|
285
286
  mn = mn.name.to_s.to_sym
286
287
  define_cmethod mn do |*args|
288
+ return if mn.to_s =~ /$(singleton_)?method_added/ and args.first.to_s =~ /$(singleton_)?method_added/
287
289
  b = nil
288
290
  b = Proc.new { yield } if block_given?
289
291
  isolation_context.send_class_message(mn, nil, *args, &b)
290
292
  end
291
293
  end
292
-
293
-
294
294
 
295
295
  end
296
296