~nchohan/appscale/GAE1.4.0-namespaces

« back to all changes in this revision

Viewing changes to AppLoadBalancer/vendor/gems/flexmock-0.8.6/lib/flexmock/mock_container.rb

  • Committer: Chris Bunch
  • Date: 2009-11-16 18:37:46 UTC
  • mto: This revision was merged to the branch mainline in revision 303.
  • Revision ID: chris@magna-carta-20091116183746-1sqxle515itjf6si
added fix for create_user on load balancer

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env ruby
 
2
 
 
3
#---
 
4
# Copyright 2003, 2004, 2005, 2006, 2007 by Jim Weirich (jim@weirichhouse.org).
 
5
# All rights reserved.
 
6
 
 
7
# Permission is granted for use, copying, modification, distribution,
 
8
# and distribution of modified versions of this work as long as the
 
9
# above copyright notice is included.
 
10
#+++
 
11
 
 
12
require 'flexmock/noop'
 
13
require 'flexmock/argument_types'
 
14
require 'flexmock/ordering'
 
15
 
 
16
class FlexMock
 
17
  
 
18
  # ######################################################################
 
19
  # Mock container methods
 
20
  #
 
21
  # Include this module in to get integration with FlexMock.  When this module
 
22
  # is included, mocks may be created with a simple call to the +flexmock+
 
23
  # method.  Mocks created with via the method call will automatically be
 
24
  # verified in the teardown of the test case.
 
25
  #   
 
26
  module MockContainer
 
27
    include Ordering
 
28
 
 
29
    # Do the flexmock specific teardown stuff.  If you need finer control,
 
30
    # you can use either +flexmock_verify+ or +flexmock_close+.
 
31
    def flexmock_teardown
 
32
      flexmock_verify if passed?
 
33
    ensure
 
34
      flexmock_close
 
35
    end
 
36
 
 
37
    # Perform verification on all mocks in the container.
 
38
    def flexmock_verify
 
39
      @flexmock_created_mocks ||= []
 
40
      @flexmock_created_mocks.each do |m|
 
41
        m.flexmock_verify
 
42
      end
 
43
    end
 
44
    
 
45
    # Close all the mock objects in the container.  Closing a mock object
 
46
    # restores any original behavior that was displaced by the mock.
 
47
    def flexmock_close
 
48
      @flexmock_created_mocks ||= []
 
49
      @flexmock_created_mocks.each do |m|
 
50
        m.flexmock_teardown
 
51
      end
 
52
      @flexmock_created_mocks = []
 
53
    end
 
54
    
 
55
    # Create a mocking object in the FlexMock framework.  The +flexmock+
 
56
    # method has a number of options available, depending on just what kind of
 
57
    # mocking object your require.  Mocks created via +flexmock+ will be
 
58
    # automatically verify during the teardown phase of your test framework.
 
59
    #
 
60
    # :call-seq:
 
61
    #   flexmock() { |mock| ... }
 
62
    #   flexmock(name) { |mock| ... }
 
63
    #   flexmock(expect_hash) { |mock| ... }
 
64
    #   flexmock(name, expect_hash) { |mock| ... }
 
65
    #   flexmock(real_object) { |mock| ... }
 
66
    #   flexmock(real_object, name) { |mock| ... }
 
67
    #   flexmock(real_object, name, expect_hash) { |mock| ... }
 
68
    #   flexmock(:base, string, name, expect_hash) { |mock| ... }
 
69
    #
 
70
    # <b>Note:</b> A plain flexmock() call without a block will return the
 
71
    # mock object (the object that interprets <tt>should_receive</tt> and its
 
72
    # brethern). A flexmock() call that _includes_ a block will return the
 
73
    # domain objects (the object that will interpret domain messages) since
 
74
    # the mock will be passed to the block for configuration. With regular
 
75
    # mocks, this distinction is unimportant because the mock object and the
 
76
    # domain object are the same object.  However, with partial mocks, the
 
77
    # mock object is separation from the domain object.  Keep that distinciton
 
78
    # in mind.
 
79
    #
 
80
    # name ::
 
81
    #   Name of the mock object.  If no name is given, "unknown" is used for
 
82
    #   full mocks and "flexmock(<em>real_object</em>)" is used for partial
 
83
    #   mocks.
 
84
    #
 
85
    # expect_hash ::
 
86
    #   Hash table of method names and values.  Each method/value pair is 
 
87
    #   used to setup a simple expectation so that if the mock object
 
88
    #   receives a message matching an entry in the table, it returns 
 
89
    #   the associated value.  No argument our call count constraints are
 
90
    #   added.  Using an expect_hash is identical to calling:
 
91
    #
 
92
    #       mock.should_receive(method_name).and_return(value)
 
93
    #
 
94
    #   for each of the method/value pairs in the hash.
 
95
    #
 
96
    # real_object ::
 
97
    #   If a real object is given, then a partial mock is constructed 
 
98
    #   using the real_object as a base. Partial mocks (formally referred 
 
99
    #   to as stubs) behave as a mock object when an expectation is matched, 
 
100
    #   and otherwise will behave like the original object.  This is useful 
 
101
    #   when you want to use a real object for testing, but need to mock out 
 
102
    #   just one or two methods.  
 
103
    #
 
104
    # :base ::
 
105
    #   Forces the following argument to be used as the base of a
 
106
    #   partial mock object.  This explicit tag is only needed if you 
 
107
    #   want to use a string or a symbol as the mock base (string and
 
108
    #   symbols would normally be interpretted as the mock name).
 
109
    #       
 
110
    # &block ::
 
111
    #   If a block is given, then the mock object is passed to the block and
 
112
    #   expectations may be configured within the block.  When a block is given
 
113
    #   for a partial mock, flexmock will return the domain object rather than 
 
114
    #   the mock object.  
 
115
    #
 
116
    def flexmock(*args)
 
117
      name = nil
 
118
      quick_defs = {}
 
119
      domain_obj = nil
 
120
      safe_mode = false
 
121
      model_class = nil
 
122
      while ! args.empty?
 
123
        case args.first
 
124
        when :base, :safe
 
125
          safe_mode = (args.shift == :safe)
 
126
          domain_obj = args.shift
 
127
        when :model
 
128
          args.shift
 
129
          model_class = args.shift
 
130
        when String, Symbol
 
131
          name = args.shift.to_s
 
132
        when Hash
 
133
          quick_defs = args.shift
 
134
        else
 
135
          domain_obj = args.shift
 
136
        end
 
137
      end
 
138
      raise UsageError, "a block is required in safe mode" if safe_mode && ! block_given?
 
139
 
 
140
      if domain_obj
 
141
        mock = ContainerHelper.make_partial_proxy(self, domain_obj, name, safe_mode)
 
142
        result = domain_obj
 
143
      elsif model_class
 
144
        id = ContainerHelper.next_id
 
145
        result = mock = FlexMock.new("#{model_class}_#{id}", self)
 
146
      else
 
147
        result = mock = FlexMock.new(name || "unknown", self)
 
148
      end
 
149
      mock.should_receive(quick_defs)
 
150
      yield(mock) if block_given?
 
151
      flexmock_remember(mock)
 
152
      ContainerHelper.add_model_methods(mock, model_class, id) if model_class
 
153
      result
 
154
    end
 
155
    alias flexstub flexmock
 
156
    
 
157
    # Remember the mock object / stub in the mock container.
 
158
    def flexmock_remember(mocking_object)
 
159
      @flexmock_created_mocks ||= []
 
160
      @flexmock_created_mocks << mocking_object
 
161
      mocking_object.flexmock_container = self
 
162
      mocking_object
 
163
    end
 
164
  end
 
165
 
 
166
  # #################################################################
 
167
  # Helper methods for mock containers.  MockContainer is a module
 
168
  # that is designed to be mixed into other classes, particularly
 
169
  # testing framework test cases.  Since we don't want to pollute the
 
170
  # method namespace of the class that mixes in MockContainer, a
 
171
  # number of MockContainer methods were moved into ContainerHelper to
 
172
  # to isoloate the names.
 
173
  #
 
174
  class MockContainerHelper
 
175
    include FlexMock::ArgumentTypes
 
176
 
 
177
    # Return the next id for mocked models.
 
178
    def next_id
 
179
      @id_counter ||= 10000
 
180
      @id_counter += 1
 
181
    end
 
182
 
 
183
    # :call-seq:
 
184
    #   parse_should_args(args) { |symbol| ... }
 
185
    #
 
186
    # This method provides common handling for the various should_receive
 
187
    # argument lists. It sorts out the differences between symbols, arrays and
 
188
    # hashes, and identifies the method names specified by each.  As each
 
189
    # method name is identified, create a mock expectation for it using the
 
190
    # supplied block.
 
191
    def parse_should_args(mock, args, &block)  # :nodoc:
 
192
      result = CompositeExpectation.new
 
193
      args.each do |arg|
 
194
        case arg
 
195
        when Hash
 
196
          arg.each do |k,v|
 
197
            exp = build_demeter_chain(mock, k, &block).and_return(v)
 
198
            result.add(exp)
 
199
          end
 
200
        when Symbol, String
 
201
          result.add(build_demeter_chain(mock, arg, &block))
 
202
        end
 
203
      end
 
204
      result
 
205
    end
 
206
 
 
207
    # Automatically add mocks for some common methods in ActiveRecord
 
208
    # models.
 
209
    def add_model_methods(mock, model_class, id)
 
210
      container = mock.flexmock_container
 
211
 
 
212
      mock_errors = container.flexmock("errors")
 
213
      mock_errors.should_receive(:count).and_return(0).by_default
 
214
      mock_errors.should_receive(:full_messages).and_return([]).by_default
 
215
 
 
216
      mock.should_receive(:id).and_return(id).by_default
 
217
      mock.should_receive(:to_params).and_return(id.to_s).by_default
 
218
      mock.should_receive(:new_record?).and_return(false).by_default
 
219
      mock.should_receive(:class).and_return(model_class).by_default
 
220
      mock.should_receive(:errors).and_return(mock_errors).by_default
 
221
 
 
222
      # HACK: Ruby 1.9 needs the following lambda so that model_class
 
223
      # is correctly bound below.
 
224
      lambda { }
 
225
      mock.should_receive(:is_a?).with(any).and_return { |other|
 
226
        other == model_class
 
227
      }.by_default
 
228
      mock.should_receive(:instance_of?).with(any).and_return { |other|
 
229
        other == model_class
 
230
      }.by_default
 
231
      mock.should_receive(:kind_of?).with(any).and_return { |other|
 
232
        model_class.ancestors.include?(other)
 
233
      }.by_default
 
234
    end
 
235
 
 
236
    # Create a PartialMockProxy for the given object.  Use +name+ as
 
237
    # the name of the mock object.
 
238
    def make_partial_proxy(container, obj, name, safe_mode)
 
239
      name ||= "flexmock(#{obj.class.to_s})"
 
240
      obj.instance_eval {
 
241
        mock = FlexMock.new(name, container)
 
242
        @flexmock_proxy ||= PartialMockProxy.new(obj, mock, safe_mode)
 
243
      }
 
244
      obj.instance_variable_get("@flexmock_proxy")
 
245
    end
 
246
 
 
247
    private
 
248
    
 
249
    # Build the chain of mocks for demeter style mocking.
 
250
    #
 
251
    # Warning: Nasty code ahead.
 
252
    #
 
253
    # This method builds a chain of mocks to support demeter style
 
254
    # mocking.  Given a mock chain of "first.second.third.last", we
 
255
    # must build a chain of mock methods that return the next mock in
 
256
    # the chain.  The expectation for the last method of the chain is
 
257
    # returned as the result of the method.
 
258
    #
 
259
    # Things to consider:
 
260
    #
 
261
    # (1) The expectation for the "first" method must be created by
 
262
    # the proper mechanism, which is supplied by the block parameter
 
263
    # "block".  In other words, first expectation is created by
 
264
    # calling the block.  (This allows us to create expectations on
 
265
    # both pure mocks and partial mocks, with the block handling the
 
266
    # details).
 
267
    #
 
268
    # (2) Although the first mock is arbitrary, the remaining mocks in
 
269
    # the chain will always be pure mocks created specifically for
 
270
    # this purpose.
 
271
    #
 
272
    # (3) The expectations for all methods but the last in the chain
 
273
    # will be setup to expect no parameters and to return the next
 
274
    # mock in the chain.
 
275
    #
 
276
    # (4) It could very well be the case that several demeter chains
 
277
    # will be defined on a single mock object, and those chains could
 
278
    # share some of the same methods (e.g. "mock.one.two.read" and
 
279
    # "mock.one.two.write" both share the methods "one" and "two").
 
280
    # It is important that the shared methods return the same mocks in
 
281
    # both chains.
 
282
    #
 
283
    def build_demeter_chain(mock, arg, &block)
 
284
      container = mock.flexmock_container
 
285
      names = arg.to_s.split('.')
 
286
      check_method_names(names)
 
287
      exp = nil
 
288
      next_exp = lambda { |n| block.call(n) }
 
289
      loop do
 
290
        method_name = names.shift.to_sym
 
291
        exp = mock.flexmock_find_expectation(method_name)
 
292
        need_new_exp = exp.nil? || names.empty?
 
293
        exp = next_exp.call(method_name) if need_new_exp
 
294
        break if names.empty?
 
295
        if need_new_exp
 
296
          mock = container.flexmock("demeter_#{method_name}")
 
297
          exp.with_no_args.and_return(mock)
 
298
        else
 
299
          mock = exp._return_value([])
 
300
        end
 
301
        check_proper_mock(mock, method_name)
 
302
        next_exp = lambda { |n| mock.should_receive(n) }
 
303
      end
 
304
      exp
 
305
    end
 
306
    
 
307
    # Check that the given mock is a real FlexMock mock.
 
308
    def check_proper_mock(mock, method_name)
 
309
      unless mock.kind_of?(FlexMock)
 
310
        fail FlexMock::UsageError,
 
311
          "Conflicting mock declaration for '#{method_name}' in demeter style mock"
 
312
      end
 
313
    end
 
314
    
 
315
    METHOD_NAME_RE = /^([A-Za-z_][A-Za-z0-9_]*[=!?]?|\[\]=?||\*\*|<<|>>|<=>|[<>=]=|=~|===|[-+]@|[-+\*\/%&^|<>~])$/
 
316
 
 
317
    # Check that all the names in the list are valid method names.
 
318
    def check_method_names(names)
 
319
      names.each do |name|
 
320
        fail FlexMock::UsageError, "Ill-formed method name '#{name}'" if
 
321
          name !~ METHOD_NAME_RE
 
322
      end
 
323
    end
 
324
  end
 
325
 
 
326
  ContainerHelper = MockContainerHelper.new
 
327
end