#GC.stress = true class FlexMock attr_reader :mock_name, :mock_groups attr_accessor :mock_current_order, :mock_container # Create a FlexMock object with the given name. The name is used in # error messages. def initialize(name="unknown") @mock_name = name @expectations = Hash.new @allocated_order = 0 @mock_current_order = 0 @mock_container = nil @mock_groups = {} #@ignore_missing = false @verified = false end # Handle missing methods by attempting to look up a handler. def method_missing(sym, *args, &block) p [:method_missing, sym, args, block] handler = @expectations[sym] handler.call(*args) end def should_receive(*args) FlexMock.should_receive(args) do |sym| handler = ExpectationDirector.new(sym) @expectations[sym] ||= handler result = Expectation.new(self, sym) handler << result result end end end class FlexMock class Expectation attr_reader :expected_args, :order_number attr_accessor :mock # Create an expectation for a method named +sym+. def initialize(mock, sym) @mock = mock @sym = sym @expected_args = nil @actual_count = 0 @return_block = lambda { nil } @order_number = nil end def verify_call(*args) @actual_count += 1 @return_block.call(*args) end def and_return(*args, &block) @return_block = block self end #alias :returns :and_return # :nodoc: end end class FlexMock class ExpectationDirector # Create an ExpectationDirector for a mock object. def initialize(sym) @sym = sym @expectations = [] @expected_order = nil end def call(*args) exp = @expectations.first exp.verify_call(*args) end def <<(expectation) @expectations << expectation end end end class FlexMock class << self attr_reader :framework_adapter def should_receive(args) # :nodoc: result = CompositeExpectation.new args.each do |arg| case arg when Symbol, String result.add(yield(arg.to_sym)) end end result end end class CompositeExpectation # Initialize the composite expectation. def initialize @expectations = [] end # Add an expectation to the composite. def add(expectation) @expectations << expectation end # Apply the constraint method to all expectations in the composite. def method_missing(sym, *args, &block) @expectations.each do |expectation| expectation.send(sym, *args, &block) end self end # The following methods return a value, so we make an arbitrary choice # and return the value for the first expectation in the composite. # Return the order number of the first expectation in the list. def order_number @expectations.first.order_number end # Return the associated mock object. def mock @expectations.first.mock end # Start a new method expectation. The following constraints will be # applied to the new expectation. def should_receive(*args, &block) @expectations.first.mock.should_receive(*args, &block) end end end class FlexMock class PartialMock attr_reader :mock, :mock_groups attr_accessor :mock_current_order, :mock_container # Initialize a PartialMock object. def initialize(obj, mock) @obj = obj @mock = mock #@method_definitions = {} @methods_proxied = [] @allocated_order = 0 @mock_current_order = 0 @mock_groups = {} end def new_name(old_name) "flexmock_original_behavior_for_#{old_name}" end def new_instances(*allocators, &block) args = [:allocate] exp = FlexMock.should_receive(args) do |sym| ex = @mock.should_receive(sym) ex.mock = self ex end exp.and_return { |*args_local| } end end end class Dog def self.create_mock obj = self name = "flexmock(Dog)" @flexmock_proxy ||= FlexMock::PartialMock.new(obj, FlexMock.new(name)) end def self.mock_allocate(*args, &block) p [:mock_allocate, args, block] @flexmock_proxy.mock.allocate(*args, &block) end end mock = Dog.create_mock mock.new_instances m = Dog.mock_allocate