diff options
Diffstat (limited to 'activerecord/test/cases/deprecated_dynamic_methods_test.rb')
-rw-r--r-- | activerecord/test/cases/deprecated_dynamic_methods_test.rb | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/activerecord/test/cases/deprecated_dynamic_methods_test.rb b/activerecord/test/cases/deprecated_dynamic_methods_test.rb new file mode 100644 index 0000000000..77a609f49a --- /dev/null +++ b/activerecord/test/cases/deprecated_dynamic_methods_test.rb @@ -0,0 +1,607 @@ +# This file should be deleted when active_record_deprecated_finders is removed as +# a dependency. +# +# It is kept for now as there is some fairly nuanced behaviour in the dynamic +# finders so it is useful to keep this around to guard against regressions if +# we need to change the code. + +require 'cases/helper' +require 'models/topic' +require 'models/reply' +require 'models/customer' +require 'models/post' +require 'models/company' +require 'models/author' +require 'models/category' +require 'models/comment' +require 'models/person' +require 'models/reader' + +class DeprecatedDynamicMethodsTest < ActiveRecord::TestCase + fixtures :topics, :customers, :companies, :accounts, :posts, :categories, :categories_posts, :authors, :people, :comments, :readers + + def setup + @deprecation_behavior = ActiveSupport::Deprecation.behavior + ActiveSupport::Deprecation.behavior = :silence + end + + def teardown + ActiveSupport::Deprecation.behavior = @deprecation_behavior + end + + def test_find_all_by_one_attribute + topics = Topic.find_all_by_content("Have a nice day") + assert_equal 2, topics.size + assert topics.include?(topics(:first)) + + assert_equal [], Topic.find_all_by_title("The First Topic!!") + end + + def test_find_all_by_one_attribute_which_is_a_symbol + topics = Topic.find_all_by_content("Have a nice day".to_sym) + assert_equal 2, topics.size + assert topics.include?(topics(:first)) + + assert_equal [], Topic.find_all_by_title("The First Topic!!") + end + + def test_find_all_by_one_attribute_that_is_an_aggregate + balance = customers(:david).balance + assert_kind_of Money, balance + found_customers = Customer.find_all_by_balance(balance) + assert_equal 1, found_customers.size + assert_equal customers(:david), found_customers.first + end + + def test_find_all_by_two_attributes_that_are_both_aggregates + balance = customers(:david).balance + address = customers(:david).address + assert_kind_of Money, balance + assert_kind_of Address, address + found_customers = Customer.find_all_by_balance_and_address(balance, address) + assert_equal 1, found_customers.size + assert_equal customers(:david), found_customers.first + end + + def test_find_all_by_two_attributes_with_one_being_an_aggregate + balance = customers(:david).balance + assert_kind_of Money, balance + found_customers = Customer.find_all_by_balance_and_name(balance, customers(:david).name) + assert_equal 1, found_customers.size + assert_equal customers(:david), found_customers.first + end + + def test_find_all_by_one_attribute_with_options + topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC") + assert_equal topics(:first), topics.last + + topics = Topic.find_all_by_content("Have a nice day", :order => "id") + assert_equal topics(:first), topics.first + end + + def test_find_all_by_array_attribute + assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic of the day"]).size + end + + def test_find_all_by_boolean_attribute + topics = Topic.find_all_by_approved(false) + assert_equal 1, topics.size + assert topics.include?(topics(:first)) + + topics = Topic.find_all_by_approved(true) + assert_equal 3, topics.size + assert topics.include?(topics(:second)) + end + + def test_find_all_by_nil_and_not_nil_attributes + topics = Topic.find_all_by_last_read_and_author_name nil, "Mary" + assert_equal 1, topics.size + assert_equal "Mary", topics[0].author_name + end + + def test_find_or_create_from_one_attribute + number_of_companies = Company.count + sig38 = Company.find_or_create_by_name("38signals") + assert_equal number_of_companies + 1, Company.count + assert_equal sig38, Company.find_or_create_by_name("38signals") + assert sig38.persisted? + end + + def test_find_or_create_from_two_attributes + number_of_topics = Topic.count + another = Topic.find_or_create_by_title_and_author_name("Another topic","John") + assert_equal number_of_topics + 1, Topic.count + assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John") + assert another.persisted? + end + + def test_find_or_create_from_one_attribute_bang + number_of_companies = Company.count + assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name!("") } + assert_equal number_of_companies, Company.count + sig38 = Company.find_or_create_by_name!("38signals") + assert_equal number_of_companies + 1, Company.count + assert_equal sig38, Company.find_or_create_by_name!("38signals") + assert sig38.persisted? + end + + def test_find_or_create_from_two_attributes_bang + number_of_companies = Company.count + assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name_and_firm_id!("", 17) } + assert_equal number_of_companies, Company.count + sig38 = Company.find_or_create_by_name_and_firm_id!("38signals", 17) + assert_equal number_of_companies + 1, Company.count + assert_equal sig38, Company.find_or_create_by_name_and_firm_id!("38signals", 17) + assert sig38.persisted? + assert_equal "38signals", sig38.name + assert_equal 17, sig38.firm_id + end + + def test_find_or_create_from_two_attributes_with_one_being_an_aggregate + number_of_customers = Customer.count + created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth") + assert_equal number_of_customers + 1, Customer.count + assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth") + assert created_customer.persisted? + end + + def test_find_or_create_from_one_attribute_and_hash + number_of_companies = Company.count + sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23}) + assert_equal number_of_companies + 1, Company.count + assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23}) + assert sig38.persisted? + assert_equal "38signals", sig38.name + assert_equal 17, sig38.firm_id + assert_equal 23, sig38.client_of + end + + def test_find_or_create_from_two_attributes_and_hash + number_of_companies = Company.count + sig38 = Company.find_or_create_by_name_and_firm_id({:name => "38signals", :firm_id => 17, :client_of => 23}) + assert_equal number_of_companies + 1, Company.count + assert_equal sig38, Company.find_or_create_by_name_and_firm_id({:name => "38signals", :firm_id => 17, :client_of => 23}) + assert sig38.persisted? + assert_equal "38signals", sig38.name + assert_equal 17, sig38.firm_id + assert_equal 23, sig38.client_of + end + + def test_find_or_create_from_one_aggregate_attribute + number_of_customers = Customer.count + created_customer = Customer.find_or_create_by_balance(Money.new(123)) + assert_equal number_of_customers + 1, Customer.count + assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123)) + assert created_customer.persisted? + end + + def test_find_or_create_from_one_aggregate_attribute_and_hash + number_of_customers = Customer.count + balance = Money.new(123) + name = "Elizabeth" + created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name}) + assert_equal number_of_customers + 1, Customer.count + assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name}) + assert created_customer.persisted? + assert_equal balance, created_customer.balance + assert_equal name, created_customer.name + end + + def test_find_or_initialize_from_one_attribute + sig38 = Company.find_or_initialize_by_name("38signals") + assert_equal "38signals", sig38.name + assert !sig38.persisted? + end + + def test_find_or_initialize_from_one_aggregate_attribute + new_customer = Customer.find_or_initialize_by_balance(Money.new(123)) + assert_equal 123, new_customer.balance.amount + assert !new_customer.persisted? + end + + def test_find_or_initialize_from_one_attribute_should_not_set_attribute_even_when_protected + c = Company.find_or_initialize_by_name({:name => "Fortune 1000", :rating => 1000}) + assert_equal "Fortune 1000", c.name + assert_not_equal 1000, c.rating + assert c.valid? + assert !c.persisted? + end + + def test_find_or_create_from_one_attribute_should_not_set_attribute_even_when_protected + c = Company.find_or_create_by_name({:name => "Fortune 1000", :rating => 1000}) + assert_equal "Fortune 1000", c.name + assert_not_equal 1000, c.rating + assert c.valid? + assert c.persisted? + end + + def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected + c = Company.find_or_initialize_by_name_and_rating("Fortune 1000", 1000) + assert_equal "Fortune 1000", c.name + assert_equal 1000, c.rating + assert c.valid? + assert !c.persisted? + end + + def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected + c = Company.find_or_create_by_name_and_rating("Fortune 1000", 1000) + assert_equal "Fortune 1000", c.name + assert_equal 1000, c.rating + assert c.valid? + assert c.persisted? + end + + def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash + c = Company.find_or_initialize_by_rating(1000, {:name => "Fortune 1000"}) + assert_equal "Fortune 1000", c.name + assert_equal 1000, c.rating + assert c.valid? + assert !c.persisted? + end + + def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash + c = Company.find_or_create_by_rating(1000, {:name => "Fortune 1000"}) + assert_equal "Fortune 1000", c.name + assert_equal 1000, c.rating + assert c.valid? + assert c.persisted? + end + + def test_find_or_initialize_should_set_protected_attributes_if_given_as_block + c = Company.find_or_initialize_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 } + assert_equal "Fortune 1000", c.name + assert_equal 1000.to_f, c.rating.to_f + assert c.valid? + assert !c.persisted? + end + + def test_find_or_create_should_set_protected_attributes_if_given_as_block + c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 } + assert_equal "Fortune 1000", c.name + assert_equal 1000.to_f, c.rating.to_f + assert c.valid? + assert c.persisted? + end + + def test_find_or_create_should_work_with_block_on_first_call + class << Company + undef_method(:find_or_create_by_name) if method_defined?(:find_or_create_by_name) + end + c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 } + assert_equal "Fortune 1000", c.name + assert_equal 1000.to_f, c.rating.to_f + assert c.valid? + assert c.persisted? + end + + def test_find_or_initialize_from_two_attributes + another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John") + assert_equal "Another topic", another.title + assert_equal "John", another.author_name + assert !another.persisted? + end + + def test_find_or_initialize_from_two_attributes_but_passing_only_one + assert_raise(ArgumentError) { Topic.find_or_initialize_by_title_and_author_name("Another topic") } + end + + def test_find_or_initialize_from_one_aggregate_attribute_and_one_not + new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth") + assert_equal 123, new_customer.balance.amount + assert_equal "Elizabeth", new_customer.name + assert !new_customer.persisted? + end + + def test_find_or_initialize_from_one_attribute_and_hash + sig38 = Company.find_or_initialize_by_name({:name => "38signals", :firm_id => 17, :client_of => 23}) + assert_equal "38signals", sig38.name + assert_equal 17, sig38.firm_id + assert_equal 23, sig38.client_of + assert !sig38.persisted? + end + + def test_find_or_initialize_from_one_aggregate_attribute_and_hash + balance = Money.new(123) + name = "Elizabeth" + new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name}) + assert_equal balance, new_customer.balance + assert_equal name, new_customer.name + assert !new_customer.persisted? + end + + def test_find_last_by_one_attribute + assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title) + assert_nil Topic.find_last_by_title("A title with no matches") + end + + def test_find_last_by_invalid_method_syntax + assert_raise(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") } + assert_raise(NoMethodError) { Topic.find_last_by_title?("The First Topic") } + end + + def test_find_last_by_one_attribute_with_several_options + assert_equal accounts(:signals37), Account.order('id DESC').where('id != ?', 3).find_last_by_credit_limit(50) + end + + def test_find_last_by_one_missing_attribute + assert_raise(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") } + end + + def test_find_last_by_two_attributes + topic = Topic.last + assert_equal topic, Topic.find_last_by_title_and_author_name(topic.title, topic.author_name) + assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous") + end + + def test_find_last_with_limit_gives_same_result_when_loaded_and_unloaded + scope = Topic.limit(2) + unloaded_last = scope.last + loaded_last = scope.all.last + assert_equal loaded_last, unloaded_last + end + + def test_find_last_with_limit_and_offset_gives_same_result_when_loaded_and_unloaded + scope = Topic.offset(2).limit(2) + unloaded_last = scope.last + loaded_last = scope.all.last + assert_equal loaded_last, unloaded_last + end + + def test_find_last_with_offset_gives_same_result_when_loaded_and_unloaded + scope = Topic.offset(3) + unloaded_last = scope.last + loaded_last = scope.all.last + assert_equal loaded_last, unloaded_last + end + + def test_find_all_by_nil_attribute + topics = Topic.find_all_by_last_read nil + assert_equal 3, topics.size + assert topics.collect(&:last_read).all?(&:nil?) + end + + def test_forwarding_to_dynamic_finders + welcome = Post.find(1) + assert_equal 4, Category.find_all_by_type('SpecialCategory').size + assert_equal 0, welcome.categories.find_all_by_type('SpecialCategory').size + assert_equal 2, welcome.categories.find_all_by_type('Category').size + end + + def test_dynamic_find_all_should_respect_association_order + assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.scoped(:where => "type = 'Client'").all + assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.find_all_by_type('Client') + end + + def test_dynamic_find_all_should_respect_association_limit + assert_equal 1, companies(:first_firm).limited_clients.scoped(:where => "type = 'Client'").all.length + assert_equal 1, companies(:first_firm).limited_clients.find_all_by_type('Client').length + end + + def test_dynamic_find_all_limit_should_override_association_limit + assert_equal 2, companies(:first_firm).limited_clients.scoped(:where => "type = 'Client'", :limit => 9_000).all.length + assert_equal 2, companies(:first_firm).limited_clients.find_all_by_type('Client', :limit => 9_000).length + end + + def test_dynamic_find_last_without_specified_order + assert_equal companies(:second_client), companies(:first_firm).unsorted_clients.find_last_by_type('Client') + end + + def test_dynamic_find_or_create_from_two_attributes_using_an_association + author = authors(:david) + number_of_posts = Post.count + another = author.posts.find_or_create_by_title_and_body("Another Post", "This is the Body") + assert_equal number_of_posts + 1, Post.count + assert_equal another, author.posts.find_or_create_by_title_and_body("Another Post", "This is the Body") + assert another.persisted? + end + + def test_dynamic_find_all_should_respect_association_order_for_through + assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.scoped(:where => "comments.type = 'SpecialComment'").all + assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.find_all_by_type('SpecialComment') + end + + def test_dynamic_find_all_should_respect_association_limit_for_through + assert_equal 1, authors(:david).limited_comments.scoped(:where => "comments.type = 'SpecialComment'").all.length + assert_equal 1, authors(:david).limited_comments.find_all_by_type('SpecialComment').length + end + + def test_dynamic_find_all_order_should_override_association_limit_for_through + assert_equal 4, authors(:david).limited_comments.scoped(:where => "comments.type = 'SpecialComment'", :limit => 9_000).all.length + assert_equal 4, authors(:david).limited_comments.find_all_by_type('SpecialComment', :limit => 9_000).length + end + + def test_find_all_include_over_the_same_table_for_through + assert_equal 2, people(:michael).posts.scoped(:includes => :people).all.length + end + + def test_find_or_create_by_resets_cached_counters + person = Person.create! :first_name => 'tenderlove' + post = Post.first + + assert_equal [], person.readers + assert_nil person.readers.find_by_post_id(post.id) + + person.readers.find_or_create_by_post_id(post.id) + + assert_equal 1, person.readers.count + assert_equal 1, person.readers.length + assert_equal post, person.readers.first.post + assert_equal person, person.readers.first.person + end + + def test_find_or_initialize + the_client = companies(:first_firm).clients.find_or_initialize_by_name("Yet another client") + assert_equal companies(:first_firm).id, the_client.firm_id + assert_equal "Yet another client", the_client.name + assert !the_client.persisted? + end + + def test_find_or_create_updates_size + number_of_clients = companies(:first_firm).clients.size + the_client = companies(:first_firm).clients.find_or_create_by_name("Yet another client") + assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size + assert_equal the_client, companies(:first_firm).clients.find_or_create_by_name("Yet another client") + assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size + end + + def test_find_or_initialize_updates_collection_size + number_of_clients = companies(:first_firm).clients_of_firm.size + companies(:first_firm).clients_of_firm.find_or_initialize_by_name("name" => "Another Client") + assert_equal number_of_clients + 1, companies(:first_firm).clients_of_firm.size + end + + def test_find_or_initialize_returns_the_instantiated_object + client = companies(:first_firm).clients_of_firm.find_or_initialize_by_name("name" => "Another Client") + assert_equal client, companies(:first_firm).clients_of_firm[-1] + end + + def test_find_or_initialize_only_instantiates_a_single_object + number_of_clients = Client.count + companies(:first_firm).clients_of_firm.find_or_initialize_by_name("name" => "Another Client").save! + companies(:first_firm).save! + assert_equal number_of_clients+1, Client.count + end + + def test_find_or_create_with_hash + post = authors(:david).posts.find_or_create_by_title(:title => 'Yet another post', :body => 'somebody') + assert_equal post, authors(:david).posts.find_or_create_by_title(:title => 'Yet another post', :body => 'somebody') + assert post.persisted? + end + + def test_find_or_create_with_one_attribute_followed_by_hash + post = authors(:david).posts.find_or_create_by_title('Yet another post', :body => 'somebody') + assert_equal post, authors(:david).posts.find_or_create_by_title('Yet another post', :body => 'somebody') + assert post.persisted? + end + + def test_find_or_create_should_work_with_block + post = authors(:david).posts.find_or_create_by_title('Yet another post') {|p| p.body = 'somebody'} + assert_equal post, authors(:david).posts.find_or_create_by_title('Yet another post') {|p| p.body = 'somebody'} + assert post.persisted? + end + + def test_forwarding_to_dynamic_finders_2 + welcome = Post.find(1) + assert_equal 4, Comment.find_all_by_type('Comment').size + assert_equal 2, welcome.comments.find_all_by_type('Comment').size + end + + def test_dynamic_find_all_by_attributes + authors = Author.scoped + + davids = authors.find_all_by_name('David') + assert_kind_of Array, davids + assert_equal [authors(:david)], davids + end + + def test_dynamic_find_or_initialize_by_attributes + authors = Author.scoped + + lifo = authors.find_or_initialize_by_name('Lifo') + assert_equal "Lifo", lifo.name + assert !lifo.persisted? + + assert_equal authors(:david), authors.find_or_initialize_by_name(:name => 'David') + end + + def test_dynamic_find_or_create_by_attributes + authors = Author.scoped + + lifo = authors.find_or_create_by_name('Lifo') + assert_equal "Lifo", lifo.name + assert lifo.persisted? + + assert_equal authors(:david), authors.find_or_create_by_name(:name => 'David') + end + + def test_dynamic_find_or_create_by_attributes_bang + authors = Author.scoped + + assert_raises(ActiveRecord::RecordInvalid) { authors.find_or_create_by_name!('') } + + lifo = authors.find_or_create_by_name!('Lifo') + assert_equal "Lifo", lifo.name + assert lifo.persisted? + + assert_equal authors(:david), authors.find_or_create_by_name!(:name => 'David') + end + + def test_finder_block + t = Topic.first + found = nil + Topic.find_by_id(t.id) { |f| found = f } + assert_equal t, found + end + + def test_finder_block_nothing_found + bad_id = Topic.maximum(:id) + 1 + assert_nil Topic.find_by_id(bad_id) { |f| raise } + end + + def test_find_returns_block_value + t = Topic.first + x = Topic.find_by_id(t.id) { |f| "hi mom!" } + assert_equal "hi mom!", x + end + + def test_dynamic_finder_with_invalid_params + assert_raise(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" } + end + + def test_find_by_one_attribute_with_order_option + assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id') + assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC') + end + + def test_dynamic_find_by_attributes_should_yield_found_object + david = authors(:david) + yielded_value = nil + Author.find_by_name(david.name) do |author| + yielded_value = author + end + assert_equal david, yielded_value + end +end + +class DynamicScopeTest < ActiveRecord::TestCase + fixtures :posts + + def setup + @test_klass = Class.new(Post) do + def self.name; "Post"; end + end + @deprecation_behavior = ActiveSupport::Deprecation.behavior + ActiveSupport::Deprecation.behavior = :silence + end + + def teardown + ActiveSupport::Deprecation.behavior = @deprecation_behavior + end + + def test_dynamic_scope + assert_equal @test_klass.scoped_by_author_id(1).find(1), @test_klass.find(1) + assert_equal @test_klass.scoped_by_author_id_and_title(1, "Welcome to the weblog").first, @test_klass.scoped(:where => { :author_id => 1, :title => "Welcome to the weblog"}).first + end + + def test_dynamic_scope_should_create_methods_after_hitting_method_missing + assert_blank @test_klass.methods.grep(/scoped_by_type/) + @test_klass.scoped_by_type(nil) + assert_present @test_klass.methods.grep(/scoped_by_type/) + end + + def test_dynamic_scope_with_less_number_of_arguments + assert_raise(ArgumentError){ @test_klass.scoped_by_author_id_and_title(1) } + end +end + +class DynamicScopeMatchTest < ActiveRecord::TestCase + def test_scoped_by_no_match + assert_nil ActiveRecord::DynamicMatchers::Method.match(nil, "not_scoped_at_all") + end + + def test_scoped_by + match = ActiveRecord::DynamicMatchers::Method.match(nil, "scoped_by_age_and_sex_and_location") + assert_not_nil match + assert_equal %w(age sex location), match.attribute_names + end +end |