aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test')
-rwxr-xr-xactiverecord/test/abstract_unit.rb22
-rw-r--r--activerecord/test/aggregations_test.rb34
-rwxr-xr-xactiverecord/test/all.sh8
-rwxr-xr-xactiverecord/test/associations_test.rb549
-rwxr-xr-xactiverecord/test/base_test.rb544
-rw-r--r--activerecord/test/class_inheritable_attributes_test.rb33
-rw-r--r--activerecord/test/connections/native_mysql/connection.rb24
-rw-r--r--activerecord/test/connections/native_postgresql/connection.rb24
-rw-r--r--activerecord/test/connections/native_sqlite/connection.rb34
-rw-r--r--activerecord/test/connections/native_sqlserver/connection.rb15
-rwxr-xr-xactiverecord/test/deprecated_associations_test.rb335
-rwxr-xr-xactiverecord/test/finder_test.rb67
-rw-r--r--activerecord/test/fixtures/accounts.yml8
-rw-r--r--activerecord/test/fixtures/auto_id.rb4
-rw-r--r--activerecord/test/fixtures/bad_fixtures/attr_with_numeric_first_char1
-rw-r--r--activerecord/test/fixtures/bad_fixtures/attr_with_spaces1
-rw-r--r--activerecord/test/fixtures/bad_fixtures/blank_line3
-rw-r--r--activerecord/test/fixtures/bad_fixtures/duplicate_attributes3
-rw-r--r--activerecord/test/fixtures/bad_fixtures/missing_value1
-rw-r--r--activerecord/test/fixtures/column_name.rb3
-rwxr-xr-xactiverecord/test/fixtures/companies/first_client6
-rwxr-xr-xactiverecord/test/fixtures/companies/first_firm4
-rwxr-xr-xactiverecord/test/fixtures/companies/second_client6
-rwxr-xr-xactiverecord/test/fixtures/company.rb37
-rw-r--r--activerecord/test/fixtures/company_in_module.rb47
-rw-r--r--activerecord/test/fixtures/course.rb3
-rw-r--r--activerecord/test/fixtures/courses/java2
-rw-r--r--activerecord/test/fixtures/courses/ruby2
-rw-r--r--activerecord/test/fixtures/customer.rb30
-rw-r--r--activerecord/test/fixtures/customers/david6
-rwxr-xr-xactiverecord/test/fixtures/db_definitions/mysql.sql97
-rw-r--r--activerecord/test/fixtures/db_definitions/mysql2.sql4
-rw-r--r--activerecord/test/fixtures/db_definitions/postgresql.sql114
-rw-r--r--activerecord/test/fixtures/db_definitions/postgresql2.sql4
-rw-r--r--activerecord/test/fixtures/db_definitions/sqlite.sql86
-rw-r--r--activerecord/test/fixtures/db_definitions/sqlite2.sql4
-rw-r--r--activerecord/test/fixtures/db_definitions/sqlserver.sql96
-rw-r--r--activerecord/test/fixtures/db_definitions/sqlserver2.sql4
-rw-r--r--activerecord/test/fixtures/default.rb2
-rw-r--r--activerecord/test/fixtures/developer.rb8
-rw-r--r--activerecord/test/fixtures/developers.yml13
-rw-r--r--activerecord/test/fixtures/developers_projects/david_action_controller3
-rw-r--r--activerecord/test/fixtures/developers_projects/david_active_record3
-rw-r--r--activerecord/test/fixtures/developers_projects/jamis_active_record2
-rw-r--r--activerecord/test/fixtures/entrant.rb3
-rw-r--r--activerecord/test/fixtures/entrants/first3
-rw-r--r--activerecord/test/fixtures/entrants/second3
-rw-r--r--activerecord/test/fixtures/entrants/third3
-rw-r--r--activerecord/test/fixtures/movie.rb5
-rw-r--r--activerecord/test/fixtures/movies/first2
-rw-r--r--activerecord/test/fixtures/movies/second2
-rw-r--r--activerecord/test/fixtures/project.rb4
-rw-r--r--activerecord/test/fixtures/projects/action_controller2
-rw-r--r--activerecord/test/fixtures/projects/active_record2
-rwxr-xr-xactiverecord/test/fixtures/reply.rb21
-rw-r--r--activerecord/test/fixtures/subscriber.rb5
-rw-r--r--activerecord/test/fixtures/subscribers/first2
-rw-r--r--activerecord/test/fixtures/subscribers/second2
-rwxr-xr-xactiverecord/test/fixtures/topic.rb20
-rwxr-xr-xactiverecord/test/fixtures/topics/first9
-rwxr-xr-xactiverecord/test/fixtures/topics/second8
-rwxr-xr-xactiverecord/test/fixtures_test.rb84
-rw-r--r--activerecord/test/inflector_test.rb121
-rwxr-xr-xactiverecord/test/inheritance_test.rb125
-rwxr-xr-xactiverecord/test/lifecycle_test.rb110
-rw-r--r--activerecord/test/modules_test.rb29
-rw-r--r--activerecord/test/multiple_db_test.rb46
-rw-r--r--activerecord/test/pk_test.rb59
-rw-r--r--activerecord/test/reflection_test.rb78
-rw-r--r--activerecord/test/thread_safety_test.rb33
-rw-r--r--activerecord/test/transactions_test.rb110
-rwxr-xr-xactiverecord/test/unconnected_test.rb24
-rwxr-xr-xactiverecord/test/validations_test.rb126
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