require "cases/helper"
require 'models/author'
require 'models/comment'
require 'models/company'
require 'models/topic'
require 'models/reply'
require 'models/entrant'
require 'models/developer'
require 'models/post'
require 'models/customer'
class FinderTest < ActiveRecord::TestCase
fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers
def test_find
assert_equal(topics(:first).title, Topic.find(1).title)
end
# find should handle strings that come from URLs
# (example: Category.find(params[:id]))
def test_find_with_string
assert_equal(Topic.find(1).title,Topic.find("1").title)
end
def test_exists
assert Topic.exists?(1)
assert Topic.exists?("1")
assert Topic.exists?(:author_name => "David")
assert Topic.exists?(:author_name => "Mary", :approved => true)
assert Topic.exists?(["parent_id = ?", 1])
assert !Topic.exists?(45)
begin
assert !Topic.exists?("foo")
rescue ActiveRecord::StatementInvalid
# PostgreSQL complains about string comparison with integer field
rescue Exception
flunk
end
assert_raise(NoMethodError) { Topic.exists?([1,2]) }
end
def test_exists_with_aggregate_having_three_mappings
existing_address = customers(:david).address
assert Customer.exists?(:address => existing_address)
end
def test_exists_with_aggregate_having_three_mappings_with_one_difference
existing_address = customers(:david).address
assert !Customer.exists?(:address =>
Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
assert !Customer.exists?(:address =>
Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
assert !Customer.exists?(:address =>
Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
end
def test_find_by_array_of_one_id
assert_kind_of(Array, Topic.find([ 1 ]))
assert_equal(1, Topic.find([ 1 ]).length)
end
def test_find_by_ids
assert_equal 2, Topic.find(1, 2).size
assert_equal topics(:second).title, Topic.find([2]).first.title
end
def test_find_by_ids_with_limit_and_offset
assert_equal 2, Entrant.find([1,3,2], :limit => 2).size
assert_equal 1, Entrant.find([1,3,2], :limit => 3, :offset => 2).size
# Also test an edge case: If you have 11 results, and you set a
# limit of 3 and offset of 9, then you should find that there
# will be only 2 results, regardless of the limit.
devs = Developer.find :all
last_devs = Developer.find devs.map(&:id), :limit => 3, :offset => 9
assert_equal 2, last_devs.size
end
def test_find_an_empty_array
assert_equal [], Topic.find([])
end
def test_find_by_ids_missing_one
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
end
def test_find_all_with_limit
entrants = Entrant.find(:all, :order => "id ASC", :limit => 2)
assert_equal(2, entrants.size)
assert_equal(entrants(:first).name, entrants.first.name)
end
def test_find_all_with_prepared_limit_and_offset
entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 1)
assert_equal(2, entrants.size)
assert_equal(entrants(:second).name, entrants.first.name)
entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 2)
assert_equal(1, entrants.size)
assert_equal(entrants(:third).name, entrants.first.name)
end
def test_find_all_with_limit_and_offset_and_multiple_orderings
developers = Developer.find(:all, :order => "salary ASC, id DESC", :limit => 3, :offset => 1)
assert_equal ["David", "fixture_10", "fixture_9"], developers.collect {|d| d.name}
end
def test_find_with_limit_and_condition
developers = Developer.find(:all, :order => "id DESC", :conditions => "salary = 100000", :limit => 3, :offset =>7)
assert_equal(1, developers.size)
assert_equal("fixture_3", developers.first.name)
end
def test_find_with_entire_select_statement
topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
assert_equal(1, topics.size)
assert_equal(topics(:second).title, topics.first.title)
end
def test_find_with_prepared_select_statement
topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
assert_equal(1, topics.size)
assert_equal(topics(:second).title, topics.first.title)
end
def test_find_by_sql_with_sti_on_joined_table
accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
assert_equal [Account], accounts.collect(&:class).uniq
end
def test_find_first
first = Topic.find(:first, :conditions => "title = 'The First Topic'")
assert_equal(topics(:first).title, first.title)
end
def test_find_first_failing
first = Topic.find(:first, :conditions => "title = 'The First Topic!'")
assert_nil(first)
end
def test_unexisting_record_exception_handling
assert_raises(ActiveRecord::RecordNotFound) {
Topic.find(1).parent
}
Topic.find(2).topic
end
def test_find_only_some_columns
topic = Topic.find(1, :select => "author_name")
assert_raises(ActiveRecord::MissingAttributeError) {topic.title}
assert_equal "David", topic.author_name
assert !topic.attribute_present?("title")
#assert !topic.respond_to?("title")
assert topic.attribute_present?("author_name")
assert topic.respond_to?("author_name")
end
def test_find_on_blank_conditions
[nil, " ", [], {}].each do |blank|
assert_nothing_raised { Topic.find(:first, :conditions => blank) }
end
end
def test_find_on_blank_bind_conditions
[ [""], ["",{}] ].each do |blank|
assert_nothing_raised { Topic.find(:first, :conditions => blank) }
end
end
def test_find_on_array_conditions
assert Topic.find(1, :conditions => ["approved = ?", false])
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => ["approved = ?", true]) }
end
def test_find_on_hash_conditions
assert Topic.find(1, :conditions => { :approved => false })
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :approved => true }) }
end
def test_find_on_hash_conditions_with_explicit_table_name
assert Topic.find(1, :conditions => { 'topics.approved' => false })
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) }
end
def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
david = customers(:david)
assert Customer.find(david.id, :conditions => { 'customers.name' => david.name, :address => david.address })
assert_raises(ActiveRecord::RecordNotFound) {
Customer.find(david.id, :conditions => { 'customers.name' => david.name + "1", :address => david.address })
}
end
def test_find_on_association_proxy_conditions
assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10], Comment.find_all_by_post_id(authors(:david).posts).map(&:id).sort
end
def test_find_on_hash_conditions_with_range
assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1..2 }).map(&:id).sort
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) }
end
def test_find_on_hash_conditions_with_multiple_ranges
assert_equal [1,2,3], Comment.find(:all, :conditions => { :id => 1..3, :post_id => 1..2 }).map(&:id).sort
assert_equal [1], Comment.find(:all, :conditions => { :id => 1..1, :post_id => 1..10 }).map(&:id).sort
end
def test_find_on_multiple_hash_conditions
assert Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false })
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }) }
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
end
def test_condition_interpolation
assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
end
def test_condition_array_interpolation
assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
end
def test_condition_hash_interpolation
assert_kind_of Firm, Company.find(:first, :conditions => { :name => "37signals"})
assert_nil Company.find(:first, :conditions => { :name => "37signals!"})
assert_kind_of Time, Topic.find(:first, :conditions => {:id => 1}).written_on
end
def test_hash_condition_find_malformed
assert_raises(ActiveRecord::StatementInvalid) {
Company.find(:first, :conditions => { :id => 2, :dhh => true })
}
end
def test_hash_condition_find_with_escaped_characters
Company.create("name" => "Ain't noth'n like' \#stuff")
assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff" })
end
def test_hash_condition_find_with_array
p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2] }, :order => 'id asc')
assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2.id] }, :order => 'id asc')
end
def test_hash_condition_find_with_nil
topic = Topic.find(:first, :conditions => { :last_read => nil } )
assert_not_nil topic
assert_nil topic.last_read
end
def test_hash_condition_find_with_aggregate_having_one_mapping
balance = customers(:david).balance
assert_kind_of Money, balance
found_customer = Customer.find(:first, :conditions => {:balance => balance})
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
gps_location = customers(:david).gps_location
assert_kind_of GpsLocation, gps_location
found_customer = Customer.find(:first, :conditions => {:gps_location => gps_location})
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
balance = customers(:david).balance
assert_kind_of Money, balance
found_customer = Customer.find(:first, :conditions => {:balance => balance.amount})
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
gps_location = customers(:david).gps_location
assert_kind_of GpsLocation, gps_location
found_customer = Customer.find(:first, :conditions => {:gps_location => gps_location.gps_location})
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_aggregate_having_three_mappings
address = customers(:david).address
assert_kind_of Address, address
found_customer = Customer.find(:first, :conditions => {:address => address})
assert_equal customers(:david), found_customer
end
def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
address = customers(:david).address
assert_kind_of Address, address
found_customer = Customer.find(:first, :conditions => {:address => address, :name => customers(:david).name})
assert_equal customers(:david), found_customer
end
def test_bind_variables
assert_kind_of Firm, Company.find(:first, :conditions => ["name = ?", "37signals"])
assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!"])
assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!' OR 1=1"])
assert_kind_of Time, Topic.find(:first, :conditions => ["id = ?", 1]).written_on
assert_raises(ActiveRecord::PreparedStatementInvalid) {
Company.find(:first, :conditions => ["id=? AND name = ?", 2])
}
assert_raises(ActiveRecord::PreparedStatementInvalid) {
Company.find(:first, :conditions => ["id=?", 2, 3, 4])
}
end
def test_bind_variables_with_quotes
Company.create("name" => "37signals' go'es agains")
assert Company.find(:first, :conditions => ["name = ?", "37signals' go'es agains"])
end
def test_named_bind_variables_with_quotes
Company.create("name" => "37signals' go'es agains")
assert Company.find(:first, :conditions => ["name = :name", {:name => "37signals' go'es agains"}])
end
def test_bind_arity
assert_nothing_raised { bind '' }
assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '?' }
assert_nothing_raised { bind '?', 1 }
assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 }
end
def test_named_bind_variables
assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
assert_kind_of Firm, Company.find(:first, :conditions => ["name = :name", { :name => "37signals" }])
assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!" }])
assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!' OR 1=1" }]