mirror of
https://github.com/TracksApp/tracks.git
synced 2026-02-20 14:14:09 +01:00
freeze rails 2.2
This commit is contained in:
parent
fe5f962dcf
commit
59d5d4c8b6
1468 changed files with 213171 additions and 0 deletions
24
vendor/rails/activerecord/test/cases/aaa_create_tables_test.rb
vendored
Normal file
24
vendor/rails/activerecord/test/cases/aaa_create_tables_test.rb
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# The filename begins with "aaa" to ensure this is the first test.
|
||||
require "cases/helper"
|
||||
|
||||
class AAACreateTablesTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def test_load_schema
|
||||
eval(File.read(SCHEMA_ROOT + "/schema.rb"))
|
||||
if File.exists?(adapter_specific_schema_file)
|
||||
eval(File.read(adapter_specific_schema_file))
|
||||
end
|
||||
assert true
|
||||
end
|
||||
|
||||
def test_drop_and_create_courses_table
|
||||
eval(File.read(SCHEMA_ROOT + "/schema2.rb"))
|
||||
assert true
|
||||
end
|
||||
|
||||
private
|
||||
def adapter_specific_schema_file
|
||||
SCHEMA_ROOT + '/' + ActiveRecord::Base.connection.adapter_name.downcase + '_specific_schema.rb'
|
||||
end
|
||||
end
|
||||
100
vendor/rails/activerecord/test/cases/active_schema_test_mysql.rb
vendored
Normal file
100
vendor/rails/activerecord/test/cases/active_schema_test_mysql.rb
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
require "cases/helper"
|
||||
|
||||
class ActiveSchemaTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
|
||||
alias_method :execute_without_stub, :execute
|
||||
def execute(sql, name = nil) return sql end
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
|
||||
remove_method :execute
|
||||
alias_method :execute, :execute_without_stub
|
||||
end
|
||||
end
|
||||
|
||||
def test_drop_table
|
||||
assert_equal "DROP TABLE `people`", drop_table(:people)
|
||||
end
|
||||
|
||||
if current_adapter?(:MysqlAdapter)
|
||||
def test_create_mysql_database_with_encoding
|
||||
assert_equal "CREATE DATABASE `matt` DEFAULT CHARACTER SET `utf8`", create_database(:matt)
|
||||
assert_equal "CREATE DATABASE `aimonetti` DEFAULT CHARACTER SET `latin1`", create_database(:aimonetti, {:charset => 'latin1'})
|
||||
assert_equal "CREATE DATABASE `matt_aimonetti` DEFAULT CHARACTER SET `big5` COLLATE `big5_chinese_ci`", create_database(:matt_aimonetti, {:charset => :big5, :collation => :big5_chinese_ci})
|
||||
end
|
||||
|
||||
def test_recreate_mysql_database_with_encoding
|
||||
create_database(:luca, {:charset => 'latin1'})
|
||||
assert_equal "CREATE DATABASE `luca` DEFAULT CHARACTER SET `latin1`", recreate_database(:luca, {:charset => 'latin1'})
|
||||
end
|
||||
end
|
||||
|
||||
def test_add_column
|
||||
assert_equal "ALTER TABLE `people` ADD `last_name` varchar(255)", add_column(:people, :last_name, :string)
|
||||
end
|
||||
|
||||
def test_add_column_with_limit
|
||||
assert_equal "ALTER TABLE `people` ADD `key` varchar(32)", add_column(:people, :key, :string, :limit => 32)
|
||||
end
|
||||
|
||||
def test_drop_table_with_specific_database
|
||||
assert_equal "DROP TABLE `otherdb`.`people`", drop_table('otherdb.people')
|
||||
end
|
||||
|
||||
def test_add_timestamps
|
||||
with_real_execute do
|
||||
begin
|
||||
ActiveRecord::Base.connection.create_table :delete_me do |t|
|
||||
end
|
||||
ActiveRecord::Base.connection.add_timestamps :delete_me
|
||||
assert column_present?('delete_me', 'updated_at', 'datetime')
|
||||
assert column_present?('delete_me', 'created_at', 'datetime')
|
||||
ensure
|
||||
ActiveRecord::Base.connection.drop_table :delete_me rescue nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_remove_timestamps
|
||||
with_real_execute do
|
||||
begin
|
||||
ActiveRecord::Base.connection.create_table :delete_me do |t|
|
||||
t.timestamps
|
||||
end
|
||||
ActiveRecord::Base.connection.remove_timestamps :delete_me
|
||||
assert !column_present?('delete_me', 'updated_at', 'datetime')
|
||||
assert !column_present?('delete_me', 'created_at', 'datetime')
|
||||
ensure
|
||||
ActiveRecord::Base.connection.drop_table :delete_me rescue nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def with_real_execute
|
||||
#we need to actually modify some data, so we make execute point to the original method
|
||||
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
|
||||
alias_method :execute_with_stub, :execute
|
||||
alias_method :execute, :execute_without_stub
|
||||
end
|
||||
yield
|
||||
ensure
|
||||
#before finishing, we restore the alias to the mock-up method
|
||||
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
|
||||
alias_method :execute, :execute_with_stub
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def method_missing(method_symbol, *arguments)
|
||||
ActiveRecord::Base.connection.send(method_symbol, *arguments)
|
||||
end
|
||||
|
||||
def column_present?(table_name, column_name, type)
|
||||
results = ActiveRecord::Base.connection.select_all("SHOW FIELDS FROM #{table_name} LIKE '#{column_name}'")
|
||||
results.first && results.first['Type'] == type
|
||||
end
|
||||
end
|
||||
24
vendor/rails/activerecord/test/cases/active_schema_test_postgresql.rb
vendored
Normal file
24
vendor/rails/activerecord/test/cases/active_schema_test_postgresql.rb
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
require 'cases/helper'
|
||||
|
||||
class PostgresqlActiveSchemaTest < Test::Unit::TestCase
|
||||
def setup
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
|
||||
alias_method :real_execute, :execute
|
||||
def execute(sql, name = nil) sql end
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:alias_method, :execute, :real_execute)
|
||||
end
|
||||
|
||||
def test_create_database_with_encoding
|
||||
assert_equal %(CREATE DATABASE "matt" ENCODING = 'utf8'), create_database(:matt)
|
||||
assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1)
|
||||
end
|
||||
|
||||
private
|
||||
def method_missing(method_symbol, *arguments)
|
||||
ActiveRecord::Base.connection.send(method_symbol, *arguments)
|
||||
end
|
||||
end
|
||||
133
vendor/rails/activerecord/test/cases/adapter_test.rb
vendored
Normal file
133
vendor/rails/activerecord/test/cases/adapter_test.rb
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
require "cases/helper"
|
||||
|
||||
class AdapterTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
end
|
||||
|
||||
def test_tables
|
||||
tables = @connection.tables
|
||||
assert tables.include?("accounts")
|
||||
assert tables.include?("authors")
|
||||
assert tables.include?("tasks")
|
||||
assert tables.include?("topics")
|
||||
end
|
||||
|
||||
def test_table_exists?
|
||||
assert @connection.table_exists?("accounts")
|
||||
assert !@connection.table_exists?("nonexistingtable")
|
||||
end
|
||||
|
||||
def test_indexes
|
||||
idx_name = "accounts_idx"
|
||||
|
||||
if @connection.respond_to?(:indexes)
|
||||
indexes = @connection.indexes("accounts")
|
||||
assert indexes.empty?
|
||||
|
||||
@connection.add_index :accounts, :firm_id, :name => idx_name
|
||||
indexes = @connection.indexes("accounts")
|
||||
assert_equal "accounts", indexes.first.table
|
||||
# OpenBase does not have the concept of a named index
|
||||
# Indexes are merely properties of columns.
|
||||
assert_equal idx_name, indexes.first.name unless current_adapter?(:OpenBaseAdapter)
|
||||
assert !indexes.first.unique
|
||||
assert_equal ["firm_id"], indexes.first.columns
|
||||
else
|
||||
warn "#{@connection.class} does not respond to #indexes"
|
||||
end
|
||||
|
||||
ensure
|
||||
@connection.remove_index(:accounts, :name => idx_name) rescue nil
|
||||
end
|
||||
|
||||
def test_current_database
|
||||
if @connection.respond_to?(:current_database)
|
||||
assert_equal ENV['ARUNIT_DB_NAME'] || "activerecord_unittest", @connection.current_database
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:MysqlAdapter)
|
||||
def test_charset
|
||||
assert_not_nil @connection.charset
|
||||
assert_not_equal 'character_set_database', @connection.charset
|
||||
assert_equal @connection.show_variable('character_set_database'), @connection.charset
|
||||
end
|
||||
|
||||
def test_collation
|
||||
assert_not_nil @connection.collation
|
||||
assert_not_equal 'collation_database', @connection.collation
|
||||
assert_equal @connection.show_variable('collation_database'), @connection.collation
|
||||
end
|
||||
|
||||
def test_show_nonexistent_variable_returns_nil
|
||||
assert_nil @connection.show_variable('foo_bar_baz')
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter)
|
||||
def test_encoding
|
||||
assert_not_nil @connection.encoding
|
||||
end
|
||||
end
|
||||
|
||||
def test_table_alias
|
||||
def @connection.test_table_alias_length() 10; end
|
||||
class << @connection
|
||||
alias_method :old_table_alias_length, :table_alias_length
|
||||
alias_method :table_alias_length, :test_table_alias_length
|
||||
end
|
||||
|
||||
assert_equal 'posts', @connection.table_alias_for('posts')
|
||||
assert_equal 'posts_comm', @connection.table_alias_for('posts_comments')
|
||||
assert_equal 'dbo_posts', @connection.table_alias_for('dbo.posts')
|
||||
|
||||
class << @connection
|
||||
remove_method :table_alias_length
|
||||
alias_method :table_alias_length, :old_table_alias_length
|
||||
end
|
||||
end
|
||||
|
||||
# test resetting sequences in odd tables in postgreSQL
|
||||
if ActiveRecord::Base.connection.respond_to?(:reset_pk_sequence!)
|
||||
require 'models/movie'
|
||||
require 'models/subscriber'
|
||||
|
||||
def test_reset_empty_table_with_custom_pk
|
||||
Movie.delete_all
|
||||
Movie.connection.reset_pk_sequence! 'movies'
|
||||
assert_equal 1, Movie.create(:name => 'fight club').id
|
||||
end
|
||||
|
||||
if ActiveRecord::Base.connection.adapter_name != "FrontBase"
|
||||
def test_reset_table_with_non_integer_pk
|
||||
Subscriber.delete_all
|
||||
Subscriber.connection.reset_pk_sequence! 'subscribers'
|
||||
sub = Subscriber.new(:name => 'robert drake')
|
||||
sub.id = 'bob drake'
|
||||
assert_nothing_raised { sub.save! }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas
|
||||
sql_inject = "1 select * from schema"
|
||||
assert_equal " LIMIT 1", @connection.add_limit_offset!("", :limit=>sql_inject)
|
||||
if current_adapter?(:MysqlAdapter)
|
||||
assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
|
||||
else
|
||||
assert_equal " LIMIT 1 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
|
||||
end
|
||||
end
|
||||
|
||||
def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas
|
||||
sql_inject = "1, 7 procedure help()"
|
||||
if current_adapter?(:MysqlAdapter)
|
||||
assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject)
|
||||
assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=> '1 ; DROP TABLE USERS', :offset=>7)
|
||||
else
|
||||
assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject)
|
||||
assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
|
||||
end
|
||||
end
|
||||
end
|
||||
167
vendor/rails/activerecord/test/cases/aggregations_test.rb
vendored
Normal file
167
vendor/rails/activerecord/test/cases/aggregations_test.rb
vendored
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
require "cases/helper"
|
||||
require 'models/customer'
|
||||
|
||||
class AggregationsTest < ActiveRecord::TestCase
|
||||
fixtures :customers
|
||||
|
||||
def test_find_single_value_object
|
||||
assert_equal 50, customers(:david).balance.amount
|
||||
assert_kind_of Money, customers(:david).balance
|
||||
assert_equal 300, customers(:david).balance.exchange_to("DKK").amount
|
||||
end
|
||||
|
||||
def test_find_multiple_value_object
|
||||
assert_equal customers(:david).address_street, customers(:david).address.street
|
||||
assert(
|
||||
customers(:david).address.close_to?(Address.new("Different Street", customers(:david).address_city, customers(:david).address_country))
|
||||
)
|
||||
end
|
||||
|
||||
def test_change_single_value_object
|
||||
customers(:david).balance = Money.new(100)
|
||||
customers(:david).save
|
||||
assert_equal 100, customers(:david).reload.balance.amount
|
||||
end
|
||||
|
||||
def test_immutable_value_objects
|
||||
customers(:david).balance = Money.new(100)
|
||||
assert_raise(ActiveSupport::FrozenObjectError) { customers(:david).balance.instance_eval { @amount = 20 } }
|
||||
end
|
||||
|
||||
def test_inferred_mapping
|
||||
assert_equal "35.544623640962634", customers(:david).gps_location.latitude
|
||||
assert_equal "-105.9309951055148", customers(:david).gps_location.longitude
|
||||
|
||||
customers(:david).gps_location = GpsLocation.new("39x-110")
|
||||
|
||||
assert_equal "39", customers(:david).gps_location.latitude
|
||||
assert_equal "-110", customers(:david).gps_location.longitude
|
||||
|
||||
customers(:david).save
|
||||
|
||||
customers(:david).reload
|
||||
|
||||
assert_equal "39", customers(:david).gps_location.latitude
|
||||
assert_equal "-110", customers(:david).gps_location.longitude
|
||||
end
|
||||
|
||||
def test_reloaded_instance_refreshes_aggregations
|
||||
assert_equal "35.544623640962634", customers(:david).gps_location.latitude
|
||||
assert_equal "-105.9309951055148", customers(:david).gps_location.longitude
|
||||
|
||||
Customer.update_all("gps_location = '24x113'")
|
||||
customers(:david).reload
|
||||
assert_equal '24x113', customers(:david)['gps_location']
|
||||
|
||||
assert_equal GpsLocation.new('24x113'), customers(:david).gps_location
|
||||
end
|
||||
|
||||
def test_gps_equality
|
||||
assert GpsLocation.new('39x110') == GpsLocation.new('39x110')
|
||||
end
|
||||
|
||||
def test_gps_inequality
|
||||
assert GpsLocation.new('39x110') != GpsLocation.new('39x111')
|
||||
end
|
||||
|
||||
def test_allow_nil_gps_is_nil
|
||||
assert_equal nil, customers(:zaphod).gps_location
|
||||
end
|
||||
|
||||
def test_allow_nil_gps_set_to_nil
|
||||
customers(:david).gps_location = nil
|
||||
customers(:david).save
|
||||
customers(:david).reload
|
||||
assert_equal nil, customers(:david).gps_location
|
||||
end
|
||||
|
||||
def test_allow_nil_set_address_attributes_to_nil
|
||||
customers(:zaphod).address = nil
|
||||
assert_equal nil, customers(:zaphod).attributes[:address_street]
|
||||
assert_equal nil, customers(:zaphod).attributes[:address_city]
|
||||
assert_equal nil, customers(:zaphod).attributes[:address_country]
|
||||
end
|
||||
|
||||
def test_allow_nil_address_set_to_nil
|
||||
customers(:zaphod).address = nil
|
||||
customers(:zaphod).save
|
||||
customers(:zaphod).reload
|
||||
assert_equal nil, customers(:zaphod).address
|
||||
end
|
||||
|
||||
def test_nil_raises_error_when_allow_nil_is_false
|
||||
assert_raise(NoMethodError) { customers(:david).balance = nil }
|
||||
end
|
||||
|
||||
def test_allow_nil_address_loaded_when_only_some_attributes_are_nil
|
||||
customers(:zaphod).address_street = nil
|
||||
customers(:zaphod).save
|
||||
customers(:zaphod).reload
|
||||
assert_kind_of Address, customers(:zaphod).address
|
||||
assert customers(:zaphod).address.street.nil?
|
||||
end
|
||||
|
||||
def test_nil_assignment_results_in_nil
|
||||
customers(:david).gps_location = GpsLocation.new('39x111')
|
||||
assert_not_equal nil, customers(:david).gps_location
|
||||
customers(:david).gps_location = nil
|
||||
assert_equal nil, customers(:david).gps_location
|
||||
end
|
||||
|
||||
def test_custom_constructor
|
||||
assert_equal 'Barney GUMBLE', customers(:barney).fullname.to_s
|
||||
assert_kind_of Fullname, customers(:barney).fullname
|
||||
end
|
||||
|
||||
def test_custom_converter
|
||||
customers(:barney).fullname = 'Barnoit Gumbleau'
|
||||
assert_equal 'Barnoit GUMBLEAU', customers(:barney).fullname.to_s
|
||||
assert_kind_of Fullname, customers(:barney).fullname
|
||||
end
|
||||
end
|
||||
|
||||
class DeprecatedAggregationsTest < ActiveRecord::TestCase
|
||||
class Person < ActiveRecord::Base; end
|
||||
|
||||
def test_conversion_block_is_deprecated
|
||||
assert_deprecated 'conversion block has been deprecated' do
|
||||
Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money }
|
||||
end
|
||||
end
|
||||
|
||||
def test_conversion_block_used_when_converter_option_is_nil
|
||||
assert_deprecated 'conversion block has been deprecated' do
|
||||
Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money }
|
||||
end
|
||||
assert_raise(NoMethodError) { Person.new.balance = 5 }
|
||||
end
|
||||
|
||||
def test_converter_option_overrides_conversion_block
|
||||
assert_deprecated 'conversion block has been deprecated' do
|
||||
Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| Money.new(balance) }) { |balance| balance.to_money }
|
||||
end
|
||||
|
||||
person = Person.new
|
||||
assert_nothing_raised { person.balance = 5 }
|
||||
assert_equal 5, person.balance.amount
|
||||
assert_kind_of Money, person.balance
|
||||
end
|
||||
end
|
||||
|
||||
class OverridingAggregationsTest < ActiveRecord::TestCase
|
||||
class Name; end
|
||||
class DifferentName; end
|
||||
|
||||
class Person < ActiveRecord::Base
|
||||
composed_of :composed_of, :mapping => %w(person_first_name first_name)
|
||||
end
|
||||
|
||||
class DifferentPerson < Person
|
||||
composed_of :composed_of, :class_name => 'DifferentName', :mapping => %w(different_person_first_name first_name)
|
||||
end
|
||||
|
||||
def test_composed_of_aggregation_redefinition_reflections_should_differ_and_not_inherited
|
||||
assert_not_equal Person.reflect_on_aggregation(:composed_of),
|
||||
DifferentPerson.reflect_on_aggregation(:composed_of)
|
||||
end
|
||||
end
|
||||
33
vendor/rails/activerecord/test/cases/ar_schema_test.rb
vendored
Normal file
33
vendor/rails/activerecord/test/cases/ar_schema_test.rb
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
require "cases/helper"
|
||||
require 'active_record/schema'
|
||||
|
||||
if ActiveRecord::Base.connection.supports_migrations?
|
||||
|
||||
class ActiveRecordSchemaTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
end
|
||||
|
||||
def teardown
|
||||
@connection.drop_table :fruits rescue nil
|
||||
end
|
||||
|
||||
def test_schema_define
|
||||
ActiveRecord::Schema.define(:version => 7) do
|
||||
create_table :fruits do |t|
|
||||
t.column :color, :string
|
||||
t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle
|
||||
t.column :texture, :string
|
||||
t.column :flavor, :string
|
||||
end
|
||||
end
|
||||
|
||||
assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
|
||||
assert_nothing_raised { @connection.select_all "SELECT * FROM schema_migrations" }
|
||||
assert_equal 7, ActiveRecord::Migrator::current_version
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
441
vendor/rails/activerecord/test/cases/associations/belongs_to_associations_test.rb
vendored
Normal file
441
vendor/rails/activerecord/test/cases/associations/belongs_to_associations_test.rb
vendored
Normal file
|
|
@ -0,0 +1,441 @@
|
|||
require "cases/helper"
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/company'
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/computer'
|
||||
require 'models/customer'
|
||||
require 'models/order'
|
||||
require 'models/post'
|
||||
require 'models/author'
|
||||
require 'models/tag'
|
||||
require 'models/tagging'
|
||||
require 'models/comment'
|
||||
require 'models/sponsor'
|
||||
require 'models/member'
|
||||
|
||||
class BelongsToAssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :accounts, :companies, :developers, :projects, :topics,
|
||||
:developers_projects, :computers, :authors, :posts, :tags, :taggings, :comments
|
||||
|
||||
def test_belongs_to
|
||||
Client.find(3).firm.name
|
||||
assert_equal companies(:first_firm).name, Client.find(3).firm.name
|
||||
assert !Client.find(3).firm.nil?, "Microsoft should have a firm"
|
||||
end
|
||||
|
||||
def test_proxy_assignment
|
||||
account = Account.find(1)
|
||||
assert_nothing_raised { account.firm = account.firm }
|
||||
end
|
||||
|
||||
def test_triple_equality
|
||||
assert Client.find(3).firm === Firm
|
||||
assert Firm === Client.find(3).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_no_unexpected_aliasing
|
||||
first_firm = companies(:first_firm)
|
||||
another_firm = companies(:another_firm)
|
||||
|
||||
citibank = Account.create("credit_limit" => 10)
|
||||
citibank.firm = first_firm
|
||||
original_proxy = citibank.firm
|
||||
citibank.firm = another_firm
|
||||
|
||||
assert_equal first_firm.object_id, original_proxy.target.object_id
|
||||
assert_equal another_firm.object_id, citibank.firm.target.object_id
|
||||
end
|
||||
|
||||
def test_creating_the_belonging_object
|
||||
citibank = Account.create("credit_limit" => 10)
|
||||
apple = citibank.create_firm("name" => "Apple")
|
||||
assert_equal apple, citibank.firm
|
||||
citibank.save
|
||||
citibank.reload
|
||||
assert_equal apple, citibank.firm
|
||||
end
|
||||
|
||||
def test_building_the_belonging_object
|
||||
citibank = Account.create("credit_limit" => 10)
|
||||
apple = citibank.build_firm("name" => "Apple")
|
||||
citibank.save
|
||||
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_with_select
|
||||
assert_equal Company.find(2).firm_with_select.attributes.size, 1
|
||||
assert_equal Company.find(2, :include => :firm_with_select ).firm_with_select.attributes.size, 1
|
||||
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 test_belongs_to_counter_with_assigning_nil
|
||||
p = Post.find(1)
|
||||
c = Comment.find(1)
|
||||
|
||||
assert_equal p.id, c.post_id
|
||||
assert_equal 2, Post.find(p.id).comments.size
|
||||
|
||||
c.post = nil
|
||||
|
||||
assert_equal 1, Post.find(p.id).comments.size
|
||||
end
|
||||
|
||||
def test_belongs_to_counter_with_reassigning
|
||||
t1 = Topic.create("title" => "t1")
|
||||
t2 = Topic.create("title" => "t2")
|
||||
r1 = Reply.new("title" => "r1", "content" => "r1")
|
||||
r1.topic = t1
|
||||
|
||||
assert r1.save
|
||||
assert_equal 1, Topic.find(t1.id).replies.size
|
||||
assert_equal 0, Topic.find(t2.id).replies.size
|
||||
|
||||
r1.topic = Topic.find(t2.id)
|
||||
|
||||
assert r1.save
|
||||
assert_equal 0, Topic.find(t1.id).replies.size
|
||||
assert_equal 1, Topic.find(t2.id).replies.size
|
||||
|
||||
r1.topic = nil
|
||||
|
||||
assert_equal 0, Topic.find(t1.id).replies.size
|
||||
assert_equal 0, Topic.find(t2.id).replies.size
|
||||
|
||||
r1.topic = t1
|
||||
|
||||
assert_equal 1, Topic.find(t1.id).replies.size
|
||||
assert_equal 0, Topic.find(t2.id).replies.size
|
||||
|
||||
r1.destroy
|
||||
|
||||
assert_equal 0, Topic.find(t1.id).replies.size
|
||||
assert_equal 0, Topic.find(t2.id).replies.size
|
||||
end
|
||||
|
||||
def test_belongs_to_counter_after_save
|
||||
topic = Topic.create!(:title => "monday night")
|
||||
topic.replies.create!(:title => "re: monday night", :content => "football")
|
||||
assert_equal 1, Topic.find(topic.id)[:replies_count]
|
||||
|
||||
topic.save!
|
||||
assert_equal 1, Topic.find(topic.id)[:replies_count]
|
||||
end
|
||||
|
||||
def test_belongs_to_counter_after_update_attributes
|
||||
topic = Topic.create!(:title => "37s")
|
||||
topic.replies.create!(:title => "re: 37s", :content => "rails")
|
||||
assert_equal 1, Topic.find(topic.id)[:replies_count]
|
||||
|
||||
topic.update_attributes(:title => "37signals")
|
||||
assert_equal 1, Topic.find(topic.id)[:replies_count]
|
||||
end
|
||||
|
||||
def test_belongs_to_counter_after_save
|
||||
topic = Topic.create("title" => "monday night")
|
||||
topic.replies.create("title" => "re: monday night", "content" => "football")
|
||||
assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count")
|
||||
|
||||
topic.save
|
||||
assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count")
|
||||
end
|
||||
|
||||
def test_belongs_to_counter_after_update_attributes
|
||||
topic = Topic.create("title" => "37s")
|
||||
topic.replies.create("title" => "re: 37s", "content" => "rails")
|
||||
assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count")
|
||||
|
||||
topic.update_attributes("title" => "37signals")
|
||||
assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count")
|
||||
end
|
||||
|
||||
def test_assignment_before_parent_saved
|
||||
client = Client.find(:first)
|
||||
apple = Firm.new("name" => "Apple")
|
||||
client.firm = apple
|
||||
assert_equal apple, client.firm
|
||||
assert apple.new_record?
|
||||
assert client.save
|
||||
assert apple.save
|
||||
assert !apple.new_record?
|
||||
assert_equal apple, client.firm
|
||||
assert_equal apple, client.firm(true)
|
||||
end
|
||||
|
||||
def test_assignment_before_child_saved
|
||||
final_cut = Client.new("name" => "Final Cut")
|
||||
firm = Firm.find(1)
|
||||
final_cut.firm = firm
|
||||
assert final_cut.new_record?
|
||||
assert final_cut.save
|
||||
assert !final_cut.new_record?
|
||||
assert !firm.new_record?
|
||||
assert_equal firm, final_cut.firm
|
||||
assert_equal firm, final_cut.firm(true)
|
||||
end
|
||||
|
||||
def test_assignment_before_either_saved
|
||||
final_cut = Client.new("name" => "Final Cut")
|
||||
apple = Firm.new("name" => "Apple")
|
||||
final_cut.firm = apple
|
||||
assert final_cut.new_record?
|
||||
assert apple.new_record?
|
||||
assert final_cut.save
|
||||
assert !final_cut.new_record?
|
||||
assert !apple.new_record?
|
||||
assert_equal apple, final_cut.firm
|
||||
assert_equal apple, final_cut.firm(true)
|
||||
end
|
||||
|
||||
def test_new_record_with_foreign_key_but_no_object
|
||||
c = Client.new("firm_id" => 1)
|
||||
assert_equal Firm.find(:first), c.firm_with_basic_id
|
||||
end
|
||||
|
||||
def test_forgetting_the_load_when_foreign_key_enters_late
|
||||
c = Client.new
|
||||
assert_nil c.firm_with_basic_id
|
||||
|
||||
c.firm_id = 1
|
||||
assert_equal Firm.find(:first), c.firm_with_basic_id
|
||||
end
|
||||
|
||||
def test_field_name_same_as_foreign_key
|
||||
computer = Computer.find(1)
|
||||
assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # '
|
||||
end
|
||||
|
||||
def test_counter_cache
|
||||
topic = Topic.create :title => "Zoom-zoom-zoom"
|
||||
assert_equal 0, topic[:replies_count]
|
||||
|
||||
reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
|
||||
reply.topic = topic
|
||||
|
||||
assert_equal 1, topic.reload[:replies_count]
|
||||
assert_equal 1, topic.replies.size
|
||||
|
||||
topic[:replies_count] = 15
|
||||
assert_equal 15, topic.replies.size
|
||||
end
|
||||
|
||||
def test_custom_counter_cache
|
||||
reply = Reply.create(:title => "re: zoom", :content => "speedy quick!")
|
||||
assert_equal 0, reply[:replies_count]
|
||||
|
||||
silly = SillyReply.create(:title => "gaga", :content => "boo-boo")
|
||||
silly.reply = reply
|
||||
|
||||
assert_equal 1, reply.reload[:replies_count]
|
||||
assert_equal 1, reply.replies.size
|
||||
|
||||
reply[:replies_count] = 17
|
||||
assert_equal 17, reply.replies.size
|
||||
end
|
||||
|
||||
def test_store_two_association_with_one_save
|
||||
num_orders = Order.count
|
||||
num_customers = Customer.count
|
||||
order = Order.new
|
||||
|
||||
customer1 = order.billing = Customer.new
|
||||
customer2 = order.shipping = Customer.new
|
||||
assert order.save
|
||||
assert_equal customer1, order.billing
|
||||
assert_equal customer2, order.shipping
|
||||
|
||||
order.reload
|
||||
|
||||
assert_equal customer1, order.billing
|
||||
assert_equal customer2, order.shipping
|
||||
|
||||
assert_equal num_orders +1, Order.count
|
||||
assert_equal num_customers +2, Customer.count
|
||||
end
|
||||
|
||||
|
||||
def test_store_association_in_two_relations_with_one_save
|
||||
num_orders = Order.count
|
||||
num_customers = Customer.count
|
||||
order = Order.new
|
||||
|
||||
customer = order.billing = order.shipping = Customer.new
|
||||
assert order.save
|
||||
assert_equal customer, order.billing
|
||||
assert_equal customer, order.shipping
|
||||
|
||||
order.reload
|
||||
|
||||
assert_equal customer, order.billing
|
||||
assert_equal customer, order.shipping
|
||||
|
||||
assert_equal num_orders +1, Order.count
|
||||
assert_equal num_customers +1, Customer.count
|
||||
end
|
||||
|
||||
def test_store_association_in_two_relations_with_one_save_in_existing_object
|
||||
num_orders = Order.count
|
||||
num_customers = Customer.count
|
||||
order = Order.create
|
||||
|
||||
customer = order.billing = order.shipping = Customer.new
|
||||
assert order.save
|
||||
assert_equal customer, order.billing
|
||||
assert_equal customer, order.shipping
|
||||
|
||||
order.reload
|
||||
|
||||
assert_equal customer, order.billing
|
||||
assert_equal customer, order.shipping
|
||||
|
||||
assert_equal num_orders +1, Order.count
|
||||
assert_equal num_customers +1, Customer.count
|
||||
end
|
||||
|
||||
def test_store_association_in_two_relations_with_one_save_in_existing_object_with_values
|
||||
num_orders = Order.count
|
||||
num_customers = Customer.count
|
||||
order = Order.create
|
||||
|
||||
customer = order.billing = order.shipping = Customer.new
|
||||
assert order.save
|
||||
assert_equal customer, order.billing
|
||||
assert_equal customer, order.shipping
|
||||
|
||||
order.reload
|
||||
|
||||
customer = order.billing = order.shipping = Customer.new
|
||||
|
||||
assert order.save
|
||||
order.reload
|
||||
|
||||
assert_equal customer, order.billing
|
||||
assert_equal customer, order.shipping
|
||||
|
||||
assert_equal num_orders +1, Order.count
|
||||
assert_equal num_customers +2, Customer.count
|
||||
end
|
||||
|
||||
|
||||
def test_association_assignment_sticks
|
||||
post = Post.find(:first)
|
||||
|
||||
author1, author2 = Author.find(:all, :limit => 2)
|
||||
assert_not_nil author1
|
||||
assert_not_nil author2
|
||||
|
||||
# make sure the association is loaded
|
||||
post.author
|
||||
|
||||
# set the association by id, directly
|
||||
post.author_id = author2.id
|
||||
|
||||
# save and reload
|
||||
post.save!
|
||||
post.reload
|
||||
|
||||
# the author id of the post should be the id we set
|
||||
assert_equal post.author_id, author2.id
|
||||
end
|
||||
|
||||
def test_cant_save_readonly_association
|
||||
assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! }
|
||||
assert companies(:first_client).readonly_firm.readonly?
|
||||
end
|
||||
|
||||
def test_polymorphic_assignment_foreign_type_field_updating
|
||||
# should update when assigning a saved record
|
||||
sponsor = Sponsor.new
|
||||
member = Member.create
|
||||
sponsor.sponsorable = member
|
||||
assert_equal "Member", sponsor.sponsorable_type
|
||||
|
||||
# should update when assigning a new record
|
||||
sponsor = Sponsor.new
|
||||
member = Member.new
|
||||
sponsor.sponsorable = member
|
||||
assert_equal "Member", sponsor.sponsorable_type
|
||||
end
|
||||
|
||||
def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records
|
||||
sponsor = Sponsor.new
|
||||
saved_member = Member.create
|
||||
new_member = Member.new
|
||||
|
||||
sponsor.sponsorable = saved_member
|
||||
assert_equal saved_member.id, sponsor.sponsorable_id
|
||||
|
||||
sponsor.sponsorable = new_member
|
||||
assert_equal nil, sponsor.sponsorable_id
|
||||
end
|
||||
|
||||
def test_save_fails_for_invalid_belongs_to
|
||||
assert log = AuditLog.create(:developer_id=>0,:message=>"")
|
||||
|
||||
log.developer = Developer.new
|
||||
assert !log.developer.valid?
|
||||
assert !log.valid?
|
||||
assert !log.save
|
||||
assert_equal "is invalid", log.errors.on("developer")
|
||||
end
|
||||
|
||||
def test_save_succeeds_for_invalid_belongs_to_with_validate_false
|
||||
assert log = AuditLog.create(:developer_id=>0,:message=>"")
|
||||
|
||||
log.unvalidated_developer = Developer.new
|
||||
assert !log.unvalidated_developer.valid?
|
||||
assert log.valid?
|
||||
assert log.save
|
||||
end
|
||||
|
||||
def test_belongs_to_proxy_should_not_respond_to_private_methods
|
||||
assert_raises(NoMethodError) { companies(:first_firm).private_method }
|
||||
assert_raises(NoMethodError) { companies(:second_client).firm.private_method }
|
||||
end
|
||||
|
||||
def test_belongs_to_proxy_should_respond_to_private_methods_via_send
|
||||
companies(:first_firm).send(:private_method)
|
||||
companies(:second_client).firm.send(:private_method)
|
||||
end
|
||||
end
|
||||
161
vendor/rails/activerecord/test/cases/associations/callbacks_test.rb
vendored
Normal file
161
vendor/rails/activerecord/test/cases/associations/callbacks_test.rb
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/comment'
|
||||
require 'models/author'
|
||||
require 'models/category'
|
||||
require 'models/project'
|
||||
require 'models/developer'
|
||||
|
||||
class AssociationCallbacksTest < ActiveRecord::TestCase
|
||||
fixtures :posts, :authors, :projects, :developers
|
||||
|
||||
def setup
|
||||
@david = authors(:david)
|
||||
@thinking = posts(:thinking)
|
||||
@authorless = posts(:authorless)
|
||||
assert @david.post_log.empty?
|
||||
end
|
||||
|
||||
def test_adding_macro_callbacks
|
||||
@david.posts_with_callbacks << @thinking
|
||||
assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}"], @david.post_log
|
||||
@david.posts_with_callbacks << @thinking
|
||||
assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}", "before_adding#{@thinking.id}",
|
||||
"after_adding#{@thinking.id}"], @david.post_log
|
||||
end
|
||||
|
||||
def test_adding_with_proc_callbacks
|
||||
@david.posts_with_proc_callbacks << @thinking
|
||||
assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}"], @david.post_log
|
||||
@david.posts_with_proc_callbacks << @thinking
|
||||
assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}", "before_adding#{@thinking.id}",
|
||||
"after_adding#{@thinking.id}"], @david.post_log
|
||||
end
|
||||
|
||||
def test_removing_with_macro_callbacks
|
||||
first_post, second_post = @david.posts_with_callbacks[0, 2]
|
||||
@david.posts_with_callbacks.delete(first_post)
|
||||
assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}"], @david.post_log
|
||||
@david.posts_with_callbacks.delete(second_post)
|
||||
assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}", "before_removing#{second_post.id}",
|
||||
"after_removing#{second_post.id}"], @david.post_log
|
||||
end
|
||||
|
||||
def test_removing_with_proc_callbacks
|
||||
first_post, second_post = @david.posts_with_callbacks[0, 2]
|
||||
@david.posts_with_proc_callbacks.delete(first_post)
|
||||
assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}"], @david.post_log
|
||||
@david.posts_with_proc_callbacks.delete(second_post)
|
||||
assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}", "before_removing#{second_post.id}",
|
||||
"after_removing#{second_post.id}"], @david.post_log
|
||||
end
|
||||
|
||||
def test_multiple_callbacks
|
||||
@david.posts_with_multiple_callbacks << @thinking
|
||||
assert_equal ["before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}", "after_adding#{@thinking.id}",
|
||||
"after_adding_proc#{@thinking.id}"], @david.post_log
|
||||
@david.posts_with_multiple_callbacks << @thinking
|
||||
assert_equal ["before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}", "after_adding#{@thinking.id}",
|
||||
"after_adding_proc#{@thinking.id}", "before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}",
|
||||
"after_adding#{@thinking.id}", "after_adding_proc#{@thinking.id}"], @david.post_log
|
||||
end
|
||||
|
||||
def test_has_many_callbacks_with_create
|
||||
morten = Author.create :name => "Morten"
|
||||
post = morten.posts_with_proc_callbacks.create! :title => "Hello", :body => "How are you doing?"
|
||||
assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log
|
||||
end
|
||||
|
||||
def test_has_many_callbacks_with_create!
|
||||
morten = Author.create! :name => "Morten"
|
||||
post = morten.posts_with_proc_callbacks.create :title => "Hello", :body => "How are you doing?"
|
||||
assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log
|
||||
end
|
||||
|
||||
def test_has_many_callbacks_for_save_on_parent
|
||||
jack = Author.new :name => "Jack"
|
||||
post = jack.posts_with_callbacks.build :title => "Call me back!", :body => "Before you wake up and after you sleep"
|
||||
|
||||
callback_log = ["before_adding<new>", "after_adding#{jack.posts_with_callbacks.first.id}"]
|
||||
assert_equal callback_log, jack.post_log
|
||||
assert jack.save
|
||||
assert_equal 1, jack.posts_with_callbacks.count
|
||||
assert_equal callback_log, jack.post_log
|
||||
end
|
||||
|
||||
def test_has_and_belongs_to_many_add_callback
|
||||
david = developers(:david)
|
||||
ar = projects(:active_record)
|
||||
assert ar.developers_log.empty?
|
||||
ar.developers_with_callbacks << david
|
||||
assert_equal ["before_adding#{david.id}", "after_adding#{david.id}"], ar.developers_log
|
||||
ar.developers_with_callbacks << david
|
||||
assert_equal ["before_adding#{david.id}", "after_adding#{david.id}", "before_adding#{david.id}",
|
||||
"after_adding#{david.id}"], ar.developers_log
|
||||
end
|
||||
|
||||
def test_has_and_belongs_to_many_after_add_called_after_save
|
||||
ar = projects(:active_record)
|
||||
assert ar.developers_log.empty?
|
||||
alice = Developer.new(:name => 'alice')
|
||||
ar.developers_with_callbacks << alice
|
||||
assert_equal"after_adding#{alice.id}", ar.developers_log.last
|
||||
|
||||
bob = ar.developers_with_callbacks.create(:name => 'bob')
|
||||
assert_equal "after_adding#{bob.id}", ar.developers_log.last
|
||||
|
||||
ar.developers_with_callbacks.build(:name => 'charlie')
|
||||
assert_equal "after_adding<new>", ar.developers_log.last
|
||||
end
|
||||
|
||||
|
||||
def test_has_and_belongs_to_many_remove_callback
|
||||
david = developers(:david)
|
||||
jamis = developers(:jamis)
|
||||
activerecord = projects(:active_record)
|
||||
assert activerecord.developers_log.empty?
|
||||
activerecord.developers_with_callbacks.delete(david)
|
||||
assert_equal ["before_removing#{david.id}", "after_removing#{david.id}"], activerecord.developers_log
|
||||
|
||||
activerecord.developers_with_callbacks.delete(jamis)
|
||||
assert_equal ["before_removing#{david.id}", "after_removing#{david.id}", "before_removing#{jamis.id}",
|
||||
"after_removing#{jamis.id}"], activerecord.developers_log
|
||||
end
|
||||
|
||||
def test_has_and_belongs_to_many_remove_callback_on_clear
|
||||
activerecord = projects(:active_record)
|
||||
assert activerecord.developers_log.empty?
|
||||
if activerecord.developers_with_callbacks.size == 0
|
||||
activerecord.developers << developers(:david)
|
||||
activerecord.developers << developers(:jamis)
|
||||
activerecord.reload
|
||||
assert activerecord.developers_with_callbacks.size == 2
|
||||
end
|
||||
log_array = activerecord.developers_with_callbacks.collect {|d| ["before_removing#{d.id}","after_removing#{d.id}"]}.flatten.sort
|
||||
assert activerecord.developers_with_callbacks.clear
|
||||
assert_equal log_array, activerecord.developers_log.sort
|
||||
end
|
||||
|
||||
def test_has_many_and_belongs_to_many_callbacks_for_save_on_parent
|
||||
project = Project.new :name => "Callbacks"
|
||||
project.developers_with_callbacks.build :name => "Jack", :salary => 95000
|
||||
|
||||
callback_log = ["before_adding<new>", "after_adding<new>"]
|
||||
assert_equal callback_log, project.developers_log
|
||||
assert project.save
|
||||
assert_equal 1, project.developers_with_callbacks.size
|
||||
assert_equal callback_log, project.developers_log
|
||||
end
|
||||
|
||||
def test_dont_add_if_before_callback_raises_exception
|
||||
assert !@david.unchangable_posts.include?(@authorless)
|
||||
begin
|
||||
@david.unchangable_posts << @authorless
|
||||
rescue Exception => e
|
||||
end
|
||||
assert @david.post_log.empty?
|
||||
assert !@david.unchangable_posts.include?(@authorless)
|
||||
@david.reload
|
||||
assert !@david.unchangable_posts.include?(@authorless)
|
||||
end
|
||||
end
|
||||
123
vendor/rails/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
vendored
Normal file
123
vendor/rails/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/comment'
|
||||
require 'models/author'
|
||||
require 'models/category'
|
||||
require 'models/categorization'
|
||||
require 'models/company'
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
|
||||
class CascadedEagerLoadingTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :mixins, :companies, :posts, :topics, :accounts, :comments, :categorizations
|
||||
|
||||
def test_eager_association_loading_with_cascaded_two_levels
|
||||
authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id")
|
||||
assert_equal 2, authors.size
|
||||
assert_equal 5, authors[0].posts.size
|
||||
assert_equal 1, authors[1].posts.size
|
||||
assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_cascaded_two_levels_and_one_level
|
||||
authors = Author.find(:all, :include=>[{:posts=>:comments}, :categorizations], :order=>"authors.id")
|
||||
assert_equal 2, authors.size
|
||||
assert_equal 5, authors[0].posts.size
|
||||
assert_equal 1, authors[1].posts.size
|
||||
assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
|
||||
assert_equal 1, authors[0].categorizations.size
|
||||
assert_equal 2, authors[1].categorizations.size
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations
|
||||
authors = Author.find(:all, :include=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id")
|
||||
assert_equal 2, authors.size
|
||||
assert_equal 5, authors[0].posts.size
|
||||
assert_equal 1, authors[1].posts.size
|
||||
assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference
|
||||
authors = Author.find(:all, :include=>{:posts=>[:comments, :author]}, :order=>"authors.id")
|
||||
assert_equal 2, authors.size
|
||||
assert_equal 5, authors[0].posts.size
|
||||
assert_equal authors(:david).name, authors[0].name
|
||||
assert_equal [authors(:david).name], authors[0].posts.collect{|post| post.author.name}.uniq
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_cascaded_two_levels_with_condition
|
||||
authors = Author.find(:all, :include=>{:posts=>:comments}, :conditions=>"authors.id=1", :order=>"authors.id")
|
||||
assert_equal 1, authors.size
|
||||
assert_equal 5, authors[0].posts.size
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong
|
||||
firms = Firm.find(:all, :include=>{:account=>{:firm=>:account}}, :order=>"companies.id")
|
||||
assert_equal 2, firms.size
|
||||
assert_equal firms.first.account, firms.first.account.firm.account
|
||||
assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account }
|
||||
assert_equal companies(:first_firm).account.firm.account, assert_no_queries { firms.first.account.firm.account }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_has_many_sti
|
||||
topics = Topic.find(:all, :include => :replies, :order => 'topics.id')
|
||||
first, second, = topics(:first).replies.size, topics(:second).replies.size
|
||||
assert_no_queries do
|
||||
assert_equal first, topics[0].replies.size
|
||||
assert_equal second, topics[1].replies.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_has_many_sti_and_subclasses
|
||||
silly = SillyReply.new(:title => "gaga", :content => "boo-boo", :parent_id => 1)
|
||||
silly.parent_id = 1
|
||||
assert silly.save
|
||||
|
||||
topics = Topic.find(:all, :include => :replies, :order => 'topics.id, replies_topics.id')
|
||||
assert_no_queries do
|
||||
assert_equal 2, topics[0].replies.size
|
||||
assert_equal 0, topics[1].replies.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_sti
|
||||
replies = Reply.find(:all, :include => :topic, :order => 'topics.id')
|
||||
assert replies.include?(topics(:second))
|
||||
assert !replies.include?(topics(:first))
|
||||
assert_equal topics(:first), assert_no_queries { replies.first.topic }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_multiple_stis_and_order
|
||||
author = Author.find(:first, :include => { :posts => [ :special_comments , :very_special_comment ] }, :order => 'authors.name, comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4')
|
||||
assert_equal authors(:david), author
|
||||
assert_no_queries do
|
||||
author.posts.first.special_comments
|
||||
author.posts.first.very_special_comment
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_association_loading_of_stis_with_multiple_references
|
||||
authors = Author.find(:all, :include => { :posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } } }, :order => 'comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4')
|
||||
assert_equal [authors(:david)], authors
|
||||
assert_no_queries do
|
||||
authors.first.posts.first.special_comments.first.post.special_comments
|
||||
authors.first.posts.first.special_comments.first.post.very_special_comment
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'models/vertex'
|
||||
require 'models/edge'
|
||||
class CascadedEagerLoadingTest < ActiveRecord::TestCase
|
||||
fixtures :edges, :vertices
|
||||
|
||||
def test_eager_association_loading_with_recursive_cascading_four_levels_has_many_through
|
||||
source = Vertex.find(:first, :include=>{:sinks=>{:sinks=>{:sinks=>:sinks}}}, :order => 'vertices.id')
|
||||
assert_equal vertices(:vertex_4), assert_no_queries { source.sinks.first.sinks.first.sinks.first }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_recursive_cascading_four_levels_has_and_belongs_to_many
|
||||
sink = Vertex.find(:first, :include=>{:sources=>{:sources=>{:sources=>:sources}}}, :order => 'vertices.id DESC')
|
||||
assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first }
|
||||
end
|
||||
end
|
||||
36
vendor/rails/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
vendored
Normal file
36
vendor/rails/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
require 'cases/helper'
|
||||
require 'models/post'
|
||||
require 'models/tagging'
|
||||
|
||||
module Namespaced
|
||||
class Post < ActiveRecord::Base
|
||||
set_table_name 'posts'
|
||||
has_one :tagging, :as => :taggable, :class_name => 'Tagging'
|
||||
end
|
||||
end
|
||||
|
||||
class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase
|
||||
|
||||
def setup
|
||||
generate_test_objects
|
||||
end
|
||||
|
||||
def generate_test_objects
|
||||
post = Namespaced::Post.create( :title => 'Great stuff', :body => 'This is not', :author_id => 1 )
|
||||
tagging = Tagging.create( :taggable => post )
|
||||
end
|
||||
|
||||
def test_class_names
|
||||
old = ActiveRecord::Base.store_full_sti_class
|
||||
|
||||
ActiveRecord::Base.store_full_sti_class = false
|
||||
post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging )
|
||||
assert_nil post.tagging
|
||||
|
||||
ActiveRecord::Base.store_full_sti_class = true
|
||||
post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging )
|
||||
assert_equal 'Tagging', post.tagging.class.name
|
||||
ensure
|
||||
ActiveRecord::Base.store_full_sti_class = old
|
||||
end
|
||||
end
|
||||
101
vendor/rails/activerecord/test/cases/associations/eager_load_nested_include_test.rb
vendored
Normal file
101
vendor/rails/activerecord/test/cases/associations/eager_load_nested_include_test.rb
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
require 'cases/helper'
|
||||
|
||||
module Remembered
|
||||
def self.included(base)
|
||||
base.extend ClassMethods
|
||||
base.class_eval do
|
||||
after_create :remember
|
||||
protected
|
||||
def remember; self.class.remembered << self; end
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def remembered; @@remembered ||= []; end
|
||||
def rand; @@remembered.rand; end
|
||||
end
|
||||
end
|
||||
|
||||
class ShapeExpression < ActiveRecord::Base
|
||||
belongs_to :shape, :polymorphic => true
|
||||
belongs_to :paint, :polymorphic => true
|
||||
end
|
||||
|
||||
class Circle < ActiveRecord::Base
|
||||
has_many :shape_expressions, :as => :shape
|
||||
include Remembered
|
||||
end
|
||||
class Square < ActiveRecord::Base
|
||||
has_many :shape_expressions, :as => :shape
|
||||
include Remembered
|
||||
end
|
||||
class Triangle < ActiveRecord::Base
|
||||
has_many :shape_expressions, :as => :shape
|
||||
include Remembered
|
||||
end
|
||||
class PaintColor < ActiveRecord::Base
|
||||
has_many :shape_expressions, :as => :paint
|
||||
belongs_to :non_poly, :foreign_key => "non_poly_one_id", :class_name => "NonPolyOne"
|
||||
include Remembered
|
||||
end
|
||||
class PaintTexture < ActiveRecord::Base
|
||||
has_many :shape_expressions, :as => :paint
|
||||
belongs_to :non_poly, :foreign_key => "non_poly_two_id", :class_name => "NonPolyTwo"
|
||||
include Remembered
|
||||
end
|
||||
class NonPolyOne < ActiveRecord::Base
|
||||
has_many :paint_colors
|
||||
include Remembered
|
||||
end
|
||||
class NonPolyTwo < ActiveRecord::Base
|
||||
has_many :paint_textures
|
||||
include Remembered
|
||||
end
|
||||
|
||||
|
||||
|
||||
class EagerLoadPolyAssocsTest < ActiveRecord::TestCase
|
||||
NUM_SIMPLE_OBJS = 50
|
||||
NUM_SHAPE_EXPRESSIONS = 100
|
||||
|
||||
def setup
|
||||
generate_test_object_graphs
|
||||
end
|
||||
|
||||
def teardown
|
||||
[Circle, Square, Triangle, PaintColor, PaintTexture,
|
||||
ShapeExpression, NonPolyOne, NonPolyTwo].each do |c|
|
||||
c.delete_all
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
def generate_test_object_graphs
|
||||
1.upto(NUM_SIMPLE_OBJS) do
|
||||
[Circle, Square, Triangle, NonPolyOne, NonPolyTwo].map(&:create!)
|
||||
end
|
||||
1.upto(NUM_SIMPLE_OBJS) do
|
||||
PaintColor.create!(:non_poly_one_id => NonPolyOne.rand.id)
|
||||
PaintTexture.create!(:non_poly_two_id => NonPolyTwo.rand.id)
|
||||
end
|
||||
1.upto(NUM_SHAPE_EXPRESSIONS) do
|
||||
shape_type = [Circle, Square, Triangle].rand
|
||||
paint_type = [PaintColor, PaintTexture].rand
|
||||
ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.rand.id,
|
||||
:paint_type => paint_type.to_s, :paint_id => paint_type.rand.id)
|
||||
end
|
||||
end
|
||||
|
||||
def test_include_query
|
||||
res = 0
|
||||
res = ShapeExpression.find :all, :include => [ :shape, { :paint => :non_poly } ]
|
||||
assert_equal NUM_SHAPE_EXPRESSIONS, res.size
|
||||
assert_queries(0) do
|
||||
res.each do |se|
|
||||
assert_not_nil se.paint.non_poly, "this is the association that was loading incorrectly before the change"
|
||||
assert_not_nil se.shape, "just making sure other associations still work"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
145
vendor/rails/activerecord/test/cases/associations/eager_singularization_test.rb
vendored
Normal file
145
vendor/rails/activerecord/test/cases/associations/eager_singularization_test.rb
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
require "cases/helper"
|
||||
|
||||
class Virus < ActiveRecord::Base
|
||||
belongs_to :octopus
|
||||
end
|
||||
class Octopus < ActiveRecord::Base
|
||||
has_one :virus
|
||||
end
|
||||
class Pass < ActiveRecord::Base
|
||||
belongs_to :bus
|
||||
end
|
||||
class Bus < ActiveRecord::Base
|
||||
has_many :passes
|
||||
end
|
||||
class Mess < ActiveRecord::Base
|
||||
has_and_belongs_to_many :crises
|
||||
end
|
||||
class Crisis < ActiveRecord::Base
|
||||
has_and_belongs_to_many :messes
|
||||
has_many :analyses, :dependent => :destroy
|
||||
has_many :successes, :through => :analyses
|
||||
has_many :dresses, :dependent => :destroy
|
||||
has_many :compresses, :through => :dresses
|
||||
end
|
||||
class Analysis < ActiveRecord::Base
|
||||
belongs_to :crisis
|
||||
belongs_to :success
|
||||
end
|
||||
class Success < ActiveRecord::Base
|
||||
has_many :analyses, :dependent => :destroy
|
||||
has_many :crises, :through => :analyses
|
||||
end
|
||||
class Dress < ActiveRecord::Base
|
||||
belongs_to :crisis
|
||||
has_many :compresses
|
||||
end
|
||||
class Compress < ActiveRecord::Base
|
||||
belongs_to :dress
|
||||
end
|
||||
|
||||
|
||||
class EagerSingularizationTest < ActiveRecord::TestCase
|
||||
|
||||
def setup
|
||||
if ActiveRecord::Base.connection.supports_migrations?
|
||||
ActiveRecord::Base.connection.create_table :viri do |t|
|
||||
t.column :octopus_id, :integer
|
||||
t.column :species, :string
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :octopi do |t|
|
||||
t.column :species, :string
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :passes do |t|
|
||||
t.column :bus_id, :integer
|
||||
t.column :rides, :integer
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :buses do |t|
|
||||
t.column :name, :string
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :crises_messes, :id => false do |t|
|
||||
t.column :crisis_id, :integer
|
||||
t.column :mess_id, :integer
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :messes do |t|
|
||||
t.column :name, :string
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :crises do |t|
|
||||
t.column :name, :string
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :successes do |t|
|
||||
t.column :name, :string
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :analyses do |t|
|
||||
t.column :crisis_id, :integer
|
||||
t.column :success_id, :integer
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :dresses do |t|
|
||||
t.column :crisis_id, :integer
|
||||
end
|
||||
ActiveRecord::Base.connection.create_table :compresses do |t|
|
||||
t.column :dress_id, :integer
|
||||
end
|
||||
@have_tables = true
|
||||
else
|
||||
@have_tables = false
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActiveRecord::Base.connection.drop_table :viri
|
||||
ActiveRecord::Base.connection.drop_table :octopi
|
||||
ActiveRecord::Base.connection.drop_table :passes
|
||||
ActiveRecord::Base.connection.drop_table :buses
|
||||
ActiveRecord::Base.connection.drop_table :crises_messes
|
||||
ActiveRecord::Base.connection.drop_table :messes
|
||||
ActiveRecord::Base.connection.drop_table :crises
|
||||
ActiveRecord::Base.connection.drop_table :successes
|
||||
ActiveRecord::Base.connection.drop_table :analyses
|
||||
ActiveRecord::Base.connection.drop_table :dresses
|
||||
ActiveRecord::Base.connection.drop_table :compresses
|
||||
end
|
||||
|
||||
def test_eager_no_extra_singularization_belongs_to
|
||||
return unless @have_tables
|
||||
assert_nothing_raised do
|
||||
Virus.find(:all, :include => :octopus)
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_no_extra_singularization_has_one
|
||||
return unless @have_tables
|
||||
assert_nothing_raised do
|
||||
Octopus.find(:all, :include => :virus)
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_no_extra_singularization_has_many
|
||||
return unless @have_tables
|
||||
assert_nothing_raised do
|
||||
Bus.find(:all, :include => :passes)
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_no_extra_singularization_has_and_belongs_to_many
|
||||
return unless @have_tables
|
||||
assert_nothing_raised do
|
||||
Crisis.find(:all, :include => :messes)
|
||||
Mess.find(:all, :include => :crises)
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_no_extra_singularization_has_many_through_belongs_to
|
||||
return unless @have_tables
|
||||
assert_nothing_raised do
|
||||
Crisis.find(:all, :include => :successes)
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_no_extra_singularization_has_many_through_has_many
|
||||
return unless @have_tables
|
||||
assert_nothing_raised do
|
||||
Crisis.find(:all, :include => :compresses)
|
||||
end
|
||||
end
|
||||
end
|
||||
692
vendor/rails/activerecord/test/cases/associations/eager_test.rb
vendored
Normal file
692
vendor/rails/activerecord/test/cases/associations/eager_test.rb
vendored
Normal file
|
|
@ -0,0 +1,692 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/tagging'
|
||||
require 'models/comment'
|
||||
require 'models/author'
|
||||
require 'models/category'
|
||||
require 'models/company'
|
||||
require 'models/person'
|
||||
require 'models/reader'
|
||||
require 'models/owner'
|
||||
require 'models/pet'
|
||||
require 'models/reference'
|
||||
require 'models/job'
|
||||
require 'models/subscriber'
|
||||
require 'models/subscription'
|
||||
require 'models/book'
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
|
||||
class EagerAssociationTest < ActiveRecord::TestCase
|
||||
fixtures :posts, :comments, :authors, :author_addresses, :categories, :categories_posts,
|
||||
:companies, :accounts, :tags, :taggings, :people, :readers,
|
||||
:owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books,
|
||||
:developers, :projects, :developers_projects
|
||||
|
||||
def test_loading_with_one_association
|
||||
posts = Post.find(:all, :include => :comments)
|
||||
post = posts.find { |p| p.id == 1 }
|
||||
assert_equal 2, post.comments.size
|
||||
assert post.comments.include?(comments(:greetings))
|
||||
|
||||
post = Post.find(:first, :include => :comments, :conditions => "posts.title = 'Welcome to the weblog'")
|
||||
assert_equal 2, post.comments.size
|
||||
assert post.comments.include?(comments(:greetings))
|
||||
|
||||
posts = Post.find(:all, :include => :last_comment)
|
||||
post = posts.find { |p| p.id == 1 }
|
||||
assert_equal Post.find(1).last_comment, post.last_comment
|
||||
end
|
||||
|
||||
def test_loading_with_one_association_with_non_preload
|
||||
posts = Post.find(:all, :include => :last_comment, :order => 'comments.id DESC')
|
||||
post = posts.find { |p| p.id == 1 }
|
||||
assert_equal Post.find(1).last_comment, post.last_comment
|
||||
end
|
||||
|
||||
def test_loading_conditions_with_or
|
||||
posts = authors(:david).posts.find(:all, :include => :comments, :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE} = 'SpecialComment'")
|
||||
assert_nil posts.detect { |p| p.author_id != authors(:david).id },
|
||||
"expected to find only david's posts"
|
||||
end
|
||||
|
||||
def test_with_ordering
|
||||
list = Post.find(:all, :include => :comments, :order => "posts.id DESC")
|
||||
[:eager_other, :sti_habtm, :sti_post_and_comments, :sti_comments,
|
||||
:authorless, :thinking, :welcome
|
||||
].each_with_index do |post, index|
|
||||
assert_equal posts(post), list[index]
|
||||
end
|
||||
end
|
||||
|
||||
def test_with_two_tables_in_from_without_getting_double_quoted
|
||||
posts = Post.find(:all,
|
||||
:select => "posts.*",
|
||||
:from => "authors, posts",
|
||||
:include => :comments,
|
||||
:conditions => "posts.author_id = authors.id",
|
||||
:order => "posts.id"
|
||||
)
|
||||
|
||||
assert_equal 2, posts.first.comments.size
|
||||
end
|
||||
|
||||
def test_loading_with_multiple_associations
|
||||
posts = Post.find(:all, :include => [ :comments, :author, :categories ], :order => "posts.id")
|
||||
assert_equal 2, posts.first.comments.size
|
||||
assert_equal 2, posts.first.categories.size
|
||||
assert posts.first.comments.include?(comments(:greetings))
|
||||
end
|
||||
|
||||
def test_duplicate_middle_objects
|
||||
comments = Comment.find :all, :conditions => 'post_id = 1', :include => [:post => :author]
|
||||
assert_no_queries do
|
||||
comments.each {|comment| comment.post.author.name}
|
||||
end
|
||||
end
|
||||
|
||||
def test_including_duplicate_objects_from_belongs_to
|
||||
popular_post = Post.create!(:title => 'foo', :body => "I like cars!")
|
||||
comment = popular_post.comments.create!(:body => "lol")
|
||||
popular_post.readers.create!(:person => people(:michael))
|
||||
popular_post.readers.create!(:person => people(:david))
|
||||
|
||||
readers = Reader.find(:all, :conditions => ["post_id = ?", popular_post.id],
|
||||
:include => {:post => :comments})
|
||||
readers.each do |reader|
|
||||
assert_equal [comment], reader.post.comments
|
||||
end
|
||||
end
|
||||
|
||||
def test_including_duplicate_objects_from_has_many
|
||||
car_post = Post.create!(:title => 'foo', :body => "I like cars!")
|
||||
car_post.categories << categories(:general)
|
||||
car_post.categories << categories(:technology)
|
||||
|
||||
comment = car_post.comments.create!(:body => "hmm")
|
||||
categories = Category.find(:all, :conditions => ["posts.id=?", car_post.id],
|
||||
:include => {:posts => :comments})
|
||||
categories.each do |category|
|
||||
assert_equal [comment], category.posts[0].comments
|
||||
end
|
||||
end
|
||||
|
||||
def test_finding_with_includes_on_has_many_association_with_same_include_includes_only_once
|
||||
author_id = authors(:david).id
|
||||
author = assert_queries(3) { Author.find(author_id, :include => {:posts_with_comments => :comments}) } # find the author, then find the posts, then find the comments
|
||||
author.posts_with_comments.each do |post_with_comments|
|
||||
assert_equal post_with_comments.comments.length, post_with_comments.comments.count
|
||||
assert_equal nil, post_with_comments.comments.uniq!
|
||||
end
|
||||
end
|
||||
|
||||
def test_finding_with_includes_on_has_one_assocation_with_same_include_includes_only_once
|
||||
author = authors(:david)
|
||||
post = author.post_about_thinking_with_last_comment
|
||||
last_comment = post.last_comment
|
||||
author = assert_queries(3) { Author.find(author.id, :include => {:post_about_thinking_with_last_comment => :last_comment})} # find the author, then find the posts, then find the comments
|
||||
assert_no_queries do
|
||||
assert_equal post, author.post_about_thinking_with_last_comment
|
||||
assert_equal last_comment, author.post_about_thinking_with_last_comment.last_comment
|
||||
end
|
||||
end
|
||||
|
||||
def test_finding_with_includes_on_belongs_to_association_with_same_include_includes_only_once
|
||||
post = posts(:welcome)
|
||||
author = post.author
|
||||
author_address = author.author_address
|
||||
post = assert_queries(3) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author, then find the address
|
||||
assert_no_queries do
|
||||
assert_equal author, post.author_with_address
|
||||
assert_equal author_address, post.author_with_address.author_address
|
||||
end
|
||||
end
|
||||
|
||||
def test_finding_with_includes_on_null_belongs_to_association_with_same_include_includes_only_once
|
||||
post = posts(:welcome)
|
||||
post.update_attributes!(:author => nil)
|
||||
post = assert_queries(2) { Post.find(post.id, :include => {:author_with_address => :author_address}) } # find the post, then find the author which is null so no query for the address
|
||||
assert_no_queries do
|
||||
assert_equal nil, post.author_with_address
|
||||
end
|
||||
end
|
||||
|
||||
def test_loading_from_an_association
|
||||
posts = authors(:david).posts.find(:all, :include => :comments, :order => "posts.id")
|
||||
assert_equal 2, posts.first.comments.size
|
||||
end
|
||||
|
||||
def test_loading_from_an_association_that_has_a_hash_of_conditions
|
||||
assert_nothing_raised do
|
||||
Author.find(:all, :include => :hello_posts_with_hash_conditions)
|
||||
end
|
||||
assert !Author.find(authors(:david).id, :include => :hello_posts_with_hash_conditions).hello_posts.empty?
|
||||
end
|
||||
|
||||
def test_loading_with_no_associations
|
||||
assert_nil Post.find(posts(:authorless).id, :include => :author).author
|
||||
end
|
||||
|
||||
def test_nested_loading_with_no_associations
|
||||
assert_nothing_raised do
|
||||
Post.find(posts(:authorless).id, :include => {:author => :author_addresss})
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_foreign_keys
|
||||
pets = Pet.find(:all, :include => :owner)
|
||||
assert_equal 3, pets.length
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to
|
||||
comments = Comment.find(:all, :include => :post)
|
||||
assert_equal 10, comments.length
|
||||
titles = comments.map { |c| c.post.title }
|
||||
assert titles.include?(posts(:welcome).title)
|
||||
assert titles.include?(posts(:sti_post_and_comments).title)
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_limit
|
||||
comments = Comment.find(:all, :include => :post, :limit => 5, :order => 'comments.id')
|
||||
assert_equal 5, comments.length
|
||||
assert_equal [1,2,3,5,6], comments.collect { |c| c.id }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_limit_and_conditions
|
||||
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :order => 'comments.id')
|
||||
assert_equal 3, comments.length
|
||||
assert_equal [5,6,7], comments.collect { |c| c.id }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_limit_and_offset
|
||||
comments = Comment.find(:all, :include => :post, :limit => 3, :offset => 2, :order => 'comments.id')
|
||||
assert_equal 3, comments.length
|
||||
assert_equal [3,5,6], comments.collect { |c| c.id }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions
|
||||
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :offset => 1, :order => 'comments.id')
|
||||
assert_equal 3, comments.length
|
||||
assert_equal [6,7,8], comments.collect { |c| c.id }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions_array
|
||||
comments = Comment.find(:all, :include => :post, :conditions => ['post_id = ?',4], :limit => 3, :offset => 1, :order => 'comments.id')
|
||||
assert_equal 3, comments.length
|
||||
assert_equal [6,7,8], comments.collect { |c| c.id }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_conditions_string_with_unquoted_table_name
|
||||
assert_nothing_raised do
|
||||
Comment.find(:all, :include => :post, :conditions => ['posts.id = ?',4])
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_conditions_string_with_quoted_table_name
|
||||
quoted_posts_id= Comment.connection.quote_table_name('posts') + '.' + Comment.connection.quote_column_name('id')
|
||||
assert_nothing_raised do
|
||||
Comment.find(:all, :include => :post, :conditions => ["#{quoted_posts_id} = ?",4])
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_order_string_with_unquoted_table_name
|
||||
assert_nothing_raised do
|
||||
Comment.find(:all, :include => :post, :order => 'posts.id')
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_order_string_with_quoted_table_name
|
||||
quoted_posts_id= Comment.connection.quote_table_name('posts') + '.' + Comment.connection.quote_column_name('id')
|
||||
assert_nothing_raised do
|
||||
Comment.find(:all, :include => :post, :order => quoted_posts_id)
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_limit_and_multiple_associations
|
||||
posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :order => 'posts.id')
|
||||
assert_equal 1, posts.length
|
||||
assert_equal [1], posts.collect { |p| p.id }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_multiple_associations
|
||||
posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :offset => 1, :order => 'posts.id')
|
||||
assert_equal 1, posts.length
|
||||
assert_equal [2], posts.collect { |p| p.id }
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_belongs_to_inferred_foreign_key_from_association_name
|
||||
author_favorite = AuthorFavorite.find(:first, :include => :favorite_author)
|
||||
assert_equal authors(:mary), assert_no_queries { author_favorite.favorite_author }
|
||||
end
|
||||
|
||||
def test_eager_load_belongs_to_quotes_table_and_column_names
|
||||
job = Job.find jobs(:unicyclist).id, :include => :ideal_reference
|
||||
references(:michael_unicyclist)
|
||||
assert_no_queries{ assert_equal references(:michael_unicyclist), job.ideal_reference}
|
||||
end
|
||||
|
||||
def test_eager_load_has_one_quotes_table_and_column_names
|
||||
michael = Person.find(people(:michael), :include => :favourite_reference)
|
||||
references(:michael_unicyclist)
|
||||
assert_no_queries{ assert_equal references(:michael_unicyclist), michael.favourite_reference}
|
||||
end
|
||||
|
||||
def test_eager_load_has_many_quotes_table_and_column_names
|
||||
michael = Person.find(people(:michael), :include => :references)
|
||||
references(:michael_magician,:michael_unicyclist)
|
||||
assert_no_queries{ assert_equal references(:michael_magician,:michael_unicyclist), michael.references.sort_by(&:id) }
|
||||
end
|
||||
|
||||
def test_eager_load_has_many_through_quotes_table_and_column_names
|
||||
michael = Person.find(people(:michael), :include => :jobs)
|
||||
jobs(:magician, :unicyclist)
|
||||
assert_no_queries{ assert_equal jobs(:unicyclist, :magician), michael.jobs.sort_by(&:id) }
|
||||
end
|
||||
|
||||
def test_eager_load_has_many_with_string_keys
|
||||
subscriptions = subscriptions(:webster_awdr, :webster_rfr)
|
||||
subscriber =Subscriber.find(subscribers(:second).id, :include => :subscriptions)
|
||||
assert_equal subscriptions, subscriber.subscriptions.sort_by(&:id)
|
||||
end
|
||||
|
||||
def test_eager_load_has_many_through_with_string_keys
|
||||
books = books(:awdr, :rfr)
|
||||
subscriber = Subscriber.find(subscribers(:second).id, :include => :books)
|
||||
assert_equal books, subscriber.books.sort_by(&:id)
|
||||
end
|
||||
|
||||
def test_eager_load_belongs_to_with_string_keys
|
||||
subscriber = subscribers(:second)
|
||||
subscription = Subscription.find(subscriptions(:webster_awdr).id, :include => :subscriber)
|
||||
assert_equal subscriber, subscription.subscriber
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_explicit_join
|
||||
posts = Post.find(:all, :include => :comments, :joins => "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", :limit => 1, :order => 'author_id')
|
||||
assert_equal 1, posts.length
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_through
|
||||
posts_with_comments = people(:michael).posts.find(:all, :include => :comments, :order => 'posts.id')
|
||||
posts_with_author = people(:michael).posts.find(:all, :include => :author, :order => 'posts.id')
|
||||
posts_with_comments_and_author = people(:michael).posts.find(:all, :include => [ :comments, :author ], :order => 'posts.id')
|
||||
assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum += post.comments.size }
|
||||
assert_equal authors(:david), assert_no_queries { posts_with_author.first.author }
|
||||
assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author }
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_through_a_belongs_to_association
|
||||
author = authors(:mary)
|
||||
post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
|
||||
author.author_favorites.create(:favorite_author_id => 1)
|
||||
author.author_favorites.create(:favorite_author_id => 2)
|
||||
posts_with_author_favorites = author.posts.find(:all, :include => :author_favorites)
|
||||
assert_no_queries { posts_with_author_favorites.first.author_favorites.first.author_id }
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_through_an_sti_join_model
|
||||
author = Author.find(:first, :include => :special_post_comments, :order => 'authors.id')
|
||||
assert_equal [comments(:does_it_hurt)], assert_no_queries { author.special_post_comments }
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_through_an_sti_join_model_with_conditions_on_both
|
||||
author = Author.find(:first, :include => :special_nonexistant_post_comments, :order => 'authors.id')
|
||||
assert_equal [], author.special_nonexistant_post_comments
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_through_join_model_with_conditions
|
||||
assert_equal Author.find(:first, :include => :hello_post_comments,
|
||||
:order => 'authors.id').hello_post_comments.sort_by(&:id),
|
||||
Author.find(:first, :order => 'authors.id').hello_post_comments.sort_by(&:id)
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_through_join_model_with_conditions_on_top_level
|
||||
assert_equal comments(:more_greetings), Author.find(authors(:david).id, :include => :comments_with_order_and_conditions).comments_with_order_and_conditions.first
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_through_join_model_with_include
|
||||
author_comments = Author.find(authors(:david).id, :include => :comments_with_include).comments_with_include.to_a
|
||||
assert_no_queries do
|
||||
author_comments.first.post.title
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit
|
||||
posts = Post.find(:all, :order => 'posts.id asc', :include => [ :author, :comments ], :limit => 2)
|
||||
assert_equal 2, posts.size
|
||||
assert_equal 3, posts.inject(0) { |sum, post| sum += post.comments.size }
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit_and_conditions
|
||||
if current_adapter?(:OpenBaseAdapter)
|
||||
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "FETCHBLOB(posts.body) = 'hello'", :order => "posts.id")
|
||||
else
|
||||
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.body = 'hello'", :order => "posts.id")
|
||||
end
|
||||
assert_equal 2, posts.size
|
||||
assert_equal [4,5], posts.collect { |p| p.id }
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit_and_conditions_array
|
||||
if current_adapter?(:OpenBaseAdapter)
|
||||
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "FETCHBLOB(posts.body) = ?", 'hello' ], :order => "posts.id")
|
||||
else
|
||||
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "posts.body = ?", 'hello' ], :order => "posts.id")
|
||||
end
|
||||
assert_equal 2, posts.size
|
||||
assert_equal [4,5], posts.collect { |p| p.id }
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers
|
||||
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
|
||||
assert_equal 2, posts.size
|
||||
|
||||
count = Post.count(:include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
|
||||
assert_equal count, posts.size
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit_ond_high_offset
|
||||
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
|
||||
assert_equal 0, posts.size
|
||||
end
|
||||
|
||||
def test_count_eager_with_has_many_and_limit_ond_high_offset
|
||||
posts = Post.count(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
|
||||
assert_equal 0, posts
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit_with_no_results
|
||||
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.title = 'magic forest'")
|
||||
assert_equal 0, posts.size
|
||||
end
|
||||
|
||||
def test_eager_count_performed_on_a_has_many_association_with_multi_table_conditional
|
||||
author = authors(:david)
|
||||
author_posts_without_comments = author.posts.select { |post| post.comments.blank? }
|
||||
assert_equal author_posts_without_comments.size, author.posts.count(:all, :include => :comments, :conditions => 'comments.id is null')
|
||||
end
|
||||
|
||||
def test_eager_count_performed_on_a_has_many_through_association_with_multi_table_conditional
|
||||
person = people(:michael)
|
||||
person_posts_without_comments = person.posts.select { |post| post.comments.blank? }
|
||||
assert_equal person_posts_without_comments.size, person.posts_with_no_comments.count
|
||||
end
|
||||
|
||||
def test_eager_with_has_and_belongs_to_many_and_limit
|
||||
posts = Post.find(:all, :include => :categories, :order => "posts.id", :limit => 3)
|
||||
assert_equal 3, posts.size
|
||||
assert_equal 2, posts[0].categories.size
|
||||
assert_equal 1, posts[1].categories.size
|
||||
assert_equal 0, posts[2].categories.size
|
||||
assert posts[0].categories.include?(categories(:technology))
|
||||
assert posts[1].categories.include?(categories(:general))
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers
|
||||
posts = authors(:david).posts.find(:all,
|
||||
:include => :comments,
|
||||
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
|
||||
:limit => 2
|
||||
)
|
||||
assert_equal 2, posts.size
|
||||
|
||||
count = Post.count(
|
||||
:include => [ :comments, :author ],
|
||||
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
|
||||
:limit => 2
|
||||
)
|
||||
assert_equal count, posts.size
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit_and_scoped_conditions_on_the_eagers
|
||||
posts = nil
|
||||
Post.with_scope(:find => {
|
||||
:include => :comments,
|
||||
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'"
|
||||
}) do
|
||||
posts = authors(:david).posts.find(:all, :limit => 2)
|
||||
assert_equal 2, posts.size
|
||||
end
|
||||
|
||||
Post.with_scope(:find => {
|
||||
:include => [ :comments, :author ],
|
||||
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')"
|
||||
}) do
|
||||
count = Post.count(:limit => 2)
|
||||
assert_equal count, posts.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_with_has_many_and_limit_and_scoped_and_explicit_conditions_on_the_eagers
|
||||
Post.with_scope(:find => { :conditions => "1=1" }) do
|
||||
posts = authors(:david).posts.find(:all,
|
||||
:include => :comments,
|
||||
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
|
||||
:limit => 2
|
||||
)
|
||||
assert_equal 2, posts.size
|
||||
|
||||
count = Post.count(
|
||||
:include => [ :comments, :author ],
|
||||
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
|
||||
:limit => 2
|
||||
)
|
||||
assert_equal count, posts.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_with_scoped_order_using_association_limiting_without_explicit_scope
|
||||
posts_with_explicit_order = Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :order => 'posts.id DESC', :limit => 2)
|
||||
posts_with_scoped_order = Post.with_scope(:find => {:order => 'posts.id DESC'}) do
|
||||
Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :limit => 2)
|
||||
end
|
||||
assert_equal posts_with_explicit_order, posts_with_scoped_order
|
||||
end
|
||||
|
||||
def test_eager_association_loading_with_habtm
|
||||
posts = Post.find(:all, :include => :categories, :order => "posts.id")
|
||||
assert_equal 2, posts[0].categories.size
|
||||
assert_equal 1, posts[1].categories.size
|
||||
assert_equal 0, posts[2].categories.size
|
||||
assert posts[0].categories.include?(categories(:technology))
|
||||
assert posts[1].categories.include?(categories(:general))
|
||||
end
|
||||
|
||||
def test_eager_with_inheritance
|
||||
posts = SpecialPost.find(:all, :include => [ :comments ])
|
||||
end
|
||||
|
||||
def test_eager_has_one_with_association_inheritance
|
||||
post = Post.find(4, :include => [ :very_special_comment ])
|
||||
assert_equal "VerySpecialComment", post.very_special_comment.class.to_s
|
||||
end
|
||||
|
||||
def test_eager_has_many_with_association_inheritance
|
||||
post = Post.find(4, :include => [ :special_comments ])
|
||||
post.special_comments.each do |special_comment|
|
||||
assert_equal "SpecialComment", special_comment.class.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_habtm_with_association_inheritance
|
||||
post = Post.find(6, :include => [ :special_categories ])
|
||||
assert_equal 1, post.special_categories.size
|
||||
post.special_categories.each do |special_category|
|
||||
assert_equal "SpecialCategory", special_category.class.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_with_has_one_dependent_does_not_destroy_dependent
|
||||
assert_not_nil companies(:first_firm).account
|
||||
f = Firm.find(:first, :include => :account,
|
||||
:conditions => ["companies.name = ?", "37signals"])
|
||||
assert_not_nil f.account
|
||||
assert_equal companies(:first_firm, :reload).account, f.account
|
||||
end
|
||||
|
||||
def test_eager_with_multi_table_conditional_properly_counts_the_records_when_using_size
|
||||
author = authors(:david)
|
||||
posts_with_no_comments = author.posts.select { |post| post.comments.blank? }
|
||||
assert_equal posts_with_no_comments.size, author.posts_with_no_comments.size
|
||||
assert_equal posts_with_no_comments, author.posts_with_no_comments
|
||||
end
|
||||
|
||||
def test_eager_with_invalid_association_reference
|
||||
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
||||
post = Post.find(6, :include=> :monkeys )
|
||||
}
|
||||
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
||||
post = Post.find(6, :include=>[ :monkeys ])
|
||||
}
|
||||
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
||||
post = Post.find(6, :include=>[ 'monkeys' ])
|
||||
}
|
||||
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
|
||||
post = Post.find(6, :include=>[ :monkeys, :elephants ])
|
||||
}
|
||||
end
|
||||
|
||||
def find_all_ordered(className, include=nil)
|
||||
className.find(:all, :order=>"#{className.table_name}.#{className.primary_key}", :include=>include)
|
||||
end
|
||||
|
||||
def test_limited_eager_with_order
|
||||
assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title)', :limit => 2, :offset => 1)
|
||||
assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC', :limit => 2, :offset => 1)
|
||||
end
|
||||
|
||||
def test_limited_eager_with_multiple_order_columns
|
||||
assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title), posts.id', :limit => 2, :offset => 1)
|
||||
assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC, posts.id', :limit => 2, :offset => 1)
|
||||
end
|
||||
|
||||
def test_preload_with_interpolation
|
||||
assert_equal [comments(:greetings)], Post.find(posts(:welcome).id, :include => :comments_with_interpolated_conditions).comments_with_interpolated_conditions
|
||||
end
|
||||
|
||||
def test_polymorphic_type_condition
|
||||
post = Post.find(posts(:thinking).id, :include => :taggings)
|
||||
assert post.taggings.include?(taggings(:thinking_general))
|
||||
post = SpecialPost.find(posts(:thinking).id, :include => :taggings)
|
||||
assert post.taggings.include?(taggings(:thinking_general))
|
||||
end
|
||||
|
||||
def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm
|
||||
# Eager includes of has many and habtm associations aren't necessarily sorted in the same way
|
||||
def assert_equal_after_sort(item1, item2, item3 = nil)
|
||||
assert_equal(item1.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id})
|
||||
assert_equal(item3.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) if item3
|
||||
end
|
||||
# Test regular association, association with conditions, association with
|
||||
# STI, and association with conditions assured not to be true
|
||||
post_types = [:posts, :other_posts, :special_posts]
|
||||
# test both has_many and has_and_belongs_to_many
|
||||
[Author, Category].each do |className|
|
||||
d1 = find_all_ordered(className)
|
||||
# test including all post types at once
|
||||
d2 = find_all_ordered(className, post_types)
|
||||
d1.each_index do |i|
|
||||
assert_equal(d1[i], d2[i])
|
||||
assert_equal_after_sort(d1[i].posts, d2[i].posts)
|
||||
post_types[1..-1].each do |post_type|
|
||||
# test including post_types together
|
||||
d3 = find_all_ordered(className, [:posts, post_type])
|
||||
assert_equal(d1[i], d3[i])
|
||||
assert_equal_after_sort(d1[i].posts, d3[i].posts)
|
||||
assert_equal_after_sort(d1[i].send(post_type), d2[i].send(post_type), d3[i].send(post_type))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_with_multiple_associations_with_same_table_has_one
|
||||
d1 = find_all_ordered(Firm)
|
||||
d2 = find_all_ordered(Firm, :account)
|
||||
d1.each_index do |i|
|
||||
assert_equal(d1[i], d2[i])
|
||||
assert_equal(d1[i].account, d2[i].account)
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_with_multiple_associations_with_same_table_belongs_to
|
||||
firm_types = [:firm, :firm_with_basic_id, :firm_with_other_name, :firm_with_condition]
|
||||
d1 = find_all_ordered(Client)
|
||||
d2 = find_all_ordered(Client, firm_types)
|
||||
d1.each_index do |i|
|
||||
assert_equal(d1[i], d2[i])
|
||||
firm_types.each { |type| assert_equal(d1[i].send(type), d2[i].send(type)) }
|
||||
end
|
||||
end
|
||||
def test_eager_with_valid_association_as_string_not_symbol
|
||||
assert_nothing_raised { Post.find(:all, :include => 'comments') }
|
||||
end
|
||||
|
||||
def test_eager_with_floating_point_numbers
|
||||
assert_queries(2) do
|
||||
# Before changes, the floating point numbers will be interpreted as table names and will cause this to run in one query
|
||||
Comment.find :all, :conditions => "123.456 = 123.456", :include => :post
|
||||
end
|
||||
end
|
||||
|
||||
def test_preconfigured_includes_with_belongs_to
|
||||
author = posts(:welcome).author_with_posts
|
||||
assert_no_queries {assert_equal 5, author.posts.size}
|
||||
end
|
||||
|
||||
def test_preconfigured_includes_with_has_one
|
||||
comment = posts(:sti_comments).very_special_comment_with_post
|
||||
assert_no_queries {assert_equal posts(:sti_comments), comment.post}
|
||||
end
|
||||
|
||||
def test_preconfigured_includes_with_has_many
|
||||
posts = authors(:david).posts_with_comments
|
||||
one = posts.detect { |p| p.id == 1 }
|
||||
assert_no_queries do
|
||||
assert_equal 5, posts.size
|
||||
assert_equal 2, one.comments.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_preconfigured_includes_with_habtm
|
||||
posts = authors(:david).posts_with_categories
|
||||
one = posts.detect { |p| p.id == 1 }
|
||||
assert_no_queries do
|
||||
assert_equal 5, posts.size
|
||||
assert_equal 2, one.categories.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_preconfigured_includes_with_has_many_and_habtm
|
||||
posts = authors(:david).posts_with_comments_and_categories
|
||||
one = posts.detect { |p| p.id == 1 }
|
||||
assert_no_queries do
|
||||
assert_equal 5, posts.size
|
||||
assert_equal 2, one.comments.size
|
||||
assert_equal 2, one.categories.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_count_with_include
|
||||
if current_adapter?(:SybaseAdapter)
|
||||
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "len(comments.body) > 15")
|
||||
elsif current_adapter?(:OpenBaseAdapter)
|
||||
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(FETCHBLOB(comments.body)) > 15")
|
||||
else
|
||||
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(comments.body) > 15")
|
||||
end
|
||||
end
|
||||
|
||||
def test_load_with_sti_sharing_association
|
||||
assert_queries(2) do #should not do 1 query per subclass
|
||||
Comment.find :all, :include => :post
|
||||
end
|
||||
end
|
||||
|
||||
def test_conditions_on_join_table_with_include_and_limit
|
||||
assert_equal 3, Developer.find(:all, :include => 'projects', :conditions => 'developers_projects.access_level = 1', :limit => 5).size
|
||||
end
|
||||
|
||||
def test_order_on_join_table_with_include_and_limit
|
||||
assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size
|
||||
end
|
||||
end
|
||||
62
vendor/rails/activerecord/test/cases/associations/extension_test.rb
vendored
Normal file
62
vendor/rails/activerecord/test/cases/associations/extension_test.rb
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/comment'
|
||||
require 'models/project'
|
||||
require 'models/developer'
|
||||
require 'models/company_in_module'
|
||||
|
||||
class AssociationsExtensionsTest < ActiveRecord::TestCase
|
||||
fixtures :projects, :developers, :developers_projects, :comments, :posts
|
||||
|
||||
def test_extension_on_has_many
|
||||
assert_equal comments(:more_greetings), posts(:welcome).comments.find_most_recent
|
||||
end
|
||||
|
||||
def test_extension_on_habtm
|
||||
assert_equal projects(:action_controller), developers(:david).projects.find_most_recent
|
||||
end
|
||||
|
||||
def test_named_extension_on_habtm
|
||||
assert_equal projects(:action_controller), developers(:david).projects_extended_by_name.find_most_recent
|
||||
end
|
||||
|
||||
def test_named_two_extensions_on_habtm
|
||||
assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_twice.find_most_recent
|
||||
assert_equal projects(:active_record), developers(:david).projects_extended_by_name_twice.find_least_recent
|
||||
end
|
||||
|
||||
def test_named_extension_and_block_on_habtm
|
||||
assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_and_block.find_most_recent
|
||||
assert_equal projects(:active_record), developers(:david).projects_extended_by_name_and_block.find_least_recent
|
||||
end
|
||||
|
||||
def test_marshalling_extensions
|
||||
david = developers(:david)
|
||||
assert_equal projects(:action_controller), david.projects.find_most_recent
|
||||
|
||||
david = Marshal.load(Marshal.dump(david))
|
||||
assert_equal projects(:action_controller), david.projects.find_most_recent
|
||||
end
|
||||
|
||||
def test_marshalling_named_extensions
|
||||
david = developers(:david)
|
||||
assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
|
||||
|
||||
david = Marshal.load(Marshal.dump(david))
|
||||
assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
|
||||
end
|
||||
|
||||
|
||||
def test_extension_name
|
||||
extension = Proc.new {}
|
||||
name = :association_name
|
||||
|
||||
assert_equal 'DeveloperAssociationNameAssociationExtension', Developer.send(:create_extension_modules, name, extension, []).first.name
|
||||
assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension',
|
||||
MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
|
||||
assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
|
||||
assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
773
vendor/rails/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
vendored
Normal file
773
vendor/rails/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
vendored
Normal file
|
|
@ -0,0 +1,773 @@
|
|||
require "cases/helper"
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/company'
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/computer'
|
||||
require 'models/customer'
|
||||
require 'models/order'
|
||||
require 'models/categorization'
|
||||
require 'models/category'
|
||||
require 'models/post'
|
||||
require 'models/author'
|
||||
require 'models/comment'
|
||||
require 'models/tag'
|
||||
require 'models/tagging'
|
||||
require 'models/person'
|
||||
require 'models/reader'
|
||||
require 'models/parrot'
|
||||
require 'models/pirate'
|
||||
require 'models/treasure'
|
||||
require 'models/price_estimate'
|
||||
require 'models/club'
|
||||
require 'models/member'
|
||||
require 'models/membership'
|
||||
require 'models/sponsor'
|
||||
|
||||
class ProjectWithAfterCreateHook < ActiveRecord::Base
|
||||
set_table_name 'projects'
|
||||
has_and_belongs_to_many :developers,
|
||||
:class_name => "DeveloperForProjectWithAfterCreateHook",
|
||||
:join_table => "developers_projects",
|
||||
:foreign_key => "project_id",
|
||||
:association_foreign_key => "developer_id"
|
||||
|
||||
after_create :add_david
|
||||
|
||||
def add_david
|
||||
david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
|
||||
david.projects << self
|
||||
end
|
||||
end
|
||||
|
||||
class DeveloperForProjectWithAfterCreateHook < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
has_and_belongs_to_many :projects,
|
||||
:class_name => "ProjectWithAfterCreateHook",
|
||||
:join_table => "developers_projects",
|
||||
:association_foreign_key => "project_id",
|
||||
:foreign_key => "developer_id"
|
||||
end
|
||||
|
||||
class ProjectWithSymbolsForKeys < ActiveRecord::Base
|
||||
set_table_name 'projects'
|
||||
has_and_belongs_to_many :developers,
|
||||
:class_name => "DeveloperWithSymbolsForKeys",
|
||||
:join_table => :developers_projects,
|
||||
:foreign_key => :project_id,
|
||||
:association_foreign_key => "developer_id"
|
||||
end
|
||||
|
||||
class DeveloperWithSymbolsForKeys < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
has_and_belongs_to_many :projects,
|
||||
:class_name => "ProjectWithSymbolsForKeys",
|
||||
:join_table => :developers_projects,
|
||||
:association_foreign_key => :project_id,
|
||||
:foreign_key => "developer_id"
|
||||
end
|
||||
|
||||
class DeveloperWithCounterSQL < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
has_and_belongs_to_many :projects,
|
||||
:class_name => "DeveloperWithCounterSQL",
|
||||
:join_table => "developers_projects",
|
||||
:association_foreign_key => "project_id",
|
||||
:foreign_key => "developer_id",
|
||||
:counter_sql => 'SELECT COUNT(*) AS count_all FROM projects INNER JOIN developers_projects ON projects.id = developers_projects.project_id WHERE developers_projects.developer_id =#{id}'
|
||||
end
|
||||
|
||||
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
|
||||
:parrots, :pirates, :treasures, :price_estimates, :tags, :taggings
|
||||
|
||||
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 3, active_record.developers.size
|
||||
assert active_record.developers.include?(david)
|
||||
end
|
||||
|
||||
def test_triple_equality
|
||||
assert !(Array === Developer.find(1).projects)
|
||||
assert Developer.find(1).projects === Array
|
||||
end
|
||||
|
||||
def test_adding_single
|
||||
jamis = Developer.find(2)
|
||||
jamis.projects.reload # 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.reload
|
||||
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_from_the_project_fixed_timestamp
|
||||
jamis = Developer.find(2)
|
||||
action_controller = Project.find(2)
|
||||
action_controller.developers.reload
|
||||
assert_equal 1, jamis.projects.size
|
||||
assert_equal 1, action_controller.developers.size
|
||||
updated_at = jamis.updated_at
|
||||
|
||||
action_controller.developers << jamis
|
||||
|
||||
assert_equal updated_at, jamis.updated_at
|
||||
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
|
||||
aredridel = Developer.new("name" => "Aredridel")
|
||||
aredridel.save
|
||||
aredridel.projects.reload
|
||||
aredridel.projects.push(Project.find(1), Project.find(2))
|
||||
assert_equal 2, aredridel.projects.size
|
||||
assert_equal 2, aredridel.projects(true).size
|
||||
end
|
||||
|
||||
def test_adding_a_collection
|
||||
aredridel = Developer.new("name" => "Aredridel")
|
||||
aredridel.save
|
||||
aredridel.projects.reload
|
||||
aredridel.projects.concat([Project.find(1), Project.find(2)])
|
||||
assert_equal 2, aredridel.projects.size
|
||||
assert_equal 2, aredridel.projects(true).size
|
||||
end
|
||||
|
||||
def test_adding_uses_default_values_on_join_table
|
||||
ac = projects(:action_controller)
|
||||
assert !developers(:jamis).projects.include?(ac)
|
||||
developers(:jamis).projects << ac
|
||||
|
||||
assert developers(:jamis, :reload).projects.include?(ac)
|
||||
project = developers(:jamis).projects.detect { |p| p == ac }
|
||||
assert_equal 1, project.access_level.to_i
|
||||
end
|
||||
|
||||
def test_habtm_attribute_access_and_respond_to
|
||||
project = developers(:jamis).projects[0]
|
||||
assert project.has_attribute?("name")
|
||||
assert project.has_attribute?("joined_on")
|
||||
assert project.has_attribute?("access_level")
|
||||
assert project.respond_to?("name")
|
||||
assert project.respond_to?("name=")
|
||||
assert project.respond_to?("name?")
|
||||
assert project.respond_to?("joined_on")
|
||||
# given that the 'join attribute' won't be persisted, I don't
|
||||
# think we should define the mutators
|
||||
#assert project.respond_to?("joined_on=")
|
||||
assert project.respond_to?("joined_on?")
|
||||
assert project.respond_to?("access_level")
|
||||
#assert project.respond_to?("access_level=")
|
||||
assert project.respond_to?("access_level?")
|
||||
end
|
||||
|
||||
def test_habtm_adding_before_save
|
||||
no_of_devels = Developer.count
|
||||
no_of_projects = Project.count
|
||||
aredridel = Developer.new("name" => "Aredridel")
|
||||
aredridel.projects.concat([Project.find(1), p = Project.new("name" => "Projekt")])
|
||||
assert aredridel.new_record?
|
||||
assert p.new_record?
|
||||
assert aredridel.save
|
||||
assert !aredridel.new_record?
|
||||
assert_equal no_of_devels+1, Developer.count
|
||||
assert_equal no_of_projects+1, Project.count
|
||||
assert_equal 2, aredridel.projects.size
|
||||
assert_equal 2, aredridel.projects(true).size
|
||||
end
|
||||
|
||||
def test_habtm_saving_multiple_relationships
|
||||
new_project = Project.new("name" => "Grimetime")
|
||||
amount_of_developers = 4
|
||||
developers = (0...amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }.reverse
|
||||
|
||||
new_project.developer_ids = [developers[0].id, developers[1].id]
|
||||
new_project.developers_with_callback_ids = [developers[2].id, developers[3].id]
|
||||
assert new_project.save
|
||||
|
||||
new_project.reload
|
||||
assert_equal amount_of_developers, new_project.developers.size
|
||||
assert_equal developers, new_project.developers
|
||||
end
|
||||
|
||||
def test_habtm_unique_order_preserved
|
||||
assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).non_unique_developers
|
||||
assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).developers
|
||||
end
|
||||
|
||||
def test_build
|
||||
devel = Developer.find(1)
|
||||
proj = assert_no_queries { devel.projects.build("name" => "Projekt") }
|
||||
assert !devel.projects.loaded?
|
||||
|
||||
assert_equal devel.projects.last, proj
|
||||
assert devel.projects.loaded?
|
||||
|
||||
assert proj.new_record?
|
||||
devel.save
|
||||
assert !proj.new_record?
|
||||
assert_equal devel.projects.last, proj
|
||||
assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
|
||||
end
|
||||
|
||||
def test_build_by_new_record
|
||||
devel = Developer.new(:name => "Marcel", :salary => 75000)
|
||||
proj1 = devel.projects.build(:name => "Make bed")
|
||||
proj2 = devel.projects.build(:name => "Lie in it")
|
||||
assert_equal devel.projects.last, proj2
|
||||
assert proj2.new_record?
|
||||
devel.save
|
||||
assert !devel.new_record?
|
||||
assert !proj2.new_record?
|
||||
assert_equal devel.projects.last, proj2
|
||||
assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
|
||||
end
|
||||
|
||||
def test_create
|
||||
devel = Developer.find(1)
|
||||
proj = devel.projects.create("name" => "Projekt")
|
||||
assert !devel.projects.loaded?
|
||||
|
||||
assert_equal devel.projects.last, proj
|
||||
assert !devel.projects.loaded?
|
||||
|
||||
assert !proj.new_record?
|
||||
assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
|
||||
end
|
||||
|
||||
def test_create_by_new_record
|
||||
devel = Developer.new(:name => "Marcel", :salary => 75000)
|
||||
proj1 = devel.projects.build(:name => "Make bed")
|
||||
proj2 = devel.projects.build(:name => "Lie in it")
|
||||
assert_equal devel.projects.last, proj2
|
||||
assert proj2.new_record?
|
||||
devel.save
|
||||
assert !devel.new_record?
|
||||
assert !proj2.new_record?
|
||||
assert_equal devel.projects.last, proj2
|
||||
assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
|
||||
end
|
||||
|
||||
def test_creation_respects_hash_condition
|
||||
post = categories(:general).post_with_conditions.build(:body => '')
|
||||
|
||||
assert post.save
|
||||
assert_equal 'Yet Another Testing Title', post.title
|
||||
|
||||
another_post = categories(:general).post_with_conditions.create(:body => '')
|
||||
|
||||
assert !another_post.new_record?
|
||||
assert_equal 'Yet Another Testing Title', another_post.title
|
||||
end
|
||||
|
||||
def test_uniq_after_the_fact
|
||||
dev = developers(:jamis)
|
||||
dev.projects << projects(:active_record)
|
||||
dev.projects << projects(:active_record)
|
||||
|
||||
assert_equal 3, dev.projects.size
|
||||
assert_equal 1, dev.projects.uniq.size
|
||||
end
|
||||
|
||||
def test_uniq_before_the_fact
|
||||
projects(:active_record).developers << developers(:jamis)
|
||||
projects(:active_record).developers << developers(:david)
|
||||
assert_equal 3, projects(:active_record, :reload).developers.size
|
||||
end
|
||||
|
||||
def test_uniq_option_prevents_duplicate_push
|
||||
project = projects(:active_record)
|
||||
project.developers << developers(:jamis)
|
||||
project.developers << developers(:david)
|
||||
assert_equal 3, project.developers.size
|
||||
|
||||
project.developers << developers(:david)
|
||||
project.developers << developers(:jamis)
|
||||
assert_equal 3, project.developers.size
|
||||
end
|
||||
|
||||
def test_deleting
|
||||
david = Developer.find(1)
|
||||
active_record = Project.find(1)
|
||||
david.projects.reload
|
||||
assert_equal 2, david.projects.size
|
||||
assert_equal 3, active_record.developers.size
|
||||
|
||||
david.projects.delete(active_record)
|
||||
|
||||
assert_equal 1, david.projects.size
|
||||
assert_equal 1, david.projects(true).size
|
||||
assert_equal 2, active_record.developers(true).size
|
||||
end
|
||||
|
||||
def test_deleting_array
|
||||
david = Developer.find(1)
|
||||
david.projects.reload
|
||||
david.projects.delete(Project.find(:all))
|
||||
assert_equal 0, david.projects.size
|
||||
assert_equal 0, david.projects(true).size
|
||||
end
|
||||
|
||||
def test_deleting_with_sql
|
||||
david = Developer.find(1)
|
||||
active_record = Project.find(1)
|
||||
active_record.developers.reload
|
||||
assert_equal 3, active_record.developers_by_sql.size
|
||||
|
||||
active_record.developers_by_sql.delete(david)
|
||||
assert_equal 2, active_record.developers_by_sql(true).size
|
||||
end
|
||||
|
||||
def test_deleting_array_with_sql
|
||||
active_record = Project.find(1)
|
||||
active_record.developers.reload
|
||||
assert_equal 3, active_record.developers_by_sql.size
|
||||
|
||||
active_record.developers_by_sql.delete(Developer.find(:all))
|
||||
assert_equal 0, active_record.developers_by_sql(true).size
|
||||
end
|
||||
|
||||
def test_deleting_all
|
||||
david = Developer.find(1)
|
||||
david.projects.reload
|
||||
david.projects.clear
|
||||
assert_equal 0, david.projects.size
|
||||
assert_equal 0, david.projects(true).size
|
||||
end
|
||||
|
||||
def test_removing_associations_on_destroy
|
||||
david = DeveloperWithBeforeDestroyRaise.find(1)
|
||||
assert !david.projects.empty?
|
||||
assert_nothing_raised { david.destroy }
|
||||
assert david.projects.empty?
|
||||
assert DeveloperWithBeforeDestroyRaise.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty?
|
||||
end
|
||||
|
||||
def test_additional_columns_from_join_table
|
||||
assert_date_from_db Date.new(2004, 10, 10), Developer.find(1).projects.first.joined_on.to_date
|
||||
end
|
||||
|
||||
def test_destroy_all
|
||||
david = Developer.find(1)
|
||||
david.projects.reload
|
||||
assert !david.projects.empty?
|
||||
david.projects.destroy_all
|
||||
assert david.projects.empty?
|
||||
assert david.projects(true).empty?
|
||||
end
|
||||
|
||||
def test_deprecated_push_with_attributes_was_removed
|
||||
jamis = developers(:jamis)
|
||||
assert_raise(NoMethodError) do
|
||||
jamis.projects.push_with_attributes(projects(:action_controller), :joined_on => Date.today)
|
||||
end
|
||||
end
|
||||
|
||||
def test_associations_with_conditions
|
||||
assert_equal 3, projects(:active_record).developers.size
|
||||
assert_equal 1, projects(:active_record).developers_named_david.size
|
||||
assert_equal 1, projects(:active_record).developers_named_david_with_hash_conditions.size
|
||||
|
||||
assert_equal developers(:david), projects(:active_record).developers_named_david.find(developers(:david).id)
|
||||
assert_equal developers(:david), projects(:active_record).developers_named_david_with_hash_conditions.find(developers(:david).id)
|
||||
assert_equal developers(:david), projects(:active_record).salaried_developers.find(developers(:david).id)
|
||||
|
||||
projects(:active_record).developers_named_david.clear
|
||||
assert_equal 2, projects(:active_record, :reload).developers.size
|
||||
end
|
||||
|
||||
def test_find_in_association
|
||||
# Using sql
|
||||
assert_equal developers(:david), projects(:active_record).developers.find(developers(:david).id), "SQL find"
|
||||
|
||||
# Using ruby
|
||||
active_record = projects(:active_record)
|
||||
active_record.developers.reload
|
||||
assert_equal developers(:david), active_record.developers.find(developers(:david).id), "Ruby find"
|
||||
end
|
||||
|
||||
def test_include_uses_array_include_after_loaded
|
||||
project = projects(:active_record)
|
||||
project.developers.class # force load target
|
||||
|
||||
developer = project.developers.first
|
||||
|
||||
assert_no_queries do
|
||||
assert project.developers.loaded?
|
||||
assert project.developers.include?(developer)
|
||||
end
|
||||
end
|
||||
|
||||
def test_include_checks_if_record_exists_if_target_not_loaded
|
||||
project = projects(:active_record)
|
||||
developer = project.developers.first
|
||||
|
||||
project.reload
|
||||
assert ! project.developers.loaded?
|
||||
assert_queries(1) do
|
||||
assert project.developers.include?(developer)
|
||||
end
|
||||
assert ! project.developers.loaded?
|
||||
end
|
||||
|
||||
def test_include_returns_false_for_non_matching_record_to_verify_scoping
|
||||
project = projects(:active_record)
|
||||
developer = Developer.create :name => "Bryan", :salary => 50_000
|
||||
|
||||
assert ! project.developers.loaded?
|
||||
assert ! project.developers.include?(developer)
|
||||
end
|
||||
|
||||
def test_find_in_association_with_custom_finder_sql
|
||||
assert_equal developers(:david), projects(:active_record).developers_with_finder_sql.find(developers(:david).id), "SQL find"
|
||||
|
||||
active_record = projects(:active_record)
|
||||
active_record.developers_with_finder_sql.reload
|
||||
assert_equal developers(:david), active_record.developers_with_finder_sql.find(developers(:david).id), "Ruby find"
|
||||
end
|
||||
|
||||
def test_find_in_association_with_custom_finder_sql_and_multiple_interpolations
|
||||
# interpolate once:
|
||||
assert_equal [developers(:david), developers(:jamis), developers(:poor_jamis)], projects(:active_record).developers_with_finder_sql, "first interpolation"
|
||||
# interpolate again, for a different project id
|
||||
assert_equal [developers(:david)], projects(:action_controller).developers_with_finder_sql, "second interpolation"
|
||||
end
|
||||
|
||||
def test_find_in_association_with_custom_finder_sql_and_string_id
|
||||
assert_equal developers(:david), projects(:active_record).developers_with_finder_sql.find(developers(:david).id.to_s), "SQL find"
|
||||
end
|
||||
|
||||
def test_find_with_merged_options
|
||||
assert_equal 1, projects(:active_record).limited_developers.size
|
||||
assert_equal 1, projects(:active_record).limited_developers.find(:all).size
|
||||
assert_equal 3, projects(:active_record).limited_developers.find(:all, :limit => nil).size
|
||||
end
|
||||
|
||||
def test_dynamic_find_should_respect_association_order
|
||||
# Developers are ordered 'name DESC, id DESC'
|
||||
low_id_jamis = developers(:jamis)
|
||||
middle_id_jamis = developers(:poor_jamis)
|
||||
high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
|
||||
|
||||
assert_equal high_id_jamis, projects(:active_record).developers.find(:first, :conditions => "name = 'Jamis'")
|
||||
assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis')
|
||||
end
|
||||
|
||||
def test_dynamic_find_order_should_override_association_order
|
||||
# Developers are ordered 'name DESC, id DESC'
|
||||
low_id_jamis = developers(:jamis)
|
||||
middle_id_jamis = developers(:poor_jamis)
|
||||
high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
|
||||
|
||||
assert_equal low_id_jamis, projects(:active_record).developers.find(:first, :conditions => "name = 'Jamis'", :order => 'id')
|
||||
assert_equal low_id_jamis, projects(:active_record).developers.find_by_name('Jamis', :order => 'id')
|
||||
end
|
||||
|
||||
def test_dynamic_find_all_should_respect_association_order
|
||||
# Developers are ordered 'name DESC, id DESC'
|
||||
low_id_jamis = developers(:jamis)
|
||||
middle_id_jamis = developers(:poor_jamis)
|
||||
high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
|
||||
|
||||
assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.find(:all, :conditions => "name = 'Jamis'")
|
||||
assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.find_all_by_name('Jamis')
|
||||
end
|
||||
|
||||
def test_dynamic_find_all_order_should_override_association_order
|
||||
# Developers are ordered 'name DESC, id DESC'
|
||||
low_id_jamis = developers(:jamis)
|
||||
middle_id_jamis = developers(:poor_jamis)
|
||||
high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
|
||||
|
||||
assert_equal [low_id_jamis, middle_id_jamis, high_id_jamis], projects(:active_record).developers.find(:all, :conditions => "name = 'Jamis'", :order => 'id')
|
||||
assert_equal [low_id_jamis, middle_id_jamis, high_id_jamis], projects(:active_record).developers.find_all_by_name('Jamis', :order => 'id')
|
||||
end
|
||||
|
||||
def test_dynamic_find_all_should_respect_association_limit
|
||||
assert_equal 1, projects(:active_record).limited_developers.find(:all, :conditions => "name = 'Jamis'").length
|
||||
assert_equal 1, projects(:active_record).limited_developers.find_all_by_name('Jamis').length
|
||||
end
|
||||
|
||||
def test_dynamic_find_all_order_should_override_association_limit
|
||||
assert_equal 2, projects(:active_record).limited_developers.find(:all, :conditions => "name = 'Jamis'", :limit => 9_000).length
|
||||
assert_equal 2, projects(:active_record).limited_developers.find_all_by_name('Jamis', :limit => 9_000).length
|
||||
end
|
||||
|
||||
def test_dynamic_find_all_should_respect_readonly_access
|
||||
projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid?}
|
||||
projects(:active_record).readonly_developers.each { |d| d.readonly? }
|
||||
end
|
||||
|
||||
def test_new_with_values_in_collection
|
||||
jamis = DeveloperForProjectWithAfterCreateHook.find_by_name('Jamis')
|
||||
david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
|
||||
project = ProjectWithAfterCreateHook.new(:name => "Cooking with Bertie")
|
||||
project.developers << jamis
|
||||
project.save!
|
||||
project.reload
|
||||
|
||||
assert project.developers.include?(jamis)
|
||||
assert project.developers.include?(david)
|
||||
end
|
||||
|
||||
def test_find_in_association_with_options
|
||||
developers = projects(:active_record).developers.find(:all)
|
||||
assert_equal 3, developers.size
|
||||
|
||||
assert_equal developers(:poor_jamis), projects(:active_record).developers.find(:first, :conditions => "salary < 10000")
|
||||
assert_equal developers(:jamis), projects(:active_record).developers.find(:first, :order => "salary DESC")
|
||||
end
|
||||
|
||||
def test_replace_with_less
|
||||
david = developers(:david)
|
||||
david.projects = [projects(:action_controller)]
|
||||
assert david.save
|
||||
assert_equal 1, david.projects.length
|
||||
end
|
||||
|
||||
def test_replace_with_new
|
||||
david = developers(:david)
|
||||
david.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
|
||||
david.save
|
||||
assert_equal 2, david.projects.length
|
||||
assert !david.projects.include?(projects(:active_record))
|
||||
end
|
||||
|
||||
def test_replace_on_new_object
|
||||
new_developer = Developer.new("name" => "Matz")
|
||||
new_developer.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
|
||||
new_developer.save
|
||||
assert_equal 2, new_developer.projects.length
|
||||
end
|
||||
|
||||
def test_consider_type
|
||||
developer = Developer.find(:first)
|
||||
special_project = SpecialProject.create("name" => "Special Project")
|
||||
|
||||
other_project = developer.projects.first
|
||||
developer.special_projects << special_project
|
||||
developer.reload
|
||||
|
||||
assert developer.projects.include?(special_project)
|
||||
assert developer.special_projects.include?(special_project)
|
||||
assert !developer.special_projects.include?(other_project)
|
||||
end
|
||||
|
||||
def test_update_attributes_after_push_without_duplicate_join_table_rows
|
||||
developer = Developer.new("name" => "Kano")
|
||||
project = SpecialProject.create("name" => "Special Project")
|
||||
assert developer.save
|
||||
developer.projects << project
|
||||
developer.update_attribute("name", "Bruza")
|
||||
assert_equal 1, Developer.connection.select_value(<<-end_sql).to_i
|
||||
SELECT count(*) FROM developers_projects
|
||||
WHERE project_id = #{project.id}
|
||||
AND developer_id = #{developer.id}
|
||||
end_sql
|
||||
end
|
||||
|
||||
def test_updating_attributes_on_non_rich_associations
|
||||
welcome = categories(:technology).posts.first
|
||||
welcome.title = "Something else"
|
||||
assert welcome.save!
|
||||
end
|
||||
|
||||
def test_habtm_respects_select
|
||||
categories(:technology).select_testing_posts(true).each do |o|
|
||||
assert_respond_to o, :correctness_marker
|
||||
end
|
||||
assert_respond_to categories(:technology).select_testing_posts.find(:first), :correctness_marker
|
||||
end
|
||||
|
||||
def test_updating_attributes_on_rich_associations
|
||||
david = projects(:action_controller).developers.first
|
||||
david.name = "DHH"
|
||||
assert_raises(ActiveRecord::ReadOnlyRecord) { david.save! }
|
||||
end
|
||||
|
||||
def test_updating_attributes_on_rich_associations_with_limited_find_from_reflection
|
||||
david = projects(:action_controller).selected_developers.first
|
||||
david.name = "DHH"
|
||||
assert_nothing_raised { david.save! }
|
||||
end
|
||||
|
||||
|
||||
def test_updating_attributes_on_rich_associations_with_limited_find
|
||||
david = projects(:action_controller).developers.find(:all, :select => "developers.*").first
|
||||
david.name = "DHH"
|
||||
assert david.save!
|
||||
end
|
||||
|
||||
def test_join_table_alias
|
||||
assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL').size
|
||||
end
|
||||
|
||||
def test_join_with_group
|
||||
group = Developer.columns.inject([]) do |g, c|
|
||||
g << "developers.#{c.name}"
|
||||
g << "developers_projects_2.#{c.name}"
|
||||
end
|
||||
Project.columns.each { |c| group << "projects.#{c.name}" }
|
||||
|
||||
assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL', :group => group.join(",")).size
|
||||
end
|
||||
|
||||
def test_find_grouped
|
||||
all_posts_from_category1 = Post.find(:all, :conditions => "category_id = 1", :joins => :categories)
|
||||
grouped_posts_of_category1 = Post.find(:all, :conditions => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories)
|
||||
assert_equal 4, all_posts_from_category1.size
|
||||
assert_equal 1, grouped_posts_of_category1.size
|
||||
end
|
||||
|
||||
def test_find_scoped_grouped
|
||||
assert_equal 4, categories(:general).posts_gruoped_by_title.size
|
||||
assert_equal 1, categories(:technology).posts_gruoped_by_title.size
|
||||
end
|
||||
|
||||
def test_get_ids
|
||||
assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort
|
||||
assert_equal [projects(:active_record).id], developers(:jamis).project_ids
|
||||
end
|
||||
|
||||
def test_get_ids_for_loaded_associations
|
||||
developer = developers(:david)
|
||||
developer.projects(true)
|
||||
assert_queries(0) do
|
||||
developer.project_ids
|
||||
developer.project_ids
|
||||
end
|
||||
end
|
||||
|
||||
def test_get_ids_for_unloaded_associations_does_not_load_them
|
||||
developer = developers(:david)
|
||||
assert !developer.projects.loaded?
|
||||
assert_equal projects(:active_record, :action_controller).map(&:id).sort, developer.project_ids.sort
|
||||
assert !developer.projects.loaded?
|
||||
end
|
||||
|
||||
def test_assign_ids
|
||||
developer = Developer.new("name" => "Joe")
|
||||
developer.project_ids = projects(:active_record, :action_controller).map(&:id)
|
||||
developer.save
|
||||
developer.reload
|
||||
assert_equal 2, developer.projects.length
|
||||
assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
|
||||
end
|
||||
|
||||
def test_assign_ids_ignoring_blanks
|
||||
developer = Developer.new("name" => "Joe")
|
||||
developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, '']
|
||||
developer.save
|
||||
developer.reload
|
||||
assert_equal 2, developer.projects.length
|
||||
assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
|
||||
end
|
||||
|
||||
def test_select_limited_ids_list
|
||||
# Set timestamps
|
||||
Developer.transaction do
|
||||
Developer.find(:all, :order => 'id').each_with_index do |record, i|
|
||||
record.update_attributes(:created_at => 5.years.ago + (i * 5.minutes))
|
||||
end
|
||||
end
|
||||
|
||||
join_base = ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase.new(Project)
|
||||
join_dep = ActiveRecord::Associations::ClassMethods::JoinDependency.new(join_base, :developers, nil)
|
||||
projects = Project.send(:select_limited_ids_list, {:order => 'developers.created_at'}, join_dep)
|
||||
assert !projects.include?("'"), projects
|
||||
assert_equal %w(1 2), projects.scan(/\d/).sort
|
||||
end
|
||||
|
||||
def test_scoped_find_on_through_association_doesnt_return_read_only_records
|
||||
tag = Post.find(1).tags.find_by_name("General")
|
||||
|
||||
assert_nothing_raised do
|
||||
tag.save!
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_many_through_polymorphic_has_manys_works
|
||||
assert_equal [10, 20].to_set, pirates(:redbeard).treasure_estimates.map(&:price).to_set
|
||||
end
|
||||
|
||||
def test_symbols_as_keys
|
||||
developer = DeveloperWithSymbolsForKeys.new(:name => 'David')
|
||||
project = ProjectWithSymbolsForKeys.new(:name => 'Rails Testing')
|
||||
project.developers << developer
|
||||
project.save!
|
||||
|
||||
assert_equal 1, project.developers.size
|
||||
assert_equal 1, developer.projects.size
|
||||
assert_equal developer, project.developers.find(:first)
|
||||
assert_equal project, developer.projects.find(:first)
|
||||
end
|
||||
|
||||
def test_dynamic_find_should_respect_association_include
|
||||
# SQL error in sort clause if :include is not included
|
||||
# due to Unknown column 'authors.id'
|
||||
assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
|
||||
end
|
||||
|
||||
def test_counting_on_habtm_association_and_not_array
|
||||
david = Developer.find(1)
|
||||
# Extra parameter just to make sure we aren't falling back to
|
||||
# Array#count in Ruby >=1.8.7, which would raise an ArgumentError
|
||||
assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
|
||||
end
|
||||
|
||||
def test_count
|
||||
david = Developer.find(1)
|
||||
assert_equal 2, david.projects.count
|
||||
end
|
||||
|
||||
def test_count_with_counter_sql
|
||||
developer = DeveloperWithCounterSQL.create(:name => 'tekin')
|
||||
developer.project_ids = [projects(:active_record).id]
|
||||
developer.save
|
||||
developer.reload
|
||||
assert_equal 1, developer.projects.count
|
||||
end
|
||||
|
||||
uses_mocha 'mocking Post.transaction' do
|
||||
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
||||
Post.expects(:transaction)
|
||||
Category.find(:first).posts.transaction do
|
||||
# nothing
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
1101
vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb
vendored
Normal file
1101
vendor/rails/activerecord/test/cases/associations/has_many_associations_test.rb
vendored
Normal file
File diff suppressed because it is too large
Load diff
247
vendor/rails/activerecord/test/cases/associations/has_many_through_associations_test.rb
vendored
Normal file
247
vendor/rails/activerecord/test/cases/associations/has_many_through_associations_test.rb
vendored
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/person'
|
||||
require 'models/reader'
|
||||
require 'models/comment'
|
||||
|
||||
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :posts, :readers, :people, :comments, :authors
|
||||
|
||||
def test_associate_existing
|
||||
assert_queries(2) { posts(:thinking);people(:david) }
|
||||
|
||||
posts(:thinking).people
|
||||
|
||||
assert_queries(1) do
|
||||
posts(:thinking).people << people(:david)
|
||||
end
|
||||
|
||||
assert_queries(1) do
|
||||
assert posts(:thinking).people.include?(people(:david))
|
||||
end
|
||||
|
||||
assert posts(:thinking).reload.people(true).include?(people(:david))
|
||||
end
|
||||
|
||||
def test_associating_new
|
||||
assert_queries(1) { posts(:thinking) }
|
||||
new_person = nil # so block binding catches it
|
||||
|
||||
assert_queries(0) do
|
||||
new_person = Person.new :first_name => 'bob'
|
||||
end
|
||||
|
||||
# Associating new records always saves them
|
||||
# Thus, 1 query for the new person record, 1 query for the new join table record
|
||||
assert_queries(2) do
|
||||
posts(:thinking).people << new_person
|
||||
end
|
||||
|
||||
assert_queries(1) do
|
||||
assert posts(:thinking).people.include?(new_person)
|
||||
end
|
||||
|
||||
assert posts(:thinking).reload.people(true).include?(new_person)
|
||||
end
|
||||
|
||||
def test_associate_new_by_building
|
||||
assert_queries(1) { posts(:thinking) }
|
||||
|
||||
assert_queries(0) do
|
||||
posts(:thinking).people.build(:first_name=>"Bob")
|
||||
posts(:thinking).people.new(:first_name=>"Ted")
|
||||
end
|
||||
|
||||
# Should only need to load the association once
|
||||
assert_queries(1) do
|
||||
assert posts(:thinking).people.collect(&:first_name).include?("Bob")
|
||||
assert posts(:thinking).people.collect(&:first_name).include?("Ted")
|
||||
end
|
||||
|
||||
# 2 queries for each new record (1 to save the record itself, 1 for the join model)
|
||||
# * 2 new records = 4
|
||||
# + 1 query to save the actual post = 5
|
||||
assert_queries(5) do
|
||||
posts(:thinking).body += '-changed'
|
||||
posts(:thinking).save
|
||||
end
|
||||
|
||||
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Bob")
|
||||
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Ted")
|
||||
end
|
||||
|
||||
def test_delete_association
|
||||
assert_queries(2){posts(:welcome);people(:michael); }
|
||||
|
||||
assert_queries(1) do
|
||||
posts(:welcome).people.delete(people(:michael))
|
||||
end
|
||||
|
||||
assert_queries(1) do
|
||||
assert posts(:welcome).people.empty?
|
||||
end
|
||||
|
||||
assert posts(:welcome).reload.people(true).empty?
|
||||
end
|
||||
|
||||
def test_replace_association
|
||||
assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
|
||||
|
||||
# 1 query to delete the existing reader (michael)
|
||||
# 1 query to associate the new reader (david)
|
||||
assert_queries(2) do
|
||||
posts(:welcome).people = [people(:david)]
|
||||
end
|
||||
|
||||
assert_queries(0){
|
||||
assert posts(:welcome).people.include?(people(:david))
|
||||
assert !posts(:welcome).people.include?(people(:michael))
|
||||
}
|
||||
|
||||
assert posts(:welcome).reload.people(true).include?(people(:david))
|
||||
assert !posts(:welcome).reload.people(true).include?(people(:michael))
|
||||
end
|
||||
|
||||
def test_associate_with_create
|
||||
assert_queries(1) { posts(:thinking) }
|
||||
|
||||
# 1 query for the new record, 1 for the join table record
|
||||
# No need to update the actual collection yet!
|
||||
assert_queries(2) do
|
||||
posts(:thinking).people.create(:first_name=>"Jeb")
|
||||
end
|
||||
|
||||
# *Now* we actually need the collection so it's loaded
|
||||
assert_queries(1) do
|
||||
assert posts(:thinking).people.collect(&:first_name).include?("Jeb")
|
||||
end
|
||||
|
||||
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Jeb")
|
||||
end
|
||||
|
||||
def test_associate_with_create_and_no_options
|
||||
peeps = posts(:thinking).people.count
|
||||
posts(:thinking).people.create(:first_name => 'foo')
|
||||
assert_equal peeps + 1, posts(:thinking).people.count
|
||||
end
|
||||
|
||||
def test_associate_with_create_exclamation_and_no_options
|
||||
peeps = posts(:thinking).people.count
|
||||
posts(:thinking).people.create!(:first_name => 'foo')
|
||||
assert_equal peeps + 1, posts(:thinking).people.count
|
||||
end
|
||||
|
||||
def test_clear_associations
|
||||
assert_queries(2) { posts(:welcome);posts(:welcome).people(true) }
|
||||
|
||||
assert_queries(1) do
|
||||
posts(:welcome).people.clear
|
||||
end
|
||||
|
||||
assert_queries(0) do
|
||||
assert posts(:welcome).people.empty?
|
||||
end
|
||||
|
||||
assert posts(:welcome).reload.people(true).empty?
|
||||
end
|
||||
|
||||
def test_association_callback_ordering
|
||||
Post.reset_log
|
||||
log = Post.log
|
||||
post = posts(:thinking)
|
||||
|
||||
post.people_with_callbacks << people(:michael)
|
||||
assert_equal [
|
||||
[:added, :before, "Michael"],
|
||||
[:added, :after, "Michael"]
|
||||
], log.last(2)
|
||||
|
||||
post.people_with_callbacks.push(people(:david), Person.create!(:first_name => "Bob"), Person.new(:first_name => "Lary"))
|
||||
assert_equal [
|
||||
[:added, :before, "David"],
|
||||
[:added, :after, "David"],
|
||||
[:added, :before, "Bob"],
|
||||
[:added, :after, "Bob"],
|
||||
[:added, :before, "Lary"],
|
||||
[:added, :after, "Lary"]
|
||||
],log.last(6)
|
||||
|
||||
post.people_with_callbacks.build(:first_name => "Ted")
|
||||
assert_equal [
|
||||
[:added, :before, "Ted"],
|
||||
[:added, :after, "Ted"]
|
||||
], log.last(2)
|
||||
|
||||
post.people_with_callbacks.create(:first_name => "Sam")
|
||||
assert_equal [
|
||||
[:added, :before, "Sam"],
|
||||
[:added, :after, "Sam"]
|
||||
], log.last(2)
|
||||
|
||||
post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")]
|
||||
assert_equal (%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort
|
||||
assert_equal [
|
||||
[:added, :before, "Julian"],
|
||||
[:added, :after, "Julian"],
|
||||
[:added, :before, "Roger"],
|
||||
[:added, :after, "Roger"]
|
||||
], log.last(4)
|
||||
|
||||
post.people_with_callbacks.clear
|
||||
assert_equal (%w(Michael David Julian Roger) * 2).sort, log.last(8).collect(&:last).sort
|
||||
end
|
||||
|
||||
def test_dynamic_find_should_respect_association_include
|
||||
# SQL error in sort clause if :include is not included
|
||||
# due to Unknown column 'comments.id'
|
||||
assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog')
|
||||
end
|
||||
|
||||
def test_count_with_include_should_alias_join_table
|
||||
assert_equal 2, people(:michael).posts.count(:include => :readers)
|
||||
end
|
||||
|
||||
def test_get_ids
|
||||
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
|
||||
end
|
||||
|
||||
def test_get_ids_for_loaded_associations
|
||||
person = people(:michael)
|
||||
person.posts(true)
|
||||
assert_queries(0) do
|
||||
person.post_ids
|
||||
person.post_ids
|
||||
end
|
||||
end
|
||||
|
||||
def test_get_ids_for_unloaded_associations_does_not_load_them
|
||||
person = people(:michael)
|
||||
assert !person.posts.loaded?
|
||||
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
|
||||
assert !person.posts.loaded?
|
||||
end
|
||||
|
||||
uses_mocha 'mocking Tag.transaction' do
|
||||
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
||||
Tag.expects(:transaction)
|
||||
Post.find(:first).tags.transaction do
|
||||
# nothing
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
|
||||
author = authors(:mary)
|
||||
post = Post.create!(:title => "TITLE", :body => "BODY")
|
||||
assert_equal [], post.author_favorites
|
||||
end
|
||||
|
||||
def test_has_many_association_through_a_belongs_to_association
|
||||
author = authors(:mary)
|
||||
post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
|
||||
author.author_favorites.create(:favorite_author_id => 1)
|
||||
author.author_favorites.create(:favorite_author_id => 2)
|
||||
author.author_favorites.create(:favorite_author_id => 3)
|
||||
assert_equal post.author.author_favorites, post.author_favorites
|
||||
end
|
||||
end
|
||||
362
vendor/rails/activerecord/test/cases/associations/has_one_associations_test.rb
vendored
Normal file
362
vendor/rails/activerecord/test/cases/associations/has_one_associations_test.rb
vendored
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
require "cases/helper"
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/company'
|
||||
|
||||
class HasOneAssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :accounts, :companies, :developers, :projects, :developers_projects
|
||||
|
||||
def setup
|
||||
Account.destroyed_account_ids.clear
|
||||
end
|
||||
|
||||
def test_has_one
|
||||
assert_equal companies(:first_firm).account, Account.find(1)
|
||||
assert_equal Account.find(1).credit_limit, companies(:first_firm).account.credit_limit
|
||||
end
|
||||
|
||||
def test_has_one_cache_nils
|
||||
firm = companies(:another_firm)
|
||||
assert_queries(1) { assert_nil firm.account }
|
||||
assert_queries(0) { assert_nil firm.account }
|
||||
|
||||
firms = Firm.find(:all, :include => :account)
|
||||
assert_queries(0) { firms.each(&:account) }
|
||||
end
|
||||
|
||||
def test_with_select
|
||||
assert_equal Firm.find(1).account_with_select.attributes.size, 2
|
||||
assert_equal Firm.find(1, :include => :account_with_select).account_with_select.attributes.size, 2
|
||||
end
|
||||
|
||||
def test_finding_using_primary_key
|
||||
firm = companies(:first_firm)
|
||||
assert_equal Account.find_by_firm_id(firm.id), firm.account
|
||||
firm.firm_id = companies(:rails_core).id
|
||||
assert_equal accounts(:rails_core_account), firm.account_using_primary_key
|
||||
end
|
||||
|
||||
def test_can_marshal_has_one_association_with_nil_target
|
||||
firm = Firm.new
|
||||
assert_nothing_raised do
|
||||
assert_equal firm.attributes, Marshal.load(Marshal.dump(firm)).attributes
|
||||
end
|
||||
|
||||
firm.account
|
||||
assert_nothing_raised do
|
||||
assert_equal firm.attributes, Marshal.load(Marshal.dump(firm)).attributes
|
||||
end
|
||||
end
|
||||
|
||||
def test_proxy_assignment
|
||||
company = companies(:first_firm)
|
||||
assert_nothing_raised { company.account = company.account }
|
||||
end
|
||||
|
||||
def test_triple_equality
|
||||
assert Account === companies(:first_firm).account
|
||||
assert companies(:first_firm).account === Account
|
||||
end
|
||||
|
||||
def test_type_mismatch
|
||||
assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).account = 1 }
|
||||
assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).account = Project.find(1) }
|
||||
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 = companies(:first_firm).account.id
|
||||
companies(:first_firm).account = nil
|
||||
companies(:first_firm).save
|
||||
assert_nil companies(:first_firm).account
|
||||
# account is dependent, therefore is destroyed when reference to owner is lost
|
||||
assert_raises(ActiveRecord::RecordNotFound) { Account.find(old_account_id) }
|
||||
end
|
||||
|
||||
def test_natural_assignment_to_already_associated_record
|
||||
company = companies(:first_firm)
|
||||
account = accounts(:signals37)
|
||||
assert_equal company.account, account
|
||||
company.account = account
|
||||
company.reload
|
||||
account.reload
|
||||
assert_equal company.account, account
|
||||
end
|
||||
|
||||
def test_assignment_without_replacement
|
||||
apple = Firm.create("name" => "Apple")
|
||||
citibank = Account.create("credit_limit" => 10)
|
||||
apple.account = citibank
|
||||
assert_equal apple.id, citibank.firm_id
|
||||
|
||||
hsbc = apple.build_account({ :credit_limit => 20}, false)
|
||||
assert_equal apple.id, hsbc.firm_id
|
||||
hsbc.save
|
||||
assert_equal apple.id, citibank.firm_id
|
||||
|
||||
nykredit = apple.create_account({ :credit_limit => 30}, false)
|
||||
assert_equal apple.id, nykredit.firm_id
|
||||
assert_equal apple.id, citibank.firm_id
|
||||
assert_equal apple.id, hsbc.firm_id
|
||||
end
|
||||
|
||||
def test_assignment_without_replacement_on_create
|
||||
apple = Firm.create("name" => "Apple")
|
||||
citibank = Account.create("credit_limit" => 10)
|
||||
apple.account = citibank
|
||||
assert_equal apple.id, citibank.firm_id
|
||||
|
||||
hsbc = apple.create_account({:credit_limit => 10}, false)
|
||||
assert_equal apple.id, hsbc.firm_id
|
||||
hsbc.save
|
||||
assert_equal apple.id, citibank.firm_id
|
||||
end
|
||||
|
||||
def test_dependence
|
||||
num_accounts = Account.count
|
||||
|
||||
firm = Firm.find(1)
|
||||
assert !firm.account.nil?
|
||||
account_id = firm.account.id
|
||||
assert_equal [], Account.destroyed_account_ids[firm.id]
|
||||
|
||||
firm.destroy
|
||||
assert_equal num_accounts - 1, Account.count
|
||||
assert_equal [account_id], Account.destroyed_account_ids[firm.id]
|
||||
end
|
||||
|
||||
def test_exclusive_dependence
|
||||
num_accounts = Account.count
|
||||
|
||||
firm = ExclusivelyDependentFirm.find(9)
|
||||
assert !firm.account.nil?
|
||||
account_id = firm.account.id
|
||||
assert_equal [], Account.destroyed_account_ids[firm.id]
|
||||
|
||||
firm.destroy
|
||||
assert_equal num_accounts - 1, Account.count
|
||||
assert_equal [], Account.destroyed_account_ids[firm.id]
|
||||
end
|
||||
|
||||
def test_dependence_with_nil_associate
|
||||
firm = DependentFirm.new(:name => 'nullify')
|
||||
firm.save!
|
||||
assert_nothing_raised { firm.destroy }
|
||||
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_build_association_twice_without_saving_affects_nothing
|
||||
count_of_account = Account.count
|
||||
firm = Firm.find(:first)
|
||||
account1 = firm.build_account("credit_limit" => 1000)
|
||||
account2 = firm.build_account("credit_limit" => 2000)
|
||||
|
||||
assert_equal count_of_account, Account.count
|
||||
end
|
||||
|
||||
def test_create_association
|
||||
firm = Firm.create(:name => "GlobalMegaCorp")
|
||||
account = firm.create_account(:credit_limit => 1000)
|
||||
assert_equal account, firm.reload.account
|
||||
end
|
||||
|
||||
def test_build
|
||||
firm = Firm.new("name" => "GlobalMegaCorp")
|
||||
firm.save
|
||||
|
||||
firm.account = account = Account.new("credit_limit" => 1000)
|
||||
assert_equal account, firm.account
|
||||
assert account.save
|
||||
assert_equal account, firm.account
|
||||
end
|
||||
|
||||
def test_build_before_child_saved
|
||||
firm = Firm.find(1)
|
||||
|
||||
account = firm.account.build("credit_limit" => 1000)
|
||||
assert_equal account, firm.account
|
||||
assert account.new_record?
|
||||
assert firm.save
|
||||
assert_equal account, firm.account
|
||||
assert !account.new_record?
|
||||
end
|
||||
|
||||
def test_build_before_either_saved
|
||||
firm = Firm.new("name" => "GlobalMegaCorp")
|
||||
|
||||
firm.account = account = Account.new("credit_limit" => 1000)
|
||||
assert_equal account, firm.account
|
||||
assert account.new_record?
|
||||
assert firm.save
|
||||
assert_equal account, firm.account
|
||||
assert !account.new_record?
|
||||
end
|
||||
|
||||
def test_failing_build_association
|
||||
firm = Firm.new("name" => "GlobalMegaCorp")
|
||||
firm.save
|
||||
|
||||
firm.account = account = Account.new
|
||||
assert_equal account, firm.account
|
||||
assert !account.save
|
||||
assert_equal account, firm.account
|
||||
assert_equal "can't be empty", account.errors.on("credit_limit")
|
||||
end
|
||||
|
||||
def test_create
|
||||
firm = Firm.new("name" => "GlobalMegaCorp")
|
||||
firm.save
|
||||
firm.account = account = Account.create("credit_limit" => 1000)
|
||||
assert_equal account, firm.account
|
||||
end
|
||||
|
||||
def test_create_before_save
|
||||
firm = Firm.new("name" => "GlobalMegaCorp")
|
||||
firm.account = account = Account.create("credit_limit" => 1000)
|
||||
assert_equal account, firm.account
|
||||
end
|
||||
|
||||
def test_dependence_with_missing_association
|
||||
Account.destroy_all
|
||||
firm = Firm.find(1)
|
||||
assert firm.account.nil?
|
||||
firm.destroy
|
||||
end
|
||||
|
||||
def test_dependence_with_missing_association_and_nullify
|
||||
Account.destroy_all
|
||||
firm = DependentFirm.find(:first)
|
||||
assert firm.account.nil?
|
||||
firm.destroy
|
||||
end
|
||||
|
||||
def test_assignment_before_parent_saved
|
||||
firm = Firm.new("name" => "GlobalMegaCorp")
|
||||
firm.account = a = Account.find(1)
|
||||
assert firm.new_record?
|
||||
assert_equal a, firm.account
|
||||
assert firm.save
|
||||
assert_equal a, firm.account
|
||||
assert_equal a, firm.account(true)
|
||||
end
|
||||
|
||||
def test_finding_with_interpolated_condition
|
||||
firm = Firm.find(:first)
|
||||
superior = firm.clients.create(:name => 'SuperiorCo')
|
||||
superior.rating = 10
|
||||
superior.save
|
||||
assert_equal 10, firm.clients_with_interpolated_conditions.first.rating
|
||||
end
|
||||
|
||||
def test_assignment_before_child_saved
|
||||
firm = Firm.find(1)
|
||||
firm.account = a = Account.new("credit_limit" => 1000)
|
||||
assert !a.new_record?
|
||||
assert_equal a, firm.account
|
||||
assert_equal a, firm.account
|
||||
assert_equal a, firm.account(true)
|
||||
end
|
||||
|
||||
def test_save_fails_for_invalid_has_one
|
||||
firm = Firm.find(:first)
|
||||
assert firm.valid?
|
||||
|
||||
firm.account = Account.new
|
||||
|
||||
assert !firm.account.valid?
|
||||
assert !firm.valid?
|
||||
assert !firm.save
|
||||
assert_equal "is invalid", firm.errors.on("account")
|
||||
end
|
||||
|
||||
|
||||
def test_save_succeeds_for_invalid_has_one_with_validate_false
|
||||
firm = Firm.find(:first)
|
||||
assert firm.valid?
|
||||
|
||||
firm.unvalidated_account = Account.new
|
||||
|
||||
assert !firm.unvalidated_account.valid?
|
||||
assert firm.valid?
|
||||
assert firm.save
|
||||
end
|
||||
|
||||
def test_assignment_before_either_saved
|
||||
firm = Firm.new("name" => "GlobalMegaCorp")
|
||||
firm.account = a = Account.new("credit_limit" => 1000)
|
||||
assert firm.new_record?
|
||||
assert a.new_record?
|
||||
assert_equal a, firm.account
|
||||
assert firm.save
|
||||
assert !firm.new_record?
|
||||
assert !a.new_record?
|
||||
assert_equal a, firm.account
|
||||
assert_equal a, firm.account(true)
|
||||
end
|
||||
|
||||
def test_not_resaved_when_unchanged
|
||||
firm = Firm.find(:first, :include => :account)
|
||||
firm.name += '-changed'
|
||||
assert_queries(1) { firm.save! }
|
||||
|
||||
firm = Firm.find(:first)
|
||||
firm.account = Account.find(:first)
|
||||
assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! }
|
||||
|
||||
firm = Firm.find(:first).clone
|
||||
firm.account = Account.find(:first)
|
||||
assert_queries(2) { firm.save! }
|
||||
|
||||
firm = Firm.find(:first).clone
|
||||
firm.account = Account.find(:first).clone
|
||||
assert_queries(2) { firm.save! }
|
||||
end
|
||||
|
||||
def test_save_still_works_after_accessing_nil_has_one
|
||||
jp = Company.new :name => 'Jaded Pixel'
|
||||
jp.dummy_account.nil?
|
||||
|
||||
assert_nothing_raised do
|
||||
jp.save!
|
||||
end
|
||||
end
|
||||
|
||||
def test_cant_save_readonly_association
|
||||
assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_firm).readonly_account.save! }
|
||||
assert companies(:first_firm).readonly_account.readonly?
|
||||
end
|
||||
|
||||
def test_has_one_proxy_should_not_respond_to_private_methods
|
||||
assert_raises(NoMethodError) { accounts(:signals37).private_method }
|
||||
assert_raises(NoMethodError) { companies(:first_firm).account.private_method }
|
||||
end
|
||||
|
||||
def test_has_one_proxy_should_respond_to_private_methods_via_send
|
||||
accounts(:signals37).send(:private_method)
|
||||
companies(:first_firm).account.send(:private_method)
|
||||
end
|
||||
|
||||
end
|
||||
161
vendor/rails/activerecord/test/cases/associations/has_one_through_associations_test.rb
vendored
Normal file
161
vendor/rails/activerecord/test/cases/associations/has_one_through_associations_test.rb
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
require "cases/helper"
|
||||
require 'models/club'
|
||||
require 'models/member'
|
||||
require 'models/membership'
|
||||
require 'models/sponsor'
|
||||
require 'models/organization'
|
||||
require 'models/member_detail'
|
||||
|
||||
class HasOneThroughAssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :members, :clubs, :memberships, :sponsors, :organizations
|
||||
|
||||
def setup
|
||||
@member = members(:groucho)
|
||||
end
|
||||
|
||||
def test_has_one_through_with_has_one
|
||||
assert_equal clubs(:boring_club), @member.club
|
||||
end
|
||||
|
||||
def test_has_one_through_with_has_many
|
||||
assert_equal clubs(:moustache_club), @member.favourite_club
|
||||
end
|
||||
|
||||
def test_creating_association_creates_through_record
|
||||
new_member = Member.create(:name => "Chris")
|
||||
new_member.club = Club.create(:name => "LRUG")
|
||||
assert_not_nil new_member.current_membership
|
||||
assert_not_nil new_member.club
|
||||
end
|
||||
|
||||
def test_replace_target_record
|
||||
new_club = Club.create(:name => "Marx Bros")
|
||||
@member.club = new_club
|
||||
@member.reload
|
||||
assert_equal new_club, @member.club
|
||||
end
|
||||
|
||||
def test_replacing_target_record_deletes_old_association
|
||||
assert_no_difference "Membership.count" do
|
||||
new_club = Club.create(:name => "Bananarama")
|
||||
@member.club = new_club
|
||||
@member.reload
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_one_through_polymorphic
|
||||
assert_equal clubs(:moustache_club), @member.sponsor_club
|
||||
end
|
||||
|
||||
def has_one_through_to_has_many
|
||||
assert_equal 2, @member.fellow_members.size
|
||||
end
|
||||
|
||||
def test_has_one_through_eager_loading
|
||||
members = assert_queries(3) do #base table, through table, clubs table
|
||||
Member.find(:all, :include => :club, :conditions => ["name = ?", "Groucho Marx"])
|
||||
end
|
||||
assert_equal 1, members.size
|
||||
assert_not_nil assert_no_queries {members[0].club}
|
||||
end
|
||||
|
||||
def test_has_one_through_eager_loading_through_polymorphic
|
||||
members = assert_queries(3) do #base table, through table, clubs table
|
||||
Member.find(:all, :include => :sponsor_club, :conditions => ["name = ?", "Groucho Marx"])
|
||||
end
|
||||
assert_equal 1, members.size
|
||||
assert_not_nil assert_no_queries {members[0].sponsor_club}
|
||||
end
|
||||
|
||||
def test_has_one_through_polymorphic_with_source_type
|
||||
assert_equal members(:groucho), clubs(:moustache_club).sponsored_member
|
||||
end
|
||||
|
||||
def test_eager_has_one_through_polymorphic_with_source_type
|
||||
clubs = Club.find(:all, :include => :sponsored_member, :conditions => ["name = ?","Moustache and Eyebrow Fancier Club"])
|
||||
# Only the eyebrow fanciers club has a sponsored_member
|
||||
assert_not_nil assert_no_queries {clubs[0].sponsored_member}
|
||||
end
|
||||
|
||||
def test_has_one_through_nonpreload_eagerloading
|
||||
members = assert_queries(1) do
|
||||
Member.find(:all, :include => :club, :conditions => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name') #force fallback
|
||||
end
|
||||
assert_equal 1, members.size
|
||||
assert_not_nil assert_no_queries {members[0].club}
|
||||
end
|
||||
|
||||
def test_has_one_through_nonpreload_eager_loading_through_polymorphic
|
||||
members = assert_queries(1) do
|
||||
Member.find(:all, :include => :sponsor_club, :conditions => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name') #force fallback
|
||||
end
|
||||
assert_equal 1, members.size
|
||||
assert_not_nil assert_no_queries {members[0].sponsor_club}
|
||||
end
|
||||
|
||||
def test_has_one_through_nonpreload_eager_loading_through_polymorphic_with_more_than_one_through_record
|
||||
Sponsor.new(:sponsor_club => clubs(:crazy_club), :sponsorable => members(:groucho)).save!
|
||||
members = assert_queries(1) do
|
||||
Member.find(:all, :include => :sponsor_club, :conditions => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name DESC') #force fallback
|
||||
end
|
||||
assert_equal 1, members.size
|
||||
assert_not_nil assert_no_queries { members[0].sponsor_club }
|
||||
assert_equal clubs(:crazy_club), members[0].sponsor_club
|
||||
end
|
||||
|
||||
def test_uninitialized_has_one_through_should_return_nil_for_unsaved_record
|
||||
assert_nil Member.new.club
|
||||
end
|
||||
|
||||
def test_assigning_association_correctly_assigns_target
|
||||
new_member = Member.create(:name => "Chris")
|
||||
new_member.club = new_club = Club.create(:name => "LRUG")
|
||||
assert_equal new_club, new_member.club.target
|
||||
end
|
||||
|
||||
def test_has_one_through_proxy_should_not_respond_to_private_methods
|
||||
assert_raises(NoMethodError) { clubs(:moustache_club).private_method }
|
||||
assert_raises(NoMethodError) { @member.club.private_method }
|
||||
end
|
||||
|
||||
def test_has_one_through_proxy_should_respond_to_private_methods_via_send
|
||||
clubs(:moustache_club).send(:private_method)
|
||||
@member.club.send(:private_method)
|
||||
end
|
||||
|
||||
def test_assigning_to_has_one_through_preserves_decorated_join_record
|
||||
@organization = organizations(:nsa)
|
||||
assert_difference 'MemberDetail.count', 1 do
|
||||
@member_detail = MemberDetail.new(:extra_data => 'Extra')
|
||||
@member.member_detail = @member_detail
|
||||
@member.organization = @organization
|
||||
end
|
||||
assert_equal @organization, @member.organization
|
||||
assert @organization.members.include?(@member)
|
||||
assert_equal 'Extra', @member.member_detail.extra_data
|
||||
end
|
||||
|
||||
def test_reassigning_has_one_through
|
||||
@organization = organizations(:nsa)
|
||||
@new_organization = organizations(:discordians)
|
||||
|
||||
assert_difference 'MemberDetail.count', 1 do
|
||||
@member_detail = MemberDetail.new(:extra_data => 'Extra')
|
||||
@member.member_detail = @member_detail
|
||||
@member.organization = @organization
|
||||
end
|
||||
assert_equal @organization, @member.organization
|
||||
assert_equal 'Extra', @member.member_detail.extra_data
|
||||
assert @organization.members.include?(@member)
|
||||
assert !@new_organization.members.include?(@member)
|
||||
|
||||
assert_no_difference 'MemberDetail.count' do
|
||||
@member.organization = @new_organization
|
||||
end
|
||||
assert_equal @new_organization, @member.organization
|
||||
assert_equal 'Extra', @member.member_detail.extra_data
|
||||
assert !@organization.members.include?(@member)
|
||||
assert @new_organization.members.include?(@member)
|
||||
end
|
||||
|
||||
end
|
||||
88
vendor/rails/activerecord/test/cases/associations/inner_join_association_test.rb
vendored
Normal file
88
vendor/rails/activerecord/test/cases/associations/inner_join_association_test.rb
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/comment'
|
||||
require 'models/author'
|
||||
require 'models/category'
|
||||
require 'models/categorization'
|
||||
|
||||
class InnerJoinAssociationTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :posts, :comments, :categories, :categories_posts, :categorizations
|
||||
|
||||
def test_construct_finder_sql_creates_inner_joins
|
||||
sql = Author.send(:construct_finder_sql, :joins => :posts)
|
||||
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
|
||||
end
|
||||
|
||||
def test_construct_finder_sql_cascades_inner_joins
|
||||
sql = Author.send(:construct_finder_sql, :joins => {:posts => :comments})
|
||||
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
|
||||
assert_match /INNER JOIN .?comments.? ON .?comments.?.post_id = posts.id/, sql
|
||||
end
|
||||
|
||||
def test_construct_finder_sql_inner_joins_through_associations
|
||||
sql = Author.send(:construct_finder_sql, :joins => :categorized_posts)
|
||||
assert_match /INNER JOIN .?categorizations.?.*INNER JOIN .?posts.?/, sql
|
||||
end
|
||||
|
||||
def test_construct_finder_sql_applies_association_conditions
|
||||
sql = Author.send(:construct_finder_sql, :joins => :categories_like_general, :conditions => "TERMINATING_MARKER")
|
||||
assert_match /INNER JOIN .?categories.? ON.*AND.*.?General.?.*TERMINATING_MARKER/, sql
|
||||
end
|
||||
|
||||
def test_construct_finder_sql_unpacks_nested_joins
|
||||
sql = Author.send(:construct_finder_sql, :joins => {:posts => [[:comments]]})
|
||||
assert_no_match /inner join.*inner join.*inner join/i, sql, "only two join clauses should be present"
|
||||
assert_match /INNER JOIN .?posts.? ON .?posts.?.author_id = authors.id/, sql
|
||||
assert_match /INNER JOIN .?comments.? ON .?comments.?.post_id = .?posts.?.id/, sql
|
||||
end
|
||||
|
||||
def test_construct_finder_sql_ignores_empty_joins_hash
|
||||
sql = Author.send(:construct_finder_sql, :joins => {})
|
||||
assert_no_match /JOIN/i, sql
|
||||
end
|
||||
|
||||
def test_construct_finder_sql_ignores_empty_joins_array
|
||||
sql = Author.send(:construct_finder_sql, :joins => [])
|
||||
assert_no_match /JOIN/i, sql
|
||||
end
|
||||
|
||||
def test_find_with_implicit_inner_joins_honors_readonly_without_select
|
||||
authors = Author.find(:all, :joins => :posts)
|
||||
assert !authors.empty?, "expected authors to be non-empty"
|
||||
assert authors.all? {|a| a.readonly? }, "expected all authors to be readonly"
|
||||
end
|
||||
|
||||
def test_find_with_implicit_inner_joins_honors_readonly_with_select
|
||||
authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
|
||||
assert !authors.empty?, "expected authors to be non-empty"
|
||||
assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly"
|
||||
end
|
||||
|
||||
def test_find_with_implicit_inner_joins_honors_readonly_false
|
||||
authors = Author.find(:all, :joins => :posts, :readonly => false)
|
||||
assert !authors.empty?, "expected authors to be non-empty"
|
||||
assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly"
|
||||
end
|
||||
|
||||
def test_find_with_implicit_inner_joins_does_not_set_associations
|
||||
authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
|
||||
assert !authors.empty?, "expected authors to be non-empty"
|
||||
assert authors.all? {|a| !a.send(:instance_variable_names).include?("@posts")}, "expected no authors to have the @posts association loaded"
|
||||
end
|
||||
|
||||
def test_count_honors_implicit_inner_joins
|
||||
real_count = Author.find(:all).sum{|a| a.posts.count }
|
||||
assert_equal real_count, Author.count(:joins => :posts), "plain inner join count should match the number of referenced posts records"
|
||||
end
|
||||
|
||||
def test_calculate_honors_implicit_inner_joins
|
||||
real_count = Author.find(:all).sum{|a| a.posts.count }
|
||||
assert_equal real_count, Author.calculate(:count, 'authors.id', :joins => :posts), "plain inner join count should match the number of referenced posts records"
|
||||
end
|
||||
|
||||
def test_calculate_honors_implicit_inner_joins_and_distinct_and_conditions
|
||||
real_count = Author.find(:all).select {|a| a.posts.any? {|p| p.title =~ /^Welcome/} }.length
|
||||
authors_with_welcoming_post_titles = Author.calculate(:count, 'authors.id', :joins => :posts, :distinct => true, :conditions => "posts.title like 'Welcome%'")
|
||||
assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'"
|
||||
end
|
||||
end
|
||||
714
vendor/rails/activerecord/test/cases/associations/join_model_test.rb
vendored
Normal file
714
vendor/rails/activerecord/test/cases/associations/join_model_test.rb
vendored
Normal file
|
|
@ -0,0 +1,714 @@
|
|||
require "cases/helper"
|
||||
require 'models/tag'
|
||||
require 'models/tagging'
|
||||
require 'models/post'
|
||||
require 'models/item'
|
||||
require 'models/comment'
|
||||
require 'models/author'
|
||||
require 'models/category'
|
||||
require 'models/categorization'
|
||||
require 'models/vertex'
|
||||
require 'models/edge'
|
||||
require 'models/book'
|
||||
require 'models/citation'
|
||||
|
||||
class AssociationsJoinModelTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books
|
||||
|
||||
def test_has_many
|
||||
assert authors(:david).categories.include?(categories(:general))
|
||||
end
|
||||
|
||||
def test_has_many_inherited
|
||||
assert authors(:mary).categories.include?(categories(:sti_test))
|
||||
end
|
||||
|
||||
def test_inherited_has_many
|
||||
assert categories(:sti_test).authors.include?(authors(:mary))
|
||||
end
|
||||
|
||||
def test_has_many_uniq_through_join_model
|
||||
assert_equal 2, authors(:mary).categorized_posts.size
|
||||
assert_equal 1, authors(:mary).unique_categorized_posts.size
|
||||
end
|
||||
|
||||
def test_has_many_uniq_through_count
|
||||
author = authors(:mary)
|
||||
assert !authors(:mary).unique_categorized_posts.loaded?
|
||||
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
|
||||
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
|
||||
assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
|
||||
assert !authors(:mary).unique_categorized_posts.loaded?
|
||||
end
|
||||
|
||||
def test_has_many_uniq_through_find
|
||||
assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
|
||||
end
|
||||
|
||||
def test_has_many_uniq_through_dynamic_find
|
||||
assert_equal 1, authors(:mary).unique_categorized_posts.find_all_by_title("So I was thinking").size
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many
|
||||
assert posts(:welcome).taggings.include?(taggings(:welcome_general))
|
||||
end
|
||||
|
||||
def test_polymorphic_has_one
|
||||
assert_equal taggings(:welcome_general), posts(:welcome).tagging
|
||||
end
|
||||
|
||||
def test_polymorphic_belongs_to
|
||||
assert_equal posts(:welcome), posts(:welcome).taggings.first.taggable
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model
|
||||
assert_equal tags(:general), tag = posts(:welcome).tags.first
|
||||
assert_no_queries do
|
||||
tag.tagging
|
||||
end
|
||||
end
|
||||
|
||||
def test_count_polymorphic_has_many
|
||||
assert_equal 1, posts(:welcome).taggings.count
|
||||
assert_equal 1, posts(:welcome).tags.count
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model_with_find
|
||||
assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
|
||||
assert_no_queries do
|
||||
tag.tagging
|
||||
end
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection
|
||||
assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
|
||||
assert_no_queries do
|
||||
tag.tagging
|
||||
end
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
|
||||
assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
|
||||
assert_no_queries do
|
||||
tag.tagging
|
||||
end
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model_with_disabled_include
|
||||
assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
|
||||
assert_queries 1 do
|
||||
tag.tagging
|
||||
end
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
|
||||
assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
|
||||
tag.author_id
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
|
||||
assert_equal tags(:misc), taggings(:welcome_general).super_tag
|
||||
assert_equal tags(:misc), posts(:welcome).super_tags.first
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
|
||||
post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
|
||||
assert_instance_of SubStiPost, post
|
||||
|
||||
tagging = tags(:misc).taggings.create(:taggable => post)
|
||||
assert_equal "SubStiPost", tagging.taggable_type
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model_with_inheritance
|
||||
assert_equal tags(:general), posts(:thinking).tags.first
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_going_through_join_model_with_inheritance_with_custom_class_name
|
||||
assert_equal tags(:general), posts(:thinking).funky_tags.first
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many_create_model_with_inheritance
|
||||
post = posts(:thinking)
|
||||
assert_instance_of SpecialPost, post
|
||||
|
||||
tagging = tags(:misc).taggings.create(:taggable => post)
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
end
|
||||
|
||||
def test_polymorphic_has_one_create_model_with_inheritance
|
||||
tagging = tags(:misc).create_tagging(:taggable => posts(:thinking))
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
end
|
||||
|
||||
def test_set_polymorphic_has_many
|
||||
tagging = tags(:misc).taggings.create
|
||||
posts(:thinking).taggings << tagging
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
end
|
||||
|
||||
def test_set_polymorphic_has_one
|
||||
tagging = tags(:misc).taggings.create
|
||||
posts(:thinking).tagging = tagging
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
end
|
||||
|
||||
def test_create_polymorphic_has_many_with_scope
|
||||
old_count = posts(:welcome).taggings.count
|
||||
tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
assert_equal old_count+1, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_create_bang_polymorphic_with_has_many_scope
|
||||
old_count = posts(:welcome).taggings.count
|
||||
tagging = posts(:welcome).taggings.create!(:tag => tags(:misc))
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
assert_equal old_count+1, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_create_polymorphic_has_one_with_scope
|
||||
old_count = Tagging.count
|
||||
tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
assert_equal old_count+1, Tagging.count
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_many_with_delete_all
|
||||
assert_equal 1, posts(:welcome).taggings.count
|
||||
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDeleteAll'
|
||||
post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count-1, Tagging.count
|
||||
assert_equal 0, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_many_with_destroy
|
||||
assert_equal 1, posts(:welcome).taggings.count
|
||||
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDestroy'
|
||||
post = find_post_with_dependency(1, :has_many, :taggings, :destroy)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count-1, Tagging.count
|
||||
assert_equal 0, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_many_with_nullify
|
||||
assert_equal 1, posts(:welcome).taggings.count
|
||||
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyNullify'
|
||||
post = find_post_with_dependency(1, :has_many, :taggings, :nullify)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count, Tagging.count
|
||||
assert_equal 0, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_one_with_destroy
|
||||
assert posts(:welcome).tagging
|
||||
posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneDestroy'
|
||||
post = find_post_with_dependency(1, :has_one, :tagging, :destroy)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count-1, Tagging.count
|
||||
assert_nil posts(:welcome).tagging(true)
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_one_with_nullify
|
||||
assert posts(:welcome).tagging
|
||||
posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneNullify'
|
||||
post = find_post_with_dependency(1, :has_one, :tagging, :nullify)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count, Tagging.count
|
||||
assert_nil posts(:welcome).tagging(true)
|
||||
end
|
||||
|
||||
def test_has_many_with_piggyback
|
||||
assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
|
||||
end
|
||||
|
||||
def test_include_has_many_through
|
||||
posts = Post.find(:all, :order => 'posts.id')
|
||||
posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
|
||||
assert_equal posts.length, posts_with_authors.length
|
||||
posts.length.times do |i|
|
||||
assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
|
||||
end
|
||||
end
|
||||
|
||||
def test_include_polymorphic_has_one
|
||||
post = Post.find_by_id(posts(:welcome).id, :include => :tagging)
|
||||
tagging = taggings(:welcome_general)
|
||||
assert_no_queries do
|
||||
assert_equal tagging, post.tagging
|
||||
end
|
||||
end
|
||||
|
||||
def test_include_polymorphic_has_one_defined_in_abstract_parent
|
||||
item = Item.find_by_id(items(:dvd).id, :include => :tagging)
|
||||
tagging = taggings(:godfather)
|
||||
assert_no_queries do
|
||||
assert_equal tagging, item.tagging
|
||||
end
|
||||
end
|
||||
|
||||
def test_include_polymorphic_has_many_through
|
||||
posts = Post.find(:all, :order => 'posts.id')
|
||||
posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
|
||||
assert_equal posts.length, posts_with_tags.length
|
||||
posts.length.times do |i|
|
||||
assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
|
||||
end
|
||||
end
|
||||
|
||||
def test_include_polymorphic_has_many
|
||||
posts = Post.find(:all, :order => 'posts.id')
|
||||
posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
|
||||
assert_equal posts.length, posts_with_taggings.length
|
||||
posts.length.times do |i|
|
||||
assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_many_find_all
|
||||
assert_equal [categories(:general)], authors(:david).categories.find(:all)
|
||||
end
|
||||
|
||||
def test_has_many_find_first
|
||||
assert_equal categories(:general), authors(:david).categories.find(:first)
|
||||
end
|
||||
|
||||
def test_has_many_with_hash_conditions
|
||||
assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
|
||||
end
|
||||
|
||||
def test_has_many_find_conditions
|
||||
assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
|
||||
assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
|
||||
end
|
||||
|
||||
def test_has_many_class_methods_called_by_method_missing
|
||||
assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
|
||||
assert_equal nil, authors(:david).categories.find_by_name('Technology')
|
||||
end
|
||||
|
||||
def test_has_many_array_methods_called_by_method_missing
|
||||
assert true, authors(:david).categories.any? { |category| category.name == 'General' }
|
||||
assert_nothing_raised { authors(:david).categories.sort }
|
||||
end
|
||||
|
||||
def test_has_many_going_through_join_model_with_custom_foreign_key
|
||||
assert_equal [], posts(:thinking).authors
|
||||
assert_equal [authors(:mary)], posts(:authorless).authors
|
||||
end
|
||||
|
||||
def test_both_scoped_and_explicit_joins_should_be_respected
|
||||
assert_nothing_raised do
|
||||
Post.send(:with_scope, :find => {:joins => "left outer join comments on comments.id = posts.id"}) do
|
||||
Post.find :all, :select => "comments.id, authors.id", :joins => "left outer join authors on authors.id = posts.author_id"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_belongs_to_polymorphic_with_counter_cache
|
||||
assert_equal 0, posts(:welcome)[:taggings_count]
|
||||
tagging = posts(:welcome).taggings.create(:tag => tags(:general))
|
||||
assert_equal 1, posts(:welcome, :reload)[:taggings_count]
|
||||
tagging.destroy
|
||||
assert posts(:welcome, :reload)[:taggings_count].zero?
|
||||
end
|
||||
|
||||
def test_unavailable_through_reflection
|
||||
assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
|
||||
end
|
||||
|
||||
def test_has_many_through_join_model_with_conditions
|
||||
assert_equal [], posts(:welcome).invalid_taggings
|
||||
assert_equal [], posts(:welcome).invalid_tags
|
||||
end
|
||||
|
||||
def test_has_many_polymorphic
|
||||
assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicError do
|
||||
assert_equal posts(:welcome, :thinking), tags(:general).taggables
|
||||
end
|
||||
assert_raise ActiveRecord::EagerLoadPolymorphicError do
|
||||
assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_many_polymorphic_with_source_type
|
||||
assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts
|
||||
end
|
||||
|
||||
def test_eager_has_many_polymorphic_with_source_type
|
||||
tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
|
||||
desired = posts(:welcome, :thinking)
|
||||
assert_no_queries do
|
||||
assert_equal desired, tag_with_include.tagged_posts
|
||||
end
|
||||
assert_equal 5, tag_with_include.taggings.length
|
||||
end
|
||||
|
||||
def test_has_many_through_has_many_find_all
|
||||
assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
|
||||
end
|
||||
|
||||
def test_has_many_through_has_many_find_all_with_custom_class
|
||||
assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
|
||||
end
|
||||
|
||||
def test_has_many_through_has_many_find_first
|
||||
assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
|
||||
end
|
||||
|
||||
def test_has_many_through_has_many_find_conditions
|
||||
options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
|
||||
assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
|
||||
end
|
||||
|
||||
def test_has_many_through_has_many_find_by_id
|
||||
assert_equal comments(:more_greetings), authors(:david).comments.find(2)
|
||||
end
|
||||
|
||||
def test_has_many_through_polymorphic_has_one
|
||||
assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tagging }
|
||||
end
|
||||
|
||||
def test_has_many_through_polymorphic_has_many
|
||||
assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
|
||||
end
|
||||
|
||||
def test_include_has_many_through_polymorphic_has_many
|
||||
author = Author.find_by_id(authors(:david).id, :include => :taggings)
|
||||
expected_taggings = taggings(:welcome_general, :thinking_general)
|
||||
assert_no_queries do
|
||||
assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_many_through_has_many_through
|
||||
assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tags }
|
||||
end
|
||||
|
||||
def test_has_many_through_habtm
|
||||
assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).post_categories }
|
||||
end
|
||||
|
||||
def test_eager_load_has_many_through_has_many
|
||||
author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
|
||||
SpecialComment.new; VerySpecialComment.new
|
||||
assert_no_queries do
|
||||
assert_equal [1,2,3,5,6,7,8,9,10], author.comments.collect(&:id)
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_load_has_many_through_has_many_with_conditions
|
||||
post = Post.find(:first, :include => :invalid_tags)
|
||||
assert_no_queries do
|
||||
post.invalid_tags
|
||||
end
|
||||
end
|
||||
|
||||
def test_eager_belongs_to_and_has_one_not_singularized
|
||||
assert_nothing_raised do
|
||||
Author.find(:first, :include => :author_address)
|
||||
AuthorAddress.find(:first, :include => :author)
|
||||
end
|
||||
end
|
||||
|
||||
def test_self_referential_has_many_through
|
||||
assert_equal [authors(:mary)], authors(:david).favorite_authors
|
||||
assert_equal [], authors(:mary).favorite_authors
|
||||
end
|
||||
|
||||
def test_add_to_self_referential_has_many_through
|
||||
new_author = Author.create(:name => "Bob")
|
||||
authors(:david).author_favorites.create :favorite_author => new_author
|
||||
assert_equal new_author, authors(:david).reload.favorite_authors.first
|
||||
end
|
||||
|
||||
def test_has_many_through_uses_conditions_specified_on_the_has_many_association
|
||||
author = Author.find(:first)
|
||||
assert !author.comments.blank?
|
||||
assert author.nonexistant_comments.blank?
|
||||
end
|
||||
|
||||
def test_has_many_through_uses_correct_attributes
|
||||
assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
|
||||
end
|
||||
|
||||
def test_associating_unsaved_records_with_has_many_through
|
||||
saved_post = posts(:thinking)
|
||||
new_tag = Tag.new(:name => "new")
|
||||
|
||||
saved_post.tags << new_tag
|
||||
assert !new_tag.new_record? #consistent with habtm!
|
||||
assert !saved_post.new_record?
|
||||
assert saved_post.tags.include?(new_tag)
|
||||
|
||||
assert !new_tag.new_record?
|
||||
assert saved_post.reload.tags(true).include?(new_tag)
|
||||
|
||||
|
||||
new_post = Post.new(:title => "Association replacmenet works!", :body => "You best believe it.")
|
||||
saved_tag = tags(:general)
|
||||
|
||||
new_post.tags << saved_tag
|
||||
assert new_post.new_record?
|
||||
assert !saved_tag.new_record?
|
||||
assert new_post.tags.include?(saved_tag)
|
||||
|
||||
new_post.save!
|
||||
assert !new_post.new_record?
|
||||
assert new_post.reload.tags(true).include?(saved_tag)
|
||||
|
||||
assert posts(:thinking).tags.build.new_record?
|
||||
assert posts(:thinking).tags.new.new_record?
|
||||
end
|
||||
|
||||
def test_create_associate_when_adding_to_has_many_through
|
||||
count = posts(:thinking).tags.count
|
||||
push = Tag.create!(:name => 'pushme')
|
||||
post_thinking = posts(:thinking)
|
||||
assert_nothing_raised { post_thinking.tags << push }
|
||||
assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
|
||||
message = "Expected a Tag in tags collection, got #{wrong.class}.")
|
||||
assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
|
||||
message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
|
||||
assert_equal(count + 1, post_thinking.tags.size)
|
||||
assert_equal(count + 1, post_thinking.tags(true).size)
|
||||
|
||||
assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
|
||||
assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
|
||||
message = "Expected a Tag in tags collection, got #{wrong.class}.")
|
||||
assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
|
||||
message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
|
||||
assert_equal(count + 2, post_thinking.tags.size)
|
||||
assert_equal(count + 2, post_thinking.tags(true).size)
|
||||
|
||||
assert_nothing_raised { post_thinking.tags.concat(Tag.create!(:name => 'abc'), Tag.create!(:name => 'def')) }
|
||||
assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
|
||||
message = "Expected a Tag in tags collection, got #{wrong.class}.")
|
||||
assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
|
||||
message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
|
||||
assert_equal(count + 4, post_thinking.tags.size)
|
||||
assert_equal(count + 4, post_thinking.tags(true).size)
|
||||
|
||||
# Raises if the wrong reflection name is used to set the Edge belongs_to
|
||||
assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
|
||||
end
|
||||
|
||||
def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
|
||||
author = authors(:david)
|
||||
assert_equal 9, author.comments.size
|
||||
assert !author.comments.loaded?
|
||||
end
|
||||
|
||||
uses_mocha('has_many_through_collection_size_uses_counter_cache_if_it_exists') do
|
||||
def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
|
||||
author = authors(:david)
|
||||
author.stubs(:read_attribute).with('comments_count').returns(100)
|
||||
assert_equal 100, author.comments.size
|
||||
assert !author.comments.loaded?
|
||||
end
|
||||
end
|
||||
|
||||
def test_adding_junk_to_has_many_through_should_raise_type_mismatch
|
||||
assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags << "Uhh what now?" }
|
||||
end
|
||||
|
||||
def test_adding_to_has_many_through_should_return_self
|
||||
tags = posts(:thinking).tags
|
||||
assert_equal tags, posts(:thinking).tags.push(tags(:general))
|
||||
end
|
||||
|
||||
def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id
|
||||
count = books(:awdr).references.count
|
||||
references_before = books(:awdr).references
|
||||
book = Book.create!(:name => 'Getting Real')
|
||||
book_awdr = books(:awdr)
|
||||
book_awdr.references << book
|
||||
assert_equal(count + 1, book_awdr.references(true).size)
|
||||
|
||||
assert_nothing_raised { book_awdr.references.delete(book) }
|
||||
assert_equal(count, book_awdr.references.size)
|
||||
assert_equal(count, book_awdr.references(true).size)
|
||||
assert_equal(references_before.sort, book_awdr.references.sort)
|
||||
end
|
||||
|
||||
def test_delete_associate_when_deleting_from_has_many_through
|
||||
count = posts(:thinking).tags.count
|
||||
tags_before = posts(:thinking).tags
|
||||
tag = Tag.create!(:name => 'doomed')
|
||||
post_thinking = posts(:thinking)
|
||||
post_thinking.tags << tag
|
||||
assert_equal(count + 1, post_thinking.taggings(true).size)
|
||||
assert_equal(count + 1, post_thinking.tags(true).size)
|
||||
|
||||
assert_nothing_raised { post_thinking.tags.delete(tag) }
|
||||
assert_equal(count, post_thinking.tags.size)
|
||||
assert_equal(count, post_thinking.tags(true).size)
|
||||
assert_equal(count, post_thinking.taggings(true).size)
|
||||
assert_equal(tags_before.sort, post_thinking.tags.sort)
|
||||
end
|
||||
|
||||
def test_delete_associate_when_deleting_from_has_many_through_with_multiple_tags
|
||||
count = posts(:thinking).tags.count
|
||||
tags_before = posts(:thinking).tags
|
||||
doomed = Tag.create!(:name => 'doomed')
|
||||
doomed2 = Tag.create!(:name => 'doomed2')
|
||||
quaked = Tag.create!(:name => 'quaked')
|
||||
post_thinking = posts(:thinking)
|
||||
post_thinking.tags << doomed << doomed2
|
||||
assert_equal(count + 2, post_thinking.tags(true).size)
|
||||
|
||||
assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
|
||||
assert_equal(count, post_thinking.tags.size)
|
||||
assert_equal(count, post_thinking.tags(true).size)
|
||||
assert_equal(tags_before.sort, post_thinking.tags.sort)
|
||||
end
|
||||
|
||||
def test_deleting_junk_from_has_many_through_should_raise_type_mismatch
|
||||
assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags.delete("Uhh what now?") }
|
||||
end
|
||||
|
||||
def test_has_many_through_sum_uses_calculations
|
||||
assert_nothing_raised { authors(:david).comments.sum(:post_id) }
|
||||
end
|
||||
|
||||
def test_calculations_on_has_many_through_should_disambiguate_fields
|
||||
assert_nothing_raised { authors(:david).categories.maximum(:id) }
|
||||
end
|
||||
|
||||
def test_calculations_on_has_many_through_should_not_disambiguate_fields_unless_necessary
|
||||
assert_nothing_raised { authors(:david).categories.maximum("categories.id") }
|
||||
end
|
||||
|
||||
def test_has_many_through_has_many_with_sti
|
||||
assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
|
||||
end
|
||||
|
||||
def test_uniq_has_many_through_should_retain_order
|
||||
comment_ids = authors(:david).comments.map(&:id)
|
||||
assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
|
||||
assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
|
||||
end
|
||||
|
||||
def test_polymorphic_has_many
|
||||
expected = taggings(:welcome_general)
|
||||
p = Post.find(posts(:welcome).id, :include => :taggings)
|
||||
assert_no_queries {assert p.taggings.include?(expected)}
|
||||
assert posts(:welcome).taggings.include?(taggings(:welcome_general))
|
||||
end
|
||||
|
||||
def test_polymorphic_has_one
|
||||
expected = posts(:welcome)
|
||||
|
||||
tagging = Tagging.find(taggings(:welcome_general).id, :include => :taggable)
|
||||
assert_no_queries { assert_equal expected, tagging.taggable}
|
||||
end
|
||||
|
||||
def test_polymorphic_belongs_to
|
||||
p = Post.find(posts(:welcome).id, :include => {:taggings => :taggable})
|
||||
assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable}
|
||||
end
|
||||
|
||||
def test_preload_polymorphic_has_many_through
|
||||
posts = Post.find(:all, :order => 'posts.id')
|
||||
posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
|
||||
assert_equal posts.length, posts_with_tags.length
|
||||
posts.length.times do |i|
|
||||
assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
|
||||
end
|
||||
end
|
||||
|
||||
def test_preload_polymorph_many_types
|
||||
taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel']
|
||||
assert_no_queries do
|
||||
taggings.first.taggable.id
|
||||
taggings[1].taggable.id
|
||||
end
|
||||
|
||||
taggables = taggings.map(&:taggable)
|
||||
assert taggables.include?(items(:dvd))
|
||||
assert taggables.include?(posts(:welcome))
|
||||
end
|
||||
|
||||
def test_preload_nil_polymorphic_belongs_to
|
||||
assert_nothing_raised do
|
||||
taggings = Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
|
||||
end
|
||||
end
|
||||
|
||||
def test_preload_polymorphic_has_many
|
||||
posts = Post.find(:all, :order => 'posts.id')
|
||||
posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
|
||||
assert_equal posts.length, posts_with_taggings.length
|
||||
posts.length.times do |i|
|
||||
assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
|
||||
end
|
||||
end
|
||||
|
||||
def test_belongs_to_shared_parent
|
||||
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 1')
|
||||
assert_no_queries do
|
||||
assert_equal comments.first.post, comments[1].post
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_many_through_include_uses_array_include_after_loaded
|
||||
david = authors(:david)
|
||||
david.categories.class # force load target
|
||||
|
||||
category = david.categories.first
|
||||
|
||||
assert_no_queries do
|
||||
assert david.categories.loaded?
|
||||
assert david.categories.include?(category)
|
||||
end
|
||||
end
|
||||
|
||||
def test_has_many_through_include_checks_if_record_exists_if_target_not_loaded
|
||||
david = authors(:david)
|
||||
category = david.categories.first
|
||||
|
||||
david.reload
|
||||
assert ! david.categories.loaded?
|
||||
assert_queries(1) do
|
||||
assert david.categories.include?(category)
|
||||
end
|
||||
assert ! david.categories.loaded?
|
||||
end
|
||||
|
||||
def test_has_many_through_include_returns_false_for_non_matching_record_to_verify_scoping
|
||||
david = authors(:david)
|
||||
category = Category.create!(:name => 'Not Associated')
|
||||
|
||||
assert ! david.categories.loaded?
|
||||
assert ! david.categories.include?(category)
|
||||
end
|
||||
|
||||
def test_has_many_through_goes_through_all_sti_classes
|
||||
sub_sti_post = SubStiPost.create!(:title => 'test', :body => 'test', :author_id => 1)
|
||||
new_comment = sub_sti_post.comments.create(:body => 'test')
|
||||
|
||||
assert_equal [9, 10, new_comment.id], authors(:david).sti_post_comments.map(&:id).sort
|
||||
end
|
||||
|
||||
private
|
||||
# create dynamic Post models to allow different dependency options
|
||||
def find_post_with_dependency(post_id, association, association_name, dependency)
|
||||
class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
|
||||
Post.find(post_id).update_attribute :type, class_name
|
||||
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
||||
klass.set_table_name 'posts'
|
||||
klass.send(association, association_name, :as => :taggable, :dependent => dependency)
|
||||
klass.find(post_id)
|
||||
end
|
||||
end
|
||||
262
vendor/rails/activerecord/test/cases/associations_test.rb
vendored
Normal file
262
vendor/rails/activerecord/test/cases/associations_test.rb
vendored
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
require "cases/helper"
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/company'
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/computer'
|
||||
require 'models/customer'
|
||||
require 'models/order'
|
||||
require 'models/categorization'
|
||||
require 'models/category'
|
||||
require 'models/post'
|
||||
require 'models/author'
|
||||
require 'models/comment'
|
||||
require 'models/tag'
|
||||
require 'models/tagging'
|
||||
require 'models/person'
|
||||
require 'models/reader'
|
||||
require 'models/parrot'
|
||||
require 'models/pirate'
|
||||
require 'models/treasure'
|
||||
require 'models/price_estimate'
|
||||
require 'models/club'
|
||||
require 'models/member'
|
||||
require 'models/membership'
|
||||
require 'models/sponsor'
|
||||
|
||||
class AssociationsTest < ActiveRecord::TestCase
|
||||
fixtures :accounts, :companies, :developers, :projects, :developers_projects,
|
||||
:computers, :people, :readers
|
||||
|
||||
def test_include_with_order_works
|
||||
assert_nothing_raised {Account.find(:first, :order => 'id', :include => :firm)}
|
||||
assert_nothing_raised {Account.find(:first, :order => :id, :include => :firm)}
|
||||
end
|
||||
|
||||
def test_bad_collection_keys
|
||||
assert_raise(ArgumentError, 'ActiveRecord should have barked on bad collection keys') do
|
||||
Class.new(ActiveRecord::Base).has_many(:wheels, :name => 'wheels')
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_construct_new_finder_sql_after_create
|
||||
person = Person.new :first_name => 'clark'
|
||||
assert_equal [], person.readers.find(:all)
|
||||
person.save!
|
||||
reader = Reader.create! :person => person, :post => Post.new(:title => "foo", :body => "bar")
|
||||
assert person.readers.find(reader.id)
|
||||
end
|
||||
|
||||
def test_force_reload
|
||||
firm = Firm.new("name" => "A New Firm, Inc")
|
||||
firm.save
|
||||
firm.clients.each {|c|} # forcing to load all clients
|
||||
assert firm.clients.empty?, "New firm shouldn't have client objects"
|
||||
assert_equal 0, firm.clients.size, "New firm should have 0 clients"
|
||||
|
||||
client = Client.new("name" => "TheClient.com", "firm_id" => firm.id)
|
||||
client.save
|
||||
|
||||
assert firm.clients.empty?, "New firm should have cached no client objects"
|
||||
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.exist?(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 AssociationProxyTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :posts, :categorizations, :categories, :developers, :projects, :developers_projects
|
||||
|
||||
def test_proxy_accessors
|
||||
welcome = posts(:welcome)
|
||||
assert_equal welcome, welcome.author.proxy_owner
|
||||
assert_equal welcome.class.reflect_on_association(:author), welcome.author.proxy_reflection
|
||||
welcome.author.class # force load target
|
||||
assert_equal welcome.author, welcome.author.proxy_target
|
||||
|
||||
david = authors(:david)
|
||||
assert_equal david, david.posts.proxy_owner
|
||||
assert_equal david.class.reflect_on_association(:posts), david.posts.proxy_reflection
|
||||
david.posts.class # force load target
|
||||
assert_equal david.posts, david.posts.proxy_target
|
||||
|
||||
assert_equal david, david.posts_with_extension.testing_proxy_owner
|
||||
assert_equal david.class.reflect_on_association(:posts_with_extension), david.posts_with_extension.testing_proxy_reflection
|
||||
david.posts_with_extension.class # force load target
|
||||
assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target
|
||||
end
|
||||
|
||||
def test_push_does_not_load_target
|
||||
david = authors(:david)
|
||||
|
||||
david.posts << (post = Post.new(:title => "New on Edge", :body => "More cool stuff!"))
|
||||
assert !david.posts.loaded?
|
||||
assert david.posts.include?(post)
|
||||
end
|
||||
|
||||
def test_push_has_many_through_does_not_load_target
|
||||
david = authors(:david)
|
||||
|
||||
david.categories << categories(:technology)
|
||||
assert !david.categories.loaded?
|
||||
assert david.categories.include?(categories(:technology))
|
||||
end
|
||||
|
||||
def test_push_followed_by_save_does_not_load_target
|
||||
david = authors(:david)
|
||||
|
||||
david.posts << (post = Post.new(:title => "New on Edge", :body => "More cool stuff!"))
|
||||
assert !david.posts.loaded?
|
||||
david.save
|
||||
assert !david.posts.loaded?
|
||||
assert david.posts.include?(post)
|
||||
end
|
||||
|
||||
def test_push_does_not_lose_additions_to_new_record
|
||||
josh = Author.new(:name => "Josh")
|
||||
josh.posts << Post.new(:title => "New on Edge", :body => "More cool stuff!")
|
||||
assert josh.posts.loaded?
|
||||
assert_equal 1, josh.posts.size
|
||||
end
|
||||
|
||||
def test_save_on_parent_does_not_load_target
|
||||
david = developers(:david)
|
||||
|
||||
assert !david.projects.loaded?
|
||||
david.update_attribute(:created_at, Time.now)
|
||||
assert !david.projects.loaded?
|
||||
end
|
||||
|
||||
def test_inspect_does_not_reload_a_not_yet_loaded_target
|
||||
andreas = Developer.new :name => 'Andreas', :log => 'new developer added'
|
||||
assert !andreas.audit_logs.loaded?
|
||||
assert_match(/message: "new developer added"/, andreas.audit_logs.inspect)
|
||||
end
|
||||
|
||||
def test_save_on_parent_saves_children
|
||||
developer = Developer.create :name => "Bryan", :salary => 50_000
|
||||
assert_equal 1, developer.reload.audit_logs.size
|
||||
end
|
||||
|
||||
def test_create_via_association_with_block
|
||||
post = authors(:david).posts.create(:title => "New on Edge") {|p| p.body = "More cool stuff!"}
|
||||
assert_equal post.title, "New on Edge"
|
||||
assert_equal post.body, "More cool stuff!"
|
||||
end
|
||||
|
||||
def test_create_with_bang_via_association_with_block
|
||||
post = authors(:david).posts.create!(:title => "New on Edge") {|p| p.body = "More cool stuff!"}
|
||||
assert_equal post.title, "New on Edge"
|
||||
assert_equal post.body, "More cool stuff!"
|
||||
end
|
||||
|
||||
def test_failed_reload_returns_nil
|
||||
p = setup_dangling_association
|
||||
assert_nil p.author.reload
|
||||
end
|
||||
|
||||
def test_failed_reset_returns_nil
|
||||
p = setup_dangling_association
|
||||
assert_nil p.author.reset
|
||||
end
|
||||
|
||||
def test_reload_returns_assocition
|
||||
david = developers(:david)
|
||||
assert_nothing_raised do
|
||||
assert_equal david.projects, david.projects.reload.reload
|
||||
end
|
||||
end
|
||||
|
||||
def setup_dangling_association
|
||||
josh = Author.create(:name => "Josh")
|
||||
p = Post.create(:title => "New on Edge", :body => "More cool stuff!", :author => josh)
|
||||
josh.destroy
|
||||
p
|
||||
end
|
||||
end
|
||||
|
||||
class OverridingAssociationsTest < ActiveRecord::TestCase
|
||||
class Person < ActiveRecord::Base; end
|
||||
class DifferentPerson < ActiveRecord::Base; end
|
||||
|
||||
class PeopleList < ActiveRecord::Base
|
||||
has_and_belongs_to_many :has_and_belongs_to_many, :before_add => :enlist
|
||||
has_many :has_many, :before_add => :enlist
|
||||
belongs_to :belongs_to
|
||||
has_one :has_one
|
||||
end
|
||||
|
||||
class DifferentPeopleList < PeopleList
|
||||
# Different association with the same name, callbacks should be omitted here.
|
||||
has_and_belongs_to_many :has_and_belongs_to_many, :class_name => 'DifferentPerson'
|
||||
has_many :has_many, :class_name => 'DifferentPerson'
|
||||
belongs_to :belongs_to, :class_name => 'DifferentPerson'
|
||||
has_one :has_one, :class_name => 'DifferentPerson'
|
||||
end
|
||||
|
||||
def test_habtm_association_redefinition_callbacks_should_differ_and_not_inherited
|
||||
# redeclared association on AR descendant should not inherit callbacks from superclass
|
||||
callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many)
|
||||
assert_equal([:enlist], callbacks)
|
||||
callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many)
|
||||
assert_equal([], callbacks)
|
||||
end
|
||||
|
||||
def test_has_many_association_redefinition_callbacks_should_differ_and_not_inherited
|
||||
# redeclared association on AR descendant should not inherit callbacks from superclass
|
||||
callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_many)
|
||||
assert_equal([:enlist], callbacks)
|
||||
callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_many)
|
||||
assert_equal([], callbacks)
|
||||
end
|
||||
|
||||
def test_habtm_association_redefinition_reflections_should_differ_and_not_inherited
|
||||
assert_not_equal(
|
||||
PeopleList.reflect_on_association(:has_and_belongs_to_many),
|
||||
DifferentPeopleList.reflect_on_association(:has_and_belongs_to_many)
|
||||
)
|
||||
end
|
||||
|
||||
def test_has_many_association_redefinition_reflections_should_differ_and_not_inherited
|
||||
assert_not_equal(
|
||||
PeopleList.reflect_on_association(:has_many),
|
||||
DifferentPeopleList.reflect_on_association(:has_many)
|
||||
)
|
||||
end
|
||||
|
||||
def test_belongs_to_association_redefinition_reflections_should_differ_and_not_inherited
|
||||
assert_not_equal(
|
||||
PeopleList.reflect_on_association(:belongs_to),
|
||||
DifferentPeopleList.reflect_on_association(:belongs_to)
|
||||
)
|
||||
end
|
||||
|
||||
def test_has_one_association_redefinition_reflections_should_differ_and_not_inherited
|
||||
assert_not_equal(
|
||||
PeopleList.reflect_on_association(:has_one),
|
||||
DifferentPeopleList.reflect_on_association(:has_one)
|
||||
)
|
||||
end
|
||||
end
|
||||
293
vendor/rails/activerecord/test/cases/attribute_methods_test.rb
vendored
Normal file
293
vendor/rails/activerecord/test/cases/attribute_methods_test.rb
vendored
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/minimalistic'
|
||||
|
||||
class AttributeMethodsTest < ActiveRecord::TestCase
|
||||
fixtures :topics
|
||||
def setup
|
||||
@old_suffixes = ActiveRecord::Base.send(:attribute_method_suffixes).dup
|
||||
@target = Class.new(ActiveRecord::Base)
|
||||
@target.table_name = 'topics'
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActiveRecord::Base.send(:attribute_method_suffixes).clear
|
||||
ActiveRecord::Base.attribute_method_suffix *@old_suffixes
|
||||
end
|
||||
|
||||
def test_match_attribute_method_query_returns_match_data
|
||||
assert_not_nil md = @target.match_attribute_method?('title=')
|
||||
assert_equal 'title', md.pre_match
|
||||
assert_equal ['='], md.captures
|
||||
|
||||
%w(_hello_world ist! _maybe?).each do |suffix|
|
||||
@target.class_eval "def attribute#{suffix}(*args) args end"
|
||||
@target.attribute_method_suffix suffix
|
||||
|
||||
assert_not_nil md = @target.match_attribute_method?("title#{suffix}")
|
||||
assert_equal 'title', md.pre_match
|
||||
assert_equal [suffix], md.captures
|
||||
end
|
||||
end
|
||||
|
||||
def test_declared_attribute_method_affects_respond_to_and_method_missing
|
||||
topic = @target.new(:title => 'Budget')
|
||||
assert topic.respond_to?('title')
|
||||
assert_equal 'Budget', topic.title
|
||||
assert !topic.respond_to?('title_hello_world')
|
||||
assert_raise(NoMethodError) { topic.title_hello_world }
|
||||
|
||||
%w(_hello_world _it! _candidate= able?).each do |suffix|
|
||||
@target.class_eval "def attribute#{suffix}(*args) args end"
|
||||
@target.attribute_method_suffix suffix
|
||||
|
||||
meth = "title#{suffix}"
|
||||
assert topic.respond_to?(meth)
|
||||
assert_equal ['title'], topic.send(meth)
|
||||
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
||||
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_unserialize_attributes_for_frozen_records
|
||||
myobj = {:value1 => :value2}
|
||||
topic = Topic.create("content" => myobj)
|
||||
topic.freeze
|
||||
assert_equal myobj, topic.content
|
||||
end
|
||||
|
||||
def test_kernel_methods_not_implemented_in_activerecord
|
||||
%w(test name display y).each do |method|
|
||||
assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
|
||||
end
|
||||
end
|
||||
|
||||
def test_primary_key_implemented
|
||||
assert Class.new(ActiveRecord::Base).instance_method_already_implemented?('id')
|
||||
end
|
||||
|
||||
def test_defined_kernel_methods_implemented_in_model
|
||||
%w(test name display y).each do |method|
|
||||
klass = Class.new ActiveRecord::Base
|
||||
klass.class_eval "def #{method}() 'defined #{method}' end"
|
||||
assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
|
||||
end
|
||||
end
|
||||
|
||||
def test_defined_kernel_methods_implemented_in_model_abstract_subclass
|
||||
%w(test name display y).each do |method|
|
||||
abstract = Class.new ActiveRecord::Base
|
||||
abstract.class_eval "def #{method}() 'defined #{method}' end"
|
||||
abstract.abstract_class = true
|
||||
klass = Class.new abstract
|
||||
assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
|
||||
end
|
||||
end
|
||||
|
||||
def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
|
||||
%w(save create_or_update).each do |method|
|
||||
klass = Class.new ActiveRecord::Base
|
||||
klass.class_eval "def #{method}() 'defined #{method}' end"
|
||||
assert_raises ActiveRecord::DangerousAttributeError do
|
||||
klass.instance_method_already_implemented?(method)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_only_time_related_columns_are_meant_to_be_cached_by_default
|
||||
expected = %w(datetime timestamp time date).sort
|
||||
assert_equal expected, ActiveRecord::Base.attribute_types_cached_by_default.map(&:to_s).sort
|
||||
end
|
||||
|
||||
def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
|
||||
default_attributes = Topic.cached_attributes
|
||||
Topic.cache_attributes :replies_count
|
||||
expected = default_attributes + ["replies_count"]
|
||||
assert_equal expected.sort, Topic.cached_attributes.sort
|
||||
Topic.instance_variable_set "@cached_attributes", nil
|
||||
end
|
||||
|
||||
def test_time_related_columns_are_actually_cached
|
||||
column_types = %w(datetime timestamp time date).map(&:to_sym)
|
||||
column_names = Topic.columns.select{|c| column_types.include?(c.type) }.map(&:name)
|
||||
|
||||
assert_equal column_names.sort, Topic.cached_attributes.sort
|
||||
assert_equal time_related_columns_on_topic.sort, Topic.cached_attributes.sort
|
||||
end
|
||||
|
||||
def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
|
||||
t = topics(:first)
|
||||
cache = t.instance_variable_get "@attributes_cache"
|
||||
|
||||
assert_not_nil cache
|
||||
assert cache.empty?
|
||||
|
||||
all_columns = Topic.columns.map(&:name)
|
||||
cached_columns = time_related_columns_on_topic
|
||||
uncached_columns = all_columns - cached_columns
|
||||
|
||||
all_columns.each do |attr_name|
|
||||
attribute_gets_cached = Topic.cache_attribute?(attr_name)
|
||||
val = t.send attr_name unless attr_name == "type"
|
||||
if attribute_gets_cached
|
||||
assert cached_columns.include?(attr_name)
|
||||
assert_equal val, cache[attr_name]
|
||||
else
|
||||
assert uncached_columns.include?(attr_name)
|
||||
assert !cache.include?(attr_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_time_attributes_are_retrieved_in_current_time_zone
|
||||
in_time_zone "Pacific Time (US & Canada)" do
|
||||
utc_time = Time.utc(2008, 1, 1)
|
||||
record = @target.new
|
||||
record[:written_on] = utc_time
|
||||
assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
|
||||
assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
|
||||
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
|
||||
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
|
||||
end
|
||||
end
|
||||
|
||||
def test_setting_time_zone_aware_attribute_to_utc
|
||||
in_time_zone "Pacific Time (US & Canada)" do
|
||||
utc_time = Time.utc(2008, 1, 1)
|
||||
record = @target.new
|
||||
record.written_on = utc_time
|
||||
assert_equal utc_time, record.written_on
|
||||
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
||||
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
||||
end
|
||||
end
|
||||
|
||||
def test_setting_time_zone_aware_attribute_in_other_time_zone
|
||||
utc_time = Time.utc(2008, 1, 1)
|
||||
cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
|
||||
in_time_zone "Pacific Time (US & Canada)" do
|
||||
record = @target.new
|
||||
record.written_on = cst_time
|
||||
assert_equal utc_time, record.written_on
|
||||
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
||||
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
||||
end
|
||||
end
|
||||
|
||||
def test_setting_time_zone_aware_attribute_with_string
|
||||
utc_time = Time.utc(2008, 1, 1)
|
||||
(-11..13).each do |timezone_offset|
|
||||
time_string = utc_time.in_time_zone(timezone_offset).to_s
|
||||
in_time_zone "Pacific Time (US & Canada)" do
|
||||
record = @target.new
|
||||
record.written_on = time_string
|
||||
assert_equal Time.zone.parse(time_string), record.written_on
|
||||
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
||||
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
|
||||
in_time_zone "Pacific Time (US & Canada)" do
|
||||
record = @target.new
|
||||
record.written_on = ' '
|
||||
assert_nil record.written_on
|
||||
end
|
||||
end
|
||||
|
||||
def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
|
||||
time_string = 'Tue Jan 01 00:00:00 2008'
|
||||
(-11..13).each do |timezone_offset|
|
||||
in_time_zone timezone_offset do
|
||||
record = @target.new
|
||||
record.written_on = time_string
|
||||
assert_equal Time.zone.parse(time_string), record.written_on
|
||||
assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
|
||||
assert_equal Time.utc(2008, 1, 1), record.written_on.time
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_setting_time_zone_aware_attribute_in_current_time_zone
|
||||
utc_time = Time.utc(2008, 1, 1)
|
||||
in_time_zone "Pacific Time (US & Canada)" do
|
||||
record = @target.new
|
||||
record.written_on = utc_time.in_time_zone
|
||||
assert_equal utc_time, record.written_on
|
||||
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
||||
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
||||
end
|
||||
end
|
||||
|
||||
def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
|
||||
Topic.skip_time_zone_conversion_for_attributes = [:field_a]
|
||||
Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
|
||||
|
||||
assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
|
||||
assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
|
||||
end
|
||||
|
||||
def test_read_attributes_respect_access_control
|
||||
privatize("title")
|
||||
|
||||
topic = @target.new(:title => "The pros and cons of programming naked.")
|
||||
assert !topic.respond_to?(:title)
|
||||
exception = assert_raise(NoMethodError) { topic.title }
|
||||
assert_equal "Attempt to call private method", exception.message
|
||||
assert_equal "I'm private", topic.send(:title)
|
||||
end
|
||||
|
||||
def test_write_attributes_respect_access_control
|
||||
privatize("title=(value)")
|
||||
|
||||
topic = @target.new
|
||||
assert !topic.respond_to?(:title=)
|
||||
exception = assert_raise(NoMethodError) { topic.title = "Pants"}
|
||||
assert_equal "Attempt to call private method", exception.message
|
||||
topic.send(:title=, "Very large pants")
|
||||
end
|
||||
|
||||
def test_question_attributes_respect_access_control
|
||||
privatize("title?")
|
||||
|
||||
topic = @target.new(:title => "Isaac Newton's pants")
|
||||
assert !topic.respond_to?(:title?)
|
||||
exception = assert_raise(NoMethodError) { topic.title? }
|
||||
assert_equal "Attempt to call private method", exception.message
|
||||
assert topic.send(:title?)
|
||||
end
|
||||
|
||||
def test_bulk_update_respects_access_control
|
||||
privatize("title=(value)")
|
||||
|
||||
assert_raise(ActiveRecord::UnknownAttributeError) { topic = @target.new(:title => "Rants about pants") }
|
||||
assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
|
||||
end
|
||||
|
||||
private
|
||||
def time_related_columns_on_topic
|
||||
Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
|
||||
end
|
||||
|
||||
def in_time_zone(zone)
|
||||
old_zone = Time.zone
|
||||
old_tz = ActiveRecord::Base.time_zone_aware_attributes
|
||||
|
||||
Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
|
||||
ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
|
||||
yield
|
||||
ensure
|
||||
Time.zone = old_zone
|
||||
ActiveRecord::Base.time_zone_aware_attributes = old_tz
|
||||
end
|
||||
|
||||
def privatize(method_signature)
|
||||
@target.class_eval <<-private_method
|
||||
private
|
||||
def #{method_signature}
|
||||
"I'm private"
|
||||
end
|
||||
private_method
|
||||
end
|
||||
end
|
||||
2087
vendor/rails/activerecord/test/cases/base_test.rb
vendored
Executable file
2087
vendor/rails/activerecord/test/cases/base_test.rb
vendored
Executable file
File diff suppressed because it is too large
Load diff
30
vendor/rails/activerecord/test/cases/binary_test.rb
vendored
Normal file
30
vendor/rails/activerecord/test/cases/binary_test.rb
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
require "cases/helper"
|
||||
|
||||
# Without using prepared statements, it makes no sense to test
|
||||
# BLOB data with DB2 or Firebird, because the length of a statement
|
||||
# is limited to 32KB.
|
||||
unless current_adapter?(:SybaseAdapter, :DB2Adapter, :FirebirdAdapter)
|
||||
require 'models/binary'
|
||||
|
||||
class BinaryTest < ActiveRecord::TestCase
|
||||
FIXTURES = %w(flowers.jpg example.log)
|
||||
|
||||
def test_load_save
|
||||
Binary.delete_all
|
||||
|
||||
FIXTURES.each do |filename|
|
||||
data = File.read(ASSETS_ROOT + "/#{filename}")
|
||||
data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding)
|
||||
data.freeze
|
||||
|
||||
bin = Binary.new(:data => data)
|
||||
assert_equal data, bin.data, 'Newly assigned data differs from original'
|
||||
|
||||
bin.save!
|
||||
assert_equal data, bin.data, 'Data differs from original after save'
|
||||
|
||||
assert_equal data, bin.reload.data, 'Reloaded data differs from original'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
328
vendor/rails/activerecord/test/cases/calculations_test.rb
vendored
Normal file
328
vendor/rails/activerecord/test/cases/calculations_test.rb
vendored
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
require "cases/helper"
|
||||
require 'models/company'
|
||||
require 'models/topic'
|
||||
require 'models/edge'
|
||||
|
||||
Company.has_many :accounts
|
||||
|
||||
class NumericData < ActiveRecord::Base
|
||||
self.table_name = 'numeric_data'
|
||||
end
|
||||
|
||||
class CalculationsTest < ActiveRecord::TestCase
|
||||
fixtures :companies, :accounts, :topics
|
||||
|
||||
def test_should_sum_field
|
||||
assert_equal 318, Account.sum(:credit_limit)
|
||||
end
|
||||
|
||||
def test_should_average_field
|
||||
value = Account.average(:credit_limit)
|
||||
assert_kind_of BigDecimal, value
|
||||
assert_equal BigDecimal.new('53.0'), value
|
||||
end
|
||||
|
||||
def test_should_return_nil_as_average
|
||||
assert_nil NumericData.average(:bank_balance)
|
||||
end
|
||||
|
||||
def test_type_cast_calculated_value_should_convert_db_averages_of_fixnum_class_to_decimal
|
||||
assert_equal 0, NumericData.send(:type_cast_calculated_value, 0, nil, 'avg')
|
||||
assert_equal 53.0, NumericData.send(:type_cast_calculated_value, 53, nil, 'avg')
|
||||
end
|
||||
|
||||
def test_should_get_maximum_of_field
|
||||
assert_equal 60, Account.maximum(:credit_limit)
|
||||
end
|
||||
|
||||
def test_should_get_maximum_of_field_with_include
|
||||
assert_equal 50, Account.maximum(:credit_limit, :include => :firm, :conditions => "companies.name != 'Summit'")
|
||||
end
|
||||
|
||||
def test_should_get_maximum_of_field_with_scoped_include
|
||||
Account.with_scope :find => { :include => :firm, :conditions => "companies.name != 'Summit'" } do
|
||||
assert_equal 50, Account.maximum(:credit_limit)
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_get_minimum_of_field
|
||||
assert_equal 50, Account.minimum(:credit_limit)
|
||||
end
|
||||
|
||||
def test_should_group_by_field
|
||||
c = Account.sum(:credit_limit, :group => :firm_id)
|
||||
[1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
|
||||
end
|
||||
|
||||
def test_should_group_by_summed_field
|
||||
c = Account.sum(:credit_limit, :group => :firm_id)
|
||||
assert_equal 50, c[1]
|
||||
assert_equal 105, c[6]
|
||||
assert_equal 60, c[2]
|
||||
end
|
||||
|
||||
def test_should_order_by_grouped_field
|
||||
c = Account.sum(:credit_limit, :group => :firm_id, :order => "firm_id")
|
||||
assert_equal [1, 2, 6, 9], c.keys.compact
|
||||
end
|
||||
|
||||
def test_should_order_by_calculation
|
||||
c = Account.sum(:credit_limit, :group => :firm_id, :order => "sum_credit_limit desc, firm_id")
|
||||
assert_equal [105, 60, 53, 50, 50], c.keys.collect { |k| c[k] }
|
||||
assert_equal [6, 2, 9, 1], c.keys.compact
|
||||
end
|
||||
|
||||
def test_should_limit_calculation
|
||||
c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
|
||||
:group => :firm_id, :order => "firm_id", :limit => 2)
|
||||
assert_equal [1, 2], c.keys.compact
|
||||
end
|
||||
|
||||
def test_should_limit_calculation_with_offset
|
||||
c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
|
||||
:group => :firm_id, :order => "firm_id", :limit => 2, :offset => 1)
|
||||
assert_equal [2, 6], c.keys.compact
|
||||
end
|
||||
|
||||
def test_should_group_by_summed_field_having_condition
|
||||
c = Account.sum(:credit_limit, :group => :firm_id,
|
||||
:having => 'sum(credit_limit) > 50')
|
||||
assert_nil c[1]
|
||||
assert_equal 105, c[6]
|
||||
assert_equal 60, c[2]
|
||||
end
|
||||
|
||||
def test_should_group_by_summed_association
|
||||
c = Account.sum(:credit_limit, :group => :firm)
|
||||
assert_equal 50, c[companies(:first_firm)]
|
||||
assert_equal 105, c[companies(:rails_core)]
|
||||
assert_equal 60, c[companies(:first_client)]
|
||||
end
|
||||
|
||||
def test_should_sum_field_with_conditions
|
||||
assert_equal 105, Account.sum(:credit_limit, :conditions => 'firm_id = 6')
|
||||
end
|
||||
|
||||
def test_should_return_zero_if_sum_conditions_return_nothing
|
||||
assert_equal 0, Account.sum(:credit_limit, :conditions => '1 = 2')
|
||||
assert_equal 0, companies(:rails_core).companies.sum(:id, :conditions => '1 = 2')
|
||||
end
|
||||
|
||||
def test_sum_should_return_valid_values_for_decimals
|
||||
NumericData.create(:bank_balance => 19.83)
|
||||
assert_equal 19.83, NumericData.sum(:bank_balance)
|
||||
end
|
||||
|
||||
def test_should_group_by_summed_field_with_conditions
|
||||
c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
|
||||
:group => :firm_id)
|
||||
assert_nil c[1]
|
||||
assert_equal 105, c[6]
|
||||
assert_equal 60, c[2]
|
||||
end
|
||||
|
||||
def test_should_group_by_summed_field_with_conditions_and_having
|
||||
c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
|
||||
:group => :firm_id,
|
||||
:having => 'sum(credit_limit) > 60')
|
||||
assert_nil c[1]
|
||||
assert_equal 105, c[6]
|
||||
assert_nil c[2]
|
||||
end
|
||||
|
||||
def test_should_group_by_fields_with_table_alias
|
||||
c = Account.sum(:credit_limit, :group => 'accounts.firm_id')
|
||||
assert_equal 50, c[1]
|
||||
assert_equal 105, c[6]
|
||||
assert_equal 60, c[2]
|
||||
end
|
||||
|
||||
def test_should_calculate_with_invalid_field
|
||||
assert_equal 6, Account.calculate(:count, '*')
|
||||
assert_equal 6, Account.calculate(:count, :all)
|
||||
end
|
||||
|
||||
def test_should_calculate_grouped_with_invalid_field
|
||||
c = Account.count(:all, :group => 'accounts.firm_id')
|
||||
assert_equal 1, c[1]
|
||||
assert_equal 2, c[6]
|
||||
assert_equal 1, c[2]
|
||||
end
|
||||
|
||||
def test_should_calculate_grouped_association_with_invalid_field
|
||||
c = Account.count(:all, :group => :firm)
|
||||
assert_equal 1, c[companies(:first_firm)]
|
||||
assert_equal 2, c[companies(:rails_core)]
|
||||
assert_equal 1, c[companies(:first_client)]
|
||||
end
|
||||
|
||||
uses_mocha 'group_by_non_numeric_foreign_key_association' do
|
||||
def test_should_group_by_association_with_non_numeric_foreign_key
|
||||
ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
|
||||
|
||||
firm = mock()
|
||||
firm.expects(:id).returns("ABC")
|
||||
firm.expects(:class).returns(Firm)
|
||||
Company.expects(:find).with(["ABC"]).returns([firm])
|
||||
|
||||
column = mock()
|
||||
column.expects(:name).at_least_once.returns(:firm_id)
|
||||
column.expects(:type_cast).with("ABC").returns("ABC")
|
||||
Account.expects(:columns).at_least_once.returns([column])
|
||||
|
||||
c = Account.count(:all, :group => :firm)
|
||||
assert_equal Firm, c.first.first.class
|
||||
assert_equal 1, c.first.last
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_calculate_grouped_association_with_foreign_key_option
|
||||
Account.belongs_to :another_firm, :class_name => 'Firm', :foreign_key => 'firm_id'
|
||||
c = Account.count(:all, :group => :another_firm)
|
||||
assert_equal 1, c[companies(:first_firm)]
|
||||
assert_equal 2, c[companies(:rails_core)]
|
||||
assert_equal 1, c[companies(:first_client)]
|
||||
end
|
||||
|
||||
def test_should_not_modify_options_when_using_includes
|
||||
options = {:conditions => 'companies.id > 1', :include => :firm}
|
||||
options_copy = options.dup
|
||||
|
||||
Account.count(:all, options)
|
||||
assert_equal options_copy, options
|
||||
end
|
||||
|
||||
def test_should_calculate_grouped_by_function
|
||||
c = Company.count(:all, :group => "UPPER(#{QUOTED_TYPE})")
|
||||
assert_equal 2, c[nil]
|
||||
assert_equal 1, c['DEPENDENTFIRM']
|
||||
assert_equal 3, c['CLIENT']
|
||||
assert_equal 2, c['FIRM']
|
||||
end
|
||||
|
||||
def test_should_calculate_grouped_by_function_with_table_alias
|
||||
c = Company.count(:all, :group => "UPPER(companies.#{QUOTED_TYPE})")
|
||||
assert_equal 2, c[nil]
|
||||
assert_equal 1, c['DEPENDENTFIRM']
|
||||
assert_equal 3, c['CLIENT']
|
||||
assert_equal 2, c['FIRM']
|
||||
end
|
||||
|
||||
def test_should_not_overshadow_enumerable_sum
|
||||
assert_equal 6, [1, 2, 3].sum(&:abs)
|
||||
end
|
||||
|
||||
def test_should_sum_scoped_field
|
||||
assert_equal 15, companies(:rails_core).companies.sum(:id)
|
||||
end
|
||||
|
||||
def test_should_sum_scoped_field_with_conditions
|
||||
assert_equal 8, companies(:rails_core).companies.sum(:id, :conditions => 'id > 7')
|
||||
end
|
||||
|
||||
def test_should_group_by_scoped_field
|
||||
c = companies(:rails_core).companies.sum(:id, :group => :name)
|
||||
assert_equal 7, c['Leetsoft']
|
||||
assert_equal 8, c['Jadedpixel']
|
||||
end
|
||||
|
||||
def test_should_group_by_summed_field_with_conditions_and_having
|
||||
c = companies(:rails_core).companies.sum(:id, :group => :name,
|
||||
:having => 'sum(id) > 7')
|
||||
assert_nil c['Leetsoft']
|
||||
assert_equal 8, c['Jadedpixel']
|
||||
end
|
||||
|
||||
def test_should_reject_invalid_options
|
||||
assert_nothing_raised do
|
||||
[:count, :sum].each do |func|
|
||||
# empty options are valid
|
||||
Company.send(:validate_calculation_options, func)
|
||||
# these options are valid for all calculations
|
||||
[:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
|
||||
Company.send(:validate_calculation_options, func, opt => true)
|
||||
end
|
||||
end
|
||||
|
||||
# :include is only valid on :count
|
||||
Company.send(:validate_calculation_options, :count, :include => true)
|
||||
end
|
||||
|
||||
assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) }
|
||||
assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
|
||||
end
|
||||
|
||||
def test_should_count_selected_field_with_include
|
||||
assert_equal 6, Account.count(:distinct => true, :include => :firm)
|
||||
assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
|
||||
end
|
||||
|
||||
def test_should_count_manual_select_with_include
|
||||
assert_equal 6, Account.count(:select => "DISTINCT accounts.id", :include => :firm)
|
||||
end
|
||||
|
||||
def test_count_with_column_parameter
|
||||
assert_equal 5, Account.count(:firm_id)
|
||||
end
|
||||
|
||||
def test_count_with_column_and_options_parameter
|
||||
assert_equal 2, Account.count(:firm_id, :conditions => "credit_limit = 50")
|
||||
end
|
||||
|
||||
def test_count_with_no_parameters_isnt_deprecated
|
||||
assert_not_deprecated { Account.count }
|
||||
end
|
||||
|
||||
def test_count_with_too_many_parameters_raises
|
||||
assert_raise(ArgumentError) { Account.count(1, 2, 3) }
|
||||
end
|
||||
|
||||
def test_should_sum_expression
|
||||
assert_equal '636', Account.sum("2 * credit_limit")
|
||||
end
|
||||
|
||||
def test_count_with_from_option
|
||||
assert_equal Company.count(:all), Company.count(:all, :from => 'companies')
|
||||
assert_equal Account.count(:all, :conditions => "credit_limit = 50"),
|
||||
Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50")
|
||||
assert_equal Company.count(:type, :conditions => {:type => "Firm"}),
|
||||
Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies')
|
||||
end
|
||||
|
||||
def test_sum_with_from_option
|
||||
assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts')
|
||||
assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"),
|
||||
Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
|
||||
end
|
||||
|
||||
def test_average_with_from_option
|
||||
assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
|
||||
assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
|
||||
Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
|
||||
end
|
||||
|
||||
def test_minimum_with_from_option
|
||||
assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts')
|
||||
assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"),
|
||||
Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
|
||||
end
|
||||
|
||||
def test_maximum_with_from_option
|
||||
assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts')
|
||||
assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"),
|
||||
Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
|
||||
end
|
||||
|
||||
def test_from_option_with_specified_index
|
||||
if Edge.connection.adapter_name == 'MySQL'
|
||||
assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
|
||||
assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
|
||||
Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
|
||||
end
|
||||
end
|
||||
|
||||
def test_from_option_with_table_different_than_class
|
||||
assert_equal Account.count(:all), Company.count(:all, :from => 'accounts')
|
||||
end
|
||||
|
||||
end
|
||||
38
vendor/rails/activerecord/test/cases/callbacks_observers_test.rb
vendored
Normal file
38
vendor/rails/activerecord/test/cases/callbacks_observers_test.rb
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
require "cases/helper"
|
||||
|
||||
class Comment < ActiveRecord::Base
|
||||
attr_accessor :callers
|
||||
|
||||
before_validation :record_callers
|
||||
|
||||
def after_validation
|
||||
record_callers
|
||||
end
|
||||
|
||||
def record_callers
|
||||
callers << self.class if callers
|
||||
end
|
||||
end
|
||||
|
||||
class CommentObserver < ActiveRecord::Observer
|
||||
attr_accessor :callers
|
||||
|
||||
def after_validation(model)
|
||||
callers << self.class if callers
|
||||
end
|
||||
end
|
||||
|
||||
class CallbacksObserversTest < ActiveRecord::TestCase
|
||||
def test_model_callbacks_fire_before_observers_are_notified
|
||||
callers = []
|
||||
|
||||
comment = Comment.new
|
||||
comment.callers = callers
|
||||
|
||||
CommentObserver.instance.callers = callers
|
||||
|
||||
comment.valid?
|
||||
|
||||
assert_equal [Comment, Comment, CommentObserver], callers, "model callbacks did not fire before observers were notified"
|
||||
end
|
||||
end
|
||||
400
vendor/rails/activerecord/test/cases/callbacks_test.rb
vendored
Normal file
400
vendor/rails/activerecord/test/cases/callbacks_test.rb
vendored
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
require "cases/helper"
|
||||
|
||||
class CallbackDeveloper < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
|
||||
class << self
|
||||
def callback_string(callback_method)
|
||||
"history << [#{callback_method.to_sym.inspect}, :string]"
|
||||
end
|
||||
|
||||
def callback_proc(callback_method)
|
||||
Proc.new { |model| model.history << [callback_method, :proc] }
|
||||
end
|
||||
|
||||
def define_callback_method(callback_method)
|
||||
define_method("#{callback_method}_method") do |model|
|
||||
model.history << [callback_method, :method]
|
||||
end
|
||||
end
|
||||
|
||||
def callback_object(callback_method)
|
||||
klass = Class.new
|
||||
klass.send(:define_method, callback_method) do |model|
|
||||
model.history << [callback_method, :object]
|
||||
end
|
||||
klass.new
|
||||
end
|
||||
end
|
||||
|
||||
ActiveRecord::Callbacks::CALLBACKS.each do |callback_method|
|
||||
callback_method_sym = callback_method.to_sym
|
||||
define_callback_method(callback_method_sym)
|
||||
send(callback_method, callback_method_sym)
|
||||
send(callback_method, callback_string(callback_method_sym))
|
||||
send(callback_method, callback_proc(callback_method_sym))
|
||||
send(callback_method, callback_object(callback_method_sym))
|
||||
send(callback_method) { |model| model.history << [callback_method_sym, :block] }
|
||||
end
|
||||
|
||||
def history
|
||||
@history ||= []
|
||||
end
|
||||
|
||||
# after_initialize and after_find are invoked only if instance methods have been defined.
|
||||
def after_initialize
|
||||
end
|
||||
|
||||
def after_find
|
||||
end
|
||||
end
|
||||
|
||||
class ParentDeveloper < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
attr_accessor :after_save_called
|
||||
before_validation {|record| record.after_save_called = true}
|
||||
end
|
||||
|
||||
class ChildDeveloper < ParentDeveloper
|
||||
|
||||
end
|
||||
|
||||
class RecursiveCallbackDeveloper < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
|
||||
before_save :on_before_save
|
||||
after_save :on_after_save
|
||||
|
||||
attr_reader :on_before_save_called, :on_after_save_called
|
||||
|
||||
def on_before_save
|
||||
@on_before_save_called ||= 0
|
||||
@on_before_save_called += 1
|
||||
save unless @on_before_save_called > 1
|
||||
end
|
||||
|
||||
def on_after_save
|
||||
@on_after_save_called ||= 0
|
||||
@on_after_save_called += 1
|
||||
save unless @on_after_save_called > 1
|
||||
end
|
||||
end
|
||||
|
||||
class ImmutableDeveloper < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
|
||||
validates_inclusion_of :salary, :in => 50000..200000
|
||||
|
||||
before_save :cancel
|
||||
before_destroy :cancel
|
||||
|
||||
def cancelled?
|
||||
@cancelled == true
|
||||
end
|
||||
|
||||
private
|
||||
def cancel
|
||||
@cancelled = true
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
class ImmutableMethodDeveloper < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
|
||||
validates_inclusion_of :salary, :in => 50000..200000
|
||||
|
||||
def cancelled?
|
||||
@cancelled == true
|
||||
end
|
||||
|
||||
def before_save
|
||||
@cancelled = true
|
||||
false
|
||||
end
|
||||
|
||||
def before_destroy
|
||||
@cancelled = true
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
class CallbackCancellationDeveloper < ActiveRecord::Base
|
||||
set_table_name 'developers'
|
||||
def before_create
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
class CallbacksTest < ActiveRecord::TestCase
|
||||
fixtures :developers
|
||||
|
||||
def test_initialize
|
||||
david = CallbackDeveloper.new
|
||||
assert_equal [
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_find
|
||||
david = CallbackDeveloper.find(1)
|
||||
assert_equal [
|
||||
[ :after_find, :string ],
|
||||
[ :after_find, :proc ],
|
||||
[ :after_find, :object ],
|
||||
[ :after_find, :block ],
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_new_valid?
|
||||
david = CallbackDeveloper.new
|
||||
david.valid?
|
||||
assert_equal [
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
[ :before_validation, :string ],
|
||||
[ :before_validation, :proc ],
|
||||
[ :before_validation, :object ],
|
||||
[ :before_validation, :block ],
|
||||
[ :before_validation_on_create, :string ],
|
||||
[ :before_validation_on_create, :proc ],
|
||||
[ :before_validation_on_create, :object ],
|
||||
[ :before_validation_on_create, :block ],
|
||||
[ :after_validation, :string ],
|
||||
[ :after_validation, :proc ],
|
||||
[ :after_validation, :object ],
|
||||
[ :after_validation, :block ],
|
||||
[ :after_validation_on_create, :string ],
|
||||
[ :after_validation_on_create, :proc ],
|
||||
[ :after_validation_on_create, :object ],
|
||||
[ :after_validation_on_create, :block ]
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_existing_valid?
|
||||
david = CallbackDeveloper.find(1)
|
||||
david.valid?
|
||||
assert_equal [
|
||||
[ :after_find, :string ],
|
||||
[ :after_find, :proc ],
|
||||
[ :after_find, :object ],
|
||||
[ :after_find, :block ],
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
[ :before_validation, :string ],
|
||||
[ :before_validation, :proc ],
|
||||
[ :before_validation, :object ],
|
||||
[ :before_validation, :block ],
|
||||
[ :before_validation_on_update, :string ],
|
||||
[ :before_validation_on_update, :proc ],
|
||||
[ :before_validation_on_update, :object ],
|
||||
[ :before_validation_on_update, :block ],
|
||||
[ :after_validation, :string ],
|
||||
[ :after_validation, :proc ],
|
||||
[ :after_validation, :object ],
|
||||
[ :after_validation, :block ],
|
||||
[ :after_validation_on_update, :string ],
|
||||
[ :after_validation_on_update, :proc ],
|
||||
[ :after_validation_on_update, :object ],
|
||||
[ :after_validation_on_update, :block ]
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_create
|
||||
david = CallbackDeveloper.create('name' => 'David', 'salary' => 1000000)
|
||||
assert_equal [
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
[ :before_validation, :string ],
|
||||
[ :before_validation, :proc ],
|
||||
[ :before_validation, :object ],
|
||||
[ :before_validation, :block ],
|
||||
[ :before_validation_on_create, :string ],
|
||||
[ :before_validation_on_create, :proc ],
|
||||
[ :before_validation_on_create, :object ],
|
||||
[ :before_validation_on_create, :block ],
|
||||
[ :after_validation, :string ],
|
||||
[ :after_validation, :proc ],
|
||||
[ :after_validation, :object ],
|
||||
[ :after_validation, :block ],
|
||||
[ :after_validation_on_create, :string ],
|
||||
[ :after_validation_on_create, :proc ],
|
||||
[ :after_validation_on_create, :object ],
|
||||
[ :after_validation_on_create, :block ],
|
||||
[ :before_save, :string ],
|
||||
[ :before_save, :proc ],
|
||||
[ :before_save, :object ],
|
||||
[ :before_save, :block ],
|
||||
[ :before_create, :string ],
|
||||
[ :before_create, :proc ],
|
||||
[ :before_create, :object ],
|
||||
[ :before_create, :block ],
|
||||
[ :after_create, :string ],
|
||||
[ :after_create, :proc ],
|
||||
[ :after_create, :object ],
|
||||
[ :after_create, :block ],
|
||||
[ :after_save, :string ],
|
||||
[ :after_save, :proc ],
|
||||
[ :after_save, :object ],
|
||||
[ :after_save, :block ]
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_save
|
||||
david = CallbackDeveloper.find(1)
|
||||
david.save
|
||||
assert_equal [
|
||||
[ :after_find, :string ],
|
||||
[ :after_find, :proc ],
|
||||
[ :after_find, :object ],
|
||||
[ :after_find, :block ],
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
[ :before_validation, :string ],
|
||||
[ :before_validation, :proc ],
|
||||
[ :before_validation, :object ],
|
||||
[ :before_validation, :block ],
|
||||
[ :before_validation_on_update, :string ],
|
||||
[ :before_validation_on_update, :proc ],
|
||||
[ :before_validation_on_update, :object ],
|
||||
[ :before_validation_on_update, :block ],
|
||||
[ :after_validation, :string ],
|
||||
[ :after_validation, :proc ],
|
||||
[ :after_validation, :object ],
|
||||
[ :after_validation, :block ],
|
||||
[ :after_validation_on_update, :string ],
|
||||
[ :after_validation_on_update, :proc ],
|
||||
[ :after_validation_on_update, :object ],
|
||||
[ :after_validation_on_update, :block ],
|
||||
[ :before_save, :string ],
|
||||
[ :before_save, :proc ],
|
||||
[ :before_save, :object ],
|
||||
[ :before_save, :block ],
|
||||
[ :before_update, :string ],
|
||||
[ :before_update, :proc ],
|
||||
[ :before_update, :object ],
|
||||
[ :before_update, :block ],
|
||||
[ :after_update, :string ],
|
||||
[ :after_update, :proc ],
|
||||
[ :after_update, :object ],
|
||||
[ :after_update, :block ],
|
||||
[ :after_save, :string ],
|
||||
[ :after_save, :proc ],
|
||||
[ :after_save, :object ],
|
||||
[ :after_save, :block ]
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_destroy
|
||||
david = CallbackDeveloper.find(1)
|
||||
david.destroy
|
||||
assert_equal [
|
||||
[ :after_find, :string ],
|
||||
[ :after_find, :proc ],
|
||||
[ :after_find, :object ],
|
||||
[ :after_find, :block ],
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
[ :before_destroy, :string ],
|
||||
[ :before_destroy, :proc ],
|
||||
[ :before_destroy, :object ],
|
||||
[ :before_destroy, :block ],
|
||||
[ :after_destroy, :string ],
|
||||
[ :after_destroy, :proc ],
|
||||
[ :after_destroy, :object ],
|
||||
[ :after_destroy, :block ]
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_delete
|
||||
david = CallbackDeveloper.find(1)
|
||||
CallbackDeveloper.delete(david.id)
|
||||
assert_equal [
|
||||
[ :after_find, :string ],
|
||||
[ :after_find, :proc ],
|
||||
[ :after_find, :object ],
|
||||
[ :after_find, :block ],
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_before_save_returning_false
|
||||
david = ImmutableDeveloper.find(1)
|
||||
assert david.valid?
|
||||
assert !david.save
|
||||
assert_raises(ActiveRecord::RecordNotSaved) { david.save! }
|
||||
|
||||
david = ImmutableDeveloper.find(1)
|
||||
david.salary = 10_000_000
|
||||
assert !david.valid?
|
||||
assert !david.save
|
||||
assert_raises(ActiveRecord::RecordInvalid) { david.save! }
|
||||
end
|
||||
|
||||
def test_before_create_returning_false
|
||||
someone = CallbackCancellationDeveloper.new
|
||||
assert someone.valid?
|
||||
assert !someone.save
|
||||
end
|
||||
|
||||
def test_before_destroy_returning_false
|
||||
david = ImmutableDeveloper.find(1)
|
||||
assert !david.destroy
|
||||
assert_not_nil ImmutableDeveloper.find_by_id(1)
|
||||
end
|
||||
|
||||
def test_zzz_callback_returning_false # must be run last since we modify CallbackDeveloper
|
||||
david = CallbackDeveloper.find(1)
|
||||
CallbackDeveloper.before_validation proc { |model| model.history << [:before_validation, :returning_false]; return false }
|
||||
CallbackDeveloper.before_validation proc { |model| model.history << [:before_validation, :should_never_get_here] }
|
||||
david.save
|
||||
assert_equal [
|
||||
[ :after_find, :string ],
|
||||
[ :after_find, :proc ],
|
||||
[ :after_find, :object ],
|
||||
[ :after_find, :block ],
|
||||
[ :after_initialize, :string ],
|
||||
[ :after_initialize, :proc ],
|
||||
[ :after_initialize, :object ],
|
||||
[ :after_initialize, :block ],
|
||||
[ :before_validation, :string ],
|
||||
[ :before_validation, :proc ],
|
||||
[ :before_validation, :object ],
|
||||
[ :before_validation, :block ],
|
||||
[ :before_validation, :returning_false ]
|
||||
], david.history
|
||||
end
|
||||
|
||||
def test_inheritence_of_callbacks
|
||||
parent = ParentDeveloper.new
|
||||
assert !parent.after_save_called
|
||||
parent.save
|
||||
assert parent.after_save_called
|
||||
|
||||
child = ChildDeveloper.new
|
||||
assert !child.after_save_called
|
||||
child.save
|
||||
assert child.after_save_called
|
||||
end
|
||||
|
||||
end
|
||||
32
vendor/rails/activerecord/test/cases/class_inheritable_attributes_test.rb
vendored
Normal file
32
vendor/rails/activerecord/test/cases/class_inheritable_attributes_test.rb
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
require 'test/unit'
|
||||
require "cases/helper"
|
||||
require 'active_support/core_ext/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 < ActiveRecord::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
|
||||
17
vendor/rails/activerecord/test/cases/column_alias_test.rb
vendored
Normal file
17
vendor/rails/activerecord/test/cases/column_alias_test.rb
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
|
||||
class TestColumnAlias < ActiveRecord::TestCase
|
||||
fixtures :topics
|
||||
|
||||
QUERY = if 'Oracle' == ActiveRecord::Base.connection.adapter_name
|
||||
'SELECT id AS pk FROM topics WHERE ROWNUM < 2'
|
||||
else
|
||||
'SELECT id AS pk FROM topics'
|
||||
end
|
||||
|
||||
def test_column_alias
|
||||
records = Topic.connection.select_all(QUERY)
|
||||
assert_equal 'pk', records[0].keys[0]
|
||||
end
|
||||
end
|
||||
36
vendor/rails/activerecord/test/cases/column_definition_test.rb
vendored
Normal file
36
vendor/rails/activerecord/test/cases/column_definition_test.rb
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
require "cases/helper"
|
||||
|
||||
class ColumnDefinitionTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@adapter = ActiveRecord::ConnectionAdapters::AbstractAdapter.new(nil)
|
||||
def @adapter.native_database_types
|
||||
{:string => "varchar"}
|
||||
end
|
||||
end
|
||||
|
||||
# Avoid column definitions in create table statements like:
|
||||
# `title` varchar(255) DEFAULT NULL
|
||||
def test_should_not_include_default_clause_when_default_is_null
|
||||
column = ActiveRecord::ConnectionAdapters::Column.new("title", nil, "varchar(20)")
|
||||
column_def = ActiveRecord::ConnectionAdapters::ColumnDefinition.new(
|
||||
@adapter, column.name, "string",
|
||||
column.limit, column.precision, column.scale, column.default, column.null)
|
||||
assert_equal "title varchar(20)", column_def.to_sql
|
||||
end
|
||||
|
||||
def test_should_include_default_clause_when_default_is_present
|
||||
column = ActiveRecord::ConnectionAdapters::Column.new("title", "Hello", "varchar(20)")
|
||||
column_def = ActiveRecord::ConnectionAdapters::ColumnDefinition.new(
|
||||
@adapter, column.name, "string",
|
||||
column.limit, column.precision, column.scale, column.default, column.null)
|
||||
assert_equal %Q{title varchar(20) DEFAULT 'Hello'}, column_def.to_sql
|
||||
end
|
||||
|
||||
def test_should_specify_not_null_if_null_option_is_false
|
||||
column = ActiveRecord::ConnectionAdapters::Column.new("title", "Hello", "varchar(20)", false)
|
||||
column_def = ActiveRecord::ConnectionAdapters::ColumnDefinition.new(
|
||||
@adapter, column.name, "string",
|
||||
column.limit, column.precision, column.scale, column.default, column.null)
|
||||
assert_equal %Q{title varchar(20) DEFAULT 'Hello' NOT NULL}, column_def.to_sql
|
||||
end
|
||||
end
|
||||
8
vendor/rails/activerecord/test/cases/connection_test_firebird.rb
vendored
Normal file
8
vendor/rails/activerecord/test/cases/connection_test_firebird.rb
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
require "cases/helper"
|
||||
|
||||
class FirebirdConnectionTest < ActiveRecord::TestCase
|
||||
def test_charset_properly_set
|
||||
fb_conn = ActiveRecord::Base.connection.instance_variable_get(:@connection)
|
||||
assert_equal 'UTF8', fb_conn.database.character_set
|
||||
end
|
||||
end
|
||||
30
vendor/rails/activerecord/test/cases/connection_test_mysql.rb
vendored
Normal file
30
vendor/rails/activerecord/test/cases/connection_test_mysql.rb
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
require "cases/helper"
|
||||
|
||||
class MysqlConnectionTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
end
|
||||
|
||||
def test_no_automatic_reconnection_after_timeout
|
||||
assert @connection.active?
|
||||
@connection.update('set @@wait_timeout=1')
|
||||
sleep 2
|
||||
assert !@connection.active?
|
||||
end
|
||||
|
||||
def test_successful_reconnection_after_timeout_with_manual_reconnect
|
||||
assert @connection.active?
|
||||
@connection.update('set @@wait_timeout=1')
|
||||
sleep 2
|
||||
@connection.reconnect!
|
||||
assert @connection.active?
|
||||
end
|
||||
|
||||
def test_successful_reconnection_after_timeout_with_verify
|
||||
assert @connection.active?
|
||||
@connection.update('set @@wait_timeout=1')
|
||||
sleep 2
|
||||
@connection.verify!
|
||||
assert @connection.active?
|
||||
end
|
||||
end
|
||||
69
vendor/rails/activerecord/test/cases/copy_table_test_sqlite.rb
vendored
Normal file
69
vendor/rails/activerecord/test/cases/copy_table_test_sqlite.rb
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
require "cases/helper"
|
||||
|
||||
class CopyTableTest < ActiveRecord::TestCase
|
||||
fixtures :companies, :comments
|
||||
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
class << @connection
|
||||
public :copy_table, :table_structure, :indexes
|
||||
end
|
||||
end
|
||||
|
||||
def test_copy_table(from = 'companies', to = 'companies2', options = {})
|
||||
assert_nothing_raised {copy_table(from, to, options)}
|
||||
assert_equal row_count(from), row_count(to)
|
||||
|
||||
if block_given?
|
||||
yield from, to, options
|
||||
else
|
||||
assert_equal column_names(from), column_names(to)
|
||||
end
|
||||
|
||||
@connection.drop_table(to) rescue nil
|
||||
end
|
||||
|
||||
def test_copy_table_renaming_column
|
||||
test_copy_table('companies', 'companies2',
|
||||
:rename => {'client_of' => 'fan_of'}) do |from, to, options|
|
||||
expected = column_values(from, 'client_of')
|
||||
assert expected.any?, 'only nils in resultset; real values are needed'
|
||||
assert_equal expected, column_values(to, 'fan_of')
|
||||
end
|
||||
end
|
||||
|
||||
def test_copy_table_with_index
|
||||
test_copy_table('comments', 'comments_with_index') do
|
||||
@connection.add_index('comments_with_index', ['post_id', 'type'])
|
||||
test_copy_table('comments_with_index', 'comments_with_index2') do
|
||||
assert_equal table_indexes_without_name('comments_with_index'),
|
||||
table_indexes_without_name('comments_with_index2')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_copy_table_without_primary_key
|
||||
test_copy_table('developers_projects', 'programmers_projects')
|
||||
end
|
||||
|
||||
protected
|
||||
def copy_table(from, to, options = {})
|
||||
@connection.copy_table(from, to, {:temporary => true}.merge(options))
|
||||
end
|
||||
|
||||
def column_names(table)
|
||||
@connection.table_structure(table).map {|column| column['name']}
|
||||
end
|
||||
|
||||
def column_values(table, column)
|
||||
@connection.select_all("SELECT #{column} FROM #{table} ORDER BY id").map {|row| row[column]}
|
||||
end
|
||||
|
||||
def table_indexes_without_name(table)
|
||||
@connection.indexes('comments_with_index').delete(:name)
|
||||
end
|
||||
|
||||
def row_count(table)
|
||||
@connection.select_one("SELECT COUNT(*) AS count FROM #{table}")['count']
|
||||
end
|
||||
end
|
||||
12
vendor/rails/activerecord/test/cases/database_statements_test.rb
vendored
Normal file
12
vendor/rails/activerecord/test/cases/database_statements_test.rb
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
require "cases/helper"
|
||||
|
||||
class DatabaseStatementsTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
end
|
||||
|
||||
def test_insert_should_return_the_inserted_id
|
||||
id = @connection.insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)")
|
||||
assert_not_nil id
|
||||
end
|
||||
end
|
||||
203
vendor/rails/activerecord/test/cases/datatype_test_postgresql.rb
vendored
Normal file
203
vendor/rails/activerecord/test/cases/datatype_test_postgresql.rb
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
require "cases/helper"
|
||||
|
||||
class PostgresqlArray < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class PostgresqlMoney < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class PostgresqlNumber < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class PostgresqlTime < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class PostgresqlNetworkAddress < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class PostgresqlBitString < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class PostgresqlOid < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class PostgresqlDataTypeTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
|
||||
@connection.execute("INSERT INTO postgresql_arrays (commission_by_quarter, nicknames) VALUES ( '{35000,21000,18000,17000}', '{foo,bar,baz}' )")
|
||||
@first_array = PostgresqlArray.find(1)
|
||||
|
||||
@connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('567.89'::money)")
|
||||
@connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('-567.89'::money)")
|
||||
@first_money = PostgresqlMoney.find(1)
|
||||
@second_money = PostgresqlMoney.find(2)
|
||||
|
||||
@connection.execute("INSERT INTO postgresql_numbers (single, double) VALUES (123.456, 123456.789)")
|
||||
@first_number = PostgresqlNumber.find(1)
|
||||
|
||||
@connection.execute("INSERT INTO postgresql_times (time_interval) VALUES ('1 year 2 days ago')")
|
||||
@first_time = PostgresqlTime.find(1)
|
||||
|
||||
@connection.execute("INSERT INTO postgresql_network_addresses (cidr_address, inet_address, mac_address) VALUES('192.168.0/24', '172.16.1.254/32', '01:23:45:67:89:0a')")
|
||||
@first_network_address = PostgresqlNetworkAddress.find(1)
|
||||
|
||||
@connection.execute("INSERT INTO postgresql_bit_strings (bit_string, bit_string_varying) VALUES (B'00010101', X'15')")
|
||||
@first_bit_string = PostgresqlBitString.find(1)
|
||||
|
||||
@connection.execute("INSERT INTO postgresql_oids (obj_id) VALUES (1234)")
|
||||
@first_oid = PostgresqlOid.find(1)
|
||||
end
|
||||
|
||||
def test_data_type_of_array_types
|
||||
assert_equal :string, @first_array.column_for_attribute(:commission_by_quarter).type
|
||||
assert_equal :string, @first_array.column_for_attribute(:nicknames).type
|
||||
end
|
||||
|
||||
def test_data_type_of_money_types
|
||||
assert_equal :decimal, @first_money.column_for_attribute(:wealth).type
|
||||
end
|
||||
|
||||
def test_data_type_of_number_types
|
||||
assert_equal :float, @first_number.column_for_attribute(:single).type
|
||||
assert_equal :float, @first_number.column_for_attribute(:double).type
|
||||
end
|
||||
|
||||
def test_data_type_of_time_types
|
||||
assert_equal :string, @first_time.column_for_attribute(:time_interval).type
|
||||
end
|
||||
|
||||
def test_data_type_of_network_address_types
|
||||
assert_equal :string, @first_network_address.column_for_attribute(:cidr_address).type
|
||||
assert_equal :string, @first_network_address.column_for_attribute(:inet_address).type
|
||||
assert_equal :string, @first_network_address.column_for_attribute(:mac_address).type
|
||||
end
|
||||
|
||||
def test_data_type_of_bit_string_types
|
||||
assert_equal :string, @first_bit_string.column_for_attribute(:bit_string).type
|
||||
assert_equal :string, @first_bit_string.column_for_attribute(:bit_string_varying).type
|
||||
end
|
||||
|
||||
def test_data_type_of_oid_types
|
||||
assert_equal :integer, @first_oid.column_for_attribute(:obj_id).type
|
||||
end
|
||||
|
||||
def test_array_values
|
||||
assert_equal '{35000,21000,18000,17000}', @first_array.commission_by_quarter
|
||||
assert_equal '{foo,bar,baz}', @first_array.nicknames
|
||||
end
|
||||
|
||||
def test_money_values
|
||||
assert_equal 567.89, @first_money.wealth
|
||||
assert_equal -567.89, @second_money.wealth
|
||||
end
|
||||
|
||||
def test_number_values
|
||||
assert_equal 123.456, @first_number.single
|
||||
assert_equal 123456.789, @first_number.double
|
||||
end
|
||||
|
||||
def test_time_values
|
||||
assert_equal '-1 years -2 days', @first_time.time_interval
|
||||
end
|
||||
|
||||
def test_network_address_values
|
||||
assert_equal '192.168.0.0/24', @first_network_address.cidr_address
|
||||
assert_equal '172.16.1.254', @first_network_address.inet_address
|
||||
assert_equal '01:23:45:67:89:0a', @first_network_address.mac_address
|
||||
end
|
||||
|
||||
def test_bit_string_values
|
||||
assert_equal '00010101', @first_bit_string.bit_string
|
||||
assert_equal '00010101', @first_bit_string.bit_string_varying
|
||||
end
|
||||
|
||||
def test_oid_values
|
||||
assert_equal 1234, @first_oid.obj_id
|
||||
end
|
||||
|
||||
def test_update_integer_array
|
||||
new_value = '{32800,95000,29350,17000}'
|
||||
assert @first_array.commission_by_quarter = new_value
|
||||
assert @first_array.save
|
||||
assert @first_array.reload
|
||||
assert_equal @first_array.commission_by_quarter, new_value
|
||||
assert @first_array.commission_by_quarter = new_value
|
||||
assert @first_array.save
|
||||
assert @first_array.reload
|
||||
assert_equal @first_array.commission_by_quarter, new_value
|
||||
end
|
||||
|
||||
def test_update_text_array
|
||||
new_value = '{robby,robert,rob,robbie}'
|
||||
assert @first_array.nicknames = new_value
|
||||
assert @first_array.save
|
||||
assert @first_array.reload
|
||||
assert_equal @first_array.nicknames, new_value
|
||||
assert @first_array.nicknames = new_value
|
||||
assert @first_array.save
|
||||
assert @first_array.reload
|
||||
assert_equal @first_array.nicknames, new_value
|
||||
end
|
||||
|
||||
def test_update_money
|
||||
new_value = BigDecimal.new('123.45')
|
||||
assert @first_money.wealth = new_value
|
||||
assert @first_money.save
|
||||
assert @first_money.reload
|
||||
assert_equal new_value, @first_money.wealth
|
||||
end
|
||||
|
||||
def test_update_number
|
||||
new_single = 789.012
|
||||
new_double = 789012.345
|
||||
assert @first_number.single = new_single
|
||||
assert @first_number.double = new_double
|
||||
assert @first_number.save
|
||||
assert @first_number.reload
|
||||
assert_equal @first_number.single, new_single
|
||||
assert_equal @first_number.double, new_double
|
||||
end
|
||||
|
||||
def test_update_time
|
||||
assert @first_time.time_interval = '2 years 3 minutes'
|
||||
assert @first_time.save
|
||||
assert @first_time.reload
|
||||
assert_equal @first_time.time_interval, '2 years 00:03:00'
|
||||
end
|
||||
|
||||
def test_update_network_address
|
||||
new_cidr_address = '10.1.2.3/32'
|
||||
new_inet_address = '10.0.0.0/8'
|
||||
new_mac_address = 'bc:de:f0:12:34:56'
|
||||
assert @first_network_address.cidr_address = new_cidr_address
|
||||
assert @first_network_address.inet_address = new_inet_address
|
||||
assert @first_network_address.mac_address = new_mac_address
|
||||
assert @first_network_address.save
|
||||
assert @first_network_address.reload
|
||||
assert_equal @first_network_address.cidr_address, new_cidr_address
|
||||
assert_equal @first_network_address.inet_address, new_inet_address
|
||||
assert_equal @first_network_address.mac_address, new_mac_address
|
||||
end
|
||||
|
||||
def test_update_bit_string
|
||||
new_bit_string = '11111111'
|
||||
new_bit_string_varying = 'FF'
|
||||
assert @first_bit_string.bit_string = new_bit_string
|
||||
assert @first_bit_string.bit_string_varying = new_bit_string_varying
|
||||
assert @first_bit_string.save
|
||||
assert @first_bit_string.reload
|
||||
assert_equal @first_bit_string.bit_string, new_bit_string
|
||||
assert_equal @first_bit_string.bit_string, @first_bit_string.bit_string_varying
|
||||
end
|
||||
|
||||
def test_update_oid
|
||||
new_value = 567890
|
||||
assert @first_oid.obj_id = new_value
|
||||
assert @first_oid.save
|
||||
assert @first_oid.reload
|
||||
assert_equal @first_oid.obj_id, new_value
|
||||
end
|
||||
end
|
||||
37
vendor/rails/activerecord/test/cases/date_time_test.rb
vendored
Normal file
37
vendor/rails/activerecord/test/cases/date_time_test.rb
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/task'
|
||||
|
||||
class DateTimeTest < ActiveRecord::TestCase
|
||||
def test_saves_both_date_and_time
|
||||
time_values = [1807, 2, 10, 15, 30, 45]
|
||||
now = DateTime.civil(*time_values)
|
||||
|
||||
task = Task.new
|
||||
task.starting = now
|
||||
task.save!
|
||||
|
||||
# check against Time.local_time, since some platforms will return a Time instead of a DateTime
|
||||
assert_equal Time.local_time(*time_values), Task.find(task.id).starting
|
||||
end
|
||||
|
||||
def test_assign_empty_date_time
|
||||
task = Task.new
|
||||
task.starting = ''
|
||||
task.ending = nil
|
||||
assert_nil task.starting
|
||||
assert_nil task.ending
|
||||
end
|
||||
|
||||
def test_assign_empty_date
|
||||
topic = Topic.new
|
||||
topic.last_read = ''
|
||||
assert_nil topic.last_read
|
||||
end
|
||||
|
||||
def test_assign_empty_time
|
||||
topic = Topic.new
|
||||
topic.bonus_time = ''
|
||||
assert_nil topic.bonus_time
|
||||
end
|
||||
end
|
||||
16
vendor/rails/activerecord/test/cases/default_test_firebird.rb
vendored
Normal file
16
vendor/rails/activerecord/test/cases/default_test_firebird.rb
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
require "cases/helper"
|
||||
require 'models/default'
|
||||
|
||||
class DefaultTest < ActiveRecord::TestCase
|
||||
def test_default_timestamp
|
||||
default = Default.new
|
||||
assert_instance_of(Time, default.default_timestamp)
|
||||
assert_equal(:datetime, default.column_for_attribute(:default_timestamp).type)
|
||||
|
||||
# Variance should be small; increase if required -- e.g., if test db is on
|
||||
# remote host and clocks aren't synchronized.
|
||||
t1 = Time.new
|
||||
accepted_variance = 1.0
|
||||
assert_in_delta(t1.to_f, default.default_timestamp.to_f, accepted_variance)
|
||||
end
|
||||
end
|
||||
100
vendor/rails/activerecord/test/cases/defaults_test.rb
vendored
Normal file
100
vendor/rails/activerecord/test/cases/defaults_test.rb
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
require "cases/helper"
|
||||
require 'models/default'
|
||||
require 'models/entrant'
|
||||
|
||||
class DefaultTest < ActiveRecord::TestCase
|
||||
def test_nil_defaults_for_not_null_columns
|
||||
column_defaults =
|
||||
if current_adapter?(:MysqlAdapter) && (Mysql.client_version < 50051 || (50100..50122).include?(Mysql.client_version))
|
||||
{ 'id' => nil, 'name' => '', 'course_id' => nil }
|
||||
else
|
||||
{ 'id' => nil, 'name' => nil, 'course_id' => nil }
|
||||
end
|
||||
|
||||
column_defaults.each do |name, default|
|
||||
column = Entrant.columns_hash[name]
|
||||
assert !column.null, "#{name} column should be NOT NULL"
|
||||
assert_equal default, column.default, "#{name} column should be DEFAULT #{default.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:MysqlAdapter)
|
||||
|
||||
#MySQL 5 and higher is quirky with not null text/blob columns.
|
||||
#With MySQL Text/blob columns cannot have defaults. If the column is not null MySQL will report that the column has a null default
|
||||
#but it behaves as though the column had a default of ''
|
||||
def test_mysql_text_not_null_defaults
|
||||
klass = Class.new(ActiveRecord::Base)
|
||||
klass.table_name = 'test_mysql_text_not_null_defaults'
|
||||
klass.connection.create_table klass.table_name do |t|
|
||||
t.column :non_null_text, :text, :null => false
|
||||
t.column :non_null_blob, :blob, :null => false
|
||||
t.column :null_text, :text, :null => true
|
||||
t.column :null_blob, :blob, :null => true
|
||||
end
|
||||
assert_equal '', klass.columns_hash['non_null_blob'].default
|
||||
assert_equal '', klass.columns_hash['non_null_text'].default
|
||||
|
||||
assert_equal nil, klass.columns_hash['null_blob'].default
|
||||
assert_equal nil, klass.columns_hash['null_text'].default
|
||||
|
||||
assert_nothing_raised do
|
||||
instance = klass.create!
|
||||
assert_equal '', instance.non_null_text
|
||||
assert_equal '', instance.non_null_blob
|
||||
assert_nil instance.null_text
|
||||
assert_nil instance.null_blob
|
||||
end
|
||||
ensure
|
||||
klass.connection.drop_table(klass.table_name) rescue nil
|
||||
end
|
||||
|
||||
|
||||
# MySQL uses an implicit default 0 rather than NULL unless in strict mode.
|
||||
# We use an implicit NULL so schema.rb is compatible with other databases.
|
||||
def test_mysql_integer_not_null_defaults
|
||||
klass = Class.new(ActiveRecord::Base)
|
||||
klass.table_name = 'test_integer_not_null_default_zero'
|
||||
klass.connection.create_table klass.table_name do |t|
|
||||
t.column :zero, :integer, :null => false, :default => 0
|
||||
t.column :omit, :integer, :null => false
|
||||
end
|
||||
|
||||
assert_equal 0, klass.columns_hash['zero'].default
|
||||
assert !klass.columns_hash['zero'].null
|
||||
# 0 in MySQL 4, nil in 5.
|
||||
assert [0, nil].include?(klass.columns_hash['omit'].default)
|
||||
assert !klass.columns_hash['omit'].null
|
||||
|
||||
assert_raise(ActiveRecord::StatementInvalid) { klass.create! }
|
||||
|
||||
assert_nothing_raised do
|
||||
instance = klass.create!(:omit => 1)
|
||||
assert_equal 0, instance.zero
|
||||
assert_equal 1, instance.omit
|
||||
end
|
||||
ensure
|
||||
klass.connection.drop_table(klass.table_name) rescue nil
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter, :FirebirdAdapter, :OpenBaseAdapter, :OracleAdapter)
|
||||
def test_default_integers
|
||||
default = Default.new
|
||||
assert_instance_of Fixnum, default.positive_integer
|
||||
assert_equal 1, default.positive_integer
|
||||
assert_instance_of Fixnum, default.negative_integer
|
||||
assert_equal -1, default.negative_integer
|
||||
assert_instance_of BigDecimal, default.decimal_number
|
||||
assert_equal BigDecimal.new("2.78"), default.decimal_number
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter)
|
||||
def test_multiline_default_text
|
||||
# older postgres versions represent the default with escapes ("\\012" for a newline)
|
||||
assert ( "--- []\n\n" == Default.columns_hash['multiline_default'].default ||
|
||||
"--- []\\012\\012" == Default.columns_hash['multiline_default'].default)
|
||||
end
|
||||
end
|
||||
end
|
||||
30
vendor/rails/activerecord/test/cases/deprecated_finder_test.rb
vendored
Normal file
30
vendor/rails/activerecord/test/cases/deprecated_finder_test.rb
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
require "cases/helper"
|
||||
require 'models/entrant'
|
||||
|
||||
class DeprecatedFinderTest < ActiveRecord::TestCase
|
||||
fixtures :entrants
|
||||
|
||||
def test_deprecated_find_all_was_removed
|
||||
assert_raise(NoMethodError) { Entrant.find_all }
|
||||
end
|
||||
|
||||
def test_deprecated_find_first_was_removed
|
||||
assert_raise(NoMethodError) { Entrant.find_first }
|
||||
end
|
||||
|
||||
def test_deprecated_find_on_conditions_was_removed
|
||||
assert_raise(NoMethodError) { Entrant.find_on_conditions }
|
||||
end
|
||||
|
||||
def test_count
|
||||
assert_equal(0, Entrant.count(:conditions => "id > 3"))
|
||||
assert_equal(1, Entrant.count(:conditions => ["id > ?", 2]))
|
||||
assert_equal(2, Entrant.count(:conditions => ["id > ?", 1]))
|
||||
end
|
||||
|
||||
def test_count_by_sql
|
||||
assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
|
||||
assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
|
||||
assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
|
||||
end
|
||||
end
|
||||
270
vendor/rails/activerecord/test/cases/dirty_test.rb
vendored
Normal file
270
vendor/rails/activerecord/test/cases/dirty_test.rb
vendored
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
require 'cases/helper'
|
||||
require 'models/topic' # For booleans
|
||||
require 'models/pirate' # For timestamps
|
||||
require 'models/parrot'
|
||||
require 'models/person' # For optimistic locking
|
||||
|
||||
class Pirate # Just reopening it, not defining it
|
||||
attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected
|
||||
attr_accessor :changes_detected_in_after_update # Actual changes
|
||||
|
||||
after_update :check_changes
|
||||
|
||||
private
|
||||
# after_save/update in sweepers, observers, and the model itself
|
||||
# can end up checking dirty status and acting on the results
|
||||
def check_changes
|
||||
if self.changed?
|
||||
self.detected_changes_in_after_update = true
|
||||
self.changes_detected_in_after_update = self.changes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class DirtyTest < ActiveRecord::TestCase
|
||||
def test_attribute_changes
|
||||
# New record - no changes.
|
||||
pirate = Pirate.new
|
||||
assert !pirate.catchphrase_changed?
|
||||
assert_nil pirate.catchphrase_change
|
||||
|
||||
# Change catchphrase.
|
||||
pirate.catchphrase = 'arrr'
|
||||
assert pirate.catchphrase_changed?
|
||||
assert_nil pirate.catchphrase_was
|
||||
assert_equal [nil, 'arrr'], pirate.catchphrase_change
|
||||
|
||||
# Saved - no changes.
|
||||
pirate.save!
|
||||
assert !pirate.catchphrase_changed?
|
||||
assert_nil pirate.catchphrase_change
|
||||
|
||||
# Same value - no changes.
|
||||
pirate.catchphrase = 'arrr'
|
||||
assert !pirate.catchphrase_changed?
|
||||
assert_nil pirate.catchphrase_change
|
||||
end
|
||||
|
||||
def test_aliased_attribute_changes
|
||||
# the actual attribute here is name, title is an
|
||||
# alias setup via alias_attribute
|
||||
parrot = Parrot.new
|
||||
assert !parrot.title_changed?
|
||||
assert_nil parrot.title_change
|
||||
|
||||
parrot.name = 'Sam'
|
||||
assert parrot.title_changed?
|
||||
assert_nil parrot.title_was
|
||||
assert_equal parrot.name_change, parrot.title_change
|
||||
end
|
||||
|
||||
def test_nullable_integer_not_marked_as_changed_if_new_value_is_blank
|
||||
pirate = Pirate.new
|
||||
|
||||
["", nil].each do |value|
|
||||
pirate.parrot_id = value
|
||||
assert !pirate.parrot_id_changed?
|
||||
assert_nil pirate.parrot_id_change
|
||||
end
|
||||
end
|
||||
|
||||
def test_zero_to_blank_marked_as_changed
|
||||
pirate = Pirate.new
|
||||
pirate.catchphrase = "Yarrrr, me hearties"
|
||||
pirate.parrot_id = 1
|
||||
pirate.save
|
||||
|
||||
# check the change from 1 to ''
|
||||
pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
|
||||
pirate.parrot_id = ''
|
||||
assert pirate.parrot_id_changed?
|
||||
assert_equal([1, nil], pirate.parrot_id_change)
|
||||
pirate.save
|
||||
|
||||
# check the change from nil to 0
|
||||
pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
|
||||
pirate.parrot_id = 0
|
||||
assert pirate.parrot_id_changed?
|
||||
assert_equal([nil, 0], pirate.parrot_id_change)
|
||||
pirate.save
|
||||
|
||||
# check the change from 0 to ''
|
||||
pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
|
||||
pirate.parrot_id = ''
|
||||
assert pirate.parrot_id_changed?
|
||||
assert_equal([0, nil], pirate.parrot_id_change)
|
||||
end
|
||||
|
||||
def test_object_should_be_changed_if_any_attribute_is_changed
|
||||
pirate = Pirate.new
|
||||
assert !pirate.changed?
|
||||
assert_equal [], pirate.changed
|
||||
assert_equal Hash.new, pirate.changes
|
||||
|
||||
pirate.catchphrase = 'arrr'
|
||||
assert pirate.changed?
|
||||
assert_nil pirate.catchphrase_was
|
||||
assert_equal %w(catchphrase), pirate.changed
|
||||
assert_equal({'catchphrase' => [nil, 'arrr']}, pirate.changes)
|
||||
|
||||
pirate.save
|
||||
assert !pirate.changed?
|
||||
assert_equal [], pirate.changed
|
||||
assert_equal Hash.new, pirate.changes
|
||||
end
|
||||
|
||||
def test_attribute_will_change!
|
||||
pirate = Pirate.create!(:catchphrase => 'arr')
|
||||
|
||||
pirate.catchphrase << ' matey'
|
||||
assert !pirate.catchphrase_changed?
|
||||
|
||||
assert pirate.catchphrase_will_change!
|
||||
assert pirate.catchphrase_changed?
|
||||
assert_equal ['arr matey', 'arr matey'], pirate.catchphrase_change
|
||||
|
||||
pirate.catchphrase << '!'
|
||||
assert pirate.catchphrase_changed?
|
||||
assert_equal ['arr matey', 'arr matey!'], pirate.catchphrase_change
|
||||
end
|
||||
|
||||
def test_association_assignment_changes_foreign_key
|
||||
pirate = Pirate.create!(:catchphrase => 'jarl')
|
||||
pirate.parrot = Parrot.create!
|
||||
assert pirate.changed?
|
||||
assert_equal %w(parrot_id), pirate.changed
|
||||
end
|
||||
|
||||
def test_attribute_should_be_compared_with_type_cast
|
||||
topic = Topic.new
|
||||
assert topic.approved?
|
||||
assert !topic.approved_changed?
|
||||
|
||||
# Coming from web form.
|
||||
params = {:topic => {:approved => 1}}
|
||||
# In the controller.
|
||||
topic.attributes = params[:topic]
|
||||
assert topic.approved?
|
||||
assert !topic.approved_changed?
|
||||
end
|
||||
|
||||
def test_partial_update
|
||||
pirate = Pirate.new(:catchphrase => 'foo')
|
||||
old_updated_on = 1.hour.ago.beginning_of_day
|
||||
|
||||
with_partial_updates Pirate, false do
|
||||
assert_queries(2) { 2.times { pirate.save! } }
|
||||
Pirate.update_all({ :updated_on => old_updated_on }, :id => pirate.id)
|
||||
end
|
||||
|
||||
with_partial_updates Pirate, true do
|
||||
assert_queries(0) { 2.times { pirate.save! } }
|
||||
assert_equal old_updated_on, pirate.reload.updated_on
|
||||
|
||||
assert_queries(1) { pirate.catchphrase = 'bar'; pirate.save! }
|
||||
assert_not_equal old_updated_on, pirate.reload.updated_on
|
||||
end
|
||||
end
|
||||
|
||||
def test_partial_update_with_optimistic_locking
|
||||
person = Person.new(:first_name => 'foo')
|
||||
old_lock_version = 1
|
||||
|
||||
with_partial_updates Person, false do
|
||||
assert_queries(2) { 2.times { person.save! } }
|
||||
Person.update_all({ :first_name => 'baz' }, :id => person.id)
|
||||
end
|
||||
|
||||
with_partial_updates Person, true do
|
||||
assert_queries(0) { 2.times { person.save! } }
|
||||
assert_equal old_lock_version, person.reload.lock_version
|
||||
|
||||
assert_queries(1) { person.first_name = 'bar'; person.save! }
|
||||
assert_not_equal old_lock_version, person.reload.lock_version
|
||||
end
|
||||
end
|
||||
|
||||
def test_changed_attributes_should_be_preserved_if_save_failure
|
||||
pirate = Pirate.new
|
||||
pirate.parrot_id = 1
|
||||
assert !pirate.save
|
||||
check_pirate_after_save_failure(pirate)
|
||||
|
||||
pirate = Pirate.new
|
||||
pirate.parrot_id = 1
|
||||
assert_raises(ActiveRecord::RecordInvalid) { pirate.save! }
|
||||
check_pirate_after_save_failure(pirate)
|
||||
end
|
||||
|
||||
def test_reload_should_clear_changed_attributes
|
||||
pirate = Pirate.create!(:catchphrase => "shiver me timbers")
|
||||
pirate.catchphrase = "*hic*"
|
||||
assert pirate.changed?
|
||||
pirate.reload
|
||||
assert !pirate.changed?
|
||||
end
|
||||
|
||||
def test_reverted_changes_are_not_dirty
|
||||
phrase = "shiver me timbers"
|
||||
pirate = Pirate.create!(:catchphrase => phrase)
|
||||
pirate.catchphrase = "*hic*"
|
||||
assert pirate.changed?
|
||||
pirate.catchphrase = phrase
|
||||
assert !pirate.changed?
|
||||
end
|
||||
|
||||
def test_reverted_changes_are_not_dirty_after_multiple_changes
|
||||
phrase = "shiver me timbers"
|
||||
pirate = Pirate.create!(:catchphrase => phrase)
|
||||
10.times do |i|
|
||||
pirate.catchphrase = "*hic*" * i
|
||||
assert pirate.changed?
|
||||
end
|
||||
assert pirate.changed?
|
||||
pirate.catchphrase = phrase
|
||||
assert !pirate.changed?
|
||||
end
|
||||
|
||||
|
||||
def test_reverted_changes_are_not_dirty_going_from_nil_to_value_and_back
|
||||
pirate = Pirate.create!(:catchphrase => "Yar!")
|
||||
|
||||
pirate.parrot_id = 1
|
||||
assert pirate.changed?
|
||||
assert pirate.parrot_id_changed?
|
||||
assert !pirate.catchphrase_changed?
|
||||
|
||||
pirate.parrot_id = nil
|
||||
assert !pirate.changed?
|
||||
assert !pirate.parrot_id_changed?
|
||||
assert !pirate.catchphrase_changed?
|
||||
end
|
||||
|
||||
def test_save_should_store_serialized_attributes_even_with_partial_updates
|
||||
with_partial_updates(Topic) do
|
||||
topic = Topic.create!(:content => {:a => "a"})
|
||||
topic.content[:b] = "b"
|
||||
#assert topic.changed? # Known bug, will fail
|
||||
topic.save!
|
||||
assert_equal "b", topic.content[:b]
|
||||
topic.reload
|
||||
assert_equal "b", topic.content[:b]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def with_partial_updates(klass, on = true)
|
||||
old = klass.partial_updates?
|
||||
klass.partial_updates = on
|
||||
yield
|
||||
ensure
|
||||
klass.partial_updates = old
|
||||
end
|
||||
|
||||
def check_pirate_after_save_failure(pirate)
|
||||
assert pirate.changed?
|
||||
assert pirate.parrot_id_changed?
|
||||
assert_equal %w(parrot_id), pirate.changed
|
||||
assert_nil pirate.parrot_id_was
|
||||
end
|
||||
end
|
||||
76
vendor/rails/activerecord/test/cases/finder_respond_to_test.rb
vendored
Normal file
76
vendor/rails/activerecord/test/cases/finder_respond_to_test.rb
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
|
||||
class FinderRespondToTest < ActiveRecord::TestCase
|
||||
|
||||
fixtures :topics
|
||||
|
||||
def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method
|
||||
class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { }
|
||||
assert Topic.respond_to?(:method_added_for_finder_respond_to_test)
|
||||
ensure
|
||||
class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test)
|
||||
end
|
||||
|
||||
def test_should_preserve_normal_respond_to_behaviour_and_respond_to_standard_object_method
|
||||
assert Topic.respond_to?(:to_s)
|
||||
end
|
||||
|
||||
def test_should_respond_to_find_by_one_attribute_before_caching
|
||||
ensure_topic_method_is_not_cached(:find_by_title)
|
||||
assert Topic.respond_to?(:find_by_title)
|
||||
end
|
||||
|
||||
def test_should_respond_to_find_all_by_one_attribute
|
||||
ensure_topic_method_is_not_cached(:find_all_by_title)
|
||||
assert Topic.respond_to?(:find_all_by_title)
|
||||
end
|
||||
|
||||
def test_should_respond_to_find_all_by_two_attributes
|
||||
ensure_topic_method_is_not_cached(:find_all_by_title_and_author_name)
|
||||
assert Topic.respond_to?(:find_all_by_title_and_author_name)
|
||||
end
|
||||
|
||||
def test_should_respond_to_find_by_two_attributes
|
||||
ensure_topic_method_is_not_cached(:find_by_title_and_author_name)
|
||||
assert Topic.respond_to?(:find_by_title_and_author_name)
|
||||
end
|
||||
|
||||
def test_should_respond_to_find_or_initialize_from_one_attribute
|
||||
ensure_topic_method_is_not_cached(:find_or_initialize_by_title)
|
||||
assert Topic.respond_to?(:find_or_initialize_by_title)
|
||||
end
|
||||
|
||||
def test_should_respond_to_find_or_initialize_from_two_attributes
|
||||
ensure_topic_method_is_not_cached(:find_or_initialize_by_title_and_author_name)
|
||||
assert Topic.respond_to?(:find_or_initialize_by_title_and_author_name)
|
||||
end
|
||||
|
||||
def test_should_respond_to_find_or_create_from_one_attribute
|
||||
ensure_topic_method_is_not_cached(:find_or_create_by_title)
|
||||
assert Topic.respond_to?(:find_or_create_by_title)
|
||||
end
|
||||
|
||||
def test_should_respond_to_find_or_create_from_two_attributes
|
||||
ensure_topic_method_is_not_cached(:find_or_create_by_title_and_author_name)
|
||||
assert Topic.respond_to?(:find_or_create_by_title_and_author_name)
|
||||
end
|
||||
|
||||
def test_should_not_respond_to_find_by_one_missing_attribute
|
||||
assert !Topic.respond_to?(:find_by_undertitle)
|
||||
end
|
||||
|
||||
def test_should_not_respond_to_find_by_invalid_method_syntax
|
||||
assert !Topic.respond_to?(:fail_to_find_by_title)
|
||||
assert !Topic.respond_to?(:find_by_title?)
|
||||
assert !Topic.respond_to?(:fail_to_find_or_create_by_title)
|
||||
assert !Topic.respond_to?(:find_or_create_by_title?)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_topic_method_is_not_cached(method_id)
|
||||
class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.any? { |m| m.to_s == method_id.to_s }
|
||||
end
|
||||
|
||||
end
|
||||
1048
vendor/rails/activerecord/test/cases/finder_test.rb
vendored
Normal file
1048
vendor/rails/activerecord/test/cases/finder_test.rb
vendored
Normal file
File diff suppressed because it is too large
Load diff
655
vendor/rails/activerecord/test/cases/fixtures_test.rb
vendored
Normal file
655
vendor/rails/activerecord/test/cases/fixtures_test.rb
vendored
Normal file
|
|
@ -0,0 +1,655 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/binary'
|
||||
require 'models/topic'
|
||||
require 'models/computer'
|
||||
require 'models/developer'
|
||||
require 'models/company'
|
||||
require 'models/task'
|
||||
require 'models/reply'
|
||||
require 'models/joke'
|
||||
require 'models/course'
|
||||
require 'models/category'
|
||||
require 'models/parrot'
|
||||
require 'models/pirate'
|
||||
require 'models/treasure'
|
||||
require 'models/matey'
|
||||
require 'models/ship'
|
||||
require 'models/book'
|
||||
|
||||
class FixturesTest < ActiveRecord::TestCase
|
||||
self.use_instantiated_fixtures = true
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
fixtures :topics, :developers, :accounts, :tasks, :categories, :funny_jokes, :binaries
|
||||
|
||||
FIXTURES = %w( accounts binaries companies customers
|
||||
developers developers_projects entrants
|
||||
movies projects subscribers topics tasks )
|
||||
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")
|
||||
first_row = ActiveRecord::Base.connection.select_one("SELECT * FROM topics WHERE author_name = 'David'")
|
||||
assert_equal("The First Topic", first_row["title"])
|
||||
|
||||
second_row = ActiveRecord::Base.connection.select_one("SELECT * FROM topics WHERE author_name = 'Mary'")
|
||||
assert_nil(second_row["author_email_address"])
|
||||
end
|
||||
|
||||
if ActiveRecord::Base.connection.supports_migrations?
|
||||
def test_inserts_with_pre_and_suffix
|
||||
# Reset cache to make finds on the new table work
|
||||
Fixtures.reset_cache
|
||||
|
||||
ActiveRecord::Base.connection.create_table :prefix_topics_suffix do |t|
|
||||
t.column :title, :string
|
||||
t.column :author_name, :string
|
||||
t.column :author_email_address, :string
|
||||
t.column :written_on, :datetime
|
||||
t.column :bonus_time, :time
|
||||
t.column :last_read, :date
|
||||
t.column :content, :string
|
||||
t.column :approved, :boolean, :default => true
|
||||
t.column :replies_count, :integer, :default => 0
|
||||
t.column :parent_id, :integer
|
||||
t.column :type, :string, :limit => 50
|
||||
end
|
||||
|
||||
# Store existing prefix/suffix
|
||||
old_prefix = ActiveRecord::Base.table_name_prefix
|
||||
old_suffix = ActiveRecord::Base.table_name_suffix
|
||||
|
||||
# Set a prefix/suffix we can test against
|
||||
ActiveRecord::Base.table_name_prefix = 'prefix_'
|
||||
ActiveRecord::Base.table_name_suffix = '_suffix'
|
||||
|
||||
topics = create_fixtures("topics")
|
||||
|
||||
first_row = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'David'")
|
||||
assert_equal("The First Topic", first_row["title"])
|
||||
|
||||
second_row = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'Mary'")
|
||||
assert_nil(second_row["author_email_address"])
|
||||
|
||||
# This checks for a caching problem which causes a bug in the fixtures
|
||||
# class-level configuration helper.
|
||||
assert_not_nil topics, "Fixture data inserted, but fixture objects not returned from create"
|
||||
ensure
|
||||
# Restore prefix/suffix to its previous values
|
||||
ActiveRecord::Base.table_name_prefix = old_prefix
|
||||
ActiveRecord::Base.table_name_suffix = old_suffix
|
||||
|
||||
ActiveRecord::Base.connection.drop_table :prefix_topics_suffix rescue nil
|
||||
end
|
||||
end
|
||||
|
||||
def test_insert_with_datetime
|
||||
topics = create_fixtures("tasks")
|
||||
first = Task.find(1)
|
||||
assert first
|
||||
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 4, @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 11, @developers.size
|
||||
assert_equal "fixture_5", @dev_5.name
|
||||
end
|
||||
|
||||
def test_empty_yaml_fixture
|
||||
assert_not_nil Fixtures.new( Account.connection, "accounts", 'Account', FIXTURES_ROOT + "/naked/yml/accounts")
|
||||
end
|
||||
|
||||
def test_empty_yaml_fixture_with_a_comment_in_it
|
||||
assert_not_nil Fixtures.new( Account.connection, "companies", 'Company', FIXTURES_ROOT + "/naked/yml/companies")
|
||||
end
|
||||
|
||||
def test_dirty_dirty_yaml_file
|
||||
assert_raises(Fixture::FormatError) do
|
||||
Fixtures.new( Account.connection, "courses", 'Course', FIXTURES_ROOT + "/naked/yml/courses")
|
||||
end
|
||||
end
|
||||
|
||||
def test_empty_csv_fixtures
|
||||
assert_not_nil Fixtures.new( Account.connection, "accounts", 'Account', FIXTURES_ROOT + "/naked/csv/accounts")
|
||||
end
|
||||
|
||||
def test_omap_fixtures
|
||||
assert_nothing_raised do
|
||||
fixtures = Fixtures.new(Account.connection, 'categories', 'Category', FIXTURES_ROOT + "/categories_ordered")
|
||||
|
||||
i = 0
|
||||
fixtures.each do |name, fixture|
|
||||
assert_equal "fixture_no_#{i}", name
|
||||
assert_equal "Category #{i}", fixture['name']
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_yml_file_in_subdirectory
|
||||
assert_equal(categories(:sub_special_1).name, "A special category in a subdir file")
|
||||
assert_equal(categories(:sub_special_1).class, SpecialCategory)
|
||||
end
|
||||
|
||||
def test_subsubdir_file_with_arbitrary_name
|
||||
assert_equal(categories(:sub_special_3).name, "A special category in an arbitrarily named subsubdir file")
|
||||
assert_equal(categories(:sub_special_3).class, SpecialCategory)
|
||||
end
|
||||
|
||||
def test_binary_in_fixtures
|
||||
assert_equal 1, @binaries.size
|
||||
data = File.read(ASSETS_ROOT + "/flowers.jpg")
|
||||
data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding)
|
||||
data.freeze
|
||||
assert_equal data, @flowers.data
|
||||
end
|
||||
end
|
||||
|
||||
if Account.connection.respond_to?(:reset_pk_sequence!)
|
||||
class FixturesResetPkSequenceTest < ActiveRecord::TestCase
|
||||
fixtures :accounts
|
||||
fixtures :companies
|
||||
|
||||
def setup
|
||||
@instances = [Account.new(:credit_limit => 50), Company.new(:name => 'RoR Consulting')]
|
||||
Fixtures.reset_cache # make sure tables get reinitialized
|
||||
end
|
||||
|
||||
def test_resets_to_min_pk_with_specified_pk_and_sequence
|
||||
@instances.each do |instance|
|
||||
model = instance.class
|
||||
model.delete_all
|
||||
model.connection.reset_pk_sequence!(model.table_name, model.primary_key, model.sequence_name)
|
||||
|
||||
instance.save!
|
||||
assert_equal 1, instance.id, "Sequence reset for #{model.table_name} failed."
|
||||
end
|
||||
end
|
||||
|
||||
def test_resets_to_min_pk_with_default_pk_and_sequence
|
||||
@instances.each do |instance|
|
||||
model = instance.class
|
||||
model.delete_all
|
||||
model.connection.reset_pk_sequence!(model.table_name)
|
||||
|
||||
instance.save!
|
||||
assert_equal 1, instance.id, "Sequence reset for #{model.table_name} failed."
|
||||
end
|
||||
end
|
||||
|
||||
def test_create_fixtures_resets_sequences_when_not_cached
|
||||
@instances.each do |instance|
|
||||
max_id = create_fixtures(instance.class.table_name).inject(0) do |max_id, (name, fixture)|
|
||||
fixture_id = fixture['id'].to_i
|
||||
fixture_id > max_id ? fixture_id : max_id
|
||||
end
|
||||
|
||||
# Clone the last fixture to check that it gets the next greatest id.
|
||||
instance.save!
|
||||
assert_equal max_id + 1, instance.id, "Sequence reset for #{instance.class.table_name} failed."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class FixturesWithoutInstantiationTest < ActiveRecord::TestCase
|
||||
self.use_instantiated_fixtures = false
|
||||
fixtures :topics, :developers, :accounts
|
||||
|
||||
def test_without_complete_instantiation
|
||||
assert_nil @first
|
||||
assert_nil @topics
|
||||
assert_nil @developers
|
||||
assert_nil @accounts
|
||||
end
|
||||
|
||||
def test_fixtures_from_root_yml_without_instantiation
|
||||
assert_nil @unknown
|
||||
end
|
||||
|
||||
def test_accessor_methods
|
||||
assert_equal "The First Topic", topics(:first).title
|
||||
assert_equal "Jamis", developers(:jamis).name
|
||||
assert_equal 50, accounts(:signals37).credit_limit
|
||||
end
|
||||
|
||||
def test_accessor_methods_with_multiple_args
|
||||
assert_equal 2, topics(:first, :second).size
|
||||
assert_raise(StandardError) { topics([:first, :second]) }
|
||||
end
|
||||
|
||||
uses_mocha 'reloading_fixtures_through_accessor_methods' do
|
||||
def test_reloading_fixtures_through_accessor_methods
|
||||
assert_equal "The First Topic", topics(:first).title
|
||||
@loaded_fixtures['topics']['first'].expects(:find).returns(stub(:title => "Fresh Topic!"))
|
||||
assert_equal "Fresh Topic!", topics(:first, true).title
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class FixturesWithoutInstanceInstantiationTest < ActiveRecord::TestCase
|
||||
self.use_instantiated_fixtures = true
|
||||
self.use_instantiated_fixtures = :no_instances
|
||||
|
||||
fixtures :topics, :developers, :accounts
|
||||
|
||||
def test_without_instance_instantiation
|
||||
assert_nil @first
|
||||
assert_not_nil @topics
|
||||
assert_not_nil @developers
|
||||
assert_not_nil @accounts
|
||||
end
|
||||
end
|
||||
|
||||
class TransactionalFixturesTest < ActiveRecord::TestCase
|
||||
self.use_instantiated_fixtures = true
|
||||
self.use_transactional_fixtures = true
|
||||
|
||||
fixtures :topics
|
||||
|
||||
def test_destroy
|
||||
assert_not_nil @first
|
||||
@first.destroy
|
||||
end
|
||||
|
||||
def test_destroy_just_kidding
|
||||
assert_not_nil @first
|
||||
end
|
||||
end
|
||||
|
||||
class MultipleFixturesTest < ActiveRecord::TestCase
|
||||
fixtures :topics
|
||||
fixtures :developers, :accounts
|
||||
|
||||
def test_fixture_table_names
|
||||
assert_equal %w(topics developers accounts), fixture_table_names
|
||||
end
|
||||
end
|
||||
|
||||
class SetupTest < ActiveRecord::TestCase
|
||||
# fixtures :topics
|
||||
|
||||
def setup
|
||||
@first = true
|
||||
end
|
||||
|
||||
def test_nothing
|
||||
end
|
||||
end
|
||||
|
||||
class SetupSubclassTest < SetupTest
|
||||
def setup
|
||||
super
|
||||
@second = true
|
||||
end
|
||||
|
||||
def test_subclassing_should_preserve_setups
|
||||
assert @first
|
||||
assert @second
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class OverlappingFixturesTest < ActiveRecord::TestCase
|
||||
fixtures :topics, :developers
|
||||
fixtures :developers, :accounts
|
||||
|
||||
def test_fixture_table_names
|
||||
assert_equal %w(topics developers accounts), fixture_table_names
|
||||
end
|
||||
end
|
||||
|
||||
class ForeignKeyFixturesTest < ActiveRecord::TestCase
|
||||
fixtures :fk_test_has_pk, :fk_test_has_fk
|
||||
|
||||
# if foreign keys are implemented and fixtures
|
||||
# are not deleted in reverse order then this test
|
||||
# case will raise StatementInvalid
|
||||
|
||||
def test_number1
|
||||
assert true
|
||||
end
|
||||
|
||||
def test_number2
|
||||
assert true
|
||||
end
|
||||
end
|
||||
|
||||
class CheckSetTableNameFixturesTest < ActiveRecord::TestCase
|
||||
set_fixture_class :funny_jokes => 'Joke'
|
||||
fixtures :funny_jokes
|
||||
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
|
||||
# and thus takes into account our set_fixture_class
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def test_table_method
|
||||
assert_kind_of Joke, funny_jokes(:a_joke)
|
||||
end
|
||||
end
|
||||
|
||||
class FixtureNameIsNotTableNameFixturesTest < ActiveRecord::TestCase
|
||||
set_fixture_class :items => Book
|
||||
fixtures :items
|
||||
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
|
||||
# and thus takes into account our set_fixture_class
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def test_named_accessor
|
||||
assert_kind_of Book, items(:dvd)
|
||||
end
|
||||
end
|
||||
|
||||
class FixtureNameIsNotTableNameMultipleFixturesTest < ActiveRecord::TestCase
|
||||
set_fixture_class :items => Book, :funny_jokes => Joke
|
||||
fixtures :items, :funny_jokes
|
||||
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
|
||||
# and thus takes into account our set_fixture_class
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def test_named_accessor_of_differently_named_fixture
|
||||
assert_kind_of Book, items(:dvd)
|
||||
end
|
||||
|
||||
def test_named_accessor_of_same_named_fixture
|
||||
assert_kind_of Joke, funny_jokes(:a_joke)
|
||||
end
|
||||
end
|
||||
|
||||
class CustomConnectionFixturesTest < ActiveRecord::TestCase
|
||||
set_fixture_class :courses => Course
|
||||
fixtures :courses
|
||||
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
|
||||
# and thus takes into account our set_fixture_class
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def test_connection
|
||||
assert_kind_of Course, courses(:ruby)
|
||||
assert_equal Course.connection, courses(:ruby).connection
|
||||
end
|
||||
end
|
||||
|
||||
class InvalidTableNameFixturesTest < ActiveRecord::TestCase
|
||||
fixtures :funny_jokes
|
||||
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
|
||||
# and thus takes into account our lack of set_fixture_class
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def test_raises_error
|
||||
assert_raises FixtureClassNotFound do
|
||||
funny_jokes(:a_joke)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class CheckEscapedYamlFixturesTest < ActiveRecord::TestCase
|
||||
set_fixture_class :funny_jokes => 'Joke'
|
||||
fixtures :funny_jokes
|
||||
# Set to false to blow away fixtures cache and ensure our fixtures are loaded
|
||||
# and thus takes into account our set_fixture_class
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def test_proper_escaped_fixture
|
||||
assert_equal "The \\n Aristocrats\nAte the candy\n", funny_jokes(:another_joke).name
|
||||
end
|
||||
end
|
||||
|
||||
class DevelopersProject; end
|
||||
class ManyToManyFixturesWithClassDefined < ActiveRecord::TestCase
|
||||
fixtures :developers_projects
|
||||
|
||||
def test_this_should_run_cleanly
|
||||
assert true
|
||||
end
|
||||
end
|
||||
|
||||
class FixturesBrokenRollbackTest < ActiveRecord::TestCase
|
||||
def blank_setup; end
|
||||
alias_method :ar_setup_fixtures, :setup_fixtures
|
||||
alias_method :setup_fixtures, :blank_setup
|
||||
alias_method :setup, :blank_setup
|
||||
|
||||
def blank_teardown; end
|
||||
alias_method :ar_teardown_fixtures, :teardown_fixtures
|
||||
alias_method :teardown_fixtures, :blank_teardown
|
||||
alias_method :teardown, :blank_teardown
|
||||
|
||||
def test_no_rollback_in_teardown_unless_transaction_active
|
||||
assert_equal 0, ActiveRecord::Base.connection.open_transactions
|
||||
assert_raise(RuntimeError) { ar_setup_fixtures }
|
||||
assert_equal 0, ActiveRecord::Base.connection.open_transactions
|
||||
assert_nothing_raised { ar_teardown_fixtures }
|
||||
assert_equal 0, ActiveRecord::Base.connection.open_transactions
|
||||
end
|
||||
|
||||
private
|
||||
def load_fixtures
|
||||
raise 'argh'
|
||||
end
|
||||
end
|
||||
|
||||
class LoadAllFixturesTest < ActiveRecord::TestCase
|
||||
self.fixture_path = FIXTURES_ROOT + "/all"
|
||||
fixtures :all
|
||||
|
||||
def test_all_there
|
||||
assert_equal %w(developers people tasks), fixture_table_names.sort
|
||||
end
|
||||
end
|
||||
|
||||
class FasterFixturesTest < ActiveRecord::TestCase
|
||||
fixtures :categories, :authors
|
||||
|
||||
def load_extra_fixture(name)
|
||||
fixture = create_fixtures(name)
|
||||
assert fixture.is_a?(Fixtures)
|
||||
@loaded_fixtures[fixture.table_name] = fixture
|
||||
end
|
||||
|
||||
def test_cache
|
||||
assert Fixtures.fixture_is_cached?(ActiveRecord::Base.connection, 'categories')
|
||||
assert Fixtures.fixture_is_cached?(ActiveRecord::Base.connection, 'authors')
|
||||
|
||||
assert_no_queries do
|
||||
create_fixtures('categories')
|
||||
create_fixtures('authors')
|
||||
end
|
||||
|
||||
load_extra_fixture('posts')
|
||||
assert Fixtures.fixture_is_cached?(ActiveRecord::Base.connection, 'posts')
|
||||
self.class.setup_fixture_accessors('posts')
|
||||
assert_equal 'Welcome to the weblog', posts(:welcome).title
|
||||
end
|
||||
end
|
||||
|
||||
class FoxyFixturesTest < ActiveRecord::TestCase
|
||||
fixtures :parrots, :parrots_pirates, :pirates, :treasures, :mateys, :ships, :computers, :developers
|
||||
|
||||
def test_identifies_strings
|
||||
assert_equal(Fixtures.identify("foo"), Fixtures.identify("foo"))
|
||||
assert_not_equal(Fixtures.identify("foo"), Fixtures.identify("FOO"))
|
||||
end
|
||||
|
||||
def test_identifies_symbols
|
||||
assert_equal(Fixtures.identify(:foo), Fixtures.identify(:foo))
|
||||
end
|
||||
|
||||
TIMESTAMP_COLUMNS = %w(created_at created_on updated_at updated_on)
|
||||
|
||||
def test_populates_timestamp_columns
|
||||
TIMESTAMP_COLUMNS.each do |property|
|
||||
assert_not_nil(parrots(:george).send(property), "should set #{property}")
|
||||
end
|
||||
end
|
||||
|
||||
def test_does_not_populate_timestamp_columns_if_model_has_set_record_timestamps_to_false
|
||||
TIMESTAMP_COLUMNS.each do |property|
|
||||
assert_nil(ships(:black_pearl).send(property), "should not set #{property}")
|
||||
end
|
||||
end
|
||||
|
||||
def test_populates_all_columns_with_the_same_time
|
||||
last = nil
|
||||
|
||||
TIMESTAMP_COLUMNS.each do |property|
|
||||
current = parrots(:george).send(property)
|
||||
last ||= current
|
||||
|
||||
assert_equal(last, current)
|
||||
last = current
|
||||
end
|
||||
end
|
||||
|
||||
def test_only_populates_columns_that_exist
|
||||
assert_not_nil(pirates(:blackbeard).created_on)
|
||||
assert_not_nil(pirates(:blackbeard).updated_on)
|
||||
end
|
||||
|
||||
def test_preserves_existing_fixture_data
|
||||
assert_equal(2.weeks.ago.to_date, pirates(:redbeard).created_on.to_date)
|
||||
assert_equal(2.weeks.ago.to_date, pirates(:redbeard).updated_on.to_date)
|
||||
end
|
||||
|
||||
def test_generates_unique_ids
|
||||
assert_not_nil(parrots(:george).id)
|
||||
assert_not_equal(parrots(:george).id, parrots(:louis).id)
|
||||
end
|
||||
|
||||
def test_automatically_sets_primary_key
|
||||
assert_not_nil(ships(:black_pearl))
|
||||
end
|
||||
|
||||
def test_preserves_existing_primary_key
|
||||
assert_equal(2, ships(:interceptor).id)
|
||||
end
|
||||
|
||||
def test_resolves_belongs_to_symbols
|
||||
assert_equal(parrots(:george), pirates(:blackbeard).parrot)
|
||||
end
|
||||
|
||||
def test_ignores_belongs_to_symbols_if_association_and_foreign_key_are_named_the_same
|
||||
assert_equal(developers(:david), computers(:workstation).developer)
|
||||
end
|
||||
|
||||
def test_supports_join_tables
|
||||
assert(pirates(:blackbeard).parrots.include?(parrots(:george)))
|
||||
assert(pirates(:blackbeard).parrots.include?(parrots(:louis)))
|
||||
assert(parrots(:george).pirates.include?(pirates(:blackbeard)))
|
||||
end
|
||||
|
||||
def test_supports_inline_habtm
|
||||
assert(parrots(:george).treasures.include?(treasures(:diamond)))
|
||||
assert(parrots(:george).treasures.include?(treasures(:sapphire)))
|
||||
assert(!parrots(:george).treasures.include?(treasures(:ruby)))
|
||||
end
|
||||
|
||||
def test_supports_inline_habtm_with_specified_id
|
||||
assert(parrots(:polly).treasures.include?(treasures(:ruby)))
|
||||
assert(parrots(:polly).treasures.include?(treasures(:sapphire)))
|
||||
assert(!parrots(:polly).treasures.include?(treasures(:diamond)))
|
||||
end
|
||||
|
||||
def test_supports_yaml_arrays
|
||||
assert(parrots(:louis).treasures.include?(treasures(:diamond)))
|
||||
assert(parrots(:louis).treasures.include?(treasures(:sapphire)))
|
||||
end
|
||||
|
||||
def test_strips_DEFAULTS_key
|
||||
assert_raise(StandardError) { parrots(:DEFAULTS) }
|
||||
|
||||
# this lets us do YAML defaults and not have an extra fixture entry
|
||||
%w(sapphire ruby).each { |t| assert(parrots(:davey).treasures.include?(treasures(t))) }
|
||||
end
|
||||
|
||||
def test_supports_label_interpolation
|
||||
assert_equal("frederick", parrots(:frederick).name)
|
||||
end
|
||||
|
||||
def test_supports_polymorphic_belongs_to
|
||||
assert_equal(pirates(:redbeard), treasures(:sapphire).looter)
|
||||
assert_equal(parrots(:louis), treasures(:ruby).looter)
|
||||
end
|
||||
|
||||
def test_only_generates_a_pk_if_necessary
|
||||
m = Matey.find(:first)
|
||||
m.pirate = pirates(:blackbeard)
|
||||
m.target = pirates(:redbeard)
|
||||
end
|
||||
|
||||
def test_supports_sti
|
||||
assert_kind_of DeadParrot, parrots(:polly)
|
||||
assert_equal pirates(:blackbeard), parrots(:polly).killer
|
||||
end
|
||||
end
|
||||
|
||||
class ActiveSupportSubclassWithFixturesTest < ActiveRecord::TestCase
|
||||
fixtures :parrots
|
||||
|
||||
# This seemingly useless assertion catches a bug that caused the fixtures
|
||||
# setup code call nil[]
|
||||
def test_foo
|
||||
assert_equal parrots(:louis), Parrot.find_by_name("King Louis")
|
||||
end
|
||||
end
|
||||
|
||||
class FixtureLoadingTest < ActiveRecord::TestCase
|
||||
uses_mocha 'reloading_fixtures_through_accessor_methods' do
|
||||
def test_logs_message_for_failed_dependency_load
|
||||
Test::Unit::TestCase.expects(:require_dependency).with(:does_not_exist).raises(LoadError)
|
||||
ActiveRecord::Base.logger.expects(:warn)
|
||||
Test::Unit::TestCase.try_to_load_dependency(:does_not_exist)
|
||||
end
|
||||
|
||||
def test_does_not_logs_message_for_successful_dependency_load
|
||||
Test::Unit::TestCase.expects(:require_dependency).with(:works_out_fine)
|
||||
ActiveRecord::Base.logger.expects(:warn).never
|
||||
Test::Unit::TestCase.try_to_load_dependency(:works_out_fine)
|
||||
end
|
||||
end
|
||||
end
|
||||
62
vendor/rails/activerecord/test/cases/helper.rb
vendored
Normal file
62
vendor/rails/activerecord/test/cases/helper.rb
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
$:.unshift(File.dirname(__FILE__) + '/../../lib')
|
||||
$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib')
|
||||
|
||||
require 'config'
|
||||
require 'test/unit'
|
||||
|
||||
require 'active_record'
|
||||
require 'active_record/fixtures'
|
||||
require 'active_record/test_case'
|
||||
require 'connection'
|
||||
|
||||
# Show backtraces for deprecated behavior for quicker cleanup.
|
||||
ActiveSupport::Deprecation.debug = true
|
||||
|
||||
# Quote "type" if it's a reserved word for the current connection.
|
||||
QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type')
|
||||
|
||||
def current_adapter?(*types)
|
||||
types.any? do |type|
|
||||
ActiveRecord::ConnectionAdapters.const_defined?(type) &&
|
||||
ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters.const_get(type))
|
||||
end
|
||||
end
|
||||
|
||||
def uses_mocha(description)
|
||||
require 'rubygems'
|
||||
require 'mocha'
|
||||
yield
|
||||
rescue LoadError
|
||||
$stderr.puts "Skipping #{description} tests. `gem install mocha` and try again."
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connection.class.class_eval do
|
||||
IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/]
|
||||
|
||||
def execute_with_query_record(sql, name = nil, &block)
|
||||
$queries_executed ||= []
|
||||
$queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r }
|
||||
execute_without_query_record(sql, name, &block)
|
||||
end
|
||||
|
||||
alias_method_chain :execute, :query_record
|
||||
end
|
||||
|
||||
# Make with_scope public for tests
|
||||
class << ActiveRecord::Base
|
||||
public :with_scope, :with_exclusive_scope
|
||||
end
|
||||
|
||||
unless ENV['FIXTURE_DEBUG']
|
||||
module Test #:nodoc:
|
||||
module Unit #:nodoc:
|
||||
class << TestCase #:nodoc:
|
||||
def try_to_load_dependency_with_silence(*args)
|
||||
ActiveRecord::Base.logger.silence { try_to_load_dependency_without_silence(*args)}
|
||||
end
|
||||
|
||||
alias_method_chain :try_to_load_dependency, :silence
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
41
vendor/rails/activerecord/test/cases/i18n_test.rb
vendored
Normal file
41
vendor/rails/activerecord/test/cases/i18n_test.rb
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
|
||||
class ActiveRecordI18nTests < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
I18n.backend = I18n::Backend::Simple.new
|
||||
end
|
||||
|
||||
def test_translated_model_attributes
|
||||
I18n.backend.store_translations 'en', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } }
|
||||
assert_equal 'topic title attribute', Topic.human_attribute_name('title')
|
||||
end
|
||||
|
||||
def test_translated_model_attributes_with_sti
|
||||
I18n.backend.store_translations 'en', :activerecord => {:attributes => {:reply => {:title => 'reply title attribute'} } }
|
||||
assert_equal 'reply title attribute', Reply.human_attribute_name('title')
|
||||
end
|
||||
|
||||
def test_translated_model_attributes_with_sti_fallback
|
||||
I18n.backend.store_translations 'en', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } }
|
||||
assert_equal 'topic title attribute', Reply.human_attribute_name('title')
|
||||
end
|
||||
|
||||
def test_translated_model_names
|
||||
I18n.backend.store_translations 'en', :activerecord => {:models => {:topic => 'topic model'} }
|
||||
assert_equal 'topic model', Topic.human_name
|
||||
end
|
||||
|
||||
def test_translated_model_names_with_sti
|
||||
I18n.backend.store_translations 'en', :activerecord => {:models => {:reply => 'reply model'} }
|
||||
assert_equal 'reply model', Reply.human_name
|
||||
end
|
||||
|
||||
def test_translated_model_names_with_sti_fallback
|
||||
I18n.backend.store_translations 'en', :activerecord => {:models => {:topic => 'topic model'} }
|
||||
assert_equal 'topic model', Reply.human_name
|
||||
end
|
||||
end
|
||||
|
||||
262
vendor/rails/activerecord/test/cases/inheritance_test.rb
vendored
Normal file
262
vendor/rails/activerecord/test/cases/inheritance_test.rb
vendored
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
require "cases/helper"
|
||||
require 'models/company'
|
||||
require 'models/project'
|
||||
require 'models/subscriber'
|
||||
|
||||
class InheritanceTest < ActiveRecord::TestCase
|
||||
fixtures :companies, :projects, :subscribers, :accounts
|
||||
|
||||
def test_class_with_store_full_sti_class_returns_full_name
|
||||
old = ActiveRecord::Base.store_full_sti_class
|
||||
ActiveRecord::Base.store_full_sti_class = true
|
||||
assert_equal 'Namespaced::Company', Namespaced::Company.sti_name
|
||||
ensure
|
||||
ActiveRecord::Base.store_full_sti_class = old
|
||||
end
|
||||
|
||||
def test_class_without_store_full_sti_class_returns_demodulized_name
|
||||
old = ActiveRecord::Base.store_full_sti_class
|
||||
ActiveRecord::Base.store_full_sti_class = false
|
||||
assert_equal 'Company', Namespaced::Company.sti_name
|
||||
ensure
|
||||
ActiveRecord::Base.store_full_sti_class = old
|
||||
end
|
||||
|
||||
def test_should_store_demodulized_class_name_with_store_full_sti_class_option_disabled
|
||||
old = ActiveRecord::Base.store_full_sti_class
|
||||
ActiveRecord::Base.store_full_sti_class = false
|
||||
item = Namespaced::Company.new
|
||||
assert_equal 'Company', item[:type]
|
||||
ensure
|
||||
ActiveRecord::Base.store_full_sti_class = old
|
||||
end
|
||||
|
||||
def test_should_store_full_class_name_with_store_full_sti_class_option_enabled
|
||||
old = ActiveRecord::Base.store_full_sti_class
|
||||
ActiveRecord::Base.store_full_sti_class = true
|
||||
item = Namespaced::Company.new
|
||||
assert_equal 'Namespaced::Company', item[:type]
|
||||
ensure
|
||||
ActiveRecord::Base.store_full_sti_class = old
|
||||
end
|
||||
|
||||
def test_different_namespace_subclass_should_load_correctly_with_store_full_sti_class_option
|
||||
old = ActiveRecord::Base.store_full_sti_class
|
||||
ActiveRecord::Base.store_full_sti_class = true
|
||||
item = Namespaced::Company.create :name => "Wolverine 2"
|
||||
assert_not_nil Company.find(item.id)
|
||||
assert_not_nil Namespaced::Company.find(item.id)
|
||||
ensure
|
||||
ActiveRecord::Base.store_full_sti_class = old
|
||||
end
|
||||
|
||||
def test_company_descends_from_active_record
|
||||
assert_raise(NoMethodError) { ActiveRecord::Base.descends_from_active_record? }
|
||||
assert AbstractCompany.descends_from_active_record?, 'AbstractCompany should descend from ActiveRecord::Base'
|
||||
assert Company.descends_from_active_record?, 'Company should descend from ActiveRecord::Base'
|
||||
assert !Class.new(Company).descends_from_active_record?, 'Company subclass should not descend from ActiveRecord::Base'
|
||||
end
|
||||
|
||||
def test_a_bad_type_column
|
||||
#SQLServer need to turn Identity Insert On before manually inserting into the Identity column
|
||||
if current_adapter?(:SybaseAdapter)
|
||||
Company.connection.execute "SET IDENTITY_INSERT companies ON"
|
||||
end
|
||||
Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
|
||||
|
||||
#We then need to turn it back Off before continuing.
|
||||
if current_adapter?(:SybaseAdapter)
|
||||
Company.connection.execute "SET IDENTITY_INSERT companies OFF"
|
||||
end
|
||||
assert_raises(ActiveRecord::SubclassNotFound) { Company.find(100) }
|
||||
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
|
||||
switch_to_default_inheritance_column
|
||||
end
|
||||
|
||||
def test_inheritance_find_all
|
||||
companies = Company.find(:all, :order => '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
|
||||
switch_to_default_inheritance_column
|
||||
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
|
||||
switch_to_default_inheritance_column
|
||||
end
|
||||
|
||||
def test_inheritance_condition
|
||||
assert_equal 9, Company.count
|
||||
assert_equal 2, Firm.count
|
||||
assert_equal 3, Client.count
|
||||
end
|
||||
|
||||
def test_alt_inheritance_condition
|
||||
switch_to_alt_inheritance_column
|
||||
test_inheritance_condition
|
||||
switch_to_default_inheritance_column
|
||||
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
|
||||
switch_to_default_inheritance_column
|
||||
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
|
||||
switch_to_default_inheritance_column
|
||||
end
|
||||
|
||||
def test_destroy_all_within_inheritance
|
||||
Client.destroy_all
|
||||
assert_equal 0, Client.count
|
||||
assert_equal 2, Firm.count
|
||||
end
|
||||
|
||||
def test_alt_destroy_all_within_inheritance
|
||||
switch_to_alt_inheritance_column
|
||||
test_destroy_all_within_inheritance
|
||||
switch_to_default_inheritance_column
|
||||
end
|
||||
|
||||
def test_find_first_within_inheritance
|
||||
assert_kind_of Firm, Company.find(:first, :conditions => "name = '37signals'")
|
||||
assert_kind_of Firm, Firm.find(:first, :conditions => "name = '37signals'")
|
||||
assert_nil Client.find(:first, :conditions => "name = '37signals'")
|
||||
end
|
||||
|
||||
def test_alt_find_first_within_inheritance
|
||||
switch_to_alt_inheritance_column
|
||||
test_find_first_within_inheritance
|
||||
switch_to_default_inheritance_column
|
||||
end
|
||||
|
||||
def test_complex_inheritance
|
||||
very_special_client = VerySpecialClient.create("name" => "veryspecial")
|
||||
assert_equal very_special_client, VerySpecialClient.find(:first, :conditions => "name = 'veryspecial'")
|
||||
assert_equal very_special_client, SpecialClient.find(:first, :conditions => "name = 'veryspecial'")
|
||||
assert_equal very_special_client, Company.find(:first, :conditions => "name = 'veryspecial'")
|
||||
assert_equal very_special_client, Client.find(:first, :conditions => "name = 'veryspecial'")
|
||||
assert_equal 1, Client.find(:all, :conditions => "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
|
||||
switch_to_default_inheritance_column
|
||||
end
|
||||
|
||||
def test_eager_load_belongs_to_something_inherited
|
||||
account = Account.find(1, :include => :firm)
|
||||
assert_not_nil account.instance_variable_get("@firm"), "nil proves eager load failed"
|
||||
end
|
||||
|
||||
def test_eager_load_belongs_to_primary_key_quoting
|
||||
con = Account.connection
|
||||
assert_sql(/\(#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} = 1\)/) do
|
||||
Account.find(1, :include => :firm)
|
||||
end
|
||||
end
|
||||
|
||||
def test_alt_eager_loading
|
||||
switch_to_alt_inheritance_column
|
||||
test_eager_load_belongs_to_something_inherited
|
||||
switch_to_default_inheritance_column
|
||||
end
|
||||
|
||||
def test_inheritance_without_mapping
|
||||
assert_kind_of SpecialSubscriber, SpecialSubscriber.find("webster132")
|
||||
assert_nothing_raised { s = SpecialSubscriber.new("name" => "And breaaaaathe!"); s.id = 'roger'; s.save }
|
||||
end
|
||||
|
||||
private
|
||||
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, :order => 'id').each do |c|
|
||||
c['type'] = nil
|
||||
c.save
|
||||
end
|
||||
[ Company, Firm, Client].each { |klass| klass.reset_column_information }
|
||||
Company.set_inheritance_column('ruby_type')
|
||||
end
|
||||
def switch_to_default_inheritance_column
|
||||
[ Company, Firm, Client].each { |klass| klass.reset_column_information }
|
||||
Company.set_inheritance_column('type')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class InheritanceComputeTypeTest < ActiveRecord::TestCase
|
||||
fixtures :companies
|
||||
|
||||
def setup
|
||||
ActiveSupport::Dependencies.log_activity = true
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActiveSupport::Dependencies.log_activity = false
|
||||
self.class.const_remove :FirmOnTheFly rescue nil
|
||||
Firm.const_remove :FirmOnTheFly rescue nil
|
||||
end
|
||||
|
||||
def test_instantiation_doesnt_try_to_require_corresponding_file
|
||||
foo = Firm.find(:first).clone
|
||||
foo.ruby_type = foo.type = 'FirmOnTheFly'
|
||||
foo.save!
|
||||
|
||||
# Should fail without FirmOnTheFly in the type condition.
|
||||
assert_raise(ActiveRecord::RecordNotFound) { Firm.find(foo.id) }
|
||||
|
||||
# Nest FirmOnTheFly in the test case where Dependencies won't see it.
|
||||
self.class.const_set :FirmOnTheFly, Class.new(Firm)
|
||||
assert_raise(ActiveRecord::SubclassNotFound) { Firm.find(foo.id) }
|
||||
|
||||
# Nest FirmOnTheFly in Firm where Dependencies will see it.
|
||||
# This is analogous to nesting models in a migration.
|
||||
Firm.const_set :FirmOnTheFly, Class.new(Firm)
|
||||
|
||||
# And instantiate will find the existing constant rather than trying
|
||||
# to require firm_on_the_fly.
|
||||
assert_nothing_raised { assert_kind_of Firm::FirmOnTheFly, Firm.find(foo.id) }
|
||||
end
|
||||
end
|
||||
24
vendor/rails/activerecord/test/cases/invalid_date_test.rb
vendored
Normal file
24
vendor/rails/activerecord/test/cases/invalid_date_test.rb
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
require 'cases/helper'
|
||||
require 'models/topic'
|
||||
|
||||
class InvalidDateTest < Test::Unit::TestCase
|
||||
def test_assign_valid_dates
|
||||
valid_dates = [[2007, 11, 30], [1993, 2, 28], [2008, 2, 29]]
|
||||
|
||||
invalid_dates = [[2007, 11, 31], [1993, 2, 29], [2007, 2, 29]]
|
||||
|
||||
topic = Topic.new
|
||||
|
||||
valid_dates.each do |date_src|
|
||||
topic = Topic.new("last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s)
|
||||
assert_equal(topic.last_read, Date.new(*date_src))
|
||||
end
|
||||
|
||||
invalid_dates.each do |date_src|
|
||||
assert_nothing_raised do
|
||||
topic = Topic.new({"last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s})
|
||||
assert_equal(topic.last_read, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
205
vendor/rails/activerecord/test/cases/json_serialization_test.rb
vendored
Normal file
205
vendor/rails/activerecord/test/cases/json_serialization_test.rb
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
require "cases/helper"
|
||||
require 'models/contact'
|
||||
require 'models/post'
|
||||
require 'models/author'
|
||||
require 'models/tagging'
|
||||
require 'models/tag'
|
||||
require 'models/comment'
|
||||
|
||||
class JsonSerializationTest < ActiveRecord::TestCase
|
||||
class NamespacedContact < Contact
|
||||
column :name, :string
|
||||
end
|
||||
|
||||
def setup
|
||||
@contact = Contact.new(
|
||||
:name => 'Konata Izumi',
|
||||
:age => 16,
|
||||
:avatar => 'binarydata',
|
||||
:created_at => Time.utc(2006, 8, 1),
|
||||
:awesome => true,
|
||||
:preferences => { :shows => 'anime' }
|
||||
)
|
||||
end
|
||||
|
||||
def test_should_demodulize_root_in_json
|
||||
NamespacedContact.include_root_in_json = true
|
||||
@contact = NamespacedContact.new :name => 'whatever'
|
||||
json = @contact.to_json
|
||||
assert_match %r{^\{"namespaced_contact": \{}, json
|
||||
end
|
||||
|
||||
def test_should_include_root_in_json
|
||||
Contact.include_root_in_json = true
|
||||
json = @contact.to_json
|
||||
|
||||
assert_match %r{^\{"contact": \{}, json
|
||||
assert_match %r{"name": "Konata Izumi"}, json
|
||||
assert_match %r{"age": 16}, json
|
||||
assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
|
||||
assert_match %r{"awesome": true}, json
|
||||
assert_match %r{"preferences": \{"shows": "anime"\}}, json
|
||||
ensure
|
||||
Contact.include_root_in_json = false
|
||||
end
|
||||
|
||||
def test_should_encode_all_encodable_attributes
|
||||
json = @contact.to_json
|
||||
|
||||
assert_match %r{"name": "Konata Izumi"}, json
|
||||
assert_match %r{"age": 16}, json
|
||||
assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
|
||||
assert_match %r{"awesome": true}, json
|
||||
assert_match %r{"preferences": \{"shows": "anime"\}}, json
|
||||
end
|
||||
|
||||
def test_should_allow_attribute_filtering_with_only
|
||||
json = @contact.to_json(:only => [:name, :age])
|
||||
|
||||
assert_match %r{"name": "Konata Izumi"}, json
|
||||
assert_match %r{"age": 16}, json
|
||||
assert_no_match %r{"awesome": true}, json
|
||||
assert !json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
|
||||
assert_no_match %r{"preferences": \{"shows": "anime"\}}, json
|
||||
end
|
||||
|
||||
def test_should_allow_attribute_filtering_with_except
|
||||
json = @contact.to_json(:except => [:name, :age])
|
||||
|
||||
assert_no_match %r{"name": "Konata Izumi"}, json
|
||||
assert_no_match %r{"age": 16}, json
|
||||
assert_match %r{"awesome": true}, json
|
||||
assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
|
||||
assert_match %r{"preferences": \{"shows": "anime"\}}, json
|
||||
end
|
||||
|
||||
def test_methods_are_called_on_object
|
||||
# Define methods on fixture.
|
||||
def @contact.label; "Has cheezburger"; end
|
||||
def @contact.favorite_quote; "Constraints are liberating"; end
|
||||
|
||||
# Single method.
|
||||
assert_match %r{"label": "Has cheezburger"}, @contact.to_json(:only => :name, :methods => :label)
|
||||
|
||||
# Both methods.
|
||||
methods_json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote])
|
||||
assert_match %r{"label": "Has cheezburger"}, methods_json
|
||||
assert_match %r{"favorite_quote": "Constraints are liberating"}, methods_json
|
||||
end
|
||||
end
|
||||
|
||||
class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :posts, :comments, :tags, :taggings
|
||||
|
||||
def setup
|
||||
@david = authors(:david)
|
||||
@mary = authors(:mary)
|
||||
end
|
||||
|
||||
def test_includes_uses_association_name
|
||||
json = @david.to_json(:include => :posts)
|
||||
|
||||
assert_match %r{"posts": \[}, json
|
||||
|
||||
assert_match %r{"id": 1}, json
|
||||
assert_match %r{"name": "David"}, json
|
||||
|
||||
assert_match %r{"author_id": 1}, json
|
||||
assert_match %r{"title": "Welcome to the weblog"}, json
|
||||
assert_match %r{"body": "Such a lovely day"}, json
|
||||
|
||||
assert_match %r{"title": "So I was thinking"}, json
|
||||
assert_match %r{"body": "Like I hopefully always am"}, json
|
||||
end
|
||||
|
||||
def test_includes_uses_association_name_and_applies_attribute_filters
|
||||
json = @david.to_json(:include => { :posts => { :only => :title } })
|
||||
|
||||
assert_match %r{"name": "David"}, json
|
||||
assert_match %r{"posts": \[}, json
|
||||
|
||||
assert_match %r{"title": "Welcome to the weblog"}, json
|
||||
assert_no_match %r{"body": "Such a lovely day"}, json
|
||||
|
||||
assert_match %r{"title": "So I was thinking"}, json
|
||||
assert_no_match %r{"body": "Like I hopefully always am"}, json
|
||||
end
|
||||
|
||||
def test_includes_fetches_second_level_associations
|
||||
json = @david.to_json(:include => { :posts => { :include => { :comments => { :only => :body } } } })
|
||||
|
||||
assert_match %r{"name": "David"}, json
|
||||
assert_match %r{"posts": \[}, json
|
||||
|
||||
assert_match %r{"comments": \[}, json
|
||||
assert_match %r{\{"body": "Thank you again for the welcome"\}}, json
|
||||
assert_match %r{\{"body": "Don't think too hard"\}}, json
|
||||
assert_no_match %r{"post_id": }, json
|
||||
end
|
||||
|
||||
def test_includes_fetches_nth_level_associations
|
||||
json = @david.to_json(
|
||||
:include => {
|
||||
:posts => {
|
||||
:include => {
|
||||
:taggings => {
|
||||
:include => {
|
||||
:tag => { :only => :name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
assert_match %r{"name": "David"}, json
|
||||
assert_match %r{"posts": \[}, json
|
||||
|
||||
assert_match %r{"taggings": \[}, json
|
||||
assert_match %r{"tag": \{"name": "General"\}}, json
|
||||
end
|
||||
|
||||
def test_should_not_call_methods_on_associations_that_dont_respond
|
||||
def @david.favorite_quote; "Constraints are liberating"; end
|
||||
json = @david.to_json(:include => :posts, :methods => :favorite_quote)
|
||||
|
||||
assert !@david.posts.first.respond_to?(:favorite_quote)
|
||||
assert_match %r{"favorite_quote": "Constraints are liberating"}, json
|
||||
assert_equal %r{"favorite_quote": }.match(json).size, 1
|
||||
end
|
||||
|
||||
def test_should_allow_only_option_for_list_of_authors
|
||||
authors = [@david, @mary]
|
||||
|
||||
assert_equal %([{"name": "David"}, {"name": "Mary"}]), authors.to_json(:only => :name)
|
||||
end
|
||||
|
||||
def test_should_allow_except_option_for_list_of_authors
|
||||
authors = [@david, @mary]
|
||||
|
||||
assert_equal %([{"id": 1}, {"id": 2}]), authors.to_json(:except => [:name, :author_address_id, :author_address_extra_id])
|
||||
end
|
||||
|
||||
def test_should_allow_includes_for_list_of_authors
|
||||
authors = [@david, @mary]
|
||||
json = authors.to_json(
|
||||
:only => :name,
|
||||
:include => {
|
||||
:posts => { :only => :id }
|
||||
}
|
||||
)
|
||||
|
||||
['"name": "David"', '"posts": [', '{"id": 1}', '{"id": 2}', '{"id": 4}',
|
||||
'{"id": 5}', '{"id": 6}', '"name": "Mary"', '"posts": [{"id": 7}]'].each do |fragment|
|
||||
assert json.include?(fragment), json
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_allow_options_for_hash_of_authors
|
||||
authors_hash = {
|
||||
1 => @david,
|
||||
2 => @mary
|
||||
}
|
||||
|
||||
assert_equal %({1: {"name": "David"}}), authors_hash.to_json(:only => [1, :name])
|
||||
end
|
||||
end
|
||||
193
vendor/rails/activerecord/test/cases/lifecycle_test.rb
vendored
Normal file
193
vendor/rails/activerecord/test/cases/lifecycle_test.rb
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/developer'
|
||||
require 'models/reply'
|
||||
require 'models/minimalistic'
|
||||
|
||||
class Topic; def after_find() end end
|
||||
class Developer; def after_find() end end
|
||||
class SpecialDeveloper < Developer; 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 TopicaAuditor < ActiveRecord::Observer
|
||||
observe :topic
|
||||
|
||||
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 MinimalisticObserver < ActiveRecord::Observer
|
||||
attr_reader :minimalistic
|
||||
|
||||
def after_find(minimalistic)
|
||||
@minimalistic = minimalistic
|
||||
end
|
||||
end
|
||||
|
||||
class MultiObserver < ActiveRecord::Observer
|
||||
attr_reader :record
|
||||
|
||||
def self.observed_class() [ Topic, Developer ] end
|
||||
|
||||
cattr_reader :last_inherited
|
||||
@@last_inherited = nil
|
||||
|
||||
def observed_class_inherited_with_testing(subclass)
|
||||
observed_class_inherited_without_testing(subclass)
|
||||
@@last_inherited = subclass
|
||||
end
|
||||
|
||||
alias_method_chain :observed_class_inherited, :testing
|
||||
|
||||
def after_find(record)
|
||||
@record = record
|
||||
end
|
||||
end
|
||||
|
||||
class LifecycleTest < ActiveRecord::TestCase
|
||||
fixtures :topics, :developers, :minimalistics
|
||||
|
||||
def test_before_destroy
|
||||
original_count = Topic.count
|
||||
(topic_to_be_destroyed = Topic.find(1)).destroy
|
||||
assert_equal original_count - (1 + topic_to_be_destroyed.replies.size), Topic.count
|
||||
end
|
||||
|
||||
def test_after_save
|
||||
ActiveRecord::Base.observers = :topic_manual_observer
|
||||
ActiveRecord::Base.instantiate_observers
|
||||
|
||||
topic = Topic.find(1)
|
||||
topic.title = "hello"
|
||||
topic.save
|
||||
|
||||
assert TopicManualObserver.instance.has_been_notified?
|
||||
assert_equal :after_save, TopicManualObserver.instance.callbacks.last["callback_method"]
|
||||
end
|
||||
|
||||
def test_observer_update_on_save
|
||||
ActiveRecord::Base.observers = TopicManualObserver
|
||||
ActiveRecord::Base.instantiate_observers
|
||||
|
||||
topic = Topic.find(1)
|
||||
assert TopicManualObserver.instance.has_been_notified?
|
||||
assert_equal :after_find, TopicManualObserver.instance.callbacks.first["callback_method"]
|
||||
end
|
||||
|
||||
def test_auto_observer
|
||||
topic_observer = TopicaAuditor.instance
|
||||
assert_nil TopicaAuditor.observed_class
|
||||
assert_equal [Topic], TopicaAuditor.instance.observed_classes.to_a
|
||||
|
||||
topic = Topic.find(1)
|
||||
assert_equal topic.title, topic_observer.topic.title
|
||||
end
|
||||
|
||||
def test_inferred_auto_observer
|
||||
topic_observer = TopicObserver.instance
|
||||
assert_equal Topic, TopicObserver.observed_class
|
||||
|
||||
topic = Topic.find(1)
|
||||
assert_equal topic.title, topic_observer.topic.title
|
||||
end
|
||||
|
||||
def test_observing_two_classes
|
||||
multi_observer = MultiObserver.instance
|
||||
|
||||
topic = Topic.find(1)
|
||||
assert_equal topic.title, multi_observer.record.title
|
||||
|
||||
developer = Developer.find(1)
|
||||
assert_equal developer.name, multi_observer.record.name
|
||||
end
|
||||
|
||||
def test_observing_subclasses
|
||||
multi_observer = MultiObserver.instance
|
||||
|
||||
developer = SpecialDeveloper.find(1)
|
||||
assert_equal developer.name, multi_observer.record.name
|
||||
|
||||
klass = Class.new(Developer)
|
||||
assert_equal klass, multi_observer.last_inherited
|
||||
|
||||
developer = klass.find(1)
|
||||
assert_equal developer.name, multi_observer.record.name
|
||||
end
|
||||
|
||||
def test_after_find_can_be_observed_when_its_not_defined_on_the_model
|
||||
observer = MinimalisticObserver.instance
|
||||
assert_equal Minimalistic, MinimalisticObserver.observed_class
|
||||
|
||||
minimalistic = Minimalistic.find(1)
|
||||
assert_equal minimalistic, observer.minimalistic
|
||||
end
|
||||
|
||||
def test_after_find_can_be_observed_when_its_defined_on_the_model
|
||||
observer = TopicObserver.instance
|
||||
assert_equal Topic, TopicObserver.observed_class
|
||||
|
||||
topic = Topic.find(1)
|
||||
assert_equal topic, observer.topic
|
||||
end
|
||||
|
||||
def test_after_find_is_not_created_if_its_not_used
|
||||
# use a fresh class so an observer can't have defined an
|
||||
# after_find on it
|
||||
model_class = Class.new(ActiveRecord::Base)
|
||||
observer_class = Class.new(ActiveRecord::Observer)
|
||||
observer_class.observe(model_class)
|
||||
|
||||
observer = observer_class.instance
|
||||
|
||||
assert !model_class.method_defined?(:after_find)
|
||||
end
|
||||
|
||||
def test_after_find_is_not_clobbered_if_it_already_exists
|
||||
# use a fresh observer class so we can instantiate it (Observer is
|
||||
# a Singleton)
|
||||
model_class = Class.new(ActiveRecord::Base) do
|
||||
def after_find; end
|
||||
end
|
||||
original_method = model_class.instance_method(:after_find)
|
||||
observer_class = Class.new(ActiveRecord::Observer) do
|
||||
def after_find; end
|
||||
end
|
||||
observer_class.observe(model_class)
|
||||
|
||||
observer = observer_class.instance
|
||||
assert_equal original_method, model_class.instance_method(:after_find)
|
||||
end
|
||||
|
||||
def test_invalid_observer
|
||||
assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers }
|
||||
end
|
||||
end
|
||||
304
vendor/rails/activerecord/test/cases/locking_test.rb
vendored
Normal file
304
vendor/rails/activerecord/test/cases/locking_test.rb
vendored
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
require "cases/helper"
|
||||
require 'models/person'
|
||||
require 'models/reader'
|
||||
require 'models/legacy_thing'
|
||||
require 'models/reference'
|
||||
|
||||
class LockWithoutDefault < ActiveRecord::Base; end
|
||||
|
||||
class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
|
||||
set_table_name :lock_without_defaults_cust
|
||||
set_locking_column :custom_lock_version
|
||||
end
|
||||
|
||||
class ReadonlyFirstNamePerson < Person
|
||||
attr_readonly :first_name
|
||||
end
|
||||
|
||||
class OptimisticLockingTest < ActiveRecord::TestCase
|
||||
fixtures :people, :legacy_things, :references
|
||||
|
||||
# need to disable transactional fixtures, because otherwise the sqlite3
|
||||
# adapter (at least) chokes when we try and change the schema in the middle
|
||||
# of a test (see test_increment_counter_*).
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def test_lock_existing
|
||||
p1 = Person.find(1)
|
||||
p2 = Person.find(1)
|
||||
assert_equal 0, p1.lock_version
|
||||
assert_equal 0, p2.lock_version
|
||||
|
||||
p1.first_name = 'stu'
|
||||
p1.save!
|
||||
assert_equal 1, p1.lock_version
|
||||
assert_equal 0, p2.lock_version
|
||||
|
||||
p2.first_name = 'sue'
|
||||
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
||||
end
|
||||
|
||||
def test_lock_repeating
|
||||
p1 = Person.find(1)
|
||||
p2 = Person.find(1)
|
||||
assert_equal 0, p1.lock_version
|
||||
assert_equal 0, p2.lock_version
|
||||
|
||||
p1.first_name = 'stu'
|
||||
p1.save!
|
||||
assert_equal 1, p1.lock_version
|
||||
assert_equal 0, p2.lock_version
|
||||
|
||||
p2.first_name = 'sue'
|
||||
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
||||
p2.first_name = 'sue2'
|
||||
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
||||
end
|
||||
|
||||
def test_lock_new
|
||||
p1 = Person.new(:first_name => 'anika')
|
||||
assert_equal 0, p1.lock_version
|
||||
|
||||
p1.first_name = 'anika2'
|
||||
p1.save!
|
||||
p2 = Person.find(p1.id)
|
||||
assert_equal 0, p1.lock_version
|
||||
assert_equal 0, p2.lock_version
|
||||
|
||||
p1.first_name = 'anika3'
|
||||
p1.save!
|
||||
assert_equal 1, p1.lock_version
|
||||
assert_equal 0, p2.lock_version
|
||||
|
||||
p2.first_name = 'sue'
|
||||
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
||||
end
|
||||
|
||||
def test_lock_new_with_nil
|
||||
p1 = Person.new(:first_name => 'anika')
|
||||
p1.save!
|
||||
p1.lock_version = nil # simulate bad fixture or column with no default
|
||||
p1.save!
|
||||
assert_equal 1, p1.lock_version
|
||||
end
|
||||
|
||||
|
||||
def test_lock_column_name_existing
|
||||
t1 = LegacyThing.find(1)
|
||||
t2 = LegacyThing.find(1)
|
||||
assert_equal 0, t1.version
|
||||
assert_equal 0, t2.version
|
||||
|
||||
t1.tps_report_number = 700
|
||||
t1.save!
|
||||
assert_equal 1, t1.version
|
||||
assert_equal 0, t2.version
|
||||
|
||||
t2.tps_report_number = 800
|
||||
assert_raises(ActiveRecord::StaleObjectError) { t2.save! }
|
||||
end
|
||||
|
||||
def test_lock_column_is_mass_assignable
|
||||
p1 = Person.create(:first_name => 'bianca')
|
||||
assert_equal 0, p1.lock_version
|
||||
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
||||
|
||||
p1.first_name = 'bianca2'
|
||||
p1.save!
|
||||
assert_equal 1, p1.lock_version
|
||||
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
||||
end
|
||||
|
||||
def test_lock_without_default_sets_version_to_zero
|
||||
t1 = LockWithoutDefault.new
|
||||
assert_equal 0, t1.lock_version
|
||||
end
|
||||
|
||||
def test_lock_with_custom_column_without_default_sets_version_to_zero
|
||||
t1 = LockWithCustomColumnWithoutDefault.new
|
||||
assert_equal 0, t1.custom_lock_version
|
||||
end
|
||||
|
||||
def test_readonly_attributes
|
||||
assert_equal Set.new([ 'first_name' ]), ReadonlyFirstNamePerson.readonly_attributes
|
||||
|
||||
p = ReadonlyFirstNamePerson.create(:first_name => "unchangeable name")
|
||||
p.reload
|
||||
assert_equal "unchangeable name", p.first_name
|
||||
|
||||
p.update_attributes(:first_name => "changed name")
|
||||
p.reload
|
||||
assert_equal "unchangeable name", p.first_name
|
||||
end
|
||||
|
||||
{ :lock_version => Person, :custom_lock_version => LegacyThing }.each do |name, model|
|
||||
define_method("test_increment_counter_updates_#{name}") do
|
||||
counter_test model, 1 do |id|
|
||||
model.increment_counter :test_count, id
|
||||
end
|
||||
end
|
||||
|
||||
define_method("test_decrement_counter_updates_#{name}") do
|
||||
counter_test model, -1 do |id|
|
||||
model.decrement_counter :test_count, id
|
||||
end
|
||||
end
|
||||
|
||||
define_method("test_update_counters_updates_#{name}") do
|
||||
counter_test model, 1 do |id|
|
||||
model.update_counters id, :test_count => 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_quote_table_name
|
||||
ref = references(:michael_magician)
|
||||
ref.favourite = !ref.favourite
|
||||
assert ref.save
|
||||
end
|
||||
|
||||
# Useful for partial updates, don't only update the lock_version if there
|
||||
# is nothing else being updated.
|
||||
def test_update_without_attributes_does_not_only_update_lock_version
|
||||
assert_nothing_raised do
|
||||
p1 = Person.new(:first_name => 'anika')
|
||||
p1.send(:update_with_lock, [])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_counter_column_to(model)
|
||||
model.connection.add_column model.table_name, :test_count, :integer, :null => false, :default => 0
|
||||
model.reset_column_information
|
||||
# OpenBase does not set a value to existing rows when adding a not null default column
|
||||
model.update_all(:test_count => 0) if current_adapter?(:OpenBaseAdapter)
|
||||
end
|
||||
|
||||
def remove_counter_column_from(model)
|
||||
model.connection.remove_column model.table_name, :test_count
|
||||
model.reset_column_information
|
||||
end
|
||||
|
||||
def counter_test(model, expected_count)
|
||||
add_counter_column_to(model)
|
||||
object = model.find(:first)
|
||||
assert_equal 0, object.test_count
|
||||
assert_equal 0, object.send(model.locking_column)
|
||||
yield object.id
|
||||
object.reload
|
||||
assert_equal expected_count, object.test_count
|
||||
assert_equal 1, object.send(model.locking_column)
|
||||
ensure
|
||||
remove_counter_column_from(model)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# TODO: test against the generated SQL since testing locking behavior itself
|
||||
# is so cumbersome. Will deadlock Ruby threads if the underlying db.execute
|
||||
# blocks, so separate script called by Kernel#system is needed.
|
||||
# (See exec vs. async_exec in the PostgreSQL adapter.)
|
||||
|
||||
# TODO: The Sybase, and OpenBase adapters currently have no support for pessimistic locking
|
||||
|
||||
unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter)
|
||||
class PessimisticLockingTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
fixtures :people, :readers
|
||||
|
||||
def setup
|
||||
# Avoid introspection queries during tests.
|
||||
Person.columns; Reader.columns
|
||||
end
|
||||
|
||||
# Test typical find.
|
||||
def test_sane_find_with_lock
|
||||
assert_nothing_raised do
|
||||
Person.transaction do
|
||||
Person.find 1, :lock => true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Test scoped lock.
|
||||
def test_sane_find_with_scoped_lock
|
||||
assert_nothing_raised do
|
||||
Person.transaction do
|
||||
Person.with_scope(:find => { :lock => true }) do
|
||||
Person.find 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
|
||||
unless current_adapter?(:PostgreSQLAdapter)
|
||||
# Test locked eager find.
|
||||
def test_eager_find_with_lock
|
||||
assert_nothing_raised do
|
||||
Person.transaction do
|
||||
Person.find 1, :include => :readers, :lock => true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Locking a record reloads it.
|
||||
def test_sane_lock_method
|
||||
assert_nothing_raised do
|
||||
Person.transaction do
|
||||
person = Person.find 1
|
||||
old, person.first_name = person.first_name, 'fooman'
|
||||
person.lock!
|
||||
assert_equal old, person.first_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
|
||||
use_concurrent_connections
|
||||
|
||||
def test_no_locks_no_wait
|
||||
first, second = duel { Person.find 1 }
|
||||
assert first.end > second.end
|
||||
end
|
||||
|
||||
def test_second_lock_waits
|
||||
assert [0.2, 1, 5].any? { |zzz|
|
||||
first, second = duel(zzz) { Person.find 1, :lock => true }
|
||||
second.end > first.end
|
||||
}
|
||||
end
|
||||
|
||||
protected
|
||||
def duel(zzz = 5)
|
||||
t0, t1, t2, t3 = nil, nil, nil, nil
|
||||
|
||||
a = Thread.new do
|
||||
t0 = Time.now
|
||||
Person.transaction do
|
||||
yield
|
||||
sleep zzz # block thread 2 for zzz seconds
|
||||
end
|
||||
t1 = Time.now
|
||||
end
|
||||
|
||||
b = Thread.new do
|
||||
sleep zzz / 2.0 # ensure thread 1 tx starts first
|
||||
t2 = Time.now
|
||||
Person.transaction { yield }
|
||||
t3 = Time.now
|
||||
end
|
||||
|
||||
a.join
|
||||
b.join
|
||||
|
||||
assert t1 > t0 + zzz
|
||||
assert t2 > t0
|
||||
assert t3 > t2
|
||||
[t0.to_f..t1.to_f, t2.to_f..t3.to_f]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
569
vendor/rails/activerecord/test/cases/method_scoping_test.rb
vendored
Normal file
569
vendor/rails/activerecord/test/cases/method_scoping_test.rb
vendored
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
require "cases/helper"
|
||||
require 'models/author'
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/comment'
|
||||
require 'models/post'
|
||||
require 'models/category'
|
||||
|
||||
class MethodScopingTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects
|
||||
|
||||
def test_set_conditions
|
||||
Developer.with_scope(:find => { :conditions => 'just a test...' }) do
|
||||
assert_equal 'just a test...', Developer.send(:current_scoped_methods)[:find][:conditions]
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_find
|
||||
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
assert_nothing_raised { Developer.find(1) }
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_find_first
|
||||
Developer.with_scope(:find => { :conditions => "salary = 100000" }) do
|
||||
assert_equal Developer.find(10), Developer.find(:first, :order => 'name')
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_find_combines_conditions
|
||||
Developer.with_scope(:find => { :conditions => "salary = 9000" }) do
|
||||
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => "name = 'Jamis'")
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_find_sanitizes_conditions
|
||||
Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
|
||||
assert_equal developers(:poor_jamis), Developer.find(:first)
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_find_combines_and_sanitizes_conditions
|
||||
Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
|
||||
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_find_all
|
||||
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
assert_equal [developers(:david)], Developer.find(:all)
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_find_select
|
||||
Developer.with_scope(:find => { :select => "id, name" }) do
|
||||
developer = Developer.find(:first, :conditions => "name = 'David'")
|
||||
assert_equal "David", developer.name
|
||||
assert !developer.has_attribute?(:salary)
|
||||
end
|
||||
end
|
||||
|
||||
def test_options_select_replaces_scope_select
|
||||
Developer.with_scope(:find => { :select => "id, name" }) do
|
||||
developer = Developer.find(:first, :select => 'id, salary', :conditions => "name = 'David'")
|
||||
assert_equal 80000, developer.salary
|
||||
assert !developer.has_attribute?(:name)
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_count
|
||||
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
assert_equal 1, Developer.count
|
||||
end
|
||||
|
||||
Developer.with_scope(:find => { :conditions => 'salary = 100000' }) do
|
||||
assert_equal 8, Developer.count
|
||||
assert_equal 1, Developer.count(:conditions => "name LIKE 'fixture_1%'")
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_find_include
|
||||
# with the include, will retrieve only developers for the given project
|
||||
scoped_developers = Developer.with_scope(:find => { :include => :projects }) do
|
||||
Developer.find(:all, :conditions => 'projects.id = 2')
|
||||
end
|
||||
assert scoped_developers.include?(developers(:david))
|
||||
assert !scoped_developers.include?(developers(:jamis))
|
||||
assert_equal 1, scoped_developers.size
|
||||
end
|
||||
|
||||
def test_scoped_find_joins
|
||||
scoped_developers = Developer.with_scope(:find => { :joins => 'JOIN developers_projects ON id = developer_id' } ) do
|
||||
Developer.find(:all, :conditions => 'developers_projects.project_id = 2')
|
||||
end
|
||||
assert scoped_developers.include?(developers(:david))
|
||||
assert !scoped_developers.include?(developers(:jamis))
|
||||
assert_equal 1, scoped_developers.size
|
||||
assert_equal developers(:david).attributes, scoped_developers.first.attributes
|
||||
end
|
||||
|
||||
def test_scoped_find_using_new_style_joins
|
||||
scoped_developers = Developer.with_scope(:find => { :joins => :projects }) do
|
||||
Developer.find(:all, :conditions => 'projects.id = 2')
|
||||
end
|
||||
assert scoped_developers.include?(developers(:david))
|
||||
assert !scoped_developers.include?(developers(:jamis))
|
||||
assert_equal 1, scoped_developers.size
|
||||
assert_equal developers(:david).attributes, scoped_developers.first.attributes
|
||||
end
|
||||
|
||||
def test_scoped_find_merges_old_style_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id ' }) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'INNER JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
|
||||
def test_scoped_find_merges_new_style_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => :posts }) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :joins => :comments, :conditions => 'comments.id = 1')
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
|
||||
def test_scoped_find_merges_new_and_old_style_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => :posts }) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
|
||||
def test_scoped_find_merges_string_array_style_and_string_style_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => ["INNER JOIN posts ON posts.author_id = authors.id"]}) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'INNER JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
|
||||
def test_scoped_find_merges_string_array_style_and_hash_style_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => :posts}) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :joins => ['INNER JOIN comments ON posts.id = comments.post_id'], :conditions => 'comments.id = 1')
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
|
||||
def test_scoped_find_merges_joins_and_eliminates_duplicate_string_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON posts.author_id = authors.id'}) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :joins => ["INNER JOIN posts ON posts.author_id = authors.id", "INNER JOIN comments ON posts.id = comments.post_id"], :conditions => 'comments.id = 1')
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
|
||||
def test_scoped_count_include
|
||||
# with the include, will retrieve only developers for the given project
|
||||
Developer.with_scope(:find => { :include => :projects }) do
|
||||
assert_equal 1, Developer.count(:conditions => 'projects.id = 2')
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_create
|
||||
new_comment = nil
|
||||
|
||||
VerySpecialComment.with_scope(:create => { :post_id => 1 }) do
|
||||
assert_equal({ :post_id => 1 }, VerySpecialComment.send(:current_scoped_methods)[:create])
|
||||
new_comment = VerySpecialComment.create :body => "Wonderful world"
|
||||
end
|
||||
|
||||
assert Post.find(1).comments.include?(new_comment)
|
||||
end
|
||||
|
||||
def test_immutable_scope
|
||||
options = { :conditions => "name = 'David'" }
|
||||
Developer.with_scope(:find => options) do
|
||||
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
||||
options[:conditions] = "name != 'David'"
|
||||
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
||||
end
|
||||
|
||||
scope = { :find => { :conditions => "name = 'David'" }}
|
||||
Developer.with_scope(scope) do
|
||||
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
||||
scope[:find][:conditions] = "name != 'David'"
|
||||
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
||||
end
|
||||
end
|
||||
|
||||
def test_scoped_with_duck_typing
|
||||
scoping = Struct.new(:method_scoping).new(:find => { :conditions => ["name = ?", 'David'] })
|
||||
Developer.with_scope(scoping) do
|
||||
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
||||
end
|
||||
end
|
||||
|
||||
def test_ensure_that_method_scoping_is_correctly_restored
|
||||
scoped_methods = Developer.instance_eval('current_scoped_methods')
|
||||
|
||||
begin
|
||||
Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
||||
raise "an exception"
|
||||
end
|
||||
rescue
|
||||
end
|
||||
assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods')
|
||||
end
|
||||
end
|
||||
|
||||
class NestedScopingTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :developers, :projects, :comments, :posts
|
||||
|
||||
def test_merge_options
|
||||
Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do
|
||||
Developer.with_scope(:find => { :limit => 10 }) do
|
||||
merged_option = Developer.instance_eval('current_scoped_methods')[:find]
|
||||
assert_equal({ :conditions => 'salary = 80000', :limit => 10 }, merged_option)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_replace_options
|
||||
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
Developer.with_exclusive_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
||||
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.instance_eval('current_scoped_methods'))
|
||||
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.send(:scoped_methods)[-1])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_append_conditions
|
||||
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do
|
||||
appended_condition = Developer.instance_eval('current_scoped_methods')[:find][:conditions]
|
||||
assert_equal("(name = 'David') AND (salary = 80000)", appended_condition)
|
||||
assert_equal(1, Developer.count)
|
||||
end
|
||||
Developer.with_scope(:find => { :conditions => "name = 'Maiha'" }) do
|
||||
assert_equal(0, Developer.count)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_merge_and_append_options
|
||||
Developer.with_scope(:find => { :conditions => 'salary = 80000', :limit => 10 }) do
|
||||
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
merged_option = Developer.instance_eval('current_scoped_methods')[:find]
|
||||
assert_equal({ :conditions => "(salary = 80000) AND (name = 'David')", :limit => 10 }, merged_option)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_nested_scoped_find
|
||||
Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
||||
Developer.with_exclusive_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
assert_nothing_raised { Developer.find(1) }
|
||||
assert_equal('David', Developer.find(:first).name)
|
||||
end
|
||||
assert_equal('Jamis', Developer.find(:first).name)
|
||||
end
|
||||
end
|
||||
|
||||
def test_nested_scoped_find_include
|
||||
Developer.with_scope(:find => { :include => :projects }) do
|
||||
Developer.with_scope(:find => { :conditions => "projects.id = 2" }) do
|
||||
assert_nothing_raised { Developer.find(1) }
|
||||
assert_equal('David', Developer.find(:first).name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_nested_scoped_find_merged_include
|
||||
# :include's remain unique and don't "double up" when merging
|
||||
Developer.with_scope(:find => { :include => :projects, :conditions => "projects.id = 2" }) do
|
||||
Developer.with_scope(:find => { :include => :projects }) do
|
||||
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
|
||||
assert_equal('David', Developer.find(:first).name)
|
||||
end
|
||||
end
|
||||
|
||||
# the nested scope doesn't remove the first :include
|
||||
Developer.with_scope(:find => { :include => :projects, :conditions => "projects.id = 2" }) do
|
||||
Developer.with_scope(:find => { :include => [] }) do
|
||||
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
|
||||
assert_equal('David', Developer.find(:first).name)
|
||||
end
|
||||
end
|
||||
|
||||
# mixing array and symbol include's will merge correctly
|
||||
Developer.with_scope(:find => { :include => [:projects], :conditions => "projects.id = 2" }) do
|
||||
Developer.with_scope(:find => { :include => :projects }) do
|
||||
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
|
||||
assert_equal('David', Developer.find(:first).name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_nested_scoped_find_replace_include
|
||||
Developer.with_scope(:find => { :include => :projects }) do
|
||||
Developer.with_exclusive_scope(:find => { :include => [] }) do
|
||||
assert_equal 0, Developer.instance_eval('current_scoped_methods')[:find][:include].length
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_three_level_nested_exclusive_scoped_find
|
||||
Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
||||
assert_equal('Jamis', Developer.find(:first).name)
|
||||
|
||||
Developer.with_exclusive_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
assert_equal('David', Developer.find(:first).name)
|
||||
|
||||
Developer.with_exclusive_scope(:find => { :conditions => "name = 'Maiha'" }) do
|
||||
assert_equal(nil, Developer.find(:first))
|
||||
end
|
||||
|
||||
# ensure that scoping is restored
|
||||
assert_equal('David', Developer.find(:first).name)
|
||||
end
|
||||
|
||||
# ensure that scoping is restored
|
||||
assert_equal('Jamis', Developer.find(:first).name)
|
||||
end
|
||||
end
|
||||
|
||||
def test_merged_scoped_find
|
||||
poor_jamis = developers(:poor_jamis)
|
||||
Developer.with_scope(:find => { :conditions => "salary < 100000" }) do
|
||||
Developer.with_scope(:find => { :offset => 1 }) do
|
||||
assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_merged_scoped_find_sanitizes_conditions
|
||||
Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
|
||||
Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
|
||||
assert_raise(ActiveRecord::RecordNotFound) { developers(:poor_jamis) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_nested_scoped_find_combines_and_sanitizes_conditions
|
||||
Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
|
||||
Developer.with_exclusive_scope(:find => { :conditions => ['salary = ?', 9000] }) do
|
||||
assert_equal developers(:poor_jamis), Developer.find(:first)
|
||||
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_merged_scoped_find_combines_and_sanitizes_conditions
|
||||
Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
|
||||
Developer.with_scope(:find => { :conditions => ['salary > ?', 9000] }) do
|
||||
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_merged_scoped_find_on_blank_conditions
|
||||
[nil, " ", [], {}].each do |blank|
|
||||
Developer.with_scope(:find => {:conditions => blank}) do
|
||||
Developer.with_scope(:find => {:conditions => blank}) do
|
||||
assert_nothing_raised { Developer.find(:first) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_merged_scoped_find_on_blank_bind_conditions
|
||||
[ [""], ["",{}] ].each do |blank|
|
||||
Developer.with_scope(:find => {:conditions => blank}) do
|
||||
Developer.with_scope(:find => {:conditions => blank}) do
|
||||
assert_nothing_raised { Developer.find(:first) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_immutable_nested_scope
|
||||
options1 = { :conditions => "name = 'Jamis'" }
|
||||
options2 = { :conditions => "name = 'David'" }
|
||||
Developer.with_scope(:find => options1) do
|
||||
Developer.with_exclusive_scope(:find => options2) do
|
||||
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
||||
options1[:conditions] = options2[:conditions] = nil
|
||||
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_immutable_merged_scope
|
||||
options1 = { :conditions => "name = 'Jamis'" }
|
||||
options2 = { :conditions => "salary > 10000" }
|
||||
Developer.with_scope(:find => options1) do
|
||||
Developer.with_scope(:find => options2) do
|
||||
assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
|
||||
options1[:conditions] = options2[:conditions] = nil
|
||||
assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_ensure_that_method_scoping_is_correctly_restored
|
||||
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
scoped_methods = Developer.instance_eval('current_scoped_methods')
|
||||
begin
|
||||
Developer.with_scope(:find => { :conditions => "name = 'Maiha'" }) do
|
||||
raise "an exception"
|
||||
end
|
||||
rescue
|
||||
end
|
||||
assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods')
|
||||
end
|
||||
end
|
||||
|
||||
def test_nested_scoped_find_merges_old_style_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON authors.id = posts.author_id' }) do
|
||||
Author.with_scope(:find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :conditions => 'comments.id = 1')
|
||||
end
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
|
||||
def test_nested_scoped_find_merges_new_style_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => :posts }) do
|
||||
Author.with_scope(:find => { :joins => :comments }) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :conditions => 'comments.id = 1')
|
||||
end
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
|
||||
def test_nested_scoped_find_merges_new_and_old_style_joins
|
||||
scoped_authors = Author.with_scope(:find => { :joins => :posts }) do
|
||||
Author.with_scope(:find => { :joins => 'INNER JOIN comments ON posts.id = comments.post_id' }) do
|
||||
Author.find(:all, :select => 'DISTINCT authors.*', :joins => '', :conditions => 'comments.id = 1')
|
||||
end
|
||||
end
|
||||
assert scoped_authors.include?(authors(:david))
|
||||
assert !scoped_authors.include?(authors(:mary))
|
||||
assert_equal 1, scoped_authors.size
|
||||
assert_equal authors(:david).attributes, scoped_authors.first.attributes
|
||||
end
|
||||
end
|
||||
|
||||
class HasManyScopingTest< ActiveRecord::TestCase
|
||||
fixtures :comments, :posts
|
||||
|
||||
def setup
|
||||
@welcome = Post.find(1)
|
||||
end
|
||||
|
||||
def test_forwarding_of_static_methods
|
||||
assert_equal 'a comment...', Comment.what_are_you
|
||||
assert_equal 'a comment...', @welcome.comments.what_are_you
|
||||
end
|
||||
|
||||
def test_forwarding_to_scoped
|
||||
assert_equal 4, Comment.search_by_type('Comment').size
|
||||
assert_equal 2, @welcome.comments.search_by_type('Comment').size
|
||||
end
|
||||
|
||||
def test_forwarding_to_dynamic_finders
|
||||
assert_equal 4, Comment.find_all_by_type('Comment').size
|
||||
assert_equal 2, @welcome.comments.find_all_by_type('Comment').size
|
||||
end
|
||||
|
||||
def test_nested_scope
|
||||
Comment.with_scope(:find => { :conditions => '1=1' }) do
|
||||
assert_equal 'a comment...', @welcome.comments.what_are_you
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase
|
||||
fixtures :posts, :categories, :categories_posts
|
||||
|
||||
def setup
|
||||
@welcome = Post.find(1)
|
||||
end
|
||||
|
||||
def test_forwarding_of_static_methods
|
||||
assert_equal 'a category...', Category.what_are_you
|
||||
assert_equal 'a category...', @welcome.categories.what_are_you
|
||||
end
|
||||
|
||||
def test_forwarding_to_dynamic_finders
|
||||
assert_equal 4, Category.find_all_by_type('SpecialCategory').size
|
||||
assert_equal 0, @welcome.categories.find_all_by_type('SpecialCategory').size
|
||||
assert_equal 2, @welcome.categories.find_all_by_type('Category').size
|
||||
end
|
||||
|
||||
def test_nested_scope
|
||||
Category.with_scope(:find => { :conditions => '1=1' }) do
|
||||
assert_equal 'a comment...', @welcome.comments.what_are_you
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
=begin
|
||||
# We disabled the scoping for has_one and belongs_to as we can't think of a proper use case
|
||||
|
||||
|
||||
class BelongsToScopingTest< ActiveRecord::TestCase
|
||||
fixtures :comments, :posts
|
||||
|
||||
def setup
|
||||
@greetings = Comment.find(1)
|
||||
end
|
||||
|
||||
def test_forwarding_of_static_method
|
||||
assert_equal 'a post...', Post.what_are_you
|
||||
assert_equal 'a post...', @greetings.post.what_are_you
|
||||
end
|
||||
|
||||
def test_forwarding_to_dynamic_finders
|
||||
assert_equal 4, Post.find_all_by_type('Post').size
|
||||
assert_equal 1, @greetings.post.find_all_by_type('Post').size
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
class HasOneScopingTest< ActiveRecord::TestCase
|
||||
fixtures :comments, :posts
|
||||
|
||||
def setup
|
||||
@sti_comments = Post.find(4)
|
||||
end
|
||||
|
||||
def test_forwarding_of_static_methods
|
||||
assert_equal 'a comment...', Comment.what_are_you
|
||||
assert_equal 'a very special comment...', @sti_comments.very_special_comment.what_are_you
|
||||
end
|
||||
|
||||
def test_forwarding_to_dynamic_finders
|
||||
assert_equal 1, Comment.find_all_by_type('VerySpecialComment').size
|
||||
assert_equal 1, @sti_comments.very_special_comment.find_all_by_type('VerySpecialComment').size
|
||||
assert_equal 0, @sti_comments.very_special_comment.find_all_by_type('Comment').size
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
=end
|
||||
1479
vendor/rails/activerecord/test/cases/migration_test.rb
vendored
Normal file
1479
vendor/rails/activerecord/test/cases/migration_test.rb
vendored
Normal file
File diff suppressed because it is too large
Load diff
124
vendor/rails/activerecord/test/cases/migration_test_firebird.rb
vendored
Normal file
124
vendor/rails/activerecord/test/cases/migration_test_firebird.rb
vendored
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
require "cases/helper"
|
||||
require 'models/course'
|
||||
|
||||
class FirebirdMigrationTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def setup
|
||||
# using Course connection for tests -- need a db that doesn't already have a BOOLEAN domain
|
||||
@connection = Course.connection
|
||||
@fireruby_connection = @connection.instance_variable_get(:@connection)
|
||||
end
|
||||
|
||||
def teardown
|
||||
@connection.drop_table :foo rescue nil
|
||||
@connection.execute("DROP DOMAIN D_BOOLEAN") rescue nil
|
||||
end
|
||||
|
||||
def test_create_table_with_custom_sequence_name
|
||||
assert_nothing_raised do
|
||||
@connection.create_table(:foo, :sequence => 'foo_custom_seq') do |f|
|
||||
f.column :bar, :string
|
||||
end
|
||||
end
|
||||
assert !sequence_exists?('foo_seq')
|
||||
assert sequence_exists?('foo_custom_seq')
|
||||
|
||||
assert_nothing_raised { @connection.drop_table(:foo, :sequence => 'foo_custom_seq') }
|
||||
assert !sequence_exists?('foo_custom_seq')
|
||||
ensure
|
||||
FireRuby::Generator.new('foo_custom_seq', @fireruby_connection).drop rescue nil
|
||||
end
|
||||
|
||||
def test_create_table_without_sequence
|
||||
assert_nothing_raised do
|
||||
@connection.create_table(:foo, :sequence => false) do |f|
|
||||
f.column :bar, :string
|
||||
end
|
||||
end
|
||||
assert !sequence_exists?('foo_seq')
|
||||
assert_nothing_raised { @connection.drop_table :foo }
|
||||
|
||||
assert_nothing_raised do
|
||||
@connection.create_table(:foo, :id => false) do |f|
|
||||
f.column :bar, :string
|
||||
end
|
||||
end
|
||||
assert !sequence_exists?('foo_seq')
|
||||
assert_nothing_raised { @connection.drop_table :foo }
|
||||
end
|
||||
|
||||
def test_create_table_with_boolean_column
|
||||
assert !boolean_domain_exists?
|
||||
assert_nothing_raised do
|
||||
@connection.create_table :foo do |f|
|
||||
f.column :bar, :string
|
||||
f.column :baz, :boolean
|
||||
end
|
||||
end
|
||||
assert boolean_domain_exists?
|
||||
end
|
||||
|
||||
def test_add_boolean_column
|
||||
assert !boolean_domain_exists?
|
||||
@connection.create_table :foo do |f|
|
||||
f.column :bar, :string
|
||||
end
|
||||
|
||||
assert_nothing_raised { @connection.add_column :foo, :baz, :boolean }
|
||||
assert boolean_domain_exists?
|
||||
assert_equal :boolean, @connection.columns(:foo).find { |c| c.name == "baz" }.type
|
||||
end
|
||||
|
||||
def test_change_column_to_boolean
|
||||
assert !boolean_domain_exists?
|
||||
# Manually create table with a SMALLINT column, which can be changed to a BOOLEAN
|
||||
@connection.execute "CREATE TABLE foo (bar SMALLINT)"
|
||||
assert_equal :integer, @connection.columns(:foo).find { |c| c.name == "bar" }.type
|
||||
|
||||
assert_nothing_raised { @connection.change_column :foo, :bar, :boolean }
|
||||
assert boolean_domain_exists?
|
||||
assert_equal :boolean, @connection.columns(:foo).find { |c| c.name == "bar" }.type
|
||||
end
|
||||
|
||||
def test_rename_table_with_data_and_index
|
||||
@connection.create_table :foo do |f|
|
||||
f.column :baz, :string, :limit => 50
|
||||
end
|
||||
100.times { |i| @connection.execute "INSERT INTO foo VALUES (GEN_ID(foo_seq, 1), 'record #{i+1}')" }
|
||||
@connection.add_index :foo, :baz
|
||||
|
||||
assert_nothing_raised { @connection.rename_table :foo, :bar }
|
||||
assert !@connection.tables.include?("foo")
|
||||
assert @connection.tables.include?("bar")
|
||||
assert_equal "index_bar_on_baz", @connection.indexes("bar").first.name
|
||||
assert_equal 100, FireRuby::Generator.new("bar_seq", @fireruby_connection).last
|
||||
assert_equal 100, @connection.select_one("SELECT COUNT(*) FROM bar")["count"]
|
||||
ensure
|
||||
@connection.drop_table :bar rescue nil
|
||||
end
|
||||
|
||||
def test_renaming_table_with_fk_constraint_raises_error
|
||||
@connection.create_table :parent do |p|
|
||||
p.column :name, :string
|
||||
end
|
||||
@connection.create_table :child do |c|
|
||||
c.column :parent_id, :integer
|
||||
end
|
||||
@connection.execute "ALTER TABLE child ADD CONSTRAINT fk_child_parent FOREIGN KEY(parent_id) REFERENCES parent(id)"
|
||||
assert_raise(ActiveRecord::ActiveRecordError) { @connection.rename_table :child, :descendant }
|
||||
ensure
|
||||
@connection.drop_table :child rescue nil
|
||||
@connection.drop_table :descendant rescue nil
|
||||
@connection.drop_table :parent rescue nil
|
||||
end
|
||||
|
||||
private
|
||||
def boolean_domain_exists?
|
||||
!@connection.select_one("SELECT 1 FROM rdb$fields WHERE rdb$field_name = 'D_BOOLEAN'").nil?
|
||||
end
|
||||
|
||||
def sequence_exists?(sequence_name)
|
||||
FireRuby::Generator.exists?(sequence_name, @fireruby_connection)
|
||||
end
|
||||
end
|
||||
96
vendor/rails/activerecord/test/cases/mixin_test.rb
vendored
Normal file
96
vendor/rails/activerecord/test/cases/mixin_test.rb
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
require "cases/helper"
|
||||
|
||||
class Mixin < ActiveRecord::Base
|
||||
end
|
||||
|
||||
# Let us control what Time.now returns for the TouchTest suite
|
||||
class Time
|
||||
@@forced_now_time = nil
|
||||
cattr_accessor :forced_now_time
|
||||
|
||||
class << self
|
||||
def now_with_forcing
|
||||
if @@forced_now_time
|
||||
@@forced_now_time
|
||||
else
|
||||
now_without_forcing
|
||||
end
|
||||
end
|
||||
alias_method_chain :now, :forcing
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class TouchTest < ActiveRecord::TestCase
|
||||
fixtures :mixins
|
||||
|
||||
def setup
|
||||
Time.forced_now_time = Time.now
|
||||
end
|
||||
|
||||
def teardown
|
||||
Time.forced_now_time = nil
|
||||
end
|
||||
|
||||
def test_time_mocking
|
||||
five_minutes_ago = 5.minutes.ago
|
||||
Time.forced_now_time = five_minutes_ago
|
||||
assert_equal five_minutes_ago, Time.now
|
||||
|
||||
Time.forced_now_time = nil
|
||||
assert_not_equal five_minutes_ago, Time.now
|
||||
end
|
||||
|
||||
def test_update
|
||||
stamped = Mixin.new
|
||||
|
||||
assert_nil stamped.updated_at
|
||||
assert_nil stamped.created_at
|
||||
stamped.save
|
||||
assert_equal Time.now, stamped.updated_at
|
||||
assert_equal Time.now, stamped.created_at
|
||||
end
|
||||
|
||||
def test_create
|
||||
obj = Mixin.create
|
||||
assert_equal Time.now, obj.updated_at
|
||||
assert_equal Time.now, obj.created_at
|
||||
end
|
||||
|
||||
def test_many_updates
|
||||
stamped = Mixin.new
|
||||
|
||||
assert_nil stamped.updated_at
|
||||
assert_nil stamped.created_at
|
||||
stamped.save
|
||||
assert_equal Time.now, stamped.created_at
|
||||
assert_equal Time.now, stamped.updated_at
|
||||
|
||||
old_updated_at = stamped.updated_at
|
||||
|
||||
Time.forced_now_time = 5.minutes.from_now
|
||||
stamped.lft_will_change!
|
||||
stamped.save
|
||||
|
||||
assert_equal Time.now, stamped.updated_at
|
||||
assert_equal old_updated_at, stamped.created_at
|
||||
end
|
||||
|
||||
def test_create_turned_off
|
||||
Mixin.record_timestamps = false
|
||||
|
||||
mixin = Mixin.new
|
||||
|
||||
assert_nil mixin.updated_at
|
||||
mixin.save
|
||||
assert_nil mixin.updated_at
|
||||
|
||||
# Make sure Mixin.record_timestamps gets reset, even if this test fails,
|
||||
# so that other tests do not fail because Mixin.record_timestamps == false
|
||||
rescue Exception => e
|
||||
raise e
|
||||
ensure
|
||||
Mixin.record_timestamps = true
|
||||
end
|
||||
|
||||
end
|
||||
39
vendor/rails/activerecord/test/cases/modules_test.rb
vendored
Normal file
39
vendor/rails/activerecord/test/cases/modules_test.rb
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
require "cases/helper"
|
||||
require 'models/company_in_module'
|
||||
|
||||
class ModulesTest < ActiveRecord::TestCase
|
||||
fixtures :accounts, :companies, :projects, :developers
|
||||
|
||||
def test_module_spanning_associations
|
||||
firm = MyApplication::Business::Firm.find(:first)
|
||||
assert !firm.clients.empty?, "Firm should have clients"
|
||||
assert_nil firm.class.table_name.match('::'), "Firm shouldn't have the module appear in its table name"
|
||||
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
|
||||
account = MyApplication::Billing::Account.find(:first, :order => 'id')
|
||||
assert_kind_of MyApplication::Business::Firm, account.firm
|
||||
assert_kind_of MyApplication::Billing::Firm, account.qualified_billing_firm
|
||||
assert_kind_of MyApplication::Billing::Firm, account.unqualified_billing_firm
|
||||
assert_kind_of MyApplication::Billing::Nested::Firm, account.nested_qualified_billing_firm
|
||||
assert_kind_of MyApplication::Billing::Nested::Firm, account.nested_unqualified_billing_firm
|
||||
end
|
||||
|
||||
def test_find_account_and_include_company
|
||||
account = MyApplication::Billing::Account.find(1, :include => :firm)
|
||||
assert_kind_of MyApplication::Business::Firm, account.instance_variable_get('@firm')
|
||||
assert_kind_of MyApplication::Business::Firm, account.firm
|
||||
end
|
||||
|
||||
def test_table_name
|
||||
assert_equal 'accounts', MyApplication::Billing::Account.table_name, 'table_name for ActiveRecord model in module'
|
||||
assert_equal 'companies', MyApplication::Business::Client.table_name, 'table_name for ActiveRecord model subclass'
|
||||
assert_equal 'company_contacts', MyApplication::Business::Client::Contact.table_name, 'table_name for ActiveRecord model enclosed by another ActiveRecord model'
|
||||
end
|
||||
end
|
||||
85
vendor/rails/activerecord/test/cases/multiple_db_test.rb
vendored
Normal file
85
vendor/rails/activerecord/test/cases/multiple_db_test.rb
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
require "cases/helper"
|
||||
require 'models/entrant'
|
||||
|
||||
# So we can test whether Course.connection survives a reload.
|
||||
require_dependency 'models/course'
|
||||
|
||||
class MultipleDbTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
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
|
||||
|
||||
def test_course_connection_should_survive_dependency_reload
|
||||
assert Course.connection
|
||||
|
||||
ActiveSupport::Dependencies.clear
|
||||
Object.send(:remove_const, :Course)
|
||||
require_dependency 'models/course'
|
||||
|
||||
assert Course.connection
|
||||
end
|
||||
|
||||
def test_transactions_across_databases
|
||||
c1 = Course.find(1)
|
||||
e1 = Entrant.find(1)
|
||||
|
||||
begin
|
||||
Course.transaction do
|
||||
Entrant.transaction do
|
||||
c1.name = "Typo"
|
||||
e1.name = "Typo"
|
||||
c1.save
|
||||
e1.save
|
||||
raise "No I messed up."
|
||||
end
|
||||
end
|
||||
rescue
|
||||
# Yup caught it
|
||||
end
|
||||
|
||||
assert_equal "Typo", c1.name
|
||||
assert_equal "Typo", e1.name
|
||||
|
||||
assert_equal "Ruby Development", Course.find(1).name
|
||||
assert_equal "Ruby Developer", Entrant.find(1).name
|
||||
end
|
||||
end
|
||||
280
vendor/rails/activerecord/test/cases/named_scope_test.rb
vendored
Normal file
280
vendor/rails/activerecord/test/cases/named_scope_test.rb
vendored
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/topic'
|
||||
require 'models/comment'
|
||||
require 'models/reply'
|
||||
require 'models/author'
|
||||
require 'models/developer'
|
||||
|
||||
class NamedScopeTest < ActiveRecord::TestCase
|
||||
fixtures :posts, :authors, :topics, :comments, :author_addresses
|
||||
|
||||
def test_implements_enumerable
|
||||
assert !Topic.find(:all).empty?
|
||||
|
||||
assert_equal Topic.find(:all), Topic.base
|
||||
assert_equal Topic.find(:all), Topic.base.to_a
|
||||
assert_equal Topic.find(:first), Topic.base.first
|
||||
assert_equal Topic.find(:all), Topic.base.each { |i| i }
|
||||
end
|
||||
|
||||
def test_found_items_are_cached
|
||||
Topic.columns
|
||||
all_posts = Topic.base
|
||||
|
||||
assert_queries(1) do
|
||||
all_posts.collect
|
||||
all_posts.collect
|
||||
end
|
||||
end
|
||||
|
||||
def test_reload_expires_cache_of_found_items
|
||||
all_posts = Topic.base
|
||||
all_posts.inspect
|
||||
|
||||
new_post = Topic.create!
|
||||
assert !all_posts.include?(new_post)
|
||||
assert all_posts.reload.include?(new_post)
|
||||
end
|
||||
|
||||
def test_delegates_finds_and_calculations_to_the_base_class
|
||||
assert !Topic.find(:all).empty?
|
||||
|
||||
assert_equal Topic.find(:all), Topic.base.find(:all)
|
||||
assert_equal Topic.find(:first), Topic.base.find(:first)
|
||||
assert_equal Topic.count, Topic.base.count
|
||||
assert_equal Topic.average(:replies_count), Topic.base.average(:replies_count)
|
||||
end
|
||||
|
||||
def test_scope_should_respond_to_own_methods_and_methods_of_the_proxy
|
||||
assert Topic.approved.respond_to?(:proxy_found)
|
||||
assert Topic.approved.respond_to?(:count)
|
||||
assert Topic.approved.respond_to?(:length)
|
||||
end
|
||||
|
||||
def test_respond_to_respects_include_private_parameter
|
||||
assert !Topic.approved.respond_to?(:load_found)
|
||||
assert Topic.approved.respond_to?(:load_found, true)
|
||||
end
|
||||
|
||||
def test_subclasses_inherit_scopes
|
||||
assert Topic.scopes.include?(:base)
|
||||
|
||||
assert Reply.scopes.include?(:base)
|
||||
assert_equal Reply.find(:all), Reply.base
|
||||
end
|
||||
|
||||
def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified
|
||||
assert !Topic.find(:all, :conditions => {:approved => true}).empty?
|
||||
|
||||
assert_equal Topic.find(:all, :conditions => {:approved => true}), Topic.approved
|
||||
assert_equal Topic.count(:conditions => {:approved => true}), Topic.approved.count
|
||||
end
|
||||
|
||||
def test_scopes_with_string_name_can_be_composed
|
||||
# NOTE that scopes defined with a string as a name worked on their own
|
||||
# but when called on another scope the other scope was completely replaced
|
||||
assert_equal Topic.replied.approved, Topic.replied.approved_as_string
|
||||
end
|
||||
|
||||
def test_scopes_can_be_specified_with_deep_hash_conditions
|
||||
assert_equal Topic.replied.approved, Topic.replied.approved_as_hash_condition
|
||||
end
|
||||
|
||||
def test_scopes_are_composable
|
||||
assert_equal (approved = Topic.find(:all, :conditions => {:approved => true})), Topic.approved
|
||||
assert_equal (replied = Topic.find(:all, :conditions => 'replies_count > 0')), Topic.replied
|
||||
assert !(approved == replied)
|
||||
assert !(approved & replied).empty?
|
||||
|
||||
assert_equal approved & replied, Topic.approved.replied
|
||||
end
|
||||
|
||||
def test_procedural_scopes
|
||||
topics_written_before_the_third = Topic.find(:all, :conditions => ['written_on < ?', topics(:third).written_on])
|
||||
topics_written_before_the_second = Topic.find(:all, :conditions => ['written_on < ?', topics(:second).written_on])
|
||||
assert_not_equal topics_written_before_the_second, topics_written_before_the_third
|
||||
|
||||
assert_equal topics_written_before_the_third, Topic.written_before(topics(:third).written_on)
|
||||
assert_equal topics_written_before_the_second, Topic.written_before(topics(:second).written_on)
|
||||
end
|
||||
|
||||
def test_scopes_with_joins
|
||||
address = author_addresses(:david_address)
|
||||
posts_with_authors_at_address = Post.find(
|
||||
:all, :joins => 'JOIN authors ON authors.id = posts.author_id',
|
||||
:conditions => [ 'authors.author_address_id = ?', address.id ]
|
||||
)
|
||||
assert_equal posts_with_authors_at_address, Post.with_authors_at_address(address)
|
||||
end
|
||||
|
||||
def test_scopes_with_joins_respects_custom_select
|
||||
address = author_addresses(:david_address)
|
||||
posts_with_authors_at_address_titles = Post.find(:all,
|
||||
:select => 'title',
|
||||
:joins => 'JOIN authors ON authors.id = posts.author_id',
|
||||
:conditions => [ 'authors.author_address_id = ?', address.id ]
|
||||
)
|
||||
assert_equal posts_with_authors_at_address_titles, Post.with_authors_at_address(address).find(:all, :select => 'title')
|
||||
end
|
||||
|
||||
def test_extensions
|
||||
assert_equal 1, Topic.anonymous_extension.one
|
||||
assert_equal 2, Topic.named_extension.two
|
||||
end
|
||||
|
||||
def test_multiple_extensions
|
||||
assert_equal 2, Topic.multiple_extensions.extension_two
|
||||
assert_equal 1, Topic.multiple_extensions.extension_one
|
||||
end
|
||||
|
||||
def test_has_many_associations_have_access_to_named_scopes
|
||||
assert_not_equal Post.containing_the_letter_a, authors(:david).posts
|
||||
assert !Post.containing_the_letter_a.empty?
|
||||
|
||||
assert_equal authors(:david).posts & Post.containing_the_letter_a, authors(:david).posts.containing_the_letter_a
|
||||
end
|
||||
|
||||
def test_has_many_through_associations_have_access_to_named_scopes
|
||||
assert_not_equal Comment.containing_the_letter_e, authors(:david).comments
|
||||
assert !Comment.containing_the_letter_e.empty?
|
||||
|
||||
assert_equal authors(:david).comments & Comment.containing_the_letter_e, authors(:david).comments.containing_the_letter_e
|
||||
end
|
||||
|
||||
def test_active_records_have_scope_named__all__
|
||||
assert !Topic.find(:all).empty?
|
||||
|
||||
assert_equal Topic.find(:all), Topic.base
|
||||
end
|
||||
|
||||
def test_active_records_have_scope_named__scoped__
|
||||
assert !Topic.find(:all, scope = {:conditions => "content LIKE '%Have%'"}).empty?
|
||||
|
||||
assert_equal Topic.find(:all, scope), Topic.scoped(scope)
|
||||
end
|
||||
|
||||
def test_proxy_options
|
||||
expected_proxy_options = { :conditions => { :approved => true } }
|
||||
assert_equal expected_proxy_options, Topic.approved.proxy_options
|
||||
end
|
||||
|
||||
def test_first_and_last_should_support_find_options
|
||||
assert_equal Topic.base.first(:order => 'title'), Topic.base.find(:first, :order => 'title')
|
||||
assert_equal Topic.base.last(:order => 'title'), Topic.base.find(:last, :order => 'title')
|
||||
end
|
||||
|
||||
def test_first_and_last_should_allow_integers_for_limit
|
||||
assert_equal Topic.base.first(2), Topic.base.to_a.first(2)
|
||||
assert_equal Topic.base.last(2), Topic.base.to_a.last(2)
|
||||
end
|
||||
|
||||
def test_first_and_last_should_not_use_query_when_results_are_loaded
|
||||
topics = Topic.base
|
||||
topics.reload # force load
|
||||
assert_no_queries do
|
||||
topics.first
|
||||
topics.last
|
||||
end
|
||||
end
|
||||
|
||||
def test_first_and_last_find_options_should_use_query_when_results_are_loaded
|
||||
topics = Topic.base
|
||||
topics.reload # force load
|
||||
assert_queries(2) do
|
||||
topics.first(:order => 'title')
|
||||
topics.last(:order => 'title')
|
||||
end
|
||||
end
|
||||
|
||||
def test_empty_should_not_load_results
|
||||
topics = Topic.base
|
||||
assert_queries(2) do
|
||||
topics.empty? # use count query
|
||||
topics.collect # force load
|
||||
topics.empty? # use loaded (no query)
|
||||
end
|
||||
end
|
||||
|
||||
def test_any_should_not_load_results
|
||||
topics = Topic.base
|
||||
assert_queries(2) do
|
||||
topics.any? # use count query
|
||||
topics.collect # force load
|
||||
topics.any? # use loaded (no query)
|
||||
end
|
||||
end
|
||||
|
||||
def test_any_should_call_proxy_found_if_using_a_block
|
||||
topics = Topic.base
|
||||
assert_queries(1) do
|
||||
topics.expects(:empty?).never
|
||||
topics.any? { true }
|
||||
end
|
||||
end
|
||||
|
||||
def test_any_should_not_fire_query_if_named_scope_loaded
|
||||
topics = Topic.base
|
||||
topics.collect # force load
|
||||
assert_no_queries { assert topics.any? }
|
||||
end
|
||||
|
||||
def test_should_build_with_proxy_options
|
||||
topic = Topic.approved.build({})
|
||||
assert topic.approved
|
||||
end
|
||||
|
||||
def test_should_build_new_with_proxy_options
|
||||
topic = Topic.approved.new
|
||||
assert topic.approved
|
||||
end
|
||||
|
||||
def test_should_create_with_proxy_options
|
||||
topic = Topic.approved.create({})
|
||||
assert topic.approved
|
||||
end
|
||||
|
||||
def test_should_create_with_bang_with_proxy_options
|
||||
topic = Topic.approved.create!({})
|
||||
assert topic.approved
|
||||
end
|
||||
|
||||
def test_should_build_with_proxy_options_chained
|
||||
topic = Topic.approved.by_lifo.build({})
|
||||
assert topic.approved
|
||||
assert_equal 'lifo', topic.author_name
|
||||
end
|
||||
|
||||
def test_find_all_should_behave_like_select
|
||||
assert_equal Topic.base.select(&:approved), Topic.base.find_all(&:approved)
|
||||
end
|
||||
|
||||
def test_rand_should_select_a_random_object_from_proxy
|
||||
assert Topic.approved.rand.is_a?(Topic)
|
||||
end
|
||||
|
||||
def test_should_use_where_in_query_for_named_scope
|
||||
assert_equal Developer.find_all_by_name('Jamis'), Developer.find_all_by_id(Developer.jamises)
|
||||
end
|
||||
|
||||
def test_size_should_use_count_when_results_are_not_loaded
|
||||
topics = Topic.base
|
||||
assert_queries(1) do
|
||||
assert_sql(/COUNT/i) { topics.size }
|
||||
end
|
||||
end
|
||||
|
||||
def test_size_should_use_length_when_results_are_loaded
|
||||
topics = Topic.base
|
||||
topics.reload # force load
|
||||
assert_no_queries do
|
||||
topics.size # use loaded (no query)
|
||||
end
|
||||
end
|
||||
|
||||
def test_chaining_with_duplicate_joins
|
||||
join = "INNER JOIN comments ON comments.post_id = posts.id"
|
||||
post = Post.find(1)
|
||||
assert_equal post.comments.size, Post.scoped(:joins => join).scoped(:joins => join, :conditions => "posts.id = #{post.id}").size
|
||||
end
|
||||
end
|
||||
101
vendor/rails/activerecord/test/cases/pk_test.rb
vendored
Normal file
101
vendor/rails/activerecord/test/cases/pk_test.rb
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/subscriber'
|
||||
require 'models/movie'
|
||||
require 'models/keyboard'
|
||||
require 'models/mixed_case_monkey'
|
||||
|
||||
class PrimaryKeysTest < ActiveRecord::TestCase
|
||||
fixtures :topics, :subscribers, :movies, :mixed_case_monkeys
|
||||
|
||||
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_customized_primary_key_auto_assigns_on_save
|
||||
Keyboard.delete_all
|
||||
keyboard = Keyboard.new(:name => 'HHKB')
|
||||
assert_nothing_raised { keyboard.save! }
|
||||
assert_equal keyboard.id, Keyboard.find_by_name('HHKB').id
|
||||
end
|
||||
|
||||
def test_customized_primary_key_can_be_get_before_saving
|
||||
keyboard = Keyboard.new
|
||||
assert_nil keyboard.id
|
||||
assert_nothing_raised { assert_nil keyboard.key_number }
|
||||
end
|
||||
|
||||
def test_customized_string_primary_key_settable_before_save
|
||||
subscriber = Subscriber.new
|
||||
assert_nothing_raised { subscriber.id = 'webster123' }
|
||||
assert_equal 'webster123', subscriber.id
|
||||
assert_equal 'webster123', subscriber.nick
|
||||
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! }
|
||||
assert_equal("jdoe", subscriber.id)
|
||||
|
||||
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
|
||||
Topic.reset_primary_key
|
||||
assert_equal "topicid", Topic.primary_key
|
||||
|
||||
ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
|
||||
Topic.reset_primary_key
|
||||
assert_equal "topic_id", Topic.primary_key
|
||||
|
||||
ActiveRecord::Base.primary_key_prefix_type = nil
|
||||
Topic.reset_primary_key
|
||||
assert_equal "id", Topic.primary_key
|
||||
end
|
||||
|
||||
def test_delete_should_quote_pkey
|
||||
assert_nothing_raised { MixedCaseMonkey.delete(1) }
|
||||
end
|
||||
def test_update_counters_should_quote_pkey_and_quote_counter_columns
|
||||
assert_nothing_raised { MixedCaseMonkey.update_counters(1, :fleaCount => 99) }
|
||||
end
|
||||
def test_find_with_one_id_should_quote_pkey
|
||||
assert_nothing_raised { MixedCaseMonkey.find(1) }
|
||||
end
|
||||
def test_find_with_multiple_ids_should_quote_pkey
|
||||
assert_nothing_raised { MixedCaseMonkey.find([1,2]) }
|
||||
end
|
||||
def test_instance_update_should_quote_pkey
|
||||
assert_nothing_raised { MixedCaseMonkey.find(1).save }
|
||||
end
|
||||
def test_instance_destroy_should_quote_pkey
|
||||
assert_nothing_raised { MixedCaseMonkey.find(1).destroy }
|
||||
end
|
||||
end
|
||||
103
vendor/rails/activerecord/test/cases/pooled_connections_test.rb
vendored
Normal file
103
vendor/rails/activerecord/test/cases/pooled_connections_test.rb
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
require "cases/helper"
|
||||
|
||||
class PooledConnectionsTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
super
|
||||
@connection = ActiveRecord::Base.remove_connection
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActiveRecord::Base.clear_all_connections!
|
||||
ActiveRecord::Base.establish_connection(@connection)
|
||||
super
|
||||
end
|
||||
|
||||
def checkout_connections
|
||||
ActiveRecord::Base.establish_connection(@connection.merge({:pool => 2, :wait_timeout => 0.3}))
|
||||
@connections = []
|
||||
@timed_out = 0
|
||||
|
||||
4.times do
|
||||
Thread.new do
|
||||
begin
|
||||
@connections << ActiveRecord::Base.connection_pool.checkout
|
||||
rescue ActiveRecord::ConnectionTimeoutError
|
||||
@timed_out += 1
|
||||
end
|
||||
end.join
|
||||
end
|
||||
end
|
||||
|
||||
# Will deadlock due to lack of Monitor timeouts in 1.9
|
||||
if RUBY_VERSION < '1.9'
|
||||
def test_pooled_connection_checkout
|
||||
checkout_connections
|
||||
assert_equal @connections.length, 2
|
||||
assert_equal @timed_out, 2
|
||||
end
|
||||
end
|
||||
|
||||
def checkout_checkin_connections(pool_size, threads)
|
||||
ActiveRecord::Base.establish_connection(@connection.merge({:pool => pool_size, :wait_timeout => 0.5}))
|
||||
@connection_count = 0
|
||||
@timed_out = 0
|
||||
threads.times do
|
||||
Thread.new do
|
||||
begin
|
||||
conn = ActiveRecord::Base.connection_pool.checkout
|
||||
sleep 0.1
|
||||
ActiveRecord::Base.connection_pool.checkin conn
|
||||
@connection_count += 1
|
||||
rescue ActiveRecord::ConnectionTimeoutError
|
||||
@timed_out += 1
|
||||
end
|
||||
end.join
|
||||
end
|
||||
end
|
||||
|
||||
def test_pooled_connection_checkin_one
|
||||
checkout_checkin_connections 1, 2
|
||||
assert_equal 2, @connection_count
|
||||
assert_equal 0, @timed_out
|
||||
end
|
||||
|
||||
def test_pooled_connection_checkin_two
|
||||
checkout_checkin_connections 2, 3
|
||||
assert_equal 3, @connection_count
|
||||
assert_equal 0, @timed_out
|
||||
end
|
||||
|
||||
def test_pooled_connection_checkout_existing_first
|
||||
ActiveRecord::Base.establish_connection(@connection.merge({:pool => 1}))
|
||||
conn_pool = ActiveRecord::Base.connection_pool
|
||||
conn = conn_pool.checkout
|
||||
conn_pool.checkin(conn)
|
||||
conn = conn_pool.checkout
|
||||
assert ActiveRecord::ConnectionAdapters::AbstractAdapter === conn
|
||||
conn_pool.checkin(conn)
|
||||
end
|
||||
|
||||
def test_not_connected_defined_connection_returns_false
|
||||
ActiveRecord::Base.establish_connection(@connection)
|
||||
assert ! ActiveRecord::Base.connected?
|
||||
end
|
||||
|
||||
def test_undefined_connection_returns_false
|
||||
old_handler = ActiveRecord::Base.connection_handler
|
||||
ActiveRecord::Base.connection_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
||||
assert_equal false, ActiveRecord::Base.connected?
|
||||
ensure
|
||||
ActiveRecord::Base.connection_handler = old_handler
|
||||
end
|
||||
end unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name
|
||||
|
||||
class AllowConcurrencyDeprecatedTest < ActiveRecord::TestCase
|
||||
def test_allow_concurrency_is_deprecated
|
||||
assert_deprecated('ActiveRecord::Base.allow_concurrency') do
|
||||
ActiveRecord::Base.allow_concurrency
|
||||
end
|
||||
assert_deprecated('ActiveRecord::Base.allow_concurrency=') do
|
||||
ActiveRecord::Base.allow_concurrency = true
|
||||
end
|
||||
end
|
||||
end
|
||||
127
vendor/rails/activerecord/test/cases/query_cache_test.rb
vendored
Normal file
127
vendor/rails/activerecord/test/cases/query_cache_test.rb
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/task'
|
||||
require 'models/course'
|
||||
require 'models/category'
|
||||
require 'models/post'
|
||||
|
||||
|
||||
class QueryCacheTest < ActiveRecord::TestCase
|
||||
fixtures :tasks, :topics, :categories, :posts, :categories_posts
|
||||
|
||||
def test_find_queries
|
||||
assert_queries(2) { Task.find(1); Task.find(1) }
|
||||
end
|
||||
|
||||
def test_find_queries_with_cache
|
||||
Task.cache do
|
||||
assert_queries(1) { Task.find(1); Task.find(1) }
|
||||
end
|
||||
end
|
||||
|
||||
def test_count_queries_with_cache
|
||||
Task.cache do
|
||||
assert_queries(1) { Task.count; Task.count }
|
||||
end
|
||||
end
|
||||
|
||||
def test_query_cache_dups_results_correctly
|
||||
Task.cache do
|
||||
now = Time.now.utc
|
||||
task = Task.find 1
|
||||
assert_not_equal now, task.starting
|
||||
task.starting = now
|
||||
task.reload
|
||||
assert_not_equal now, task.starting
|
||||
end
|
||||
end
|
||||
|
||||
def test_cache_is_flat
|
||||
Task.cache do
|
||||
Topic.columns # don't count this query
|
||||
assert_queries(1) { Topic.find(1); Topic.find(1); }
|
||||
end
|
||||
|
||||
ActiveRecord::Base.cache do
|
||||
assert_queries(1) { Task.find(1); Task.find(1) }
|
||||
end
|
||||
end
|
||||
|
||||
def test_cache_does_not_wrap_string_results_in_arrays
|
||||
Task.cache do
|
||||
assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
uses_mocha 'QueryCacheExpiryTest' do
|
||||
|
||||
class QueryCacheExpiryTest < ActiveRecord::TestCase
|
||||
fixtures :tasks, :posts, :categories, :categories_posts
|
||||
|
||||
def test_find
|
||||
Task.connection.expects(:clear_query_cache).times(1)
|
||||
|
||||
assert !Task.connection.query_cache_enabled
|
||||
Task.cache do
|
||||
assert Task.connection.query_cache_enabled
|
||||
Task.find(1)
|
||||
|
||||
Task.uncached do
|
||||
assert !Task.connection.query_cache_enabled
|
||||
Task.find(1)
|
||||
end
|
||||
|
||||
assert Task.connection.query_cache_enabled
|
||||
end
|
||||
assert !Task.connection.query_cache_enabled
|
||||
end
|
||||
|
||||
def test_update
|
||||
Task.connection.expects(:clear_query_cache).times(2)
|
||||
|
||||
Task.cache do
|
||||
task = Task.find(1)
|
||||
task.starting = Time.now.utc
|
||||
task.save!
|
||||
end
|
||||
end
|
||||
|
||||
def test_destroy
|
||||
Task.connection.expects(:clear_query_cache).times(2)
|
||||
|
||||
Task.cache do
|
||||
Task.find(1).destroy
|
||||
end
|
||||
end
|
||||
|
||||
def test_insert
|
||||
ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
|
||||
|
||||
Task.cache do
|
||||
Task.create!
|
||||
end
|
||||
end
|
||||
|
||||
def test_cache_is_expired_by_habtm_update
|
||||
ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
|
||||
ActiveRecord::Base.cache do
|
||||
c = Category.find(:first)
|
||||
p = Post.find(:first)
|
||||
p.categories << c
|
||||
end
|
||||
end
|
||||
|
||||
def test_cache_is_expired_by_habtm_delete
|
||||
ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
|
||||
ActiveRecord::Base.cache do
|
||||
c = Category.find(1)
|
||||
p = Post.find(1)
|
||||
assert p.categories.any?
|
||||
p.categories.delete_all
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
107
vendor/rails/activerecord/test/cases/readonly_test.rb
vendored
Normal file
107
vendor/rails/activerecord/test/cases/readonly_test.rb
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
require "cases/helper"
|
||||
require 'models/post'
|
||||
require 'models/comment'
|
||||
require 'models/developer'
|
||||
require 'models/project'
|
||||
require 'models/reader'
|
||||
require 'models/person'
|
||||
|
||||
# Dummy class methods to test implicit association scoping.
|
||||
def Comment.foo() find :first end
|
||||
def Project.foo() find :first end
|
||||
|
||||
|
||||
class ReadOnlyTest < ActiveRecord::TestCase
|
||||
fixtures :posts, :comments, :developers, :projects, :developers_projects
|
||||
|
||||
def test_cant_save_readonly_record
|
||||
dev = Developer.find(1)
|
||||
assert !dev.readonly?
|
||||
|
||||
dev.readonly!
|
||||
assert dev.readonly?
|
||||
|
||||
assert_nothing_raised do
|
||||
dev.name = 'Luscious forbidden fruit.'
|
||||
assert !dev.save
|
||||
dev.name = 'Forbidden.'
|
||||
end
|
||||
assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save }
|
||||
assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save! }
|
||||
end
|
||||
|
||||
|
||||
def test_find_with_readonly_option
|
||||
Developer.find(:all).each { |d| assert !d.readonly? }
|
||||
Developer.find(:all, :readonly => false).each { |d| assert !d.readonly? }
|
||||
Developer.find(:all, :readonly => true).each { |d| assert d.readonly? }
|
||||
end
|
||||
|
||||
|
||||
def test_find_with_joins_option_implies_readonly
|
||||
# Blank joins don't count.
|
||||
Developer.find(:all, :joins => ' ').each { |d| assert !d.readonly? }
|
||||
Developer.find(:all, :joins => ' ', :readonly => false).each { |d| assert !d.readonly? }
|
||||
|
||||
# Others do.
|
||||
Developer.find(:all, :joins => ', projects').each { |d| assert d.readonly? }
|
||||
Developer.find(:all, :joins => ', projects', :readonly => false).each { |d| assert !d.readonly? }
|
||||
end
|
||||
|
||||
|
||||
def test_habtm_find_readonly
|
||||
dev = Developer.find(1)
|
||||
assert !dev.projects.empty?
|
||||
assert dev.projects.all?(&:readonly?)
|
||||
assert dev.projects.find(:all).all?(&:readonly?)
|
||||
assert dev.projects.find(:all, :readonly => true).all?(&:readonly?)
|
||||
end
|
||||
|
||||
def test_has_many_find_readonly
|
||||
post = Post.find(1)
|
||||
assert !post.comments.empty?
|
||||
assert !post.comments.any?(&:readonly?)
|
||||
assert !post.comments.find(:all).any?(&:readonly?)
|
||||
assert post.comments.find(:all, :readonly => true).all?(&:readonly?)
|
||||
end
|
||||
|
||||
def test_has_many_with_through_is_not_implicitly_marked_readonly
|
||||
assert people = Post.find(1).people
|
||||
assert !people.any?(&:readonly?)
|
||||
end
|
||||
|
||||
def test_readonly_scoping
|
||||
Post.with_scope(:find => { :conditions => '1=1' }) do
|
||||
assert !Post.find(1).readonly?
|
||||
assert Post.find(1, :readonly => true).readonly?
|
||||
assert !Post.find(1, :readonly => false).readonly?
|
||||
end
|
||||
|
||||
Post.with_scope(:find => { :joins => ' ' }) do
|
||||
assert !Post.find(1).readonly?
|
||||
assert Post.find(1, :readonly => true).readonly?
|
||||
assert !Post.find(1, :readonly => false).readonly?
|
||||
end
|
||||
|
||||
# Oracle barfs on this because the join includes unqualified and
|
||||
# conflicting column names
|
||||
unless current_adapter?(:OracleAdapter)
|
||||
Post.with_scope(:find => { :joins => ', developers' }) do
|
||||
assert Post.find(1).readonly?
|
||||
assert Post.find(1, :readonly => true).readonly?
|
||||
assert !Post.find(1, :readonly => false).readonly?
|
||||
end
|
||||
end
|
||||
|
||||
Post.with_scope(:find => { :readonly => true }) do
|
||||
assert Post.find(1).readonly?
|
||||
assert Post.find(1, :readonly => true).readonly?
|
||||
assert !Post.find(1, :readonly => false).readonly?
|
||||
end
|
||||
end
|
||||
|
||||
def test_association_collection_method_missing_scoping_not_readonly
|
||||
assert !Developer.find(1).projects.foo.readonly?
|
||||
assert !Post.find(1).comments.foo.readonly?
|
||||
end
|
||||
end
|
||||
184
vendor/rails/activerecord/test/cases/reflection_test.rb
vendored
Normal file
184
vendor/rails/activerecord/test/cases/reflection_test.rb
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/customer'
|
||||
require 'models/company'
|
||||
require 'models/company_in_module'
|
||||
require 'models/subscriber'
|
||||
|
||||
class ReflectionTest < ActiveRecord::TestCase
|
||||
fixtures :topics, :customers, :companies, :subscribers
|
||||
|
||||
def setup
|
||||
@first = Topic.find(1)
|
||||
end
|
||||
|
||||
def test_column_null_not_null
|
||||
subscriber = Subscriber.find(:first)
|
||||
assert subscriber.column_for_attribute("name").null
|
||||
assert !subscriber.column_for_attribute("nick").null
|
||||
end
|
||||
|
||||
def test_read_attribute_names
|
||||
assert_equal(
|
||||
%w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id type ).sort,
|
||||
@first.attribute_names
|
||||
)
|
||||
end
|
||||
|
||||
def test_columns
|
||||
assert_equal 12, Topic.columns.length
|
||||
end
|
||||
|
||||
def test_columns_are_returned_in_the_order_they_were_declared
|
||||
column_names = Topic.columns.map { |column| column.name }
|
||||
assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id type), column_names
|
||||
end
|
||||
|
||||
def test_content_columns
|
||||
content_columns = Topic.content_columns
|
||||
content_column_names = content_columns.map {|column| column.name}
|
||||
assert_equal 8, content_columns.length
|
||||
assert_equal %w(title author_name author_email_address written_on bonus_time last_read content approved).sort, content_column_names.sort
|
||||
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_column_null_not_null
|
||||
subscriber = Subscriber.find(:first)
|
||||
assert subscriber.column_for_attribute("name").null
|
||||
assert !subscriber.column_for_attribute("nick").null
|
||||
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_reflection_klass_for_nested_class_name
|
||||
reflection = ActiveRecord::Reflection::MacroReflection.new(nil, nil, { :class_name => 'MyApplication::Business::Company' }, nil)
|
||||
assert_nothing_raised do
|
||||
assert_equal MyApplication::Business::Company, reflection.klass
|
||||
end
|
||||
end
|
||||
|
||||
def test_aggregation_reflection
|
||||
reflection_for_address = ActiveRecord::Reflection::AggregateReflection.new(
|
||||
:composed_of, :address, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer
|
||||
)
|
||||
|
||||
reflection_for_balance = ActiveRecord::Reflection::AggregateReflection.new(
|
||||
:composed_of, :balance, { :class_name => "Money", :mapping => %w(balance amount) }, Customer
|
||||
)
|
||||
|
||||
reflection_for_gps_location = ActiveRecord::Reflection::AggregateReflection.new(
|
||||
:composed_of, :gps_location, { }, Customer
|
||||
)
|
||||
|
||||
assert Customer.reflect_on_all_aggregations.include?(reflection_for_gps_location)
|
||||
assert Customer.reflect_on_all_aggregations.include?(reflection_for_balance)
|
||||
assert Customer.reflect_on_all_aggregations.include?(reflection_for_address)
|
||||
|
||||
assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address)
|
||||
|
||||
assert_equal Address, Customer.reflect_on_aggregation(:address).klass
|
||||
|
||||
assert_equal Money, Customer.reflect_on_aggregation(:balance).klass
|
||||
end
|
||||
|
||||
def test_has_many_reflection
|
||||
reflection_for_clients = ActiveRecord::Reflection::AssociationReflection.new(:has_many, :clients, { :order => "id", :dependent => :destroy }, Firm)
|
||||
|
||||
assert_equal reflection_for_clients, Firm.reflect_on_association(:clients)
|
||||
|
||||
assert_equal Client, Firm.reflect_on_association(:clients).klass
|
||||
assert_equal 'companies', Firm.reflect_on_association(:clients).table_name
|
||||
|
||||
assert_equal Client, Firm.reflect_on_association(:clients_of_firm).klass
|
||||
assert_equal 'companies', Firm.reflect_on_association(:clients_of_firm).table_name
|
||||
end
|
||||
|
||||
def test_has_one_reflection
|
||||
reflection_for_account = ActiveRecord::Reflection::AssociationReflection.new(:has_one, :account, { :foreign_key => "firm_id", :dependent => :destroy }, Firm)
|
||||
assert_equal reflection_for_account, Firm.reflect_on_association(:account)
|
||||
|
||||
assert_equal Account, Firm.reflect_on_association(:account).klass
|
||||
assert_equal 'accounts', Firm.reflect_on_association(:account).table_name
|
||||
end
|
||||
|
||||
def test_belongs_to_inferred_foreign_key_from_assoc_name
|
||||
Company.belongs_to :foo
|
||||
assert_equal "foo_id", Company.reflect_on_association(:foo).primary_key_name
|
||||
Company.belongs_to :bar, :class_name => "Xyzzy"
|
||||
assert_equal "bar_id", Company.reflect_on_association(:bar).primary_key_name
|
||||
Company.belongs_to :baz, :class_name => "Xyzzy", :foreign_key => "xyzzy_id"
|
||||
assert_equal "xyzzy_id", Company.reflect_on_association(:baz).primary_key_name
|
||||
end
|
||||
|
||||
def test_association_reflection_in_modules
|
||||
assert_reflection MyApplication::Business::Firm,
|
||||
:clients_of_firm,
|
||||
:klass => MyApplication::Business::Client,
|
||||
:class_name => 'Client',
|
||||
:table_name => 'companies'
|
||||
|
||||
assert_reflection MyApplication::Billing::Account,
|
||||
:firm,
|
||||
:klass => MyApplication::Business::Firm,
|
||||
:class_name => 'MyApplication::Business::Firm',
|
||||
:table_name => 'companies'
|
||||
|
||||
assert_reflection MyApplication::Billing::Account,
|
||||
:qualified_billing_firm,
|
||||
:klass => MyApplication::Billing::Firm,
|
||||
:class_name => 'MyApplication::Billing::Firm',
|
||||
:table_name => 'companies'
|
||||
|
||||
assert_reflection MyApplication::Billing::Account,
|
||||
:unqualified_billing_firm,
|
||||
:klass => MyApplication::Billing::Firm,
|
||||
:class_name => 'Firm',
|
||||
:table_name => 'companies'
|
||||
|
||||
assert_reflection MyApplication::Billing::Account,
|
||||
:nested_qualified_billing_firm,
|
||||
:klass => MyApplication::Billing::Nested::Firm,
|
||||
:class_name => 'MyApplication::Billing::Nested::Firm',
|
||||
:table_name => 'companies'
|
||||
|
||||
assert_reflection MyApplication::Billing::Account,
|
||||
:nested_unqualified_billing_firm,
|
||||
:klass => MyApplication::Billing::Nested::Firm,
|
||||
:class_name => 'Nested::Firm',
|
||||
:table_name => 'companies'
|
||||
end
|
||||
|
||||
def test_reflection_of_all_associations
|
||||
# FIXME these assertions bust a lot
|
||||
assert_equal 26, Firm.reflect_on_all_associations.size
|
||||
assert_equal 20, Firm.reflect_on_all_associations(:has_many).size
|
||||
assert_equal 6, Firm.reflect_on_all_associations(:has_one).size
|
||||
assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
|
||||
end
|
||||
|
||||
def test_reflection_should_not_raise_error_when_compared_to_other_object
|
||||
assert_nothing_raised { Firm.reflections[:clients] == Object.new }
|
||||
end
|
||||
|
||||
def test_has_many_through_reflection
|
||||
assert_kind_of ActiveRecord::Reflection::ThroughReflection, Subscriber.reflect_on_association(:books)
|
||||
end
|
||||
|
||||
private
|
||||
def assert_reflection(klass, association, options)
|
||||
assert reflection = klass.reflect_on_association(association)
|
||||
options.each do |method, value|
|
||||
assert_equal(value, reflection.send(method))
|
||||
end
|
||||
end
|
||||
end
|
||||
20
vendor/rails/activerecord/test/cases/reload_models_test.rb
vendored
Normal file
20
vendor/rails/activerecord/test/cases/reload_models_test.rb
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
require "cases/helper"
|
||||
require 'models/owner'
|
||||
require 'models/pet'
|
||||
|
||||
class ReloadModelsTest < ActiveRecord::TestCase
|
||||
def test_has_one_with_reload
|
||||
pet = Pet.find_by_name('parrot')
|
||||
pet.owner = Owner.find_by_name('ashley')
|
||||
|
||||
# Reload the class Owner, simulating auto-reloading of model classes in a
|
||||
# development environment. Note that meanwhile the class Pet is not
|
||||
# reloaded, simulating a class that is present in a plugin.
|
||||
Object.class_eval { remove_const :Owner }
|
||||
Kernel.load(File.expand_path(File.join(File.dirname(__FILE__), "../models/owner.rb")))
|
||||
|
||||
pet = Pet.find_by_name('parrot')
|
||||
pet.owner = Owner.find_by_name('ashley')
|
||||
assert_equal pet.owner, Owner.find_by_name('ashley')
|
||||
end
|
||||
end
|
||||
176
vendor/rails/activerecord/test/cases/reserved_word_test_mysql.rb
vendored
Normal file
176
vendor/rails/activerecord/test/cases/reserved_word_test_mysql.rb
vendored
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
require "cases/helper"
|
||||
|
||||
class Group < ActiveRecord::Base
|
||||
Group.table_name = 'group'
|
||||
belongs_to :select, :class_name => 'Select'
|
||||
has_one :values
|
||||
end
|
||||
|
||||
class Select < ActiveRecord::Base
|
||||
Select.table_name = 'select'
|
||||
has_many :groups
|
||||
end
|
||||
|
||||
class Values < ActiveRecord::Base
|
||||
Values.table_name = 'values'
|
||||
end
|
||||
|
||||
class Distinct < ActiveRecord::Base
|
||||
Distinct.table_name = 'distinct'
|
||||
has_and_belongs_to_many :selects
|
||||
has_many :values, :through => :groups
|
||||
end
|
||||
|
||||
# a suite of tests to ensure the ConnectionAdapters#MysqlAdapter can handle tables with
|
||||
# reserved word names (ie: group, order, values, etc...)
|
||||
class MysqlReservedWordTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
|
||||
# we call execute directly here (and do similar below) because ActiveRecord::Base#create_table()
|
||||
# will fail with these table names if these test cases fail
|
||||
|
||||
create_tables_directly 'group'=>'id int auto_increment primary key, `order` varchar(255), select_id int',
|
||||
'select'=>'id int auto_increment primary key',
|
||||
'values'=>'id int auto_increment primary key, group_id int',
|
||||
'distinct'=>'id int auto_increment primary key',
|
||||
'distincts_selects'=>'distinct_id int, select_id int'
|
||||
end
|
||||
|
||||
def teardown
|
||||
drop_tables_directly ['group', 'select', 'values', 'distinct', 'distincts_selects', 'order']
|
||||
end
|
||||
|
||||
# create tables with reserved-word names and columns
|
||||
def test_create_tables
|
||||
assert_nothing_raised {
|
||||
@connection.create_table :order do |t|
|
||||
t.column :group, :string
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# rename tables with reserved-word names
|
||||
def test_rename_tables
|
||||
assert_nothing_raised { @connection.rename_table(:group, :order) }
|
||||
end
|
||||
|
||||
# alter column with a reserved-word name in a table with a reserved-word name
|
||||
def test_change_columns
|
||||
assert_nothing_raised { @connection.change_column_default(:group, :order, 'whatever') }
|
||||
#the quoting here will reveal any double quoting issues in change_column's interaction with the column method in the adapter
|
||||
assert_nothing_raised { @connection.change_column('group', 'order', :Int, :default => 0) }
|
||||
assert_nothing_raised { @connection.rename_column(:group, :order, :values) }
|
||||
end
|
||||
|
||||
# dump structure of table with reserved word name
|
||||
def test_structure_dump
|
||||
assert_nothing_raised { @connection.structure_dump }
|
||||
end
|
||||
|
||||
# introspect table with reserved word name
|
||||
def test_introspect
|
||||
assert_nothing_raised { @connection.columns(:group) }
|
||||
assert_nothing_raised { @connection.indexes(:group) }
|
||||
end
|
||||
|
||||
#fixtures
|
||||
self.use_instantiated_fixtures = true
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
#fixtures :group
|
||||
|
||||
def test_fixtures
|
||||
f = create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
||||
|
||||
assert_nothing_raised {
|
||||
f.each do |x|
|
||||
x.delete_existing_fixtures
|
||||
end
|
||||
}
|
||||
|
||||
assert_nothing_raised {
|
||||
f.each do |x|
|
||||
x.insert_fixtures
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
#activerecord model class with reserved-word table name
|
||||
def test_activerecord_model
|
||||
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
||||
x = nil
|
||||
assert_nothing_raised { x = Group.new }
|
||||
x.order = 'x'
|
||||
assert_nothing_raised { x.save }
|
||||
x.order = 'y'
|
||||
assert_nothing_raised { x.save }
|
||||
assert_nothing_raised { y = Group.find_by_order('y') }
|
||||
assert_nothing_raised { y = Group.find(1) }
|
||||
x = Group.find(1)
|
||||
end
|
||||
|
||||
# has_one association with reserved-word table name
|
||||
def test_has_one_associations
|
||||
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
||||
v = nil
|
||||
assert_nothing_raised { v = Group.find(1).values }
|
||||
assert_equal v.id, 2
|
||||
end
|
||||
|
||||
# belongs_to association with reserved-word table name
|
||||
def test_belongs_to_associations
|
||||
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
||||
gs = nil
|
||||
assert_nothing_raised { gs = Select.find(2).groups }
|
||||
assert_equal gs.length, 2
|
||||
assert(gs.collect{|x| x.id}.sort == [2, 3])
|
||||
end
|
||||
|
||||
# has_and_belongs_to_many with reserved-word table name
|
||||
def test_has_and_belongs_to_many
|
||||
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
||||
s = nil
|
||||
assert_nothing_raised { s = Distinct.find(1).selects }
|
||||
assert_equal s.length, 2
|
||||
assert(s.collect{|x|x.id}.sort == [1, 2])
|
||||
end
|
||||
|
||||
# activerecord model introspection with reserved-word table and column names
|
||||
def test_activerecord_introspection
|
||||
assert_nothing_raised { Group.table_exists? }
|
||||
assert_nothing_raised { Group.columns }
|
||||
end
|
||||
|
||||
# Calculations
|
||||
def test_calculations_work_with_reserved_words
|
||||
assert_nothing_raised { Group.count }
|
||||
end
|
||||
|
||||
def test_associations_work_with_reserved_words
|
||||
assert_nothing_raised { Select.find(:all, :include => [:groups]) }
|
||||
end
|
||||
|
||||
#the following functions were added to DRY test cases
|
||||
|
||||
private
|
||||
# custom fixture loader, uses Fixtures#create_fixtures and appends base_path to the current file's path
|
||||
def create_test_fixtures(*fixture_names)
|
||||
Fixtures.create_fixtures(FIXTURES_ROOT + "/reserved_words", fixture_names)
|
||||
end
|
||||
|
||||
# custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name
|
||||
def drop_tables_directly(table_names, connection = @connection)
|
||||
table_names.each do |name|
|
||||
connection.execute("DROP TABLE IF EXISTS `#{name}`")
|
||||
end
|
||||
end
|
||||
|
||||
# custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns
|
||||
def create_tables_directly (tables, connection = @connection)
|
||||
tables.each do |table_name, column_properties|
|
||||
connection.execute("CREATE TABLE `#{table_name}` ( #{column_properties} )")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
25
vendor/rails/activerecord/test/cases/sanitize_test.rb
vendored
Normal file
25
vendor/rails/activerecord/test/cases/sanitize_test.rb
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
require "cases/helper"
|
||||
require 'models/binary'
|
||||
|
||||
class SanitizeTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
end
|
||||
|
||||
def test_sanitize_sql_array_handles_string_interpolation
|
||||
quoted_bambi = ActiveRecord::Base.connection.quote_string("Bambi")
|
||||
assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi"])
|
||||
assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi".mb_chars])
|
||||
quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote_string("Bambi\nand\nThumper")
|
||||
assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper"])
|
||||
assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper".mb_chars])
|
||||
end
|
||||
|
||||
def test_sanitize_sql_array_handles_bind_variables
|
||||
quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
|
||||
assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi"])
|
||||
assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi".mb_chars])
|
||||
quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
|
||||
assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper"])
|
||||
assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper".mb_chars])
|
||||
end
|
||||
end
|
||||
75
vendor/rails/activerecord/test/cases/schema_authorization_test_postgresql.rb
vendored
Normal file
75
vendor/rails/activerecord/test/cases/schema_authorization_test_postgresql.rb
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
require "cases/helper"
|
||||
|
||||
class SchemaThing < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class SchemaAuthorizationTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
TABLE_NAME = 'schema_things'
|
||||
COLUMNS = [
|
||||
'id serial primary key',
|
||||
'name character varying(50)'
|
||||
]
|
||||
USERS = ['rails_pg_schema_user1', 'rails_pg_schema_user2']
|
||||
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
@connection.execute "SET search_path TO '$user',public"
|
||||
set_session_auth
|
||||
USERS.each do |u|
|
||||
@connection.execute "CREATE USER #{u}" rescue nil
|
||||
@connection.execute "CREATE SCHEMA AUTHORIZATION #{u}" rescue nil
|
||||
set_session_auth u
|
||||
@connection.execute "CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
|
||||
@connection.execute "INSERT INTO #{TABLE_NAME} (name) VALUES ('#{u}')"
|
||||
set_session_auth
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
set_session_auth
|
||||
@connection.execute "RESET search_path"
|
||||
USERS.each do |u|
|
||||
@connection.execute "DROP SCHEMA #{u} CASCADE"
|
||||
@connection.execute "DROP USER #{u}"
|
||||
end
|
||||
end
|
||||
|
||||
def test_schema_invisible
|
||||
assert_raise(ActiveRecord::StatementInvalid) do
|
||||
set_session_auth
|
||||
@connection.execute "SELECT * FROM #{TABLE_NAME}"
|
||||
end
|
||||
end
|
||||
|
||||
def test_schema_uniqueness
|
||||
assert_nothing_raised do
|
||||
set_session_auth
|
||||
USERS.each do |u|
|
||||
set_session_auth u
|
||||
assert_equal u, @connection.select_value("SELECT name FROM #{TABLE_NAME} WHERE id = 1")
|
||||
set_session_auth
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_sequence_schema_caching
|
||||
assert_nothing_raised do
|
||||
USERS.each do |u|
|
||||
set_session_auth u
|
||||
st = SchemaThing.new :name => 'TEST1'
|
||||
st.save!
|
||||
st = SchemaThing.new :id => 5, :name => 'TEST2'
|
||||
st.save!
|
||||
set_session_auth
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def set_session_auth auth = nil
|
||||
@connection.execute "SET SESSION AUTHORIZATION #{auth || 'default'}"
|
||||
end
|
||||
|
||||
end
|
||||
184
vendor/rails/activerecord/test/cases/schema_dumper_test.rb
vendored
Normal file
184
vendor/rails/activerecord/test/cases/schema_dumper_test.rb
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
require "cases/helper"
|
||||
require 'active_record/schema_dumper'
|
||||
require 'stringio'
|
||||
|
||||
|
||||
class SchemaDumperTest < ActiveRecord::TestCase
|
||||
def standard_dump
|
||||
stream = StringIO.new
|
||||
ActiveRecord::SchemaDumper.ignore_tables = []
|
||||
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
||||
stream.string
|
||||
end
|
||||
|
||||
def test_schema_dump
|
||||
output = standard_dump
|
||||
assert_match %r{create_table "accounts"}, output
|
||||
assert_match %r{create_table "authors"}, output
|
||||
assert_no_match %r{create_table "schema_migrations"}, output
|
||||
end
|
||||
|
||||
def test_schema_dump_excludes_sqlite_sequence
|
||||
output = standard_dump
|
||||
assert_no_match %r{create_table "sqlite_sequence"}, output
|
||||
end
|
||||
|
||||
def assert_line_up(lines, pattern, required = false)
|
||||
return assert(true) if lines.empty?
|
||||
matches = lines.map { |line| line.match(pattern) }
|
||||
assert matches.all? if required
|
||||
matches.compact!
|
||||
return assert(true) if matches.empty?
|
||||
assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
|
||||
end
|
||||
|
||||
def column_definition_lines(output = standard_dump)
|
||||
output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }
|
||||
end
|
||||
|
||||
def test_types_line_up
|
||||
column_definition_lines.each do |column_set|
|
||||
next if column_set.empty?
|
||||
|
||||
lengths = column_set.map do |column|
|
||||
if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
|
||||
match[0].length
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal 1, lengths.uniq.length
|
||||
end
|
||||
end
|
||||
|
||||
def test_arguments_line_up
|
||||
column_definition_lines.each do |column_set|
|
||||
assert_line_up(column_set, /:default => /)
|
||||
assert_line_up(column_set, /:limit => /)
|
||||
assert_line_up(column_set, /:null => /)
|
||||
end
|
||||
end
|
||||
|
||||
def test_no_dump_errors
|
||||
output = standard_dump
|
||||
assert_no_match %r{\# Could not dump table}, output
|
||||
end
|
||||
|
||||
def test_schema_dump_includes_not_null_columns
|
||||
stream = StringIO.new
|
||||
|
||||
ActiveRecord::SchemaDumper.ignore_tables = [/^[^r]/]
|
||||
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
||||
output = stream.string
|
||||
assert_match %r{:null => false}, output
|
||||
end
|
||||
|
||||
def test_schema_dump_includes_limit_constraint_for_integer_columns
|
||||
stream = StringIO.new
|
||||
|
||||
ActiveRecord::SchemaDumper.ignore_tables = [/^(?!integer_limits)/]
|
||||
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
||||
output = stream.string
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter)
|
||||
assert_match %r{c_int_1.*:limit => 2}, output
|
||||
assert_match %r{c_int_2.*:limit => 2}, output
|
||||
|
||||
# int 3 is 4 bytes in postgresql
|
||||
assert_match %r{c_int_3.*}, output
|
||||
assert_no_match %r{c_int_3.*:limit}, output
|
||||
|
||||
assert_match %r{c_int_4.*}, output
|
||||
assert_no_match %r{c_int_4.*:limit}, output
|
||||
elsif current_adapter?(:MysqlAdapter)
|
||||
assert_match %r{c_int_1.*:limit => 1}, output
|
||||
assert_match %r{c_int_2.*:limit => 2}, output
|
||||
assert_match %r{c_int_3.*:limit => 3}, output
|
||||
|
||||
assert_match %r{c_int_4.*}, output
|
||||
assert_no_match %r{c_int_4.*:limit}, output
|
||||
elsif current_adapter?(:SQLiteAdapter)
|
||||
assert_match %r{c_int_1.*:limit => 1}, output
|
||||
assert_match %r{c_int_2.*:limit => 2}, output
|
||||
assert_match %r{c_int_3.*:limit => 3}, output
|
||||
assert_match %r{c_int_4.*:limit => 4}, output
|
||||
end
|
||||
assert_match %r{c_int_without_limit.*}, output
|
||||
assert_no_match %r{c_int_without_limit.*:limit}, output
|
||||
|
||||
if current_adapter?(:SQLiteAdapter)
|
||||
assert_match %r{c_int_5.*:limit => 5}, output
|
||||
assert_match %r{c_int_6.*:limit => 6}, output
|
||||
assert_match %r{c_int_7.*:limit => 7}, output
|
||||
assert_match %r{c_int_8.*:limit => 8}, output
|
||||
else
|
||||
assert_match %r{c_int_5.*:limit => 8}, output
|
||||
assert_match %r{c_int_6.*:limit => 8}, output
|
||||
assert_match %r{c_int_7.*:limit => 8}, output
|
||||
assert_match %r{c_int_8.*:limit => 8}, output
|
||||
end
|
||||
end
|
||||
|
||||
def test_schema_dump_with_string_ignored_table
|
||||
stream = StringIO.new
|
||||
|
||||
ActiveRecord::SchemaDumper.ignore_tables = ['accounts']
|
||||
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
||||
output = stream.string
|
||||
assert_no_match %r{create_table "accounts"}, output
|
||||
assert_match %r{create_table "authors"}, output
|
||||
assert_no_match %r{create_table "schema_migrations"}, output
|
||||
end
|
||||
|
||||
def test_schema_dump_with_regexp_ignored_table
|
||||
stream = StringIO.new
|
||||
|
||||
ActiveRecord::SchemaDumper.ignore_tables = [/^account/]
|
||||
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
||||
output = stream.string
|
||||
assert_no_match %r{create_table "accounts"}, output
|
||||
assert_match %r{create_table "authors"}, output
|
||||
assert_no_match %r{create_table "schema_migrations"}, output
|
||||
end
|
||||
|
||||
def test_schema_dump_illegal_ignored_table_value
|
||||
stream = StringIO.new
|
||||
ActiveRecord::SchemaDumper.ignore_tables = [5]
|
||||
assert_raise(StandardError) do
|
||||
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:MysqlAdapter)
|
||||
def test_schema_dump_should_not_add_default_value_for_mysql_text_field
|
||||
output = standard_dump
|
||||
assert_match %r{t.text\s+"body",\s+:null => false$}, output
|
||||
end
|
||||
|
||||
def test_mysql_schema_dump_should_honor_nonstandard_primary_keys
|
||||
output = standard_dump
|
||||
match = output.match(%r{create_table "movies"(.*)do})
|
||||
assert_not_nil(match, "nonstandardpk table not found")
|
||||
assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
|
||||
end
|
||||
|
||||
def test_schema_dump_includes_length_for_mysql_blob_and_text_fields
|
||||
output = standard_dump
|
||||
assert_match %r{t.binary\s+"tiny_blob",\s+:limit => 255$}, output
|
||||
assert_match %r{t.binary\s+"normal_blob"$}, output
|
||||
assert_match %r{t.binary\s+"medium_blob",\s+:limit => 16777215$}, output
|
||||
assert_match %r{t.binary\s+"long_blob",\s+:limit => 2147483647$}, output
|
||||
assert_match %r{t.text\s+"tiny_text",\s+:limit => 255$}, output
|
||||
assert_match %r{t.text\s+"normal_text"$}, output
|
||||
assert_match %r{t.text\s+"medium_text",\s+:limit => 16777215$}, output
|
||||
assert_match %r{t.text\s+"long_text",\s+:limit => 2147483647$}, output
|
||||
end
|
||||
end
|
||||
|
||||
def test_schema_dump_includes_decimal_options
|
||||
stream = StringIO.new
|
||||
ActiveRecord::SchemaDumper.ignore_tables = [/^[^n]/]
|
||||
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
||||
output = stream.string
|
||||
assert_match %r{:precision => 3,[[:space:]]+:scale => 2,[[:space:]]+:default => 2.78}, output
|
||||
end
|
||||
end
|
||||
102
vendor/rails/activerecord/test/cases/schema_test_postgresql.rb
vendored
Normal file
102
vendor/rails/activerecord/test/cases/schema_test_postgresql.rb
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
require "cases/helper"
|
||||
|
||||
class SchemaTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
SCHEMA_NAME = 'test_schema'
|
||||
SCHEMA2_NAME = 'test_schema2'
|
||||
TABLE_NAME = 'things'
|
||||
INDEX_A_NAME = 'a_index_things_on_name'
|
||||
INDEX_B_NAME = 'b_index_things_on_different_columns_in_each_schema'
|
||||
INDEX_A_COLUMN = 'name'
|
||||
INDEX_B_COLUMN_S1 = 'email'
|
||||
INDEX_B_COLUMN_S2 = 'moment'
|
||||
COLUMNS = [
|
||||
'id integer',
|
||||
'name character varying(50)',
|
||||
'email character varying(50)',
|
||||
'moment timestamp without time zone default now()'
|
||||
]
|
||||
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
@connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
|
||||
@connection.execute "CREATE SCHEMA #{SCHEMA2_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
|
||||
@connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME} USING btree (#{INDEX_A_COLUMN});"
|
||||
@connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING btree (#{INDEX_A_COLUMN});"
|
||||
@connection.execute "CREATE INDEX #{INDEX_B_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME} USING btree (#{INDEX_B_COLUMN_S1});"
|
||||
@connection.execute "CREATE INDEX #{INDEX_B_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING btree (#{INDEX_B_COLUMN_S2});"
|
||||
end
|
||||
|
||||
def teardown
|
||||
@connection.execute "DROP SCHEMA #{SCHEMA2_NAME} CASCADE"
|
||||
@connection.execute "DROP SCHEMA #{SCHEMA_NAME} CASCADE"
|
||||
end
|
||||
|
||||
def test_with_schema_prefixed_table_name
|
||||
assert_nothing_raised do
|
||||
assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{TABLE_NAME}")
|
||||
end
|
||||
end
|
||||
|
||||
def test_with_schema_search_path
|
||||
assert_nothing_raised do
|
||||
with_schema_search_path(SCHEMA_NAME) do
|
||||
assert_equal COLUMNS, columns(TABLE_NAME)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_raise_on_unquoted_schema_name
|
||||
assert_raise(ActiveRecord::StatementInvalid) do
|
||||
with_schema_search_path '$user,public'
|
||||
end
|
||||
end
|
||||
|
||||
def test_without_schema_search_path
|
||||
assert_raise(ActiveRecord::StatementInvalid) { columns(TABLE_NAME) }
|
||||
end
|
||||
|
||||
def test_ignore_nil_schema_search_path
|
||||
assert_nothing_raised { with_schema_search_path nil }
|
||||
end
|
||||
|
||||
def test_dump_indexes_for_schema_one
|
||||
do_dump_index_tests_for_schema(SCHEMA_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S1)
|
||||
end
|
||||
|
||||
def test_dump_indexes_for_schema_two
|
||||
do_dump_index_tests_for_schema(SCHEMA2_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S2)
|
||||
end
|
||||
|
||||
private
|
||||
def columns(table_name)
|
||||
@connection.send(:column_definitions, table_name).map do |name, type, default|
|
||||
"#{name} #{type}" + (default ? " default #{default}" : '')
|
||||
end
|
||||
end
|
||||
|
||||
def with_schema_search_path(schema_search_path)
|
||||
@connection.schema_search_path = schema_search_path
|
||||
yield if block_given?
|
||||
ensure
|
||||
@connection.schema_search_path = "'$user', public"
|
||||
end
|
||||
|
||||
def do_dump_index_tests_for_schema(this_schema_name, first_index_column_name, second_index_column_name)
|
||||
with_schema_search_path(this_schema_name) do
|
||||
indexes = @connection.indexes(TABLE_NAME).sort_by {|i| i.name}
|
||||
assert_equal 2,indexes.size
|
||||
|
||||
do_dump_index_assertions_for_one_index(indexes[0], INDEX_A_NAME, first_index_column_name)
|
||||
do_dump_index_assertions_for_one_index(indexes[1], INDEX_B_NAME, second_index_column_name)
|
||||
end
|
||||
end
|
||||
|
||||
def do_dump_index_assertions_for_one_index(this_index, this_index_name, this_index_column)
|
||||
assert_equal TABLE_NAME, this_index.table
|
||||
assert_equal 1, this_index.columns.size
|
||||
assert_equal this_index_column, this_index.columns[0]
|
||||
assert_equal this_index_name, this_index.name
|
||||
end
|
||||
end
|
||||
47
vendor/rails/activerecord/test/cases/serialization_test.rb
vendored
Normal file
47
vendor/rails/activerecord/test/cases/serialization_test.rb
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
require "cases/helper"
|
||||
require 'models/contact'
|
||||
|
||||
class SerializationTest < ActiveRecord::TestCase
|
||||
FORMATS = [ :xml, :json ]
|
||||
|
||||
def setup
|
||||
@contact_attributes = {
|
||||
:name => 'aaron stack',
|
||||
:age => 25,
|
||||
:avatar => 'binarydata',
|
||||
:created_at => Time.utc(2006, 8, 1),
|
||||
:awesome => false,
|
||||
:preferences => { :gem => '<strong>ruby</strong>' }
|
||||
}
|
||||
|
||||
@contact = Contact.new(@contact_attributes)
|
||||
end
|
||||
|
||||
def test_serialize_should_be_reversible
|
||||
for format in FORMATS
|
||||
@serialized = Contact.new.send("to_#{format}")
|
||||
contact = Contact.new.send("from_#{format}", @serialized)
|
||||
|
||||
assert_equal @contact_attributes.keys.collect(&:to_s).sort, contact.attributes.keys.collect(&:to_s).sort, "For #{format}"
|
||||
end
|
||||
end
|
||||
|
||||
def test_serialize_should_allow_attribute_only_filtering
|
||||
for format in FORMATS
|
||||
@serialized = Contact.new(@contact_attributes).send("to_#{format}", :only => [ :age, :name ])
|
||||
contact = Contact.new.send("from_#{format}", @serialized)
|
||||
assert_equal @contact_attributes[:name], contact.name, "For #{format}"
|
||||
assert_nil contact.avatar, "For #{format}"
|
||||
end
|
||||
end
|
||||
|
||||
def test_serialize_should_allow_attribute_except_filtering
|
||||
for format in FORMATS
|
||||
@serialized = Contact.new(@contact_attributes).send("to_#{format}", :except => [ :age, :name ])
|
||||
contact = Contact.new.send("from_#{format}", @serialized)
|
||||
assert_nil contact.name, "For #{format}"
|
||||
assert_nil contact.age, "For #{format}"
|
||||
assert_equal @contact_attributes[:awesome], contact.awesome, "For #{format}"
|
||||
end
|
||||
end
|
||||
end
|
||||
17
vendor/rails/activerecord/test/cases/synonym_test_oracle.rb
vendored
Normal file
17
vendor/rails/activerecord/test/cases/synonym_test_oracle.rb
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/subject'
|
||||
|
||||
# confirm that synonyms work just like tables; in this case
|
||||
# the "subjects" table in Oracle (defined in oci.sql) is just
|
||||
# a synonym to the "topics" table
|
||||
|
||||
class TestOracleSynonym < ActiveRecord::TestCase
|
||||
|
||||
def test_oracle_synonym
|
||||
topic = Topic.new
|
||||
subject = Subject.new
|
||||
assert_equal(topic.attributes, subject.attributes)
|
||||
end
|
||||
|
||||
end
|
||||
357
vendor/rails/activerecord/test/cases/transactions_test.rb
vendored
Normal file
357
vendor/rails/activerecord/test/cases/transactions_test.rb
vendored
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
require 'models/developer'
|
||||
require 'models/book'
|
||||
|
||||
class TransactionTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
fixtures :topics, :developers
|
||||
|
||||
def setup
|
||||
@first, @second = Topic.find(1, 2).sort_by { |t| t.id }
|
||||
end
|
||||
|
||||
def test_successful
|
||||
Topic.transaction do
|
||||
@first.approved = true
|
||||
@second.approved = false
|
||||
@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 transaction_with_return
|
||||
Topic.transaction do
|
||||
@first.approved = true
|
||||
@second.approved = false
|
||||
@first.save
|
||||
@second.save
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
def test_successful_with_return
|
||||
class << Topic.connection
|
||||
alias :real_commit_db_transaction :commit_db_transaction
|
||||
def commit_db_transaction
|
||||
$committed = true
|
||||
real_commit_db_transaction
|
||||
end
|
||||
end
|
||||
|
||||
$committed = false
|
||||
transaction_with_return
|
||||
assert $committed
|
||||
|
||||
assert Topic.find(1).approved?, "First should have been approved"
|
||||
assert !Topic.find(2).approved?, "Second should have been unapproved"
|
||||
ensure
|
||||
class << Topic.connection
|
||||
alias :commit_db_transaction :real_commit_db_transaction rescue nil
|
||||
end
|
||||
end
|
||||
|
||||
def test_successful_with_instance_method
|
||||
@first.transaction do
|
||||
@first.approved = true
|
||||
@second.approved = false
|
||||
@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_raising_exception_in_callback_rollbacks_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 test_cancellation_from_before_destroy_rollbacks_in_destroy
|
||||
add_cancelling_before_destroy_with_db_side_effect_to_topic
|
||||
begin
|
||||
nbooks_before_destroy = Book.count
|
||||
status = @first.destroy
|
||||
assert !status
|
||||
assert_nothing_raised(ActiveRecord::RecordNotFound) { @first.reload }
|
||||
assert_equal nbooks_before_destroy, Book.count
|
||||
ensure
|
||||
remove_cancelling_before_destroy_with_db_side_effect_to_topic
|
||||
end
|
||||
end
|
||||
|
||||
def test_cancellation_from_before_filters_rollbacks_in_save
|
||||
%w(validation save).each do |filter|
|
||||
send("add_cancelling_before_#{filter}_with_db_side_effect_to_topic")
|
||||
begin
|
||||
nbooks_before_save = Book.count
|
||||
original_author_name = @first.author_name
|
||||
@first.author_name += '_this_should_not_end_up_in_the_db'
|
||||
status = @first.save
|
||||
assert !status
|
||||
assert_equal original_author_name, @first.reload.author_name
|
||||
assert_equal nbooks_before_save, Book.count
|
||||
ensure
|
||||
send("remove_cancelling_before_#{filter}_with_db_side_effect_to_topic")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_cancellation_from_before_filters_rollbacks_in_save!
|
||||
%w(validation save).each do |filter|
|
||||
send("add_cancelling_before_#{filter}_with_db_side_effect_to_topic")
|
||||
begin
|
||||
nbooks_before_save = Book.count
|
||||
original_author_name = @first.author_name
|
||||
@first.author_name += '_this_should_not_end_up_in_the_db'
|
||||
@first.save!
|
||||
flunk
|
||||
rescue => e
|
||||
assert_equal original_author_name, @first.reload.author_name
|
||||
assert_equal nbooks_before_save, Book.count
|
||||
ensure
|
||||
send("remove_cancelling_before_#{filter}_with_db_side_effect_to_topic")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_callback_rollback_in_create
|
||||
new_topic = Topic.new(
|
||||
:title => "A new topic",
|
||||
:author_name => "Ben",
|
||||
:author_email_address => "ben@example.com",
|
||||
:written_on => "2003-07-16t15:28:11.2233+01:00",
|
||||
:last_read => "2004-04-15",
|
||||
:bonus_time => "2005-01-30t15:28:00.00+01:00",
|
||||
:content => "Have a nice day",
|
||||
:approved => false)
|
||||
new_record_snapshot = new_topic.new_record?
|
||||
id_present = new_topic.has_attribute?(Topic.primary_key)
|
||||
id_snapshot = new_topic.id
|
||||
|
||||
# Make sure the second save gets the after_create callback called.
|
||||
2.times do
|
||||
begin
|
||||
add_exception_raising_after_create_callback_to_topic
|
||||
new_topic.approved = true
|
||||
new_topic.save
|
||||
flunk
|
||||
rescue => e
|
||||
assert_equal "Make the transaction rollback", e.message
|
||||
assert_equal new_record_snapshot, new_topic.new_record?, "The topic should have its old new_record value"
|
||||
assert_equal id_snapshot, new_topic.id, "The topic should have its old id"
|
||||
assert_equal id_present, new_topic.has_attribute?(Topic.primary_key)
|
||||
ensure
|
||||
remove_exception_raising_after_create_callback_to_topic
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_nested_explicit_transactions
|
||||
Topic.transaction do
|
||||
Topic.transaction do
|
||||
@first.approved = true
|
||||
@second.approved = false
|
||||
@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
|
||||
|
||||
def test_manually_rolling_back_a_transaction
|
||||
Topic.transaction do
|
||||
@first.approved = true
|
||||
@second.approved = false
|
||||
@first.save
|
||||
@second.save
|
||||
|
||||
raise ActiveRecord::Rollback
|
||||
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
|
||||
|
||||
uses_mocha 'mocking connection.commit_db_transaction' do
|
||||
def test_rollback_when_commit_raises
|
||||
Topic.connection.expects(:begin_db_transaction)
|
||||
Topic.connection.expects(:transaction_active?).returns(true) if current_adapter?(:PostgreSQLAdapter)
|
||||
Topic.connection.expects(:commit_db_transaction).raises('OH NOES')
|
||||
Topic.connection.expects(:rollback_db_transaction)
|
||||
|
||||
assert_raise RuntimeError do
|
||||
Topic.transaction do
|
||||
# do nothing
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_sqlite_add_column_in_transaction_raises_statement_invalid
|
||||
return true unless current_adapter?(:SQLite3Adapter, :SQLiteAdapter)
|
||||
|
||||
# Test first if column creation/deletion works correctly when no
|
||||
# transaction is in place.
|
||||
#
|
||||
# We go back to the connection for the column queries because
|
||||
# Topic.columns is cached and won't report changes to the DB
|
||||
|
||||
assert_nothing_raised do
|
||||
Topic.reset_column_information
|
||||
Topic.connection.add_column('topics', 'stuff', :string)
|
||||
assert Topic.column_names.include?('stuff')
|
||||
|
||||
Topic.reset_column_information
|
||||
Topic.connection.remove_column('topics', 'stuff')
|
||||
assert !Topic.column_names.include?('stuff')
|
||||
end
|
||||
|
||||
# Test now inside a transaction: add_column should raise a StatementInvalid
|
||||
Topic.transaction do
|
||||
assert_raises(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) }
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
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
|
||||
|
||||
def add_exception_raising_after_create_callback_to_topic
|
||||
Topic.class_eval { def after_create() raise "Make the transaction rollback" end }
|
||||
end
|
||||
|
||||
def remove_exception_raising_after_create_callback_to_topic
|
||||
Topic.class_eval { remove_method :after_create }
|
||||
end
|
||||
|
||||
%w(validation save destroy).each do |filter|
|
||||
define_method("add_cancelling_before_#{filter}_with_db_side_effect_to_topic") do
|
||||
Topic.class_eval "def before_#{filter}() Book.create; false end"
|
||||
end
|
||||
|
||||
define_method("remove_cancelling_before_#{filter}_with_db_side_effect_to_topic") do
|
||||
Topic.class_eval "remove_method :before_#{filter}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter)
|
||||
class ConcurrentTransactionTest < TransactionTest
|
||||
use_concurrent_connections
|
||||
|
||||
# This will cause transactions to overlap and fail unless they are performed on
|
||||
# separate database connections.
|
||||
def test_transaction_per_thread
|
||||
assert_nothing_raised do
|
||||
threads = (1..3).map do
|
||||
Thread.new do
|
||||
Topic.transaction do
|
||||
topic = Topic.find(1)
|
||||
topic.approved = !topic.approved?
|
||||
topic.save!
|
||||
topic.approved = !topic.approved?
|
||||
topic.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
threads.each { |t| t.join }
|
||||
end
|
||||
end
|
||||
|
||||
# Test for dirty reads among simultaneous transactions.
|
||||
def test_transaction_isolation__read_committed
|
||||
# Should be invariant.
|
||||
original_salary = Developer.find(1).salary
|
||||
temporary_salary = 200000
|
||||
|
||||
assert_nothing_raised do
|
||||
threads = (1..3).map do
|
||||
Thread.new do
|
||||
Developer.transaction do
|
||||
# Expect original salary.
|
||||
dev = Developer.find(1)
|
||||
assert_equal original_salary, dev.salary
|
||||
|
||||
dev.salary = temporary_salary
|
||||
dev.save!
|
||||
|
||||
# Expect temporary salary.
|
||||
dev = Developer.find(1)
|
||||
assert_equal temporary_salary, dev.salary
|
||||
|
||||
dev.salary = original_salary
|
||||
dev.save!
|
||||
|
||||
# Expect original salary.
|
||||
dev = Developer.find(1)
|
||||
assert_equal original_salary, dev.salary
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Keep our eyes peeled.
|
||||
threads << Thread.new do
|
||||
10.times do
|
||||
sleep 0.05
|
||||
Developer.transaction do
|
||||
# Always expect original salary.
|
||||
assert_equal original_salary, Developer.find(1).salary
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
threads.each { |t| t.join }
|
||||
end
|
||||
|
||||
assert_equal original_salary, Developer.find(1).salary
|
||||
end
|
||||
end
|
||||
end
|
||||
32
vendor/rails/activerecord/test/cases/unconnected_test.rb
vendored
Normal file
32
vendor/rails/activerecord/test/cases/unconnected_test.rb
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
require "cases/helper"
|
||||
|
||||
class TestRecord < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class TestUnconnectedAdapter < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
|
||||
def setup
|
||||
@underlying = ActiveRecord::Base.connection
|
||||
@specification = ActiveRecord::Base.remove_connection
|
||||
end
|
||||
|
||||
def teardown
|
||||
@underlying = nil
|
||||
ActiveRecord::Base.establish_connection(@specification)
|
||||
end
|
||||
|
||||
def test_connection_no_longer_established
|
||||
assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
||||
TestRecord.find(1)
|
||||
end
|
||||
|
||||
assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
||||
TestRecord.new.save
|
||||
end
|
||||
end
|
||||
|
||||
def test_underlying_adapter_no_longer_active
|
||||
assert !@underlying.active?, "Removed adapter should no longer be active"
|
||||
end
|
||||
end
|
||||
921
vendor/rails/activerecord/test/cases/validations_i18n_test.rb
vendored
Normal file
921
vendor/rails/activerecord/test/cases/validations_i18n_test.rb
vendored
Normal file
|
|
@ -0,0 +1,921 @@
|
|||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
|
||||
class ActiveRecordValidationsI18nTests < Test::Unit::TestCase
|
||||
def setup
|
||||
reset_callbacks Topic
|
||||
@topic = Topic.new
|
||||
@old_load_path, @old_backend = I18n.load_path, I18n.backend
|
||||
I18n.load_path.clear
|
||||
I18n.backend = I18n::Backend::Simple.new
|
||||
I18n.backend.store_translations('en', :activerecord => {:errors => {:messages => {:custom => nil}}})
|
||||
end
|
||||
|
||||
def teardown
|
||||
reset_callbacks Topic
|
||||
I18n.load_path.replace @old_load_path
|
||||
I18n.backend = @old_backend
|
||||
end
|
||||
|
||||
def unique_topic
|
||||
@unique ||= Topic.create :title => 'unique!'
|
||||
end
|
||||
|
||||
def replied_topic
|
||||
@replied_topic ||= begin
|
||||
topic = Topic.create(:title => "topic")
|
||||
topic.replies << Reply.new
|
||||
topic
|
||||
end
|
||||
end
|
||||
|
||||
def reset_callbacks(*models)
|
||||
models.each do |model|
|
||||
model.instance_variable_set("@validate_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
model.instance_variable_set("@validate_on_create_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
model.instance_variable_set("@validate_on_update_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
end
|
||||
end
|
||||
|
||||
def test_default_error_messages_is_deprecated
|
||||
assert_deprecated('ActiveRecord::Errors.default_error_messages') do
|
||||
ActiveRecord::Errors.default_error_messages
|
||||
end
|
||||
end
|
||||
|
||||
def test_percent_s_interpolation_syntax_in_error_messages_still_works
|
||||
ActiveSupport::Deprecation.silence do
|
||||
result = I18n.t :does_not_exist, :default => "%s interpolation syntax is deprecated", :value => 'this'
|
||||
assert_equal result, "this interpolation syntax is deprecated"
|
||||
end
|
||||
end
|
||||
|
||||
def test_percent_s_interpolation_syntax_in_error_messages_is_deprecated
|
||||
assert_deprecated('using %s in messages') do
|
||||
I18n.t :does_not_exist, :default => "%s interpolation syntax is deprected", :value => 'this'
|
||||
end
|
||||
end
|
||||
|
||||
def test_percent_d_interpolation_syntax_in_error_messages_still_works
|
||||
ActiveSupport::Deprecation.silence do
|
||||
result = I18n.t :does_not_exist, :default => "%d interpolation syntaxes are deprecated", :count => 2
|
||||
assert_equal result, "2 interpolation syntaxes are deprecated"
|
||||
end
|
||||
end
|
||||
|
||||
def test_percent_d_interpolation_syntax_in_error_messages_is_deprecated
|
||||
assert_deprecated('using %d in messages') do
|
||||
I18n.t :does_not_exist, :default => "%d interpolation syntaxes are deprected", :count => 2
|
||||
end
|
||||
end
|
||||
|
||||
# ActiveRecord::Errors
|
||||
uses_mocha 'ActiveRecord::Errors' do
|
||||
|
||||
def test_errors_generate_message_translates_custom_model_attribute_key
|
||||
|
||||
I18n.expects(:translate).with(
|
||||
:topic,
|
||||
{ :count => 1,
|
||||
:default => ['Topic'],
|
||||
:scope => [:activerecord, :models]
|
||||
}
|
||||
).returns('Topic')
|
||||
|
||||
I18n.expects(:translate).with(
|
||||
:"topic.title",
|
||||
{ :count => 1,
|
||||
:default => ['Title'],
|
||||
:scope => [:activerecord, :attributes]
|
||||
}
|
||||
).returns('Title')
|
||||
|
||||
I18n.expects(:translate).with(
|
||||
:"models.topic.attributes.title.invalid",
|
||||
:value => nil,
|
||||
:scope => [:activerecord, :errors],
|
||||
:default => [
|
||||
:"models.topic.invalid",
|
||||
'default from class def error 1',
|
||||
:"messages.invalid"],
|
||||
:attribute => "Title",
|
||||
:model => "Topic"
|
||||
).returns('default from class def error 1')
|
||||
|
||||
@topic.errors.generate_message :title, :invalid, :default => 'default from class def error 1'
|
||||
end
|
||||
|
||||
def test_errors_generate_message_translates_custom_model_attribute_keys_with_sti
|
||||
|
||||
I18n.expects(:translate).with(
|
||||
:reply,
|
||||
{ :count => 1,
|
||||
:default => [:topic, 'Reply'],
|
||||
:scope => [:activerecord, :models]
|
||||
}
|
||||
).returns('Reply')
|
||||
|
||||
I18n.expects(:translate).with(
|
||||
:"reply.title",
|
||||
{ :count => 1,
|
||||
:default => [:'topic.title', 'Title'],
|
||||
:scope => [:activerecord, :attributes]
|
||||
}
|
||||
).returns('Title')
|
||||
|
||||
I18n.expects(:translate).with(
|
||||
:"models.reply.attributes.title.invalid",
|
||||
:value => nil,
|
||||
:scope => [:activerecord, :errors],
|
||||
:default => [
|
||||
:"models.reply.invalid",
|
||||
:"models.topic.attributes.title.invalid",
|
||||
:"models.topic.invalid",
|
||||
'default from class def',
|
||||
:"messages.invalid"],
|
||||
:model => 'Reply',
|
||||
:attribute => 'Title'
|
||||
).returns("default from class def")
|
||||
|
||||
Reply.new.errors.generate_message :title, :invalid, :default => 'default from class def'
|
||||
|
||||
end
|
||||
|
||||
def test_errors_add_on_empty_generates_message
|
||||
@topic.errors.expects(:generate_message).with(:title, :empty, {:default => nil})
|
||||
@topic.errors.add_on_empty :title
|
||||
end
|
||||
|
||||
def test_errors_add_on_empty_generates_message_with_custom_default_message
|
||||
@topic.errors.expects(:generate_message).with(:title, :empty, {:default => 'custom'})
|
||||
@topic.errors.add_on_empty :title, 'custom'
|
||||
end
|
||||
|
||||
def test_errors_add_on_blank_generates_message
|
||||
@topic.errors.expects(:generate_message).with(:title, :blank, {:default => nil})
|
||||
@topic.errors.add_on_blank :title
|
||||
end
|
||||
|
||||
def test_errors_add_on_blank_generates_message_with_custom_default_message
|
||||
@topic.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'})
|
||||
@topic.errors.add_on_blank :title, 'custom'
|
||||
end
|
||||
|
||||
def test_errors_full_messages_translates_human_attribute_name_for_model_attributes
|
||||
@topic.errors.instance_variable_set :@errors, { 'title' => ['empty'] }
|
||||
I18n.expects(:translate).with(:"topic.title", :default => ['Title'], :scope => [:activerecord, :attributes], :count => 1).returns('Title')
|
||||
@topic.errors.full_messages :locale => 'en'
|
||||
end
|
||||
end
|
||||
|
||||
# ActiveRecord::Validations
|
||||
uses_mocha 'ActiveRecord::Validations' do
|
||||
# validates_confirmation_of w/ mocha
|
||||
|
||||
def test_validates_confirmation_of_generates_message
|
||||
Topic.validates_confirmation_of :title
|
||||
@topic.title_confirmation = 'foo'
|
||||
@topic.errors.expects(:generate_message).with(:title, :confirmation, {:default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_confirmation_of_generates_message_with_custom_default_message
|
||||
Topic.validates_confirmation_of :title, :message => 'custom'
|
||||
@topic.title_confirmation = 'foo'
|
||||
@topic.errors.expects(:generate_message).with(:title, :confirmation, {:default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_acceptance_of w/ mocha
|
||||
|
||||
def test_validates_acceptance_of_generates_message
|
||||
Topic.validates_acceptance_of :title, :allow_nil => false
|
||||
@topic.errors.expects(:generate_message).with(:title, :accepted, {:default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_acceptance_of_generates_message_with_custom_default_message
|
||||
Topic.validates_acceptance_of :title, :message => 'custom', :allow_nil => false
|
||||
@topic.errors.expects(:generate_message).with(:title, :accepted, {:default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_presence_of w/ mocha
|
||||
|
||||
def test_validates_presence_of_generates_message
|
||||
Topic.validates_presence_of :title
|
||||
@topic.errors.expects(:generate_message).with(:title, :blank, {:default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_presence_of_generates_message_with_custom_default_message
|
||||
Topic.validates_presence_of :title, :message => 'custom'
|
||||
@topic.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_generates_message_with_title_too_short
|
||||
Topic.validates_length_of :title, :within => 3..5
|
||||
@topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_generates_message_with_title_too_short_and_custom_default_message
|
||||
Topic.validates_length_of :title, :within => 3..5, :too_short => 'custom'
|
||||
@topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_generates_message_with_title_too_long
|
||||
Topic.validates_length_of :title, :within => 3..5
|
||||
@topic.title = 'this title is too long'
|
||||
@topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message
|
||||
Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom'
|
||||
@topic.title = 'this title is too long'
|
||||
@topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_length_of :within w/ mocha
|
||||
|
||||
def test_validates_length_of_within_generates_message_with_title_too_short
|
||||
Topic.validates_length_of :title, :within => 3..5
|
||||
@topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_generates_message_with_title_too_short_and_custom_default_message
|
||||
Topic.validates_length_of :title, :within => 3..5, :too_short => 'custom'
|
||||
@topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_generates_message_with_title_too_long
|
||||
Topic.validates_length_of :title, :within => 3..5
|
||||
@topic.title = 'this title is too long'
|
||||
@topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message
|
||||
Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom'
|
||||
@topic.title = 'this title is too long'
|
||||
@topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_length_of :is w/ mocha
|
||||
|
||||
def test_validates_length_of_is_generates_message
|
||||
Topic.validates_length_of :title, :is => 5
|
||||
@topic.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_length_of_is_generates_message_with_custom_default_message
|
||||
Topic.validates_length_of :title, :is => 5, :message => 'custom'
|
||||
@topic.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_uniqueness_of w/ mocha
|
||||
|
||||
def test_validates_uniqueness_of_generates_message
|
||||
Topic.validates_uniqueness_of :title
|
||||
@topic.title = unique_topic.title
|
||||
@topic.errors.expects(:generate_message).with(:title, :taken, {:default => nil, :value => 'unique!'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_uniqueness_of_generates_message_with_custom_default_message
|
||||
Topic.validates_uniqueness_of :title, :message => 'custom'
|
||||
@topic.title = unique_topic.title
|
||||
@topic.errors.expects(:generate_message).with(:title, :taken, {:default => 'custom', :value => 'unique!'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_format_of w/ mocha
|
||||
|
||||
def test_validates_format_of_generates_message
|
||||
Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/
|
||||
@topic.title = '72x'
|
||||
@topic.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_format_of_generates_message_with_custom_default_message
|
||||
Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/, :message => 'custom'
|
||||
@topic.title = '72x'
|
||||
@topic.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_inclusion_of w/ mocha
|
||||
|
||||
def test_validates_inclusion_of_generates_message
|
||||
Topic.validates_inclusion_of :title, :in => %w(a b c)
|
||||
@topic.title = 'z'
|
||||
@topic.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_inclusion_of_generates_message_with_custom_default_message
|
||||
Topic.validates_inclusion_of :title, :in => %w(a b c), :message => 'custom'
|
||||
@topic.title = 'z'
|
||||
@topic.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_exclusion_of w/ mocha
|
||||
|
||||
def test_validates_exclusion_of_generates_message
|
||||
Topic.validates_exclusion_of :title, :in => %w(a b c)
|
||||
@topic.title = 'a'
|
||||
@topic.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_exclusion_of_generates_message_with_custom_default_message
|
||||
Topic.validates_exclusion_of :title, :in => %w(a b c), :message => 'custom'
|
||||
@topic.title = 'a'
|
||||
@topic.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_numericality_of without :only_integer w/ mocha
|
||||
|
||||
def test_validates_numericality_of_generates_message
|
||||
Topic.validates_numericality_of :title
|
||||
@topic.title = 'a'
|
||||
@topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_generates_message_with_custom_default_message
|
||||
Topic.validates_numericality_of :title, :message => 'custom'
|
||||
@topic.title = 'a'
|
||||
@topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_numericality_of with :only_integer w/ mocha
|
||||
|
||||
def test_validates_numericality_of_only_integer_generates_message
|
||||
Topic.validates_numericality_of :title, :only_integer => true
|
||||
@topic.title = 'a'
|
||||
@topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :message => 'custom'
|
||||
@topic.title = 'a'
|
||||
@topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_numericality_of :odd w/ mocha
|
||||
|
||||
def test_validates_numericality_of_odd_generates_message
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :odd => true
|
||||
@topic.title = 0
|
||||
@topic.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_odd_generates_message_with_custom_default_message
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :odd => true, :message => 'custom'
|
||||
@topic.title = 0
|
||||
@topic.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_numericality_of :less_than w/ mocha
|
||||
|
||||
def test_validates_numericality_of_less_than_generates_message
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0
|
||||
@topic.title = 1
|
||||
@topic.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => nil})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_odd_generates_message_with_custom_default_message
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0, :message => 'custom'
|
||||
@topic.title = 1
|
||||
@topic.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => 'custom'})
|
||||
@topic.valid?
|
||||
end
|
||||
|
||||
# validates_associated w/ mocha
|
||||
|
||||
def test_validates_associated_generates_message
|
||||
Topic.validates_associated :replies
|
||||
replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil})
|
||||
replied_topic.valid?
|
||||
end
|
||||
|
||||
def test_validates_associated_generates_message_with_custom_default_message
|
||||
Topic.validates_associated :replies
|
||||
replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil})
|
||||
replied_topic.valid?
|
||||
end
|
||||
end
|
||||
|
||||
# validates_confirmation_of w/o mocha
|
||||
|
||||
def test_validates_confirmation_of_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:confirmation => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:confirmation => 'global message'}}}
|
||||
|
||||
Topic.validates_confirmation_of :title
|
||||
@topic.title_confirmation = 'foo'
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_confirmation_of_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:confirmation => 'global message'}}}
|
||||
|
||||
Topic.validates_confirmation_of :title
|
||||
@topic.title_confirmation = 'foo'
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_acceptance_of w/o mocha
|
||||
|
||||
def test_validates_acceptance_of_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:accepted => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:accepted => 'global message'}}}
|
||||
|
||||
Topic.validates_acceptance_of :title, :allow_nil => false
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_acceptance_of_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:accepted => 'global message'}}}
|
||||
|
||||
Topic.validates_acceptance_of :title, :allow_nil => false
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_presence_of w/o mocha
|
||||
|
||||
def test_validates_presence_of_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:blank => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:blank => 'global message'}}}
|
||||
|
||||
Topic.validates_presence_of :title
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_presence_of_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:blank => 'global message'}}}
|
||||
|
||||
Topic.validates_presence_of :title
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_length_of :within w/o mocha
|
||||
|
||||
def test_validates_length_of_within_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:too_short => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:too_short => 'global message'}}}
|
||||
|
||||
Topic.validates_length_of :title, :within => 3..5
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:too_short => 'global message'}}}
|
||||
|
||||
Topic.validates_length_of :title, :within => 3..5
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_length_of :is w/o mocha
|
||||
|
||||
def test_validates_length_of_within_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:wrong_length => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:wrong_length => 'global message'}}}
|
||||
|
||||
Topic.validates_length_of :title, :is => 5
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:wrong_length => 'global message'}}}
|
||||
|
||||
Topic.validates_length_of :title, :is => 5
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_uniqueness_of w/o mocha
|
||||
|
||||
def test_validates_length_of_within_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:wrong_length => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:wrong_length => 'global message'}}}
|
||||
|
||||
Topic.validates_length_of :title, :is => 5
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_length_of_within_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:wrong_length => 'global message'}}}
|
||||
|
||||
Topic.validates_length_of :title, :is => 5
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
|
||||
# validates_format_of w/o mocha
|
||||
|
||||
def test_validates_format_of_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:invalid => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:invalid => 'global message'}}}
|
||||
|
||||
Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_format_of_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:invalid => 'global message'}}}
|
||||
|
||||
Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_inclusion_of w/o mocha
|
||||
|
||||
def test_validates_inclusion_of_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:inclusion => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:inclusion => 'global message'}}}
|
||||
|
||||
Topic.validates_inclusion_of :title, :in => %w(a b c)
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_inclusion_of_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:inclusion => 'global message'}}}
|
||||
|
||||
Topic.validates_inclusion_of :title, :in => %w(a b c)
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_exclusion_of w/o mocha
|
||||
|
||||
def test_validates_exclusion_of_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:exclusion => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:exclusion => 'global message'}}}
|
||||
|
||||
Topic.validates_exclusion_of :title, :in => %w(a b c)
|
||||
@topic.title = 'a'
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_exclusion_of_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:exclusion => 'global message'}}}
|
||||
|
||||
Topic.validates_exclusion_of :title, :in => %w(a b c)
|
||||
@topic.title = 'a'
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_numericality_of without :only_integer w/o mocha
|
||||
|
||||
def test_validates_numericality_of_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:not_a_number => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:not_a_number => 'global message'}}}
|
||||
|
||||
Topic.validates_numericality_of :title
|
||||
@topic.title = 'a'
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:not_a_number => 'global message'}}}
|
||||
|
||||
Topic.validates_numericality_of :title, :only_integer => true
|
||||
@topic.title = 'a'
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_numericality_of with :only_integer w/o mocha
|
||||
|
||||
def test_validates_numericality_of_only_integer_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:not_a_number => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:not_a_number => 'global message'}}}
|
||||
|
||||
Topic.validates_numericality_of :title, :only_integer => true
|
||||
@topic.title = 'a'
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_only_integer_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:not_a_number => 'global message'}}}
|
||||
|
||||
Topic.validates_numericality_of :title, :only_integer => true
|
||||
@topic.title = 'a'
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_numericality_of :odd w/o mocha
|
||||
|
||||
def test_validates_numericality_of_odd_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:odd => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:odd => 'global message'}}}
|
||||
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :odd => true
|
||||
@topic.title = 0
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_odd_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:odd => 'global message'}}}
|
||||
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :odd => true
|
||||
@topic.title = 0
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
# validates_numericality_of :less_than w/o mocha
|
||||
|
||||
def test_validates_numericality_of_less_than_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:less_than => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:less_than => 'global message'}}}
|
||||
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0
|
||||
@topic.title = 1
|
||||
@topic.valid?
|
||||
assert_equal 'custom message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_numericality_of_less_than_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:less_than => 'global message'}}}
|
||||
|
||||
Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0
|
||||
@topic.title = 1
|
||||
@topic.valid?
|
||||
assert_equal 'global message', @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
|
||||
# validates_associated w/o mocha
|
||||
|
||||
def test_validates_associated_finds_custom_model_key_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:replies => {:invalid => 'custom message'}}}}}}
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:invalid => 'global message'}}}
|
||||
|
||||
Topic.validates_associated :replies
|
||||
replied_topic.valid?
|
||||
assert_equal 'custom message', replied_topic.errors.on(:replies)
|
||||
end
|
||||
|
||||
def test_validates_associated_finds_global_default_translation
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:invalid => 'global message'}}}
|
||||
|
||||
Topic.validates_associated :replies
|
||||
replied_topic.valid?
|
||||
assert_equal 'global message', replied_topic.errors.on(:replies)
|
||||
end
|
||||
|
||||
def test_validations_with_message_symbol_must_translate
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:custom_error => "I am a custom error"}}}
|
||||
Topic.validates_presence_of :title, :message => :custom_error
|
||||
@topic.title = nil
|
||||
@topic.valid?
|
||||
assert_equal "I am a custom error", @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_with_message_symbol_must_translate_per_attribute
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:title => {:custom_error => "I am a custom error"}}}}}}
|
||||
Topic.validates_presence_of :title, :message => :custom_error
|
||||
@topic.title = nil
|
||||
@topic.valid?
|
||||
assert_equal "I am a custom error", @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_with_message_symbol_must_translate_per_model
|
||||
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:custom_error => "I am a custom error"}}}}
|
||||
Topic.validates_presence_of :title, :message => :custom_error
|
||||
@topic.title = nil
|
||||
@topic.valid?
|
||||
assert_equal "I am a custom error", @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
def test_validates_with_message_string
|
||||
Topic.validates_presence_of :title, :message => "I am a custom error"
|
||||
@topic.title = nil
|
||||
@topic.valid?
|
||||
assert_equal "I am a custom error", @topic.errors.on(:title)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class ActiveRecordValidationsGenerateMessageI18nTests < Test::Unit::TestCase
|
||||
def setup
|
||||
reset_callbacks Topic
|
||||
@topic = Topic.new
|
||||
I18n.backend.store_translations :'en', {
|
||||
:activerecord => {
|
||||
:errors => {
|
||||
:messages => {
|
||||
:inclusion => "is not included in the list",
|
||||
:exclusion => "is reserved",
|
||||
:invalid => "is invalid",
|
||||
:confirmation => "doesn't match confirmation",
|
||||
:accepted => "must be accepted",
|
||||
:empty => "can't be empty",
|
||||
:blank => "can't be blank",
|
||||
:too_long => "is too long (maximum is {{count}} characters)",
|
||||
:too_short => "is too short (minimum is {{count}} characters)",
|
||||
:wrong_length => "is the wrong length (should be {{count}} characters)",
|
||||
:taken => "has already been taken",
|
||||
:not_a_number => "is not a number",
|
||||
:greater_than => "must be greater than {{count}}",
|
||||
:greater_than_or_equal_to => "must be greater than or equal to {{count}}",
|
||||
:equal_to => "must be equal to {{count}}",
|
||||
:less_than => "must be less than {{count}}",
|
||||
:less_than_or_equal_to => "must be less than or equal to {{count}}",
|
||||
:odd => "must be odd",
|
||||
:even => "must be even"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def reset_callbacks(*models)
|
||||
models.each do |model|
|
||||
model.instance_variable_set("@validate_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
model.instance_variable_set("@validate_on_create_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
model.instance_variable_set("@validate_on_update_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
end
|
||||
end
|
||||
|
||||
# validates_inclusion_of: generate_message(attr_name, :inclusion, :default => configuration[:message], :value => value)
|
||||
def test_generate_message_inclusion_with_default_message
|
||||
assert_equal 'is not included in the list', @topic.errors.generate_message(:title, :inclusion, :default => nil, :value => 'title')
|
||||
end
|
||||
|
||||
def test_generate_message_inclusion_with_custom_message
|
||||
assert_equal 'custom message title', @topic.errors.generate_message(:title, :inclusion, :default => 'custom message {{value}}', :value => 'title')
|
||||
end
|
||||
|
||||
# validates_exclusion_of: generate_message(attr_name, :exclusion, :default => configuration[:message], :value => value)
|
||||
def test_generate_message_exclusion_with_default_message
|
||||
assert_equal 'is reserved', @topic.errors.generate_message(:title, :exclusion, :default => nil, :value => 'title')
|
||||
end
|
||||
|
||||
def test_generate_message_exclusion_with_custom_message
|
||||
assert_equal 'custom message title', @topic.errors.generate_message(:title, :exclusion, :default => 'custom message {{value}}', :value => 'title')
|
||||
end
|
||||
|
||||
# validates_associated: generate_message(attr_name, :invalid, :default => configuration[:message], :value => value)
|
||||
# validates_format_of: generate_message(attr_name, :invalid, :default => configuration[:message], :value => value)
|
||||
def test_generate_message_invalid_with_default_message
|
||||
assert_equal 'is invalid', @topic.errors.generate_message(:title, :invalid, :default => nil, :value => 'title')
|
||||
end
|
||||
|
||||
def test_generate_message_invalid_with_custom_message
|
||||
assert_equal 'custom message title', @topic.errors.generate_message(:title, :invalid, :default => 'custom message {{value}}', :value => 'title')
|
||||
end
|
||||
|
||||
# validates_confirmation_of: generate_message(attr_name, :confirmation, :default => configuration[:message])
|
||||
def test_generate_message_confirmation_with_default_message
|
||||
assert_equal "doesn't match confirmation", @topic.errors.generate_message(:title, :confirmation, :default => nil)
|
||||
end
|
||||
|
||||
def test_generate_message_confirmation_with_custom_message
|
||||
assert_equal 'custom message', @topic.errors.generate_message(:title, :confirmation, :default => 'custom message')
|
||||
end
|
||||
|
||||
# validates_acceptance_of: generate_message(attr_name, :accepted, :default => configuration[:message])
|
||||
def test_generate_message_accepted_with_default_message
|
||||
assert_equal "must be accepted", @topic.errors.generate_message(:title, :accepted, :default => nil)
|
||||
end
|
||||
|
||||
def test_generate_message_accepted_with_custom_message
|
||||
assert_equal 'custom message', @topic.errors.generate_message(:title, :accepted, :default => 'custom message')
|
||||
end
|
||||
|
||||
# add_on_empty: generate_message(attr, :empty, :default => custom_message)
|
||||
def test_generate_message_empty_with_default_message
|
||||
assert_equal "can't be empty", @topic.errors.generate_message(:title, :empty, :default => nil)
|
||||
end
|
||||
|
||||
def test_generate_message_empty_with_custom_message
|
||||
assert_equal 'custom message', @topic.errors.generate_message(:title, :empty, :default => 'custom message')
|
||||
end
|
||||
|
||||
# add_on_blank: generate_message(attr, :blank, :default => custom_message)
|
||||
def test_generate_message_blank_with_default_message
|
||||
assert_equal "can't be blank", @topic.errors.generate_message(:title, :blank, :default => nil)
|
||||
end
|
||||
|
||||
def test_generate_message_blank_with_custom_message
|
||||
assert_equal 'custom message', @topic.errors.generate_message(:title, :blank, :default => 'custom message')
|
||||
end
|
||||
|
||||
# validates_length_of: generate_message(attr, :too_long, :default => options[:too_long], :count => option_value.end)
|
||||
def test_generate_message_too_long_with_default_message
|
||||
assert_equal "is too long (maximum is 10 characters)", @topic.errors.generate_message(:title, :too_long, :default => nil, :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_too_long_with_custom_message
|
||||
assert_equal 'custom message 10', @topic.errors.generate_message(:title, :too_long, :default => 'custom message {{count}}', :count => 10)
|
||||
end
|
||||
|
||||
# validates_length_of: generate_message(attr, :too_short, :default => options[:too_short], :count => option_value.begin)
|
||||
def test_generate_message_too_short_with_default_message
|
||||
assert_equal "is too short (minimum is 10 characters)", @topic.errors.generate_message(:title, :too_short, :default => nil, :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_too_short_with_custom_message
|
||||
assert_equal 'custom message 10', @topic.errors.generate_message(:title, :too_short, :default => 'custom message {{count}}', :count => 10)
|
||||
end
|
||||
|
||||
# validates_length_of: generate_message(attr, key, :default => custom_message, :count => option_value)
|
||||
def test_generate_message_wrong_length_with_default_message
|
||||
assert_equal "is the wrong length (should be 10 characters)", @topic.errors.generate_message(:title, :wrong_length, :default => nil, :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_wrong_length_with_custom_message
|
||||
assert_equal 'custom message 10', @topic.errors.generate_message(:title, :wrong_length, :default => 'custom message {{count}}', :count => 10)
|
||||
end
|
||||
|
||||
# validates_uniqueness_of: generate_message(attr_name, :taken, :default => configuration[:message])
|
||||
def test_generate_message_taken_with_default_message
|
||||
assert_equal "has already been taken", @topic.errors.generate_message(:title, :taken, :default => nil, :value => 'title')
|
||||
end
|
||||
|
||||
def test_generate_message_taken_with_custom_message
|
||||
assert_equal 'custom message title', @topic.errors.generate_message(:title, :taken, :default => 'custom message {{value}}', :value => 'title')
|
||||
end
|
||||
|
||||
# validates_numericality_of: generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message])
|
||||
def test_generate_message_not_a_number_with_default_message
|
||||
assert_equal "is not a number", @topic.errors.generate_message(:title, :not_a_number, :default => nil, :value => 'title')
|
||||
end
|
||||
|
||||
def test_generate_message_not_a_number_with_custom_message
|
||||
assert_equal 'custom message title', @topic.errors.generate_message(:title, :not_a_number, :default => 'custom message {{value}}', :value => 'title')
|
||||
end
|
||||
|
||||
# validates_numericality_of: generate_message(attr_name, option, :value => raw_value, :default => configuration[:message])
|
||||
def test_generate_message_greater_than_with_default_message
|
||||
assert_equal "must be greater than 10", @topic.errors.generate_message(:title, :greater_than, :default => nil, :value => 'title', :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_greater_than_or_equal_to_with_default_message
|
||||
assert_equal "must be greater than or equal to 10", @topic.errors.generate_message(:title, :greater_than_or_equal_to, :default => nil, :value => 'title', :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_equal_to_with_default_message
|
||||
assert_equal "must be equal to 10", @topic.errors.generate_message(:title, :equal_to, :default => nil, :value => 'title', :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_less_than_with_default_message
|
||||
assert_equal "must be less than 10", @topic.errors.generate_message(:title, :less_than, :default => nil, :value => 'title', :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_less_than_or_equal_to_with_default_message
|
||||
assert_equal "must be less than or equal to 10", @topic.errors.generate_message(:title, :less_than_or_equal_to, :default => nil, :value => 'title', :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_odd_with_default_message
|
||||
assert_equal "must be odd", @topic.errors.generate_message(:title, :odd, :default => nil, :value => 'title', :count => 10)
|
||||
end
|
||||
|
||||
def test_generate_message_even_with_default_message
|
||||
assert_equal "must be even", @topic.errors.generate_message(:title, :even, :default => nil, :value => 'title', :count => 10)
|
||||
end
|
||||
|
||||
end
|
||||
1552
vendor/rails/activerecord/test/cases/validations_test.rb
vendored
Normal file
1552
vendor/rails/activerecord/test/cases/validations_test.rb
vendored
Normal file
File diff suppressed because it is too large
Load diff
202
vendor/rails/activerecord/test/cases/xml_serialization_test.rb
vendored
Normal file
202
vendor/rails/activerecord/test/cases/xml_serialization_test.rb
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
require "cases/helper"
|
||||
require 'models/contact'
|
||||
require 'models/post'
|
||||
require 'models/author'
|
||||
require 'models/tagging'
|
||||
require 'models/comment'
|
||||
|
||||
class XmlSerializationTest < ActiveRecord::TestCase
|
||||
def test_should_serialize_default_root
|
||||
@xml = Contact.new.to_xml
|
||||
assert_match %r{^<contact>}, @xml
|
||||
assert_match %r{</contact>$}, @xml
|
||||
end
|
||||
|
||||
def test_should_serialize_default_root_with_namespace
|
||||
@xml = Contact.new.to_xml :namespace=>"http://xml.rubyonrails.org/contact"
|
||||
assert_match %r{^<contact xmlns="http://xml.rubyonrails.org/contact">}, @xml
|
||||
assert_match %r{</contact>$}, @xml
|
||||
end
|
||||
|
||||
def test_should_serialize_custom_root
|
||||
@xml = Contact.new.to_xml :root => 'xml_contact'
|
||||
assert_match %r{^<xml-contact>}, @xml
|
||||
assert_match %r{</xml-contact>$}, @xml
|
||||
end
|
||||
|
||||
def test_should_allow_undasherized_tags
|
||||
@xml = Contact.new.to_xml :root => 'xml_contact', :dasherize => false
|
||||
assert_match %r{^<xml_contact>}, @xml
|
||||
assert_match %r{</xml_contact>$}, @xml
|
||||
assert_match %r{<created_at}, @xml
|
||||
end
|
||||
|
||||
def test_should_include_yielded_additions
|
||||
@xml = Contact.new.to_xml do |xml|
|
||||
xml.creator "David"
|
||||
end
|
||||
|
||||
assert_match %r{<creator>David</creator>}, @xml
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultXmlSerializationTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@xml = Contact.new(:name => 'aaron stack', :age => 25, :avatar => 'binarydata', :created_at => Time.utc(2006, 8, 1), :awesome => false, :preferences => { :gem => 'ruby' }).to_xml
|
||||
end
|
||||
|
||||
def test_should_serialize_string
|
||||
assert_match %r{<name>aaron stack</name>}, @xml
|
||||
end
|
||||
|
||||
def test_should_serialize_integer
|
||||
assert_match %r{<age type="integer">25</age>}, @xml
|
||||
end
|
||||
|
||||
def test_should_serialize_binary
|
||||
assert_match %r{YmluYXJ5ZGF0YQ==\n</avatar>}, @xml
|
||||
assert_match %r{<avatar(.*)(type="binary")}, @xml
|
||||
assert_match %r{<avatar(.*)(encoding="base64")}, @xml
|
||||
end
|
||||
|
||||
def test_should_serialize_datetime
|
||||
assert_match %r{<created-at type=\"datetime\">2006-08-01T00:00:00Z</created-at>}, @xml
|
||||
end
|
||||
|
||||
def test_should_serialize_boolean
|
||||
assert_match %r{<awesome type=\"boolean\">false</awesome>}, @xml
|
||||
end
|
||||
|
||||
def test_should_serialize_yaml
|
||||
assert_match %r{<preferences type=\"yaml\">--- \n:gem: ruby\n</preferences>}, @xml
|
||||
end
|
||||
end
|
||||
|
||||
class NilXmlSerializationTest < ActiveRecord::TestCase
|
||||
def setup
|
||||
@xml = Contact.new.to_xml(:root => 'xml_contact')
|
||||
end
|
||||
|
||||
def test_should_serialize_string
|
||||
assert_match %r{<name nil="true"></name>}, @xml
|
||||
end
|
||||
|
||||
def test_should_serialize_integer
|
||||
assert %r{<age (.*)></age>}.match(@xml)
|
||||
attributes = $1
|
||||
assert_match %r{nil="true"}, attributes
|
||||
assert_match %r{type="integer"}, attributes
|
||||
end
|
||||
|
||||
def test_should_serialize_binary
|
||||
assert %r{<avatar (.*)></avatar>}.match(@xml)
|
||||
attributes = $1
|
||||
assert_match %r{type="binary"}, attributes
|
||||
assert_match %r{encoding="base64"}, attributes
|
||||
assert_match %r{nil="true"}, attributes
|
||||
end
|
||||
|
||||
def test_should_serialize_datetime
|
||||
assert %r{<created-at (.*)></created-at>}.match(@xml)
|
||||
attributes = $1
|
||||
assert_match %r{nil="true"}, attributes
|
||||
assert_match %r{type="datetime"}, attributes
|
||||
end
|
||||
|
||||
def test_should_serialize_boolean
|
||||
assert %r{<awesome (.*)></awesome>}.match(@xml)
|
||||
attributes = $1
|
||||
assert_match %r{type="boolean"}, attributes
|
||||
assert_match %r{nil="true"}, attributes
|
||||
end
|
||||
|
||||
def test_should_serialize_yaml
|
||||
assert %r{<preferences(.*)></preferences>}.match(@xml)
|
||||
attributes = $1
|
||||
assert_match %r{type="yaml"}, attributes
|
||||
assert_match %r{nil="true"}, attributes
|
||||
end
|
||||
end
|
||||
|
||||
class DatabaseConnectedXmlSerializationTest < ActiveRecord::TestCase
|
||||
fixtures :authors, :posts
|
||||
# to_xml used to mess with the hash the user provided which
|
||||
# caused the builder to be reused. This meant the document kept
|
||||
# getting appended to.
|
||||
def test_passing_hash_shouldnt_reuse_builder
|
||||
options = {:include=>:posts}
|
||||
david = authors(:david)
|
||||
first_xml_size = david.to_xml(options).size
|
||||
second_xml_size = david.to_xml(options).size
|
||||
assert_equal first_xml_size, second_xml_size
|
||||
end
|
||||
|
||||
def test_include_uses_association_name
|
||||
xml = authors(:david).to_xml :include=>:hello_posts, :indent => 0
|
||||
assert_match %r{<hello-posts type="array">}, xml
|
||||
assert_match %r{<hello-post type="Post">}, xml
|
||||
assert_match %r{<hello-post type="StiPost">}, xml
|
||||
end
|
||||
|
||||
def test_methods_are_called_on_object
|
||||
xml = authors(:david).to_xml :methods => :label, :indent => 0
|
||||
assert_match %r{<label>.*</label>}, xml
|
||||
end
|
||||
|
||||
def test_should_not_call_methods_on_associations_that_dont_respond
|
||||
xml = authors(:david).to_xml :include=>:hello_posts, :methods => :label, :indent => 2
|
||||
assert !authors(:david).hello_posts.first.respond_to?(:label)
|
||||
assert_match %r{^ <label>.*</label>}, xml
|
||||
assert_no_match %r{^ <label>}, xml
|
||||
end
|
||||
|
||||
def test_procs_are_called_on_object
|
||||
proc = Proc.new { |options| options[:builder].tag!('nationality', 'Danish') }
|
||||
xml = authors(:david).to_xml(:procs => [ proc ])
|
||||
assert_match %r{<nationality>Danish</nationality>}, xml
|
||||
end
|
||||
|
||||
def test_top_level_procs_arent_applied_to_associations
|
||||
author_proc = Proc.new { |options| options[:builder].tag!('nationality', 'Danish') }
|
||||
xml = authors(:david).to_xml(:procs => [ author_proc ], :include => :posts, :indent => 2)
|
||||
|
||||
assert_match %r{^ <nationality>Danish</nationality>}, xml
|
||||
assert_no_match %r{^ {6}<nationality>Danish</nationality>}, xml
|
||||
end
|
||||
|
||||
def test_procs_on_included_associations_are_called
|
||||
posts_proc = Proc.new { |options| options[:builder].tag!('copyright', 'DHH') }
|
||||
xml = authors(:david).to_xml(
|
||||
:indent => 2,
|
||||
:include => {
|
||||
:posts => { :procs => [ posts_proc ] }
|
||||
}
|
||||
)
|
||||
|
||||
assert_no_match %r{^ <copyright>DHH</copyright>}, xml
|
||||
assert_match %r{^ {6}<copyright>DHH</copyright>}, xml
|
||||
end
|
||||
|
||||
def test_should_include_empty_has_many_as_empty_array
|
||||
authors(:david).posts.delete_all
|
||||
xml = authors(:david).to_xml :include=>:posts, :indent => 2
|
||||
|
||||
assert_equal [], Hash.from_xml(xml)['author']['posts']
|
||||
assert_match %r{^ <posts type="array"/>}, xml
|
||||
end
|
||||
|
||||
def test_should_has_many_array_elements_should_include_type_when_different_from_guessed_value
|
||||
xml = authors(:david).to_xml :include=>:posts_with_comments, :indent => 2
|
||||
|
||||
assert Hash.from_xml(xml)
|
||||
assert_match %r{^ <posts-with-comments type="array">}, xml
|
||||
assert_match %r{^ <posts-with-comment type="Post">}, xml
|
||||
assert_match %r{^ <posts-with-comment type="StiPost">}, xml
|
||||
|
||||
types = Hash.from_xml(xml)['author']['posts_with_comments'].collect {|t| t['type'] }
|
||||
assert types.include?('SpecialPost')
|
||||
assert types.include?('Post')
|
||||
assert types.include?('StiPost')
|
||||
end
|
||||
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue