diff options
Diffstat (limited to 'activerecord/test')
73 files changed, 3337 insertions, 0 deletions
diff --git a/activerecord/test/abstract_unit.rb b/activerecord/test/abstract_unit.rb new file mode 100755 index 0000000000..1b33579206 --- /dev/null +++ b/activerecord/test/abstract_unit.rb @@ -0,0 +1,22 @@ +$:.unshift(File.dirname(__FILE__) + '/../lib')#.unshift(File.dirname(__FILE__)) + +# Make rubygems available for testing if possible +begin require('rubygems'); rescue LoadError; end +begin require('dev-utils/debug'); rescue LoadError; end + +require 'test/unit' +require 'active_record' +require 'active_record/fixtures' +require 'connection' + +class Test::Unit::TestCase #:nodoc: + def create_fixtures(*table_names) + if block_given? + Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names) { yield } + else + Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names) + end + end +end + +Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
\ No newline at end of file diff --git a/activerecord/test/aggregations_test.rb b/activerecord/test/aggregations_test.rb new file mode 100644 index 0000000000..2eff36dc73 --- /dev/null +++ b/activerecord/test/aggregations_test.rb @@ -0,0 +1,34 @@ +require 'abstract_unit' +# require File.dirname(__FILE__) + '/../dev-utils/eval_debugger' +require 'fixtures/customer' + +class AggregationsTest < Test::Unit::TestCase + def setup + @customers = create_fixtures "customers" + @david = Customer.find(1) + end + + def test_find_single_value_object + assert_equal 50, @david.balance.amount + assert_kind_of Money, @david.balance + assert_equal 300, @david.balance.exchange_to("DKK").amount + end + + def test_find_multiple_value_object + assert_equal @customers["david"]["address_street"], @david.address.street + assert( + @david.address.close_to?(Address.new("Different Street", @customers["david"]["address_city"], @customers["david"]["address_country"])) + ) + end + + def test_change_single_value_object + @david.balance = Money.new(100) + @david.save + assert_equal 100, Customer.find(1).balance.amount + end + + def test_immutable_value_objects + @david.balance = Money.new(100) + assert_raises(TypeError) { @david.balance.instance_eval { @amount = 20 } } + end +end
\ No newline at end of file diff --git a/activerecord/test/all.sh b/activerecord/test/all.sh new file mode 100755 index 0000000000..a6712cc48e --- /dev/null +++ b/activerecord/test/all.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -z "$1" ]; then + echo "Usage: $0 connections/<db_library>" 1>&2 + exit 1 +fi + +ruby -I $1 -e 'Dir.foreach(".") { |file| require file if file =~ /_test.rb$/ }' diff --git a/activerecord/test/associations_test.rb b/activerecord/test/associations_test.rb new file mode 100755 index 0000000000..2eb6ba267e --- /dev/null +++ b/activerecord/test/associations_test.rb @@ -0,0 +1,549 @@ +require 'abstract_unit' +require 'fixtures/developer' +require 'fixtures/project' +# require File.dirname(__FILE__) + '/../dev-utils/eval_debugger' +require 'fixtures/company' +require 'fixtures/topic' +require 'fixtures/reply' + +# Can't declare new classes in test case methods, so tests before that +bad_collection_keys = false +begin + class Car < ActiveRecord::Base; has_many :wheels, :name => "wheels"; end +rescue ActiveRecord::ActiveRecordError + bad_collection_keys = true +end +raise "ActiveRecord should have barked on bad collection keys" unless bad_collection_keys + + +class AssociationsTest < Test::Unit::TestCase + def setup + create_fixtures "accounts", "companies", "accounts", "developers", "projects", "developers_projects" + @signals37 = Firm.find(1) + end + + def test_force_reload + firm = Firm.new + firm.save + firm.clients.each {|c|} # forcing to load all clients + assert firm.clients.empty?, "New firm shouldn't have client objects" + assert !firm.has_clients?, "New firm shouldn't have clients" + assert_equal 0, firm.clients.size, "New firm should have 0 clients" + + client = Client.new("firm_id" => firm.id) + client.save + + assert firm.clients.empty?, "New firm should have cached no client objects" + assert !firm.has_clients?, "New firm should have cached a no-clients response" + assert_equal 0, firm.clients.size, "New firm should have cached 0 clients count" + + assert !firm.clients(true).empty?, "New firm should have reloaded client objects" + assert_equal 1, firm.clients(true).size, "New firm should have reloaded clients count" + end + + def test_storing_in_pstore + require "tmpdir" + store_filename = File.join(Dir.tmpdir, "ar-pstore-association-test") + File.delete(store_filename) if File.exists?(store_filename) + require "pstore" + apple = Firm.create("name" => "Apple") + natural = Client.new("name" => "Natural Company") + apple.clients << natural + + db = PStore.new(store_filename) + db.transaction do + db["apple"] = apple + end + + db = PStore.new(store_filename) + db.transaction do + assert_equal "Natural Company", db["apple"].clients.first.name + end + end +end + +class HasOneAssociationsTest < Test::Unit::TestCase + def setup + create_fixtures "accounts", "companies", "accounts", "developers", "projects", "developers_projects" + @signals37 = Firm.find(1) + end + + def test_has_one + assert_equal @signals37.account, Account.find(1) + assert_equal Account.find(1).credit_limit, @signals37.account.credit_limit + assert @signals37.has_account?, "37signals should have an account" + assert Account.find(1).firm?(@signals37), "37signals account should be able to backtrack" + assert Account.find(1).has_firm?, "37signals account should be able to backtrack" + + assert !Account.find(2).has_firm?, "Unknown isn't linked" + assert !Account.find(2).firm?(@signals37), "Unknown isn't linked" + end + + def test_type_mismatch + assert_raises(ActiveRecord::AssociationTypeMismatch) { @signals37.account = 1 } + assert_raises(ActiveRecord::AssociationTypeMismatch) { @signals37.account = Project.find(1) } + end + + def test_natural_assignment + apple = Firm.create("name" => "Apple") + citibank = Account.create("credit_limit" => 10) + apple.account = citibank + assert_equal apple.id, citibank.firm_id + end + + def test_natural_assignment_to_nil + old_account_id = @signals37.account.id + @signals37.account = nil + @signals37.save + assert_nil @signals37.account + assert_nil Account.find(old_account_id).firm_id + end + + def test_build + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + + account = firm.build_account("credit_limit" => 1000) + assert account.save + assert_equal account, firm.account + end + + def test_failing_build_association + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + + account = firm.build_account + assert !account.save + assert_equal "can't be empty", account.errors.on("credit_limit") + end + + def test_create + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + assert_equal firm.create_account("credit_limit" => 1000), firm.account + end + + def test_dependence + firm = Firm.find(1) + assert !firm.account.nil? + firm.destroy + assert_equal 1, Account.find_all.length + end + + def test_dependence_with_missing_association + Account.destroy_all + firm = Firm.find(1) + assert !firm.has_account? + firm.destroy + end +end + + +class HasManyAssociationsTest < Test::Unit::TestCase + def setup + create_fixtures "accounts", "companies", "accounts", "developers", "projects", "developers_projects", "topics" + @signals37 = Firm.find(1) + end + + def force_signal37_to_load_all_clients_of_firm + @signals37.clients_of_firm.each {|f| } + end + + def test_finding + assert_equal 2, Firm.find_first.clients.length + end + + def test_finding_default_orders + assert_equal "Summit", Firm.find_first.clients.first.name + end + + def test_finding_with_different_class_name_and_order + assert_equal "Microsoft", Firm.find_first.clients_sorted_desc.first.name + end + + def test_finding_with_foreign_key + assert_equal "Microsoft", Firm.find_first.clients_of_firm.first.name + end + + def test_finding_with_condition + assert_equal "Microsoft", Firm.find_first.clients_like_ms.first.name + end + + def test_finding_using_sql + firm = Firm.find_first + first_client = firm.clients_using_sql.first + assert_not_nil first_client + assert_equal "Microsoft", first_client.name + assert_equal 1, firm.clients_using_sql.size + assert_equal 1, Firm.find_first.clients_using_sql.size + end + + def test_find_all + assert_equal 2, Firm.find_first.clients.find_all("type = 'Client'").length + assert_equal 1, Firm.find_first.clients.find_all("name = 'Summit'").length + end + + def test_find_all_sanitized + firm = Firm.find_first + assert_equal firm.clients.find_all("name = 'Summit'"), firm.clients.find_all(["name = '%s'", "Summit"]) + end + + def test_find_in_collection + assert_equal Client.find(2).name, @signals37.clients.find(2).name + assert_equal Client.find(2).name, @signals37.clients.find {|c| c.name == @signals37.clients.find(2).name }.name + assert_raises(ActiveRecord::RecordNotFound) { @signals37.clients.find(6) } + end + + def test_adding + force_signal37_to_load_all_clients_of_firm + natural = Client.new("name" => "Natural Company") + @signals37.clients_of_firm << natural + assert_equal 2, @signals37.clients_of_firm.size # checking via the collection + assert_equal 2, @signals37.clients_of_firm(true).size # checking using the db + assert_equal natural, @signals37.clients_of_firm.last + end + + def test_adding_a_mismatch_class + assert_raises(ActiveRecord::AssociationTypeMismatch) { @signals37.clients_of_firm << nil } + assert_raises(ActiveRecord::AssociationTypeMismatch) { @signals37.clients_of_firm << 1 } + assert_raises(ActiveRecord::AssociationTypeMismatch) { @signals37.clients_of_firm << Topic.find(1) } + end + + def test_adding_a_collection + force_signal37_to_load_all_clients_of_firm + @signals37.clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")]) + assert_equal 3, @signals37.clients_of_firm.size + assert_equal 3, @signals37.clients_of_firm(true).size + end + + def test_build + new_client = @signals37.clients_of_firm.build("name" => "Another Client") + assert_equal "Another Client", new_client.name + assert new_client.save + assert_equal 2, @signals37.clients_of_firm(true).size + end + + def test_create + force_signal37_to_load_all_clients_of_firm + new_client = @signals37.clients_of_firm.create("name" => "Another Client") + assert_equal new_client, @signals37.clients_of_firm.last + assert_equal new_client, @signals37.clients_of_firm(true).last + end + + def test_deleting + force_signal37_to_load_all_clients_of_firm + @signals37.clients_of_firm.delete(@signals37.clients_of_firm.first) + assert_equal 0, @signals37.clients_of_firm.size + assert_equal 0, @signals37.clients_of_firm(true).size + end + + def test_deleting_a_collection + force_signal37_to_load_all_clients_of_firm + @signals37.clients_of_firm.create("name" => "Another Client") + assert_equal 2, @signals37.clients_of_firm.size + #@signals37.clients_of_firm.clear + @signals37.clients_of_firm.delete([@signals37.clients_of_firm[0], @signals37.clients_of_firm[1]]) + assert_equal 0, @signals37.clients_of_firm.size + assert_equal 0, @signals37.clients_of_firm(true).size + end + + def test_deleting_a_association_collection + force_signal37_to_load_all_clients_of_firm + @signals37.clients_of_firm.create("name" => "Another Client") + assert_equal 2, @signals37.clients_of_firm.size + @signals37.clients_of_firm.clear + assert_equal 0, @signals37.clients_of_firm.size + assert_equal 0, @signals37.clients_of_firm(true).size + end + + def test_deleting_a_item_which_is_not_in_the_collection + force_signal37_to_load_all_clients_of_firm + summit = Client.find_first("name = 'Summit'") + @signals37.clients_of_firm.delete(summit) + assert_equal 1, @signals37.clients_of_firm.size + assert_equal 1, @signals37.clients_of_firm(true).size + assert_equal 2, summit.client_of + end + + def test_deleting_type_mismatch + david = Developer.find(1) + david.projects.id + assert_raises(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(1) } + end + + def test_deleting_self_type_mismatch + david = Developer.find(1) + david.projects.id + assert_raises(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(Project.find(1).developers) } + end + + def test_destroy_all + force_signal37_to_load_all_clients_of_firm + assert !@signals37.clients_of_firm.empty?, "37signals has clients after load" + @signals37.clients_of_firm.destroy_all + assert @signals37.clients_of_firm.empty?, "37signals has no clients after destroy all" + assert @signals37.clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh" + end + + def test_dependence + assert_equal 2, Client.find_all.length + Firm.find_first.destroy + assert_equal 0, Client.find_all.length + end + + def test_dependence_with_transaction_support_on_failure + assert_equal 2, Client.find_all.length + firm = Firm.find_first + clients = firm.clients + clients.last.instance_eval { def before_destroy() raise "Trigger rollback" end } + + firm.destroy rescue "do nothing" + + assert_equal 2, Client.find_all.length + end + + def test_dependence_on_account + assert_equal 2, Account.find_all.length + @signals37.destroy + assert_equal 1, Account.find_all.length + end + + def test_included_in_collection + assert @signals37.clients.include?(Client.find(2)) + end + + def test_adding_array_and_collection + assert_nothing_raised { Firm.find_first.clients + Firm.find_all.last.clients } + end +end + +class BelongsToAssociationsTest < Test::Unit::TestCase + def setup + create_fixtures "accounts", "companies", "accounts", "developers", "projects", "developers_projects", "topics" + @signals37 = Firm.find(1) + end + + def test_belongs_to + Client.find(3).firm.name + assert_equal @signals37.name, Client.find(3).firm.name + assert !Client.find(3).firm.nil?, "Microsoft should have a firm" + end + + def test_type_mismatch + assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 } + assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) } + end + + def test_natural_assignment + apple = Firm.create("name" => "Apple") + citibank = Account.create("credit_limit" => 10) + citibank.firm = apple + assert_equal apple.id, citibank.firm_id + end + + def test_natural_assignment_to_nil + client = Client.find(3) + client.firm = nil + client.save + assert_nil client.firm(true) + assert_nil client.client_of + end + + def test_with_different_class_name + assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name + assert_not_nil Company.find(3).firm_with_other_name, "Microsoft should have a firm" + end + + def test_with_condition + assert_equal Company.find(1).name, Company.find(3).firm_with_condition.name + assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm" + end + + def test_belongs_to_counter + debate = Topic.create("title" => "debate") + assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet" + + trash = debate.replies.create("title" => "blah!", "content" => "world around!") + assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply created" + + trash.destroy + assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted" + end + + def xtest_counter_cache + apple = Firm.create("name" => "Apple") + final_cut = apple.clients.create("name" => "Final Cut") + + apple.clients.to_s + assert_equal 1, apple.clients.size, "Created one client" + + apple.companies_count = 2 + apple.save + + apple = Firm.find_first("name = 'Apple'") + assert_equal 2, apple.clients.size, "Should use the new cached number" + + apple.clients.to_s + assert_equal 1, apple.clients.size, "Should not use the cached number, but go to the database" + end +end + + +class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase + def setup + @accounts, @companies, @developers, @projects, @developers_projects = + create_fixtures "accounts", "companies", "developers", "projects", "developers_projects" + + @signals37 = Firm.find(1) + end + + def test_has_and_belongs_to_many + david = Developer.find(1) + + assert !david.projects.empty? + assert_equal 2, david.projects.size + + active_record = Project.find(1) + assert !active_record.developers.empty? + assert_equal 2, active_record.developers.size + assert_equal david.name, active_record.developers.first.name + end + + def test_adding_single + jamis = Developer.find(2) + jamis.projects.id # causing the collection to load + action_controller = Project.find(2) + assert_equal 1, jamis.projects.size + assert_equal 1, action_controller.developers.size + + jamis.projects << action_controller + + assert_equal 2, jamis.projects.size + assert_equal 2, jamis.projects(true).size + assert_equal 2, action_controller.developers(true).size + end + + def test_adding_type_mismatch + jamis = Developer.find(2) + assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << nil } + assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << 1 } + end + + def test_adding_from_the_project + jamis = Developer.find(2) + action_controller = Project.find(2) + action_controller.developers.id + assert_equal 1, jamis.projects.size + assert_equal 1, action_controller.developers.size + + action_controller.developers << jamis + + assert_equal 2, jamis.projects(true).size + assert_equal 2, action_controller.developers.size + assert_equal 2, action_controller.developers(true).size + end + + def test_adding_multiple + aridridel = Developer.new("name" => "Aridridel") + aridridel.save + aridridel.projects.id + aridridel.projects.push(Project.find(1), Project.find(2)) + assert_equal 2, aridridel.projects.size + assert_equal 2, aridridel.projects(true).size + end + + def test_adding_a_collection + aridridel = Developer.new("name" => "Aridridel") + aridridel.save + aridridel.projects.id + aridridel.projects.concat([Project.find(1), Project.find(2)]) + assert_equal 2, aridridel.projects.size + assert_equal 2, aridridel.projects(true).size + end + + def test_uniq_after_the_fact + @developers["jamis"].find.projects << @projects["active_record"].find + @developers["jamis"].find.projects << @projects["active_record"].find + assert_equal 3, @developers["jamis"].find.projects.size + assert_equal 1, @developers["jamis"].find.projects.uniq.size + end + + def test_uniq_before_the_fact + @projects["active_record"].find.developers << @developers["jamis"].find + @projects["active_record"].find.developers << @developers["david"].find + assert_equal 2, @projects["active_record"].find.developers.size + end + + def test_deleting + david = Developer.find(1) + active_record = Project.find(1) + david.projects.id + assert_equal 2, david.projects.size + assert_equal 2, active_record.developers.size + + david.projects.delete(active_record) + + assert_equal 1, david.projects.size + assert_equal 1, david.projects(true).size + assert_equal 1, active_record.developers(true).size + end + + def test_deleting_array + david = Developer.find(1) + david.projects.id + david.projects.delete(Project.find_all) + assert_equal 0, david.projects.size + assert_equal 0, david.projects(true).size + end + + def test_deleting_all + david = Developer.find(1) + david.projects.id + david.projects.clear + assert_equal 0, david.projects.size + assert_equal 0, david.projects(true).size + end + + def test_removing_associations_on_destroy + Developer.find(1).destroy + assert Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = '1'").empty? + end + + def test_additional_columns_from_join_table + assert_equal Date.new(2004, 10, 10).to_s, Developer.find(1).projects.first.joined_on.to_s + end + + def test_destroy_all + david = Developer.find(1) + david.projects.id + assert !david.projects.empty? + david.projects.destroy_all + assert david.projects.empty? + assert david.projects(true).empty? + end + + def test_rich_association + @jamis = @developers["jamis"].find + @jamis.projects.push_with_attributes(@projects["action_controller"].find, :joined_on => Date.today) + assert_equal Date.today.to_s, @jamis.projects.select { |p| p.name == @projects["action_controller"]["name"] }.first.joined_on.to_s + assert_equal Date.today.to_s, @developers["jamis"].find.projects.select { |p| p.name == @projects["action_controller"]["name"] }.first.joined_on.to_s + end + + def test_associations_with_conditions + assert_equal 2, @projects["active_record"].find.developers.size + assert_equal 1, @projects["active_record"].find.developers_named_david.size + + @projects["active_record"].find.developers_named_david.clear + assert_equal 1, @projects["active_record"].find.developers.size + end + + def test_find_in_association + # Using sql + assert_equal @developers["david"].find, @projects["active_record"].find.developers.find(@developers["david"]["id"]), "SQL find" + + # Using ruby + @active_record = @projects["active_record"].find + @active_record.developers.reload + assert_equal @developers["david"].find, @active_record.developers.find(@developers["david"]["id"]), "Ruby find" + end +end diff --git a/activerecord/test/base_test.rb b/activerecord/test/base_test.rb new file mode 100755 index 0000000000..0d2278eb58 --- /dev/null +++ b/activerecord/test/base_test.rb @@ -0,0 +1,544 @@ +require 'abstract_unit' +require 'fixtures/topic' +require 'fixtures/reply' +require 'fixtures/company' +require 'fixtures/default' +require 'fixtures/auto_id' +require 'fixtures/column_name' + +class Category < ActiveRecord::Base; end +class Smarts < ActiveRecord::Base; end +class CreditCard < ActiveRecord::Base; end +class MasterCreditCard < ActiveRecord::Base; end + +class LoosePerson < ActiveRecord::Base + attr_protected :credit_rating, :administrator +end + +class TightPerson < ActiveRecord::Base + attr_accessible :name, :address +end + +class TightDescendent < TightPerson + attr_accessible :phone_number +end + +class Booleantest < ActiveRecord::Base; end + +class BasicsTest < Test::Unit::TestCase + def setup + @topic_fixtures, @companies = create_fixtures "topics", "companies" + end + + def test_set_attributes + topic = Topic.find(1) + topic.attributes = { "title" => "Budget", "author_name" => "Jason" } + topic.save + assert_equal("Budget", topic.title) + assert_equal("Jason", topic.author_name) + assert_equal(@topic_fixtures["first"]["author_email_address"], Topic.find(1).author_email_address) + end + + def test_integers_as_nil + Topic.update(1, "approved" => "") + assert_nil Topic.find(1).approved + end + + def test_set_attributes_with_block + topic = Topic.new do |t| + t.title = "Budget" + t.author_name = "Jason" + end + + assert_equal("Budget", topic.title) + assert_equal("Jason", topic.author_name) + end + + def test_respond_to? + topic = Topic.find(1) + assert topic.respond_to?("title") + assert topic.respond_to?("title?") + assert topic.respond_to?("title=") + assert topic.respond_to?(:title) + assert topic.respond_to?(:title?) + assert topic.respond_to?(:title=) + assert topic.respond_to?("author_name") + assert topic.respond_to?("attribute_names") + assert !topic.respond_to?("nothingness") + assert !topic.respond_to?(:nothingness) + end + + def test_array_content + topic = Topic.new + topic.content = %w( one two three ) + topic.save + + assert_equal(%w( one two three ), Topic.find(topic.id).content) + end + + def test_hash_content + topic = Topic.new + topic.content = { "one" => 1, "two" => 2 } + topic.save + + assert_equal 2, Topic.find(topic.id).content["two"] + + topic.content["three"] = 3 + topic.save + + assert_equal 3, Topic.find(topic.id).content["three"] + end + + def test_update_array_content + topic = Topic.new + topic.content = %w( one two three ) + + topic.content.push "four" + assert_equal(%w( one two three four ), topic.content) + + topic.save + + topic = Topic.find(topic.id) + topic.content << "five" + assert_equal(%w( one two three four five ), topic.content) + end + + def test_create + topic = Topic.new + topic.title = "New Topic" + topic.save + id = topic.id + topicReloaded = Topic.find(id) + assert_equal("New Topic", topicReloaded.title) + end + + def test_create_through_factory + topic = Topic.create("title" => "New Topic") + topicReloaded = Topic.find(topic.id) + assert_equal(topic, topicReloaded) + end + + def test_update + topic = Topic.new + topic.title = "Another New Topic" + topic.written_on = "2003-12-12 23:23" + topic.save + id = topic.id + assert_equal(id, topic.id) + + topicReloaded = Topic.find(id) + assert_equal("Another New Topic", topicReloaded.title) + + topicReloaded.title = "Updated topic" + topicReloaded.save + + topicReloadedAgain = Topic.find(id) + + assert_equal("Updated topic", topicReloadedAgain.title) + end + + def test_preserving_date_objects + # SQL Server doesn't have a separate column type just for dates, so all are returned as time + if ActiveRecord::ConnectionAdapters.const_defined? :SQLServerAdapter + return true if ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::SQLServerAdapter) + end + + assert_kind_of( + Date, Topic.find(1).last_read, + "The last_read attribute should be of the Date class" + ) + end + + def test_preserving_time_objects + assert_kind_of( + Time, Topic.find(1).written_on, + "The written_on attribute should be of the Time class" + ) + end + + def test_destroy + topic = Topic.new + topic.title = "Yet Another New Topic" + topic.written_on = "2003-12-12 23:23" + topic.save + id = topic.id + topic.destroy + + assert_raises(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(id) } + end + + def test_record_not_found_exception + assert_raises(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(id) } + end + + def test_initialize_with_attributes + topic = Topic.new({ + "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23" + }) + + assert_equal("initialized from attributes", topic.title) + end + + def test_load + topics = Topic.find_all nil, "id" + assert_equal(2, topics.size) + assert_equal(@topic_fixtures["first"]["title"], topics.first.title) + end + + def test_load_with_condition + topics = Topic.find_all "author_name = 'Mary'" + + assert_equal(1, topics.size) + assert_equal(@topic_fixtures["second"]["title"], topics.first.title) + end + + def test_table_name_guesses + assert_equal "topics", Topic.table_name + + assert_equal "categories", Category.table_name + assert_equal "smarts", Smarts.table_name + assert_equal "credit_cards", CreditCard.table_name + assert_equal "master_credit_cards", MasterCreditCard.table_name + + ActiveRecord::Base.pluralize_table_names = false + assert_equal "category", Category.table_name + assert_equal "smarts", Smarts.table_name + assert_equal "credit_card", CreditCard.table_name + assert_equal "master_credit_card", MasterCreditCard.table_name + ActiveRecord::Base.pluralize_table_names = true + + ActiveRecord::Base.table_name_prefix = "test_" + assert_equal "test_categories", Category.table_name + ActiveRecord::Base.table_name_suffix = "_test" + assert_equal "test_categories_test", Category.table_name + ActiveRecord::Base.table_name_prefix = "" + assert_equal "categories_test", Category.table_name + ActiveRecord::Base.table_name_suffix = "" + assert_equal "categories", Category.table_name + + ActiveRecord::Base.pluralize_table_names = false + ActiveRecord::Base.table_name_prefix = "test_" + assert_equal "test_category", Category.table_name + ActiveRecord::Base.table_name_suffix = "_test" + assert_equal "test_category_test", Category.table_name + ActiveRecord::Base.table_name_prefix = "" + assert_equal "category_test", Category.table_name + ActiveRecord::Base.table_name_suffix = "" + assert_equal "category", Category.table_name + ActiveRecord::Base.pluralize_table_names = true + end + + def test_destroy_all + assert_equal(2, Topic.find_all.size) + + Topic.destroy_all "author_name = 'Mary'" + assert_equal(1, Topic.find_all.size) + end + + def test_boolean_attributes + assert ! Topic.find(1).approved? + assert Topic.find(2).approved? + end + + def test_increment_counter + Topic.increment_counter("replies_count", 1) + assert_equal 1, Topic.find(1).replies_count + + Topic.increment_counter("replies_count", 1) + assert_equal 2, Topic.find(1).replies_count + end + + def test_decrement_counter + Topic.decrement_counter("replies_count", 2) + assert_equal 1, Topic.find(2).replies_count + + Topic.decrement_counter("replies_count", 2) + assert_equal 0, Topic.find(1).replies_count + end + + def test_update_all + Topic.update_all "content = 'bulk updated!'" + assert_equal "bulk updated!", Topic.find(1).content + assert_equal "bulk updated!", Topic.find(2).content + end + + def test_update_by_condition + Topic.update_all "content = 'bulk updated!'", "approved = 1" + assert_equal "Have a nice day", Topic.find(1).content + assert_equal "bulk updated!", Topic.find(2).content + end + + def test_attribute_present + t = Topic.new + t.title = "hello there!" + t.written_on = Time.now + assert t.attribute_present?("title") + assert t.attribute_present?("written_on") + assert !t.attribute_present?("content") + end + + def test_attribute_keys_on_new_instance + t = Topic.new + assert_equal nil, t.title, "The topics table has a title column, so it should be nil" + assert_raises(NoMethodError) { t.title2 } + end + + def test_class_name + assert_equal "Firm", ActiveRecord::Base.class_name("firms") + assert_equal "Category", ActiveRecord::Base.class_name("categories") + assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder") + + ActiveRecord::Base.pluralize_table_names = false + assert_equal "Firms", ActiveRecord::Base.class_name( "firms" ) + ActiveRecord::Base.pluralize_table_names = true + + ActiveRecord::Base.table_name_prefix = "test_" + assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms" ) + ActiveRecord::Base.table_name_suffix = "_tests" + assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms_tests" ) + ActiveRecord::Base.table_name_prefix = "" + assert_equal "Firm", ActiveRecord::Base.class_name( "firms_tests" ) + ActiveRecord::Base.table_name_suffix = "" + assert_equal "Firm", ActiveRecord::Base.class_name( "firms" ) + end + + def test_null_fields + assert_nil Topic.find(1).parent_id + assert_nil Topic.create("title" => "Hey you").parent_id + end + + def test_default_values + topic = Topic.new + assert_equal 1, topic.approved + assert_nil topic.written_on + assert_nil topic.last_read + + topic.save + + topic = Topic.find(topic.id) + assert_equal 1, topic.approved + assert_nil topic.last_read + end + + def test_default_values_on_empty_strings + topic = Topic.new + topic.approved = nil + topic.last_read = nil + + topic.save + + topic = Topic.find(topic.id) + assert_nil topic.last_read + assert_nil topic.approved + end + + def test_equality + assert_equal Topic.find(1), Topic.find(2).parent + end + + def test_hashing + assert_equal [ Topic.find(1) ], [ Topic.find(2).parent ] & [ Topic.find(1) ] + end + + def test_destroy_new_record + client = Client.new + client.destroy + assert client.frozen? + end + + def test_update_attribute + assert !Topic.find(1).approved? + Topic.find(1).update_attribute("approved", true) + assert Topic.find(1).approved? + end + + def test_mass_assignment_protection + firm = Firm.new + firm.attributes = { "name" => "Next Angle", "rating" => 5 } + assert_equal 1, firm.rating + end + + def test_mass_assignment_accessible + reply = Reply.new("title" => "hello", "content" => "world", "approved" => 0) + reply.save + + assert_equal 1, reply.approved + + reply.approved = 0 + reply.save + + assert_equal 0, reply.approved + end + + def test_mass_assignment_protection_inheritance + assert_equal [ :credit_rating, :administrator ], LoosePerson.protected_attributes + assert_nil TightPerson.protected_attributes + end + + def test_multiparameter_attributes_on_date + # SQL Server doesn't have a separate column type just for dates, so all are returned as time + if ActiveRecord::ConnectionAdapters.const_defined? :SQLServerAdapter + return true if ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::SQLServerAdapter) + end + + attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" } + topic = Topic.find(1) + topic.attributes = attributes + assert_equal Date.new(2004, 6, 24).to_s, topic.last_read.to_s + end + + def test_multiparameter_attributes_on_date_with_empty_date + # SQL Server doesn't have a separate column type just for dates, so all are returned as time + if ActiveRecord::ConnectionAdapters.const_defined? :SQLServerAdapter + return true if ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::SQLServerAdapter) + end + + attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "" } + topic = Topic.find(1) + topic.attributes = attributes + assert_equal Date.new(2004, 6, 1).to_s, topic.last_read.to_s + end + + def test_multiparameter_attributes_on_date_with_all_empty + attributes = { "last_read(1i)" => "", "last_read(2i)" => "", "last_read(3i)" => "" } + topic = Topic.find(1) + topic.attributes = attributes + assert_nil topic.last_read + end + + def test_multiparameter_attributes_on_time + attributes = { + "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24", + "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00" + } + topic = Topic.find(1) + topic.attributes = attributes + assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on + end + + def test_multiparameter_attributes_on_time_with_empty_seconds + attributes = { + "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24", + "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "" + } + topic = Topic.find(1) + topic.attributes = attributes + assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on + end + + def test_boolean + b_false = Booleantest.create({ "value" => false }) + false_id = b_false.id + b_true = Booleantest.create({ "value" => true }) + true_id = b_true.id + + b_false = Booleantest.find(false_id) + assert !b_false.value? + b_true = Booleantest.find(true_id) + assert b_true.value? + end + + def test_clone + topic = Topic.find(1) + cloned_topic = topic.clone + assert_equal topic.title, cloned_topic.title + assert cloned_topic.new_record? + + # test if the attributes have been cloned + topic.title = "a" + cloned_topic.title = "b" + assert_equal "a", topic.title + assert_equal "b", cloned_topic.title + + # test if the attribute values have been cloned + topic.title = {"a" => "b"} + cloned_topic = topic.clone + cloned_topic.title["a"] = "c" + assert_equal "b", topic.title["a"] + end + + def test_bignum + company = Company.find(1) + company.rating = 2147483647 + company.save + company = Company.find(1) + assert_equal 2147483647, company.rating + end + + def test_default + if Default.connection.class.name == 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter' + default = Default.new + + # dates / timestampts + time_format = "%m/%d/%Y %H:%M" + assert_equal Time.now.strftime(time_format), default.modified_time.strftime(time_format) + assert_equal Date.today, default.modified_date + + # fixed dates / times + assert_equal Date.new(2004, 1, 1), default.fixed_date + assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time + + # char types + assert_equal 'Y', default.char1 + assert_equal 'a varchar field', default.char2 + assert_equal 'a text field', default.char3 + end + end + + def test_auto_id + auto = AutoId.new + auto.save + assert (auto.id > 0) + end + + def quote_column_name(name) + "<#{name}>" + end + + def test_quote_keys + ar = AutoId.new + source = {"foo" => "bar", "baz" => "quux"} + actual = ar.send(:quote_columns, self, source) + inverted = actual.invert + assert_equal("<foo>", inverted["bar"]) + assert_equal("<baz>", inverted["quux"]) + end + + def test_column_name_properly_quoted + col_record = ColumnName.new + col_record.references = 40 + col_record.save + col_record.references = 41 + col_record.save + c2 = ColumnName.find(col_record.id) + assert_equal(41, c2.references) + end + + MyObject = Struct.new :attribute1, :attribute2 + + def test_serialized_attribute + myobj = MyObject.new('value1', 'value2') + topic = Topic.create("content" => myobj) + Topic.serialize("content", MyObject) + assert_equal(myobj, topic.content) + end + + def test_serialized_attribute_with_class_constraint + myobj = MyObject.new('value1', 'value2') + topic = Topic.create("content" => myobj) + Topic.serialize(:content, Hash) + + assert_raises(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content } + + settings = { "color" => "blue" } + Topic.find(topic.id).update_attribute("content", settings) + assert_equal(settings, Topic.find(topic.id).content) + Topic.serialize(:content) + end + + def test_quote + content = "\\ \001 ' \n \\n \"" + topic = Topic.create('content' => content) + assert_equal content, Topic.find(topic.id).content + end +end diff --git a/activerecord/test/class_inheritable_attributes_test.rb b/activerecord/test/class_inheritable_attributes_test.rb new file mode 100644 index 0000000000..00a6945a66 --- /dev/null +++ b/activerecord/test/class_inheritable_attributes_test.rb @@ -0,0 +1,33 @@ +$:.unshift(File.dirname(__FILE__) + '/../lib') + +require 'test/unit' +require 'active_record/support/class_inheritable_attributes' + +class A + include ClassInheritableAttributes +end + +class B < A + write_inheritable_array "first", [ :one, :two ] +end + +class C < A + write_inheritable_array "first", [ :three ] +end + +class D < B + write_inheritable_array "first", [ :four ] +end + + +class ClassInheritableAttributesTest < Test::Unit::TestCase + def test_first_level + assert_equal [ :one, :two ], B.read_inheritable_attribute("first") + assert_equal [ :three ], C.read_inheritable_attribute("first") + end + + def test_second_level + assert_equal [ :one, :two, :four ], D.read_inheritable_attribute("first") + assert_equal [ :one, :two ], B.read_inheritable_attribute("first") + end +end
\ No newline at end of file diff --git a/activerecord/test/connections/native_mysql/connection.rb b/activerecord/test/connections/native_mysql/connection.rb new file mode 100644 index 0000000000..b663106d1f --- /dev/null +++ b/activerecord/test/connections/native_mysql/connection.rb @@ -0,0 +1,24 @@ +print "Using native MySQL\n" +require 'fixtures/course' +require 'logger' + +ActiveRecord::Base.logger = Logger.new("debug.log") + +db1 = 'activerecord_unittest' +db2 = 'activerecord_unittest2' + +ActiveRecord::Base.establish_connection( + :adapter => "mysql", + :host => "localhost", + :username => "root", + :password => "", + :database => db1 +) + +Course.establish_connection( + :adapter => "mysql", + :host => "localhost", + :username => "root", + :password => "", + :database => db2 +) diff --git a/activerecord/test/connections/native_postgresql/connection.rb b/activerecord/test/connections/native_postgresql/connection.rb new file mode 100644 index 0000000000..c9b00447f9 --- /dev/null +++ b/activerecord/test/connections/native_postgresql/connection.rb @@ -0,0 +1,24 @@ +print "Using native PostgreSQL\n" +require 'fixtures/course' +require 'logger' + +ActiveRecord::Base.logger = Logger.new("debug.log") + +db1 = 'activerecord_unittest' +db2 = 'activerecord_unittest2' + +ActiveRecord::Base.establish_connection( + :adapter => "postgresql", + :host => nil, + :username => "postgres", + :password => "postgres", + :database => db1 +) + +Course.establish_connection( + :adapter => "postgresql", + :host => nil, + :username => "postgres", + :password => "postgres", + :database => db2 +)
\ No newline at end of file diff --git a/activerecord/test/connections/native_sqlite/connection.rb b/activerecord/test/connections/native_sqlite/connection.rb new file mode 100644 index 0000000000..db688bdb70 --- /dev/null +++ b/activerecord/test/connections/native_sqlite/connection.rb @@ -0,0 +1,34 @@ +print "Using native SQlite\n" +require 'fixtures/course' +require 'logger' +ActiveRecord::Base.logger = Logger.new("debug.log") + +BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../fixtures') +sqlite_test_db = "#{BASE_DIR}/fixture_database.sqlite" +sqlite_test_db2 = "#{BASE_DIR}/fixture_database_2.sqlite" + +def make_connection(clazz, db_file, db_definitions_file) + unless File.exist?(db_file) + puts "SQLite database not found at #{db_file}. Rebuilding it." + sqlite_command = "sqlite #{db_file} 'create table a (a integer); drop table a;'" + puts "Executing '#{sqlite_command}'" + `#{sqlite_command}` + clazz.establish_connection( + :adapter => "sqlite", + :dbfile => db_file) + script = File.read("#{BASE_DIR}/db_definitions/#{db_definitions_file}") + # SQLite-Ruby has problems with semi-colon separated commands, so split and execute one at a time + script.split(';').each do + |command| + clazz.connection.execute(command) unless command.strip.empty? + end + else + clazz.establish_connection( + :adapter => "sqlite", + :dbfile => db_file) + end +end + +make_connection(ActiveRecord::Base, sqlite_test_db, 'sqlite.sql') +make_connection(Course, sqlite_test_db2, 'sqlite2.sql') + diff --git a/activerecord/test/connections/native_sqlserver/connection.rb b/activerecord/test/connections/native_sqlserver/connection.rb new file mode 100644 index 0000000000..b198f21c4b --- /dev/null +++ b/activerecord/test/connections/native_sqlserver/connection.rb @@ -0,0 +1,15 @@ +print "Using native SQLServer\n" +require 'fixtures/course' +require 'logger' + +ActiveRecord::Base.logger = Logger.new("debug.log") + +ActiveRecord::Base.establish_connection( + :adapter => "sqlserver", + :dsn => "DBI:ADO:Provider=SQLOLEDB;Data Source=(local);Initial Catalog=test;User Id=sa;Password=password;" +) + +Course.establish_connection( + :adapter => "sqlserver", + :dsn => "DBI:ADO:Provider=SQLOLEDB;Data Source=(local);Initial Catalog=test2;User Id=sa;Password=password;" +) diff --git a/activerecord/test/deprecated_associations_test.rb b/activerecord/test/deprecated_associations_test.rb new file mode 100755 index 0000000000..cb3d1aec8a --- /dev/null +++ b/activerecord/test/deprecated_associations_test.rb @@ -0,0 +1,335 @@ +require 'abstract_unit' +require 'fixtures/developer' +require 'fixtures/project' +require 'fixtures/company' +require 'fixtures/topic' +# require File.dirname(__FILE__) + '/../dev-utils/eval_debugger' +require 'fixtures/reply' + +# Can't declare new classes in test case methods, so tests before that +bad_collection_keys = false +begin + class Car < ActiveRecord::Base; has_many :wheels, :name => "wheels"; end +rescue ActiveRecord::ActiveRecordError + bad_collection_keys = true +end +raise "ActiveRecord should have barked on bad collection keys" unless bad_collection_keys + + +class DeprecatedAssociationsTest < Test::Unit::TestCase + def setup + create_fixtures "accounts", "companies", "accounts", "developers", "projects", "developers_projects", "topics" + @signals37 = Firm.find(1) + end + + def test_has_many_find + assert_equal 2, Firm.find_first.clients.length + end + + def test_has_many_orders + assert_equal "Summit", Firm.find_first.clients.first.name + end + + def test_has_many_class_name + assert_equal "Microsoft", Firm.find_first.clients_sorted_desc.first.name + end + + def test_has_many_foreign_key + assert_equal "Microsoft", Firm.find_first.clients_of_firm.first.name + end + + def test_has_many_conditions + assert_equal "Microsoft", Firm.find_first.clients_like_ms.first.name + end + + def test_has_many_sql + firm = Firm.find_first + assert_equal "Microsoft", firm.clients_using_sql.first.name + assert_equal 1, firm.clients_using_sql_count + assert_equal 1, Firm.find_first.clients_using_sql_count + end + + def test_has_many_queries + assert Firm.find_first.has_clients? + firm = Firm.find_first + assert_equal 2, firm.clients_count # tests using class count + firm.clients + assert firm.has_clients? + assert_equal 2, firm.clients_count # tests using collection length + end + + def test_has_many_dependence + assert_equal 2, Client.find_all.length + Firm.find_first.destroy + assert_equal 0, Client.find_all.length + end + + def test_has_many_dependence_with_transaction_support_on_failure + assert_equal 2, Client.find_all.length + + firm = Firm.find_first + clients = firm.clients + clients.last.instance_eval { def before_destroy() raise "Trigger rollback" end } + + firm.destroy rescue "do nothing" + + assert_equal 2, Client.find_all.length + end + + def test_has_one_dependence + firm = Firm.find(1) + assert firm.has_account? + firm.destroy + assert_equal 1, Account.find_all.length + end + + def test_has_one_dependence_with_missing_association + Account.destroy_all + firm = Firm.find(1) + assert !firm.has_account? + firm.destroy + end + + def test_belongs_to + assert_equal @signals37.name, Client.find(3).firm.name + assert Client.find(3).has_firm?, "Microsoft should have a firm" + # assert !Company.find(1).has_firm?, "37signals shouldn't have a firm" + end + + def test_belongs_to_with_different_class_name + assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name + assert Company.find(3).has_firm_with_other_name?, "Microsoft should have a firm" + end + + def test_belongs_to_with_condition + assert_equal Company.find(1).name, Company.find(3).firm_with_condition.name + assert Company.find(3).has_firm_with_condition?, "Microsoft should have a firm" + end + + + def test_belongs_to_equality + assert Company.find(3).firm?(Company.find(1)), "Microsoft should have 37signals as firm" + assert_raises(RuntimeError) { !Company.find(3).firm?(Company.find(3)) } # "Summit shouldn't have itself as firm" + end + + def test_has_one + assert @signals37.account?(Account.find(1)) + assert_equal Account.find(1).credit_limit, @signals37.account.credit_limit + assert @signals37.has_account?, "37signals should have an account" + assert Account.find(1).firm?(@signals37), "37signals account should be able to backtrack" + assert Account.find(1).has_firm?, "37signals account should be able to backtrack" + + assert !Account.find(2).has_firm?, "Unknown isn't linked" + assert !Account.find(2).firm?(@signals37), "Unknown isn't linked" + end + + def test_has_many_dependence_on_account + assert_equal 2, Account.find_all.length + @signals37.destroy + assert_equal 1, Account.find_all.length + end + + def test_find_in + assert_equal Client.find(2).name, @signals37.find_in_clients(2).name + assert_raises(ActiveRecord::RecordNotFound) { @signals37.find_in_clients(6) } + end + + def test_force_reload + firm = Firm.new + firm.save + firm.clients.each {|c|} # forcing to load all clients + assert firm.clients.empty?, "New firm shouldn't have client objects" + assert !firm.has_clients?, "New firm shouldn't have clients" + assert_equal 0, firm.clients_count, "New firm should have 0 clients" + + client = Client.new("firm_id" => firm.id) + client.save + + assert firm.clients.empty?, "New firm should have cached no client objects" + assert !firm.has_clients?, "New firm should have cached a no-clients response" + assert_equal 0, firm.clients_count, "New firm should have cached 0 clients count" + + assert !firm.clients(true).empty?, "New firm should have reloaded client objects" + assert firm.has_clients?(true), "New firm should have reloaded with a have-clients response" + assert_equal 1, firm.clients_count(true), "New firm should have reloaded clients count" + end + + def test_included_in_collection + assert @signals37.clients.include?(Client.find(2)) + end + + def test_build_to_collection + assert_equal 1, @signals37.clients_of_firm_count + new_client = @signals37.build_to_clients_of_firm("name" => "Another Client") + assert_equal "Another Client", new_client.name + assert new_client.save + + assert new_client.firm?(@signals37) + assert_equal 2, @signals37.clients_of_firm_count(true) + end + + def test_create_in_collection + assert_equal @signals37.create_in_clients_of_firm("name" => "Another Client"), @signals37.clients_of_firm(true).last + end + + def test_succesful_build_association + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + + account = firm.build_account("credit_limit" => 1000) + assert account.save + assert_equal account, firm.account + end + + def test_failing_build_association + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + + account = firm.build_account + assert !account.save + assert_equal "can't be empty", account.errors.on("credit_limit") + end + + def test_create_association + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + assert_equal firm.create_account("credit_limit" => 1000), firm.account + end + + def test_has_and_belongs_to_many + david = Developer.find(1) + assert david.has_projects? + assert_equal 2, david.projects_count + + active_record = Project.find(1) + assert active_record.has_developers? + assert_equal 2, active_record.developers_count + assert_equal david.name, active_record.developers.first.name + end + + def test_has_and_belongs_to_many_removing + david = Developer.find(1) + active_record = Project.find(1) + + david.remove_projects(active_record) + + assert_equal 1, david.projects_count + assert_equal 1, active_record.developers_count + end + + def test_has_and_belongs_to_many_zero + david = Developer.find(1) + david.remove_projects(Project.find_all) + + assert_equal 0, david.projects_count + assert !david.has_projects? + end + + def test_has_and_belongs_to_many_adding + jamis = Developer.find(2) + action_controller = Project.find(2) + + jamis.add_projects(action_controller) + + assert_equal 2, jamis.projects_count + assert_equal 2, action_controller.developers_count + end + + def test_has_and_belongs_to_many_adding_from_the_project + jamis = Developer.find(2) + action_controller = Project.find(2) + + action_controller.add_developers(jamis) + + assert_equal 2, jamis.projects_count + assert_equal 2, action_controller.developers_count + end + + def test_has_and_belongs_to_many_adding_a_collection + aridridel = Developer.new("name" => "Aridridel") + aridridel.save + + aridridel.add_projects([ Project.find(1), Project.find(2) ]) + assert_equal 2, aridridel.projects_count + end + + def test_belongs_to_counter + topic = Topic.create("title" => "Apple", "content" => "hello world") + assert_equal 0, topic.send(:read_attribute, "replies_count"), "No replies yet" + + reply = topic.create_in_replies("title" => "I'm saying no!", "content" => "over here") + assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count"), "First reply created" + + reply.destroy + assert_equal 0, Topic.find(topic.id).send(:read_attribute, "replies_count"), "First reply deleted" + end + + def test_natural_assignment_of_has_one + apple = Firm.create("name" => "Apple") + citibank = Account.create("credit_limit" => 10) + apple.account = citibank + assert_equal apple.id, citibank.firm_id + end + + def test_natural_assignment_of_belongs_to + apple = Firm.create("name" => "Apple") + citibank = Account.create("credit_limit" => 10) + citibank.firm = apple + assert_equal apple.id, citibank.firm_id + end + + def test_natural_assignment_of_has_many + apple = Firm.create("name" => "Apple") + natural = Client.new("name" => "Natural Company") + apple.clients << natural + assert_equal apple.id, natural.firm_id + assert_equal Client.find(natural.id), Firm.find(apple.id).clients.find { |c| c.id == natural.id } + apple.clients.delete natural + assert_nil Firm.find(apple.id).clients.find { |c| c.id == natural.id } + end + + + def test_natural_adding_of_has_and_belongs_to_many + rails = Project.create("name" => "Rails") + ap = Project.create("name" => "Action Pack") + john = Developer.create("name" => "John") + mike = Developer.create("name" => "Mike") + rails.developers << john + rails.developers << mike + + assert_equal Developer.find(john.id), Project.find(rails.id).developers.find { |d| d.id == john.id } + assert_equal Developer.find(mike.id), Project.find(rails.id).developers.find { |d| d.id == mike.id } + assert_equal Project.find(rails.id), Developer.find(mike.id).projects.find { |p| p.id == rails.id } + assert_equal Project.find(rails.id), Developer.find(john.id).projects.find { |p| p.id == rails.id } + ap.developers << john + assert_equal Developer.find(john.id), Project.find(ap.id).developers.find { |d| d.id == john.id } + assert_equal Project.find(ap.id), Developer.find(john.id).projects.find { |p| p.id == ap.id } + + ap.developers.delete john + assert_nil Project.find(ap.id).developers.find { |d| d.id == john.id } + assert_nil Developer.find(john.id).projects.find { |p| p.id == ap.id } + end + + def test_storing_in_pstore + require "pstore" + require "tmpdir" + apple = Firm.create("name" => "Apple") + natural = Client.new("name" => "Natural Company") + apple.clients << natural + + db = PStore.new(File.join(Dir.tmpdir, "ar-pstore-association-test")) + db.transaction do + db["apple"] = apple + end + + db = PStore.new(File.join(Dir.tmpdir, "ar-pstore-association-test")) + db.transaction do + assert_equal "Natural Company", db["apple"].clients.first.name + end + end + + def test_has_many_find_all + assert_equal 2, Firm.find_first.find_all_in_clients("type = 'Client'").length + assert_equal 1, Firm.find_first.find_all_in_clients("name = 'Summit'").length + end +end
\ No newline at end of file diff --git a/activerecord/test/finder_test.rb b/activerecord/test/finder_test.rb new file mode 100755 index 0000000000..d369f6b033 --- /dev/null +++ b/activerecord/test/finder_test.rb @@ -0,0 +1,67 @@ +require 'abstract_unit' +require 'fixtures/company' +require 'fixtures/topic' + +class FinderTest < Test::Unit::TestCase + def setup + @company_fixtures = create_fixtures("companies") + @topic_fixtures = create_fixtures("topics") + end + + def test_find + assert_equal(@topic_fixtures["first"]["title"], Topic.find(1).title) + end + + def test_find_by_ids + assert_equal(2, Topic.find(1, 2).length) + assert_equal(@topic_fixtures["second"]["title"], Topic.find([ 2 ]).title) + end + + def test_find_by_ids_missing_one + assert_raises(ActiveRecord::RecordNotFound) { + Topic.find(1, 2, 45) + } + end + + def test_find_with_entire_select_statement + topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'" + + assert_equal(1, topics.size) + assert_equal(@topic_fixtures["second"]["title"], topics.first.title) + end + + def test_find_first + first = Topic.find_first "title = 'The First Topic'" + assert_equal(@topic_fixtures["first"]["title"], first.title) + end + + def test_find_first_failing + first = Topic.find_first "title = 'The First Topic!'" + assert_nil(first) + end + + def test_unexisting_record_exception_handling + assert_raises(ActiveRecord::RecordNotFound) { + Topic.find(1).parent + } + + Topic.find(2).parent + end + + def test_find_on_conditions + assert Topic.find_on_conditions(1, "approved = 0") + assert_raises(ActiveRecord::RecordNotFound) { Topic.find_on_conditions(1, "approved = 1") } + end + + def test_condition_interpolation + assert_kind_of Firm, Company.find_first(["name = '%s'", "37signals"]) + assert_nil Company.find_first(["name = '%s'", "37signals!"]) + assert_nil Company.find_first(["name = '%s'", "37signals!' OR 1=1"]) + assert_kind_of Time, Topic.find_first(["id = %d", 1]).written_on + end + + def test_string_sanitation + assert_equal "something '' 1=1", ActiveRecord::Base.sanitize("something ' 1=1") + assert_equal "something select table", ActiveRecord::Base.sanitize("something; select table") + end +end
\ No newline at end of file diff --git a/activerecord/test/fixtures/accounts.yml b/activerecord/test/fixtures/accounts.yml new file mode 100644 index 0000000000..21a0aab52a --- /dev/null +++ b/activerecord/test/fixtures/accounts.yml @@ -0,0 +1,8 @@ +signals37: + id: 1 + firm_id: 1 + credit_limit: 50 + +unknown: + id: 2 + credit_limit: 50 diff --git a/activerecord/test/fixtures/auto_id.rb b/activerecord/test/fixtures/auto_id.rb new file mode 100644 index 0000000000..d720e2be5e --- /dev/null +++ b/activerecord/test/fixtures/auto_id.rb @@ -0,0 +1,4 @@ +class AutoId < ActiveRecord::Base + def self.table_name () "auto_id_tests" end + def self.primary_key () "auto_id" end +end diff --git a/activerecord/test/fixtures/bad_fixtures/attr_with_numeric_first_char b/activerecord/test/fixtures/bad_fixtures/attr_with_numeric_first_char new file mode 100644 index 0000000000..ef27947f27 --- /dev/null +++ b/activerecord/test/fixtures/bad_fixtures/attr_with_numeric_first_char @@ -0,0 +1 @@ +1b => 1 diff --git a/activerecord/test/fixtures/bad_fixtures/attr_with_spaces b/activerecord/test/fixtures/bad_fixtures/attr_with_spaces new file mode 100644 index 0000000000..46fd6f2fe9 --- /dev/null +++ b/activerecord/test/fixtures/bad_fixtures/attr_with_spaces @@ -0,0 +1 @@ +a b => 1 diff --git a/activerecord/test/fixtures/bad_fixtures/blank_line b/activerecord/test/fixtures/bad_fixtures/blank_line new file mode 100644 index 0000000000..3ea1f71743 --- /dev/null +++ b/activerecord/test/fixtures/bad_fixtures/blank_line @@ -0,0 +1,3 @@ +a => 1 + +b => 2 diff --git a/activerecord/test/fixtures/bad_fixtures/duplicate_attributes b/activerecord/test/fixtures/bad_fixtures/duplicate_attributes new file mode 100644 index 0000000000..cc0236f26f --- /dev/null +++ b/activerecord/test/fixtures/bad_fixtures/duplicate_attributes @@ -0,0 +1,3 @@ +a => 1 +b => 2 +a => 3 diff --git a/activerecord/test/fixtures/bad_fixtures/missing_value b/activerecord/test/fixtures/bad_fixtures/missing_value new file mode 100644 index 0000000000..fb59ec33e8 --- /dev/null +++ b/activerecord/test/fixtures/bad_fixtures/missing_value @@ -0,0 +1 @@ +a => diff --git a/activerecord/test/fixtures/column_name.rb b/activerecord/test/fixtures/column_name.rb new file mode 100644 index 0000000000..ec07205a3a --- /dev/null +++ b/activerecord/test/fixtures/column_name.rb @@ -0,0 +1,3 @@ +class ColumnName < ActiveRecord::Base + def self.table_name () "colnametests" end +end
\ No newline at end of file diff --git a/activerecord/test/fixtures/companies/first_client b/activerecord/test/fixtures/companies/first_client new file mode 100755 index 0000000000..800c694eeb --- /dev/null +++ b/activerecord/test/fixtures/companies/first_client @@ -0,0 +1,6 @@ +id => 2 +type => Client +firm_id => 1 +client_of => 2 +name => Summit +ruby_type => Client diff --git a/activerecord/test/fixtures/companies/first_firm b/activerecord/test/fixtures/companies/first_firm new file mode 100755 index 0000000000..22d876dad1 --- /dev/null +++ b/activerecord/test/fixtures/companies/first_firm @@ -0,0 +1,4 @@ +id => 1 +type => Firm +name => 37signals +ruby_type => Firm diff --git a/activerecord/test/fixtures/companies/second_client b/activerecord/test/fixtures/companies/second_client new file mode 100755 index 0000000000..69f8adc49c --- /dev/null +++ b/activerecord/test/fixtures/companies/second_client @@ -0,0 +1,6 @@ +id => 3 +type => Client +firm_id => 1 +client_of => 1 +name => Microsoft +ruby_type => Client diff --git a/activerecord/test/fixtures/company.rb b/activerecord/test/fixtures/company.rb new file mode 100755 index 0000000000..b5ee055948 --- /dev/null +++ b/activerecord/test/fixtures/company.rb @@ -0,0 +1,37 @@ +class Company < ActiveRecord::Base + attr_protected :rating +end + + +class Firm < Company + has_many :clients, :order => "id", :dependent => true + 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 :clients_like_ms, :conditions => "name = 'Microsoft'", :class_name => "Client", :order => "id" + has_many :clients_using_sql, :class_name => "Client", :finder_sql => 'SELECT * FROM companies WHERE client_of = #{id}' + + has_one :account, :dependent => true +end + +class Client < Company + belongs_to :firm, :foreign_key => "client_of" + belongs_to :firm_with_basic_id, :class_name => "Firm", :foreign_key => "firm_id" + belongs_to :firm_with_other_name, :class_name => "Firm", :foreign_key => "client_of" + belongs_to :firm_with_condition, :class_name => "Firm", :foreign_key => "client_of", :conditions => "1 = 1" +end + + +class SpecialClient < Client +end + +class VerySpecialClient < SpecialClient +end + +class Account < ActiveRecord::Base + belongs_to :firm + + protected + def validate + errors.add_on_empty "credit_limit" + end +end diff --git a/activerecord/test/fixtures/company_in_module.rb b/activerecord/test/fixtures/company_in_module.rb new file mode 100644 index 0000000000..a484ed5eaf --- /dev/null +++ b/activerecord/test/fixtures/company_in_module.rb @@ -0,0 +1,47 @@ +module MyApplication + module Business + class Company < ActiveRecord::Base + attr_protected :rating + end + + class Firm < Company + has_many :clients, :order => "id", :dependent => true + 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 :clients_like_ms, :conditions => "name = 'Microsoft'", :class_name => "Client", :order => "id" + has_many :clients_using_sql, :class_name => "Client", :finder_sql => 'SELECT * FROM companies WHERE client_of = #{id}' + + has_one :account, :dependent => true + end + + class Client < Company + belongs_to :firm, :foreign_key => "client_of" + belongs_to :firm_with_other_name, :class_name => "Firm", :foreign_key => "client_of" + end + + class Developer < ActiveRecord::Base + has_and_belongs_to_many :projects + + protected + def validate + errors.add_on_boundry_breaking("name", 3..20) + end + end + + class Project < ActiveRecord::Base + has_and_belongs_to_many :developers + end + + end + + module Billing + class Account < ActiveRecord::Base + belongs_to :firm, :class_name => "MyApplication::Business::Firm" + + protected + def validate + errors.add_on_empty "credit_limit" + end + end + end +end diff --git a/activerecord/test/fixtures/course.rb b/activerecord/test/fixtures/course.rb new file mode 100644 index 0000000000..8a40fa740d --- /dev/null +++ b/activerecord/test/fixtures/course.rb @@ -0,0 +1,3 @@ +class Course < ActiveRecord::Base + has_many :entrants +end diff --git a/activerecord/test/fixtures/courses/java b/activerecord/test/fixtures/courses/java new file mode 100644 index 0000000000..84b10d390b --- /dev/null +++ b/activerecord/test/fixtures/courses/java @@ -0,0 +1,2 @@ +id => 2 +name => Java Development diff --git a/activerecord/test/fixtures/courses/ruby b/activerecord/test/fixtures/courses/ruby new file mode 100644 index 0000000000..db42f96d27 --- /dev/null +++ b/activerecord/test/fixtures/courses/ruby @@ -0,0 +1,2 @@ +id => 1 +name => Ruby Development diff --git a/activerecord/test/fixtures/customer.rb b/activerecord/test/fixtures/customer.rb new file mode 100644 index 0000000000..5275a5209d --- /dev/null +++ b/activerecord/test/fixtures/customer.rb @@ -0,0 +1,30 @@ +class Customer < ActiveRecord::Base + composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] + composed_of :balance, :class_name => "Money", :mapping => %w(balance amount) +end + +class Address + attr_reader :street, :city, :country + + def initialize(street, city, country) + @street, @city, @country = street, city, country + end + + def close_to?(other_address) + city == other_address.city && country == other_address.country + end +end + +class Money + attr_reader :amount, :currency + + EXCHANGE_RATES = { "USD_TO_DKK" => 6, "DKK_TO_USD" => 0.6 } + + def initialize(amount, currency = "USD") + @amount, @currency = amount, currency + end + + def exchange_to(other_currency) + Money.new((amount * EXCHANGE_RATES["#{currency}_TO_#{other_currency}"]).floor, other_currency) + end +end
\ No newline at end of file diff --git a/activerecord/test/fixtures/customers/david b/activerecord/test/fixtures/customers/david new file mode 100644 index 0000000000..69b9c32376 --- /dev/null +++ b/activerecord/test/fixtures/customers/david @@ -0,0 +1,6 @@ +id => 1 +name => David +balance => 50 +address_street => Funny Street +address_city => Scary Town +address_country => Loony Land
\ No newline at end of file diff --git a/activerecord/test/fixtures/db_definitions/mysql.sql b/activerecord/test/fixtures/db_definitions/mysql.sql new file mode 100755 index 0000000000..766c0ec71f --- /dev/null +++ b/activerecord/test/fixtures/db_definitions/mysql.sql @@ -0,0 +1,97 @@ +CREATE TABLE `accounts` ( + `id` int(11) NOT NULL auto_increment, + `firm_id` int(11) default NULL, + `credit_limit` int(5) default NULL, + PRIMARY KEY (`id`) +) TYPE=InnoDB; + +CREATE TABLE `companies` ( + `id` int(11) NOT NULL auto_increment, + `type` varchar(50) default NULL, + `ruby_type` varchar(50) default NULL, + `firm_id` int(11) default NULL, + `name` varchar(50) default NULL, + `client_of` int(11) default NULL, + `rating` int(11) default NULL default 1, + PRIMARY KEY (`id`) +) TYPE=InnoDB; + + +CREATE TABLE `topics` ( + `id` int(11) NOT NULL auto_increment, + `title` varchar(255) default NULL, + `author_name` varchar(255) default NULL, + `author_email_address` varchar(255) default NULL, + `written_on` datetime default NULL, + `last_read` date default NULL, + `content` text, + `approved` tinyint(1) default 1, + `replies_count` int(11) default 0, + `parent_id` int(11) default NULL, + `type` varchar(50) default NULL, + PRIMARY KEY (`id`) +) TYPE=InnoDB; + +CREATE TABLE `developers` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(100) default NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `projects` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(100) default NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `developers_projects` ( + `developer_id` int(11) NOT NULL, + `project_id` int(11) NOT NULL, + `joined_on` date default NULL +); + +CREATE TABLE `customers` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(100) default NULL, + `balance` int(6) default 0, + `address_street` varchar(100) default NULL, + `address_city` varchar(100) default NULL, + `address_country` varchar(100) default NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `movies` ( + `movieid` int(11) NOT NULL auto_increment, + `name` varchar(100) default NULL, + PRIMARY KEY (`movieid`) +); + +CREATE TABLE `subscribers` ( + `nick` varchar(100) NOT NULL, + `name` varchar(100) default NULL, + PRIMARY KEY (`nick`) +); + +CREATE TABLE `booleantests` ( + `id` int(11) NOT NULL auto_increment, + `value` integer default NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `auto_id_tests` ( + `auto_id` int(11) NOT NULL auto_increment, + `value` integer default NULL, + PRIMARY KEY (`auto_id`) +); + +CREATE TABLE `entrants` ( + `id` INTEGER NOT NULL PRIMARY KEY, + `name` VARCHAR(255) NOT NULL, + `course_id` INTEGER NOT NULL +); + +CREATE TABLE `colnametests` ( + `id` int(11) NOT NULL auto_increment, + `references` int(11) NOT NULL, + PRIMARY KEY (`id`) +); diff --git a/activerecord/test/fixtures/db_definitions/mysql2.sql b/activerecord/test/fixtures/db_definitions/mysql2.sql new file mode 100644 index 0000000000..0a16a0a2f9 --- /dev/null +++ b/activerecord/test/fixtures/db_definitions/mysql2.sql @@ -0,0 +1,4 @@ +CREATE TABLE `courses` ( + `id` INTEGER NOT NULL PRIMARY KEY, + `name` VARCHAR(255) NOT NULL +); diff --git a/activerecord/test/fixtures/db_definitions/postgresql.sql b/activerecord/test/fixtures/db_definitions/postgresql.sql new file mode 100644 index 0000000000..e83356627b --- /dev/null +++ b/activerecord/test/fixtures/db_definitions/postgresql.sql @@ -0,0 +1,114 @@ +SET search_path = public, pg_catalog; + +CREATE TABLE accounts ( + id serial, + firm_id integer, + credit_limit integer, + PRIMARY KEY (id) +); +SELECT setval('accounts_id_seq', 100); + +CREATE TABLE companies ( + id serial, + "type" character varying(50), + "ruby_type" character varying(50), + firm_id integer, + name character varying(50), + client_of integer, + rating integer default 1, + PRIMARY KEY (id) +); +SELECT setval('companies_id_seq', 100); + +CREATE TABLE developers_projects ( + developer_id integer NOT NULL, + project_id integer NOT NULL, + joined_on date +); + +CREATE TABLE developers ( + id serial, + name character varying(100), + PRIMARY KEY (id) +); +SELECT setval('developers_id_seq', 100); + +CREATE TABLE projects ( + id serial, + name character varying(100), + PRIMARY KEY (id) +); +SELECT setval('projects_id_seq', 100); + +CREATE TABLE topics ( + id serial, + title character varying(255), + author_name character varying(255), + author_email_address character varying(255), + written_on timestamp without time zone, + last_read date, + content text, + replies_count integer default 0, + parent_id integer, + "type" character varying(50), + approved smallint DEFAULT 1, + PRIMARY KEY (id) +); +SELECT setval('topics_id_seq', 100); + +CREATE TABLE customers ( + id serial, + name character varying, + balance integer default 0, + address_street character varying, + address_city character varying, + address_country character varying, + PRIMARY KEY (id) +); +SELECT setval('customers_id_seq', 100); + +CREATE TABLE movies ( + movieid serial, + name text, + PRIMARY KEY (movieid) +); + +CREATE TABLE subscribers ( + nick text NOT NULL, + name text, + PRIMARY KEY (nick) +); + +CREATE TABLE booleantests ( + id serial, + value boolean, + PRIMARY KEY (id) +); + +CREATE TABLE defaults ( + id serial, + modified_date date default CURRENT_DATE, + fixed_date date default '2004-01-01', + modified_time timestamp default CURRENT_TIMESTAMP, + fixed_time timestamp default '2004-01-01 00:00:00.000000-00', + char1 char(1) default 'Y', + char2 character varying(50) default 'a varchar field', + char3 text default 'a text field' +); + +CREATE TABLE auto_id_tests ( + auto_id serial, + value integer, + PRIMARY KEY (auto_id) +); + +CREATE TABLE entrants ( + id serial, + name text, + course_id integer +); + +CREATE TABLE colnametests ( + id serial, + "references" integer NOT NULL +); diff --git a/activerecord/test/fixtures/db_definitions/postgresql2.sql b/activerecord/test/fixtures/db_definitions/postgresql2.sql new file mode 100644 index 0000000000..b58a45eff7 --- /dev/null +++ b/activerecord/test/fixtures/db_definitions/postgresql2.sql @@ -0,0 +1,4 @@ +CREATE TABLE courses ( + id serial, + name text +);
\ No newline at end of file diff --git a/activerecord/test/fixtures/db_definitions/sqlite.sql b/activerecord/test/fixtures/db_definitions/sqlite.sql new file mode 100644 index 0000000000..cb617305dc --- /dev/null +++ b/activerecord/test/fixtures/db_definitions/sqlite.sql @@ -0,0 +1,86 @@ +CREATE TABLE 'accounts' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'firm_id' INTEGER DEFAULT NULL, + 'credit_limit' INTEGER DEFAULT NULL +); + +CREATE TABLE 'companies' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'type' VARCHAR(255) DEFAULT NULL, + 'ruby_type' VARCHAR(255) DEFAULT NULL, + 'firm_id' INTEGER DEFAULT NULL, + 'name' TEXT DEFAULT NULL, + 'client_of' INTEGER DEFAULT NULL, + 'rating' INTEGER DEFAULT 1 +); + + +CREATE TABLE 'topics' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'title' VARCHAR(255) DEFAULT NULL, + 'author_name' VARCHAR(255) DEFAULT NULL, + 'author_email_address' VARCHAR(255) DEFAULT NULL, + 'written_on' DATETIME DEFAULT NULL, + 'last_read' DATE DEFAULT NULL, + 'content' TEXT, + 'approved' INTEGER DEFAULT 1, + 'replies_count' INTEGER DEFAULT 0, + 'parent_id' INTEGER DEFAULT NULL, + 'type' VARCHAR(255) DEFAULT NULL +); + +CREATE TABLE 'developers' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT DEFAULT NULL +); + +CREATE TABLE 'projects' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT DEFAULT NULL +); + +CREATE TABLE 'developers_projects' ( + 'developer_id' INTEGER NOT NULL, + 'project_id' INTEGER NOT NULL, + 'joined_on' DATE DEFAULT NULL +); + +CREATE TABLE 'customers' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' VARCHAR(255) DEFAULT NULL, + 'balance' INTEGER DEFAULT 0, + 'address_street' TEXT DEFAULT NULL, + 'address_city' TEXT DEFAULT NULL, + 'address_country' TEXT DEFAULT NULL +); + +CREATE TABLE 'movies' ( + 'movieid' INTEGER PRIMARY KEY NOT NULL, + 'name' VARCHAR(255) DEFAULT NULL +); + +CREATE TABLE subscribers ( + 'nick' VARCHAR(255) PRIMARY KEY NOT NULL, + 'name' VARCHAR(255) DEFAULT NULL +); + +CREATE TABLE 'booleantests' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'value' INTEGER DEFAULT NULL +); + +CREATE TABLE 'auto_id_tests' ( + 'auto_id' INTEGER PRIMARY KEY NOT NULL, + 'value' INTEGER DEFAULT NULL +); + +CREATE TABLE 'entrants' ( + 'id' INTEGER NOT NULL PRIMARY KEY, + 'name' VARCHAR(255) NOT NULL, + 'course_id' INTEGER NOT NULL +); + +CREATE TABLE 'colnametests' ( + 'id' INTEGER NOT NULL PRIMARY KEY, + 'references' INTEGER NOT NULL +); diff --git a/activerecord/test/fixtures/db_definitions/sqlite2.sql b/activerecord/test/fixtures/db_definitions/sqlite2.sql new file mode 100644 index 0000000000..19b123968a --- /dev/null +++ b/activerecord/test/fixtures/db_definitions/sqlite2.sql @@ -0,0 +1,4 @@ +CREATE TABLE 'courses' ( + 'id' INTEGER NOT NULL PRIMARY KEY, + 'name' VARCHAR(255) NOT NULL +); diff --git a/activerecord/test/fixtures/db_definitions/sqlserver.sql b/activerecord/test/fixtures/db_definitions/sqlserver.sql new file mode 100644 index 0000000000..0ae9780273 --- /dev/null +++ b/activerecord/test/fixtures/db_definitions/sqlserver.sql @@ -0,0 +1,96 @@ +CREATE TABLE accounts ( + id int NOT NULL IDENTITY(1, 1), + firm_id int default NULL, + credit_limit int default NULL, + PRIMARY KEY (id) +) + +CREATE TABLE companies ( + id int NOT NULL IDENTITY(1, 1), + type varchar(50) default NULL, + ruby_type varchar(50) default NULL, + firm_id int default NULL, + name varchar(50) default NULL, + client_of int default NULL, + companies_count int default 0, + rating int default 1, + PRIMARY KEY (id) +) + +CREATE TABLE topics ( + id int NOT NULL IDENTITY(1, 1), + title varchar(255) default NULL, + author_name varchar(255) default NULL, + author_email_address varchar(255) default NULL, + written_on datetime default NULL, + last_read datetime default NULL, + content text, + approved tinyint default 1, + replies_count int default 0, + parent_id int default NULL, + type varchar(50) default NULL, + PRIMARY KEY (id) +) + +CREATE TABLE developers ( + id int NOT NULL IDENTITY(1, 1), + name varchar(100) default NULL, + PRIMARY KEY (id) +); + +CREATE TABLE projects ( + id int NOT NULL IDENTITY(1, 1), + name varchar(100) default NULL, + PRIMARY KEY (id) +); + +CREATE TABLE developers_projects ( + developer_id int NOT NULL, + project_id int NOT NULL +); + +CREATE TABLE customers ( + id int NOT NULL IDENTITY(1, 1), + name varchar(100) default NULL, + balance int default 0, + address_street varchar(100) default NULL, + address_city varchar(100) default NULL, + address_country varchar(100) default NULL, + PRIMARY KEY (id) +); + +CREATE TABLE movies ( + movieid int NOT NULL IDENTITY(1, 1), + name varchar(100) default NULL, + PRIMARY KEY (movieid) +); + +CREATE TABLE subscribers ( + nick varchar(100) NOT NULL, + name varchar(100) default NULL, + PRIMARY KEY (nick) +); + +CREATE TABLE booleantests ( + id int NOT NULL IDENTITY(1, 1), + value integer default NULL, + PRIMARY KEY (id) +); + +CREATE TABLE auto_id_tests ( + auto_id int NOT NULL IDENTITY(1, 1), + value int default NULL, + PRIMARY KEY (auto_id) +); + +CREATE TABLE entrants ( + id int NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL, + course_id int NOT NULL +); + +CREATE TABLE colnametests ( + id int NOT NULL IDENTITY(1, 1), + [references] int NOT NULL, + PRIMARY KEY (id) +);
\ No newline at end of file diff --git a/activerecord/test/fixtures/db_definitions/sqlserver2.sql b/activerecord/test/fixtures/db_definitions/sqlserver2.sql new file mode 100644 index 0000000000..dc4f9ed364 --- /dev/null +++ b/activerecord/test/fixtures/db_definitions/sqlserver2.sql @@ -0,0 +1,4 @@ +CREATE TABLE courses ( + id int NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL +); diff --git a/activerecord/test/fixtures/default.rb b/activerecord/test/fixtures/default.rb new file mode 100644 index 0000000000..887e9cc999 --- /dev/null +++ b/activerecord/test/fixtures/default.rb @@ -0,0 +1,2 @@ +class Default < ActiveRecord::Base +end diff --git a/activerecord/test/fixtures/developer.rb b/activerecord/test/fixtures/developer.rb new file mode 100644 index 0000000000..737fc3824b --- /dev/null +++ b/activerecord/test/fixtures/developer.rb @@ -0,0 +1,8 @@ +class Developer < ActiveRecord::Base + has_and_belongs_to_many :projects + + protected + def validate + errors.add_on_boundry_breaking("name", 3..20) + end +end
\ No newline at end of file diff --git a/activerecord/test/fixtures/developers.yml b/activerecord/test/fixtures/developers.yml new file mode 100644 index 0000000000..733455f789 --- /dev/null +++ b/activerecord/test/fixtures/developers.yml @@ -0,0 +1,13 @@ +david: + id: 1 + name: David + +jamis: + id: 2 + name: Jamis + +<% for digit in 3..10 %> +dev_<%= digit %>: + id: <%= digit %> + name: fixture_<%= digit %> +<% end %>
\ No newline at end of file diff --git a/activerecord/test/fixtures/developers_projects/david_action_controller b/activerecord/test/fixtures/developers_projects/david_action_controller new file mode 100644 index 0000000000..e6e9d0e59b --- /dev/null +++ b/activerecord/test/fixtures/developers_projects/david_action_controller @@ -0,0 +1,3 @@ +developer_id => 1 +project_id => 2 +joined_on => 2004-10-10
\ No newline at end of file diff --git a/activerecord/test/fixtures/developers_projects/david_active_record b/activerecord/test/fixtures/developers_projects/david_active_record new file mode 100644 index 0000000000..2ef474c10d --- /dev/null +++ b/activerecord/test/fixtures/developers_projects/david_active_record @@ -0,0 +1,3 @@ +developer_id => 1 +project_id => 1 +joined_on => 2004-10-10
\ No newline at end of file diff --git a/activerecord/test/fixtures/developers_projects/jamis_active_record b/activerecord/test/fixtures/developers_projects/jamis_active_record new file mode 100644 index 0000000000..91beb80797 --- /dev/null +++ b/activerecord/test/fixtures/developers_projects/jamis_active_record @@ -0,0 +1,2 @@ +developer_id => 2 +project_id => 1
\ No newline at end of file diff --git a/activerecord/test/fixtures/entrant.rb b/activerecord/test/fixtures/entrant.rb new file mode 100644 index 0000000000..4682ce48c8 --- /dev/null +++ b/activerecord/test/fixtures/entrant.rb @@ -0,0 +1,3 @@ +class Entrant < ActiveRecord::Base + belongs_to :course +end diff --git a/activerecord/test/fixtures/entrants/first b/activerecord/test/fixtures/entrants/first new file mode 100644 index 0000000000..e45cd6c1c2 --- /dev/null +++ b/activerecord/test/fixtures/entrants/first @@ -0,0 +1,3 @@ +id => 1 +course_id => 1 +name => Ruby Developer diff --git a/activerecord/test/fixtures/entrants/second b/activerecord/test/fixtures/entrants/second new file mode 100644 index 0000000000..38cd702476 --- /dev/null +++ b/activerecord/test/fixtures/entrants/second @@ -0,0 +1,3 @@ +id => 2 +course_id => 1 +name => Ruby Guru diff --git a/activerecord/test/fixtures/entrants/third b/activerecord/test/fixtures/entrants/third new file mode 100644 index 0000000000..594ac77af0 --- /dev/null +++ b/activerecord/test/fixtures/entrants/third @@ -0,0 +1,3 @@ +id => 3 +course_id => 2 +name => Java Lover diff --git a/activerecord/test/fixtures/movie.rb b/activerecord/test/fixtures/movie.rb new file mode 100644 index 0000000000..6384b4c801 --- /dev/null +++ b/activerecord/test/fixtures/movie.rb @@ -0,0 +1,5 @@ +class Movie < ActiveRecord::Base + def self.primary_key + "movieid" + end +end diff --git a/activerecord/test/fixtures/movies/first b/activerecord/test/fixtures/movies/first new file mode 100644 index 0000000000..0feaeac7b0 --- /dev/null +++ b/activerecord/test/fixtures/movies/first @@ -0,0 +1,2 @@ +movieid => 1 +name => Terminator diff --git a/activerecord/test/fixtures/movies/second b/activerecord/test/fixtures/movies/second new file mode 100644 index 0000000000..b3c506b7da --- /dev/null +++ b/activerecord/test/fixtures/movies/second @@ -0,0 +1,2 @@ +movieid => 2 +name => Gladiator diff --git a/activerecord/test/fixtures/project.rb b/activerecord/test/fixtures/project.rb new file mode 100644 index 0000000000..1ccf39d7cf --- /dev/null +++ b/activerecord/test/fixtures/project.rb @@ -0,0 +1,4 @@ +class Project < ActiveRecord::Base + has_and_belongs_to_many :developers, :uniq => true + has_and_belongs_to_many :developers_named_david, :class_name => "Developer", :conditions => "name = 'David'", :uniq => true +end
\ No newline at end of file diff --git a/activerecord/test/fixtures/projects/action_controller b/activerecord/test/fixtures/projects/action_controller new file mode 100644 index 0000000000..b3f00ae727 --- /dev/null +++ b/activerecord/test/fixtures/projects/action_controller @@ -0,0 +1,2 @@ +id => 2 +name => Active Controller
\ No newline at end of file diff --git a/activerecord/test/fixtures/projects/active_record b/activerecord/test/fixtures/projects/active_record new file mode 100644 index 0000000000..31131a7f30 --- /dev/null +++ b/activerecord/test/fixtures/projects/active_record @@ -0,0 +1,2 @@ +id => 1 +name => Active Record
\ No newline at end of file diff --git a/activerecord/test/fixtures/reply.rb b/activerecord/test/fixtures/reply.rb new file mode 100755 index 0000000000..51dfe21d2d --- /dev/null +++ b/activerecord/test/fixtures/reply.rb @@ -0,0 +1,21 @@ +class Reply < Topic + belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true + + attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read + + def validate + errors.add("title", "Empty") unless attribute_present? "title" + errors.add("content", "Empty") unless attribute_present? "content" + end + + def validate_on_create + errors.add("title", "is Wrong Create") if attribute_present?("title") && title == "Wrong Create" + if attribute_present?("title") && attribute_present?("content") && content == "Mismatch" + errors.add("title", "is Content Mismatch") + end + end + + def validate_on_update + errors.add("title", "is Wrong Update") if attribute_present?("title") && title == "Wrong Update" + end +end
\ No newline at end of file diff --git a/activerecord/test/fixtures/subscriber.rb b/activerecord/test/fixtures/subscriber.rb new file mode 100644 index 0000000000..3f1ade0d83 --- /dev/null +++ b/activerecord/test/fixtures/subscriber.rb @@ -0,0 +1,5 @@ +class Subscriber < ActiveRecord::Base + def self.primary_key + "nick" + end +end diff --git a/activerecord/test/fixtures/subscribers/first b/activerecord/test/fixtures/subscribers/first new file mode 100644 index 0000000000..5287e26e4d --- /dev/null +++ b/activerecord/test/fixtures/subscribers/first @@ -0,0 +1,2 @@ +nick => alterself +name => Luke Holden diff --git a/activerecord/test/fixtures/subscribers/second b/activerecord/test/fixtures/subscribers/second new file mode 100644 index 0000000000..2345e4475a --- /dev/null +++ b/activerecord/test/fixtures/subscribers/second @@ -0,0 +1,2 @@ +nick => webster132 +name => David Heinemeier Hansson diff --git a/activerecord/test/fixtures/topic.rb b/activerecord/test/fixtures/topic.rb new file mode 100755 index 0000000000..55c94e9e88 --- /dev/null +++ b/activerecord/test/fixtures/topic.rb @@ -0,0 +1,20 @@ +class Topic < ActiveRecord::Base + has_many :replies, :foreign_key => "parent_id" + serialize :content + + before_create :default_written_on + before_destroy :destroy_children #'self.class.delete_all "parent_id = #{id}"' + + def parent + self.class.find(parent_id) + end + + protected + def default_written_on + self.written_on = Time.now unless attribute_present?("written_on") + end + + def destroy_children + self.class.delete_all "parent_id = #{id}" + end +end
\ No newline at end of file diff --git a/activerecord/test/fixtures/topics/first b/activerecord/test/fixtures/topics/first new file mode 100755 index 0000000000..9972a578c8 --- /dev/null +++ b/activerecord/test/fixtures/topics/first @@ -0,0 +1,9 @@ +id => 1 +title => The First Topic +author_name => David +author_email_address => david@loudthinking.com +written_on => 2003-07-16 15:28 +last_read => 2004-04-15 +content => Have a nice day +approved => 0 +replies_count => 0
\ No newline at end of file diff --git a/activerecord/test/fixtures/topics/second b/activerecord/test/fixtures/topics/second new file mode 100755 index 0000000000..f669b4fef4 --- /dev/null +++ b/activerecord/test/fixtures/topics/second @@ -0,0 +1,8 @@ +id => 2 +title => The Second Topic's of the day +author_name => Mary +written_on => 2003-07-15 15:28 +content => Have a great day! +approved => 1 +replies_count => 2 +parent_id => 1
\ No newline at end of file diff --git a/activerecord/test/fixtures_test.rb b/activerecord/test/fixtures_test.rb new file mode 100755 index 0000000000..015b6ababe --- /dev/null +++ b/activerecord/test/fixtures_test.rb @@ -0,0 +1,84 @@ +require 'abstract_unit' +require 'fixtures/topic' +require 'fixtures/developer' +require 'fixtures/company' + +class FixturesTest < Test::Unit::TestCase + fixtures :topics, :developers, :accounts, :developers + + FIXTURES = %w( accounts companies customers + developers developers_projects entrants + movies projects subscribers topics ) + MATCH_ATTRIBUTE_NAME = /[a-zA-Z][-_\w]*/ + + def test_clean_fixtures + FIXTURES.each do |name| + fixtures = nil + assert_nothing_raised { fixtures = create_fixtures(name) } + assert_kind_of(Fixtures, fixtures) + fixtures.each { |name, fixture| + fixture.each { |key, value| + assert_match(MATCH_ATTRIBUTE_NAME, key) + } + } + end + end + + def test_multiple_clean_fixtures + fixtures_array = nil + assert_nothing_raised { fixtures_array = create_fixtures(*FIXTURES) } + assert_kind_of(Array, fixtures_array) + fixtures_array.each { |fixtures| assert_kind_of(Fixtures, fixtures) } + end + + def test_attributes + topics = create_fixtures("topics") + assert_equal("The First Topic", topics["first"]["title"]) + assert_nil(topics["second"]["author_email_address"]) + end + + def test_inserts + topics = create_fixtures("topics") + firstRow = ActiveRecord::Base.connection.select_one("SELECT * FROM topics WHERE author_name = 'David'") + assert_equal("The First Topic", firstRow["title"]) + + secondRow = ActiveRecord::Base.connection.select_one("SELECT * FROM topics WHERE author_name = 'Mary'") + assert_nil(secondRow["author_email_address"]) + end + + def test_bad_format + path = File.join(File.dirname(__FILE__), 'fixtures', 'bad_fixtures') + Dir.entries(path).each do |file| + next unless File.file?(file) and file !~ %r(^.|.yaml$) + assert_raise(Fixture::FormatError) { + Fixture.new(bad_fixtures_path, file) + } + end + end + + def test_logger_level_invariant + level = ActiveRecord::Base.logger.level + create_fixtures('topics') + assert_equal level, ActiveRecord::Base.logger.level + end + + def test_instantiation + topics = create_fixtures("topics") + assert_kind_of Topic, topics["first"].find + end + + def test_complete_instantiation + assert_equal 2, @topics.size + assert_equal "The First Topic", @first.title + end + + def test_fixtures_from_root_yml_with_instantiation + # assert_equal 2, @accounts.size + assert_equal 50, @unknown.credit_limit + end + + def test_erb_in_fixtures + assert_equal 10, @developers.size + assert_equal "fixture_5", @dev_5.name + end +end
\ No newline at end of file diff --git a/activerecord/test/inflector_test.rb b/activerecord/test/inflector_test.rb new file mode 100644 index 0000000000..4665558e74 --- /dev/null +++ b/activerecord/test/inflector_test.rb @@ -0,0 +1,121 @@ +require 'abstract_unit' + +class InflectorTest < Test::Unit::TestCase + SingularToPlural = { + "search" => "searches", + "switch" => "switches", + "fix" => "fixes", + "box" => "boxes", + "process" => "processes", + "address" => "addresses", + "case" => "cases", + "stack" => "stacks", + + "category" => "categories", + "query" => "queries", + "ability" => "abilities", + "agency" => "agencies", + + "wife" => "wives", + "safe" => "saves", + "half" => "halves", + + "salesperson" => "salespeople", + "person" => "people", + + "spokesman" => "spokesmen", + "man" => "men", + "woman" => "women", + + "basis" => "bases", + "diagnosis" => "diagnoses", + + "datum" => "data", + "medium" => "media", + + "node_child" => "node_children", + "child" => "children", + + "experience" => "experiences", + "day" => "days", + + "comment" => "comments", + "foobar" => "foobars" + } + + CamelToUnderscore = { + "Product" => "product", + "SpecialGuest" => "special_guest", + "AbstractApplicationController" => "abstract_application_controller" + } + + ClassNameToForeignKeyWithUnderscore = { + "Person" => "person_id", + "MyApplication::Billing::Account" => "account_id" + } + + ClassNameToForeignKeyWithoutUnderscore = { + "Person" => "personid", + "MyApplication::Billing::Account" => "accountid" + } + + ClassNameToTableName = { + "PrimarySpokesman" => "primary_spokesmen", + "NodeChild" => "node_children" + } + + def test_pluralize + SingularToPlural.each do |singular, plural| + assert_equal(plural, Inflector.pluralize(singular)) + end + + assert_equal("plurals", Inflector.pluralize("plurals")) + end + + def test_singularize + SingularToPlural.each do |singular, plural| + assert_equal(singular, Inflector.singularize(plural)) + end + end + + def test_camelize + CamelToUnderscore.each do |camel, underscore| + assert_equal(camel, Inflector.camelize(underscore)) + end + end + + def test_underscore + CamelToUnderscore.each do |camel, underscore| + assert_equal(underscore, Inflector.underscore(camel)) + end + + assert_equal "html_tidy", Inflector.underscore("HTMLTidy") + assert_equal "html_tidy_generator", Inflector.underscore("HTMLTidyGenerator") + end + + def test_demodulize + assert_equal "Account", Inflector.demodulize("MyApplication::Billing::Account") + end + + def test_foreign_key + ClassNameToForeignKeyWithUnderscore.each do |klass, foreign_key| + assert_equal(foreign_key, Inflector.foreign_key(klass)) + end + + ClassNameToForeignKeyWithoutUnderscore.each do |klass, foreign_key| + assert_equal(foreign_key, Inflector.foreign_key(klass, false)) + end + end + + def test_tableize + ClassNameToTableName.each do |class_name, table_name| + assert_equal(table_name, Inflector.tableize(class_name)) + end + end + + def test_classify + ClassNameToTableName.each do |class_name, table_name| + assert_equal(class_name, Inflector.classify(table_name)) + end + end +end
\ No newline at end of file diff --git a/activerecord/test/inheritance_test.rb b/activerecord/test/inheritance_test.rb new file mode 100755 index 0000000000..6f8175801d --- /dev/null +++ b/activerecord/test/inheritance_test.rb @@ -0,0 +1,125 @@ +require 'abstract_unit' +require 'fixtures/company' + + +class InheritanceTest < Test::Unit::TestCase + def setup + @company_fixtures = create_fixtures "companies" + end + + def switch_to_alt_inheritance_column + # we don't want misleading test results, so get rid of the values in the type column + Company.find_all(nil, "id").each do |c| + c['type'] = nil + c.save + end + + def Company.inheritance_column() "ruby_type" end + end + + def test_inheritance_find + assert Company.find(1).kind_of?(Firm), "37signals should be a firm" + assert Firm.find(1).kind_of?(Firm), "37signals should be a firm" + assert Company.find(2).kind_of?(Client), "Summit should be a client" + assert Client.find(2).kind_of?(Client), "Summit should be a client" + end + + def test_alt_inheritance_find + switch_to_alt_inheritance_column + test_inheritance_find + end + + def test_inheritance_find_all + companies = Company.find_all(nil, "id") + assert companies[0].kind_of?(Firm), "37signals should be a firm" + assert companies[1].kind_of?(Client), "Summit should be a client" + end + + def test_alt_inheritance_find_all + switch_to_alt_inheritance_column + test_inheritance_find_all + end + + def test_inheritance_save + firm = Firm.new + firm.name = "Next Angle" + firm.save + + next_angle = Company.find(firm.id) + assert next_angle.kind_of?(Firm), "Next Angle should be a firm" + end + + def test_alt_inheritance_save + switch_to_alt_inheritance_column + test_inheritance_save + end + + def test_inheritance_condition + assert_equal 3, Company.find_all.length + assert_equal 1, Firm.find_all.length + assert_equal 2, Client.find_all.length + end + + def test_alt_inheritance_condition + switch_to_alt_inheritance_column + test_inheritance_condition + end + + def test_finding_incorrect_type_data + assert_raises(ActiveRecord::RecordNotFound) { Firm.find(2) } + assert_nothing_raised { Firm.find(1) } + end + + def test_alt_finding_incorrect_type_data + switch_to_alt_inheritance_column + test_finding_incorrect_type_data + end + + def test_update_all_within_inheritance + Client.update_all "name = 'I am a client'" + assert_equal "I am a client", Client.find_all.first.name + assert_equal "37signals", Firm.find_all.first.name + end + + def test_alt_update_all_within_inheritance + switch_to_alt_inheritance_column + test_update_all_within_inheritance + end + + def test_destroy_all_within_inheritance + Client.destroy_all + assert_equal 0, Client.find_all.length + assert_equal 1, Firm.find_all.length + end + + def test_alt_destroy_all_within_inheritance + switch_to_alt_inheritance_column + test_destroy_all_within_inheritance + end + + def test_find_first_within_inheritance + assert_kind_of Firm, Company.find_first("name = '37signals'") + assert_kind_of Firm, Firm.find_first("name = '37signals'") + assert_nil Client.find_first("name = '37signals'") + end + + def test_alt_find_first_within_inheritance + switch_to_alt_inheritance_column + test_find_first_within_inheritance + end + + def test_complex_inheritance + very_special_client = VerySpecialClient.create("name" => "veryspecial") + assert_equal very_special_client, VerySpecialClient.find_first("name = 'veryspecial'") + assert_equal very_special_client, SpecialClient.find_first("name = 'veryspecial'") + assert_equal very_special_client, Company.find_first("name = 'veryspecial'") + assert_equal very_special_client, Client.find_first("name = 'veryspecial'") + assert_equal 1, Client.find_all("name = 'Summit'").size + assert_equal very_special_client, Client.find(very_special_client.id) + end + + def test_alt_complex_inheritance + switch_to_alt_inheritance_column + test_complex_inheritance + end +end
\ No newline at end of file diff --git a/activerecord/test/lifecycle_test.rb b/activerecord/test/lifecycle_test.rb new file mode 100755 index 0000000000..8b34c8c24c --- /dev/null +++ b/activerecord/test/lifecycle_test.rb @@ -0,0 +1,110 @@ +# require File.dirname(__FILE__) + '/../dev-utils/eval_debugger' +require 'abstract_unit' +require 'fixtures/topic' +require 'fixtures/developer' + +class Topic; def after_find() end end +class Developer; def after_find() end end + +class TopicManualObserver + include Singleton + + attr_reader :action, :object, :callbacks + + def initialize + Topic.add_observer(self) + @callbacks = [] + end + + def update(callback_method, object) + @callbacks << { "callback_method" => callback_method, "object" => object } + end + + def has_been_notified? + !@callbacks.empty? + end +end + +class TopicaObserver < ActiveRecord::Observer + def self.observed_class() Topic end + + attr_reader :topic + + def after_find(topic) + @topic = topic + end +end + +class TopicObserver < ActiveRecord::Observer + attr_reader :topic + + def after_find(topic) + @topic = topic + end +end + +class MultiObserver < ActiveRecord::Observer + attr_reader :record + + def self.observed_class() [ Topic, Developer ] end + + def after_find(record) + @record = record + end + +end + +class LifecycleTest < Test::Unit::TestCase + def setup + @topics, @developers = create_fixtures("topics", "developers") + end + + def test_before_destroy + assert_equal 2, Topic.count + Topic.find(1).destroy + assert_equal 0, Topic.count + end + + def test_after_save + topic_observer = TopicManualObserver.instance + + topic = Topic.find(1) + topic.title = "hello" + topic.save + + assert topic_observer.has_been_notified? + assert_equal :after_save, topic_observer.callbacks.last["callback_method"] + end + + def test_observer_update_on_save + topic_observer = TopicManualObserver.instance + + topic = Topic.find(1) + assert topic_observer.has_been_notified? + assert_equal :after_find, topic_observer.callbacks.first["callback_method"] + end + + def test_auto_observer + topic_observer = TopicaObserver.instance + + topic = Topic.find(1) + assert_equal topic_observer.topic.title, topic.title + end + + def test_infered_auto_observer + topic_observer = TopicObserver.instance + + topic = Topic.find(1) + assert_equal topic_observer.topic.title, topic.title + end + + def test_observing_two_classes + multi_observer = MultiObserver.instance + + topic = Topic.find(1) + assert_equal multi_observer.record.title, topic.title + + developer = Developer.find(1) + assert_equal multi_observer.record.name, developer.name + end +end
\ No newline at end of file diff --git a/activerecord/test/modules_test.rb b/activerecord/test/modules_test.rb new file mode 100644 index 0000000000..f43bb1d077 --- /dev/null +++ b/activerecord/test/modules_test.rb @@ -0,0 +1,29 @@ +require 'abstract_unit' +# require File.dirname(__FILE__) + '/../dev-utils/eval_debugger' +require 'fixtures/company_in_module' + +class ModulesTest < Test::Unit::TestCase + def setup + create_fixtures "accounts" + create_fixtures "companies" + create_fixtures "projects" + create_fixtures "developers" + end + + def test_module_spanning_associations + assert MyApplication::Business::Firm.find_first.has_clients?, "Firm should have clients" + firm = MyApplication::Business::Firm.find_first + assert_nil firm.class.table_name.match('::'), "Firm shouldn't have the module appear in its table name" + assert_equal 2, firm.clients_count, "Firm should have two clients" + end + + def test_module_spanning_has_and_belongs_to_many_associations + project = MyApplication::Business::Project.find_first + project.developers << MyApplication::Business::Developer.create("name" => "John") + assert "John", project.developers.last.name + end + + def test_associations_spanning_cross_modules + assert MyApplication::Billing::Account.find(1).has_firm?, "37signals account should be able to backtrack" + end +end
\ No newline at end of file diff --git a/activerecord/test/multiple_db_test.rb b/activerecord/test/multiple_db_test.rb new file mode 100644 index 0000000000..f2f73c0dda --- /dev/null +++ b/activerecord/test/multiple_db_test.rb @@ -0,0 +1,46 @@ +require 'abstract_unit' +require 'fixtures/course' +require 'fixtures/entrant' + +class MultipleDbTest < Test::Unit::TestCase + def setup + @courses = create_fixtures("courses") { Course.retrieve_connection } + @entrants = create_fixtures("entrants") + end + + def test_connected + assert_not_nil Entrant.connection + assert_not_nil Course.connection + end + + def test_proper_connection + assert_not_equal(Entrant.connection, Course.connection) + assert_equal(Entrant.connection, Entrant.retrieve_connection) + assert_equal(Course.connection, Course.retrieve_connection) + assert_equal(ActiveRecord::Base.connection, Entrant.connection) + end + + def test_find + c1 = Course.find(1) + assert_equal "Ruby Development", c1.name + c2 = Course.find(2) + assert_equal "Java Development", c2.name + e1 = Entrant.find(1) + assert_equal "Ruby Developer", e1.name + e2 = Entrant.find(2) + assert_equal "Ruby Guru", e2.name + e3 = Entrant.find(3) + assert_equal "Java Lover", e3.name + end + + def test_associations + c1 = Course.find(1) + assert_equal 2, c1.entrants_count + e1 = Entrant.find(1) + assert_equal e1.course.id, c1.id + c2 = Course.find(2) + assert_equal 1, c2.entrants_count + e3 = Entrant.find(3) + assert_equal e3.course.id, c2.id + end +end diff --git a/activerecord/test/pk_test.rb b/activerecord/test/pk_test.rb new file mode 100644 index 0000000000..aefaebde6e --- /dev/null +++ b/activerecord/test/pk_test.rb @@ -0,0 +1,59 @@ +require 'abstract_unit' +require 'fixtures/topic' +require 'fixtures/subscriber' +require 'fixtures/movie' + +class PrimaryKeysTest < Test::Unit::TestCase + def setup + @topics = create_fixtures "topics" + @subscribers = create_fixtures "subscribers" + @movies = create_fixtures "movies" + end + + def test_integer_key + topic = Topic.find(1) + assert_equal(@topics["first"]["author_name"], topic.author_name) + topic = Topic.find(2) + assert_equal(@topics["second"]["author_name"], topic.author_name) + + topic = Topic.new + topic.title = "New Topic" + assert_equal(nil, topic.id) + assert_nothing_raised{ topic.save } + id = topic.id + + topicReloaded = Topic.find(id) + assert_equal("New Topic", topicReloaded.title) + end + + def test_string_key + subscriber = Subscriber.find(@subscribers["first"]["nick"]) + assert_equal(@subscribers["first"]["name"], subscriber.name) + subscriber = Subscriber.find(@subscribers["second"]["nick"]) + assert_equal(@subscribers["second"]["name"], subscriber.name) + + subscriber = Subscriber.new + subscriber.id = "jdoe" + assert_equal("jdoe", subscriber.id) + subscriber.name = "John Doe" + assert_nothing_raised{ subscriber.save } + + subscriberReloaded = Subscriber.find("jdoe") + assert_equal("John Doe", subscriberReloaded.name) + end + + def test_find_with_more_than_one_string_key + assert_equal 2, Subscriber.find(@subscribers["first"]["nick"], @subscribers["second"]["nick"]).length + end + + def test_primary_key_prefix + ActiveRecord::Base.primary_key_prefix_type = :table_name + assert_equal "topicid", Topic.primary_key + + ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore + assert_equal "topic_id", Topic.primary_key + + ActiveRecord::Base.primary_key_prefix_type = nil + assert_equal "id", Topic.primary_key + end +end diff --git a/activerecord/test/reflection_test.rb b/activerecord/test/reflection_test.rb new file mode 100644 index 0000000000..5d7e9d1197 --- /dev/null +++ b/activerecord/test/reflection_test.rb @@ -0,0 +1,78 @@ +#require File.dirname(__FILE__) + '/../dev-utils/eval_debugger' +require 'abstract_unit' +require 'fixtures/topic' +require 'fixtures/customer' +require 'fixtures/company' +require 'fixtures/company_in_module' + +class ReflectionTest < Test::Unit::TestCase + def setup + @topics = create_fixtures "topics" + @customers = create_fixtures "customers" + @companies = create_fixtures "companies" + @first = Topic.find(1) + end + + def test_read_attribute_names + assert_equal( + %w( id title author_name author_email_address written_on last_read content approved replies_count parent_id type ).sort, + @first.attribute_names + ) + end + + def test_columns + assert_equal 11, Topic.columns.length + end + + def test_content_columns + assert_equal 7, Topic.content_columns.length + end + + def test_column_string_type_and_limit + assert_equal :string, @first.column_for_attribute("title").type + assert_equal 255, @first.column_for_attribute("title").limit + end + + def test_human_name_for_column + assert_equal "Author name", @first.column_for_attribute("author_name").human_name + end + + def test_integer_columns + assert_equal :integer, @first.column_for_attribute("id").type + end + + def test_aggregation_reflection + reflection_for_address = ActiveRecord::Reflection::AggregateReflection.new( + :address, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer + ) + + reflection_for_balance = ActiveRecord::Reflection::AggregateReflection.new( + :balance, { :class_name => "Money", :mapping => %w(balance amount) }, Customer + ) + + assert_equal( + [ reflection_for_address, reflection_for_balance ], + Customer.reflect_on_all_aggregations + ) + + assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address) + + assert_equal Address, Customer.reflect_on_aggregation(:address).klass + end + + def test_association_reflection + reflection_for_clients = ActiveRecord::Reflection::AssociationReflection.new( + :clients, { :order => "id", :dependent => true }, Firm + ) + + assert_equal reflection_for_clients, Firm.reflect_on_association(:clients) + + assert_equal Client, Firm.reflect_on_association(:clients).klass + assert_equal Client, Firm.reflect_on_association(:clients_of_firm).klass + end + + def test_association_reflection_in_modules + assert_equal MyApplication::Business::Client, MyApplication::Business::Firm.reflect_on_association(:clients_of_firm).klass + assert_equal MyApplication::Business::Firm, MyApplication::Billing::Account.reflect_on_association(:firm).klass + end +end
\ No newline at end of file diff --git a/activerecord/test/thread_safety_test.rb b/activerecord/test/thread_safety_test.rb new file mode 100644 index 0000000000..635240c6af --- /dev/null +++ b/activerecord/test/thread_safety_test.rb @@ -0,0 +1,33 @@ +require 'abstract_unit' +require 'fixtures/topic' + +class ThreadSafetyTest < Test::Unit::TestCase + def setup + @topics = create_fixtures "topics" + @threads = [] + end + + def test_threading_on_transactions + # SQLite breaks down under thread banging + # Jamis Buck (author of SQLite-ruby): "I know that sqlite itself is not designed for concurrent access" + if ActiveRecord::ConnectionAdapters.const_defined? :SQLiteAdapter + return true if ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::SQLiteAdapter) + end + + 5.times do |thread_number| + @threads << Thread.new(thread_number) do |thread_number| + first, second = Topic.find(1, 2) + Topic.transaction(first, second) do + Topic.logger.info "started #{thread_number}" + first.approved = 1 + second.approved = 0 + first.save + second.save + Topic.logger.info "ended #{thread_number}" + end + end + end + + @threads.each { |t| t.join } + end +end diff --git a/activerecord/test/transactions_test.rb b/activerecord/test/transactions_test.rb new file mode 100644 index 0000000000..18b2ea3e65 --- /dev/null +++ b/activerecord/test/transactions_test.rb @@ -0,0 +1,110 @@ +require 'abstract_unit' +require 'fixtures/topic' + + +class TransactionTest < Test::Unit::TestCase + def setup + @topics = create_fixtures "topics" + @first, @second = Topic.find(1, 2) + end + + def test_successful + Topic.transaction do + @first.approved = 1 + @second.approved = 0 + @first.save + @second.save + end + + assert Topic.find(1).approved?, "First should have been approved" + assert !Topic.find(2).approved?, "Second should have been unapproved" + end + + def test_successful_with_instance_method + @first.transaction do + @first.approved = 1 + @second.approved = 0 + @first.save + @second.save + end + + assert Topic.find(1).approved?, "First should have been approved" + assert !Topic.find(2).approved?, "Second should have been unapproved" + end + + def test_failing_on_exception + begin + Topic.transaction do + @first.approved = true + @second.approved = false + @first.save + @second.save + raise "Bad things!" + end + rescue + # caught it + end + + assert @first.approved?, "First should still be changed in the objects" + assert !@second.approved?, "Second should still be changed in the objects" + + assert !Topic.find(1).approved?, "First shouldn't have been approved" + assert Topic.find(2).approved?, "Second should still be approved" + end + + def test_failing_with_object_rollback + begin + Topic.transaction(@first, @second) do + @first.approved = true + @second.approved = false + @first.save + @second.save + raise "Bad things!" + end + rescue + # caught it + end + + assert !@first.approved?, "First shouldn't have been approved" + assert @second.approved?, "Second should still be approved" + end + + def test_callback_rollback_in_save + add_exception_raising_after_save_callback_to_topic + + begin + @first.approved = true + @first.save + flunk + rescue => e + assert_equal "Make the transaction rollback", e.message + assert !Topic.find(1).approved? + ensure + remove_exception_raising_after_save_callback_to_topic + end + end + + def xtest_nested_explicit_transactions + Topic.transaction do + Topic.transaction do + @first.approved = 1 + @second.approved = 0 + @first.save + @second.save + end + end + + assert Topic.find(1).approved?, "First should have been approved" + assert !Topic.find(2).approved?, "Second should have been unapproved" + end + + + private + def add_exception_raising_after_save_callback_to_topic + Topic.class_eval { def after_save() raise "Make the transaction rollback" end } + end + + def remove_exception_raising_after_save_callback_to_topic + Topic.class_eval { remove_method :after_save } + end +end diff --git a/activerecord/test/unconnected_test.rb b/activerecord/test/unconnected_test.rb new file mode 100755 index 0000000000..0966dd9b06 --- /dev/null +++ b/activerecord/test/unconnected_test.rb @@ -0,0 +1,24 @@ +require 'abstract_unit' + +class TestRecord < ActiveRecord::Base +end + +class TestUnconnectedAdaptor < Test::Unit::TestCase + + def setup + @connection = ActiveRecord::Base.remove_connection + end + + def teardown + ActiveRecord::Base.establish_connection(@connection) + end + + def test_unconnected + assert_raise(ActiveRecord::ConnectionNotEstablished) do + TestRecord.find(1) + end + assert_raise(ActiveRecord::ConnectionNotEstablished) do + TestRecord.new.save + end + end +end diff --git a/activerecord/test/validations_test.rb b/activerecord/test/validations_test.rb new file mode 100755 index 0000000000..27a9b21c7d --- /dev/null +++ b/activerecord/test/validations_test.rb @@ -0,0 +1,126 @@ +require 'abstract_unit' +require 'fixtures/topic' +require 'fixtures/reply' +require 'fixtures/developer' + + +class ValidationsTest < Test::Unit::TestCase + def setup + @topic_fixtures = create_fixtures("topics") + @developers = create_fixtures("developers") + end + + def test_single_field_validation + r = Reply.new + r.title = "There's no content!" + assert !r.save, "A reply without content shouldn't be saveable" + + r.content = "Messa content!" + assert r.save, "A reply with content should be saveable" + end + + def test_single_attr_validation_and_error_msg + r = Reply.new + r.title = "There's no content!" + r.save + assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid" + assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error" + assert_equal 1, r.errors.count + end + + def test_double_attr_validation_and_error_msg + r = Reply.new + assert !r.save + + assert r.errors.invalid?("title"), "A reply without title should mark that attribute as invalid" + assert_equal "Empty", r.errors.on("title"), "A reply without title should contain an error" + + assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid" + assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error" + + assert_equal 2, r.errors.count + end + + def test_error_on_create + r = Reply.new + r.title = "Wrong Create" + assert !r.save + assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid" + assert_equal "is Wrong Create", r.errors.on("title"), "A reply with a bad content should contain an error" + end + + + def test_error_on_update + r = Reply.new + r.title = "Bad" + r.content = "Good" + + assert r.save, "First save should be successful" + + r.title = "Wrong Update" + assert !r.save, "Second save should fail" + + assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid" + assert_equal "is Wrong Update", r.errors.on("title"), "A reply with a bad content should contain an error" + end + + def test_single_error_per_attr_iteration + r = Reply.new + r.save + + errors = [] + r.errors.each { |attr, msg| errors << [attr, msg] } + + assert errors.include?(["title", "Empty"]) + assert errors.include?(["content", "Empty"]) + end + + def test_multiple_errors_per_attr_iteration_with_full_error_composition + r = Reply.new + r.title = "Wrong Create" + r.content = "Mismatch" + r.save + + errors = [] + r.errors.each_full { |error| errors << error } + + assert_equal "Title is Wrong Create", errors[0] + assert_equal "Title is Content Mismatch", errors[1] + assert_equal 2, r.errors.count + end + + def test_errors_on_base + r = Reply.new + r.content = "Mismatch" + r.save + r.errors.add_to_base "Reply is not dignifying" + + errors = [] + r.errors.each_full { |error| errors << error } + + assert_equal "Reply is not dignifying", r.errors.on_base + + assert errors.include?("Title Empty") + assert errors.include?("Reply is not dignifying") + assert_equal 2, r.errors.count + end + + def test_create_without_validation + reply = Reply.new + assert !reply.save + assert reply.save(false) + end + + def test_errors_on_boundary_breaking + developer = Developer.new("name" => "xs") + assert !developer.save + assert_equal "is too short (min is 3 characters)", developer.errors.on("name") + + developer.name = "All too very long for this boundary, it really is" + assert !developer.save + assert_equal "is too long (max is 20 characters)", developer.errors.on("name") + + developer.name = "Just right" + assert developer.save + end +end |