diff options
author | Ryan Bigg <radarlistener@gmail.com> | 2009-04-04 16:13:18 +1000 |
---|---|---|
committer | Ryan Bigg <radarlistener@gmail.com> | 2009-04-04 16:13:18 +1000 |
commit | e878c3e44a8dba19c1188b636e25ec1bc2165116 (patch) | |
tree | 3d06b83492653b6b73422cbf37014fc5c89e9685 /activerecord/test | |
parent | ab55ddcc4c5cf31bcaf7720b52dc55d6d54cb150 (diff) | |
parent | 9e9469e83f6144310115124cdecc5cb65db5128e (diff) | |
download | rails-e878c3e44a8dba19c1188b636e25ec1bc2165116.tar.gz rails-e878c3e44a8dba19c1188b636e25ec1bc2165116.tar.bz2 rails-e878c3e44a8dba19c1188b636e25ec1bc2165116.zip |
Merge branch 'master' of git@github.com:lifo/docrails
* 'master' of git@github.com:lifo/docrails: (319 commits)
deletes screencast promo in prologue, its proper place is the References section
Typo fix
list -> index
in caching guide, RESTifies some examples, revised conventions here and there
Tech edit of caching guide from Gregg Pollack
Fix typo in comment: hide_actions -> hide_action
Fix two typos in a comment in config/initializers/backtrace_silencers.rb
With -> with in a title
Clear up a little confusing wording in Routing Guide.
copyedited minor details in the rack on rails guide
remove piece of UrlWriter documentation claiming that you can access named routes as its class methods
Add note about change to session options
TRUNCATE is also a MySQL DDL statement, so document this is a possible caveat when using transactions and savepoints.
Improve documentation for ActiveResource::Validations, fix typos
Fix typos in ActiveResource::Base documentation, use present tense, reword confusing sentences
Update ActiveResource::Connection documentation to use present tense
Fix typos in Active Resource README
Fix a small typo
ensure authors get warnings about broken links, and ensure end users don't
in guides generator, warn about duplicate header IDs only if WARN_DUPLICATE_HEADERS
...
Diffstat (limited to 'activerecord/test')
38 files changed, 1213 insertions, 526 deletions
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 40a8503980..13a78a1890 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -154,6 +154,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal 0, Topic.find(t2.id).replies.size end + def test_belongs_to_reassign_with_namespaced_models_and_counters + t1 = Web::Topic.create("title" => "t1") + t2 = Web::Topic.create("title" => "t2") + r1 = Web::Reply.new("title" => "r1", "content" => "r1") + r1.topic = t1 + + assert r1.save + assert_equal 1, Web::Topic.find(t1.id).replies.size + assert_equal 0, Web::Topic.find(t2.id).replies.size + + r1.topic = Web::Topic.find(t2.id) + + assert r1.save + assert_equal 0, Web::Topic.find(t1.id).replies.size + assert_equal 1, Web::Topic.find(t2.id).replies.size + end + def test_belongs_to_counter_after_save topic = Topic.create!(:title => "monday night") topic.replies.create!(:title => "re: monday night", :content => "football") @@ -190,19 +207,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") end - def test_assignment_before_parent_saved - client = Client.find(:first) - apple = Firm.new("name" => "Apple") - client.firm = apple - assert_equal apple, client.firm - assert apple.new_record? - assert client.save - assert apple.save - assert !apple.new_record? - assert_equal apple, client.firm - assert_equal apple, client.firm(true) - end - def test_assignment_before_child_saved final_cut = Client.new("name" => "Final Cut") firm = Firm.find(1) @@ -215,19 +219,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal firm, final_cut.firm(true) end - def test_assignment_before_either_saved - final_cut = Client.new("name" => "Final Cut") - apple = Firm.new("name" => "Apple") - final_cut.firm = apple - assert final_cut.new_record? - assert apple.new_record? - assert final_cut.save - assert !final_cut.new_record? - assert !apple.new_record? - assert_equal apple, final_cut.firm - assert_equal apple, final_cut.firm(true) - end - def test_new_record_with_foreign_key_but_no_object c = Client.new("firm_id" => 1) assert_equal Firm.find(:first), c.firm_with_basic_id @@ -274,90 +265,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal 17, reply.replies.size end - def test_store_two_association_with_one_save - num_orders = Order.count - num_customers = Customer.count - order = Order.new - - customer1 = order.billing = Customer.new - customer2 = order.shipping = Customer.new - assert order.save - assert_equal customer1, order.billing - assert_equal customer2, order.shipping - - order.reload - - assert_equal customer1, order.billing - assert_equal customer2, order.shipping - - assert_equal num_orders +1, Order.count - assert_equal num_customers +2, Customer.count - end - - - def test_store_association_in_two_relations_with_one_save - num_orders = Order.count - num_customers = Customer.count - order = Order.new - - customer = order.billing = order.shipping = Customer.new - assert order.save - assert_equal customer, order.billing - assert_equal customer, order.shipping - - order.reload - - assert_equal customer, order.billing - assert_equal customer, order.shipping - - assert_equal num_orders +1, Order.count - assert_equal num_customers +1, Customer.count - end - - def test_store_association_in_two_relations_with_one_save_in_existing_object - num_orders = Order.count - num_customers = Customer.count - order = Order.create - - customer = order.billing = order.shipping = Customer.new - assert order.save - assert_equal customer, order.billing - assert_equal customer, order.shipping - - order.reload - - assert_equal customer, order.billing - assert_equal customer, order.shipping - - assert_equal num_orders +1, Order.count - assert_equal num_customers +1, Customer.count - end - - def test_store_association_in_two_relations_with_one_save_in_existing_object_with_values - num_orders = Order.count - num_customers = Customer.count - order = Order.create - - customer = order.billing = order.shipping = Customer.new - assert order.save - assert_equal customer, order.billing - assert_equal customer, order.shipping - - order.reload - - customer = order.billing = order.shipping = Customer.new - - assert order.save - order.reload - - assert_equal customer, order.billing - assert_equal customer, order.shipping - - assert_equal num_orders +1, Order.count - assert_equal num_customers +2, Customer.count - end - - def test_association_assignment_sticks post = Post.find(:first) @@ -410,32 +317,29 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal nil, sponsor.sponsorable_id end - def test_save_fails_for_invalid_belongs_to - assert log = AuditLog.create(:developer_id=>0,:message=>"") - - log.developer = Developer.new - assert !log.developer.valid? - assert !log.valid? - assert !log.save - assert_equal "is invalid", log.errors.on("developer") - end - - def test_save_succeeds_for_invalid_belongs_to_with_validate_false - assert log = AuditLog.create(:developer_id=>0,:message=>"") - - log.unvalidated_developer = Developer.new - assert !log.unvalidated_developer.valid? - assert log.valid? - assert log.save - end - def test_belongs_to_proxy_should_not_respond_to_private_methods - assert_raises(NoMethodError) { companies(:first_firm).private_method } - assert_raises(NoMethodError) { companies(:second_client).firm.private_method } + assert_raise(NoMethodError) { companies(:first_firm).private_method } + assert_raise(NoMethodError) { companies(:second_client).firm.private_method } end def test_belongs_to_proxy_should_respond_to_private_methods_via_send companies(:first_firm).send(:private_method) companies(:second_client).firm.send(:private_method) end + + def test_save_of_record_with_loaded_belongs_to + @account = companies(:first_firm).account + + assert_nothing_raised do + Account.find(@account.id).save! + Account.find(@account.id, :include => :firm).save! + end + + @account.firm.delete + + assert_nothing_raised do + Account.find(@account.id).save! + Account.find(@account.id, :include => :firm).save! + end + end end diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb index 12dec5ccd1..1b2e0fc11e 100644 --- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb +++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb @@ -1,4 +1,9 @@ require 'cases/helper' +require 'models/author' +require 'models/post' +require 'models/comment' +require 'models/category' +require 'models/categorization' module Remembered def self.included(base) @@ -99,3 +104,27 @@ class EagerLoadPolyAssocsTest < ActiveRecord::TestCase end end end + +class EagerLoadNestedIncludeWithMissingDataTest < ActiveRecord::TestCase + def setup + @davey_mcdave = Author.create(:name => 'Davey McDave') + @first_post = @davey_mcdave.posts.create(:title => 'Davey Speaks', :body => 'Expressive wordage') + @first_comment = @first_post.comments.create(:body => 'Inflamatory doublespeak') + @first_categorization = @davey_mcdave.categorizations.create(:category => Category.first, :post => @first_post) + end + + def teardown + @davey_mcdave.destroy + @first_post.destroy + @first_comment.destroy + @first_categorization.destroy + end + + def test_missing_data_in_a_nested_include_should_not_cause_errors_when_constructing_objects + assert_nothing_raised do + # @davey_mcdave doesn't have any author_favorites + includes = {:posts => :comments, :categorizations => :category, :author_favorites => :favorite_author } + Author.all :include => includes, :conditions => {:authors => {:name => @davey_mcdave.name}}, :order => 'categories.name' + end + end +end
\ No newline at end of file diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 14099d4176..40723814c5 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -549,16 +549,16 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_invalid_association_reference - assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { + assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { post = Post.find(6, :include=> :monkeys ) } - assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { + assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { post = Post.find(6, :include=>[ :monkeys ]) } - assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { + assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { post = Post.find(6, :include=>[ 'monkeys' ]) } - assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") { + assert_raise(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") { post = Post.find(6, :include=>[ :monkeys, :elephants ]) } end diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 0f43d97f4a..5e8b2cadfc 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -381,6 +381,33 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_date_from_db Date.new(2004, 10, 10), Developer.find(1).projects.first.joined_on.to_date end + def test_destroying + david = Developer.find(1) + active_record = Project.find(1) + david.projects.reload + assert_equal 2, david.projects.size + assert_equal 3, active_record.developers.size + + assert_difference "Project.count", -1 do + david.projects.destroy(active_record) + end + + assert_equal 1, david.reload.projects.size + assert_equal 1, david.projects(true).size + end + + def test_destroying_array + david = Developer.find(1) + david.projects.reload + + assert_difference "Project.count", -Project.count do + david.projects.destroy(Project.find(:all)) + end + + assert_equal 0, david.reload.projects.size + assert_equal 0, david.projects(true).size + end + def test_destroy_all david = Developer.find(1) david.projects.reload @@ -616,7 +643,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_updating_attributes_on_rich_associations david = projects(:action_controller).developers.first david.name = "DHH" - assert_raises(ActiveRecord::ReadOnlyRecord) { david.save! } + assert_raise(ActiveRecord::ReadOnlyRecord) { david.save! } end def test_updating_attributes_on_rich_associations_with_limited_find_from_reflection @@ -740,6 +767,14 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal developer, project.developers.find(:first) assert_equal project, developer.projects.find(:first) end + + def test_self_referential_habtm_without_foreign_key_set_should_raise_exception + assert_raise(ActiveRecord::HasAndBelongsToManyAssociationForeignKeyNeeded) { + Member.class_eval do + has_and_belongs_to_many :friends, :class_name => "Member", :join_table => "member_friends" + end + } + end def test_dynamic_find_should_respect_association_include # SQL error in sort clause if :include is not included diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index a2525f1d70..30edf79a26 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -70,6 +70,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, companies(:first_firm).limited_clients.find(:all, :limit => nil).size 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_should_respect_association_order assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.find(:first, :conditions => "type = 'Client'") assert_equal companies(:second_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client') @@ -176,7 +180,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_find_ids firm = Firm.find(:first) - assert_raises(ActiveRecord::RecordNotFound) { firm.clients.find } + assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find } client = firm.clients.find(2) assert_kind_of Client, client @@ -190,7 +194,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, client_ary.size assert_equal client, client_ary.first - assert_raises(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) } + assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) } end def test_find_string_ids_when_using_finder_sql @@ -215,6 +219,45 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 1, firm.clients.find(:all, :conditions => "name = 'Summit'").length end + def test_find_each + firm = companies(:first_firm) + + assert ! firm.clients.loaded? + + assert_queries(3) do + firm.clients.find_each(:batch_size => 1) {|c| assert_equal firm.id, c.firm_id } + end + + assert ! firm.clients.loaded? + end + + def test_find_each_with_conditions + firm = companies(:first_firm) + + assert_queries(2) do + firm.clients.find_each(:batch_size => 1, :conditions => {:name => "Microsoft"}) do |c| + assert_equal firm.id, c.firm_id + assert_equal "Microsoft", c.name + end + end + + assert ! firm.clients.loaded? + end + + def test_find_in_batches + firm = companies(:first_firm) + + assert ! firm.clients.loaded? + + assert_queries(2) do + firm.clients.find_in_batches(:batch_size => 2) do |clients| + clients.each {|c| assert_equal firm.id, c.firm_id } + end + end + + assert ! firm.clients.loaded? + end + def test_find_all_sanitized firm = Firm.find(:first) summit = firm.clients.find(:all, :conditions => "name = 'Summit'") @@ -238,7 +281,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_find_in_collection assert_equal Client.find(2).name, companies(:first_firm).clients.find(2).name - assert_raises(ActiveRecord::RecordNotFound) { companies(:first_firm).clients.find(6) } + assert_raise(ActiveRecord::RecordNotFound) { companies(:first_firm).clients.find(6) } end def test_find_grouped @@ -278,36 +321,36 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_create_with_bang_on_has_many_when_parent_is_new_raises - assert_raises(ActiveRecord::RecordNotSaved) do + assert_raise(ActiveRecord::RecordNotSaved) do firm = Firm.new firm.plain_clients.create! :name=>"Whoever" end end def test_regular_create_on_has_many_when_parent_is_new_raises - assert_raises(ActiveRecord::RecordNotSaved) do + assert_raise(ActiveRecord::RecordNotSaved) do firm = Firm.new firm.plain_clients.create :name=>"Whoever" end end def test_create_with_bang_on_has_many_raises_when_record_not_saved - assert_raises(ActiveRecord::RecordInvalid) do + assert_raise(ActiveRecord::RecordInvalid) do firm = Firm.find(:first) firm.plain_clients.create! end end def test_create_with_bang_on_habtm_when_parent_is_new_raises - assert_raises(ActiveRecord::RecordNotSaved) do + assert_raise(ActiveRecord::RecordNotSaved) do Developer.new("name" => "Aredridel").projects.create! end end def test_adding_a_mismatch_class - assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil } - assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 } - assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << Topic.find(1) } + assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil } + assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 } + assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << Topic.find(1) } end def test_adding_a_collection @@ -317,81 +360,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 3, companies(:first_firm).clients_of_firm(true).size end - def test_adding_before_save - no_of_firms = Firm.count - no_of_clients = Client.count - - new_firm = Firm.new("name" => "A New Firm, Inc") - c = Client.new("name" => "Apple") - - new_firm.clients_of_firm.push Client.new("name" => "Natural Company") - assert_equal 1, new_firm.clients_of_firm.size - new_firm.clients_of_firm << c - assert_equal 2, new_firm.clients_of_firm.size - - assert_equal no_of_firms, Firm.count # Firm was not saved to database. - assert_equal no_of_clients, Client.count # Clients were not saved to database. - assert new_firm.save - assert !new_firm.new_record? - assert !c.new_record? - assert_equal new_firm, c.firm - assert_equal no_of_firms+1, Firm.count # Firm was saved to database. - assert_equal no_of_clients+2, Client.count # Clients were saved to database. - - assert_equal 2, new_firm.clients_of_firm.size - assert_equal 2, new_firm.clients_of_firm(true).size - end - - def test_invalid_adding - firm = Firm.find(1) - assert !(firm.clients_of_firm << c = Client.new) - assert c.new_record? - assert !firm.valid? - assert !firm.save - assert c.new_record? - end - - def test_invalid_adding_before_save - no_of_firms = Firm.count - no_of_clients = Client.count - new_firm = Firm.new("name" => "A New Firm, Inc") - new_firm.clients_of_firm.concat([c = Client.new, Client.new("name" => "Apple")]) - assert c.new_record? - assert !c.valid? - assert !new_firm.valid? - assert !new_firm.save - assert c.new_record? - assert new_firm.new_record? - end - - def test_invalid_adding_with_validate_false - firm = Firm.find(:first) - client = Client.new - firm.unvalidated_clients_of_firm << client - - assert firm.valid? - assert !client.valid? - assert firm.save - assert client.new_record? - end - - def test_valid_adding_with_validate_false - no_of_clients = Client.count - - firm = Firm.find(:first) - client = Client.new("name" => "Apple") - - assert firm.valid? - assert client.valid? - assert client.new_record? - - firm.unvalidated_clients_of_firm << client - - assert firm.save - assert !client.new_record? - assert_equal no_of_clients+1, Client.count - end - def test_build company = companies(:first_firm) new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") } @@ -400,10 +368,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal "Another Client", new_client.name assert new_client.new_record? assert_equal new_client, company.clients_of_firm.last - company.name += '-changed' - assert_queries(2) { assert company.save } - assert !new_client.new_record? - assert_equal 2, company.clients_of_firm(true).size end def test_collection_size_after_building @@ -428,11 +392,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_many company = companies(:first_firm) new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } - assert_equal 2, new_clients.size - company.name += '-changed' - assert_queries(3) { assert company.save } - assert_equal 3, company.clients_of_firm(true).size end def test_build_followed_by_save_does_not_load_target @@ -463,10 +423,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal "Another Client", new_client.name assert new_client.new_record? assert_equal new_client, company.clients_of_firm.last - company.name += '-changed' - assert_queries(2) { assert company.save } - assert !new_client.new_record? - assert_equal 2, company.clients_of_firm(true).size end def test_build_many_via_block @@ -480,10 +436,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, new_clients.size assert_equal "changed", new_clients.first.name assert_equal "changed", new_clients.last.name - - company.name += '-changed' - assert_queries(3) { assert company.save } - assert_equal 3, company.clients_of_firm(true).size end def test_create_without_loading_association @@ -501,16 +453,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, first_firm.clients_of_firm.size end - def test_invalid_build - new_client = companies(:first_firm).clients_of_firm.build - assert new_client.new_record? - assert !new_client.valid? - assert_equal new_client, companies(:first_firm).clients_of_firm.last - assert !companies(:first_firm).save - assert new_client.new_record? - assert_equal 1, companies(:first_firm).clients_of_firm(true).size - end - def test_create force_signal37_to_load_all_clients_of_firm new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client") @@ -703,7 +645,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_invalid_belongs_to_dependent_option_raises_exception - assert_raises ArgumentError do + assert_raise ArgumentError do Author.belongs_to :special_author_address, :dependent => :nullify end end @@ -729,13 +671,37 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_deleting_type_mismatch david = Developer.find(1) david.projects.reload - assert_raises(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(1) } + assert_raise(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(1) } end def test_deleting_self_type_mismatch david = Developer.find(1) david.projects.reload - assert_raises(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(Project.find(1).developers) } + assert_raise(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(Project.find(1).developers) } + end + + def test_destroying + force_signal37_to_load_all_clients_of_firm + + assert_difference "Client.count", -1 do + companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first) + end + + assert_equal 0, companies(:first_firm).reload.clients_of_firm.size + assert_equal 0, companies(:first_firm).clients_of_firm(true).size + end + + def test_destroying_a_collection + force_signal37_to_load_all_clients_of_firm + companies(:first_firm).clients_of_firm.create("name" => "Another Client") + assert_equal 2, companies(:first_firm).clients_of_firm.size + + assert_difference "Client.count", -2 do + companies(:first_firm).clients_of_firm.destroy([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1]]) + end + + assert_equal 0, companies(:first_firm).reload.clients_of_firm.size + assert_equal 0, companies(:first_firm).clients_of_firm(true).size end def test_destroy_all @@ -843,15 +809,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !firm.clients.include?(:first_client) end - def test_replace_on_new_object - firm = Firm.new("name" => "New Firm") - firm.clients = [companies(:second_client), Client.new("name" => "New Client")] - assert firm.save - firm.reload - assert_equal 2, firm.clients.length - assert firm.clients.include?(Client.find_by_name("New Client")) - end - def test_get_ids assert_equal [companies(:first_client).id, companies(:second_client).id], companies(:first_firm).client_ids end @@ -879,15 +836,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert company.clients_using_sql.loaded? end - def test_assign_ids - firm = Firm.new("name" => "Apple") - firm.client_ids = [companies(:first_client).id, companies(:second_client).id] - firm.save - firm.reload - assert_equal 2, firm.clients.length - assert firm.clients.include?(companies(:second_client)) - end - def test_assign_ids_ignoring_blanks firm = Firm.create!(:name => 'Apple') firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, ''] @@ -910,16 +858,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasManyReflection, &block) } end - - def test_assign_ids_for_through_a_belongs_to - post = Post.new(:title => "Assigning IDs works!", :body => "You heared it here first, folks!") - post.person_ids = [people(:david).id, people(:michael).id] - post.save - post.reload - assert_equal 2, post.people.length - assert post.people.include?(people(:david)) - end - def test_dynamic_find_should_respect_association_order_for_through assert_equal Comment.find(10), authors(:david).comments_desc.find(:first, :conditions => "comments.type = 'SpecialComment'") assert_equal Comment.find(10), authors(:david).comments_desc.find_by_type('SpecialComment') diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 1e5d1a0202..97efca7891 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -1,14 +1,19 @@ require "cases/helper" require 'models/post' require 'models/person' +require 'models/reference' +require 'models/job' require 'models/reader' require 'models/comment' require 'models/tag' require 'models/tagging' require 'models/author' +require 'models/owner' +require 'models/pet' +require 'models/toy' class HasManyThroughAssociationsTest < ActiveRecord::TestCase - fixtures :posts, :readers, :people, :comments, :authors + fixtures :posts, :readers, :people, :comments, :authors, :owners, :pets, :toys def test_associate_existing assert_queries(2) { posts(:thinking);people(:david) } @@ -87,6 +92,24 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert posts(:welcome).reload.people(true).empty? end + def test_destroy_association + assert_difference "Person.count", -1 do + posts(:welcome).people.destroy(people(:michael)) + end + + assert posts(:welcome).reload.people.empty? + assert posts(:welcome).people(true).empty? + end + + def test_destroy_all + assert_difference "Person.count", -1 do + posts(:welcome).people.destroy_all + end + + assert posts(:welcome).reload.people.empty? + assert posts(:welcome).people(true).empty? + end + def test_replace_association assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)} @@ -249,4 +272,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase author.author_favorites.create(:favorite_author_id => 3) assert_equal post.author.author_favorites, post.author_favorites end + + def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys + assert_equal 1, owners(:blackbeard).toys.count + end end diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 14032a67c0..1ddb3f49bf 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -59,8 +59,8 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_type_mismatch - assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).account = 1 } - assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).account = Project.find(1) } + assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).account = 1 } + assert_raise(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).account = Project.find(1) } end def test_natural_assignment @@ -76,7 +76,25 @@ class HasOneAssociationsTest < ActiveRecord::TestCase companies(:first_firm).save assert_nil companies(:first_firm).account # account is dependent, therefore is destroyed when reference to owner is lost - assert_raises(ActiveRecord::RecordNotFound) { Account.find(old_account_id) } + assert_raise(ActiveRecord::RecordNotFound) { Account.find(old_account_id) } + end + + def test_nullification_on_association_change + firm = companies(:rails_core) + old_account_id = firm.account.id + firm.account = Account.new + # account is dependent with nullify, therefore its firm_id should be nil + assert_nil Account.find(old_account_id).firm_id + end + + def test_association_changecalls_delete + companies(:first_firm).deletable_account = Account.new + assert_equal [], Account.destroyed_account_ids[companies(:first_firm).id] + end + + def test_association_change_calls_destroy + companies(:first_firm).account = Account.new + assert_equal [companies(:first_firm).id], Account.destroyed_account_ids[companies(:first_firm).id] end def test_natural_assignment_to_already_associated_record @@ -193,28 +211,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal account, firm.account end - def test_build_before_child_saved - firm = Firm.find(1) - - account = firm.account.build("credit_limit" => 1000) - assert_equal account, firm.account - assert account.new_record? - assert firm.save - assert_equal account, firm.account - assert !account.new_record? - end - - def test_build_before_either_saved - firm = Firm.new("name" => "GlobalMegaCorp") - - firm.account = account = Account.new("credit_limit" => 1000) - assert_equal account, firm.account - assert account.new_record? - assert firm.save - assert_equal account, firm.account - assert !account.new_record? - end - def test_failing_build_association firm = Firm.new("name" => "GlobalMegaCorp") firm.save @@ -253,16 +249,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase firm.destroy end - def test_assignment_before_parent_saved - firm = Firm.new("name" => "GlobalMegaCorp") - firm.account = a = Account.find(1) - assert firm.new_record? - assert_equal a, firm.account - assert firm.save - assert_equal a, firm.account - assert_equal a, firm.account(true) - end - def test_finding_with_interpolated_condition firm = Firm.find(:first) superior = firm.clients.create(:name => 'SuperiorCo') @@ -279,61 +265,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal a, firm.account assert_equal a, firm.account(true) end - - def test_save_fails_for_invalid_has_one - firm = Firm.find(:first) - assert firm.valid? - - firm.account = Account.new - - assert !firm.account.valid? - assert !firm.valid? - assert !firm.save - assert_equal "is invalid", firm.errors.on("account") - end - - - def test_save_succeeds_for_invalid_has_one_with_validate_false - firm = Firm.find(:first) - assert firm.valid? - - firm.unvalidated_account = Account.new - - assert !firm.unvalidated_account.valid? - assert firm.valid? - assert firm.save - end - - def test_assignment_before_either_saved - firm = Firm.new("name" => "GlobalMegaCorp") - firm.account = a = Account.new("credit_limit" => 1000) - assert firm.new_record? - assert a.new_record? - assert_equal a, firm.account - assert firm.save - assert !firm.new_record? - assert !a.new_record? - assert_equal a, firm.account - assert_equal a, firm.account(true) - end - - def test_not_resaved_when_unchanged - firm = Firm.find(:first, :include => :account) - firm.name += '-changed' - assert_queries(1) { firm.save! } - - firm = Firm.find(:first) - firm.account = Account.find(:first) - assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! } - - firm = Firm.find(:first).clone - firm.account = Account.find(:first) - assert_queries(2) { firm.save! } - - firm = Firm.find(:first).clone - firm.account = Account.find(:first).clone - assert_queries(2) { firm.save! } - end def test_save_still_works_after_accessing_nil_has_one jp = Company.new :name => 'Jaded Pixel' @@ -350,8 +281,8 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_has_one_proxy_should_not_respond_to_private_methods - assert_raises(NoMethodError) { accounts(:signals37).private_method } - assert_raises(NoMethodError) { companies(:first_firm).account.private_method } + assert_raise(NoMethodError) { accounts(:signals37).private_method } + assert_raise(NoMethodError) { companies(:first_firm).account.private_method } end def test_has_one_proxy_should_respond_to_private_methods_via_send @@ -359,4 +290,20 @@ class HasOneAssociationsTest < ActiveRecord::TestCase companies(:first_firm).account.send(:private_method) end + def test_save_of_record_with_loaded_has_one + @firm = companies(:first_firm) + assert_not_nil @firm.account + + assert_nothing_raised do + Firm.find(@firm.id).save! + Firm.find(@firm.id, :include => :account).save! + end + + @firm.account.destroy + + assert_nothing_raised do + Firm.find(@firm.id).save! + Firm.find(@firm.id, :include => :account).save! + end + end end diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb index f65d76e2ce..12c598751b 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -115,8 +115,8 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_has_one_through_proxy_should_not_respond_to_private_methods - assert_raises(NoMethodError) { clubs(:moustache_club).private_method } - assert_raises(NoMethodError) { @member.club.private_method } + assert_raise(NoMethodError) { clubs(:moustache_club).private_method } + assert_raise(NoMethodError) { @member.club.private_method } end def test_has_one_through_proxy_should_respond_to_private_methods_via_send @@ -173,4 +173,20 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase assert_not_nil assert_no_queries { @new_detail.member_type } end + def test_save_of_record_with_loaded_has_one_through + @club = @member.club + assert_not_nil @club.sponsored_member + + assert_nothing_raised do + Club.find(@club.id).save! + Club.find(@club.id, :include => :sponsored_member).save! + end + + @club.sponsor.destroy + + assert_nothing_raised do + Club.find(@club.id).save! + Club.find(@club.id, :include => :sponsored_member).save! + end + end end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 759f9f3872..17ed302465 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -100,7 +100,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase %w(save create_or_update).each do |method| klass = Class.new ActiveRecord::Base klass.class_eval "def #{method}() 'defined #{method}' end" - assert_raises ActiveRecord::DangerousAttributeError do + assert_raise ActiveRecord::DangerousAttributeError do klass.instance_method_already_implemented?(method) end end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 381249c0c2..436f50d395 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -1,10 +1,17 @@ -require "cases/helper" -require "models/pirate" -require "models/ship" -require "models/ship_part" -require "models/bird" -require "models/parrot" -require "models/treasure" +require 'cases/helper' +require 'models/bird' +require 'models/company' +require 'models/customer' +require 'models/developer' +require 'models/order' +require 'models/parrot' +require 'models/person' +require 'models/pirate' +require 'models/post' +require 'models/reader' +require 'models/ship' +require 'models/ship_part' +require 'models/treasure' class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase def test_autosave_should_be_a_valid_option_for_has_one @@ -30,6 +37,383 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase end end +class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase + def test_save_fails_for_invalid_has_one + firm = Firm.find(:first) + assert firm.valid? + + firm.account = Account.new + + assert !firm.account.valid? + assert !firm.valid? + assert !firm.save + assert_equal "is invalid", firm.errors.on("account") + end + + def test_save_succeeds_for_invalid_has_one_with_validate_false + firm = Firm.find(:first) + assert firm.valid? + + firm.unvalidated_account = Account.new + + assert !firm.unvalidated_account.valid? + assert firm.valid? + assert firm.save + end + + def test_build_before_child_saved + firm = Firm.find(1) + + account = firm.account.build("credit_limit" => 1000) + assert_equal account, firm.account + assert account.new_record? + assert firm.save + assert_equal account, firm.account + assert !account.new_record? + end + + def test_build_before_either_saved + firm = Firm.new("name" => "GlobalMegaCorp") + + firm.account = account = Account.new("credit_limit" => 1000) + assert_equal account, firm.account + assert account.new_record? + assert firm.save + assert_equal account, firm.account + assert !account.new_record? + end + + def test_assignment_before_parent_saved + firm = Firm.new("name" => "GlobalMegaCorp") + firm.account = a = Account.find(1) + assert firm.new_record? + assert_equal a, firm.account + assert firm.save + assert_equal a, firm.account + assert_equal a, firm.account(true) + end + + def test_assignment_before_either_saved + firm = Firm.new("name" => "GlobalMegaCorp") + firm.account = a = Account.new("credit_limit" => 1000) + assert firm.new_record? + assert a.new_record? + assert_equal a, firm.account + assert firm.save + assert !firm.new_record? + assert !a.new_record? + assert_equal a, firm.account + assert_equal a, firm.account(true) + end + + def test_not_resaved_when_unchanged + firm = Firm.find(:first, :include => :account) + firm.name += '-changed' + assert_queries(1) { firm.save! } + + firm = Firm.find(:first) + firm.account = Account.find(:first) + assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! } + + firm = Firm.find(:first).clone + firm.account = Account.find(:first) + assert_queries(2) { firm.save! } + + firm = Firm.find(:first).clone + firm.account = Account.find(:first).clone + assert_queries(2) { firm.save! } + end +end + +class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase + def test_save_fails_for_invalid_belongs_to + assert log = AuditLog.create(:developer_id => 0, :message => "") + + log.developer = Developer.new + assert !log.developer.valid? + assert !log.valid? + assert !log.save + assert_equal "is invalid", log.errors.on("developer") + end + + def test_save_succeeds_for_invalid_belongs_to_with_validate_false + assert log = AuditLog.create(:developer_id => 0, :message=> "") + + log.unvalidated_developer = Developer.new + assert !log.unvalidated_developer.valid? + assert log.valid? + assert log.save + end + + def test_assignment_before_parent_saved + client = Client.find(:first) + apple = Firm.new("name" => "Apple") + client.firm = apple + assert_equal apple, client.firm + assert apple.new_record? + assert client.save + assert apple.save + assert !apple.new_record? + assert_equal apple, client.firm + assert_equal apple, client.firm(true) + end + + def test_assignment_before_either_saved + final_cut = Client.new("name" => "Final Cut") + apple = Firm.new("name" => "Apple") + final_cut.firm = apple + assert final_cut.new_record? + assert apple.new_record? + assert final_cut.save + assert !final_cut.new_record? + assert !apple.new_record? + assert_equal apple, final_cut.firm + assert_equal apple, final_cut.firm(true) + end + + def test_store_two_association_with_one_save + num_orders = Order.count + num_customers = Customer.count + order = Order.new + + customer1 = order.billing = Customer.new + customer2 = order.shipping = Customer.new + assert order.save + assert_equal customer1, order.billing + assert_equal customer2, order.shipping + + order.reload + + assert_equal customer1, order.billing + assert_equal customer2, order.shipping + + assert_equal num_orders +1, Order.count + assert_equal num_customers +2, Customer.count + end + + def test_store_association_in_two_relations_with_one_save + num_orders = Order.count + num_customers = Customer.count + order = Order.new + + customer = order.billing = order.shipping = Customer.new + assert order.save + assert_equal customer, order.billing + assert_equal customer, order.shipping + + order.reload + + assert_equal customer, order.billing + assert_equal customer, order.shipping + + assert_equal num_orders +1, Order.count + assert_equal num_customers +1, Customer.count + end + + def test_store_association_in_two_relations_with_one_save_in_existing_object + num_orders = Order.count + num_customers = Customer.count + order = Order.create + + customer = order.billing = order.shipping = Customer.new + assert order.save + assert_equal customer, order.billing + assert_equal customer, order.shipping + + order.reload + + assert_equal customer, order.billing + assert_equal customer, order.shipping + + assert_equal num_orders +1, Order.count + assert_equal num_customers +1, Customer.count + end + + def test_store_association_in_two_relations_with_one_save_in_existing_object_with_values + num_orders = Order.count + num_customers = Customer.count + order = Order.create + + customer = order.billing = order.shipping = Customer.new + assert order.save + assert_equal customer, order.billing + assert_equal customer, order.shipping + + order.reload + + customer = order.billing = order.shipping = Customer.new + + assert order.save + order.reload + + assert_equal customer, order.billing + assert_equal customer, order.shipping + + assert_equal num_orders +1, Order.count + assert_equal num_customers +2, Customer.count + end +end + +class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCase + fixtures :companies, :people + + def test_invalid_adding + firm = Firm.find(1) + assert !(firm.clients_of_firm << c = Client.new) + assert c.new_record? + assert !firm.valid? + assert !firm.save + assert c.new_record? + end + + def test_invalid_adding_before_save + no_of_firms = Firm.count + no_of_clients = Client.count + new_firm = Firm.new("name" => "A New Firm, Inc") + new_firm.clients_of_firm.concat([c = Client.new, Client.new("name" => "Apple")]) + assert c.new_record? + assert !c.valid? + assert !new_firm.valid? + assert !new_firm.save + assert c.new_record? + assert new_firm.new_record? + end + + def test_invalid_adding_with_validate_false + firm = Firm.find(:first) + client = Client.new + firm.unvalidated_clients_of_firm << client + + assert firm.valid? + assert !client.valid? + assert firm.save + assert client.new_record? + end + + def test_valid_adding_with_validate_false + no_of_clients = Client.count + + firm = Firm.find(:first) + client = Client.new("name" => "Apple") + + assert firm.valid? + assert client.valid? + assert client.new_record? + + firm.unvalidated_clients_of_firm << client + + assert firm.save + assert !client.new_record? + assert_equal no_of_clients+1, Client.count + end + + def test_invalid_build + new_client = companies(:first_firm).clients_of_firm.build + assert new_client.new_record? + assert !new_client.valid? + assert_equal new_client, companies(:first_firm).clients_of_firm.last + assert !companies(:first_firm).save + assert new_client.new_record? + assert_equal 1, companies(:first_firm).clients_of_firm(true).size + end + + def test_adding_before_save + no_of_firms = Firm.count + no_of_clients = Client.count + + new_firm = Firm.new("name" => "A New Firm, Inc") + c = Client.new("name" => "Apple") + + new_firm.clients_of_firm.push Client.new("name" => "Natural Company") + assert_equal 1, new_firm.clients_of_firm.size + new_firm.clients_of_firm << c + assert_equal 2, new_firm.clients_of_firm.size + + assert_equal no_of_firms, Firm.count # Firm was not saved to database. + assert_equal no_of_clients, Client.count # Clients were not saved to database. + assert new_firm.save + assert !new_firm.new_record? + assert !c.new_record? + assert_equal new_firm, c.firm + assert_equal no_of_firms+1, Firm.count # Firm was saved to database. + assert_equal no_of_clients+2, Client.count # Clients were saved to database. + + assert_equal 2, new_firm.clients_of_firm.size + assert_equal 2, new_firm.clients_of_firm(true).size + end + + def test_assign_ids + firm = Firm.new("name" => "Apple") + firm.client_ids = [companies(:first_client).id, companies(:second_client).id] + firm.save + firm.reload + assert_equal 2, firm.clients.length + assert firm.clients.include?(companies(:second_client)) + end + + def test_assign_ids_for_through_a_belongs_to + post = Post.new(:title => "Assigning IDs works!", :body => "You heared it here first, folks!") + post.person_ids = [people(:david).id, people(:michael).id] + post.save + post.reload + assert_equal 2, post.people.length + assert post.people.include?(people(:david)) + end + + def test_build_before_save + company = companies(:first_firm) + new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") } + assert !company.clients_of_firm.loaded? + + company.name += '-changed' + assert_queries(2) { assert company.save } + assert !new_client.new_record? + assert_equal 2, company.clients_of_firm(true).size + end + + def test_build_many_before_save + company = companies(:first_firm) + new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } + + company.name += '-changed' + assert_queries(3) { assert company.save } + assert_equal 3, company.clients_of_firm(true).size + end + + def test_build_via_block_before_save + company = companies(:first_firm) + new_client = assert_no_queries { company.clients_of_firm.build {|client| client.name = "Another Client" } } + assert !company.clients_of_firm.loaded? + + company.name += '-changed' + assert_queries(2) { assert company.save } + assert !new_client.new_record? + assert_equal 2, company.clients_of_firm(true).size + end + + def test_build_many_via_block_before_save + company = companies(:first_firm) + new_clients = assert_no_queries do + company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client| + client.name = "changed" + end + end + + company.name += '-changed' + assert_queries(3) { assert company.save } + assert_equal 3, company.clients_of_firm(true).size + end + + def test_replace_on_new_object + firm = Firm.new("name" => "New Firm") + firm.clients = [companies(:second_client), Client.new("name" => "New Client")] + assert firm.save + firm.reload + assert_equal 2, firm.clients.length + assert firm.clients.include?(Client.find_by_name("New Client")) + end +end + class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase self.use_transactional_fixtures = false @@ -62,6 +446,14 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase assert_nil Ship.find_by_id(id) end + def test_should_skip_validation_on_a_child_association_if_marked_for_destruction + @pirate.ship.name = '' + assert !@pirate.valid? + + @pirate.ship.mark_for_destruction + assert_difference('Ship.count', -1) { @pirate.save! } + end + def test_should_rollback_destructions_if_an_exception_occurred_while_saving_a_child # Stub the save method of the @pirate.ship instance to destroy and then raise an exception class << @pirate.ship @@ -91,6 +483,14 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase assert_nil Pirate.find_by_id(id) end + def test_should_skip_validation_on_a_parent_association_if_marked_for_destruction + @ship.pirate.catchphrase = '' + assert !@ship.valid? + + @ship.pirate.mark_for_destruction + assert_difference('Pirate.count', -1) { @ship.save! } + end + def test_should_rollback_destructions_if_an_exception_occurred_while_saving_a_parent # Stub the save method of the @ship.pirate instance to destroy and then raise an exception class << @ship.pirate @@ -124,6 +524,17 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase ids.each { |id| assert_nil klass.find_by_id(id) } end + define_method("test_should_skip_validation_on_the_#{association_name}_association_if_marked_for_destruction") do + 2.times { |i| @pirate.send(association_name).create!(:name => "#{association_name}_#{i}") } + children = @pirate.send(association_name) + + children.each { |child| child.name = '' } + assert !@pirate.valid? + + children.each { |child| child.mark_for_destruction } + assert_difference("#{association_name.classify}.count", -2) { @pirate.save! } + end + define_method("test_should_rollback_destructions_if_an_exception_occurred_while_saving_#{association_name}") do 2.times { |i| @pirate.send(association_name).create!(:name => "#{association_name}_#{i}") } before = @pirate.send(association_name).map { |c| c } @@ -145,6 +556,41 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase assert_raise(RuntimeError) { assert !@pirate.save } assert_equal before, @pirate.reload.send(association_name) end + + # Add and remove callbacks tests for association collections. + %w{ method proc }.each do |callback_type| + define_method("test_should_run_add_callback_#{callback_type}s_for_#{association_name}") do + association_name_with_callbacks = "#{association_name}_with_#{callback_type}_callbacks" + + pirate = Pirate.new(:catchphrase => "Arr") + pirate.send(association_name_with_callbacks).build(:name => "Crowe the One-Eyed") + + expected = [ + "before_adding_#{callback_type}_#{association_name.singularize}_<new>", + "after_adding_#{callback_type}_#{association_name.singularize}_<new>" + ] + + assert_equal expected, pirate.ship_log + end + + define_method("test_should_run_remove_callback_#{callback_type}s_for_#{association_name}") do + association_name_with_callbacks = "#{association_name}_with_#{callback_type}_callbacks" + + @pirate.send(association_name_with_callbacks).create!(:name => "Crowe the One-Eyed") + @pirate.send(association_name_with_callbacks).each { |c| c.mark_for_destruction } + child_id = @pirate.send(association_name_with_callbacks).first.id + + @pirate.ship_log.clear + @pirate.save + + expected = [ + "before_removing_#{callback_type}_#{association_name.singularize}_#{child_id}", + "after_removing_#{callback_type}_#{association_name.singularize}_#{child_id}" + ] + + assert_equal expected, @pirate.ship_log + end + end end end @@ -181,6 +627,14 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase assert !@pirate.errors.on(:ship_name).blank? end + def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid + @pirate.ship.name = nil + @pirate.catchphrase = nil + assert !@pirate.valid? + assert !@pirate.errors.on(:ship_name).blank? + assert !@pirate.errors.on(:catchphrase).blank? + end + def test_should_still_allow_to_bypass_validations_on_the_associated_model @pirate.catchphrase = '' @pirate.ship.name = '' @@ -263,6 +717,14 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase assert !@ship.errors.on(:pirate_catchphrase).blank? end + def test_should_merge_errors_on_the_associated_model_onto_the_parent_even_if_it_is_not_valid + @ship.name = nil + @ship.pirate.catchphrase = nil + assert !@ship.valid? + assert !@ship.errors.on(:name).blank? + assert !@ship.errors.on(:pirate_catchphrase).blank? + end + def test_should_still_allow_to_bypass_validations_on_the_associated_model @ship.pirate.catchphrase = '' @ship.name = '' @@ -326,7 +788,24 @@ module AutosaveAssociationOnACollectionAssociationTests assert @pirate.errors.on(@association_name).blank? end - def test_should_still_allow_to_bypass_validations_on_the_associated_models + def test_should_not_use_default_invalid_error_on_associated_models + @pirate.send(@association_name).build(:name => '') + + assert !@pirate.valid? + assert_equal "can't be blank", @pirate.errors.on("#{@association_name}_name") + assert @pirate.errors.on(@association_name).blank? + end + + def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid + @pirate.send(@association_name).each { |child| child.name = '' } + @pirate.catchphrase = nil + + assert !@pirate.valid? + assert_equal "can't be blank", @pirate.errors.on("#{@association_name}_name") + assert !@pirate.errors.on(:catchphrase).blank? + end + + def test_should_allow_to_bypass_validations_on_the_associated_models_on_update @pirate.catchphrase = '' @pirate.send(@association_name).each { |child| child.name = '' } @@ -338,6 +817,20 @@ module AutosaveAssociationOnACollectionAssociationTests ] end + def test_should_validation_the_associated_models_on_create + assert_no_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count") do + 2.times { @pirate.send(@association_name).build } + @pirate.save(true) + end + end + + def test_should_allow_to_bypass_validations_on_the_associated_models_on_create + assert_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count", +2) do + 2.times { @pirate.send(@association_name).build } + @pirate.save(false) + end + end + def test_should_rollback_any_changes_if_an_exception_occurred_while_saving before = [@pirate.catchphrase, *@pirate.send(@association_name).map(&:name)] new_names = ['Grace OMalley', 'Privateers Greed'] diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 973bb567bd..99d77961fc 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -424,8 +424,8 @@ class BasicsTest < ActiveRecord::TestCase def test_non_attribute_access_and_assignment topic = Topic.new assert !topic.respond_to?("mumbo") - assert_raises(NoMethodError) { topic.mumbo } - assert_raises(NoMethodError) { topic.mumbo = 5 } + assert_raise(NoMethodError) { topic.mumbo } + assert_raise(NoMethodError) { topic.mumbo = 5 } end def test_preserving_date_objects @@ -490,7 +490,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_record_not_found_exception - assert_raises(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(99999) } + assert_raise(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(99999) } end def test_initialize_with_attributes @@ -848,7 +848,7 @@ class BasicsTest < ActiveRecord::TestCase client.delete assert client.frozen? assert_kind_of Firm, client.firm - assert_raises(ActiveSupport::FrozenObjectError) { client.name = "something else" } + assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" } end def test_destroy_new_record @@ -862,7 +862,7 @@ class BasicsTest < ActiveRecord::TestCase client.destroy assert client.frozen? assert_kind_of Firm, client.firm - assert_raises(ActiveSupport::FrozenObjectError) { client.name = "something else" } + assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" } end def test_update_attribute @@ -910,8 +910,8 @@ class BasicsTest < ActiveRecord::TestCase def test_mass_assignment_should_raise_exception_if_accessible_and_protected_attribute_writers_are_both_used topic = TopicWithProtectedContentAndAccessibleAuthorName.new - assert_raises(RuntimeError) { topic.attributes = { "author_name" => "me" } } - assert_raises(RuntimeError) { topic.attributes = { "content" => "stuff" } } + assert_raise(RuntimeError) { topic.attributes = { "author_name" => "me" } } + assert_raise(RuntimeError) { topic.attributes = { "content" => "stuff" } } end def test_mass_assignment_protection @@ -949,7 +949,7 @@ class BasicsTest < ActiveRecord::TestCase def test_mass_assigning_invalid_attribute firm = Firm.new - assert_raises(ActiveRecord::UnknownAttributeError) do + assert_raise(ActiveRecord::UnknownAttributeError) do firm.attributes = { "id" => 5, "type" => "Client", "i_dont_even_exist" => 20 } end end @@ -1402,7 +1402,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_sql_injection_via_find - assert_raises(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do Topic.find("123456 OR id > 0") end end @@ -1755,6 +1755,13 @@ class BasicsTest < ActiveRecord::TestCase end end + def test_scoped_find_with_group_and_having + developers = Developer.with_scope(:find => { :group => 'salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do + Developer.find(:all) + end + assert_equal 3, developers.size + end + def test_find_last last = Developer.find :last assert_equal last, Developer.find(:first, :order => 'id desc') @@ -1783,6 +1790,11 @@ class BasicsTest < ActiveRecord::TestCase assert_equal last, Developer.find(:all, :order => 'developers.name, developers.salary DESC').last end + def test_find_symbol_ordered_last + last = Developer.find :last, :order => :salary + assert_equal last, Developer.find(:all, :order => :salary).last + end + def test_find_scoped_ordered_last last_developer = Developer.with_scope(:find => { :order => 'developers.salary ASC' }) do Developer.find(:last) @@ -2092,18 +2104,4 @@ class BasicsTest < ActiveRecord::TestCase assert_equal custom_datetime, parrot[attribute] end end - - private - def with_kcode(kcode) - if RUBY_VERSION < '1.9' - orig_kcode, $KCODE = $KCODE, kcode - begin - yield - ensure - $KCODE = orig_kcode - end - else - yield - end - end end diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index 108d679108..5009a90846 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -11,7 +11,7 @@ class EachTest < ActiveRecord::TestCase def test_each_should_excecute_one_query_per_batch assert_queries(Post.count + 1) do - Post.each(:batch_size => 1) do |post| + Post.find_each(:batch_size => 1) do |post| assert_kind_of Post, post end end @@ -19,13 +19,13 @@ class EachTest < ActiveRecord::TestCase def test_each_should_raise_if_the_order_is_set assert_raise(RuntimeError) do - Post.each(:order => "title") { |post| post } + Post.find_each(:order => "title") { |post| post } end end def test_each_should_raise_if_the_limit_is_set assert_raise(RuntimeError) do - Post.each(:limit => 1) { |post| post } + Post.find_each(:limit => 1) { |post| post } end end @@ -46,4 +46,16 @@ class EachTest < ActiveRecord::TestCase end end end + + def test_find_in_batches_shouldnt_excute_query_unless_needed + post_count = Post.count + + assert_queries(2) do + Post.find_in_batches(:batch_size => post_count) {|batch| assert_kind_of Array, batch } + end + + assert_queries(1) do + Post.find_in_batches(:batch_size => post_count + 1) {|batch| assert_kind_of Array, batch } + end + end end
\ No newline at end of file diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 5a4ed429b6..56dcdea110 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -92,6 +92,14 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 60, c[2] end + def test_should_group_by_summed_field_having_sanitized_condition + c = Account.sum(:credit_limit, :group => :firm_id, + :having => ['sum(credit_limit) > ?', 50]) + assert_nil c[1] + assert_equal 105, c[6] + assert_equal 60, c[2] + end + def test_should_group_by_summed_association c = Account.sum(:credit_limit, :group => :firm) assert_equal 50, c[companies(:first_firm)] @@ -247,8 +255,8 @@ class CalculationsTest < ActiveRecord::TestCase Company.send(:validate_calculation_options, :count, :include => true) end - assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) } - assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) } + assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) } + assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) } end def test_should_count_selected_field_with_include @@ -256,6 +264,19 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit) end + def test_should_count_scoped_select + Account.update_all("credit_limit = NULL") + assert_equal 0, Account.scoped(:select => "credit_limit").count + end + + def test_should_count_scoped_select_with_options + Account.update_all("credit_limit = NULL") + Account.last.update_attribute('credit_limit', 49) + Account.first.update_attribute('credit_limit', 51) + + assert_equal 1, Account.scoped(:select => "credit_limit").count(:conditions => ['credit_limit >= 50']) + end + def test_should_count_manual_select_with_include assert_equal 6, Account.count(:select => "DISTINCT accounts.id", :include => :firm) end diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index 33b1ea034d..95fddaeef6 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -352,13 +352,13 @@ class CallbacksTest < ActiveRecord::TestCase david = ImmutableDeveloper.find(1) assert david.valid? assert !david.save - assert_raises(ActiveRecord::RecordNotSaved) { david.save! } + assert_raise(ActiveRecord::RecordNotSaved) { david.save! } david = ImmutableDeveloper.find(1) david.salary = 10_000_000 assert !david.valid? assert !david.save - assert_raises(ActiveRecord::RecordInvalid) { david.save! } + assert_raise(ActiveRecord::RecordInvalid) { david.save! } someone = CallbackCancellationDeveloper.find(1) someone.cancel_before_save = true diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb new file mode 100644 index 0000000000..cc9b2a45f4 --- /dev/null +++ b/activerecord/test/cases/connection_pool_test.rb @@ -0,0 +1,25 @@ +require "cases/helper" + +class ConnectionManagementTest < ActiveRecord::TestCase + def setup + @env = {} + @app = stub('App') + @management = ActiveRecord::ConnectionAdapters::ConnectionManagement.new(@app) + + @connections_cleared = false + ActiveRecord::Base.stubs(:clear_active_connections!).with { @connections_cleared = true } + end + + test "clears active connections after each call" do + @app.expects(:call).with(@env) + @management.call(@env) + assert @connections_cleared + end + + test "doesn't clear active connections when running in a test case" do + @env['rack.test'] = true + @app.expects(:call).with(@env) + @management.call(@env) + assert !@connections_cleared + end +end
\ No newline at end of file diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 5f5707b388..ac95bac4ad 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -228,7 +228,7 @@ class DirtyTest < ActiveRecord::TestCase pirate = Pirate.new pirate.parrot_id = 1 - assert_raises(ActiveRecord::RecordInvalid) { pirate.save! } + assert_raise(ActiveRecord::RecordInvalid) { pirate.save! } check_pirate_after_save_failure(pirate) end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index ee8f4901f9..d8778957c0 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -146,7 +146,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_by_ids_missing_one - assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) } end def test_find_all_with_limit @@ -191,6 +191,13 @@ class FinderTest < ActiveRecord::TestCase assert developers.all? { |developer| developer.salary > 10000 } end + def test_find_with_group_and_sanitized_having + developers = Developer.find(:all, :group => "salary", :having => ["sum(salary) > ?", 10000], :select => "salary") + assert_equal 3, developers.size + assert_equal 3, developers.map(&:salary).uniq.size + assert developers.all? { |developer| developer.salary > 10000 } + end + def test_find_with_entire_select_statement topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'" @@ -229,7 +236,7 @@ class FinderTest < ActiveRecord::TestCase end def test_unexisting_record_exception_handling - assert_raises(ActiveRecord::RecordNotFound) { + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1).parent } @@ -238,7 +245,7 @@ class FinderTest < ActiveRecord::TestCase def test_find_only_some_columns topic = Topic.find(1, :select => "author_name") - assert_raises(ActiveRecord::MissingAttributeError) {topic.title} + assert_raise(ActiveRecord::MissingAttributeError) {topic.title} assert_equal "David", topic.author_name assert !topic.attribute_present?("title") #assert !topic.respond_to?("title") @@ -260,22 +267,22 @@ class FinderTest < ActiveRecord::TestCase def test_find_on_array_conditions assert Topic.find(1, :conditions => ["approved = ?", false]) - assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => ["approved = ?", true]) } + assert_raise(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 }) } + assert_raise(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 }) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) } end def test_find_on_hash_conditions_with_hashed_table_name assert Topic.find(1, :conditions => {:topics => { :approved => false }}) - assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => {:topics => { :approved => true }}) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => {:topics => { :approved => true }}) } end def test_find_with_hash_conditions_on_joined_table @@ -293,7 +300,7 @@ class FinderTest < ActiveRecord::TestCase 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) { + assert_raise(ActiveRecord::RecordNotFound) { Customer.find(david.id, :conditions => { 'customers.name' => david.name + "1", :address => david.address }) } end @@ -304,13 +311,13 @@ class FinderTest < ActiveRecord::TestCase 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 }) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) } end def test_find_on_hash_conditions_with_end_exclusive_range assert_equal [1,2,3], Topic.find(:all, :conditions => { :id => 1..3 }).map(&:id).sort assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1...3 }).map(&:id).sort - assert_raises(ActiveRecord::RecordNotFound) { Topic.find(3, :conditions => { :id => 2...3 }) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(3, :conditions => { :id => 2...3 }) } end def test_find_on_hash_conditions_with_multiple_ranges @@ -320,9 +327,9 @@ class FinderTest < ActiveRecord::TestCase 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 }) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) } end def test_condition_interpolation @@ -346,7 +353,7 @@ class FinderTest < ActiveRecord::TestCase end def test_hash_condition_find_malformed - assert_raises(ActiveRecord::StatementInvalid) { + assert_raise(ActiveRecord::StatementInvalid) { Company.find(:first, :conditions => { :id => 2, :dhh => true }) } end @@ -415,10 +422,10 @@ class FinderTest < ActiveRecord::TestCase 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) { + assert_raise(ActiveRecord::PreparedStatementInvalid) { Company.find(:first, :conditions => ["id=? AND name = ?", 2]) } - assert_raises(ActiveRecord::PreparedStatementInvalid) { + assert_raise(ActiveRecord::PreparedStatementInvalid) { Company.find(:first, :conditions => ["id=?", 2, 3, 4]) } end @@ -435,11 +442,11 @@ class FinderTest < ActiveRecord::TestCase def test_bind_arity assert_nothing_raised { bind '' } - assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '', 1 } + assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '', 1 } - assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '?' } + assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?' } assert_nothing_raised { bind '?', 1 } - assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 } + assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 } end def test_named_bind_variables @@ -544,7 +551,7 @@ class FinderTest < ActiveRecord::TestCase def test_find_by_one_attribute_bang assert_equal topics(:first), Topic.find_by_title!("The First Topic") - assert_raises(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") } + assert_raise(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") } end def test_find_by_one_attribute_caches_dynamic_finder @@ -625,14 +632,14 @@ class FinderTest < ActiveRecord::TestCase end def test_find_by_one_missing_attribute - assert_raises(NoMethodError) { Topic.find_by_undertitle("The First Topic!") } + assert_raise(NoMethodError) { Topic.find_by_undertitle("The First Topic!") } end def test_find_by_invalid_method_syntax - assert_raises(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") } - assert_raises(NoMethodError) { Topic.find_by_title?("The First Topic") } - assert_raises(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") } - assert_raises(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") } + assert_raise(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") } + assert_raise(NoMethodError) { Topic.find_by_title?("The First Topic") } + assert_raise(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") } + assert_raise(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") } end def test_find_by_two_attributes @@ -654,8 +661,8 @@ class FinderTest < ActiveRecord::TestCase end def test_find_last_by_invalid_method_syntax - assert_raises(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") } - assert_raises(NoMethodError) { Topic.find_last_by_title?("The First Topic") } + 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 @@ -663,7 +670,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_last_by_one_missing_attribute - assert_raises(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") } + assert_raise(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") } end def test_find_last_by_two_attributes @@ -916,16 +923,16 @@ class FinderTest < ActiveRecord::TestCase end def test_find_with_bad_sql - assert_raises(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" } + assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" } end def test_find_with_invalid_params - assert_raises(ArgumentError) { Topic.find :first, :join => "It should be `joins'" } - assert_raises(ArgumentError) { Topic.find :first, :conditions => '1 = 1', :join => "It should be `joins'" } + assert_raise(ArgumentError) { Topic.find :first, :join => "It should be `joins'" } + assert_raise(ArgumentError) { Topic.find :first, :conditions => '1 = 1', :join => "It should be `joins'" } end def test_dynamic_finder_with_invalid_params - assert_raises(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" } + assert_raise(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" } end def test_find_all_with_limit @@ -1057,6 +1064,14 @@ class FinderTest < ActiveRecord::TestCase assert_equal [0, 1, 1], posts.map(&:author_id).sort end + def test_finder_with_scoped_from + all_topics = Topic.all + + Topic.with_scope(:find => { :from => 'fake_topics' }) do + assert_equal all_topics, Topic.all(:from => 'topics') + end + end + protected def bind(statement, *vars) if vars.first.is_a?(Hash) diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index eb63fd5f34..252bf4ff61 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -151,7 +151,7 @@ class FixturesTest < ActiveRecord::TestCase end def test_dirty_dirty_yaml_file - assert_raises(Fixture::FormatError) do + assert_raise(Fixture::FormatError) do Fixtures.new( Account.connection, "courses", 'Course', FIXTURES_ROOT + "/naked/yml/courses") end end @@ -420,7 +420,7 @@ class InvalidTableNameFixturesTest < ActiveRecord::TestCase self.use_transactional_fixtures = false def test_raises_error - assert_raises FixtureClassNotFound do + assert_raise FixtureClassNotFound do funny_jokes(:a_joke) end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 3f59eb9706..eae5a60829 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -68,7 +68,7 @@ class InheritanceTest < ActiveRecord::TestCase if current_adapter?(:SybaseAdapter) Company.connection.execute "SET IDENTITY_INSERT companies OFF" end - assert_raises(ActiveRecord::SubclassNotFound) { Company.find(100) } + assert_raise(ActiveRecord::SubclassNotFound) { Company.find(100) } end def test_inheritance_find @@ -124,7 +124,7 @@ class InheritanceTest < ActiveRecord::TestCase end def test_finding_incorrect_type_data - assert_raises(ActiveRecord::RecordNotFound) { Firm.find(2) } + assert_raise(ActiveRecord::RecordNotFound) { Firm.find(2) } assert_nothing_raised { Firm.find(1) } end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 077cac7747..e177235591 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -35,7 +35,25 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, p2.lock_version p2.first_name = 'sue' - assert_raises(ActiveRecord::StaleObjectError) { p2.save! } + assert_raise(ActiveRecord::StaleObjectError) { p2.save! } + end + + def test_lock_destroy + p1 = Person.find(1) + p2 = Person.find(1) + assert_equal 0, p1.lock_version + assert_equal 0, p2.lock_version + + p1.first_name = 'stu' + p1.save! + assert_equal 1, p1.lock_version + assert_equal 0, p2.lock_version + + assert_raises(ActiveRecord::StaleObjectError) { p2.destroy } + + assert p1.destroy + assert_equal true, p1.frozen? + assert_raises(ActiveRecord::RecordNotFound) { Person.find(1) } end def test_lock_repeating @@ -50,9 +68,9 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, p2.lock_version p2.first_name = 'sue' - assert_raises(ActiveRecord::StaleObjectError) { p2.save! } + assert_raise(ActiveRecord::StaleObjectError) { p2.save! } p2.first_name = 'sue2' - assert_raises(ActiveRecord::StaleObjectError) { p2.save! } + assert_raise(ActiveRecord::StaleObjectError) { p2.save! } end def test_lock_new @@ -71,7 +89,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, p2.lock_version p2.first_name = 'sue' - assert_raises(ActiveRecord::StaleObjectError) { p2.save! } + assert_raise(ActiveRecord::StaleObjectError) { p2.save! } end def test_lock_new_with_nil @@ -95,7 +113,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, t2.version t2.tps_report_number = 800 - assert_raises(ActiveRecord::StaleObjectError) { t2.save! } + assert_raise(ActiveRecord::StaleObjectError) { t2.save! } end def test_lock_column_is_mass_assignable diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 71e2ce8790..3c34cdeade 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -262,6 +262,15 @@ class NestedScopingTest < ActiveRecord::TestCase end end + def test_merge_inner_scope_has_priority + Developer.with_scope(:find => { :limit => 5 }) do + Developer.with_scope(:find => { :limit => 10 }) do + merged_option = Developer.instance_eval('current_scoped_methods')[:find] + assert_equal({ :limit => 10 }, merged_option) + end + end + end + def test_replace_options Developer.with_scope(:find => { :conditions => "name = 'David'" }) do Developer.with_exclusive_scope(:find => { :conditions => "name = 'Jamis'" }) do @@ -369,8 +378,10 @@ class NestedScopingTest < ActiveRecord::TestCase def test_merged_scoped_find poor_jamis = developers(:poor_jamis) Developer.with_scope(:find => { :conditions => "salary < 100000" }) do - Developer.with_scope(:find => { :offset => 1 }) do - assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc')) + Developer.with_scope(:find => { :offset => 1, :order => 'id asc' }) do + assert_sql /ORDER BY id asc / do + assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc')) + end end end end @@ -400,6 +411,29 @@ class NestedScopingTest < ActiveRecord::TestCase end end + def test_nested_scoped_create + comment = nil + Comment.with_scope(:create => { :post_id => 1}) do + Comment.with_scope(:create => { :post_id => 2}) do + assert_equal({ :post_id => 2 }, Comment.send(:current_scoped_methods)[:create]) + comment = Comment.create :body => "Hey guys, nested scopes are broken. Please fix!" + end + end + assert_equal 2, comment.post_id + end + + def test_nested_exclusive_scope_for_create + comment = nil + Comment.with_scope(:create => { :body => "Hey guys, nested scopes are broken. Please fix!" }) do + Comment.with_exclusive_scope(:create => { :post_id => 1 }) do + assert_equal({ :post_id => 1 }, Comment.send(:current_scoped_methods)[:create]) + comment = Comment.create :body => "Hey guys" + end + end + assert_equal 1, comment.post_id + assert_equal 'Hey guys', comment.body + end + def test_merged_scoped_find_on_blank_conditions [nil, " ", [], {}].each do |blank| Developer.with_scope(:find => {:conditions => blank}) do @@ -523,7 +557,6 @@ class HasManyScopingTest< ActiveRecord::TestCase end end - class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase fixtures :posts, :categories, :categories_posts @@ -549,7 +582,6 @@ class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase end end - class DefaultScopingTest < ActiveRecord::TestCase fixtures :developers @@ -577,7 +609,7 @@ class DefaultScopingTest < ActiveRecord::TestCase # Scopes added on children should append to parent scope expected_klass_scope = [{ :create => {}, :find => { :order => 'salary DESC' }}, { :create => {}, :find => {} }] assert_equal expected_klass_scope, klass.send(:scoped_methods) - + # Parent should still have the original scope assert_equal scope, DeveloperOrderedBySalary.send(:scoped_methods) end @@ -597,7 +629,7 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_named_scope - expected = Developer.find(:all, :order => 'name DESC').collect { |dev| dev.salary } + expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.salary } received = DeveloperOrderedBySalary.by_name.find(:all).collect { |dev| dev.salary } assert_equal expected, received end @@ -620,7 +652,6 @@ end =begin # We disabled the scoping for has_one and belongs_to as we can't think of a proper use case - class BelongsToScopingTest< ActiveRecord::TestCase fixtures :comments, :posts @@ -640,7 +671,6 @@ class BelongsToScopingTest< ActiveRecord::TestCase end - class HasOneScopingTest< ActiveRecord::TestCase fixtures :comments, :posts diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 1c974e4825..16861f21b1 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -93,6 +93,30 @@ if ActiveRecord::Base.connection.supports_migrations? end end + def testing_table_with_only_foo_attribute + Person.connection.create_table :testings, :id => false do |t| + t.column :foo, :string + end + + yield Person.connection + ensure + Person.connection.drop_table :testings rescue nil + end + protected :testing_table_with_only_foo_attribute + + def test_create_table_without_id + testing_table_with_only_foo_attribute do |connection| + assert_equal connection.columns(:testings).size, 1 + end + end + + def test_add_column_with_primary_key_attribute + testing_table_with_only_foo_attribute do |connection| + assert_nothing_raised { connection.add_column :testings, :id, :primary_key } + assert_equal connection.columns(:testings).size, 2 + end + end + def test_create_table_adds_id Person.connection.create_table :testings do |t| t.column :foo, :string @@ -111,7 +135,7 @@ if ActiveRecord::Base.connection.supports_migrations? end end - assert_raises(ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::StatementInvalid) do Person.connection.execute "insert into testings (foo) values (NULL)" end ensure @@ -278,7 +302,7 @@ if ActiveRecord::Base.connection.supports_migrations? end Person.connection.add_column :testings, :bar, :string, :null => false - assert_raises(ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::StatementInvalid) do Person.connection.execute "insert into testings (foo, bar) values ('hello', NULL)" end ensure @@ -297,7 +321,7 @@ if ActiveRecord::Base.connection.supports_migrations? Person.connection.enable_identity_insert("testings", false) if current_adapter?(:SybaseAdapter) assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" } - assert_raises(ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::StatementInvalid) do unless current_adapter?(:OpenBaseAdapter) Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) values (2, 'hello', NULL)" else @@ -545,7 +569,7 @@ if ActiveRecord::Base.connection.supports_migrations? else ActiveRecord::ActiveRecordError end - assert_raises(exception) do + assert_raise(exception) do Person.connection.rename_column "hats", "nonexistent", "should_fail" end ensure @@ -795,7 +819,7 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "hello world", Reminder.find(:first).content WeNeedReminders.down - assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) } + assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) } end def test_add_table_with_decimals @@ -856,7 +880,7 @@ if ActiveRecord::Base.connection.supports_migrations? end GiveMeBigNumbers.down - assert_raises(ActiveRecord::StatementInvalid) { BigNumber.find(:first) } + assert_raise(ActiveRecord::StatementInvalid) { BigNumber.find(:first) } end def test_migrator @@ -876,7 +900,7 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal 0, ActiveRecord::Migrator.current_version Person.reset_column_information assert !Person.column_methods_hash.include?(:last_name) - assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) } + assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) } end def test_migrator_one_up @@ -928,11 +952,11 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal(0, ActiveRecord::Migrator.current_version) end - if current_adapter?(:PostgreSQLAdapter) + if ActiveRecord::Base.connection.supports_ddl_transactions? def test_migrator_one_up_with_exception_and_rollback assert !Person.column_methods_hash.include?(:last_name) - e = assert_raises(StandardError) do + e = assert_raise(StandardError) do ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/broken", 100) end @@ -945,20 +969,20 @@ if ActiveRecord::Base.connection.supports_migrations? def test_finds_migrations migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid").migrations - [['1', 'people_have_last_names'], - ['2', 'we_need_reminders'], - ['3', 'innocent_jointable']].each_with_index do |pair, i| - migrations[i].version == pair.first - migrations[1].name == pair.last + + [[1, 'PeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i| + assert_equal migrations[i].version, pair.first + assert_equal migrations[i].name, pair.last end end def test_finds_pending_migrations ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2", 1) migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/interleaved/pass_2").pending_migrations + assert_equal 1, migrations.size - migrations[0].version == '3' - migrations[0].name == 'innocent_jointable' + assert_equal migrations[0].version, 3 + assert_equal migrations[0].name, 'InnocentJointable' end def test_only_loads_pending_migrations @@ -1107,7 +1131,7 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "hello world", Reminder.find(:first).content WeNeedReminders.down - assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) } + assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) } ensure ActiveRecord::Base.table_name_prefix = '' ActiveRecord::Base.table_name_suffix = '' @@ -1137,13 +1161,13 @@ if ActiveRecord::Base.connection.supports_migrations? end def test_migrator_with_duplicates - assert_raises(ActiveRecord::DuplicateMigrationVersionError) do + assert_raise(ActiveRecord::DuplicateMigrationVersionError) do ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/duplicate", nil) end end def test_migrator_with_duplicate_names - assert_raises(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do + assert_raise(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/duplicate_names", nil) end end @@ -1159,7 +1183,7 @@ if ActiveRecord::Base.connection.supports_migrations? # table name is 29 chars, the standard sequence name will # be 33 chars and fail - assert_raises(ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::StatementInvalid) do begin Person.connection.create_table :table_with_name_thats_just_ok do |t| t.column :foo, :string, :null => false @@ -1186,7 +1210,7 @@ if ActiveRecord::Base.connection.supports_migrations? end # confirm the custom sequence got dropped - assert_raises(ActiveRecord::StatementInvalid) do + assert_raise(ActiveRecord::StatementInvalid) do Person.connection.execute("select suitably_short_seq.nextval from dual") end end diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index e1e27fa130..ae6a54a5bd 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -15,7 +15,7 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal Topic.find(:all), Topic.base assert_equal Topic.find(:all), Topic.base.to_a assert_equal Topic.find(:first), Topic.base.first - assert_equal Topic.find(:all), Topic.base.each { |i| i } + assert_equal Topic.find(:all), Topic.base.map { |i| i } end def test_found_items_are_cached @@ -99,6 +99,12 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal topics_written_before_the_second, Topic.written_before(topics(:second).written_on) end + def test_procedural_scopes_returning_nil + all_topics = Topic.find(:all) + + assert_equal all_topics, Topic.written_before(nil) + end + def test_scopes_with_joins address = author_addresses(:david_address) posts_with_authors_at_address = Post.find( @@ -142,6 +148,15 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal authors(:david).comments & Comment.containing_the_letter_e, authors(:david).comments.containing_the_letter_e end + def test_named_scopes_honor_current_scopes_from_when_defined + assert !Post.ranked_by_comments.limit(5).empty? + assert !authors(:david).posts.ranked_by_comments.limit(5).empty? + assert_not_equal Post.ranked_by_comments.limit(5), authors(:david).posts.ranked_by_comments.limit(5) + assert_not_equal Post.top(5), authors(:david).posts.top(5) + assert_equal authors(:david).posts.ranked_by_comments.limit(5), authors(:david).posts.top(5) + assert_equal Post.ranked_by_comments.limit(5), Post.top(5) + end + def test_active_records_have_scope_named__all__ assert !Topic.find(:all).empty? @@ -238,7 +253,7 @@ class NamedScopeTest < ActiveRecord::TestCase topic = Topic.approved.create!({}) assert topic.approved end - + def test_should_build_with_proxy_options_chained topic = Topic.approved.by_lifo.build({}) assert topic.approved @@ -278,15 +293,21 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal post.comments.size, Post.scoped(:joins => join).scoped(:joins => join, :conditions => "posts.id = #{post.id}").size end - def test_chanining_should_use_latest_conditions_when_creating - post1 = Topic.rejected.approved.new - assert post1.approved? + def test_chaining_should_use_latest_conditions_when_creating + post = Topic.rejected.new + assert !post.approved? + + post = Topic.rejected.approved.new + assert post.approved? - post2 = Topic.approved.rejected.new - assert ! post2.approved? + post = Topic.approved.rejected.new + assert !post.approved? + + post = Topic.approved.rejected.approved.new + assert post.approved? end - def test_chanining_should_use_latest_conditions_when_searching + def test_chaining_should_use_latest_conditions_when_searching # Normal hash conditions assert_equal Topic.all(:conditions => {:approved => true}), Topic.rejected.approved.all assert_equal Topic.all(:conditions => {:approved => false}), Topic.approved.rejected.all @@ -297,6 +318,24 @@ class NamedScopeTest < ActiveRecord::TestCase # Nested hash conditions with different keys assert_equal [posts(:sti_comments)], Post.with_special_comments.with_post(4).all.uniq end + + def test_methods_invoked_within_scopes_should_respect_scope + assert_equal [], Topic.approved.by_rejected_ids.proxy_options[:conditions][:id] + end + + def test_named_scopes_batch_finders + assert_equal 3, Topic.approved.count + + assert_queries(4) do + Topic.approved.find_each(:batch_size => 1) {|t| assert t.approved? } + end + + assert_queries(2) do + Topic.approved.find_in_batches(:batch_size => 2) do |group| + group.each {|t| assert t.approved? } + end + end + end end class DynamicScopeMatchTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 8b1c714ead..db64bbb806 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -4,6 +4,7 @@ require 'models/customer' require 'models/company' require 'models/company_in_module' require 'models/subscriber' +require 'models/pirate' class ReflectionTest < ActiveRecord::TestCase fixtures :topics, :customers, :companies, :subscribers @@ -169,9 +170,9 @@ class ReflectionTest < ActiveRecord::TestCase def test_reflection_of_all_associations # FIXME these assertions bust a lot - assert_equal 26, Firm.reflect_on_all_associations.size - assert_equal 20, Firm.reflect_on_all_associations(:has_many).size - assert_equal 6, Firm.reflect_on_all_associations(:has_one).size + assert_equal 28, Firm.reflect_on_all_associations.size + assert_equal 21, Firm.reflect_on_all_associations(:has_many).size + assert_equal 7, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 40abd935df..f6533b5396 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -214,7 +214,7 @@ class TransactionTest < ActiveRecord::TestCase end def test_invalid_keys_for_transaction - assert_raises ArgumentError do + assert_raise ArgumentError do Topic.transaction :nested => true do end end @@ -349,7 +349,7 @@ class TransactionTest < ActiveRecord::TestCase end end - def test_sqlite_add_column_in_transaction_raises_statement_invalid + def test_sqlite_add_column_in_transaction return true unless current_adapter?(:SQLite3Adapter, :SQLiteAdapter) # Test first if column creation/deletion works correctly when no @@ -368,10 +368,15 @@ class TransactionTest < ActiveRecord::TestCase assert !Topic.column_names.include?('stuff') end - # Test now inside a transaction: add_column should raise a StatementInvalid - Topic.transaction do - assert_raises(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) } - raise ActiveRecord::Rollback + if Topic.connection.supports_ddl_transactions? + assert_nothing_raised do + Topic.transaction { Topic.connection.add_column('topics', 'stuff', :string) } + end + else + Topic.transaction do + assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) } + raise ActiveRecord::Rollback + end end end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index cbb184131f..c20f5ae63e 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -8,6 +8,7 @@ require 'models/warehouse_thing' require 'models/guid' require 'models/owner' require 'models/pet' +require 'models/event' # The following methods in Topic are used in test_conditional_validation_* class Topic @@ -113,8 +114,8 @@ class ValidationsTest < ActiveRecord::TestCase end def test_invalid_record_exception - assert_raises(ActiveRecord::RecordInvalid) { Reply.create! } - assert_raises(ActiveRecord::RecordInvalid) { Reply.new.save! } + assert_raise(ActiveRecord::RecordInvalid) { Reply.create! } + assert_raise(ActiveRecord::RecordInvalid) { Reply.new.save! } begin r = Reply.new @@ -126,13 +127,13 @@ class ValidationsTest < ActiveRecord::TestCase end def test_exception_on_create_bang_many - assert_raises(ActiveRecord::RecordInvalid) do + assert_raise(ActiveRecord::RecordInvalid) do Reply.create!([ { "title" => "OK" }, { "title" => "Wrong Create" }]) end end def test_exception_on_create_bang_with_block - assert_raises(ActiveRecord::RecordInvalid) do + assert_raise(ActiveRecord::RecordInvalid) do Reply.create!({ "title" => "OK" }) do |r| r.content = nil end @@ -140,7 +141,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_exception_on_create_bang_many_with_block - assert_raises(ActiveRecord::RecordInvalid) do + assert_raise(ActiveRecord::RecordInvalid) do Reply.create!([{ "title" => "OK" }, { "title" => "Wrong Create" }]) do |r| r.content = nil end @@ -149,7 +150,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_scoped_create_without_attributes Reply.with_scope(:create => {}) do - assert_raises(ActiveRecord::RecordInvalid) { Reply.create! } + assert_raise(ActiveRecord::RecordInvalid) { Reply.create! } end end @@ -169,7 +170,7 @@ class ValidationsTest < ActiveRecord::TestCase assert_equal person.first_name, "Mary", "should be ok when no attributes are passed to create!" end end - end + end def test_single_error_per_attr_iteration r = Reply.new @@ -530,6 +531,14 @@ class ValidationsTest < ActiveRecord::TestCase end end + def test_validate_uniqueness_with_limit + # Event.title is limited to 5 characters + e1 = Event.create(:title => "abcde") + assert e1.valid?, "Could not create an event with a unique, 5 character title" + e2 = Event.create(:title => "abcdefgh") + assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique" + end + def test_validate_straight_inheritance_uniqueness w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork") assert w1.valid?, "Saving w1" @@ -1421,6 +1430,17 @@ class ValidationsTest < ActiveRecord::TestCase assert_equal "can't be blank", t.errors.on("title").first end + def test_invalid_should_be_the_opposite_of_valid + Topic.validates_presence_of :title + + t = Topic.new + assert t.invalid? + assert t.errors.invalid?(:title) + + t.title = 'Things are going to change' + assert !t.invalid? + end + # previous implementation of validates_presence_of eval'd the # string with the wrong binding, this regression test is to # ensure that it works correctly @@ -1442,20 +1462,6 @@ class ValidationsTest < ActiveRecord::TestCase t.author_name = "Hubert J. Farnsworth" assert t.valid?, "A topic with an important title and author should be valid" end - - private - def with_kcode(kcode) - if RUBY_VERSION < '1.9' - orig_kcode, $KCODE = $KCODE, kcode - begin - yield - ensure - $KCODE = orig_kcode - end - else - yield - end - end end diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb index 39c6ea820d..b49997669e 100644 --- a/activerecord/test/cases/xml_serialization_test.rb +++ b/activerecord/test/cases/xml_serialization_test.rb @@ -38,11 +38,15 @@ class XmlSerializationTest < ActiveRecord::TestCase assert_match %r{<CreatedAt}, @xml end + def test_should_allow_skipped_types + @xml = Contact.new(:age => 25).to_xml :skip_types => true + assert %r{<age>25</age>}.match(@xml) + end + def test_should_include_yielded_additions @xml = Contact.new.to_xml do |xml| xml.creator "David" end - assert_match %r{<creator>David</creator>}, @xml end end @@ -145,6 +149,13 @@ class DatabaseConnectedXmlSerializationTest < ActiveRecord::TestCase assert_match %r{<hello-post type="StiPost">}, xml end + def test_included_associations_should_skip_types + xml = authors(:david).to_xml :include=>:hello_posts, :indent => 0, :skip_types => true + assert_match %r{<hello-posts>}, xml + assert_match %r{<hello-post>}, xml + assert_match %r{<hello-post>}, xml + end + def test_methods_are_called_on_object xml = authors(:david).to_xml :methods => :label, :indent => 0 assert_match %r{<label>.*</label>}, xml diff --git a/activerecord/test/fixtures/toys.yml b/activerecord/test/fixtures/toys.yml new file mode 100644 index 0000000000..037e335e0a --- /dev/null +++ b/activerecord/test/fixtures/toys.yml @@ -0,0 +1,4 @@ +bone: + toy_id: 1 + name: Bone + pet_id: 1 diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 3b27a9e272..02a775f9ef 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -37,6 +37,7 @@ class Firm < Company has_many :clients, :order => "id", :dependent => :destroy, :counter_sql => "SELECT COUNT(*) FROM companies WHERE firm_id = 1 " + "AND (#{QUOTED_TYPE} = 'Client' OR #{QUOTED_TYPE} = 'SpecialClient' OR #{QUOTED_TYPE} = 'VerySpecialClient' )" + has_many :unsorted_clients, :class_name => "Client" has_many :clients_sorted_desc, :class_name => "Client", :order => "id DESC" has_many :clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id" has_many :unvalidated_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :validate => false @@ -69,6 +70,7 @@ class Firm < Company has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account' has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true has_one :account_using_primary_key, :primary_key => "firm_id", :class_name => "Account" + has_one :deletable_account, :foreign_key => "firm_id", :class_name => "Account", :dependent => :delete end class DependentFirm < Company diff --git a/activerecord/test/models/event.rb b/activerecord/test/models/event.rb new file mode 100644 index 0000000000..99fa0feeb7 --- /dev/null +++ b/activerecord/test/models/event.rb @@ -0,0 +1,3 @@ +class Event < ActiveRecord::Base + validates_uniqueness_of :title +end
\ No newline at end of file diff --git a/activerecord/test/models/owner.rb b/activerecord/test/models/owner.rb index dbaf2ce688..5760b991ec 100644 --- a/activerecord/test/models/owner.rb +++ b/activerecord/test/models/owner.rb @@ -1,4 +1,5 @@ class Owner < ActiveRecord::Base set_primary_key :owner_id has_many :pets -end
\ No newline at end of file + has_many :toys, :through => :pets +end diff --git a/activerecord/test/models/pet.rb b/activerecord/test/models/pet.rb index 889ce46f33..dc1a3c5e94 100644 --- a/activerecord/test/models/pet.rb +++ b/activerecord/test/models/pet.rb @@ -1,4 +1,5 @@ class Pet < ActiveRecord::Base set_primary_key :pet_id belongs_to :owner -end
\ No newline at end of file + has_many :toys +end diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb index 7bc50e0e7b..238917bf30 100644 --- a/activerecord/test/models/pirate.rb +++ b/activerecord/test/models/pirate.rb @@ -1,16 +1,63 @@ class Pirate < ActiveRecord::Base belongs_to :parrot has_and_belongs_to_many :parrots - has_many :treasures, :as => :looter + has_and_belongs_to_many :parrots_with_method_callbacks, :class_name => "Parrot", + :before_add => :log_before_add, + :after_add => :log_after_add, + :before_remove => :log_before_remove, + :after_remove => :log_after_remove + has_and_belongs_to_many :parrots_with_proc_callbacks, :class_name => "Parrot", + :before_add => proc {|p,pa| p.ship_log << "before_adding_proc_parrot_#{pa.id || '<new>'}"}, + :after_add => proc {|p,pa| p.ship_log << "after_adding_proc_parrot_#{pa.id || '<new>'}"}, + :before_remove => proc {|p,pa| p.ship_log << "before_removing_proc_parrot_#{pa.id}"}, + :after_remove => proc {|p,pa| p.ship_log << "after_removing_proc_parrot_#{pa.id}"} + has_many :treasures, :as => :looter has_many :treasure_estimates, :through => :treasures, :source => :price_estimates # These both have :autosave enabled because accepts_nested_attributes_for is used on them. has_one :ship has_many :birds + has_many :birds_with_method_callbacks, :class_name => "Bird", + :before_add => :log_before_add, + :after_add => :log_after_add, + :before_remove => :log_before_remove, + :after_remove => :log_after_remove + has_many :birds_with_proc_callbacks, :class_name => "Bird", + :before_add => proc {|p,b| p.ship_log << "before_adding_proc_bird_#{b.id || '<new>'}"}, + :after_add => proc {|p,b| p.ship_log << "after_adding_proc_bird_#{b.id || '<new>'}"}, + :before_remove => proc {|p,b| p.ship_log << "before_removing_proc_bird_#{b.id}"}, + :after_remove => proc {|p,b| p.ship_log << "after_removing_proc_bird_#{b.id}"} accepts_nested_attributes_for :parrots, :birds, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } + accepts_nested_attributes_for :parrots_with_method_callbacks, :parrots_with_proc_callbacks, + :birds_with_method_callbacks, :birds_with_proc_callbacks, :allow_destroy => true validates_presence_of :catchphrase + + def ship_log + @ship_log ||= [] + end + + private + def log_before_add(record) + log(record, "before_adding_method") + end + + def log_after_add(record) + log(record, "after_adding_method") + end + + def log_before_remove(record) + log(record, "before_removing_method") + end + + def log_after_remove(record) + log(record, "after_removing_method") + end + + def log(record, callback) + ship_log << "#{callback}_#{record.class.name.downcase}_#{record.id || '<new>'}" + end end diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 388fff8fba..374e536a5b 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -1,5 +1,7 @@ class Post < ActiveRecord::Base named_scope :containing_the_letter_a, :conditions => "body LIKE '%a%'" + named_scope :ranked_by_comments, :order => "comments_count DESC" + named_scope :limit, lambda {|limit| {:limit => limit} } named_scope :with_authors_at_address, lambda { |address| { :conditions => [ 'authors.author_address_id = ?', address.id ], :joins => 'JOIN authors ON authors.id = posts.author_id' @@ -68,6 +70,10 @@ class Post < ActiveRecord::Base :before_remove => lambda {|owner, reader| log(:removed, :before, reader.first_name) }, :after_remove => lambda {|owner, reader| log(:removed, :after, reader.first_name) } + def self.top(limit) + ranked_by_comments.limit(limit) + end + def self.reset_log @log = [] end diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb index 812bc1f535..1c990acab6 100644 --- a/activerecord/test/models/reply.rb +++ b/activerecord/test/models/reply.rb @@ -37,3 +37,9 @@ end class SillyReply < Reply belongs_to :reply, :foreign_key => "parent_id", :counter_cache => :replies_count end + +module Web + class Reply < Web::Topic + belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true, :class_name => 'Web::Topic' + end +end
\ No newline at end of file diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 08bb24ed03..51012d22ed 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -1,7 +1,9 @@ class Topic < ActiveRecord::Base named_scope :base named_scope :written_before, lambda { |time| - { :conditions => ['written_on < ?', time] } + if time + { :conditions => ['written_on < ?', time] } + end } named_scope :approved, :conditions => {:approved => true} named_scope :rejected, :conditions => {:approved => false} @@ -33,6 +35,8 @@ class Topic < ActiveRecord::Base end named_scope :named_extension, :extend => NamedExtension named_scope :multiple_extensions, :extend => [MultipleExtensionTwo, MultipleExtensionOne] + + named_scope :by_rejected_ids, lambda {{ :conditions => { :id => all(:conditions => {:approved => false}).map(&:id) } }} has_many :replies, :dependent => :destroy, :foreign_key => "parent_id" serialize :content @@ -69,3 +73,9 @@ class Topic < ActiveRecord::Base end end end + +module Web + class Topic < ActiveRecord::Base + has_many :replies, :dependent => :destroy, :foreign_key => "parent_id", :class_name => 'Web::Reply' + end +end
\ No newline at end of file diff --git a/activerecord/test/models/toy.rb b/activerecord/test/models/toy.rb new file mode 100644 index 0000000000..79a88db0da --- /dev/null +++ b/activerecord/test/models/toy.rb @@ -0,0 +1,4 @@ +class Toy < ActiveRecord::Base + set_primary_key :toy_id + belongs_to :pet +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 74a893983f..ea848a2940 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -155,6 +155,10 @@ ActiveRecord::Schema.define do t.integer :course_id, :null => false end + create_table :events, :force => true do |t| + t.string :title, :limit => 5 + end + create_table :funny_jokes, :force => true do |t| t.string :name end @@ -421,6 +425,11 @@ ActiveRecord::Schema.define do t.column :taggings_count, :integer, :default => 0 end + create_table :toys, :primary_key => :toy_id ,:force => true do |t| + t.string :name + t.integer :pet_id, :integer + end + create_table :treasures, :force => true do |t| t.column :name, :string t.column :looter_id, :integer |