module InactiveRecord
module Finders
# Ease the task of mocking ActiveRecord finder methods.
#
# Ex.:
#
# Product.finds 1, :name => 'Pizza'
#
# Then calling Product.find(1) will return an instance of product
# with the id 1 and the name Pizza.
# Product.find(:all) will return all records registered with the +finds+
# method. You also get the Product.count for free.
#
# You can also use the wildcard magic word +anything+ to return the
# same thing whatever the id or the finder used.
#
# Product.finds :anything, :name => 'god'
#
# Product.find_by_name 'what?' # => <#Product name=god>
# Product.find(123) # => <#Product name=god>
#
# finds_by_* allows you to use the find_by_* methods.
# Additionnaly the corresponding method will be initialized.
#
# Product.finds_by_name 'marc'
#
# Product.find_by_name 'marc' # => <#Product name=marc>
#
def finds(record_id, attributes={})
self.inactivate! attributes
record = self.new(attributes)
if record_id == :anything
record.stubs(:id).returns 1
self.stubs(:find).returns record
self.stubs(:find_every).returns [record]
else
record.stubs(:id).returns record_id
self.stubs(:find).with{ |id, *args| id == record_id || id == record_id.to_s }.returns record
record.extend InstanceMethods
end
reset_global_cache
end
def finds_by(attribute_name, attribute_value, attributes={})
attributes ||= {}
self.inactivate! attributes
record = self.new(attributes)
record.stubs(:id).returns attributes[:id] || 1
record[attribute_name] = attribute_value
self.stubs(:"find_by_#{attribute_name}").returns nil
self.stubs(:"find_by_#{attribute_name}").with(attribute_value).returns record
end
def method_missing_with_finds(method, *args)
if matches = method.to_s.match(/^finds_by_(.*)$/)
finds_by(matches[1], args[0], args[1])
else
method_missing_without_finds method, args
end
end
alias_method_chain :method_missing, :finds
def destroy_mock(id)
remove_expectations_for(:find, id)
reset_global_cache
true
end
# Module mixed-in all stubed records
module InstanceMethods
def destroy
self.class.destroy_mock(id)
end
end
private
def reset_global_cache
# Finds all previous expectation for find(id)
expectations = expectations_for(:find, instance_of(Fixnum))
self.stubs(:count).returns expectations.size
self.stubs(:find).with(:all).returns expectations.collect { |exp| exp.invoke }
end
def expectations
@mocha.expectations.instance_eval{@expectations}
end
def expectations_for(method, *parameters)
expectations.find_all do |exp|
exp.match?(method, *parameters)
end
end
def remove_expectations_for(method, *parameters)
expectations.reject! do |exp|
exp.match?(method, *parameters)
end
end
end
end