aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2014-01-11 17:28:43 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2014-01-11 17:28:43 -0800
commit11e8badb16876e6bd72c874631d25aec41dad293 (patch)
tree5ec87baa3a8e7652c46d6804b174b81b8f9c7745 /activerecord/test
parent474ebc55bd13ad58626a49dfc44c8e6407813935 (diff)
parentcaa981d88112f019ade868f75af6b5f399c244a4 (diff)
downloadrails-11e8badb16876e6bd72c874631d25aec41dad293.tar.gz
rails-11e8badb16876e6bd72c874631d25aec41dad293.tar.bz2
rails-11e8badb16876e6bd72c874631d25aec41dad293.zip
Merge branch 'master' into set_binds
* master: (2794 commits) doc, API example on how to use `Model#exists?` with multiple IDs. [ci skip] Restore DATABASE_URL even if it's nil in connection_handler test [ci skip] - error_messages_for has been deprecated since 2.3.8 - lets reduce any confusion for users Ensure Active Record connection consistency Revert "ask the fixture set for the sql statements" Check `respond_to` before delegation due to: https://github.com/ruby/ruby/commit/d781caaf313b8649948c107bba277e5ad7307314 Adding Hash#compact and Hash#compact! methods MySQL version 4.1 was EOL on December 31, 2009 We should at least recommend modern versions of MySQL to users. clear cache on body close so that cache remains during rendering add a more restricted codepath for templates fixes #13390 refactor generator tests to use block form of Tempfile Fix typo [ci skip] Move finish_template as the last public method in the generator Minor typos fix [ci skip] make `change_column_null` reversible. Closes #13576. create/drop test and development databases only if RAILS_ENV is nil Revert "Speedup String#to" typo fix in test name. [ci skip]. `core_ext/string/access.rb` test what we are documenting. Fix typo in image_tag documentation ... Conflicts: activerecord/lib/active_record/associations/join_dependency/join_association.rb activerecord/lib/active_record/relation/query_methods.rb
Diffstat (limited to 'activerecord/test')
-rw-r--r--activerecord/test/cases/adapter_test.rb41
-rw-r--r--activerecord/test/cases/adapters/firebird/connection_test.rb8
-rw-r--r--activerecord/test/cases/adapters/firebird/default_test.rb16
-rw-r--r--activerecord/test/cases/adapters/firebird/migration_test.rb124
-rw-r--r--activerecord/test/cases/adapters/mysql/connection_test.rb29
-rw-r--r--activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb26
-rw-r--r--activerecord/test/cases/adapters/mysql/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql/statement_pool_test.rb24
-rw-r--r--activerecord/test/cases/adapters/mysql2/boolean_test.rb91
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb27
-rw-r--r--activerecord/test/cases/adapters/mysql2/explain_test.rb6
-rw-r--r--activerecord/test/cases/adapters/mysql2/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb25
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_test.rb9
-rw-r--r--activerecord/test/cases/adapters/oracle/synonym_test.rb17
-rw-r--r--activerecord/test/cases/adapters/postgresql/active_schema_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb89
-rw-r--r--activerecord/test/cases/adapters/postgresql/bytea_test.rb23
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb72
-rw-r--r--activerecord/test/cases/adapters/postgresql/datatype_test.rb411
-rw-r--r--activerecord/test/cases/adapters/postgresql/hstore_test.rb311
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb34
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb66
-rw-r--r--activerecord/test/cases/adapters/postgresql/quoting_test.rb7
-rw-r--r--activerecord/test/cases/adapters/postgresql/range_test.rb245
-rw-r--r--activerecord/test/cases/adapters/postgresql/statement_pool_test.rb56
-rw-r--r--activerecord/test/cases/adapters/postgresql/timestamp_test.rb12
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb113
-rw-r--r--activerecord/test/cases/adapters/postgresql/xml_test.rb38
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb7
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb63
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb21
-rw-r--r--activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb23
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb82
-rw-r--r--activerecord/test/cases/associations/cascaded_eager_loading_test.rb21
-rw-r--r--activerecord/test/cases/associations/eager_test.rb49
-rw-r--r--activerecord/test/cases/associations/extension_test.rb13
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb126
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb370
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb195
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb55
-rw-r--r--activerecord/test/cases/associations/has_one_through_associations_test.rb11
-rw-r--r--activerecord/test/cases/associations/inner_join_association_test.rb23
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb53
-rw-r--r--activerecord/test/cases/associations/join_dependency_test.rb8
-rw-r--r--activerecord/test/cases/associations/nested_through_associations_test.rb13
-rw-r--r--activerecord/test/cases/associations_test.rb4
-rw-r--r--activerecord/test/cases/attribute_methods/read_test.rb11
-rw-r--r--activerecord/test/cases/attribute_methods/serialization_test.rb29
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb60
-rw-r--r--activerecord/test/cases/autosave_association_test.rb11
-rw-r--r--activerecord/test/cases/base_test.rb292
-rw-r--r--activerecord/test/cases/batches_test.rb28
-rw-r--r--activerecord/test/cases/bind_parameter_test.rb77
-rw-r--r--activerecord/test/cases/calculations_test.rb40
-rw-r--r--activerecord/test/cases/column_test.rb8
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handler_test.rb127
-rw-r--r--activerecord/test/cases/connection_management_test.rb32
-rw-r--r--activerecord/test/cases/connection_pool_test.rb3
-rw-r--r--activerecord/test/cases/connection_specification/resolver_test.rb76
-rw-r--r--activerecord/test/cases/core_test.rb33
-rw-r--r--activerecord/test/cases/counter_cache_test.rb17
-rw-r--r--activerecord/test/cases/date_time_test.rb2
-rw-r--r--activerecord/test/cases/defaults_test.rb25
-rw-r--r--activerecord/test/cases/deprecated_dynamic_methods_test.rb592
-rw-r--r--activerecord/test/cases/dirty_test.rb64
-rw-r--r--activerecord/test/cases/disconnected_test.rb28
-rw-r--r--activerecord/test/cases/dup_test.rb2
-rw-r--r--activerecord/test/cases/enum_test.rb91
-rw-r--r--activerecord/test/cases/finder_respond_to_test.rb41
-rw-r--r--activerecord/test/cases/finder_test.rb271
-rw-r--r--activerecord/test/cases/fixture_set/file_test.rb55
-rw-r--r--activerecord/test/cases/fixtures_test.rb100
-rw-r--r--activerecord/test/cases/forbidden_attributes_protection_test.rb5
-rw-r--r--activerecord/test/cases/helper.rb93
-rw-r--r--activerecord/test/cases/inheritance_test.rb10
-rw-r--r--activerecord/test/cases/integration_test.rb67
-rw-r--r--activerecord/test/cases/invalid_connection_test.rb22
-rw-r--r--activerecord/test/cases/locking_test.rb20
-rw-r--r--activerecord/test/cases/log_subscriber_test.rb19
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb63
-rw-r--r--activerecord/test/cases/migration/change_table_test.rb2
-rw-r--r--activerecord/test/cases/migration/column_attributes_test.rb91
-rw-r--r--activerecord/test/cases/migration/column_positioning_test.rb47
-rw-r--r--activerecord/test/cases/migration/command_recorder_test.rb13
-rw-r--r--activerecord/test/cases/migration/index_test.rb66
-rw-r--r--activerecord/test/cases/migration/references_index_test.rb28
-rw-r--r--activerecord/test/cases/migration/rename_table_test.rb48
-rw-r--r--activerecord/test/cases/migration_test.rb357
-rw-r--r--activerecord/test/cases/migrator_test.rb6
-rw-r--r--activerecord/test/cases/mixin_test.rb44
-rw-r--r--activerecord/test/cases/modules_test.rb1
-rw-r--r--activerecord/test/cases/multiparameter_attributes_test.rb168
-rw-r--r--activerecord/test/cases/multiple_db_test.rb2
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb20
-rw-r--r--activerecord/test/cases/nested_attributes_with_callbacks_test.rb144
-rw-r--r--activerecord/test/cases/persistence_test.rb42
-rw-r--r--activerecord/test/cases/pooled_connections_test.rb16
-rw-r--r--activerecord/test/cases/primary_keys_test.rb19
-rw-r--r--activerecord/test/cases/query_cache_test.rb9
-rw-r--r--activerecord/test/cases/quoting_test.rb69
-rw-r--r--activerecord/test/cases/readonly_test.rb18
-rw-r--r--activerecord/test/cases/reflection_test.rb29
-rw-r--r--activerecord/test/cases/relation/delegation_test.rb68
-rw-r--r--activerecord/test/cases/relation/merging_test.rb162
-rw-r--r--activerecord/test/cases/relation/mutation_test.rb144
-rw-r--r--activerecord/test/cases/relation/predicate_builder_test.rb14
-rw-r--r--activerecord/test/cases/relation/where_chain_test.rb36
-rw-r--r--activerecord/test/cases/relation/where_test.rb63
-rw-r--r--activerecord/test/cases/relation_test.rb165
-rw-r--r--activerecord/test/cases/relations_test.rb246
-rw-r--r--activerecord/test/cases/result_test.rb32
-rw-r--r--activerecord/test/cases/sanitize_test.rb17
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb30
-rw-r--r--activerecord/test/cases/scoping/default_scoping_test.rb84
-rw-r--r--activerecord/test/cases/scoping/named_scoping_test.rb20
-rw-r--r--activerecord/test/cases/serialized_attribute_test.rb28
-rw-r--r--activerecord/test/cases/store_test.rb17
-rw-r--r--activerecord/test/cases/tasks/database_tasks_test.rb29
-rw-r--r--activerecord/test/cases/tasks/firebird_rake_test.rb100
-rw-r--r--activerecord/test/cases/tasks/mysql_rake_test.rb158
-rw-r--r--activerecord/test/cases/tasks/oracle_rake_test.rb93
-rw-r--r--activerecord/test/cases/tasks/postgresql_rake_test.rb9
-rw-r--r--activerecord/test/cases/tasks/sqlite_rake_test.rb6
-rw-r--r--activerecord/test/cases/tasks/sqlserver_rake_test.rb87
-rw-r--r--activerecord/test/cases/test_case.rb111
-rw-r--r--activerecord/test/cases/timestamp_test.rb118
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb8
-rw-r--r--activerecord/test/cases/transaction_isolation_test.rb152
-rw-r--r--activerecord/test/cases/transactions_test.rb84
-rw-r--r--activerecord/test/cases/validations/association_validation_test.rb71
-rw-r--r--activerecord/test/cases/validations/i18n_generate_message_validation_test.rb24
-rw-r--r--activerecord/test/cases/validations/presence_validation_test.rb16
-rw-r--r--activerecord/test/cases/validations/uniqueness_validation_test.rb43
-rw-r--r--activerecord/test/cases/validations_test.rb10
-rw-r--r--activerecord/test/cases/xml_serialization_test.rb20
-rw-r--r--activerecord/test/cases/yaml_serialization_test.rb18
l---------activerecord/test/fixtures/all/admin1
-rw-r--r--activerecord/test/fixtures/owners.yml1
-rw-r--r--activerecord/test/fixtures/sponsors.yml2
-rw-r--r--activerecord/test/fixtures/tasks.yml2
-rw-r--r--activerecord/test/fixtures/to_be_linked/accounts.yml2
-rw-r--r--activerecord/test/fixtures/to_be_linked/users.yml10
-rw-r--r--activerecord/test/migrations/version_check/20131219224947_migration_version_check.rb8
-rw-r--r--activerecord/test/models/admin/user.rb1
-rw-r--r--activerecord/test/models/author.rb18
-rw-r--r--activerecord/test/models/auto_id.rb4
-rw-r--r--activerecord/test/models/book.rb12
-rw-r--r--activerecord/test/models/bulb.rb12
-rw-r--r--activerecord/test/models/cake_designer.rb3
-rw-r--r--activerecord/test/models/car.rb6
-rw-r--r--activerecord/test/models/chef.rb3
-rw-r--r--activerecord/test/models/citation.rb3
-rw-r--r--activerecord/test/models/club.rb3
-rw-r--r--activerecord/test/models/column_name.rb4
-rw-r--r--activerecord/test/models/company.rb45
-rw-r--r--activerecord/test/models/company_in_module.rb4
-rw-r--r--activerecord/test/models/contract.rb1
-rw-r--r--activerecord/test/models/department.rb4
-rw-r--r--activerecord/test/models/developer.rb12
-rw-r--r--activerecord/test/models/drink_designer.rb3
-rw-r--r--activerecord/test/models/hotel.rb6
-rw-r--r--activerecord/test/models/interest.rb2
-rw-r--r--activerecord/test/models/man.rb3
-rw-r--r--activerecord/test/models/member.rb3
-rw-r--r--activerecord/test/models/member_detail.rb2
-rw-r--r--activerecord/test/models/membership.rb5
-rw-r--r--activerecord/test/models/mixed_case_monkey.rb2
-rw-r--r--activerecord/test/models/movie.rb4
-rw-r--r--activerecord/test/models/parrot.rb6
-rw-r--r--activerecord/test/models/person.rb1
-rw-r--r--activerecord/test/models/post.rb12
-rw-r--r--activerecord/test/models/project.rb14
-rw-r--r--activerecord/test/models/topic.rb5
-rw-r--r--activerecord/test/schema/oracle_specific_schema.rb3
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb15
-rw-r--r--activerecord/test/schema/schema.rb453
-rw-r--r--activerecord/test/schema/sqlite_specific_schema.rb7
-rw-r--r--activerecord/test/support/connection.rb4
179 files changed, 5490 insertions, 4224 deletions
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index e28bb7b6ca..b67e70ec7e 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -92,7 +92,7 @@ module ActiveRecord
)
end
ensure
- ActiveRecord::Base.establish_connection 'arunit'
+ ActiveRecord::Base.establish_connection :arunit
end
end
end
@@ -173,6 +173,15 @@ module ActiveRecord
end
end
end
+
+ def test_select_all_always_return_activerecord_result
+ result = @connection.select_all "SELECT * FROM posts"
+ assert result.is_a?(ActiveRecord::Result)
+ end
+
+ test "type_to_sql returns a String for unmapped types" do
+ assert_equal "special_db_type", @connection.type_to_sql(:special_db_type)
+ end
end
class AdapterTestWithoutTransaction < ActiveRecord::TestCase
@@ -182,7 +191,7 @@ module ActiveRecord
end
def setup
- Klass.establish_connection 'arunit'
+ Klass.establish_connection :arunit
@connection = Klass.connection
end
@@ -190,22 +199,20 @@ module ActiveRecord
Klass.remove_connection
end
- test "transaction state is reset after a reconnect" do
- skip "in-memory db doesn't allow reconnect" if in_memory_db?
-
- @connection.begin_transaction
- assert @connection.transaction_open?
- @connection.reconnect!
- assert !@connection.transaction_open?
- end
-
- test "transaction state is reset after a disconnect" do
- skip "in-memory db doesn't allow disconnect" if in_memory_db?
+ unless in_memory_db?
+ test "transaction state is reset after a reconnect" do
+ @connection.begin_transaction
+ assert @connection.transaction_open?
+ @connection.reconnect!
+ assert !@connection.transaction_open?
+ end
- @connection.begin_transaction
- assert @connection.transaction_open?
- @connection.disconnect!
- assert !@connection.transaction_open?
+ test "transaction state is reset after a disconnect" do
+ @connection.begin_transaction
+ assert @connection.transaction_open?
+ @connection.disconnect!
+ assert !@connection.transaction_open?
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/firebird/connection_test.rb b/activerecord/test/cases/adapters/firebird/connection_test.rb
deleted file mode 100644
index f57ea686a5..0000000000
--- a/activerecord/test/cases/adapters/firebird/connection_test.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-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
diff --git a/activerecord/test/cases/adapters/firebird/default_test.rb b/activerecord/test/cases/adapters/firebird/default_test.rb
deleted file mode 100644
index 713c7e11bf..0000000000
--- a/activerecord/test/cases/adapters/firebird/default_test.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-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
diff --git a/activerecord/test/cases/adapters/firebird/migration_test.rb b/activerecord/test/cases/adapters/firebird/migration_test.rb
deleted file mode 100644
index 5c94593765..0000000000
--- a/activerecord/test/cases/adapters/firebird/migration_test.rb
+++ /dev/null
@@ -1,124 +0,0 @@
-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) }
- 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
diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb
index 1844a2e0dc..5cd5d8ac5f 100644
--- a/activerecord/test/cases/adapters/mysql/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql/connection_test.rb
@@ -16,15 +16,15 @@ class MysqlConnectionTest < ActiveRecord::TestCase
end
end
- def test_connect_with_url
- run_without_connection do
- ar_config = ARTest.connection_config['arunit']
-
- skip "This test doesn't work with custom socket location" if ar_config['socket']
-
- url = "mysql://#{ar_config["username"]}@localhost/#{ar_config["database"]}"
- Klass.establish_connection(url)
- assert_equal ar_config['database'], Klass.connection.current_database
+ unless ARTest.connection_config['arunit']['socket']
+ def test_connect_with_url
+ run_without_connection do
+ ar_config = ARTest.connection_config['arunit']
+
+ url = "mysql://#{ar_config["username"]}@localhost/#{ar_config["database"]}"
+ Klass.establish_connection(url)
+ assert_equal ar_config['database'], Klass.connection.current_database
+ end
end
end
@@ -40,6 +40,11 @@ class MysqlConnectionTest < ActiveRecord::TestCase
@connection.update('set @@wait_timeout=1')
sleep 2
assert !@connection.active?
+
+ # Repair all fixture connections so other tests won't break.
+ @fixture_connections.each do |c|
+ c.verify!
+ end
end
def test_successful_reconnection_after_timeout_with_manual_reconnect
@@ -66,7 +71,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
def test_exec_no_binds
@connection.exec_query('drop table if exists ex')
@connection.exec_query(<<-eosql)
- CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY,
+ CREATE TABLE `ex` (`id` int(11) auto_increment PRIMARY KEY,
`data` varchar(255))
eosql
result = @connection.exec_query('SELECT id, data FROM ex')
@@ -88,7 +93,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
def test_exec_with_binds
@connection.exec_query('drop table if exists ex')
@connection.exec_query(<<-eosql)
- CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY,
+ CREATE TABLE `ex` (`id` int(11) auto_increment PRIMARY KEY,
`data` varchar(255))
eosql
@connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
@@ -104,7 +109,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
def test_exec_typecasts_bind_vals
@connection.exec_query('drop table if exists ex')
@connection.exec_query(<<-eosql)
- CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY,
+ CREATE TABLE `ex` (`id` int(11) auto_increment PRIMARY KEY,
`data` varchar(255))
eosql
@connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
diff --git a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
index 4a23287448..578f6301bd 100644
--- a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
@@ -10,12 +10,20 @@ module ActiveRecord
@conn.exec_query('drop table if exists ex')
@conn.exec_query(<<-eosql)
CREATE TABLE `ex` (
- `id` int(11) DEFAULT NULL auto_increment PRIMARY KEY,
+ `id` int(11) auto_increment PRIMARY KEY,
`number` integer,
`data` varchar(255))
eosql
end
+ def test_bad_connection_mysql
+ assert_raise ActiveRecord::NoDatabaseError do
+ configuration = ActiveRecord::Base.configurations['arunit'].merge(database: 'inexistent_activerecord_unittest')
+ connection = ActiveRecord::Base.mysql_connection(configuration)
+ connection.exec_query('drop table if exists ex')
+ end
+ end
+
def test_valid_column
column = @conn.columns('ex').find { |col| col.name == 'id' }
assert @conn.valid_type?(column.type)
@@ -75,7 +83,7 @@ module ActiveRecord
@conn.exec_query('drop table if exists ex_with_non_standard_pk')
@conn.exec_query(<<-eosql)
CREATE TABLE `ex_with_non_standard_pk` (
- `code` INT(11) DEFAULT NULL auto_increment,
+ `code` INT(11) auto_increment,
PRIMARY KEY (`code`))
eosql
pk, seq = @conn.pk_and_sequence_for('ex_with_non_standard_pk')
@@ -87,7 +95,7 @@ module ActiveRecord
@conn.exec_query('drop table if exists ex_with_custom_index_type_pk')
@conn.exec_query(<<-eosql)
CREATE TABLE `ex_with_custom_index_type_pk` (
- `id` INT(11) DEFAULT NULL auto_increment,
+ `id` INT(11) auto_increment,
PRIMARY KEY USING BTREE (`id`))
eosql
pk, seq = @conn.pk_and_sequence_for('ex_with_custom_index_type_pk')
@@ -108,6 +116,18 @@ module ActiveRecord
assert_equal 2, result.column_types['status'].type_cast(result.last['status'])
end
+ def test_supports_extensions
+ assert_not @conn.supports_extensions?, 'does not support extensions'
+ end
+
+ def test_respond_to_enable_extension
+ assert @conn.respond_to?(:enable_extension)
+ end
+
+ def test_respond_to_disable_extension
+ assert @conn.respond_to?(:disable_extension)
+ end
+
private
def insert(ctx, data, table='ex')
binds = data.map { |name, value|
diff --git a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
index 4cf4bc4c61..8eb9565963 100644
--- a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
@@ -2,7 +2,7 @@ require "cases/helper"
class Group < ActiveRecord::Base
Group.table_name = 'group'
- belongs_to :select, :class_name => 'Select'
+ belongs_to :select
has_one :values
end
diff --git a/activerecord/test/cases/adapters/mysql/statement_pool_test.rb b/activerecord/test/cases/adapters/mysql/statement_pool_test.rb
index 83de90f179..209a0cf464 100644
--- a/activerecord/test/cases/adapters/mysql/statement_pool_test.rb
+++ b/activerecord/test/cases/adapters/mysql/statement_pool_test.rb
@@ -3,20 +3,20 @@ require 'cases/helper'
module ActiveRecord::ConnectionAdapters
class MysqlAdapter
class StatementPoolTest < ActiveRecord::TestCase
- def test_cache_is_per_pid
- return skip('must support fork') unless Process.respond_to?(:fork)
+ if Process.respond_to?(:fork)
+ def test_cache_is_per_pid
+ cache = StatementPool.new nil, 10
+ cache['foo'] = 'bar'
+ assert_equal 'bar', cache['foo']
- cache = StatementPool.new nil, 10
- cache['foo'] = 'bar'
- assert_equal 'bar', cache['foo']
+ pid = fork {
+ lookup = cache['foo'];
+ exit!(!lookup)
+ }
- pid = fork {
- lookup = cache['foo'];
- exit!(!lookup)
- }
-
- Process.waitpid pid
- assert $?.success?, 'process should exit successfully'
+ Process.waitpid pid
+ assert $?.success?, 'process should exit successfully'
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/boolean_test.rb b/activerecord/test/cases/adapters/mysql2/boolean_test.rb
new file mode 100644
index 0000000000..267aa232d9
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/boolean_test.rb
@@ -0,0 +1,91 @@
+require "cases/helper"
+
+class Mysql2BooleanTest < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ class BooleanType < ActiveRecord::Base
+ self.table_name = "mysql_booleans"
+ end
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table("mysql_booleans") do |t|
+ t.boolean "archived"
+ t.string "published", limit: 1
+ end
+ BooleanType.reset_column_information
+
+ @emulate_booleans = ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans
+ end
+
+ teardown do
+ emulate_booleans @emulate_booleans
+ @connection.drop_table "mysql_booleans"
+ end
+
+ test "column type with emulated booleans" do
+ emulate_booleans true
+
+ assert_equal :boolean, boolean_column.type
+ assert_equal :string, string_column.type
+ end
+
+ test "column type without emulated booleans" do
+ emulate_booleans false
+
+ assert_equal :integer, boolean_column.type
+ assert_equal :string, string_column.type
+ end
+
+ test "test type casting with emulated booleans" do
+ emulate_booleans true
+
+ boolean = BooleanType.create!(archived: true, published: true)
+ attributes = boolean.reload.attributes_before_type_cast
+
+ assert_equal 1, attributes["archived"]
+ assert_equal "1", attributes["published"]
+
+ assert_equal 1, @connection.type_cast(true, boolean_column)
+ assert_equal 1, @connection.type_cast(true, string_column)
+ end
+
+ test "test type casting without emulated booleans" do
+ emulate_booleans false
+
+ boolean = BooleanType.create!(archived: true, published: true)
+ attributes = boolean.reload.attributes_before_type_cast
+
+ assert_equal 1, attributes["archived"]
+ assert_equal "1", attributes["published"]
+
+ assert_equal 1, @connection.type_cast(true, boolean_column)
+ assert_equal 1, @connection.type_cast(true, string_column)
+ end
+
+ test "with booleans stored as 1 and 0" do
+ @connection.execute "INSERT INTO mysql_booleans(archived, published) VALUES(1, '1')"
+ boolean = BooleanType.first
+ assert_equal true, boolean.archived
+ assert_equal "1", boolean.published
+ end
+
+ test "with booleans stored as t" do
+ @connection.execute "INSERT INTO mysql_booleans(published) VALUES('t')"
+ boolean = BooleanType.first
+ assert_equal "t", boolean.published
+ end
+
+ def boolean_column
+ BooleanType.columns.find { |c| c.name == 'archived' }
+ end
+
+ def string_column
+ BooleanType.columns.find { |c| c.name == 'published' }
+ end
+
+ def emulate_booleans(value)
+ ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans = value
+ BooleanType.reset_column_information
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index fedd9f603c..9b7202c915 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -3,14 +3,22 @@ require "cases/helper"
class MysqlConnectionTest < ActiveRecord::TestCase
def setup
super
+ @subscriber = SQLSubscriber.new
+ ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber)
@connection = ActiveRecord::Base.connection
- @connection.extend(LogIntercepter)
- @connection.intercepted = true
end
def teardown
- @connection.intercepted = false
- @connection.logged = []
+ ActiveSupport::Notifications.unsubscribe(@subscriber)
+ super
+ end
+
+ def test_bad_connection
+ assert_raise ActiveRecord::NoDatabaseError do
+ configuration = ActiveRecord::Base.configurations['arunit'].merge(database: 'inexistent_activerecord_unittest')
+ connection = ActiveRecord::Base.mysql2_connection(configuration)
+ connection.exec_query('drop table if exists ex')
+ end
end
def test_no_automatic_reconnection_after_timeout
@@ -18,6 +26,11 @@ class MysqlConnectionTest < ActiveRecord::TestCase
@connection.update('set @@wait_timeout=1')
sleep 2
assert !@connection.active?
+
+ # Repair all fixture connections so other tests won't break.
+ @fixture_connections.each do |c|
+ c.verify!
+ end
end
def test_successful_reconnection_after_timeout_with_manual_reconnect
@@ -72,14 +85,14 @@ class MysqlConnectionTest < ActiveRecord::TestCase
def test_logs_name_show_variable
@connection.show_variable 'foo'
- assert_equal "SCHEMA", @connection.logged[0][1]
+ assert_equal "SCHEMA", @subscriber.logged[0][1]
end
def test_logs_name_rename_column_sql
@connection.execute "CREATE TABLE `bar_baz` (`foo` varchar(255))"
- @connection.logged = []
+ @subscriber.logged.clear
@connection.send(:rename_column_sql, 'bar_baz', 'foo', 'foo2')
- assert_equal "SCHEMA", @connection.logged[0][1]
+ assert_equal "SCHEMA", @subscriber.logged[0][1]
ensure
@connection.execute "DROP TABLE `bar_baz`"
end
diff --git a/activerecord/test/cases/adapters/mysql2/explain_test.rb b/activerecord/test/cases/adapters/mysql2/explain_test.rb
index 68ed361aeb..1cd356e868 100644
--- a/activerecord/test/cases/adapters/mysql2/explain_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/explain_test.rb
@@ -10,15 +10,15 @@ module ActiveRecord
def test_explain_for_one_query
explain = Developer.where(:id => 1).explain
assert_match %(EXPLAIN for: SELECT `developers`.* FROM `developers` WHERE `developers`.`id` = 1), explain
- assert_match %(developers | const), explain
+ assert_match %r(developers |.* const), explain
end
def test_explain_with_eager_loading
explain = Developer.where(:id => 1).includes(:audit_logs).explain
assert_match %(EXPLAIN for: SELECT `developers`.* FROM `developers` WHERE `developers`.`id` = 1), explain
- assert_match %(developers | const), explain
+ assert_match %r(developers |.* const), explain
assert_match %(EXPLAIN for: SELECT `audit_logs`.* FROM `audit_logs` WHERE `audit_logs`.`developer_id` IN (1)), explain
- assert_match %(audit_logs | ALL), explain
+ assert_match %r(audit_logs |.* ALL), explain
end
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
index e76617b845..1a82308176 100644
--- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
@@ -2,7 +2,7 @@ require "cases/helper"
class Group < ActiveRecord::Base
Group.table_name = 'group'
- belongs_to :select, :class_name => 'Select'
+ belongs_to :select
has_one :values
end
diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
index 9ecd901eac..ec73ec35aa 100644
--- a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
@@ -4,22 +4,35 @@ module ActiveRecord
module ConnectionAdapters
class Mysql2Adapter
class SchemaMigrationsTest < ActiveRecord::TestCase
- def test_initializes_schema_migrations_for_encoding_utf8mb4
- conn = ActiveRecord::Base.connection
+ def test_renaming_index_on_foreign_key
+ connection.add_index "engines", "car_id"
+ connection.execute "ALTER TABLE engines ADD CONSTRAINT fk_engines_cars FOREIGN KEY (car_id) REFERENCES cars(id)"
+
+ connection.rename_index("engines", "index_engines_on_car_id", "idx_renamed")
+ assert_equal ["idx_renamed"], connection.indexes("engines").map(&:name)
+ ensure
+ connection.execute "ALTER TABLE engines DROP FOREIGN KEY fk_engines_cars"
+ end
+ def test_initializes_schema_migrations_for_encoding_utf8mb4
smtn = ActiveRecord::Migrator.schema_migrations_table_name
- conn.drop_table(smtn) if conn.table_exists?(smtn)
+ connection.drop_table(smtn) if connection.table_exists?(smtn)
- config = conn.instance_variable_get(:@config)
+ config = connection.instance_variable_get(:@config)
original_encoding = config[:encoding]
config[:encoding] = 'utf8mb4'
- conn.initialize_schema_migrations_table
+ connection.initialize_schema_migrations_table
- assert conn.column_exists?(smtn, :version, :string, limit: Mysql2Adapter::MAX_INDEX_LENGTH_FOR_UTF8MB4)
+ assert connection.column_exists?(smtn, :version, :string, limit: Mysql2Adapter::MAX_INDEX_LENGTH_FOR_UTF8MB4)
ensure
config[:encoding] = original_encoding
end
+
+ private
+ def connection
+ @connection ||= ActiveRecord::Base.connection
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/schema_test.rb b/activerecord/test/cases/adapters/mysql2/schema_test.rb
index 5db60ff8a0..43c9116b5a 100644
--- a/activerecord/test/cases/adapters/mysql2/schema_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/schema_test.rb
@@ -65,6 +65,15 @@ module ActiveRecord
assert_nil index_c.using
assert_equal :fulltext, index_c.type
end
+
+ def test_drop_temporary_table
+ @connection.transaction do
+ @connection.create_table(:temp_table, temporary: true)
+ # if it doesn't properly say DROP TEMPORARY TABLE, the transaction commit
+ # will complain that no transaction is active
+ @connection.drop_table(:temp_table, temporary: true)
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/oracle/synonym_test.rb b/activerecord/test/cases/adapters/oracle/synonym_test.rb
deleted file mode 100644
index b9a422a6ca..0000000000
--- a/activerecord/test/cases/adapters/oracle/synonym_test.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-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
diff --git a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb
index 16329689c0..22dd48e113 100644
--- a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb
@@ -25,9 +25,7 @@ class PostgresqlActiveSchemaTest < ActiveRecord::TestCase
def test_add_index
# add_index calls index_name_exists? which can't work since execute is stubbed
- ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:define_method, :index_name_exists?) do |*|
- false
- end
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.stubs(:index_name_exists?).returns(false)
expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" ("last_name") WHERE state = 'active')
assert_equal expected, add_index(:people, :last_name, :unique => true, :where => "state = 'active'")
@@ -51,8 +49,6 @@ class PostgresqlActiveSchemaTest < ActiveRecord::TestCase
expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" USING gist ("last_name") WHERE state = 'active')
assert_equal expected, add_index(:people, :last_name, :unique => true, :where => "state = 'active'", :using => :gist)
-
- ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:remove_method, :index_name_exists?)
end
private
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 61a3a2ba0f..d71e2aa2bb 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -10,11 +10,12 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
def setup
@connection = ActiveRecord::Base.connection
- @connection.transaction do
- @connection.create_table('pg_arrays') do |t|
- t.string 'tags', :array => true
- end
+ @connection.transaction do
+ @connection.create_table('pg_arrays') do |t|
+ t.string 'tags', array: true
+ t.integer 'ratings', array: true
end
+ end
@column = PgArray.columns.find { |c| c.name == 'tags' }
end
@@ -25,11 +26,36 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
def test_column
assert_equal :string, @column.type
assert @column.array
+ assert_not @column.text?
+
+ ratings_column = PgArray.columns_hash['ratings']
+ assert_equal :integer, ratings_column.type
+ assert ratings_column.array
+ assert_not ratings_column.number?
end
- def test_type_cast_array
- assert @column
+ def test_change_column_with_array
+ @connection.add_column :pg_arrays, :snippets, :string, array: true, default: []
+ @connection.change_column :pg_arrays, :snippets, :text, array: true, default: "{}"
+
+ PgArray.reset_column_information
+ column = PgArray.columns.find { |c| c.name == 'snippets' }
+
+ assert_equal :text, column.type
+ assert_equal [], column.default
+ assert column.array
+ end
+ def test_change_column_cant_make_non_array_column_to_array
+ @connection.add_column :pg_arrays, :a_string, :string
+ assert_raises ActiveRecord::StatementInvalid do
+ @connection.transaction do
+ @connection.change_column :pg_arrays, :a_string, :string, array: true
+ end
+ end
+ end
+
+ def test_type_cast_array
data = '{1,2,3}'
oid_type = @column.instance_variable_get('@oid_type').subtype
# we are getting the instance variable in this test, but in the
@@ -44,6 +70,12 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
assert_equal([nil], @column.type_cast('{NULL}'))
end
+ def test_type_cast_integers
+ x = PgArray.new(ratings: ['1', '2'])
+ assert x.save!
+ assert_equal(['1', '2'], x.ratings)
+ end
+
def test_rewrite
@connection.execute "insert into pg_arrays (tags) VALUES ('{1,2,3}')"
x = PgArray.first
@@ -57,28 +89,32 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
assert_equal(['1','2','3'], x.tags)
end
- def test_multi_dimensional
- assert_cycle([['1','2'],['2','3']])
+ def test_multi_dimensional_with_strings
+ assert_cycle(:tags, [[['1'], ['2']], [['2'], ['3']]])
+ end
+
+ def test_multi_dimensional_with_integers
+ assert_cycle(:ratings, [[[1], [7]], [[8], [10]]])
end
def test_strings_with_quotes
- assert_cycle(['this has','some "s that need to be escaped"'])
+ assert_cycle(:tags, ['this has','some "s that need to be escaped"'])
end
def test_strings_with_commas
- assert_cycle(['this,has','many,values'])
+ assert_cycle(:tags, ['this,has','many,values'])
end
def test_strings_with_array_delimiters
- assert_cycle(['{','}'])
+ assert_cycle(:tags, ['{','}'])
end
def test_strings_with_null_strings
- assert_cycle(['NULL','NULL'])
+ assert_cycle(:tags, ['NULL','NULL'])
end
def test_contains_nils
- assert_cycle(['1',nil,nil])
+ assert_cycle(:tags, ['1',nil,nil])
end
def test_insert_fixture
@@ -87,18 +123,33 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
assert_equal(PgArray.last.tags, tag_values)
end
+ def test_attribute_for_inspect_for_array_field
+ record = PgArray.new { |a| a.ratings = (1..11).to_a }
+ assert_equal("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]", record.attribute_for_inspect(:ratings))
+ end
+
+ def test_update_all
+ pg_array = PgArray.create! tags: ["one", "two", "three"]
+
+ PgArray.update_all tags: ["four", "five"]
+ assert_equal ["four", "five"], pg_array.reload.tags
+
+ PgArray.update_all tags: []
+ assert_equal [], pg_array.reload.tags
+ end
+
private
- def assert_cycle array
+ def assert_cycle field, array
# test creation
- x = PgArray.create!(:tags => array)
+ x = PgArray.create!(field => array)
x.reload
- assert_equal(array, x.tags)
+ assert_equal(array, x.public_send(field))
# test updating
- x = PgArray.create!(:tags => [])
- x.tags = array
+ x = PgArray.create!(field => [])
+ x.public_send("#{field}=", array)
x.save!
x.reload
- assert_equal(array, x.tags)
+ assert_equal(array, x.public_send(field))
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
index d7d77f96e2..b8dd35c4c5 100644
--- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
@@ -15,6 +15,7 @@ class PostgresqlByteaTest < ActiveRecord::TestCase
@connection.transaction do
@connection.create_table('bytea_data_type') do |t|
t.binary 'payload'
+ t.binary 'serialized'
end
end
end
@@ -65,7 +66,7 @@ class PostgresqlByteaTest < ActiveRecord::TestCase
def test_write_value
data = "\u001F"
record = ByteaDataType.create(payload: data)
- refute record.new_record?
+ assert_not record.new_record?
assert_equal(data, record.payload)
end
@@ -73,15 +74,31 @@ class PostgresqlByteaTest < ActiveRecord::TestCase
data = File.read(File.join(File.dirname(__FILE__), '..', '..', '..', 'assets', 'example.log'))
assert(data.size > 1)
record = ByteaDataType.create(payload: data)
- refute record.new_record?
+ assert_not record.new_record?
assert_equal(data, record.payload)
assert_equal(data, ByteaDataType.where(id: record.id).first.payload)
end
def test_write_nil
record = ByteaDataType.create(payload: nil)
- refute record.new_record?
+ assert_not record.new_record?
assert_equal(nil, record.payload)
assert_equal(nil, ByteaDataType.where(id: record.id).first.payload)
end
+
+ class Serializer
+ def load(str); str; end
+ def dump(str); str; end
+ end
+
+ def test_serialize
+ klass = Class.new(ByteaDataType) {
+ serialize :serialized, Serializer.new
+ }
+ obj = klass.new
+ obj.serialized = "hello world"
+ obj.save!
+ obj.reload
+ assert_equal "hello world", obj.serialized
+ end
end
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index 6b726ce875..90cca7d3e6 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -7,14 +7,14 @@ module ActiveRecord
def setup
super
+ @subscriber = SQLSubscriber.new
+ ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber)
@connection = ActiveRecord::Base.connection
- @connection.extend(LogIntercepter)
- @connection.intercepted = true
end
def teardown
- @connection.intercepted = false
- @connection.logged = []
+ ActiveSupport::Notifications.unsubscribe(@subscriber)
+ super
end
def test_encoding
@@ -47,38 +47,48 @@ module ActiveRecord
def test_tables_logs_name
@connection.tables('hello')
- assert_equal 'SCHEMA', @connection.logged[0][1]
+ assert_equal 'SCHEMA', @subscriber.logged[0][1]
end
def test_indexes_logs_name
@connection.indexes('items', 'hello')
- assert_equal 'SCHEMA', @connection.logged[0][1]
+ assert_equal 'SCHEMA', @subscriber.logged[0][1]
end
def test_table_exists_logs_name
@connection.table_exists?('items')
- assert_equal 'SCHEMA', @connection.logged[0][1]
+ assert_equal 'SCHEMA', @subscriber.logged[0][1]
end
def test_table_alias_length_logs_name
@connection.instance_variable_set("@table_alias_length", nil)
@connection.table_alias_length
- assert_equal 'SCHEMA', @connection.logged[0][1]
+ assert_equal 'SCHEMA', @subscriber.logged[0][1]
end
def test_current_database_logs_name
@connection.current_database
- assert_equal 'SCHEMA', @connection.logged[0][1]
+ assert_equal 'SCHEMA', @subscriber.logged[0][1]
end
def test_encoding_logs_name
@connection.encoding
- assert_equal 'SCHEMA', @connection.logged[0][1]
+ assert_equal 'SCHEMA', @subscriber.logged[0][1]
end
def test_schema_names_logs_name
@connection.schema_names
- assert_equal 'SCHEMA', @connection.logged[0][1]
+ assert_equal 'SCHEMA', @subscriber.logged[0][1]
+ end
+
+ def test_statement_key_is_logged
+ bindval = 1
+ @connection.exec_query('SELECT $1::integer', 'SQL', [[nil, bindval]])
+ name = @subscriber.payloads.last[:statement_name]
+ assert name
+ res = @connection.exec_query("EXPLAIN (FORMAT JSON) EXECUTE #{name}(#{bindval})")
+ plan = res.column_types['QUERY PLAN'].type_cast res.rows.first.first
+ assert_operator plan.length, :>, 0
end
# Must have with_manual_interventions set to true for this
@@ -88,33 +98,33 @@ module ActiveRecord
# you know the incantation to do that.
# To restart PostgreSQL 9.1 on OS X, installed via MacPorts, ...
# sudo su postgres -c "pg_ctl restart -D /opt/local/var/db/postgresql91/defaultdb/ -m fast"
- def test_reconnection_after_actual_disconnection_with_verify
- skip "with_manual_interventions is false in configuration" unless ARTest.config['with_manual_interventions']
-
- original_connection_pid = @connection.query('select pg_backend_pid()')
+ if ARTest.config['with_manual_interventions']
+ def test_reconnection_after_actual_disconnection_with_verify
+ original_connection_pid = @connection.query('select pg_backend_pid()')
- # Sanity check.
- assert @connection.active?
+ # Sanity check.
+ assert @connection.active?
- puts 'Kill the connection now (e.g. by restarting the PostgreSQL ' +
- 'server with the "-m fast" option) and then press enter.'
- $stdin.gets
+ puts 'Kill the connection now (e.g. by restarting the PostgreSQL ' +
+ 'server with the "-m fast" option) and then press enter.'
+ $stdin.gets
- @connection.verify!
+ @connection.verify!
- assert @connection.active?
+ assert @connection.active?
- # If we get no exception here, then either we re-connected successfully, or
- # we never actually got disconnected.
- new_connection_pid = @connection.query('select pg_backend_pid()')
+ # If we get no exception here, then either we re-connected successfully, or
+ # we never actually got disconnected.
+ new_connection_pid = @connection.query('select pg_backend_pid()')
- assert_not_equal original_connection_pid, new_connection_pid,
- "umm -- looks like you didn't break the connection, because we're still " +
- "successfully querying with the same connection pid."
+ assert_not_equal original_connection_pid, new_connection_pid,
+ "umm -- looks like you didn't break the connection, because we're still " +
+ "successfully querying with the same connection pid."
- # Repair all fixture connections so other tests won't break.
- @fixture_connections.each do |c|
- c.verify!
+ # Repair all fixture connections so other tests won't break.
+ @fixture_connections.each do |c|
+ c.verify!
+ end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index b5d7ea603e..04a458fbce 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -3,9 +3,6 @@ require "cases/helper"
class PostgresqlArray < ActiveRecord::Base
end
-class PostgresqlRange < ActiveRecord::Base
-end
-
class PostgresqlTsvector < ActiveRecord::Base
end
@@ -46,104 +43,6 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
@connection.execute("INSERT INTO postgresql_arrays (id, commission_by_quarter, nicknames) VALUES (1, '{35000,21000,18000,17000}', '{foo,bar,baz}')")
@first_array = PostgresqlArray.find(1)
- @connection.execute <<_SQL if @connection.supports_ranges?
- INSERT INTO postgresql_ranges (
- date_range,
- num_range,
- ts_range,
- tstz_range,
- int4_range,
- int8_range
- ) VALUES (
- '[''2012-01-02'', ''2012-01-04'']',
- '[0.1, 0.2]',
- '[''2010-01-01 14:30'', ''2011-01-01 14:30'']',
- '[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']',
- '[1, 10]',
- '[10, 100]'
- )
-_SQL
-
- @connection.execute <<_SQL if @connection.supports_ranges?
- INSERT INTO postgresql_ranges (
- date_range,
- num_range,
- ts_range,
- tstz_range,
- int4_range,
- int8_range
- ) VALUES (
- '(''2012-01-02'', ''2012-01-04'')',
- '[0.1, 0.2)',
- '[''2010-01-01 14:30'', ''2011-01-01 14:30'')',
- '[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'')',
- '(1, 10)',
- '(10, 100)'
- )
-_SQL
-
- @connection.execute <<_SQL if @connection.supports_ranges?
- INSERT INTO postgresql_ranges (
- date_range,
- num_range,
- ts_range,
- tstz_range,
- int4_range,
- int8_range
- ) VALUES (
- '(''2012-01-02'',]',
- '[0.1,]',
- '[''2010-01-01 14:30'',]',
- '[''2010-01-01 14:30:00+05'',]',
- '(1,]',
- '(10,]'
- )
-_SQL
-
- @connection.execute <<_SQL if @connection.supports_ranges?
- INSERT INTO postgresql_ranges (
- date_range,
- num_range,
- ts_range,
- tstz_range,
- int4_range,
- int8_range
- ) VALUES (
- '[,]',
- '[,]',
- '[,]',
- '[,]',
- '[,]',
- '[,]'
- )
-_SQL
-
- @connection.execute <<_SQL if @connection.supports_ranges?
- INSERT INTO postgresql_ranges (
- date_range,
- num_range,
- ts_range,
- tstz_range,
- int4_range,
- int8_range
- ) VALUES (
- '(''2012-01-02'', ''2012-01-02'')',
- '(0.1, 0.1)',
- '(''2010-01-01 14:30'', ''2010-01-01 14:30'')',
- '(''2010-01-01 14:30:00+05'', ''2010-01-01 06:30:00-03'')',
- '(1, 1)',
- '(10, 10)'
- )
-_SQL
-
- if @connection.supports_ranges?
- @first_range = PostgresqlRange.find(1)
- @second_range = PostgresqlRange.find(2)
- @third_range = PostgresqlRange.find(3)
- @fourth_range = PostgresqlRange.find(4)
- @empty_range = PostgresqlRange.find(5)
- end
-
@connection.execute("INSERT INTO postgresql_tsvectors (id, text_vector) VALUES (1, ' ''text'' ''vector'' ')")
@first_tsvector = PostgresqlTsvector.find(1)
@@ -184,16 +83,6 @@ _SQL
assert_equal :text, @first_array.column_for_attribute(:nicknames).type
end
- def test_data_type_of_range_types
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- assert_equal :daterange, @first_range.column_for_attribute(:date_range).type
- assert_equal :numrange, @first_range.column_for_attribute(:num_range).type
- assert_equal :tsrange, @first_range.column_for_attribute(:ts_range).type
- assert_equal :tstzrange, @first_range.column_for_attribute(:tstz_range).type
- assert_equal :int4range, @first_range.column_for_attribute(:int4_range).type
- assert_equal :int8range, @first_range.column_for_attribute(:int8_range).type
- end
-
def test_data_type_of_tsvector_types
assert_equal :tsvector, @first_tsvector.column_for_attribute(:text_vector).type
end
@@ -240,208 +129,28 @@ _SQL
assert_equal "'text' 'vector'", @first_tsvector.text_vector
end
- def test_int4range_values
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- assert_equal 1...11, @first_range.int4_range
- assert_equal 2...10, @second_range.int4_range
- assert_equal 2...Float::INFINITY, @third_range.int4_range
- assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int4_range)
- assert_equal nil, @empty_range.int4_range
- end
-
- def test_int8range_values
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- assert_equal 10...101, @first_range.int8_range
- assert_equal 11...100, @second_range.int8_range
- assert_equal 11...Float::INFINITY, @third_range.int8_range
- assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int8_range)
- assert_equal nil, @empty_range.int8_range
- end
-
- def test_daterange_values
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- assert_equal Date.new(2012, 1, 2)...Date.new(2012, 1, 5), @first_range.date_range
- assert_equal Date.new(2012, 1, 3)...Date.new(2012, 1, 4), @second_range.date_range
- assert_equal Date.new(2012, 1, 3)...Float::INFINITY, @third_range.date_range
- assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.date_range)
- assert_equal nil, @empty_range.date_range
- end
-
- def test_numrange_values
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- assert_equal BigDecimal.new('0.1')..BigDecimal.new('0.2'), @first_range.num_range
- assert_equal BigDecimal.new('0.1')...BigDecimal.new('0.2'), @second_range.num_range
- assert_equal BigDecimal.new('0.1')...BigDecimal.new('Infinity'), @third_range.num_range
- assert_equal BigDecimal.new('-Infinity')...BigDecimal.new('Infinity'), @fourth_range.num_range
- assert_equal nil, @empty_range.num_range
- end
-
- def test_tsrange_values
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- tz = ::ActiveRecord::Base.default_timezone
- assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)..Time.send(tz, 2011, 1, 1, 14, 30, 0), @first_range.ts_range
- assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 1, 1, 14, 30, 0), @second_range.ts_range
- assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.ts_range)
- assert_equal nil, @empty_range.ts_range
- end
-
- def test_tstzrange_values
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- assert_equal Time.parse('2010-01-01 09:30:00 UTC')..Time.parse('2011-01-01 17:30:00 UTC'), @first_range.tstz_range
- assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Time.parse('2011-01-01 17:30:00 UTC'), @second_range.tstz_range
- assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.tstz_range)
- assert_equal nil, @empty_range.tstz_range
- end
-
def test_money_values
assert_equal 567.89, @first_money.wealth
assert_equal(-567.89, @second_money.wealth)
end
- def test_create_tstzrange
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- tstzrange = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2011-02-02 14:30:00 CDT')
- range = PostgresqlRange.new(:tstz_range => tstzrange)
- assert range.save
- assert range.reload
- assert_equal range.tstz_range, tstzrange
- assert_equal range.tstz_range, Time.parse('2010-01-01 13:30:00 UTC')...Time.parse('2011-02-02 19:30:00 UTC')
- end
-
- def test_update_tstzrange
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- new_tstzrange = Time.parse('2010-01-01 14:30:00 CDT')...Time.parse('2011-02-02 14:30:00 CET')
- assert @first_range.tstz_range = new_tstzrange
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.tstz_range, new_tstzrange
- assert @first_range.tstz_range = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2010-01-01 13:30:00 +0000')
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.tstz_range, nil
- end
-
- def test_create_tsrange
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- tz = ::ActiveRecord::Base.default_timezone
- tsrange = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0)
- range = PostgresqlRange.new(:ts_range => tsrange)
- assert range.save
- assert range.reload
- assert_equal range.ts_range, tsrange
- end
-
- def test_update_tsrange
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- tz = ::ActiveRecord::Base.default_timezone
- new_tsrange = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0)
- assert @first_range.ts_range = new_tsrange
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.ts_range, new_tsrange
- assert @first_range.ts_range = Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2010, 1, 1, 14, 30, 0)
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.ts_range, nil
- end
-
- def test_create_numrange
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- numrange = BigDecimal.new('0.5')...BigDecimal.new('1')
- range = PostgresqlRange.new(:num_range => numrange)
- assert range.save
- assert range.reload
- assert_equal range.num_range, numrange
- end
-
- def test_update_numrange
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- new_numrange = BigDecimal.new('0.5')...BigDecimal.new('1')
- assert @first_range.num_range = new_numrange
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.num_range, new_numrange
- assert @first_range.num_range = BigDecimal.new('0.5')...BigDecimal.new('0.5')
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.num_range, nil
- end
-
- def test_create_daterange
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- daterange = Range.new(Date.new(2012, 1, 1), Date.new(2013, 1, 1), true)
- range = PostgresqlRange.new(:date_range => daterange)
- assert range.save
- assert range.reload
- assert_equal range.date_range, daterange
- end
-
- def test_update_daterange
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- new_daterange = Date.new(2012, 2, 3)...Date.new(2012, 2, 10)
- assert @first_range.date_range = new_daterange
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.date_range, new_daterange
- assert @first_range.date_range = Date.new(2012, 2, 3)...Date.new(2012, 2, 3)
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.date_range, nil
- end
-
- def test_create_int4range
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- int4range = Range.new(3, 50, true)
- range = PostgresqlRange.new(:int4_range => int4range)
- assert range.save
- assert range.reload
- assert_equal range.int4_range, int4range
- end
-
- def test_update_int4range
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- new_int4range = 6...10
- assert @first_range.int4_range = new_int4range
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.int4_range, new_int4range
- assert @first_range.int4_range = 3...3
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.int4_range, nil
- end
-
- def test_create_int8range
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- int8range = Range.new(30, 50, true)
- range = PostgresqlRange.new(:int8_range => int8range)
- assert range.save
- assert range.reload
- assert_equal range.int8_range, int8range
- end
-
- def test_update_int8range
- skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges?
- new_int8range = 60000...10000000
- assert @first_range.int8_range = new_int8range
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.int8_range, new_int8range
- assert @first_range.int8_range = 39999...39999
- assert @first_range.save
- assert @first_range.reload
- assert_equal @first_range.int8_range, nil
+ def test_money_type_cast
+ column = PostgresqlMoney.columns.find { |c| c.name == 'wealth' }
+ assert_equal(12345678.12, column.type_cast("$12,345,678.12"))
+ assert_equal(12345678.12, column.type_cast("$12.345.678,12"))
+ assert_equal(-1.15, column.type_cast("-$1.15"))
+ assert_equal(-2.25, column.type_cast("($2.25)"))
end
def test_update_tsvector
new_text_vector = "'new' 'text' 'vector'"
- assert @first_tsvector.text_vector = new_text_vector
+ @first_tsvector.text_vector = new_text_vector
assert @first_tsvector.save
assert @first_tsvector.reload
- assert @first_tsvector.text_vector = new_text_vector
+ @first_tsvector.text_vector = new_text_vector
assert @first_tsvector.save
assert @first_tsvector.reload
- assert_equal @first_tsvector.text_vector, new_text_vector
+ assert_equal new_text_vector, @first_tsvector.text_vector
end
def test_number_values
@@ -479,31 +188,31 @@ _SQL
def test_update_integer_array
new_value = [32800,95000,29350,17000]
- assert @first_array.commission_by_quarter = new_value
+ @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_equal new_value, @first_array.commission_by_quarter
+ @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_equal new_value, @first_array.commission_by_quarter
end
def test_update_text_array
new_value = ['robby','robert','rob','robbie']
- assert @first_array.nicknames = new_value
+ @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_equal new_value, @first_array.nicknames
+ @first_array.nicknames = new_value
assert @first_array.save
assert @first_array.reload
- assert_equal @first_array.nicknames, new_value
+ assert_equal new_value, @first_array.nicknames
end
def test_update_money
new_value = BigDecimal.new('123.45')
- assert @first_money.wealth = new_value
+ @first_money.wealth = new_value
assert @first_money.save
assert @first_money.reload
assert_equal new_value, @first_money.wealth
@@ -512,28 +221,28 @@ _SQL
def test_update_number
new_single = 789.012
new_double = 789012.345
- assert @first_number.single = new_single
- assert @first_number.double = new_double
+ @first_number.single = new_single
+ @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
+ assert_equal new_single, @first_number.single
+ assert_equal new_double, @first_number.double
end
def test_update_time
- assert @first_time.time_interval = '2 years 3 minutes'
+ @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'
+ assert_equal '2 years 00:03:00', @first_time.time_interval
end
def test_update_network_address
new_inet_address = '10.1.2.3/32'
new_cidr_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
+ @first_network_address.cidr_address = new_cidr_address
+ @first_network_address.inet_address = new_inet_address
+ @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
@@ -544,61 +253,65 @@ _SQL
def test_update_bit_string
new_bit_string = '11111111'
new_bit_string_varying = '0xFF'
- assert @first_bit_string.bit_string = new_bit_string
- assert @first_bit_string.bit_string_varying = new_bit_string_varying
+ @first_bit_string.bit_string = new_bit_string
+ @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 new_bit_string, @first_bit_string.bit_string
assert_equal @first_bit_string.bit_string, @first_bit_string.bit_string_varying
end
-
+
def test_invalid_hex_string
new_bit_string = 'FF'
@first_bit_string.bit_string = new_bit_string
assert_raise(ActiveRecord::StatementInvalid) { assert @first_bit_string.save }
end
+ def test_invalid_network_address
+ @first_network_address.cidr_address = 'invalid addr'
+ assert_nil @first_network_address.cidr_address
+ assert_equal 'invalid addr', @first_network_address.cidr_address_before_type_cast
+ assert @first_network_address.save
+
+ @first_network_address.reload
+
+ @first_network_address.inet_address = 'invalid addr'
+ assert_nil @first_network_address.inet_address
+ assert_equal 'invalid addr', @first_network_address.inet_address_before_type_cast
+ assert @first_network_address.save
+ end
+
def test_update_oid
new_value = 567890
- assert @first_oid.obj_id = new_value
+ @first_oid.obj_id = new_value
assert @first_oid.save
assert @first_oid.reload
- assert_equal @first_oid.obj_id, new_value
+ assert_equal new_value, @first_oid.obj_id
end
def test_timestamp_with_zone_values_with_rails_time_zone_support
- old_tz = ActiveRecord::Base.time_zone_aware_attributes
- old_default_tz = ActiveRecord::Base.default_timezone
-
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
+ with_timezone_config default: :utc, aware_attributes: true do
+ @connection.reconnect!
- @connection.reconnect!
-
- @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1)
- assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time
- assert_instance_of Time, @first_timestamp_with_zone.time
+ @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1)
+ assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time
+ assert_instance_of Time, @first_timestamp_with_zone.time
+ end
ensure
- ActiveRecord::Base.default_timezone = old_default_tz
- ActiveRecord::Base.time_zone_aware_attributes = old_tz
@connection.reconnect!
end
def test_timestamp_with_zone_values_without_rails_time_zone_support
- old_tz = ActiveRecord::Base.time_zone_aware_attributes
- old_default_tz = ActiveRecord::Base.default_timezone
-
- ActiveRecord::Base.time_zone_aware_attributes = false
- ActiveRecord::Base.default_timezone = :local
-
- @connection.reconnect!
-
- @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1)
- assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time
- assert_instance_of Time, @first_timestamp_with_zone.time
+ with_timezone_config default: :local, aware_attributes: false do
+ @connection.reconnect!
+ # make sure to use a non-UTC time zone
+ @connection.execute("SET time zone 'America/Jamaica'", 'SCHEMA')
+
+ @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1)
+ assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time
+ assert_instance_of Time, @first_timestamp_with_zone.time
+ end
ensure
- ActiveRecord::Base.default_timezone = old_default_tz
- ActiveRecord::Base.time_zone_aware_attributes = old_tz
@connection.reconnect!
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
index e434b4861c..d8782f5eaa 100644
--- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -7,15 +7,13 @@ require 'active_record/connection_adapters/postgresql_adapter'
class PostgresqlHstoreTest < ActiveRecord::TestCase
class Hstore < ActiveRecord::Base
self.table_name = 'hstores'
+
+ store_accessor :settings, :language, :timezone
end
def setup
@connection = ActiveRecord::Base.connection
- unless @connection.supports_extensions?
- return skip "do not test on PG without hstore"
- end
-
unless @connection.extension_enabled?('hstore')
@connection.enable_extension 'hstore'
@connection.commit_db_transaction
@@ -26,6 +24,7 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
@connection.transaction do
@connection.create_table('hstores') do |t|
t.hstore 'tags', :default => ''
+ t.hstore 'settings'
end
end
@column = Hstore.columns.find { |c| c.name == 'tags' }
@@ -35,166 +34,220 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
@connection.execute 'drop table if exists hstores'
end
- def test_hstore_included_in_extensions
- assert @connection.respond_to?(:extensions), "connection should have a list of extensions"
- assert @connection.extensions.include?('hstore'), "extension list should include hstore"
- end
+ if ActiveRecord::Base.connection.supports_extensions?
+ def test_hstore_included_in_extensions
+ assert @connection.respond_to?(:extensions), "connection should have a list of extensions"
+ assert @connection.extensions.include?('hstore'), "extension list should include hstore"
+ end
- def test_disable_enable_hstore
- assert @connection.extension_enabled?('hstore')
- @connection.disable_extension 'hstore'
- assert_not @connection.extension_enabled?('hstore')
- @connection.enable_extension 'hstore'
- assert @connection.extension_enabled?('hstore')
- ensure
- # Restore column(s) dropped by `drop extension hstore cascade;`
- load_schema
- end
+ def test_disable_enable_hstore
+ assert @connection.extension_enabled?('hstore')
+ @connection.disable_extension 'hstore'
+ assert_not @connection.extension_enabled?('hstore')
+ @connection.enable_extension 'hstore'
+ assert @connection.extension_enabled?('hstore')
+ ensure
+ # Restore column(s) dropped by `drop extension hstore cascade;`
+ load_schema
+ end
- def test_column
- assert_equal :hstore, @column.type
- end
+ def test_column
+ assert_equal :hstore, @column.type
+ end
- def test_change_table_supports_hstore
- @connection.transaction do
- @connection.change_table('hstores') do |t|
- t.hstore 'users', default: ''
+ def test_change_table_supports_hstore
+ @connection.transaction do
+ @connection.change_table('hstores') do |t|
+ t.hstore 'users', default: ''
+ end
+ Hstore.reset_column_information
+ column = Hstore.columns.find { |c| c.name == 'users' }
+ assert_equal :hstore, column.type
+
+ raise ActiveRecord::Rollback # reset the schema change
end
+ ensure
Hstore.reset_column_information
- column = Hstore.columns.find { |c| c.name == 'users' }
- assert_equal :hstore, column.type
+ end
+
+ def test_hstore_migration
+ hstore_migration = Class.new(ActiveRecord::Migration) do
+ def change
+ change_table("hstores") do |t|
+ t.hstore :keys
+ end
+ end
+ end
- raise ActiveRecord::Rollback # reset the schema change
+ hstore_migration.new.suppress_messages do
+ hstore_migration.migrate(:up)
+ assert_includes @connection.columns(:hstores).map(&:name), "keys"
+ hstore_migration.migrate(:down)
+ assert_not_includes @connection.columns(:hstores).map(&:name), "keys"
+ end
end
- ensure
- Hstore.reset_column_information
- end
- def test_type_cast_hstore
- assert @column
+ def test_cast_value_on_write
+ x = Hstore.new tags: {"bool" => true, "number" => 5}
+ assert_equal({"bool" => "true", "number" => "5"}, x.tags)
+ x.save
+ assert_equal({"bool" => "true", "number" => "5"}, x.reload.tags)
+ end
- data = "\"1\"=>\"2\""
- hash = @column.class.string_to_hstore data
- assert_equal({'1' => '2'}, hash)
- assert_equal({'1' => '2'}, @column.type_cast(data))
+ def test_type_cast_hstore
+ assert @column
- assert_equal({}, @column.type_cast(""))
- assert_equal({'key'=>nil}, @column.type_cast('key => NULL'))
- assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast(%q(c=>"}", "\"a\""=>"b \"a b")))
- end
+ data = "\"1\"=>\"2\""
+ hash = @column.class.string_to_hstore data
+ assert_equal({'1' => '2'}, hash)
+ assert_equal({'1' => '2'}, @column.type_cast(data))
- def test_gen1
- assert_equal(%q(" "=>""), @column.class.hstore_to_string({' '=>''}))
- end
+ assert_equal({}, @column.type_cast(""))
+ assert_equal({'key'=>nil}, @column.type_cast('key => NULL'))
+ assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast(%q(c=>"}", "\"a\""=>"b \"a b")))
+ end
- def test_gen2
- assert_equal(%q(","=>""), @column.class.hstore_to_string({','=>''}))
- end
+ def test_with_store_accessors
+ x = Hstore.new(language: "fr", timezone: "GMT")
+ assert_equal "fr", x.language
+ assert_equal "GMT", x.timezone
- def test_gen3
- assert_equal(%q("="=>""), @column.class.hstore_to_string({'='=>''}))
- end
+ x.save!
+ x = Hstore.first
+ assert_equal "fr", x.language
+ assert_equal "GMT", x.timezone
- def test_gen4
- assert_equal(%q(">"=>""), @column.class.hstore_to_string({'>'=>''}))
- end
+ x.language = "de"
+ x.save!
- def test_parse1
- assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @column.type_cast('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
- end
+ x = Hstore.first
+ assert_equal "de", x.language
+ assert_equal "GMT", x.timezone
+ end
- def test_parse2
- assert_equal({" " => " "}, @column.type_cast("\\ =>\\ "))
- end
+ def test_gen1
+ assert_equal(%q(" "=>""), @column.class.hstore_to_string({' '=>''}))
+ end
- def test_parse3
- assert_equal({"=" => ">"}, @column.type_cast("==>>"))
- end
+ def test_gen2
+ assert_equal(%q(","=>""), @column.class.hstore_to_string({','=>''}))
+ end
- def test_parse4
- assert_equal({"=a"=>"q=w"}, @column.type_cast('\=a=>q=w'))
- end
+ def test_gen3
+ assert_equal(%q("="=>""), @column.class.hstore_to_string({'='=>''}))
+ end
- def test_parse5
- assert_equal({"=a"=>"q=w"}, @column.type_cast('"=a"=>q\=w'))
- end
+ def test_gen4
+ assert_equal(%q(">"=>""), @column.class.hstore_to_string({'>'=>''}))
+ end
- def test_parse6
- assert_equal({"\"a"=>"q>w"}, @column.type_cast('"\"a"=>q>w'))
- end
+ def test_parse1
+ assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @column.type_cast('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
+ end
- def test_parse7
- assert_equal({"\"a"=>"q\"w"}, @column.type_cast('\"a=>q"w'))
- end
+ def test_parse2
+ assert_equal({" " => " "}, @column.type_cast("\\ =>\\ "))
+ end
- def test_rewrite
- @connection.execute "insert into hstores (tags) VALUES ('1=>2')"
- x = Hstore.first
- x.tags = { '"a\'' => 'b' }
- assert x.save!
- end
+ def test_parse3
+ assert_equal({"=" => ">"}, @column.type_cast("==>>"))
+ end
+ def test_parse4
+ assert_equal({"=a"=>"q=w"}, @column.type_cast('\=a=>q=w'))
+ end
- def test_select
- @connection.execute "insert into hstores (tags) VALUES ('1=>2')"
- x = Hstore.first
- assert_equal({'1' => '2'}, x.tags)
- end
+ def test_parse5
+ assert_equal({"=a"=>"q=w"}, @column.type_cast('"=a"=>q\=w'))
+ end
- def test_select_multikey
- @connection.execute "insert into hstores (tags) VALUES ('1=>2,2=>3')"
- x = Hstore.first
- assert_equal({'1' => '2', '2' => '3'}, x.tags)
- end
+ def test_parse6
+ assert_equal({"\"a"=>"q>w"}, @column.type_cast('"\"a"=>q>w'))
+ end
- def test_create
- assert_cycle('a' => 'b', '1' => '2')
- end
+ def test_parse7
+ assert_equal({"\"a"=>"q\"w"}, @column.type_cast('\"a=>q"w'))
+ end
- def test_nil
- assert_cycle('a' => nil)
- end
+ def test_rewrite
+ @connection.execute "insert into hstores (tags) VALUES ('1=>2')"
+ x = Hstore.first
+ x.tags = { '"a\'' => 'b' }
+ assert x.save!
+ end
- def test_quotes
- assert_cycle('a' => 'b"ar', '1"foo' => '2')
- end
+ def test_select
+ @connection.execute "insert into hstores (tags) VALUES ('1=>2')"
+ x = Hstore.first
+ assert_equal({'1' => '2'}, x.tags)
+ end
- def test_whitespace
- assert_cycle('a b' => 'b ar', '1"foo' => '2')
- end
+ def test_select_multikey
+ @connection.execute "insert into hstores (tags) VALUES ('1=>2,2=>3')"
+ x = Hstore.first
+ assert_equal({'1' => '2', '2' => '3'}, x.tags)
+ end
- def test_backslash
- assert_cycle('a\\b' => 'b\\ar', '1"foo' => '2')
- end
+ def test_create
+ assert_cycle('a' => 'b', '1' => '2')
+ end
- def test_comma
- assert_cycle('a, b' => 'bar', '1"foo' => '2')
- end
+ def test_nil
+ assert_cycle('a' => nil)
+ end
- def test_arrow
- assert_cycle('a=>b' => 'bar', '1"foo' => '2')
- end
+ def test_quotes
+ assert_cycle('a' => 'b"ar', '1"foo' => '2')
+ end
- def test_quoting_special_characters
- assert_cycle('ca' => 'cà', 'ac' => 'àc')
- end
+ def test_whitespace
+ assert_cycle('a b' => 'b ar', '1"foo' => '2')
+ end
+
+ def test_backslash
+ assert_cycle('a\\b' => 'b\\ar', '1"foo' => '2')
+ end
- def test_multiline
- assert_cycle("a\nb" => "c\nd")
+ def test_comma
+ assert_cycle('a, b' => 'bar', '1"foo' => '2')
+ end
+
+ def test_arrow
+ assert_cycle('a=>b' => 'bar', '1"foo' => '2')
+ end
+
+ def test_quoting_special_characters
+ assert_cycle('ca' => 'cà', 'ac' => 'àc')
+ end
+
+ def test_multiline
+ assert_cycle("a\nb" => "c\nd")
+ end
+
+ def test_update_all
+ hstore = Hstore.create! tags: { "one" => "two" }
+
+ Hstore.update_all tags: { "three" => "four" }
+ assert_equal({ "three" => "four" }, hstore.reload.tags)
+
+ Hstore.update_all tags: { }
+ assert_equal({ }, hstore.reload.tags)
+ end
end
private
- def assert_cycle hash
- # test creation
- x = Hstore.create!(:tags => hash)
- x.reload
- assert_equal(hash, x.tags)
-
- # test updating
- x = Hstore.create!(:tags => {})
- x.tags = hash
- x.save!
- x.reload
- assert_equal(hash, x.tags)
- end
+
+ def assert_cycle(hash)
+ # test creation
+ x = Hstore.create!(:tags => hash)
+ x.reload
+ assert_equal(hash, x.tags)
+
+ # test updating
+ x = Hstore.create!(:tags => {})
+ x.tags = hash
+ x.save!
+ x.reload
+ assert_equal(hash, x.tags)
+ end
end
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index f45c7afcc0..01e7334aad 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -7,6 +7,8 @@ require 'active_record/connection_adapters/postgresql_adapter'
class PostgresqlJSONTest < ActiveRecord::TestCase
class JsonDataType < ActiveRecord::Base
self.table_name = 'json_data_type'
+
+ store_accessor :settings, :resolution
end
def setup
@@ -15,6 +17,7 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
@connection.transaction do
@connection.create_table('json_data_type') do |t|
t.json 'payload', :default => {}
+ t.json 'settings'
end
end
rescue ActiveRecord::StatementInvalid
@@ -46,6 +49,13 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
JsonDataType.reset_column_information
end
+ def test_cast_value_on_write
+ x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar}
+ assert_equal({"string" => "foo", "symbol" => "bar"}, x.payload)
+ x.save
+ assert_equal({"string" => "foo", "symbol" => "bar"}, x.reload.payload)
+ end
+
def test_type_cast_json
assert @column
@@ -97,4 +107,28 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
assert x.save!
end
+ def test_with_store_accessors
+ x = JsonDataType.new(resolution: "320×480")
+ assert_equal "320×480", x.resolution
+
+ x.save!
+ x = JsonDataType.first
+ assert_equal "320×480", x.resolution
+
+ x.resolution = "640×1136"
+ x.save!
+
+ x = JsonDataType.first
+ assert_equal "640×1136", x.resolution
+ end
+
+ def test_update_all
+ json = JsonDataType.create! payload: { "one" => "two" }
+
+ JsonDataType.update_all payload: { "three" => "four" }
+ assert_equal({ "three" => "four" }, json.reload.payload)
+
+ JsonDataType.update_all payload: { }
+ assert_equal({ }, json.reload.payload)
+ end
end
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index fb88ab7c09..131080913c 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -10,6 +10,14 @@ module ActiveRecord
@connection.exec_query('create table ex(id serial primary key, number integer, data character varying(255))')
end
+ def test_bad_connection
+ assert_raise ActiveRecord::NoDatabaseError do
+ configuration = ActiveRecord::Base.configurations['arunit'].merge(database: 'should_not_exist-cinco-dog-db')
+ connection = ActiveRecord::Base.postgresql_connection(configuration)
+ connection.exec_query('drop table if exists ex')
+ end
+ end
+
def test_valid_column
column = @connection.columns('ex').find { |col| col.name == 'id' }
assert @connection.valid_type?(column.type)
@@ -62,6 +70,18 @@ module ActiveRecord
assert_equal expect, id
end
+ def test_multiline_insert_sql
+ id = @connection.insert_sql(<<-SQL)
+ insert into ex(
+ number)
+ values(
+ 5152
+ )
+ SQL
+ expect = @connection.query('select max(id) from ex').first.first
+ assert_equal expect, id
+ end
+
def test_insert_sql_with_returning_disabled
connection = connection_without_insert_returning
id = connection.insert_sql("insert into postgresql_partitioned_table_parent (number) VALUES (1)")
@@ -225,65 +245,26 @@ module ActiveRecord
assert_equal "(number > 100)", index.where
end
- def test_distinct_zero_orders
- assert_deprecated do
- assert_equal "DISTINCT posts.id",
- @connection.distinct("posts.id", [])
- end
- end
-
def test_columns_for_distinct_zero_orders
assert_equal "posts.id",
@connection.columns_for_distinct("posts.id", [])
end
- def test_distinct_one_order
- assert_deprecated do
- assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
- @connection.distinct("posts.id", ["posts.created_at desc"])
- end
- end
-
def test_columns_for_distinct_one_order
assert_equal "posts.id, posts.created_at AS alias_0",
@connection.columns_for_distinct("posts.id", ["posts.created_at desc"])
end
- def test_distinct_few_orders
- assert_deprecated do
- assert_equal "DISTINCT posts.id, posts.created_at AS alias_0, posts.position AS alias_1",
- @connection.distinct("posts.id", ["posts.created_at desc", "posts.position asc"])
- end
- end
-
def test_columns_for_distinct_few_orders
assert_equal "posts.id, posts.created_at AS alias_0, posts.position AS alias_1",
@connection.columns_for_distinct("posts.id", ["posts.created_at desc", "posts.position asc"])
end
- def test_distinct_blank_not_nil_orders
- assert_deprecated do
- assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
- @connection.distinct("posts.id", ["posts.created_at desc", "", " "])
- end
- end
-
def test_columns_for_distinct_blank_not_nil_orders
assert_equal "posts.id, posts.created_at AS alias_0",
@connection.columns_for_distinct("posts.id", ["posts.created_at desc", "", " "])
end
- def test_distinct_with_arel_order
- order = Object.new
- def order.to_sql
- "posts.created_at desc"
- end
- assert_deprecated do
- assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
- @connection.distinct("posts.id", [order])
- end
- end
-
def test_columns_for_distinct_with_arel_order
order = Object.new
def order.to_sql
@@ -293,13 +274,6 @@ module ActiveRecord
@connection.columns_for_distinct("posts.id", [order])
end
- def test_distinct_with_nulls
- assert_deprecated do
- assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls first"])
- assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"])
- end
- end
-
def test_columns_for_distinct_with_nulls
assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls first"])
assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls last"])
diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
index b3429648ee..1122f8b9a1 100644
--- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
@@ -47,11 +47,16 @@ module ActiveRecord
def test_quote_cast_numeric
fixnum = 666
- c = Column.new(nil, nil, 'string')
+ c = Column.new(nil, nil, 'varchar')
assert_equal "'666'", @conn.quote(fixnum, c)
c = Column.new(nil, nil, 'text')
assert_equal "'666'", @conn.quote(fixnum, c)
end
+
+ def test_quote_time_usec
+ assert_equal "'1970-01-01 00:00:00.000000'", @conn.quote(Time.at(0))
+ assert_equal "'1970-01-01 00:00:00.000000'", @conn.quote(Time.at(0).to_datetime)
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb
new file mode 100644
index 0000000000..a56b8ac791
--- /dev/null
+++ b/activerecord/test/cases/adapters/postgresql/range_test.rb
@@ -0,0 +1,245 @@
+require "cases/helper"
+require 'active_record/base'
+require 'active_record/connection_adapters/postgresql_adapter'
+
+if ActiveRecord::Base.connection.supports_ranges?
+ class PostgresqlRange < ActiveRecord::Base
+ self.table_name = "postgresql_ranges"
+ end
+
+ class PostgresqlRangeTest < ActiveRecord::TestCase
+ def teardown
+ @connection.execute 'DROP TABLE IF EXISTS postgresql_ranges'
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ begin
+ @connection.transaction do
+ @connection.create_table('postgresql_ranges') do |t|
+ t.daterange :date_range
+ t.numrange :num_range
+ t.tsrange :ts_range
+ t.tstzrange :tstz_range
+ t.int4range :int4_range
+ t.int8range :int8_range
+ end
+ end
+ rescue ActiveRecord::StatementInvalid
+ return skip "do not test on PG without range"
+ end
+
+ insert_range(id: 101,
+ date_range: "[''2012-01-02'', ''2012-01-04'']",
+ num_range: "[0.1, 0.2]",
+ ts_range: "[''2010-01-01 14:30'', ''2011-01-01 14:30'']",
+ tstz_range: "[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']",
+ int4_range: "[1, 10]",
+ int8_range: "[10, 100]")
+
+ insert_range(id: 102,
+ date_range: "(''2012-01-02'', ''2012-01-04'')",
+ num_range: "[0.1, 0.2)",
+ ts_range: "[''2010-01-01 14:30'', ''2011-01-01 14:30'')",
+ tstz_range: "[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'')",
+ int4_range: "(1, 10)",
+ int8_range: "(10, 100)")
+
+ insert_range(id: 103,
+ date_range: "(''2012-01-02'',]",
+ num_range: "[0.1,]",
+ ts_range: "[''2010-01-01 14:30'',]",
+ tstz_range: "[''2010-01-01 14:30:00+05'',]",
+ int4_range: "(1,]",
+ int8_range: "(10,]")
+
+ insert_range(id: 104,
+ date_range: "[,]",
+ num_range: "[,]",
+ ts_range: "[,]",
+ tstz_range: "[,]",
+ int4_range: "[,]",
+ int8_range: "[,]")
+
+ insert_range(id: 105,
+ date_range: "(''2012-01-02'', ''2012-01-02'')",
+ num_range: "(0.1, 0.1)",
+ ts_range: "(''2010-01-01 14:30'', ''2010-01-01 14:30'')",
+ tstz_range: "(''2010-01-01 14:30:00+05'', ''2010-01-01 06:30:00-03'')",
+ int4_range: "(1, 1)",
+ int8_range: "(10, 10)")
+
+ @new_range = PostgresqlRange.new
+ @first_range = PostgresqlRange.find(101)
+ @second_range = PostgresqlRange.find(102)
+ @third_range = PostgresqlRange.find(103)
+ @fourth_range = PostgresqlRange.find(104)
+ @empty_range = PostgresqlRange.find(105)
+ end
+
+ def test_data_type_of_range_types
+ assert_equal :daterange, @first_range.column_for_attribute(:date_range).type
+ assert_equal :numrange, @first_range.column_for_attribute(:num_range).type
+ assert_equal :tsrange, @first_range.column_for_attribute(:ts_range).type
+ assert_equal :tstzrange, @first_range.column_for_attribute(:tstz_range).type
+ assert_equal :int4range, @first_range.column_for_attribute(:int4_range).type
+ assert_equal :int8range, @first_range.column_for_attribute(:int8_range).type
+ end
+
+ def test_int4range_values
+ assert_equal 1...11, @first_range.int4_range
+ assert_equal 2...10, @second_range.int4_range
+ assert_equal 2...Float::INFINITY, @third_range.int4_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int4_range)
+ assert_nil @empty_range.int4_range
+ end
+
+ def test_int8range_values
+ assert_equal 10...101, @first_range.int8_range
+ assert_equal 11...100, @second_range.int8_range
+ assert_equal 11...Float::INFINITY, @third_range.int8_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int8_range)
+ assert_nil @empty_range.int8_range
+ end
+
+ def test_daterange_values
+ assert_equal Date.new(2012, 1, 2)...Date.new(2012, 1, 5), @first_range.date_range
+ assert_equal Date.new(2012, 1, 3)...Date.new(2012, 1, 4), @second_range.date_range
+ assert_equal Date.new(2012, 1, 3)...Float::INFINITY, @third_range.date_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.date_range)
+ assert_nil @empty_range.date_range
+ end
+
+ def test_numrange_values
+ assert_equal BigDecimal.new('0.1')..BigDecimal.new('0.2'), @first_range.num_range
+ assert_equal BigDecimal.new('0.1')...BigDecimal.new('0.2'), @second_range.num_range
+ assert_equal BigDecimal.new('0.1')...BigDecimal.new('Infinity'), @third_range.num_range
+ assert_equal BigDecimal.new('-Infinity')...BigDecimal.new('Infinity'), @fourth_range.num_range
+ assert_nil @empty_range.num_range
+ end
+
+ def test_tsrange_values
+ tz = ::ActiveRecord::Base.default_timezone
+ assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)..Time.send(tz, 2011, 1, 1, 14, 30, 0), @first_range.ts_range
+ assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 1, 1, 14, 30, 0), @second_range.ts_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.ts_range)
+ assert_nil @empty_range.ts_range
+ end
+
+ def test_tstzrange_values
+ assert_equal Time.parse('2010-01-01 09:30:00 UTC')..Time.parse('2011-01-01 17:30:00 UTC'), @first_range.tstz_range
+ assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Time.parse('2011-01-01 17:30:00 UTC'), @second_range.tstz_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.tstz_range)
+ assert_nil @empty_range.tstz_range
+ end
+
+ def test_create_tstzrange
+ tstzrange = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2011-02-02 14:30:00 CDT')
+ round_trip(@new_range, :tstz_range, tstzrange)
+ assert_equal @new_range.tstz_range, tstzrange
+ assert_equal @new_range.tstz_range, Time.parse('2010-01-01 13:30:00 UTC')...Time.parse('2011-02-02 19:30:00 UTC')
+ end
+
+ def test_update_tstzrange
+ assert_equal_round_trip(@first_range, :tstz_range,
+ Time.parse('2010-01-01 14:30:00 CDT')...Time.parse('2011-02-02 14:30:00 CET'))
+ assert_nil_round_trip(@first_range, :tstz_range,
+ Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2010-01-01 13:30:00 +0000'))
+ end
+
+ def test_create_tsrange
+ tz = ::ActiveRecord::Base.default_timezone
+ assert_equal_round_trip(@new_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0))
+ end
+
+ def test_update_tsrange
+ tz = ::ActiveRecord::Base.default_timezone
+ assert_equal_round_trip(@first_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0))
+ assert_nil_round_trip(@first_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2010, 1, 1, 14, 30, 0))
+ end
+
+ def test_create_numrange
+ assert_equal_round_trip(@new_range, :num_range,
+ BigDecimal.new('0.5')...BigDecimal.new('1'))
+ end
+
+ def test_update_numrange
+ assert_equal_round_trip(@first_range, :num_range,
+ BigDecimal.new('0.5')...BigDecimal.new('1'))
+ assert_nil_round_trip(@first_range, :num_range,
+ BigDecimal.new('0.5')...BigDecimal.new('0.5'))
+ end
+
+ def test_create_daterange
+ assert_equal_round_trip(@new_range, :date_range,
+ Range.new(Date.new(2012, 1, 1), Date.new(2013, 1, 1), true))
+ end
+
+ def test_update_daterange
+ assert_equal_round_trip(@first_range, :date_range,
+ Date.new(2012, 2, 3)...Date.new(2012, 2, 10))
+ assert_nil_round_trip(@first_range, :date_range,
+ Date.new(2012, 2, 3)...Date.new(2012, 2, 3))
+ end
+
+ def test_create_int4range
+ assert_equal_round_trip(@new_range, :int4_range, Range.new(3, 50, true))
+ end
+
+ def test_update_int4range
+ assert_equal_round_trip(@first_range, :int4_range, 6...10)
+ assert_nil_round_trip(@first_range, :int4_range, 3...3)
+ end
+
+ def test_create_int8range
+ assert_equal_round_trip(@new_range, :int8_range, Range.new(30, 50, true))
+ end
+
+ def test_update_int8range
+ assert_equal_round_trip(@first_range, :int8_range, 60000...10000000)
+ assert_nil_round_trip(@first_range, :int8_range, 39999...39999)
+ end
+
+ private
+ def assert_equal_round_trip(range, attribute, value)
+ round_trip(range, attribute, value)
+ assert_equal value, range.public_send(attribute)
+ end
+
+ def assert_nil_round_trip(range, attribute, value)
+ round_trip(range, attribute, value)
+ assert_nil range.public_send(attribute)
+ end
+
+ def round_trip(range, attribute, value)
+ range.public_send "#{attribute}=", value
+ assert range.save
+ assert range.reload
+ end
+
+ def insert_range(values)
+ @connection.execute <<-SQL
+ INSERT INTO postgresql_ranges (
+ id,
+ date_range,
+ num_range,
+ ts_range,
+ tstz_range,
+ int4_range,
+ int8_range
+ ) VALUES (
+ #{values[:id]},
+ '#{values[:date_range]}',
+ '#{values[:num_range]}',
+ '#{values[:ts_range]}',
+ '#{values[:tstz_range]}',
+ '#{values[:int4_range]}',
+ '#{values[:int8_range]}'
+ )
+ SQL
+ end
+ end
+end
diff --git a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb
index f1c4b85126..1497b0abc7 100644
--- a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb
@@ -1,38 +1,40 @@
require 'cases/helper'
-module ActiveRecord::ConnectionAdapters
- class PostgreSQLAdapter < AbstractAdapter
- class InactivePGconn
- def query(*args)
- raise PGError
- end
+module ActiveRecord
+ module ConnectionAdapters
+ class PostgreSQLAdapter < AbstractAdapter
+ class InactivePGconn
+ def query(*args)
+ raise PGError
+ end
- def status
- PGconn::CONNECTION_BAD
+ def status
+ PGconn::CONNECTION_BAD
+ end
end
- end
- class StatementPoolTest < ActiveRecord::TestCase
- def test_cache_is_per_pid
- return skip('must support fork') unless Process.respond_to?(:fork)
+ class StatementPoolTest < ActiveRecord::TestCase
+ if Process.respond_to?(:fork)
+ def test_cache_is_per_pid
+ cache = StatementPool.new nil, 10
+ cache['foo'] = 'bar'
+ assert_equal 'bar', cache['foo']
- cache = StatementPool.new nil, 10
- cache['foo'] = 'bar'
- assert_equal 'bar', cache['foo']
+ pid = fork {
+ lookup = cache['foo'];
+ exit!(!lookup)
+ }
- pid = fork {
- lookup = cache['foo'];
- exit!(!lookup)
- }
-
- Process.waitpid pid
- assert $?.success?, 'process should exit successfully'
- end
+ Process.waitpid pid
+ assert $?.success?, 'process should exit successfully'
+ end
+ end
- def test_dealloc_does_not_raise_on_inactive_connection
- cache = StatementPool.new InactivePGconn.new, 10
- cache['foo'] = 'bar'
- assert_nothing_raised { cache.clear }
+ def test_dealloc_does_not_raise_on_inactive_connection
+ cache = StatementPool.new InactivePGconn.new, 10
+ cache['foo'] = 'bar'
+ assert_nothing_raised { cache.clear }
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
index dbc69a529c..89210866f0 100644
--- a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
@@ -12,10 +12,6 @@ class TimestampTest < ActiveRecord::TestCase
end
def test_load_infinity_and_beyond
- unless current_adapter?(:PostgreSQLAdapter)
- return skip("only tested on postgresql")
- end
-
d = Developer.find_by_sql("select 'infinity'::timestamp as updated_at")
assert d.first.updated_at.infinite?, 'timestamp should be infinite'
@@ -26,10 +22,6 @@ class TimestampTest < ActiveRecord::TestCase
end
def test_save_infinity_and_beyond
- unless current_adapter?(:PostgreSQLAdapter)
- return skip("only tested on postgresql")
- end
-
d = Developer.create!(:name => 'aaron', :updated_at => 1.0 / 0.0)
assert_equal(1.0 / 0.0, d.updated_at)
@@ -85,9 +77,6 @@ class TimestampTest < ActiveRecord::TestCase
end
def test_bc_timestamp
- unless current_adapter?(:PostgreSQLAdapter)
- return skip("only tested on postgresql")
- end
date = Date.new(0) - 1.second
Developer.create!(:name => "aaron", :updated_at => date)
assert_equal date, Developer.find_by_name("aaron").updated_at
@@ -109,5 +98,4 @@ class TimestampTest < ActiveRecord::TestCase
end
result && result.send(option)
end
-
end
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index b573d48807..3f5d981444 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -12,10 +12,6 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase
def setup
@connection = ActiveRecord::Base.connection
- unless @connection.supports_extensions?
- return skip "do not test on PG without uuid-ossp"
- end
-
unless @connection.extension_enabled?('uuid-ossp')
@connection.enable_extension 'uuid-ossp'
@connection.commit_db_transaction
@@ -24,7 +20,7 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase
@connection.reconnect!
@connection.transaction do
- @connection.create_table('pg_uuids', id: :uuid) do |t|
+ @connection.create_table('pg_uuids', id: :uuid, default: 'uuid_generate_v1()') do |t|
t.string 'name'
t.uuid 'other_uuid', default: 'uuid_generate_v4()'
end
@@ -35,32 +31,35 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase
@connection.execute 'drop table if exists pg_uuids'
end
- def test_id_is_uuid
- assert_equal :uuid, UUID.columns_hash['id'].type
- assert UUID.primary_key
- end
+ if ActiveRecord::Base.connection.supports_extensions?
+ def test_id_is_uuid
+ assert_equal :uuid, UUID.columns_hash['id'].type
+ assert UUID.primary_key
+ end
- def test_id_has_a_default
- u = UUID.create
- assert_not_nil u.id
- end
+ def test_id_has_a_default
+ u = UUID.create
+ assert_not_nil u.id
+ end
- def test_auto_create_uuid
- u = UUID.create
- u.reload
- assert_not_nil u.other_uuid
- end
+ def test_auto_create_uuid
+ u = UUID.create
+ u.reload
+ assert_not_nil u.other_uuid
+ end
- def test_pk_and_sequence_for_uuid_primary_key
- pk, seq = @connection.pk_and_sequence_for('pg_uuids')
- assert_equal 'id', pk
- assert_equal nil, seq
- end
+ def test_pk_and_sequence_for_uuid_primary_key
+ pk, seq = @connection.pk_and_sequence_for('pg_uuids')
+ assert_equal 'id', pk
+ assert_equal nil, seq
+ end
- def test_schema_dumper_for_uuid_primary_key
- schema = StringIO.new
- ActiveRecord::SchemaDumper.dump(@connection, schema)
- assert_match(/\bcreate_table "pg_uuids", id: :uuid\b/, schema.string)
+ def test_schema_dumper_for_uuid_primary_key
+ schema = StringIO.new
+ ActiveRecord::SchemaDumper.dump(@connection, schema)
+ assert_match(/\bcreate_table "pg_uuids", id: :uuid, default: "uuid_generate_v1\(\)"/, schema.string)
+ assert_match(/t\.uuid "other_uuid", default: "uuid_generate_v4\(\)"/, schema.string)
+ end
end
end
@@ -73,6 +72,11 @@ class PostgresqlUUIDTestNilDefault < ActiveRecord::TestCase
@connection = ActiveRecord::Base.connection
@connection.reconnect!
+ unless @connection.extension_enabled?('uuid-ossp')
+ @connection.enable_extension 'uuid-ossp'
+ @connection.commit_db_transaction
+ end
+
@connection.transaction do
@connection.create_table('pg_uuids', id: false) do |t|
t.primary_key :id, :uuid, default: nil
@@ -85,11 +89,60 @@ class PostgresqlUUIDTestNilDefault < ActiveRecord::TestCase
@connection.execute 'drop table if exists pg_uuids'
end
- def test_id_allows_default_override_via_nil
- col_desc = @connection.execute("SELECT pg_get_expr(d.adbin, d.adrelid) as default
+ if ActiveRecord::Base.connection.supports_extensions?
+ def test_id_allows_default_override_via_nil
+ col_desc = @connection.execute("SELECT pg_get_expr(d.adbin, d.adrelid) as default
FROM pg_attribute a
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attname='id' AND a.attrelid = 'pg_uuids'::regclass").first
- assert_nil col_desc["default"]
+ assert_nil col_desc["default"]
+ end
+ end
+end
+
+class PostgresqlUUIDTestInverseOf < ActiveRecord::TestCase
+ class UuidPost < ActiveRecord::Base
+ self.table_name = 'pg_uuid_posts'
+ has_many :uuid_comments, inverse_of: :uuid_post
+ end
+
+ class UuidComment < ActiveRecord::Base
+ self.table_name = 'pg_uuid_comments'
+ belongs_to :uuid_post
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ @connection.reconnect!
+
+ unless @connection.extension_enabled?('uuid-ossp')
+ @connection.enable_extension 'uuid-ossp'
+ @connection.commit_db_transaction
+ end
+
+ @connection.transaction do
+ @connection.create_table('pg_uuid_posts', id: :uuid) do |t|
+ t.string 'title'
+ end
+ @connection.create_table('pg_uuid_comments', id: :uuid) do |t|
+ t.uuid :uuid_post_id, default: 'uuid_generate_v4()'
+ t.string 'content'
+ end
+ end
+ end
+
+ def teardown
+ @connection.transaction do
+ @connection.execute 'drop table if exists pg_uuid_comments'
+ @connection.execute 'drop table if exists pg_uuid_posts'
+ end
+ end
+
+ if ActiveRecord::Base.connection.supports_extensions?
+ def test_collection_association_with_uuid
+ post = UuidPost.create!
+ comment = post.uuid_comments.create!
+ assert post.uuid_comments.find(comment.id)
+ end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/xml_test.rb b/activerecord/test/cases/adapters/postgresql/xml_test.rb
new file mode 100644
index 0000000000..bf14b378d8
--- /dev/null
+++ b/activerecord/test/cases/adapters/postgresql/xml_test.rb
@@ -0,0 +1,38 @@
+# encoding: utf-8
+
+require 'cases/helper'
+require 'active_record/base'
+require 'active_record/connection_adapters/postgresql_adapter'
+
+class PostgresqlXMLTest < ActiveRecord::TestCase
+ class XmlDataType < ActiveRecord::Base
+ self.table_name = 'xml_data_type'
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ begin
+ @connection.transaction do
+ @connection.create_table('xml_data_type') do |t|
+ t.xml 'payload', default: {}
+ end
+ end
+ rescue ActiveRecord::StatementInvalid
+ return skip "do not test on PG without xml"
+ end
+ @column = XmlDataType.columns.find { |c| c.name == 'payload' }
+ end
+
+ def teardown
+ @connection.execute 'drop table if exists xml_data_type'
+ end
+
+ def test_column
+ assert_equal :xml, @column.type
+ end
+
+ def test_null_xml
+ @connection.execute %q|insert into xml_data_type (payload) VALUES(null)|
+ assert_nil XmlDataType.first.payload
+ end
+end
diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index a7b2764fc1..ba89487838 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -95,6 +95,13 @@ module ActiveRecord
end
}.new
assert_equal 10, @conn.type_cast(quoted_id_obj, nil)
+
+ quoted_id_obj = Class.new {
+ def quoted_id
+ "'zomg'"
+ end
+ }
+ assert_raise(TypeError) { @conn.type_cast(quoted_id_obj, nil) }
end
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index 1c2d5cdaf2..b82dd7b04b 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -1,6 +1,7 @@
# encoding: utf-8
require "cases/helper"
require 'models/owner'
+require 'tempfile'
module ActiveRecord
module ConnectionAdapters
@@ -21,8 +22,36 @@ module ActiveRecord
)
eosql
- @conn.extend(LogIntercepter)
- @conn.intercepted = true
+ @subscriber = SQLSubscriber.new
+ ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber)
+ end
+
+ def test_bad_connection
+ assert_raise ActiveRecord::NoDatabaseError do
+ connection = ActiveRecord::Base.sqlite3_connection(adapter: "sqlite3", database: "/tmp/should/_not/_exist/-cinco-dog.db")
+ connection.exec_query('drop table if exists ex')
+ end
+ end
+
+ def test_connect_with_url
+ original_connection = ActiveRecord::Base.remove_connection
+ tf = Tempfile.open 'whatever'
+ url = "sqlite3://#{tf.path}"
+ ActiveRecord::Base.establish_connection(url)
+ assert ActiveRecord::Base.connection
+ ensure
+ tf.close
+ tf.unlink
+ ActiveRecord::Base.establish_connection(original_connection)
+ end
+
+ def test_connect_memory_with_url
+ original_connection = ActiveRecord::Base.remove_connection
+ url = "sqlite3:///:memory:"
+ ActiveRecord::Base.establish_connection(url)
+ assert ActiveRecord::Base.connection
+ ensure
+ ActiveRecord::Base.establish_connection(original_connection)
end
def test_valid_column
@@ -31,16 +60,16 @@ module ActiveRecord
end
# sqlite databases should be able to support any type and not
- # just the ones mentioned in the native_database_types.
- # Therefore test_invalid column should always return true
+ # just the ones mentioned in the native_database_types.
+ # Therefore test_invalid column should always return true
# even if the type is not valid.
def test_invalid_column
assert @conn.valid_type?(:foobar)
end
def teardown
- @conn.intercepted = false
- @conn.logged = []
+ ActiveSupport::Notifications.unsubscribe(@subscriber)
+ super
end
def test_column_types
@@ -255,7 +284,7 @@ module ActiveRecord
def test_tables_logs_name
assert_logged [['SCHEMA', []]] do
@conn.tables('hello')
- assert_not_nil @conn.logged.first.shift
+ assert_not_nil @subscriber.logged.first.shift
end
end
@@ -267,7 +296,7 @@ module ActiveRecord
def test_table_exists_logs_name
assert @conn.table_exists?('items')
- assert_equal 'SCHEMA', @conn.logged[0][1]
+ assert_equal 'SCHEMA', @subscriber.logged[0][1]
end
def test_columns
@@ -305,10 +334,10 @@ module ActiveRecord
end
def test_indexes_logs
- assert_difference('@conn.logged.length') do
+ assert_difference('@subscriber.logged.length') do
@conn.indexes('items')
end
- assert_match(/items/, @conn.logged.last.first)
+ assert_match(/items/, @subscriber.logged.last.first)
end
def test_no_indexes
@@ -353,11 +382,23 @@ module ActiveRecord
assert_nil @conn.primary_key('failboat')
end
+ def test_supports_extensions
+ assert_not @conn.supports_extensions?, 'does not support extensions'
+ end
+
+ def test_respond_to_enable_extension
+ assert @conn.respond_to?(:enable_extension)
+ end
+
+ def test_respond_to_disable_extension
+ assert @conn.respond_to?(:disable_extension)
+ end
+
private
def assert_logged logs
yield
- assert_equal logs, @conn.logged
+ assert_equal logs, @subscriber.logged
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb
new file mode 100644
index 0000000000..f545fc2011
--- /dev/null
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb
@@ -0,0 +1,21 @@
+# encoding: utf-8
+require "cases/helper"
+require 'models/owner'
+
+module ActiveRecord
+ module ConnectionAdapters
+ class SQLite3CreateFolder < ActiveRecord::TestCase
+ def test_sqlite_creates_directory
+ Dir.mktmpdir do |dir|
+ dir = Pathname.new(dir)
+ @conn = Base.sqlite3_connection :database => dir.join("db/foo.sqlite3"),
+ :adapter => 'sqlite3',
+ :timeout => 100
+
+ assert Dir.exist? dir.join('db')
+ assert File.exist? dir.join('db/foo.sqlite3')
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb
index 2f04c60a9a..fd0044ac05 100644
--- a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb
@@ -3,20 +3,21 @@ require 'cases/helper'
module ActiveRecord::ConnectionAdapters
class SQLite3Adapter
class StatementPoolTest < ActiveRecord::TestCase
- def test_cache_is_per_pid
- return skip('must support fork') unless Process.respond_to?(:fork)
+ if Process.respond_to?(:fork)
+ def test_cache_is_per_pid
- cache = StatementPool.new nil, 10
- cache['foo'] = 'bar'
- assert_equal 'bar', cache['foo']
+ cache = StatementPool.new nil, 10
+ cache['foo'] = 'bar'
+ assert_equal 'bar', cache['foo']
- pid = fork {
- lookup = cache['foo'];
- exit!(!lookup)
- }
+ pid = fork {
+ lookup = cache['foo'];
+ exit!(!lookup)
+ }
- Process.waitpid pid
- assert $?.success?, 'process should exit successfully'
+ Process.waitpid pid
+ assert $?.success?, 'process should exit successfully'
+ end
end
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 87af24cbe6..3205d0c28b 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -1,4 +1,4 @@
-require "cases/helper"
+require 'cases/helper'
require 'models/developer'
require 'models/project'
require 'models/company'
@@ -14,6 +14,8 @@ require 'models/sponsor'
require 'models/member'
require 'models/essay'
require 'models/toy'
+require 'models/invoice'
+require 'models/line_item'
class BelongsToAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :developers, :projects, :topics,
@@ -324,6 +326,53 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal 1, Topic.find(topic.id)[:replies_count]
end
+ def test_belongs_to_with_touch_option_on_touch
+ line_item = LineItem.create!
+ Invoice.create!(line_items: [line_item])
+
+ assert_queries(1) { line_item.touch }
+ end
+
+ def test_belongs_to_with_touch_option_on_touch_and_removed_parent
+ line_item = LineItem.create!
+ Invoice.create!(line_items: [line_item])
+
+ line_item.invoice = nil
+
+ assert_queries(2) { line_item.touch }
+ end
+
+ def test_belongs_to_with_touch_option_on_update
+ line_item = LineItem.create!
+ Invoice.create!(line_items: [line_item])
+
+ assert_queries(2) { line_item.update amount: 10 }
+ end
+
+ def test_belongs_to_with_touch_option_on_destroy
+ line_item = LineItem.create!
+ Invoice.create!(line_items: [line_item])
+
+ assert_queries(2) { line_item.destroy }
+ end
+
+ def test_belongs_to_with_touch_option_on_destroy_with_destroyed_parent
+ line_item = LineItem.create!
+ invoice = Invoice.create!(line_items: [line_item])
+ invoice.destroy
+
+ assert_queries(1) { line_item.destroy }
+ end
+
+ def test_belongs_to_with_touch_option_on_touch_and_reassigned_parent
+ line_item = LineItem.create!
+ Invoice.create!(line_items: [line_item])
+
+ line_item.invoice = Invoice.create!
+
+ assert_queries(3) { line_item.touch }
+ end
+
def test_belongs_to_counter_after_update
topic = Topic.create!(title: "37s")
topic.replies.create!(title: "re: 37s", content: "rails")
@@ -338,7 +387,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
topic.replies.create!(:title => "re: 37s", :content => "rails")
assert_equal 1, Topic.find(topic.id)[:replies_count]
- topic.update_columns(content: "rails is wonderfull")
+ topic.update_columns(content: "rails is wonderful")
assert_equal 1, Topic.find(topic.id)[:replies_count]
end
@@ -391,8 +440,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
def test_dont_find_target_when_foreign_key_is_null
tagging = taggings(:thinking_general)
- queries = assert_sql { tagging.super_tag }
- assert_equal 0, queries.length
+ assert_queries(0) { tagging.super_tag }
end
def test_field_name_same_as_foreign_key
@@ -538,6 +586,19 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_nil essay.writer_id
end
+ def test_polymorphic_assignment_with_nil
+ essay = Essay.new
+ assert_nil essay.writer_id
+ assert_nil essay.writer_type
+
+ essay.writer_id = 1
+ essay.writer_type = 'Author'
+
+ essay.writer = nil
+ assert_nil essay.writer_id
+ assert_nil essay.writer_type
+ end
+
def test_belongs_to_proxy_should_not_respond_to_private_methods
assert_raise(NoMethodError) { companies(:first_firm).private_method }
assert_raise(NoMethodError) { companies(:second_client).firm.private_method }
@@ -565,6 +626,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
end
def test_dependent_delete_and_destroy_with_belongs_to
+ AuthorAddress.destroyed_author_address_ids.clear
+
author_address = author_addresses(:david_address)
author_address_extra = author_addresses(:david_address_extra)
assert_equal [], AuthorAddress.destroyed_author_address_ids
@@ -577,16 +640,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal [author_address.id], AuthorAddress.destroyed_author_address_ids
end
- def test_invalid_belongs_to_dependent_option_nullify_raises_exception
- assert_raise ArgumentError do
+ def test_belongs_to_invalid_dependent_option_raises_exception
+ error = assert_raise ArgumentError do
Class.new(Author).belongs_to :special_author_address, :dependent => :nullify
end
- end
-
- def test_invalid_belongs_to_dependent_option_restrict_raises_exception
- assert_raise ArgumentError do
- Class.new(Author).belongs_to :special_author_address, :dependent => :restrict
- end
+ assert_equal error.message, 'The :dependent option must be one of [:destroy, :delete], but is :nullify'
end
def test_attributes_are_being_set_when_initialized_from_belongs_to_association_with_where_clause
diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
index e693d34f99..71c0609df5 100644
--- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
+++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
@@ -52,12 +52,10 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
def test_cascaded_eager_association_loading_with_join_for_count
categories = Category.joins(:categorizations).includes([{:posts=>:comments}, :authors])
- assert_nothing_raised do
- assert_equal 4, categories.count
- assert_equal 4, categories.to_a.count
- assert_equal 3, categories.distinct.count
- assert_equal 3, categories.to_a.uniq.size # Must uniq since instantiating with inner joins will get dupes
- end
+ assert_equal 4, categories.count
+ assert_equal 4, categories.to_a.count
+ assert_equal 3, categories.distinct.count
+ assert_equal 3, categories.to_a.uniq.size # Must uniq since instantiating with inner joins will get dupes
end
def test_cascaded_eager_association_loading_with_duplicated_includes
@@ -176,4 +174,15 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
sink = Vertex.all.merge!(:includes=>{:sources=>{:sources=>{:sources=>:sources}}}, :order => 'vertices.id DESC').first
assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first }
end
+
+ def test_eager_association_loading_with_cascaded_interdependent_one_level_and_two_levels
+ authors_relation = Author.all.merge!(includes: [:comments, { posts: :categorizations }], order: "authors.id")
+ authors = authors_relation.to_a
+ assert_equal 3, authors.size
+ assert_equal 10, authors[0].comments.size
+ assert_equal 1, authors[1].comments.size
+ assert_equal 5, authors[0].posts.size
+ assert_equal 3, authors[1].posts.size
+ assert_equal 3, authors[0].posts.collect { |post| post.categorizations.size }.inject(0) { |sum, i| sum+i }
+ end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 4aa6567d85..498a4e8144 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -4,6 +4,7 @@ require 'models/tagging'
require 'models/tag'
require 'models/comment'
require 'models/author'
+require 'models/essay'
require 'models/category'
require 'models/company'
require 'models/person'
@@ -24,7 +25,7 @@ require 'models/categorization'
require 'models/sponsor'
class EagerAssociationTest < ActiveRecord::TestCase
- fixtures :posts, :comments, :authors, :author_addresses, :categories, :categories_posts,
+ fixtures :posts, :comments, :authors, :essays, :author_addresses, :categories, :categories_posts,
:companies, :accounts, :tags, :taggings, :people, :readers, :categorizations,
:owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books,
:developers, :projects, :developers_projects, :members, :memberships, :clubs, :sponsors
@@ -250,7 +251,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_nil Post.all.merge!(:includes => :author).find(posts(:authorless).id).author
end
- def test_nested_loading_with_no_associations
+ # Regression test for 21c75e5
+ def test_nested_loading_does_not_raise_exception_when_association_does_not_exist
assert_nothing_raised do
Post.all.merge!(:includes => {:author => :author_addresss}).find(posts(:authorless).id)
end
@@ -345,9 +347,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
def test_eager_association_loading_with_belongs_to_and_conditions_string_with_unquoted_table_name
assert_nothing_raised do
- ActiveSupport::Deprecation.silence do
- Comment.all.merge!(:includes => :post, :where => ['posts.id = ?',4]).to_a
- end
+ Comment.includes(:post).references(:posts).where('posts.id = ?', 4)
end
end
@@ -366,9 +366,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
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
- ActiveSupport::Deprecation.silence do
- Comment.all.merge!(:includes => :post, :where => ["#{quoted_posts_id} = ?",4]).to_a
- end
+ Comment.includes(:post).references(:posts).where("#{quoted_posts_id} = ?", 4)
end
end
@@ -381,9 +379,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
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
- ActiveSupport::Deprecation.silence do
- Comment.all.merge!(:includes => :post, :order => quoted_posts_id).to_a
- end
+ Comment.includes(:post).references(:posts).order(quoted_posts_id)
end
end
@@ -547,15 +543,11 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers
- posts = ActiveSupport::Deprecation.silence do
- Post.all.merge!(:includes => [ :author, :comments ], :limit => 2, :where => [ "authors.name = ?", 'David' ]).to_a
- end
+ posts = Post.includes(:author, :comments).limit(2).references(:author).where("authors.name = ?", 'David')
assert_equal 2, posts.size
- count = ActiveSupport::Deprecation.silence do
- Post.count(:include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
- end
- assert_equal count, posts.size
+ count = Post.includes(:author, :comments).limit(2).references(:author).where("authors.name = ?", 'David').count
+ assert_equal posts.size, count
end
def test_eager_with_has_many_and_limit_and_high_offset
@@ -756,6 +748,8 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_eager_with_default_scope_as_block
+ # warm up the habtm cache
+ EagerDeveloperWithBlockDefaultScope.where(:name => 'David').first.projects
developer = EagerDeveloperWithBlockDefaultScope.where(:name => 'David').first
projects = Project.order(:id).to_a
assert_no_queries do
@@ -1145,6 +1139,10 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
def test_deep_including_through_habtm
+ # warm up habtm cache
+ posts = Post.all.merge!(:includes => {:categories => :categorizations}, :order => "posts.id").to_a
+ posts[0].categories[0].categorizations.length
+
posts = Post.all.merge!(:includes => {:categories => :categorizations}, :order => "posts.id").to_a
assert_no_queries { assert_equal 2, posts[0].categories[0].categorizations.length }
assert_no_queries { assert_equal 1, posts[0].categories[1].categorizations.length }
@@ -1181,8 +1179,19 @@ class EagerAssociationTest < ActiveRecord::TestCase
}
end
- test "works in combination with order(:symbol)" do
- author = Author.includes(:posts).references(:posts).order(:name).where('posts.title IS NOT NULL').first
+ test "works in combination with order(:symbol) and reorder(:symbol)" do
+ author = Author.includes(:posts).references(:posts).order(:name).find_by('posts.title IS NOT NULL')
assert_equal authors(:bob), author
+
+ author = Author.includes(:posts).references(:posts).reorder(:name).find_by('posts.title IS NOT NULL')
+ assert_equal authors(:bob), author
+ end
+
+ test "preloading with a polymorphic association and using the existential predicate" do
+ assert_equal authors(:david), authors(:david).essays.includes(:writer).first.writer
+
+ assert_nothing_raised do
+ authors(:david).essays.includes(:writer).any?
+ end
end
end
diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb
index da767a2a7e..4c1fdfdd9a 100644
--- a/activerecord/test/cases/associations/extension_test.rb
+++ b/activerecord/test/cases/associations/extension_test.rb
@@ -59,9 +59,11 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase
end
def test_extension_name
- assert_equal 'DeveloperAssociationNameAssociationExtension', extension_name(Developer)
- assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', extension_name(MyApplication::Business::Developer)
- assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', extension_name(MyApplication::Business::Developer)
+ extend!(Developer)
+ extend!(MyApplication::Business::Developer)
+
+ assert Object.const_get 'DeveloperAssociationNameAssociationExtension'
+ assert MyApplication::Business.const_get 'DeveloperAssociationNameAssociationExtension'
end
def test_proxy_association_after_scoped
@@ -72,9 +74,8 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase
private
- def extension_name(model)
+ def extend!(model)
builder = ActiveRecord::Associations::Builder::HasMany.new(model, :association_name, nil, {}) { }
- builder.send(:wrap_block_extension)
- builder.extension_module.name
+ builder.define_extensions(model)
end
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index 84bdca3a97..8aee7ff40e 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -65,19 +65,6 @@ class DeveloperWithSymbolsForKeys < ActiveRecord::Base
:foreign_key => "developer_id"
end
-class DeveloperWithCounterSQL < ActiveRecord::Base
- self.table_name = 'developers'
-
- ActiveSupport::Deprecation.silence do
- has_and_belongs_to_many :projects,
- :class_name => "DeveloperWithCounterSQL",
- :join_table => "developers_projects",
- :association_foreign_key => "project_id",
- :foreign_key => "developer_id",
- :counter_sql => proc { "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
-end
-
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
:parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings
@@ -364,31 +351,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
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.all)
- assert_equal 0, active_record.developers_by_sql(true).size
- end
-
- def test_deleting_all_with_sql
- project = Project.find(1)
- project.developers_by_sql.delete_all
- assert_equal 0, project.developers_by_sql.size
- end
-
def test_deleting_all
david = Developer.find(1)
david.projects.reload
@@ -475,13 +437,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert george.treasures(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
@@ -537,25 +492,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
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.to_a.size
@@ -570,9 +506,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis')
end
- def test_find_should_prepend_to_association_order
+ def test_find_should_append_to_association_order
ordered_developers = projects(:active_record).developers.order('projects.id')
- assert_equal ['projects.id', 'developers.name desc, developers.id desc'], ordered_developers.order_values
+ assert_equal ['developers.name desc, developers.id desc', 'projects.id'], ordered_developers.order_values
end
def test_dynamic_find_all_should_respect_readonly_access
@@ -634,6 +570,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert !developer.special_projects.include?(other_project)
end
+ def test_symbol_join_table
+ developer = Developer.first
+ sp = developer.sym_special_projects.create("name" => "omg")
+ developer.reload
+ assert_includes developer.sym_special_projects, sp
+ end
+
def test_update_attributes_after_push_without_duplicate_join_table_rows
developer = Developer.new("name" => "Kano")
project = SpecialProject.create("name" => "Special Project")
@@ -669,16 +612,24 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
end
def test_join_table_alias
+ # FIXME: `references` has no impact on the aliases generated for the join
+ # query. The fact that we pass `:developers_projects_join` to `references`
+ # and that the SQL string contains `developers_projects_join` is merely a
+ # coincidence.
assert_equal(
3,
Developer.references(:developers_projects_join).merge(
:includes => {:projects => :developers},
- :where => 'developers_projects_join.joined_on IS NOT NULL'
+ :where => 'projects_developers_projects_join.joined_on IS NOT NULL'
).to_a.size
)
end
def test_join_with_group
+ # FIXME: `references` has no impact on the aliases generated for the join
+ # query. The fact that we pass `:developers_projects_join` to `references`
+ # and that the SQL string contains `developers_projects_join` is merely a
+ # coincidence.
group = Developer.columns.inject([]) do |g, c|
g << "developers.#{c.name}"
g << "developers_projects_2.#{c.name}"
@@ -688,7 +639,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal(
3,
Developer.references(:developers_projects_join).merge(
- :includes => {:projects => :developers}, :where => 'developers_projects_join.joined_on IS NOT NULL',
+ :includes => {:projects => :developers}, :where => 'projects_developers_projects_join.joined_on IS NOT NULL',
:group => group.join(",")
).to_a.size
)
@@ -702,12 +653,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_scoped_grouped
- assert_equal 5, categories(:general).posts_grouped_by_title.size
- assert_equal 1, categories(:technology).posts_grouped_by_title.size
+ assert_equal 5, categories(:general).posts_grouped_by_title.to_a.size
+ assert_equal 1, categories(:technology).posts_grouped_by_title.to_a.size
end
def test_find_scoped_grouped_having
- assert_equal 2, projects(:active_record).well_payed_salary_groups.size
+ assert_equal 2, projects(:active_record).well_payed_salary_groups.to_a.size
assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary > 10000 }
end
@@ -774,12 +725,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal project, developer.projects.first
end
- def test_self_referential_habtm_without_foreign_key_set_should_raise_exception
- assert_raise(ActiveRecord::HasAndBelongsToManyAssociationForeignKeyNeeded) {
- SelfMember.new.friends
- }
- 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'
@@ -791,21 +736,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
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
-
- unless current_adapter?(:PostgreSQLAdapter)
- def test_count_with_finder_sql
- assert_equal 3, projects(:active_record).developers_with_finder_sql.count
- assert_equal 3, projects(:active_record).developers_with_multiline_finder_sql.count
- end
- end
-
def test_association_proxy_transaction_method_starts_transaction_in_association_class
Post.expects(:transaction)
Category.first.posts.transaction do
@@ -845,18 +775,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert project.developers.include?(developer)
end
- test ":insert_sql is deprecated" do
- klass = Class.new(ActiveRecord::Base)
- def klass.name; 'Foo'; end
- assert_deprecated { klass.has_and_belongs_to_many :posts, :insert_sql => 'lol' }
- end
-
- test ":delete_sql is deprecated" do
- klass = Class.new(ActiveRecord::Base)
- def klass.name; 'Foo'; end
- assert_deprecated { klass.has_and_belongs_to_many :posts, :delete_sql => 'lol' }
- end
-
test "has and belongs to many associations on new records use null relations" do
projects = Developer.new.projects
assert_no_queries do
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index d85570236f..e45efb0161 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -23,79 +23,6 @@ require 'models/categorization'
require 'models/minivan'
require 'models/speedometer'
-class HasManyAssociationsTestForCountWithFinderSql < ActiveRecord::TestCase
- class Invoice < ActiveRecord::Base
- ActiveSupport::Deprecation.silence do
- has_many :custom_line_items, :class_name => 'LineItem', :finder_sql => "SELECT line_items.* from line_items"
- end
- end
- def test_should_fail
- assert_raise(ArgumentError) do
- Invoice.create.custom_line_items.count(:conditions => {:amount => 0})
- end
- end
-end
-
-class HasManyAssociationsTestForCountWithCountSql < ActiveRecord::TestCase
- class Invoice < ActiveRecord::Base
- ActiveSupport::Deprecation.silence do
- has_many :custom_line_items, :class_name => 'LineItem', :counter_sql => "SELECT COUNT(*) line_items.* from line_items"
- end
- end
- def test_should_fail
- assert_raise(ArgumentError) do
- Invoice.create.custom_line_items.count(:conditions => {:amount => 0})
- end
- end
-end
-
-class HasManyAssociationsTestForCountWithVariousFinderSqls < ActiveRecord::TestCase
- class Invoice < ActiveRecord::Base
- ActiveSupport::Deprecation.silence do
- has_many :custom_line_items, :class_name => 'LineItem', :finder_sql => "SELECT DISTINCT line_items.amount from line_items"
- has_many :custom_full_line_items, :class_name => 'LineItem', :finder_sql => "SELECT line_items.invoice_id, line_items.amount from line_items"
- has_many :custom_star_line_items, :class_name => 'LineItem', :finder_sql => "SELECT * from line_items"
- has_many :custom_qualified_star_line_items, :class_name => 'LineItem', :finder_sql => "SELECT line_items.* from line_items"
- end
- end
-
- def test_should_count_distinct_results
- invoice = Invoice.new
- invoice.custom_line_items << LineItem.new(:amount => 0)
- invoice.custom_line_items << LineItem.new(:amount => 0)
- invoice.save!
-
- assert_equal 1, invoice.custom_line_items.count
- end
-
- def test_should_count_results_with_multiple_fields
- invoice = Invoice.new
- invoice.custom_full_line_items << LineItem.new(:amount => 0)
- invoice.custom_full_line_items << LineItem.new(:amount => 0)
- invoice.save!
-
- assert_equal 2, invoice.custom_full_line_items.count
- end
-
- def test_should_count_results_with_star
- invoice = Invoice.new
- invoice.custom_star_line_items << LineItem.new(:amount => 0)
- invoice.custom_star_line_items << LineItem.new(:amount => 0)
- invoice.save!
-
- assert_equal 2, invoice.custom_star_line_items.count
- end
-
- def test_should_count_results_with_qualified_star
- invoice = Invoice.new
- invoice.custom_qualified_star_line_items << LineItem.new(:amount => 0)
- invoice.custom_qualified_star_line_items << LineItem.new(:amount => 0)
- invoice.save!
-
- assert_equal 2, invoice.custom_qualified_star_line_items.count
- end
-end
-
class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase
fixtures :authors, :posts, :comments
@@ -118,6 +45,24 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
Client.destroyed_client_ids.clear
end
+ def test_anonymous_has_many
+ developer = Class.new(ActiveRecord::Base) {
+ self.table_name = 'developers'
+ dev = self
+
+ developer_project = Class.new(ActiveRecord::Base) {
+ self.table_name = 'developers_projects'
+ belongs_to :developer, :class => dev
+ }
+ has_many :developer_projects, :class => developer_project, :foreign_key => 'developer_id'
+ }
+ dev = developer.first
+ named = Developer.find(dev.id)
+ assert_operator dev.developer_projects.count, :>, 0
+ assert_equal named.projects.map(&:id).sort,
+ dev.developer_projects.map(&:project_id).sort
+ end
+
def test_create_from_association_should_respect_default_scope
car = Car.create(:name => 'honda')
assert_equal 'honda', car.name
@@ -135,6 +80,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 'exotic', bulb.name
end
+ def test_build_from_association_should_respect_scope
+ author = Author.new
+
+ post = author.thinking_posts.build
+ assert_equal 'So I was thinking', post.title
+ end
+
def test_create_from_association_with_nil_values_should_work
car = Car.create(:name => 'honda')
@@ -148,6 +100,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 'defaulty', bulb.name
end
+ def test_do_not_call_callbacks_for_delete_all
+ car = Car.create(:name => 'honda')
+ car.funky_bulbs.create!
+ assert_nothing_raised { car.reload.funky_bulbs.delete_all }
+ assert_equal 0, Bulb.count, "bulbs should have been deleted using :delete_all strategy"
+ end
+
def test_building_the_associated_object_with_implicit_sti_base_class
firm = DependentFirm.new
company = firm.companies.build
@@ -176,6 +135,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(:type => "Account") }
end
+ test "building the association with an array" do
+ speedometer = Speedometer.new(speedometer_id: "a")
+ data = [{name: "first"}, {name: "second"}]
+ speedometer.minivans.build(data)
+
+ assert_equal 2, speedometer.minivans.size
+ assert speedometer.save
+ assert_equal ["first", "second"], speedometer.reload.minivans.map(&:name)
+ end
+
def test_association_keys_bypass_attribute_protection
car = Car.create(:name => 'honda')
@@ -308,9 +277,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 2, companies(:first_firm).limited_clients.limit(nil).to_a.size
end
- def test_find_should_prepend_to_association_order
+ def test_find_should_append_to_association_order
ordered_clients = companies(:first_firm).clients_sorted_desc.order('companies.id')
- assert_equal ['companies.id', 'id DESC'], ordered_clients.order_values
+ assert_equal ['id DESC', 'companies.id'], ordered_clients.order_values
end
def test_dynamic_find_should_respect_association_order
@@ -347,42 +316,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients_using_primary_key.first.name
end
- def test_finding_using_sql
- firm = Firm.order("id").first
- first_client = firm.clients_using_sql.first
- assert_not_nil first_client
- assert_equal "Microsoft", first_client.name
- assert_equal 1, firm.clients_using_sql.size
- assert_equal 1, Firm.order("id").first.clients_using_sql.size
- end
-
- def test_finding_using_sql_take_into_account_only_uniq_ids
- firm = Firm.order("id").first
- client = firm.clients_using_sql.first
- assert_equal client, firm.clients_using_sql.find(client.id, client.id)
- assert_equal client, firm.clients_using_sql.find(client.id, client.id.to_s)
- end
-
- def test_counting_using_sql
- assert_equal 1, Firm.order("id").first.clients_using_counter_sql.size
- assert Firm.order("id").first.clients_using_counter_sql.any?
- assert_equal 0, Firm.order("id").first.clients_using_zero_counter_sql.size
- assert !Firm.order("id").first.clients_using_zero_counter_sql.any?
- end
-
- def test_counting_non_existant_items_using_sql
- assert_equal 0, Firm.order("id").first.no_clients_using_counter_sql.size
- end
-
- def test_counting_using_finder_sql
- assert_equal 2, Firm.find(4).clients_using_sql.count
- end
-
def test_belongs_to_sanity
c = Client.new
- assert_nil c.firm
-
- flunk "belongs_to failed if check" if c.firm
+ assert_nil c.firm, "belongs_to failed sanity check on new object"
end
def test_find_ids
@@ -405,20 +341,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) }
end
- def test_find_string_ids_when_using_finder_sql
- firm = Firm.order("id").first
+ def test_find_ids_and_inverse_of
+ force_signal37_to_load_all_clients_of_firm
- client = firm.clients_using_finder_sql.find("2")
+ firm = companies(:first_firm)
+ client = firm.clients_of_firm.find(3)
assert_kind_of Client, client
- client_ary = firm.clients_using_finder_sql.find(["2"])
+ client_ary = firm.clients_of_firm.find([3])
assert_kind_of Array, client_ary
assert_equal client, client_ary.first
-
- client_ary = firm.clients_using_finder_sql.find("2", "3")
- assert_kind_of Array, client_ary
- assert_equal 2, client_ary.size
- assert client_ary.include?(client)
end
def test_find_all
@@ -523,9 +455,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_select_query_method
- assert_equal ['id'], posts(:welcome).comments.select(:id).first.attributes.keys
+ assert_equal ['id', 'body'], posts(:welcome).comments.select(:id, :body).first.attributes.keys
end
+ def test_select_with_block
+ assert_equal [1], posts(:welcome).comments.select { |c| c.id == 1 }.map(&:id)
+ end
+
+ def test_select_without_foreign_key
+ assert_equal companies(:first_firm).accounts.first.credit_limit, companies(:first_firm).accounts.select(:credit_limit).first.credit_limit
+ end
+
def test_adding
force_signal37_to_load_all_clients_of_firm
natural = Client.new("name" => "Natural Company")
@@ -602,6 +542,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
end
+ def test_inverse_on_before_validate
+ firm = companies(:first_firm)
+ assert_queries(1) do
+ firm.clients_of_firm << Client.new("name" => "Natural Company")
+ end
+ end
+
def test_new_aliased_to_build
company = companies(:first_firm)
new_client = assert_no_queries { company.clients_of_firm.new("name" => "Another Client") }
@@ -840,13 +787,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_delete_all
force_signal37_to_load_all_clients_of_firm
- companies(:first_firm).clients_of_firm.create("name" => "Another Client")
- clients = companies(:first_firm).clients_of_firm.to_a
+ companies(:first_firm).dependent_clients_of_firm.create("name" => "Another Client")
+ clients = companies(:first_firm).dependent_clients_of_firm.to_a
assert_equal 2, clients.count
- deleted = companies(:first_firm).clients_of_firm.delete_all
- assert_equal clients.sort_by(&:id), deleted.sort_by(&:id)
- assert_equal 0, companies(:first_firm).clients_of_firm.size
- assert_equal 0, companies(:first_firm).clients_of_firm(true).size
+
+ assert_difference "Client.count", -(clients.count) do
+ companies(:first_firm).dependent_clients_of_firm.delete_all
+ end
end
def test_delete_all_with_not_yet_loaded_association_collection
@@ -920,18 +867,33 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm = companies(:first_firm)
client_id = firm.dependent_clients_of_firm.first.id
assert_equal 1, firm.dependent_clients_of_firm.size
+ assert_equal 1, Client.find_by_id(client_id).client_of
- # :dependent means destroy is called on each client
+ # :delete_all is called on each client since the dependent options is :destroy
firm.dependent_clients_of_firm.clear
assert_equal 0, firm.dependent_clients_of_firm.size
assert_equal 0, firm.dependent_clients_of_firm(true).size
- assert_equal [client_id], Client.destroyed_client_ids[firm.id]
+ assert_equal [], Client.destroyed_client_ids[firm.id]
# Should be destroyed since the association is dependent.
assert_nil Client.find_by_id(client_id)
end
+ def test_delete_all_with_option_delete_all
+ firm = companies(:first_firm)
+ client_id = firm.dependent_clients_of_firm.first.id
+ firm.dependent_clients_of_firm.delete_all(:delete_all)
+ assert_nil Client.find_by_id(client_id)
+ end
+
+ def test_delete_all_accepts_limited_parameters
+ firm = companies(:first_firm)
+ assert_raise(ArgumentError) do
+ firm.dependent_clients_of_firm.delete_all(:destroy)
+ end
+ end
+
def test_clearing_an_exclusively_dependent_association_collection
firm = companies(:first_firm)
client_id = firm.exclusively_dependent_clients_of_firm.first.id
@@ -1179,21 +1141,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal num_accounts, Account.count
end
- def test_restrict
- firm = RestrictedFirm.create!(:name => 'restrict')
- firm.companies.create(:name => 'child')
-
- assert !firm.companies.empty?
- assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy }
- assert RestrictedFirm.exists?(:name => 'restrict')
- assert firm.companies.exists?(:name => 'child')
- end
-
- def test_restrict_is_deprecated
- klass = Class.new(ActiveRecord::Base)
- assert_deprecated { klass.has_many :posts, dependent: :restrict }
- end
-
def test_restrict_with_exception
firm = RestrictedWithExceptionFirm.create!(:name => 'restrict')
firm.companies.create(:name => 'child')
@@ -1220,14 +1167,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_included_in_collection
- assert companies(:first_firm).clients.include?(Client.find(2))
+ assert_equal true, companies(:first_firm).clients.include?(Client.find(2))
end
def test_included_in_collection_for_new_records
client = Client.create(:name => 'Persisted')
assert_nil client.client_of
- assert !Firm.new.clients_of_firm.include?(client),
- 'includes a client that does not belong to any firm'
+ assert_equal false, Firm.new.clients_of_firm.include?(client),
+ 'includes a client that does not belong to any firm'
end
def test_adding_array_and_collection
@@ -1254,7 +1201,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm.save
firm.reload
assert_equal 2, firm.clients.length
- assert !firm.clients.include?(:first_client)
+ assert_equal false, firm.clients.include?(:first_client)
end
def test_replace_failure
@@ -1315,24 +1262,44 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [readers(:michael_welcome).id], posts(:welcome).readers_with_person_ids
end
- def test_get_ids_for_unloaded_finder_sql_associations_loads_them
- company = companies(:first_firm)
- assert !company.clients_using_sql.loaded?
- assert_equal [companies(:second_client).id], company.clients_using_sql_ids
- assert company.clients_using_sql.loaded?
- end
-
def test_get_ids_for_ordered_association
assert_equal [companies(:second_client).id, companies(:first_client).id], companies(:first_firm).clients_ordered_by_name_ids
end
+ def test_get_ids_for_association_on_new_record_does_not_try_to_find_records
+ Company.columns # Load schema information so we don't query below
+ Contract.columns # if running just this test.
+
+ company = Company.new
+ assert_queries(0) do
+ company.contract_ids
+ end
+
+ assert_equal [], company.contract_ids
+ end
+
+ def test_set_ids_for_association_on_new_record_applies_association_correctly
+ contract_a = Contract.create!
+ contract_b = Contract.create!
+ Contract.create! # another contract
+ company = Company.new(:name => "Some Company")
+
+ company.contract_ids = [contract_a.id, contract_b.id]
+ assert_equal [contract_a.id, contract_b.id], company.contract_ids
+ assert_equal [contract_a, contract_b], company.contracts
+
+ company.save!
+ assert_equal company, contract_a.reload.company
+ assert_equal company, contract_b.reload.company
+ end
+
def test_assign_ids_ignoring_blanks
firm = Firm.create!(:name => 'Apple')
firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, '']
firm.save!
assert_equal 2, firm.clients(true).size
- assert firm.clients.include?(companies(:second_client))
+ assert_equal true, firm.clients.include?(companies(:second_client))
end
def test_get_ids_for_through
@@ -1366,7 +1333,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_no_queries do
assert firm.clients.loaded?
- assert firm.clients.include?(client)
+ assert_equal true, firm.clients.include?(client)
end
end
@@ -1377,28 +1344,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm.reload
assert ! firm.clients.loaded?
assert_queries(1) do
- assert firm.clients.include?(client)
+ assert_equal true, firm.clients.include?(client)
end
assert ! firm.clients.loaded?
end
- def test_include_loads_collection_if_target_uses_finder_sql
- firm = companies(:first_firm)
- client = firm.clients_using_sql.first
-
- firm.reload
- assert ! firm.clients_using_sql.loaded?
- assert firm.clients_using_sql.include?(client)
- assert firm.clients_using_sql.loaded?
- end
-
-
def test_include_returns_false_for_non_matching_record_to_verify_scoping
firm = companies(:first_firm)
client = Client.create!(:name => 'Not Associated')
assert ! firm.clients.loaded?
- assert ! firm.clients.include?(client)
+ assert_equal false, firm.clients.include?(client)
end
def test_calling_first_or_last_on_association_should_not_load_association
@@ -1472,6 +1428,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal david.essays, Essay.where(writer_id: "David")
end
+ def test_has_many_assignment_with_custom_primary_key
+ david = people(:david)
+
+ assert_equal ["A Modest Proposal"], david.essays.map(&:name)
+ david.essays = [Essay.create!(name: "Remote Work" )]
+ assert_equal ["Remote Work"], david.essays.map(&:name)
+ end
+
def test_blank_custom_primary_key_on_new_record_should_not_run_queries
author = Author.new
assert !author.essays.loaded?
@@ -1481,15 +1445,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
end
- def test_calling_first_or_last_with_integer_on_association_should_load_association
+ def test_calling_first_or_last_with_integer_on_association_should_not_load_association
firm = companies(:first_firm)
+ firm.clients.create(:name => 'Foo')
+ assert !firm.clients.loaded?
- assert_queries 1 do
+ assert_queries 2 do
firm.clients.first(2)
firm.clients.last(2)
end
- assert firm.clients.loaded?
+ assert !firm.clients.loaded?
end
def test_calling_many_should_count_instead_of_loading_association
@@ -1605,7 +1571,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_include_method_in_has_many_association_should_return_true_for_instance_added_with_build
post = Post.new
comment = post.comments.build
- assert post.comments.include?(comment)
+ assert_equal true, post.comments.include?(comment)
end
def test_load_target_respects_protected_attributes
@@ -1675,6 +1641,22 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal car.id, bulb.attributes_after_initialize['car_id']
end
+ def test_attributes_are_set_when_initialized_from_has_many_null_relationship
+ car = Car.new name: 'honda'
+ bulb = car.bulbs.where(name: 'headlight').first_or_initialize
+ assert_equal 'headlight', bulb.name
+ end
+
+ def test_attributes_are_set_when_initialized_from_polymorphic_has_many_null_relationship
+ post = Post.new title: 'title', body: 'bar'
+ tag = Tag.create!(name: 'foo')
+
+ tagging = post.taggings.where(tag: tag).first_or_initialize
+
+ assert_equal tag.id, tagging.tag_id
+ assert_equal 'Post', tagging.taggable_type
+ end
+
def test_replace
car = Car.create(:name => 'honda')
bulb1 = car.bulbs.create
@@ -1729,22 +1711,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
end
- test ":finder_sql is deprecated" do
- klass = Class.new(ActiveRecord::Base)
- assert_deprecated { klass.has_many :foo, :finder_sql => 'lol' }
- end
-
- test ":counter_sql is deprecated" do
- klass = Class.new(ActiveRecord::Base)
- assert_deprecated { klass.has_many :foo, :counter_sql => 'lol' }
- end
-
- test "sum calculation with block for array compatibility is deprecated" do
- assert_deprecated do
- posts(:welcome).comments.sum { |c| c.id }
- end
- end
-
test "has many associations on new records use null relations" do
post = Post.new
@@ -1797,4 +1763,32 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 1, speedometer.minivans.to_a.size, "Only one association should be present:\n#{speedometer.minivans.to_a}"
assert_equal 1, speedometer.reload.minivans.to_a.size
end
+
+ test "can unscope the default scope of the associated model" do
+ car = Car.create!
+ bulb1 = Bulb.create! name: "defaulty", car: car
+ bulb2 = Bulb.create! name: "other", car: car
+
+ assert_equal [bulb1], car.bulbs
+ assert_equal [bulb1, bulb2], car.all_bulbs.sort_by(&:id)
+ end
+
+ test "raises RecordNotDestroyed when replaced child can't be destroyed" do
+ car = Car.create!
+ original_child = FailedBulb.create!(car: car)
+
+ assert_raise(ActiveRecord::RecordNotDestroyed) do
+ car.failed_bulbs = [FailedBulb.create!]
+ end
+
+ assert_equal [original_child], car.reload.failed_bulbs
+ end
+
+ test 'updates counter cache when default scope is given' do
+ topic = DefaultRejectedTopic.create approved: true
+
+ assert_difference "topic.reload.replies_count", 1 do
+ topic.approved_replies.create!
+ end
+ end
end
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 70c6b489aa..47592f312e 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -5,6 +5,7 @@ require 'models/reference'
require 'models/job'
require 'models/reader'
require 'models/comment'
+require 'models/rating'
require 'models/tag'
require 'models/tagging'
require 'models/author'
@@ -27,7 +28,8 @@ require 'models/club'
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
:owners, :pets, :toys, :jobs, :references, :companies, :members, :author_addresses,
- :subscribers, :books, :subscriptions, :developers, :categorizations, :essays
+ :subscribers, :books, :subscriptions, :developers, :categorizations, :essays,
+ :categories_posts, :clubs, :memberships
# Dummies to force column loads so query counts are clean.
def setup
@@ -35,6 +37,136 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
Reader.create :person_id => 0, :post_id => 0
end
+ def test_preload_sti_rhs_class
+ developers = Developer.includes(:firms).all.to_a
+ assert_no_queries do
+ developers.each { |d| d.firms }
+ end
+ end
+
+ def test_preload_sti_middle_relation
+ club = Club.create!(name: 'Aaron cool banana club')
+ member1 = Member.create!(name: 'Aaron')
+ member2 = Member.create!(name: 'Cat')
+
+ SuperMembership.create! club: club, member: member1
+ CurrentMembership.create! club: club, member: member2
+
+ club1 = Club.includes(:members).find_by_id club.id
+ assert_equal [member1, member2].sort_by(&:id),
+ club1.members.sort_by(&:id)
+ end
+
+ def make_model(name)
+ Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
+ end
+
+ def test_ordered_habtm
+ person_prime = Class.new(ActiveRecord::Base) do
+ def self.name; 'Person'; end
+
+ has_many :readers
+ has_many :posts, -> { order('posts.id DESC') }, :through => :readers
+ end
+ posts = person_prime.includes(:posts).first.posts
+
+ assert_operator posts.length, :>, 1
+ posts.each_cons(2) do |left,right|
+ assert_operator left.id, :>, right.id
+ end
+ end
+
+ def test_singleton_has_many_through
+ book = make_model "Book"
+ subscription = make_model "Subscription"
+ subscriber = make_model "Subscriber"
+
+ subscriber.primary_key = 'nick'
+ subscription.belongs_to :book, class: book
+ subscription.belongs_to :subscriber, class: subscriber
+
+ book.has_many :subscriptions, class: subscription
+ book.has_many :subscribers, through: :subscriptions, class: subscriber
+
+ anonbook = book.first
+ namebook = Book.find anonbook.id
+
+ assert_operator anonbook.subscribers.count, :>, 0
+ anonbook.subscribers.each do |s|
+ assert_instance_of subscriber, s
+ end
+ assert_equal namebook.subscribers.map(&:id).sort,
+ anonbook.subscribers.map(&:id).sort
+ end
+
+ def test_no_pk_join_table_append
+ lesson, _, student = make_no_pk_hm_t
+
+ sicp = lesson.new(:name => "SICP")
+ ben = student.new(:name => "Ben Bitdiddle")
+ sicp.students << ben
+ assert sicp.save!
+ end
+
+ def test_no_pk_join_table_delete
+ lesson, lesson_student, student = make_no_pk_hm_t
+
+ sicp = lesson.new(:name => "SICP")
+ ben = student.new(:name => "Ben Bitdiddle")
+ louis = student.new(:name => "Louis Reasoner")
+ sicp.students << ben
+ sicp.students << louis
+ assert sicp.save!
+
+ sicp.students.reload
+ assert_operator lesson_student.count, :>=, 2
+ assert_no_difference('student.count') do
+ assert_difference('lesson_student.count', -2) do
+ sicp.students.destroy(*student.all.to_a)
+ end
+ end
+ end
+
+ def test_no_pk_join_model_callbacks
+ lesson, lesson_student, student = make_no_pk_hm_t
+
+ after_destroy_called = false
+ lesson_student.after_destroy do
+ after_destroy_called = true
+ end
+
+ sicp = lesson.new(:name => "SICP")
+ ben = student.new(:name => "Ben Bitdiddle")
+ sicp.students << ben
+ assert sicp.save!
+
+ sicp.students.reload
+ sicp.students.destroy(*student.all.to_a)
+ assert after_destroy_called, "after destroy should be called"
+ end
+
+ def make_no_pk_hm_t
+ lesson = make_model 'Lesson'
+ student = make_model 'Student'
+
+ lesson_student = make_model 'LessonStudent'
+ lesson_student.table_name = 'lessons_students'
+
+ lesson_student.belongs_to :lesson, :class => lesson
+ lesson_student.belongs_to :student, :class => student
+ lesson.has_many :lesson_students, :class => lesson_student
+ lesson.has_many :students, :through => :lesson_students, :class => student
+ [lesson, lesson_student, student]
+ end
+
+ def test_pk_is_not_required_for_join
+ post = Post.includes(:scategories).first
+ post2 = Post.includes(:categories).first
+
+ assert_operator post.categories.length, :>, 0
+ assert_equal post2.categories, post.categories
+ end
+
def test_include?
person = Person.new
post = Post.new
@@ -57,6 +189,47 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert post.reload.people(true).include?(person)
end
+ def test_delete_all_for_with_dependent_option_destroy
+ person = people(:david)
+ assert_equal 1, person.jobs_with_dependent_destroy.count
+
+ assert_no_difference 'Job.count' do
+ assert_difference 'Reference.count', -1 do
+ person.reload.jobs_with_dependent_destroy.delete_all
+ end
+ end
+ end
+
+ def test_delete_all_for_with_dependent_option_nullify
+ person = people(:david)
+ assert_equal 1, person.jobs_with_dependent_nullify.count
+
+ assert_no_difference 'Job.count' do
+ assert_no_difference 'Reference.count' do
+ person.reload.jobs_with_dependent_nullify.delete_all
+ end
+ end
+ end
+
+ def test_delete_all_for_with_dependent_option_delete_all
+ person = people(:david)
+ assert_equal 1, person.jobs_with_dependent_delete_all.count
+
+ assert_no_difference 'Job.count' do
+ assert_difference 'Reference.count', -1 do
+ person.reload.jobs_with_dependent_delete_all.delete_all
+ end
+ end
+ end
+
+ def test_concat
+ person = people(:david)
+ post = posts(:thinking)
+ post.people.concat [person]
+ assert_equal 1, post.people.size
+ assert_equal 1, post.people(true).size
+ end
+
def test_associate_existing_record_twice_should_add_to_target_twice
post = posts(:thinking)
person = people(:david)
@@ -341,6 +514,15 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_equal(post.taggings.count, post.taggings_count)
end
+ def test_update_counter_caches_on_destroy
+ post = posts(:welcome)
+ tag = post.tags.create!(name: 'doomed')
+
+ assert_difference 'post.reload.taggings_count', -1 do
+ tag.tagged_posts.destroy(post)
+ end
+ end
+
def test_replace_association
assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
@@ -582,6 +764,11 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_equal post.author.author_favorites, post.author_favorites
end
+ def test_merge_join_association_with_has_many_through_association_proxy
+ author = authors(:mary)
+ assert_nothing_raised { author.comments.ratings.to_sql }
+ end
+
def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
assert_equal 2, owners(:blackbeard).toys.count
end
@@ -607,7 +794,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
sarah = Person.create!(:first_name => 'Sarah', :primary_contact_id => people(:susan).id, :gender => 'F', :number1_fan_id => 1)
john = Person.create!(:first_name => 'John', :primary_contact_id => sarah.id, :gender => 'M', :number1_fan_id => 1)
assert_equal sarah.agents, [john]
- assert_equal people(:susan).agents.map(&:agents).flatten, people(:susan).agents_of_agents
+ assert_equal people(:susan).agents.flat_map(&:agents), people(:susan).agents_of_agents
end
def test_associate_existing_with_nonstandard_primary_key_on_belongs_to
@@ -907,4 +1094,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
readers(:michael_authorless).update(first_post_id: 1)
assert_equal [posts(:thinking)], person.reload.first_posts
end
+
+ def test_has_many_through_with_includes_in_through_association_scope
+ assert_not_empty posts(:welcome).author_address_extra_with_address
+ end
end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 0e48fbca9c..5a41461edf 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -158,22 +158,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_nothing_raised { firm.destroy }
end
- def test_restrict
- firm = RestrictedFirm.create!(:name => 'restrict')
- firm.create_account(:credit_limit => 10)
-
- assert_not_nil firm.account
-
- assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy }
- assert RestrictedFirm.exists?(:name => 'restrict')
- assert firm.account.present?
- end
-
- def test_restrict_is_deprecated
- klass = Class.new(ActiveRecord::Base)
- assert_deprecated { klass.has_one :post, dependent: :restrict }
- end
-
def test_restrict_with_exception
firm = RestrictedWithExceptionFirm.create!(:name => 'restrict')
firm.create_account(:credit_limit => 10)
@@ -521,21 +505,56 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_no_queries { company.account = nil }
account = Account.find(2)
assert_queries { company.account = account }
+
+ assert_no_queries { Firm.new.account = account }
end
- def test_has_one_assignment_triggers_save_on_change
+ def test_has_one_assignment_dont_trigger_save_on_change_of_same_object
pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?")
ship = pirate.build_ship(name: 'old name')
ship.save!
ship.name = 'new name'
assert ship.changed?
+ assert_queries(1) do
+ # One query for updating name, not triggering query for updating pirate_id
+ pirate.ship = ship
+ end
+
+ assert_equal 'new name', pirate.ship.reload.name
+ end
+
+ def test_has_one_assignment_triggers_save_on_change_on_replacing_object
+ pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?")
+ ship = pirate.build_ship(name: 'old name')
+ ship.save!
+
+ new_ship = Ship.create(name: 'new name')
assert_queries(2) do
# One query for updating name and second query for updating pirate_id
- pirate.ship = ship
+ pirate.ship = new_ship
end
assert_equal 'new name', pirate.ship.reload.name
end
+ def test_has_one_autosave_with_primary_key_manually_set
+ post = Post.create(id: 1234, title: "Some title", body: 'Some content')
+ author = Author.new(id: 33, name: 'Hank Moody')
+
+ author.post = post
+ author.save
+ author.reload
+
+ assert_not_nil author.post
+ assert_equal author.post, post
+ end
+
+ def test_has_one_relationship_cannot_have_a_counter_cache
+ assert_raise(ArgumentError) do
+ Class.new(ActiveRecord::Base) do
+ has_one :thing, counter_cache: true
+ end
+ end
+ end
end
diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb
index 90c557e886..a2725441b3 100644
--- a/activerecord/test/cases/associations/has_one_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb
@@ -191,6 +191,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
end
def test_preloading_has_one_through_on_belongs_to
+ MemberDetail.delete_all
assert_not_nil @member.member_type
@organization = organizations(:nsa)
@member_detail = MemberDetail.new
@@ -201,7 +202,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
end
@new_detail = @member_details[0]
assert @new_detail.send(:association, :member_type).loaded?
- assert_not_nil assert_no_queries { @new_detail.member_type }
+ assert_no_queries { @new_detail.member_type }
end
def test_save_of_record_with_loaded_has_one_through
@@ -314,4 +315,12 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
def test_has_one_through_with_custom_select_on_join_model_default_scope
assert_equal clubs(:boring_club), members(:groucho).selected_club
end
+
+ def test_has_one_through_relationship_cannot_have_a_counter_cache
+ assert_raise(ArgumentError) do
+ Class.new(ActiveRecord::Base) do
+ has_one :thing, through: :other_thing, counter_cache: true
+ end
+ end
+ end
end
diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb
index 918783e8f1..a9efa6d86a 100644
--- a/activerecord/test/cases/associations/inner_join_association_test.rb
+++ b/activerecord/test/cases/associations/inner_join_association_test.rb
@@ -41,15 +41,20 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
assert_no_match(/WHERE/i, sql)
end
+ def test_join_association_conditions_support_string_and_arel_expressions
+ assert_equal 0, Author.joins(:welcome_posts_with_one_comment).count
+ assert_equal 1, Author.joins(:welcome_posts_with_comments).count
+ end
+
def test_join_conditions_allow_nil_associations
authors = Author.includes(:essays).where(:essays => {:id => nil})
assert_equal 2, authors.count
end
- def test_find_with_implicit_inner_joins_honors_readonly_without_select
- authors = Author.joins(:posts).to_a
- assert !authors.empty?, "expected authors to be non-empty"
- assert authors.all? {|a| a.readonly? }, "expected all authors to be readonly"
+ def test_find_with_implicit_inner_joins_without_select_does_not_imply_readonly
+ authors = Author.joins(:posts)
+ assert_not authors.empty?, "expected authors to be non-empty"
+ assert authors.none? {|a| a.readonly? }, "expected no authors to be readonly"
end
def test_find_with_implicit_inner_joins_honors_readonly_with_select
@@ -65,7 +70,7 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
end
def test_find_with_implicit_inner_joins_does_not_set_associations
- authors = Author.joins(:posts).select('authors.*')
+ authors = Author.joins(:posts).select('authors.*').to_a
assert !authors.empty?, "expected authors to be non-empty"
assert authors.all? { |a| !a.instance_variable_defined?(:@posts) }, "expected no authors to have the @posts association loaded"
end
@@ -104,4 +109,12 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase
assert !posts(:welcome).tags.empty?
assert Post.joins(:misc_tags).where(:id => posts(:welcome).id).empty?
end
+
+ test "the default scope of the target is applied when joining associations" do
+ author = Author.create! name: "Jon"
+ author.categorizations.create!
+ author.categorizations.create! special: true
+
+ assert_equal [author], Author.where(id: author).joins(:special_categorizations)
+ end
end
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index b1f0be3204..893030345f 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -9,10 +9,24 @@ require 'models/rating'
require 'models/comment'
require 'models/car'
require 'models/bulb'
+require 'models/mixed_case_monkey'
class AutomaticInverseFindingTests < ActiveRecord::TestCase
fixtures :ratings, :comments, :cars
+ def test_has_one_and_belongs_to_should_find_inverse_automatically_on_multiple_word_name
+ monkey_reflection = MixedCaseMonkey.reflect_on_association(:man)
+ man_reflection = Man.reflect_on_association(:mixed_case_monkey)
+
+ assert_respond_to monkey_reflection, :has_inverse?
+ assert monkey_reflection.has_inverse?, "The monkey reflection should have an inverse"
+ assert_equal man_reflection, monkey_reflection.inverse_of, "The monkey reflection's inverse should be the man reflection"
+
+ assert_respond_to man_reflection, :has_inverse?
+ assert man_reflection.has_inverse?, "The man reflection should have an inverse"
+ assert_equal monkey_reflection, man_reflection.inverse_of, "The man reflection's inverse should be the monkey reflection"
+ end
+
def test_has_one_and_belongs_to_should_find_inverse_automatically
car_reflection = Car.reflect_on_association(:bulb)
bulb_reflection = Bulb.reflect_on_association(:car)
@@ -401,10 +415,22 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match after the child name is changed"
end
+ def test_find_on_child_instance_with_id_should_not_load_all_child_records
+ man = Man.create!
+ interest = Interest.create!(man: man)
+
+ man.interests.find(interest.id)
+ assert_not man.interests.loaded?
+ end
+
def test_raise_record_not_found_error_when_invalid_ids_are_passed
+ # delete all interest records to ensure that hard coded invalid_id(s)
+ # are indeed invalid.
+ Interest.delete_all
+
man = Man.create!
- invalid_id = 2394823094892348920348523452345
+ invalid_id = 245324523
assert_raise(ActiveRecord::RecordNotFound) { man.interests.find(invalid_id) }
invalid_ids = [8432342, 2390102913, 2453245234523452]
@@ -420,6 +446,19 @@ class InverseHasManyTests < ActiveRecord::TestCase
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.first.secret_interests }
end
+
+ def test_child_instance_should_point_to_parent_without_saving
+ man = Man.new
+ i = Interest.create(:topic => 'Industrial Revolution Re-enactment')
+
+ man.interests << i
+ assert_not_nil i.man
+
+ i.man.name = "Charles"
+ assert_equal i.man.name, man.name
+
+ assert !man.persisted?
+ end
end
class InverseBelongsToTests < ActiveRecord::TestCase
@@ -564,6 +603,18 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
end
+ def test_inversed_instance_should_not_be_reloaded_after_stale_state_changed
+ new_man = Man.new
+ face = Face.new
+ new_man.face = face
+
+ old_inversed_man = face.man
+ new_man.save!
+ new_inversed_man = face.man
+
+ assert_equal old_inversed_man.object_id, new_inversed_man.object_id
+ end
+
def test_should_not_try_to_set_inverse_instances_when_the_inverse_is_a_has_many
i = interests(:llama_wrangling)
m = i.polymorphic_man
diff --git a/activerecord/test/cases/associations/join_dependency_test.rb b/activerecord/test/cases/associations/join_dependency_test.rb
deleted file mode 100644
index 08c166dc33..0000000000
--- a/activerecord/test/cases/associations/join_dependency_test.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require "cases/helper"
-require 'models/edge'
-
-class JoinDependencyTest < ActiveRecord::TestCase
- def test_column_names_with_alias_handles_nil_primary_key
- assert_equal Edge.column_names, ActiveRecord::Associations::JoinDependency::JoinBase.new(Edge).column_names_with_alias.map(&:first)
- end
-end \ No newline at end of file
diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb
index e75d43bda8..8ef351cda8 100644
--- a/activerecord/test/cases/associations/nested_through_associations_test.rb
+++ b/activerecord/test/cases/associations/nested_through_associations_test.rb
@@ -186,7 +186,9 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
members = assert_queries(4) { Member.includes(:organization_member_details_2).to_a.sort_by(&:id) }
groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
- assert_no_queries do
+ # postgresql test if randomly executed then executes "SHOW max_identifier_length". Hence
+ # the need to ignore certain predefined sqls that deal with system calls.
+ assert_no_queries(ignore_none: false) do
assert_equal [groucho_details, other_details], members.first.organization_member_details_2.sort_by(&:id)
end
end
@@ -212,7 +214,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
end
def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection_preload
- authors = assert_queries(3) { Author.includes(:post_categories).to_a.sort_by(&:id) }
+ authors = assert_queries(4) { Author.includes(:post_categories).to_a.sort_by(&:id) }
general, cooking = categories(:general), categories(:cooking)
assert_no_queries do
@@ -240,7 +242,8 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
end
def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection_preload
- categories = assert_queries(3) { Category.includes(:post_comments).to_a.sort_by(&:id) }
+ Category.includes(:post_comments).to_a # preheat cache
+ categories = assert_queries(4) { Category.includes(:post_comments).to_a.sort_by(&:id) }
greetings, more = comments(:greetings), comments(:more_greetings)
assert_no_queries do
@@ -268,7 +271,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
end
def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection_preload
- authors = assert_queries(5) { Author.includes(:category_post_comments).to_a.sort_by(&:id) }
+ authors = assert_queries(6) { Author.includes(:category_post_comments).to_a.sort_by(&:id) }
greetings, more = comments(:greetings), comments(:more_greetings)
assert_no_queries do
@@ -369,7 +372,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
prev_default_scope = Club.default_scopes
[:includes, :preload, :joins, :eager_load].each do |q|
- Club.default_scopes = [Club.send(q, :category)]
+ Club.default_scopes = [proc { Club.send(q, :category) }]
assert_equal categories(:general), members(:groucho).reload.club_category
end
ensure
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index c3b728296e..48e6fc5cd4 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -278,7 +278,7 @@ class OverridingAssociationsTest < ActiveRecord::TestCase
def test_habtm_association_redefinition_callbacks_should_differ_and_not_inherited
# redeclared association on AR descendant should not inherit callbacks from superclass
callbacks = PeopleList.before_add_for_has_and_belongs_to_many
- assert_equal([:enlist], callbacks)
+ assert_equal(1, callbacks.length)
callbacks = DifferentPeopleList.before_add_for_has_and_belongs_to_many
assert_equal([], callbacks)
end
@@ -286,7 +286,7 @@ class OverridingAssociationsTest < ActiveRecord::TestCase
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.before_add_for_has_many
- assert_equal([:enlist], callbacks)
+ assert_equal(1, callbacks.length)
callbacks = DifferentPeopleList.before_add_for_has_many
assert_equal([], callbacks)
end
diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb
index 8d8ff2f952..c0659fddef 100644
--- a/activerecord/test/cases/attribute_methods/read_test.rb
+++ b/activerecord/test/cases/attribute_methods/read_test.rb
@@ -15,13 +15,6 @@ module ActiveRecord
include ActiveRecord::AttributeMethods
- def self.define_attribute_methods
- # Created in the inherited/included hook for "proper" ARs
- @attribute_methods_mutex ||= Mutex.new
-
- super
- end
-
def self.column_names
%w{ one two three }
end
@@ -56,9 +49,9 @@ module ActiveRecord
end
def test_attribute_methods_generated?
- assert(!@klass.attribute_methods_generated?, 'attribute_methods_generated?')
+ assert_not @klass.method_defined?(:one)
@klass.define_attribute_methods
- assert(@klass.attribute_methods_generated?, 'attribute_methods_generated?')
+ assert @klass.method_defined?(:one)
end
end
end
diff --git a/activerecord/test/cases/attribute_methods/serialization_test.rb b/activerecord/test/cases/attribute_methods/serialization_test.rb
new file mode 100644
index 0000000000..75de773961
--- /dev/null
+++ b/activerecord/test/cases/attribute_methods/serialization_test.rb
@@ -0,0 +1,29 @@
+require "cases/helper"
+
+module ActiveRecord
+ module AttributeMethods
+ class SerializationTest < ActiveSupport::TestCase
+ class FakeColumn < Struct.new(:name)
+ def type; :integer; end
+ def type_cast(s); "#{s}!"; end
+ end
+
+ class NullCoder
+ def load(v); v; end
+ end
+
+ def test_type_cast_serialized_value
+ value = Serialization::Attribute.new(NullCoder.new, "Hello world", :serialized)
+ type = Serialization::Type.new(FakeColumn.new)
+ assert_equal "Hello world!", type.type_cast(value)
+ end
+
+ def test_type_cast_unserialized_value
+ value = Serialization::Attribute.new(nil, "Hello world", :unserialized)
+ type = Serialization::Type.new(FakeColumn.new)
+ type.type_cast(value)
+ assert_equal "Hello world", type.type_cast(value)
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index f10732ddda..6c581a432f 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -27,6 +27,14 @@ class AttributeMethodsTest < ActiveRecord::TestCase
ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
end
+ def test_attribute_for_inspect
+ t = topics(:first)
+ t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
+
+ assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
+ assert_equal '"The First Topic Now Has A Title With\nNewlines And ..."', t.attribute_for_inspect(:title)
+ end
+
def test_attribute_present
t = Topic.new
t.title = "hello there!"
@@ -84,7 +92,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
def test_set_attributes_without_hash
topic = Topic.new
- assert_nothing_raised { topic.attributes = '' }
+ assert_raise(ArgumentError) { topic.attributes = '' }
end
def test_integers_as_nil
@@ -751,21 +759,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert subklass.method_defined?(:id), "subklass is missing id method"
end
- def test_dispatching_column_attributes_through_method_missing_deprecated
- Topic.define_attribute_methods
-
- topic = Topic.new(:id => 5)
- topic.id = 5
-
- topic.method(:id).owner.send(:undef_method, :id)
-
- assert_deprecated do
- assert_equal 5, topic.id
- end
- ensure
- Topic.undefine_attribute_methods
- end
-
def test_read_attribute_with_nil_should_not_asplode
assert_equal nil, Topic.new.read_attribute(nil)
end
@@ -774,8 +767,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
# that by defining a 'foo' method in the generated methods module for B.
# (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].)
def test_inherited_custom_accessors
- klass = Class.new(ActiveRecord::Base) do
- self.table_name = "topics"
+ klass = new_topic_like_ar_class do
self.abstract_class = true
def title; "omg"; end
def title=(val); self.author_name = val; end
@@ -790,8 +782,40 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert_equal "lol", topic.author_name
end
+ def test_on_the_fly_super_invokable_generated_attribute_methods_via_method_missing
+ klass = new_topic_like_ar_class do
+ def title
+ super + '!'
+ end
+ end
+
+ real_topic = topics(:first)
+ assert_equal real_topic.title + '!', klass.find(real_topic.id).title
+ end
+
+ def test_on_the_fly_super_invokable_generated_predicate_attribute_methods_via_method_missing
+ klass = new_topic_like_ar_class do
+ def title?
+ !super
+ end
+ end
+
+ real_topic = topics(:first)
+ assert_equal !real_topic.title?, klass.find(real_topic.id).title?
+ end
+
private
+ def new_topic_like_ar_class(&block)
+ klass = Class.new(ActiveRecord::Base) do
+ self.table_name = 'topics'
+ class_eval(&block)
+ end
+
+ assert_empty klass.generated_attribute_methods.instance_methods(false)
+ klass
+ end
+
def cached_columns
Topic.columns.map(&:name) - Topic.serialized_attributes.keys
end
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index 580aa96ecd..517d2674a7 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -705,6 +705,13 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
ids.each { |id| assert_nil klass.find_by_id(id) }
end
+ def test_should_not_resave_destroyed_association
+ @pirate.birds.create!(name: :parrot)
+ @pirate.birds.first.destroy
+ @pirate.save!
+ assert @pirate.reload.birds.empty?
+ end
+
def test_should_skip_validation_on_has_many_if_marked_for_destruction
2.times { |i| @pirate.birds.create!(:name => "birds_#{i}") }
@@ -1433,10 +1440,6 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas
test "should generate validation methods for HABTM associations with :validate => true" do
assert_respond_to @pirate, :validate_associated_records_for_parrots
end
-
- test "should not generate validation methods for HABTM associations without :validate => true" do
- assert !@pirate.respond_to?(:validate_associated_records_for_non_validated_parrots)
- end
end
class TestAutosaveAssociationWithTouch < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 15d536daf5..cb8e564da1 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1,4 +1,7 @@
+# encoding: utf-8
+
require "cases/helper"
+require 'active_support/concurrency/latch'
require 'models/post'
require 'models/author'
require 'models/topic'
@@ -75,22 +78,6 @@ end
class BasicsTest < ActiveRecord::TestCase
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
- def setup
- ActiveRecord::Base.time_zone_aware_attributes = false
- ActiveRecord::Base.default_timezone = :local
- Time.zone = nil
- end
-
- def test_generated_methods_modules
- modules = Computer.ancestors
- assert modules.include?(Computer::GeneratedFeatureMethods)
- assert_equal(Computer::GeneratedFeatureMethods, Computer.generated_feature_methods)
- assert(modules.index(Computer.generated_attribute_methods) > modules.index(Computer.generated_feature_methods),
- "generated_attribute_methods must be higher in inheritance hierarchy than generated_feature_methods")
- assert_not_equal Computer.generated_feature_methods, Post.generated_feature_methods
- assert(modules.index(Computer.generated_attribute_methods) < modules.index(ActiveRecord::Base.ancestors[1]))
- end
-
def test_column_names_are_escaped
conn = ActiveRecord::Base.connection
classname = conn.class.name[/[^:]*$/]
@@ -134,6 +121,10 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal 1, Topic.limit(1).to_a.length
end
+ def test_limit_should_take_value_from_latest_limit
+ assert_equal 1, Topic.limit(2).limit(1).to_a.length
+ end
+
def test_invalid_limit
assert_raises(ArgumentError) do
Topic.limit("asdfadf").to_a
@@ -231,7 +222,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_preserving_time_objects_with_local_time_conversion_to_default_timezone_utc
with_env_tz 'America/New_York' do
- with_active_record_default_timezone :utc do
+ with_timezone_config default: :utc do
time = Time.local(2000)
topic = Topic.create('written_on' => time)
saved_time = Topic.find(topic.id).reload.written_on
@@ -244,7 +235,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_utc
with_env_tz 'America/New_York' do
- with_active_record_default_timezone :utc do
+ with_timezone_config default: :utc do
Time.use_zone 'Central Time (US & Canada)' do
time = Time.zone.local(2000)
topic = Topic.create('written_on' => time)
@@ -259,18 +250,20 @@ class BasicsTest < ActiveRecord::TestCase
def test_preserving_time_objects_with_utc_time_conversion_to_default_timezone_local
with_env_tz 'America/New_York' do
- time = Time.utc(2000)
- topic = Topic.create('written_on' => time)
- saved_time = Topic.find(topic.id).reload.written_on
- assert_equal time, saved_time
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], time.to_a
- assert_equal [0, 0, 19, 31, 12, 1999, 5, 365, false, "EST"], saved_time.to_a
+ with_timezone_config default: :local do
+ time = Time.utc(2000)
+ topic = Topic.create('written_on' => time)
+ saved_time = Topic.find(topic.id).reload.written_on
+ assert_equal time, saved_time
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], time.to_a
+ assert_equal [0, 0, 19, 31, 12, 1999, 5, 365, false, "EST"], saved_time.to_a
+ end
end
end
def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_local
with_env_tz 'America/New_York' do
- with_active_record_default_timezone :local do
+ with_timezone_config default: :local do
Time.use_zone 'Central Time (US & Canada)' do
time = Time.zone.local(2000)
topic = Topic.create('written_on' => time)
@@ -490,25 +483,25 @@ class BasicsTest < ActiveRecord::TestCase
# Oracle, and Sybase do not have a TIME datatype.
unless current_adapter?(:OracleAdapter, :SybaseAdapter)
def test_utc_as_time_zone
- Topic.default_timezone = :utc
- attributes = { "bonus_time" => "5:42:00AM" }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
- Topic.default_timezone = :local
+ with_timezone_config default: :utc do
+ attributes = { "bonus_time" => "5:42:00AM" }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
+ end
end
def test_utc_as_time_zone_and_new
- Topic.default_timezone = :utc
- attributes = { "bonus_time(1i)"=>"2000",
- "bonus_time(2i)"=>"1",
- "bonus_time(3i)"=>"1",
- "bonus_time(4i)"=>"10",
- "bonus_time(5i)"=>"35",
- "bonus_time(6i)"=>"50" }
- topic = Topic.new(attributes)
- assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
- Topic.default_timezone = :local
+ with_timezone_config default: :utc do
+ attributes = { "bonus_time(1i)"=>"2000",
+ "bonus_time(2i)"=>"1",
+ "bonus_time(3i)"=>"1",
+ "bonus_time(4i)"=>"10",
+ "bonus_time(5i)"=>"35",
+ "bonus_time(6i)"=>"50" }
+ topic = Topic.new(attributes)
+ assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
+ end
end
end
@@ -555,19 +548,55 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
end
- def test_comparison
+ def test_successful_comparison_of_like_class_records
topic_1 = Topic.create!
topic_2 = Topic.create!
assert_equal [topic_2, topic_1].sort, [topic_1, topic_2]
end
+ def test_failed_comparison_of_unlike_class_records
+ assert_raises ArgumentError do
+ [ topics(:first), posts(:welcome) ].sort
+ end
+ end
+
+ def test_create_without_prepared_statement
+ topic = Topic.connection.unprepared_statement do
+ Topic.create(:title => 'foo')
+ end
+
+ assert_equal topic, Topic.find(topic.id)
+ end
+
+ def test_destroy_without_prepared_statement
+ topic = Topic.create(title: 'foo')
+ Topic.connection.unprepared_statement do
+ Topic.find(topic.id).destroy
+ end
+
+ assert_equal nil, Topic.find_by_id(topic.id)
+ end
+
+ def test_blank_ids
+ one = Subscriber.new(:id => '')
+ two = Subscriber.new(:id => '')
+ assert_equal one, two
+ end
+
def test_comparison_with_different_objects
topic = Topic.create
category = Category.create(:name => "comparison")
assert_nil topic <=> category
end
+ def test_comparison_with_different_objects_in_array
+ topic = Topic.create
+ assert_raises(ArgumentError) do
+ [1, topic].sort
+ end
+ end
+
def test_readonly_attributes
assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes
@@ -581,10 +610,23 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal "changed", post.body
end
- def test_attr_readonly_is_class_level_setting
- post = ReadonlyTitlePost.new
- assert_raise(NoMethodError) { post._attr_readonly = [:title] }
- assert_deprecated { post._attr_readonly }
+ def test_unicode_column_name
+ Weird.reset_column_information
+ weird = Weird.create(:なまえ => 'たこ焼き仮面')
+ assert_equal 'たこ焼き仮面', weird.なまえ
+ end
+
+ unless current_adapter?(:PostgreSQLAdapter)
+ def test_respect_internal_encoding
+ old_default_internal = Encoding.default_internal
+ silence_warnings { Encoding.default_internal = "EUC-JP" }
+
+ Weird.reset_column_information
+
+ assert_equal ["EUC-JP"], Weird.columns.map {|c| c.name.encoding.name }.uniq
+ ensure
+ silence_warnings { Encoding.default_internal = old_default_internal }
+ end
end
def test_non_valid_identifier_column_name
@@ -609,12 +651,14 @@ class BasicsTest < ActiveRecord::TestCase
# Oracle, and Sybase do not have a TIME datatype.
return true if current_adapter?(:OracleAdapter, :SybaseAdapter)
- attributes = {
- "bonus_time" => "5:42:00AM"
- }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
+ with_timezone_config default: :local do
+ attributes = {
+ "bonus_time" => "5:42:00AM"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
+ end
end
def test_attributes_on_dummy_time_with_invalid_time
@@ -802,19 +846,18 @@ class BasicsTest < ActiveRecord::TestCase
# TODO: extend defaults tests to other databases!
if current_adapter?(:PostgreSQLAdapter)
def test_default
- tz = Default.default_timezone
- Default.default_timezone = :local
- default = Default.new
- Default.default_timezone = tz
-
- # fixed dates / times
- assert_equal Date.new(2004, 1, 1), default.fixed_date
- assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
-
- # char types
- assert_equal 'Y', default.char1
- assert_equal 'a varchar field', default.char2
- assert_equal 'a text field', default.char3
+ with_timezone_config default: :local do
+ default = Default.new
+
+ # fixed dates / times
+ assert_equal Date.new(2004, 1, 1), default.fixed_date
+ assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
+
+ # char types
+ assert_equal 'Y', default.char1
+ assert_equal 'a varchar field', default.char2
+ assert_equal 'a text field', default.char3
+ end
end
class Geometric < ActiveRecord::Base; end
@@ -1228,83 +1271,6 @@ class BasicsTest < ActiveRecord::TestCase
assert_no_queries { assert true }
end
- def test_inspect_class
- assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect
- assert_equal 'LoosePerson(abstract)', LoosePerson.inspect
- assert_match(/^Topic\(id: integer, title: string/, Topic.inspect)
- end
-
- def test_inspect_instance
- topic = topics(:first)
- assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", important: nil, approved: false, replies_count: 1, unique_replies_count: 0, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect
- end
-
- def test_inspect_new_instance
- assert_match(/Topic id: nil/, Topic.new.inspect)
- end
-
- def test_inspect_limited_select_instance
- assert_equal %(#<Topic id: 1>), Topic.all.merge!(:select => 'id', :where => 'id = 1').first.inspect
- assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.all.merge!(:select => 'id, title', :where => 'id = 1').first.inspect
- end
-
- def test_inspect_class_without_table
- assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect
- end
-
- def test_attribute_for_inspect
- t = topics(:first)
- t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
-
- assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
- assert_equal '"The First Topic Now Has A Title With\nNewlines And M..."', t.attribute_for_inspect(:title)
- end
-
- def test_becomes
- assert_kind_of Reply, topics(:first).becomes(Reply)
- assert_equal "The First Topic", topics(:first).becomes(Reply).title
- end
-
- def test_becomes_includes_errors
- company = Company.new(:name => nil)
- assert !company.valid?
- original_errors = company.errors
- client = company.becomes(Client)
- assert_equal original_errors, client.errors
- end
-
- def test_silence_sets_log_level_to_error_in_block
- original_logger = ActiveRecord::Base.logger
-
- assert_deprecated do
- log = StringIO.new
- ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
- ActiveRecord::Base.logger.level = Logger::DEBUG
- ActiveRecord::Base.silence do
- ActiveRecord::Base.logger.warn "warn"
- ActiveRecord::Base.logger.error "error"
- end
- assert_equal "error\n", log.string
- end
- ensure
- ActiveRecord::Base.logger = original_logger
- end
-
- def test_silence_sets_log_level_back_to_level_before_yield
- original_logger = ActiveRecord::Base.logger
-
- assert_deprecated do
- log = StringIO.new
- ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
- ActiveRecord::Base.logger.level = Logger::WARN
- ActiveRecord::Base.silence do
- end
- assert_equal Logger::WARN, ActiveRecord::Base.logger.level
- end
- ensure
- ActiveRecord::Base.logger = original_logger
- end
-
def test_benchmark_with_log_level
original_logger = ActiveRecord::Base.logger
log = StringIO.new
@@ -1399,6 +1365,35 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal 1, post.comments.length
end
+ if Process.respond_to?(:fork) && !in_memory_db?
+ def test_marshal_between_processes
+ # Define a new model to ensure there are no caches
+ if self.class.const_defined?("Post", false)
+ flunk "there should be no post constant"
+ end
+
+ self.class.const_set("Post", Class.new(ActiveRecord::Base) {
+ has_many :comments
+ })
+
+ rd, wr = IO.pipe
+
+ ActiveRecord::Base.connection_handler.clear_all_connections!
+
+ fork do
+ rd.close
+ post = Post.new
+ post.comments.build
+ wr.write Marshal.dump(post)
+ wr.close
+ end
+
+ wr.close
+ assert Marshal.load rd.read
+ rd.close
+ end
+ end
+
def test_marshalling_new_record_round_trip_with_associations
post = Post.new
post.comments.build
@@ -1541,21 +1536,20 @@ class BasicsTest < ActiveRecord::TestCase
orig_handler = klass.connection_handler
new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
after_handler = nil
- is_set = false
+ latch1 = ActiveSupport::Concurrency::Latch.new
+ latch2 = ActiveSupport::Concurrency::Latch.new
t = Thread.new do
klass.connection_handler = new_handler
- is_set = true
- Thread.stop
+ latch1.release
+ latch2.await
after_handler = klass.connection_handler
end
- while(!is_set)
- Thread.pass
- end
+ latch1.await
klass.connection_handler = orig_handler
- t.wakeup
+ latch2.release
t.join
assert_equal after_handler, new_handler
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index e09fa95756..38c2560d69 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -26,6 +26,24 @@ class EachTest < ActiveRecord::TestCase
end
end
+ def test_each_should_return_an_enumerator_if_no_block_is_present
+ assert_queries(1) do
+ Post.find_each(:batch_size => 100000).with_index do |post, index|
+ assert_kind_of Post, post
+ assert_kind_of Integer, index
+ end
+ end
+ end
+
+ def test_each_enumerator_should_execute_one_query_per_batch
+ assert_queries(@total + 1) do
+ Post.find_each(:batch_size => 1).with_index do |post, index|
+ assert_kind_of Post, post
+ assert_kind_of Integer, index
+ end
+ end
+ end
+
def test_each_should_raise_if_select_is_set_without_id
assert_raise(RuntimeError) do
Post.select(:title).find_each(:batch_size => 1) { |post| post }
@@ -50,6 +68,16 @@ class EachTest < ActiveRecord::TestCase
Post.order("title").find_each { |post| post }
end
+ def test_logger_not_required
+ previous_logger = ActiveRecord::Base.logger
+ ActiveRecord::Base.logger = nil
+ assert_nothing_raised do
+ Post.limit(1).find_each { |post| post }
+ end
+ ensure
+ ActiveRecord::Base.logger = previous_logger
+ end
+
def test_find_in_batches_should_return_batches
assert_queries(@total + 1) do
Post.find_in_batches(:batch_size => 1) do |batch|
diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb
index 03aa9fdb27..291751c435 100644
--- a/activerecord/test/cases/bind_parameter_test.rb
+++ b/activerecord/test/cases/bind_parameter_test.rb
@@ -23,46 +23,56 @@ module ActiveRecord
@listener = LogListener.new
@pk = Topic.columns.find { |c| c.primary }
ActiveSupport::Notifications.subscribe('sql.active_record', @listener)
-
- skip_if_prepared_statement_caching_is_not_supported
end
def teardown
ActiveSupport::Notifications.unsubscribe(@listener)
end
- def test_binds_are_logged
- sub = @connection.substitute_at(@pk, 0)
- binds = [[@pk, 1]]
- sql = "select * from topics where id = #{sub}"
+ if ActiveRecord::Base.connection.supports_statement_cache?
+ def test_binds_are_logged
+ sub = @connection.substitute_at(@pk, 0)
+ binds = [[@pk, 1]]
+ sql = "select * from topics where id = #{sub}"
- @connection.exec_query(sql, 'SQL', binds)
+ @connection.exec_query(sql, 'SQL', binds)
- message = @listener.calls.find { |args| args[4][:sql] == sql }
- assert_equal binds, message[4][:binds]
- end
+ message = @listener.calls.find { |args| args[4][:sql] == sql }
+ assert_equal binds, message[4][:binds]
+ end
- def test_find_one_uses_binds
- Topic.find(1)
- binds = [[@pk, 1]]
- message = @listener.calls.find { |args| args[4][:binds] == binds }
- assert message, 'expected a message with binds'
- end
+ def test_binds_are_logged_after_type_cast
+ sub = @connection.substitute_at(@pk, 0)
+ binds = [[@pk, "3"]]
+ sql = "select * from topics where id = #{sub}"
- def test_logs_bind_vars
- pk = Topic.columns.find { |x| x.primary }
-
- payload = {
- :name => 'SQL',
- :sql => 'select * from topics where id = ?',
- :binds => [[pk, 10]]
- }
- event = ActiveSupport::Notifications::Event.new(
- 'foo',
- Time.now,
- Time.now,
- 123,
- payload)
+ @connection.exec_query(sql, 'SQL', binds)
+
+ message = @listener.calls.find { |args| args[4][:sql] == sql }
+ assert_equal [[@pk, 3]], message[4][:binds]
+ end
+
+ def test_find_one_uses_binds
+ Topic.find(1)
+ binds = [[@pk, 1]]
+ message = @listener.calls.find { |args| args[4][:binds] == binds }
+ assert message, 'expected a message with binds'
+ end
+
+ def test_logs_bind_vars
+ pk = Topic.columns.find { |x| x.primary }
+
+ payload = {
+ :name => 'SQL',
+ :sql => 'select * from topics where id = ?',
+ :binds => [[pk, 10]]
+ }
+ event = ActiveSupport::Notifications::Event.new(
+ 'foo',
+ Time.now,
+ Time.now,
+ 123,
+ payload)
logger = Class.new(ActiveRecord::LogSubscriber) {
attr_reader :debugs
@@ -78,12 +88,7 @@ module ActiveRecord
logger.sql event
assert_match([[pk.name, 10]].inspect, logger.debugs.first)
- end
-
- private
-
- def skip_if_prepared_statement_caching_is_not_supported
- skip('prepared statement caching is not supported') unless @connection.supports_statement_cache?
+ end
end
end
end
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index f49bef2346..2f6913167d 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -6,6 +6,7 @@ require 'models/edge'
require 'models/organization'
require 'models/possession'
require 'models/topic'
+require 'models/reply'
require 'models/minivan'
require 'models/speedometer'
require 'models/ship_part'
@@ -166,6 +167,15 @@ class CalculationsTest < ActiveRecord::TestCase
assert_no_match(/OFFSET/, queries.first)
end
+ def test_count_on_invalid_columns_raises
+ e = assert_raises(ActiveRecord::StatementInvalid) {
+ Account.select("credit_limit, firm_name").count
+ }
+
+ assert_match %r{accounts}i, e.message
+ assert_match "credit_limit, firm_name", e.message
+ end
+
def test_should_group_by_summed_field_having_condition
c = Account.group(:firm_id).having('sum(credit_limit) > 50').sum(:credit_limit)
assert_nil c[1]
@@ -201,6 +211,10 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal 19.83, NumericData.sum(:bank_balance)
end
+ def test_should_return_type_casted_values_with_group_and_expression
+ assert_equal 0.5, Account.group(:firm_name).sum('0.01 * credit_limit')['37signals']
+ end
+
def test_should_group_by_summed_field_with_conditions
c = Account.where('firm_id > 1').group(:firm_id).sum(:credit_limit)
assert_nil c[1]
@@ -341,16 +355,6 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal 5, Account.count(:firm_id)
end
- def test_count_distinct_option_is_deprecated
- assert_deprecated do
- assert_equal 4, Account.select(:credit_limit).count(distinct: true)
- end
-
- assert_deprecated do
- assert_equal 6, Account.select(:credit_limit).count(distinct: false)
- end
- end
-
def test_count_with_distinct
assert_equal 4, Account.select(:credit_limit).distinct.count
assert_equal 4, Account.select(:credit_limit).uniq.count
@@ -410,12 +414,6 @@ class CalculationsTest < ActiveRecord::TestCase
Account.where("credit_limit > 50").from('accounts').sum(:credit_limit)
end
- def test_sum_array_compatibility_deprecation
- assert_deprecated do
- assert_equal Account.sum(:credit_limit), Account.sum(&:credit_limit)
- end
- end
-
def test_average_with_from_option
assert_equal Account.average(:credit_limit), Account.from('accounts').average(:credit_limit)
assert_equal Account.where("credit_limit > 50").average(:credit_limit),
@@ -478,6 +476,11 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal [1,2,3,4], Topic.order(:id).pluck(:id)
end
+ def test_pluck_without_column_names
+ assert_equal [[1, "Firm", 1, nil, "37signals", nil, 1, nil, ""]],
+ Company.order(:id).limit(1).pluck
+ end
+
def test_pluck_type_cast
topic = topics(:first)
relation = Topic.where(:id => topic.id)
@@ -539,6 +542,11 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal Company.all.map(&:id).sort, Company.ids.sort
end
+ def test_pluck_with_includes_limit_and_empty_result
+ assert_equal [], Topic.includes(:replies).limit(0).pluck(:id)
+ assert_equal [], Topic.includes(:replies).limit(1).where('0 = 1').pluck(:id)
+ end
+
def test_pluck_not_auto_table_name_prefix_if_column_included
Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)])
ids = Company.includes(:contracts).pluck(:developer_id)
diff --git a/activerecord/test/cases/column_test.rb b/activerecord/test/cases/column_test.rb
index 3a4f414ae8..2a6d8cc2ab 100644
--- a/activerecord/test/cases/column_test.rb
+++ b/activerecord/test/cases/column_test.rb
@@ -110,6 +110,14 @@ module ActiveRecord
assert_equal 1800, column.type_cast(30.minutes)
assert_equal 7200, column.type_cast(2.hours)
end
+
+ def test_string_to_time_with_timezone
+ [:utc, :local].each do |zone|
+ with_timezone_config default: zone do
+ assert_equal Time.utc(2013, 9, 4, 0, 0, 0), Column.string_to_time("Wed, 04 Sep 2013 03:00:00 EAT")
+ end
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
index 3e33b30144..318cc5a32c 100644
--- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb
+++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
@@ -2,6 +2,133 @@ require "cases/helper"
module ActiveRecord
module ConnectionAdapters
+
+ class MergeAndResolveDefaultUrlConfigTest < ActiveRecord::TestCase
+
+ def klass
+ ActiveRecord::ConnectionHandling::MergeAndResolveDefaultUrlConfig
+ end
+
+ def setup
+ @previous_database_url = ENV.delete("DATABASE_URL")
+ end
+
+ def teardown
+ ENV["DATABASE_URL"] = @previous_database_url
+ end
+
+ def test_string_connection
+ config = { "production" => "postgres://localhost/foo" }
+ actual = klass.new(config).resolve
+ expected = { "production" =>
+ { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost"
+ }
+ }
+ assert_equal expected, actual
+ end
+
+ def test_url_sub_key
+ config = { "production" => { "url" => "postgres://localhost/foo" } }
+ actual = klass.new(config).resolve
+ expected = { "production" =>
+ { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost"
+ }
+ }
+ assert_equal expected, actual
+ end
+
+ def test_hash
+ config = { "production" => { "adapter" => "postgres", "database" => "foo" } }
+ actual = klass.new(config).resolve
+ assert_equal config, actual
+ end
+
+ def test_blank
+ config = {}
+ actual = klass.new(config).resolve
+ assert_equal config, actual
+ end
+
+ def test_blank_with_database_url
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+
+ config = {}
+ actual = klass.new(config).resolve
+ expected = { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost" }
+ assert_equal expected, actual["production"]
+ assert_equal expected, actual["development"]
+ assert_equal expected, actual["test"]
+ assert_equal nil, actual[:production]
+ assert_equal nil, actual[:development]
+ assert_equal nil, actual[:test]
+ end
+
+ def test_sting_with_database_url
+ ENV['DATABASE_URL'] = "NOT-POSTGRES://localhost/NOT_FOO"
+
+ config = { "production" => "postgres://localhost/foo" }
+ actual = klass.new(config).resolve
+
+ expected = { "production" =>
+ { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost"
+ }
+ }
+ assert_equal expected, actual
+ end
+
+ def test_url_sub_key_with_database_url
+ ENV['DATABASE_URL'] = "NOT-POSTGRES://localhost/NOT_FOO"
+
+ config = { "production" => { "url" => "postgres://localhost/foo" } }
+ actual = klass.new(config).resolve
+ expected = { "production" =>
+ { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost"
+ }
+ }
+ assert_equal expected, actual
+ end
+
+ def test_merge_no_conflicts_with_database_url
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+
+ config = {"production" => { "pool" => "5" } }
+ actual = klass.new(config).resolve
+ expected = { "production" =>
+ { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost",
+ "pool" => "5"
+ }
+ }
+ assert_equal expected, actual
+ end
+
+ def test_merge_conflicts_with_database_url
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+
+ config = {"production" => { "adapter" => "NOT-POSTGRES", "database" => "NOT-FOO", "pool" => "5" } }
+ actual = klass.new(config).resolve
+ expected = { "production" =>
+ { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost",
+ "pool" => "5"
+ }
+ }
+ assert_equal expected, actual
+ end
+ end
+
class ConnectionHandlerTest < ActiveRecord::TestCase
def setup
@klass = Class.new(Base) { def self.name; 'klass'; end }
diff --git a/activerecord/test/cases/connection_management_test.rb b/activerecord/test/cases/connection_management_test.rb
index fe1b40d884..00667cc52e 100644
--- a/activerecord/test/cases/connection_management_test.rb
+++ b/activerecord/test/cases/connection_management_test.rb
@@ -26,25 +26,25 @@ module ActiveRecord
assert ActiveRecord::Base.connection_handler.active_connections?
end
- def test_connection_pool_per_pid
- return skip('must support fork') unless Process.respond_to?(:fork)
+ if Process.respond_to?(:fork)
+ def test_connection_pool_per_pid
+ object_id = ActiveRecord::Base.connection.object_id
- object_id = ActiveRecord::Base.connection.object_id
+ rd, wr = IO.pipe
- rd, wr = IO.pipe
+ pid = fork {
+ rd.close
+ wr.write Marshal.dump ActiveRecord::Base.connection.object_id
+ wr.close
+ exit!
+ }
- pid = fork {
- rd.close
- wr.write Marshal.dump ActiveRecord::Base.connection.object_id
wr.close
- exit!
- }
-
- wr.close
- Process.waitpid pid
- assert_not_equal object_id, Marshal.load(rd.read)
- rd.close
+ Process.waitpid pid
+ assert_not_equal object_id, Marshal.load(rd.read)
+ rd.close
+ end
end
def test_app_delegation
@@ -80,9 +80,9 @@ module ActiveRecord
end
def test_connections_closed_if_exception
- app = Class.new(App) { def call(env); raise; end }.new
+ app = Class.new(App) { def call(env); raise NotImplementedError; end }.new
explosive = ConnectionManagement.new(app)
- assert_raises(RuntimeError) { explosive.call(@env) }
+ assert_raises(NotImplementedError) { explosive.call(@env) }
assert !ActiveRecord::Base.connection_handler.active_connections?
end
diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb
index e6af29282c..2da51ea015 100644
--- a/activerecord/test/cases/connection_pool_test.rb
+++ b/activerecord/test/cases/connection_pool_test.rb
@@ -118,6 +118,7 @@ module ActiveRecord
connection = cs.first
@pool.remove connection
assert_respond_to t.join.value, :execute
+ connection.close
end
def test_reap_and_active
@@ -329,7 +330,7 @@ module ActiveRecord
end
# make sure exceptions are thrown when establish_connection
- # is called with a anonymous class
+ # is called with an anonymous class
def test_anonymous_class_exception
anonymous = Class.new(ActiveRecord::Base)
handler = ActiveRecord::Base.connection_handler
diff --git a/activerecord/test/cases/connection_specification/resolver_test.rb b/activerecord/test/cases/connection_specification/resolver_test.rb
index c8dfc3244b..fdd1914cba 100644
--- a/activerecord/test/cases/connection_specification/resolver_test.rb
+++ b/activerecord/test/cases/connection_specification/resolver_test.rb
@@ -4,58 +4,92 @@ module ActiveRecord
module ConnectionAdapters
class ConnectionSpecification
class ResolverTest < ActiveRecord::TestCase
- def resolve(spec)
- Resolver.new(spec, {}).spec.config
+ def resolve(spec, config={})
+ Resolver.new(config).resolve(spec)
+ end
+
+ def spec(spec, config={})
+ Resolver.new(config).spec(spec)
end
def test_url_invalid_adapter
- assert_raises(LoadError) do
- resolve 'ridiculous://foo?encoding=utf8'
+ error = assert_raises(LoadError) do
+ spec 'ridiculous://foo?encoding=utf8'
end
+
+ assert_match "Could not load 'active_record/connection_adapters/ridiculous_adapter'", error.message
end
# The abstract adapter is used simply to bypass the bit of code that
# checks that the adapter file can be required in.
+ def test_url_from_environment
+ spec = resolve :production, 'production' => 'abstract://foo?encoding=utf8'
+ assert_equal({
+ "adapter" => "abstract",
+ "host" => "foo",
+ "encoding" => "utf8" }, spec)
+ end
+
+ def test_url_sub_key
+ spec = resolve :production, 'production' => {"url" => 'abstract://foo?encoding=utf8'}
+ assert_equal({
+ "adapter" => "abstract",
+ "host" => "foo",
+ "encoding" => "utf8" }, spec)
+ end
+
+ def test_url_sub_key_merges_correctly
+ hash = {"url" => 'abstract://foo?encoding=utf8&', "adapter" => "sqlite3", "host" => "bar", "pool" => "3"}
+ spec = resolve :production, 'production' => hash
+ assert_equal({
+ "adapter" => "abstract",
+ "host" => "foo",
+ "encoding" => "utf8",
+ "pool" => "3" }, spec)
+ end
+
def test_url_host_no_db
spec = resolve 'abstract://foo?encoding=utf8'
assert_equal({
- adapter: "abstract",
- host: "foo",
- encoding: "utf8" }, spec)
+ "adapter" => "abstract",
+ "host" => "foo",
+ "encoding" => "utf8" }, spec)
end
def test_url_host_db
spec = resolve 'abstract://foo/bar?encoding=utf8'
assert_equal({
- adapter: "abstract",
- database: "bar",
- host: "foo",
- encoding: "utf8" }, spec)
+ "adapter" => "abstract",
+ "database" => "bar",
+ "host" => "foo",
+ "encoding" => "utf8" }, spec)
end
def test_url_port
spec = resolve 'abstract://foo:123?encoding=utf8'
assert_equal({
- adapter: "abstract",
- port: 123,
- host: "foo",
- encoding: "utf8" }, spec)
+ "adapter" => "abstract",
+ "port" => 123,
+ "host" => "foo",
+ "encoding" => "utf8" }, spec)
end
def test_encoded_password
password = 'am@z1ng_p@ssw0rd#!'
encoded_password = URI.encode_www_form_component(password)
spec = resolve "abstract://foo:#{encoded_password}@localhost/bar"
- assert_equal password, spec[:password]
+ assert_equal password, spec["password"]
end
- def test_descriptive_error_message_when_adapter_is_missing
- error = assert_raise(LoadError) do
- resolve(adapter: 'non-existing')
- end
+ def test_url_host_db_for_sqlite3
+ spec = resolve 'sqlite3://foo:bar@dburl:9000/foo_test'
+ assert_equal('/foo_test', spec["database"])
+ end
- assert_match "Could not load 'active_record/connection_adapters/non-existing_adapter'", error.message
+ def test_url_host_memory_db_for_sqlite3
+ spec = resolve 'sqlite3://foo:bar@dburl:9000/:memory:'
+ assert_equal(':memory:', spec["database"])
end
end
end
diff --git a/activerecord/test/cases/core_test.rb b/activerecord/test/cases/core_test.rb
new file mode 100644
index 0000000000..2a52bf574c
--- /dev/null
+++ b/activerecord/test/cases/core_test.rb
@@ -0,0 +1,33 @@
+require 'cases/helper'
+require 'models/person'
+require 'models/topic'
+
+class NonExistentTable < ActiveRecord::Base; end
+
+class CoreTest < ActiveRecord::TestCase
+ fixtures :topics
+
+ def test_inspect_class
+ assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect
+ assert_equal 'LoosePerson(abstract)', LoosePerson.inspect
+ assert_match(/^Topic\(id: integer, title: string/, Topic.inspect)
+ end
+
+ def test_inspect_instance
+ topic = topics(:first)
+ assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", important: nil, approved: false, replies_count: 1, unique_replies_count: 0, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect
+ end
+
+ def test_inspect_new_instance
+ assert_match(/Topic id: nil/, Topic.new.inspect)
+ end
+
+ def test_inspect_limited_select_instance
+ assert_equal %(#<Topic id: 1>), Topic.all.merge!(:select => 'id', :where => 'id = 1').first.inspect
+ assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.all.merge!(:select => 'id, title', :where => 'id = 1').first.inspect
+ end
+
+ def test_inspect_class_without_table
+ assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect
+ end
+end
diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb
index 61f9d4cdae..ee3d8a81c2 100644
--- a/activerecord/test/cases/counter_cache_test.rb
+++ b/activerecord/test/cases/counter_cache_test.rb
@@ -51,14 +51,9 @@ class CounterCacheTest < ActiveRecord::TestCase
end
end
- test 'reset multiple association counters' do
- Topic.increment_counter(:replies_count, @topic.id)
- assert_difference '@topic.reload.replies_count', -1 do
- Topic.reset_counters(@topic.id, :replies, :unique_replies)
- end
-
- Topic.increment_counter(:unique_replies_count, @topic.id)
- assert_difference '@topic.reload.unique_replies_count', -1 do
+ test 'reset multiple counters' do
+ Topic.update_counters @topic.id, replies_count: 1, unique_replies_count: 1
+ assert_difference ['@topic.reload.replies_count', '@topic.reload.unique_replies_count'], -1 do
Topic.reset_counters(@topic.id, :replies, :unique_replies)
end
end
@@ -127,6 +122,12 @@ class CounterCacheTest < ActiveRecord::TestCase
end
end
+ test 'update multiple counters' do
+ assert_difference ['@topic.reload.replies_count', '@topic.reload.unique_replies_count'], 2 do
+ Topic.update_counters @topic.id, replies_count: 2, unique_replies_count: 2
+ end
+ end
+
test "update other counters on parent destroy" do
david, joanna = dog_lovers(:david, :joanna)
joanna = joanna # squelch a warning
diff --git a/activerecord/test/cases/date_time_test.rb b/activerecord/test/cases/date_time_test.rb
index 427076bd80..c0491bbee5 100644
--- a/activerecord/test/cases/date_time_test.rb
+++ b/activerecord/test/cases/date_time_test.rb
@@ -5,7 +5,7 @@ require 'models/task'
class DateTimeTest < ActiveRecord::TestCase
def test_saves_both_date_and_time
with_env_tz 'America/New_York' do
- with_active_record_default_timezone :utc do
+ with_timezone_config default: :utc do
time_values = [1807, 2, 10, 15, 30, 45]
# create DateTime value with local time zone offset
local_offset = Rational(Time.local(*time_values).utc_offset, 86400)
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index e0cf4adf13..7e3d91e08c 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -39,6 +39,31 @@ class DefaultTest < ActiveRecord::TestCase
end
end
+class DefaultStringsTest < ActiveRecord::TestCase
+ class DefaultString < ActiveRecord::Base; end
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table :default_strings do |t|
+ t.string :string_col, default: "Smith"
+ t.string :string_col_with_quotes, default: "O'Connor"
+ end
+ DefaultString.reset_column_information
+ end
+
+ def test_default_strings
+ assert_equal "Smith", DefaultString.new.string_col
+ end
+
+ def test_default_strings_containing_single_quotes
+ assert_equal "O'Connor", DefaultString.new.string_col_with_quotes
+ end
+
+ teardown do
+ @connection.drop_table :default_strings
+ end
+end
+
if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
class DefaultsTestWithoutTransactionalFixtures < ActiveRecord::TestCase
# ActiveRecord::Base#create! (and #save and other related methods) will
diff --git a/activerecord/test/cases/deprecated_dynamic_methods_test.rb b/activerecord/test/cases/deprecated_dynamic_methods_test.rb
deleted file mode 100644
index 8e842d8758..0000000000
--- a/activerecord/test/cases/deprecated_dynamic_methods_test.rb
+++ /dev/null
@@ -1,592 +0,0 @@
-# This file should be deleted when activerecord-deprecated_finders is removed as
-# a dependency.
-#
-# It is kept for now as there is some fairly nuanced behavior in the dynamic
-# finders so it is useful to keep this around to guard against regressions if
-# we need to change the code.
-
-require 'cases/helper'
-require 'models/topic'
-require 'models/reply'
-require 'models/customer'
-require 'models/post'
-require 'models/company'
-require 'models/author'
-require 'models/category'
-require 'models/comment'
-require 'models/person'
-require 'models/reader'
-
-class DeprecatedDynamicMethodsTest < ActiveRecord::TestCase
- fixtures :topics, :customers, :companies, :accounts, :posts, :categories, :categories_posts, :authors, :people, :comments, :readers
-
- def setup
- @deprecation_behavior = ActiveSupport::Deprecation.behavior
- ActiveSupport::Deprecation.behavior = :silence
- end
-
- def teardown
- ActiveSupport::Deprecation.behavior = @deprecation_behavior
- end
-
- def test_find_all_by_one_attribute
- topics = Topic.find_all_by_content("Have a nice day")
- assert_equal 2, topics.size
- assert topics.include?(topics(:first))
-
- assert_equal [], Topic.find_all_by_title("The First Topic!!")
- end
-
- def test_find_all_by_one_attribute_which_is_a_symbol
- topics = Topic.find_all_by_content("Have a nice day".to_sym)
- assert_equal 2, topics.size
- assert topics.include?(topics(:first))
-
- assert_equal [], Topic.find_all_by_title("The First Topic!!")
- end
-
- def test_find_all_by_one_attribute_that_is_an_aggregate
- balance = customers(:david).balance
- assert_kind_of Money, balance
- found_customers = Customer.find_all_by_balance(balance)
- assert_equal 1, found_customers.size
- assert_equal customers(:david), found_customers.first
- end
-
- def test_find_all_by_two_attributes_that_are_both_aggregates
- balance = customers(:david).balance
- address = customers(:david).address
- assert_kind_of Money, balance
- assert_kind_of Address, address
- found_customers = Customer.find_all_by_balance_and_address(balance, address)
- assert_equal 1, found_customers.size
- assert_equal customers(:david), found_customers.first
- end
-
- def test_find_all_by_two_attributes_with_one_being_an_aggregate
- balance = customers(:david).balance
- assert_kind_of Money, balance
- found_customers = Customer.find_all_by_balance_and_name(balance, customers(:david).name)
- assert_equal 1, found_customers.size
- assert_equal customers(:david), found_customers.first
- end
-
- def test_find_all_by_one_attribute_with_options
- topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC")
- assert_equal topics(:first), topics.last
-
- topics = Topic.find_all_by_content("Have a nice day", :order => "id")
- assert_equal topics(:first), topics.first
- end
-
- def test_find_all_by_array_attribute
- assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic of the day"]).size
- end
-
- def test_find_all_by_boolean_attribute
- topics = Topic.find_all_by_approved(false)
- assert_equal 1, topics.size
- assert topics.include?(topics(:first))
-
- topics = Topic.find_all_by_approved(true)
- assert_equal 3, topics.size
- assert topics.include?(topics(:second))
- end
-
- def test_find_all_by_nil_and_not_nil_attributes
- topics = Topic.find_all_by_last_read_and_author_name nil, "Mary"
- assert_equal 1, topics.size
- assert_equal "Mary", topics[0].author_name
- end
-
- def test_find_or_create_from_one_attribute
- number_of_companies = Company.count
- sig38 = Company.find_or_create_by_name("38signals")
- assert_equal number_of_companies + 1, Company.count
- assert_equal sig38, Company.find_or_create_by_name("38signals")
- assert sig38.persisted?
- end
-
- def test_find_or_create_from_two_attributes
- number_of_topics = Topic.count
- another = Topic.find_or_create_by_title_and_author_name("Another topic","John")
- assert_equal number_of_topics + 1, Topic.count
- assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John")
- assert another.persisted?
- end
-
- def test_find_or_create_from_one_attribute_bang
- number_of_companies = Company.count
- assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name!("") }
- assert_equal number_of_companies, Company.count
- sig38 = Company.find_or_create_by_name!("38signals")
- assert_equal number_of_companies + 1, Company.count
- assert_equal sig38, Company.find_or_create_by_name!("38signals")
- assert sig38.persisted?
- end
-
- def test_find_or_create_from_two_attributes_bang
- number_of_companies = Company.count
- assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name_and_firm_id!("", 17) }
- assert_equal number_of_companies, Company.count
- sig38 = Company.find_or_create_by_name_and_firm_id!("38signals", 17)
- assert_equal number_of_companies + 1, Company.count
- assert_equal sig38, Company.find_or_create_by_name_and_firm_id!("38signals", 17)
- assert sig38.persisted?
- assert_equal "38signals", sig38.name
- assert_equal 17, sig38.firm_id
- end
-
- def test_find_or_create_from_two_attributes_with_one_being_an_aggregate
- number_of_customers = Customer.count
- created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth")
- assert_equal number_of_customers + 1, Customer.count
- assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth")
- assert created_customer.persisted?
- end
-
- def test_find_or_create_from_one_attribute_and_hash
- number_of_companies = Company.count
- sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
- assert_equal number_of_companies + 1, Company.count
- assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
- assert sig38.persisted?
- assert_equal "38signals", sig38.name
- assert_equal 17, sig38.firm_id
- assert_equal 23, sig38.client_of
- end
-
- def test_find_or_create_from_two_attributes_and_hash
- number_of_companies = Company.count
- sig38 = Company.find_or_create_by_name_and_firm_id({:name => "38signals", :firm_id => 17, :client_of => 23})
- assert_equal number_of_companies + 1, Company.count
- assert_equal sig38, Company.find_or_create_by_name_and_firm_id({:name => "38signals", :firm_id => 17, :client_of => 23})
- assert sig38.persisted?
- assert_equal "38signals", sig38.name
- assert_equal 17, sig38.firm_id
- assert_equal 23, sig38.client_of
- end
-
- def test_find_or_create_from_one_aggregate_attribute
- number_of_customers = Customer.count
- created_customer = Customer.find_or_create_by_balance(Money.new(123))
- assert_equal number_of_customers + 1, Customer.count
- assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123))
- assert created_customer.persisted?
- end
-
- def test_find_or_create_from_one_aggregate_attribute_and_hash
- number_of_customers = Customer.count
- balance = Money.new(123)
- name = "Elizabeth"
- created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name})
- assert_equal number_of_customers + 1, Customer.count
- assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name})
- assert created_customer.persisted?
- assert_equal balance, created_customer.balance
- assert_equal name, created_customer.name
- end
-
- def test_find_or_initialize_from_one_attribute
- sig38 = Company.find_or_initialize_by_name("38signals")
- assert_equal "38signals", sig38.name
- assert !sig38.persisted?
- end
-
- def test_find_or_initialize_from_one_aggregate_attribute
- new_customer = Customer.find_or_initialize_by_balance(Money.new(123))
- assert_equal 123, new_customer.balance.amount
- assert !new_customer.persisted?
- end
-
- def test_find_or_initialize_from_one_attribute_should_set_attribute
- c = Company.find_or_initialize_by_name_and_rating("Fortune 1000", 1000)
- assert_equal "Fortune 1000", c.name
- assert_equal 1000, c.rating
- assert c.valid?
- assert !c.persisted?
- end
-
- def test_find_or_create_from_one_attribute_should_set_attribute
- c = Company.find_or_create_by_name_and_rating("Fortune 1000", 1000)
- assert_equal "Fortune 1000", c.name
- assert_equal 1000, c.rating
- assert c.valid?
- assert c.persisted?
- end
-
- def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_set_the_hash
- c = Company.find_or_initialize_by_rating(1000, {:name => "Fortune 1000"})
- assert_equal "Fortune 1000", c.name
- assert_equal 1000, c.rating
- assert c.valid?
- assert !c.persisted?
- end
-
- def test_find_or_create_from_one_attribute_should_set_attribute_even_when_set_the_hash
- c = Company.find_or_create_by_rating(1000, {:name => "Fortune 1000"})
- assert_equal "Fortune 1000", c.name
- assert_equal 1000, c.rating
- assert c.valid?
- assert c.persisted?
- end
-
- def test_find_or_initialize_should_set_attributes_if_given_as_block
- c = Company.find_or_initialize_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
- assert_equal "Fortune 1000", c.name
- assert_equal 1000.to_f, c.rating.to_f
- assert c.valid?
- assert !c.persisted?
- end
-
- def test_find_or_create_should_set_attributes_if_given_as_block
- c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
- assert_equal "Fortune 1000", c.name
- assert_equal 1000.to_f, c.rating.to_f
- assert c.valid?
- assert c.persisted?
- end
-
- def test_find_or_create_should_work_with_block_on_first_call
- class << Company
- undef_method(:find_or_create_by_name) if method_defined?(:find_or_create_by_name)
- end
- c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
- assert_equal "Fortune 1000", c.name
- assert_equal 1000.to_f, c.rating.to_f
- assert c.valid?
- assert c.persisted?
- end
-
- def test_find_or_initialize_from_two_attributes
- another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John")
- assert_equal "Another topic", another.title
- assert_equal "John", another.author_name
- assert !another.persisted?
- end
-
- def test_find_or_initialize_from_two_attributes_but_passing_only_one
- assert_raise(ArgumentError) { Topic.find_or_initialize_by_title_and_author_name("Another topic") }
- end
-
- def test_find_or_initialize_from_one_aggregate_attribute_and_one_not
- new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth")
- assert_equal 123, new_customer.balance.amount
- assert_equal "Elizabeth", new_customer.name
- assert !new_customer.persisted?
- end
-
- def test_find_or_initialize_from_one_attribute_and_hash
- sig38 = Company.find_or_initialize_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
- assert_equal "38signals", sig38.name
- assert_equal 17, sig38.firm_id
- assert_equal 23, sig38.client_of
- assert !sig38.persisted?
- end
-
- def test_find_or_initialize_from_one_aggregate_attribute_and_hash
- balance = Money.new(123)
- name = "Elizabeth"
- new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name})
- assert_equal balance, new_customer.balance
- assert_equal name, new_customer.name
- assert !new_customer.persisted?
- end
-
- def test_find_last_by_one_attribute
- assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title)
- assert_nil Topic.find_last_by_title("A title with no matches")
- end
-
- def test_find_last_by_invalid_method_syntax
- assert_raise(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") }
- assert_raise(NoMethodError) { Topic.find_last_by_title?("The First Topic") }
- end
-
- def test_find_last_by_one_attribute_with_several_options
- assert_equal accounts(:signals37), Account.order('id DESC').where('id != ?', 3).find_last_by_credit_limit(50)
- end
-
- def test_find_last_by_one_missing_attribute
- assert_raise(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") }
- end
-
- def test_find_last_by_two_attributes
- topic = Topic.last
- assert_equal topic, Topic.find_last_by_title_and_author_name(topic.title, topic.author_name)
- assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous")
- end
-
- def test_find_last_with_limit_gives_same_result_when_loaded_and_unloaded
- scope = Topic.limit(2)
- unloaded_last = scope.last
- loaded_last = scope.to_a.last
- assert_equal loaded_last, unloaded_last
- end
-
- def test_find_last_with_limit_and_offset_gives_same_result_when_loaded_and_unloaded
- scope = Topic.offset(2).limit(2)
- unloaded_last = scope.last
- loaded_last = scope.to_a.last
- assert_equal loaded_last, unloaded_last
- end
-
- def test_find_last_with_offset_gives_same_result_when_loaded_and_unloaded
- scope = Topic.offset(3)
- unloaded_last = scope.last
- loaded_last = scope.to_a.last
- assert_equal loaded_last, unloaded_last
- end
-
- def test_find_all_by_nil_attribute
- topics = Topic.find_all_by_last_read nil
- assert_equal 3, topics.size
- assert topics.collect(&:last_read).all?(&:nil?)
- end
-
- def test_forwarding_to_dynamic_finders
- welcome = Post.find(1)
- assert_equal 4, Category.find_all_by_type('SpecialCategory').size
- assert_equal 0, welcome.categories.find_all_by_type('SpecialCategory').size
- assert_equal 2, welcome.categories.find_all_by_type('Category').size
- end
-
- def test_dynamic_find_all_should_respect_association_order
- assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.where("type = 'Client'").to_a
- assert_equal [companies(:second_client), companies(:first_client)], companies(:first_firm).clients_sorted_desc.find_all_by_type('Client')
- end
-
- def test_dynamic_find_all_should_respect_association_limit
- assert_equal 1, companies(:first_firm).limited_clients.where("type = 'Client'").to_a.length
- assert_equal 1, companies(:first_firm).limited_clients.find_all_by_type('Client').length
- end
-
- def test_dynamic_find_all_limit_should_override_association_limit
- assert_equal 2, companies(:first_firm).limited_clients.where("type = 'Client'").limit(9_000).to_a.length
- assert_equal 2, companies(:first_firm).limited_clients.find_all_by_type('Client', :limit => 9_000).length
- end
-
- def test_dynamic_find_last_without_specified_order
- assert_equal companies(:second_client), companies(:first_firm).unsorted_clients.find_last_by_type('Client')
- end
-
- def test_dynamic_find_or_create_from_two_attributes_using_an_association
- author = authors(:david)
- number_of_posts = Post.count
- another = author.posts.find_or_create_by_title_and_body("Another Post", "This is the Body")
- assert_equal number_of_posts + 1, Post.count
- assert_equal another, author.posts.find_or_create_by_title_and_body("Another Post", "This is the Body")
- assert another.persisted?
- end
-
- def test_dynamic_find_all_should_respect_association_order_for_through
- assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.where("comments.type = 'SpecialComment'").to_a
- assert_equal [Comment.find(10), Comment.find(7), Comment.find(6), Comment.find(3)], authors(:david).comments_desc.find_all_by_type('SpecialComment')
- end
-
- def test_dynamic_find_all_should_respect_association_limit_for_through
- assert_equal 1, authors(:david).limited_comments.where("comments.type = 'SpecialComment'").to_a.length
- assert_equal 1, authors(:david).limited_comments.find_all_by_type('SpecialComment').length
- end
-
- def test_dynamic_find_all_order_should_override_association_limit_for_through
- assert_equal 4, authors(:david).limited_comments.where("comments.type = 'SpecialComment'").limit(9_000).to_a.length
- assert_equal 4, authors(:david).limited_comments.find_all_by_type('SpecialComment', :limit => 9_000).length
- end
-
- def test_find_all_include_over_the_same_table_for_through
- assert_equal 2, people(:michael).posts.includes(:people).to_a.length
- end
-
- def test_find_or_create_by_resets_cached_counters
- person = Person.create! :first_name => 'tenderlove'
- post = Post.first
-
- assert_equal [], person.readers
- assert_nil person.readers.find_by_post_id(post.id)
-
- person.readers.find_or_create_by_post_id(post.id)
-
- assert_equal 1, person.readers.count
- assert_equal 1, person.readers.length
- assert_equal post, person.readers.first.post
- assert_equal person, person.readers.first.person
- end
-
- def test_find_or_initialize
- the_client = companies(:first_firm).clients.find_or_initialize_by_name("Yet another client")
- assert_equal companies(:first_firm).id, the_client.firm_id
- assert_equal "Yet another client", the_client.name
- assert !the_client.persisted?
- end
-
- def test_find_or_create_updates_size
- number_of_clients = companies(:first_firm).clients.size
- the_client = companies(:first_firm).clients.find_or_create_by_name("Yet another client")
- assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
- assert_equal the_client, companies(:first_firm).clients.find_or_create_by_name("Yet another client")
- assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
- end
-
- def test_find_or_initialize_updates_collection_size
- number_of_clients = companies(:first_firm).clients_of_firm.size
- companies(:first_firm).clients_of_firm.find_or_initialize_by_name("name" => "Another Client")
- assert_equal number_of_clients + 1, companies(:first_firm).clients_of_firm.size
- end
-
- def test_find_or_initialize_returns_the_instantiated_object
- client = companies(:first_firm).clients_of_firm.find_or_initialize_by_name("name" => "Another Client")
- assert_equal client, companies(:first_firm).clients_of_firm[-1]
- end
-
- def test_find_or_initialize_only_instantiates_a_single_object
- number_of_clients = Client.count
- companies(:first_firm).clients_of_firm.find_or_initialize_by_name("name" => "Another Client").save!
- companies(:first_firm).save!
- assert_equal number_of_clients+1, Client.count
- end
-
- def test_find_or_create_with_hash
- post = authors(:david).posts.find_or_create_by_title(:title => 'Yet another post', :body => 'somebody')
- assert_equal post, authors(:david).posts.find_or_create_by_title(:title => 'Yet another post', :body => 'somebody')
- assert post.persisted?
- end
-
- def test_find_or_create_with_one_attribute_followed_by_hash
- post = authors(:david).posts.find_or_create_by_title('Yet another post', :body => 'somebody')
- assert_equal post, authors(:david).posts.find_or_create_by_title('Yet another post', :body => 'somebody')
- assert post.persisted?
- end
-
- def test_find_or_create_should_work_with_block
- post = authors(:david).posts.find_or_create_by_title('Yet another post') {|p| p.body = 'somebody'}
- assert_equal post, authors(:david).posts.find_or_create_by_title('Yet another post') {|p| p.body = 'somebody'}
- assert post.persisted?
- end
-
- def test_forwarding_to_dynamic_finders_2
- welcome = Post.find(1)
- assert_equal 4, Comment.find_all_by_type('Comment').size
- assert_equal 2, welcome.comments.find_all_by_type('Comment').size
- end
-
- def test_dynamic_find_all_by_attributes
- authors = Author.all
-
- davids = authors.find_all_by_name('David')
- assert_kind_of Array, davids
- assert_equal [authors(:david)], davids
- end
-
- def test_dynamic_find_or_initialize_by_attributes
- authors = Author.all
-
- lifo = authors.find_or_initialize_by_name('Lifo')
- assert_equal "Lifo", lifo.name
- assert !lifo.persisted?
-
- assert_equal authors(:david), authors.find_or_initialize_by_name(:name => 'David')
- end
-
- def test_dynamic_find_or_create_by_attributes
- authors = Author.all
-
- lifo = authors.find_or_create_by_name('Lifo')
- assert_equal "Lifo", lifo.name
- assert lifo.persisted?
-
- assert_equal authors(:david), authors.find_or_create_by_name(:name => 'David')
- end
-
- def test_dynamic_find_or_create_by_attributes_bang
- authors = Author.all
-
- assert_raises(ActiveRecord::RecordInvalid) { authors.find_or_create_by_name!('') }
-
- lifo = authors.find_or_create_by_name!('Lifo')
- assert_equal "Lifo", lifo.name
- assert lifo.persisted?
-
- assert_equal authors(:david), authors.find_or_create_by_name!(:name => 'David')
- end
-
- def test_finder_block
- t = Topic.first
- found = nil
- Topic.find_by_id(t.id) { |f| found = f }
- assert_equal t, found
- end
-
- def test_finder_block_nothing_found
- bad_id = Topic.maximum(:id) + 1
- assert_nil Topic.find_by_id(bad_id) { |f| raise }
- end
-
- def test_find_returns_block_value
- t = Topic.first
- x = Topic.find_by_id(t.id) { |f| "hi mom!" }
- assert_equal "hi mom!", x
- end
-
- def test_dynamic_finder_with_invalid_params
- assert_raise(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" }
- end
-
- def test_find_by_one_attribute_with_order_option
- assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id')
- assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC')
- end
-
- def test_dynamic_find_by_attributes_should_yield_found_object
- david = authors(:david)
- yielded_value = nil
- Author.find_by_name(david.name) do |author|
- yielded_value = author
- end
- assert_equal david, yielded_value
- end
-end
-
-class DynamicScopeTest < ActiveRecord::TestCase
- fixtures :posts
-
- def setup
- @test_klass = Class.new(Post) do
- def self.name; "Post"; end
- end
- @deprecation_behavior = ActiveSupport::Deprecation.behavior
- ActiveSupport::Deprecation.behavior = :silence
- end
-
- def teardown
- ActiveSupport::Deprecation.behavior = @deprecation_behavior
- end
-
- def test_dynamic_scope
- assert_equal @test_klass.scoped_by_author_id(1).find(1), @test_klass.find(1)
- assert_equal @test_klass.scoped_by_author_id_and_title(1, "Welcome to the weblog").first, @test_klass.all.merge!(:where => { :author_id => 1, :title => "Welcome to the weblog"}).first
- end
-
- def test_dynamic_scope_should_create_methods_after_hitting_method_missing
- assert @test_klass.methods.grep(/scoped_by_type/).blank?
- @test_klass.scoped_by_type(nil)
- assert @test_klass.methods.grep(/scoped_by_type/).present?
- end
-
- def test_dynamic_scope_with_less_number_of_arguments
- assert_raise(ArgumentError){ @test_klass.scoped_by_author_id_and_title(1) }
- end
-end
-
-class DynamicScopeMatchTest < ActiveRecord::TestCase
- def test_scoped_by_no_match
- assert_nil ActiveRecord::DynamicMatchers::Method.match(nil, "not_scoped_at_all")
- end
-
- def test_scoped_by
- model = stub(attribute_aliases: {})
- match = ActiveRecord::DynamicMatchers::Method.match(model, "scoped_by_age_and_sex_and_location")
- assert_not_nil match
- assert_equal %w(age sex location), match.attribute_names
- end
-end
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 36b87033ae..df4183c065 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -125,30 +125,30 @@ class DirtyTest < ActiveRecord::TestCase
end
def test_time_attributes_changes_without_time_zone
- target = Class.new(ActiveRecord::Base)
- target.table_name = 'pirates'
-
- target.time_zone_aware_attributes = false
+ with_timezone_config aware_attributes: false do
+ target = Class.new(ActiveRecord::Base)
+ target.table_name = 'pirates'
- # New record - no changes.
- pirate = target.new
- assert !pirate.created_on_changed?
- assert_nil pirate.created_on_change
+ # New record - no changes.
+ pirate = target.new
+ assert !pirate.created_on_changed?
+ assert_nil pirate.created_on_change
- # Saved - no changes.
- pirate.catchphrase = 'arrrr, time zone!!'
- pirate.save!
- assert !pirate.created_on_changed?
- assert_nil pirate.created_on_change
+ # Saved - no changes.
+ pirate.catchphrase = 'arrrr, time zone!!'
+ pirate.save!
+ assert !pirate.created_on_changed?
+ assert_nil pirate.created_on_change
- # Change created_on.
- old_created_on = pirate.created_on
- pirate.created_on = Time.now + 1.day
- assert pirate.created_on_changed?
- # kind_of does not work because
- # ActiveSupport::TimeWithZone.name == 'Time'
- assert_instance_of Time, pirate.created_on_was
- assert_equal old_created_on, pirate.created_on_was
+ # Change created_on.
+ old_created_on = pirate.created_on
+ pirate.created_on = Time.now + 1.day
+ assert pirate.created_on_changed?
+ # kind_of does not work because
+ # ActiveSupport::TimeWithZone.name == 'Time'
+ assert_instance_of Time, pirate.created_on_was
+ assert_equal old_created_on, pirate.created_on_was
+ end
end
@@ -584,6 +584,14 @@ class DirtyTest < ActiveRecord::TestCase
end
end
+ def test_datetime_attribute_doesnt_change_if_zone_is_modified_in_string
+ time_in_paris = Time.utc(2014, 1, 1, 12, 0, 0).in_time_zone('Paris')
+ pirate = Pirate.create!(:catchphrase => 'rrrr', :created_on => time_in_paris)
+
+ pirate.created_on = pirate.created_on.in_time_zone('Tokyo').to_s
+ assert !pirate.created_on_changed?
+ end
+
test "partial insert" do
with_partial_writes Person do
jon = nil
@@ -608,20 +616,6 @@ class DirtyTest < ActiveRecord::TestCase
end
end
- test "partial_updates config attribute is deprecated" do
- klass = Class.new(ActiveRecord::Base)
-
- assert klass.partial_writes?
- assert_deprecated { assert klass.partial_updates? }
- assert_deprecated { assert klass.partial_updates }
-
- assert_deprecated { klass.partial_updates = false }
-
- assert !klass.partial_writes?
- assert_deprecated { assert !klass.partial_updates? }
- assert_deprecated { assert !klass.partial_updates }
- end
-
private
def with_partial_writes(klass, on = true)
old = klass.partial_writes?
diff --git a/activerecord/test/cases/disconnected_test.rb b/activerecord/test/cases/disconnected_test.rb
new file mode 100644
index 0000000000..9e268dad74
--- /dev/null
+++ b/activerecord/test/cases/disconnected_test.rb
@@ -0,0 +1,28 @@
+require "cases/helper"
+
+class TestRecord < ActiveRecord::Base
+end
+
+class TestDisconnectedAdapter < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ end
+
+ def teardown
+ return if in_memory_db?
+ spec = ActiveRecord::Base.connection_config
+ ActiveRecord::Base.establish_connection(spec)
+ end
+
+ unless in_memory_db?
+ test "can't execute statements while disconnected" do
+ @connection.execute "SELECT count(*) from products"
+ @connection.disconnect!
+ assert_raises(ActiveRecord::StatementInvalid) do
+ @connection.execute "SELECT count(*) from products"
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb
index f73e449610..1e6ccecfab 100644
--- a/activerecord/test/cases/dup_test.rb
+++ b/activerecord/test/cases/dup_test.rb
@@ -126,7 +126,7 @@ module ActiveRecord
def test_dup_with_default_scope
prev_default_scopes = Topic.default_scopes
- Topic.default_scopes = [Topic.where(:approved => true)]
+ Topic.default_scopes = [proc { Topic.where(:approved => true) }]
topic = Topic.new(:approved => false)
assert !topic.dup.approved?, "should not be overridden by default scopes"
ensure
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
new file mode 100644
index 0000000000..c09e58fbf1
--- /dev/null
+++ b/activerecord/test/cases/enum_test.rb
@@ -0,0 +1,91 @@
+require 'cases/helper'
+require 'models/book'
+
+class EnumTest < ActiveRecord::TestCase
+ fixtures :books
+
+ setup do
+ @book = books(:awdr)
+ end
+
+ test "query state by predicate" do
+ assert @book.proposed?
+ assert_not @book.written?
+ assert_not @book.published?
+
+ assert @book.unread?
+ end
+
+ test "query state with strings" do
+ assert_equal "proposed", @book.status
+ assert_equal "unread", @book.read_status
+ end
+
+ test "find via scope" do
+ assert_equal @book, Book.proposed.first
+ assert_equal @book, Book.unread.first
+ end
+
+ test "update by declaration" do
+ @book.written!
+ assert @book.written?
+ end
+
+ test "update by setter" do
+ @book.update! status: :written
+ assert @book.written?
+ end
+
+ test "enum methods are overwritable" do
+ assert_equal "do publish work...", @book.published!
+ assert @book.published?
+ end
+
+ test "direct assignment" do
+ @book.status = :written
+ assert @book.written?
+ end
+
+ test "assign string value" do
+ @book.status = "written"
+ assert @book.written?
+ end
+
+ test "assign non existing value raises an error" do
+ e = assert_raises(ArgumentError) do
+ @book.status = :unknown
+ end
+ assert_equal "'unknown' is not a valid status", e.message
+ end
+
+ test "assign nil value" do
+ @book.status = nil
+ assert @book.status.nil?
+ end
+
+ test "assign empty string value" do
+ @book.status = ''
+ assert @book.status.nil?
+ end
+
+ test "assign long empty string value" do
+ @book.status = ' '
+ assert @book.status.nil?
+ end
+
+ test "constant to access the mapping" do
+ assert_equal 0, Book::STATUS[:proposed]
+ assert_equal 1, Book::STATUS["written"]
+ assert_equal 2, Book::STATUS[:published]
+ end
+
+ test "building new objects with enum scopes" do
+ assert Book.written.build.written?
+ assert Book.read.build.read?
+ end
+
+ test "creating new objects with enum scopes" do
+ assert Book.written.create.written?
+ assert Book.read.create.read?
+ end
+end
diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb
index 9440cd429a..3ff22f222f 100644
--- a/activerecord/test/cases/finder_respond_to_test.rb
+++ b/activerecord/test/cases/finder_respond_to_test.rb
@@ -21,14 +21,9 @@ class FinderRespondToTest < ActiveRecord::TestCase
assert_respond_to Topic, :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_respond_to Topic, :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_respond_to Topic, :find_all_by_title_and_author_name
+ def test_should_respond_to_find_by_with_bang
+ ensure_topic_method_is_not_cached(:find_by_title!)
+ assert_respond_to Topic, :find_by_title!
end
def test_should_respond_to_find_by_two_attributes
@@ -41,36 +36,6 @@ class FinderRespondToTest < ActiveRecord::TestCase
assert_respond_to Topic, :find_by_heading
end
- def test_should_respond_to_find_or_initialize_from_one_attribute
- ensure_topic_method_is_not_cached(:find_or_initialize_by_title)
- assert_respond_to Topic, :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_respond_to Topic, :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_respond_to Topic, :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_respond_to Topic, :find_or_create_by_title_and_author_name
- end
-
- def test_should_respond_to_find_or_create_from_one_attribute_bang
- ensure_topic_method_is_not_cached(:find_or_create_by_title!)
- assert_respond_to Topic, :find_or_create_by_title!
- end
-
- def test_should_respond_to_find_or_create_from_two_attributes_bang
- ensure_topic_method_is_not_cached(:find_or_create_by_title_and_author_name!)
- assert_respond_to Topic, :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
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 6f0de42aef..5125d5df2a 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -11,6 +11,8 @@ require 'models/project'
require 'models/developer'
require 'models/customer'
require 'models/toy'
+require 'models/matey'
+require 'models/dog'
class FinderTest < ActiveRecord::TestCase
fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers, :categories, :categorizations
@@ -45,17 +47,19 @@ class FinderTest < ActiveRecord::TestCase
end
def test_exists
- assert Topic.exists?(1)
- assert Topic.exists?("1")
- assert Topic.exists?(title: "The First Topic")
- assert Topic.exists?(heading: "The First Topic")
- assert Topic.exists?(:author_name => "Mary", :approved => true)
- assert Topic.exists?(["parent_id = ?", 1])
- assert !Topic.exists?(45)
- assert !Topic.exists?(Topic.new)
+ assert_equal true, Topic.exists?(1)
+ assert_equal true, Topic.exists?("1")
+ assert_equal true, Topic.exists?(title: "The First Topic")
+ assert_equal true, Topic.exists?(heading: "The First Topic")
+ assert_equal true, Topic.exists?(:author_name => "Mary", :approved => true)
+ assert_equal true, Topic.exists?(["parent_id = ?", 1])
+ assert_equal true, Topic.exists?(id: [1, 9999])
+
+ assert_equal false, Topic.exists?(45)
+ assert_equal false, Topic.exists?(Topic.new)
begin
- assert !Topic.exists?("foo")
+ assert_equal false, Topic.exists?("foo")
rescue ActiveRecord::StatementInvalid
# PostgreSQL complains about string comparison with integer field
rescue Exception
@@ -72,61 +76,62 @@ class FinderTest < ActiveRecord::TestCase
end
def test_exists_returns_true_with_one_record_and_no_args
- assert Topic.exists?
+ assert_equal true, Topic.exists?
end
def test_exists_returns_false_with_false_arg
- assert !Topic.exists?(false)
+ assert_equal false, Topic.exists?(false)
end
# exists? should handle nil for id's that come from URLs and always return false
# (example: Topic.exists?(params[:id])) where params[:id] is nil
def test_exists_with_nil_arg
- assert !Topic.exists?(nil)
- assert Topic.exists?
- assert !Topic.first.replies.exists?(nil)
- assert Topic.first.replies.exists?
+ assert_equal false, Topic.exists?(nil)
+ assert_equal true, Topic.exists?
+
+ assert_equal false, Topic.first.replies.exists?(nil)
+ assert_equal true, Topic.first.replies.exists?
end
# ensures +exists?+ runs valid SQL by excluding order value
def test_exists_with_order
- assert Topic.order(:id).distinct.exists?
+ assert_equal true, Topic.order(:id).distinct.exists?
end
def test_exists_with_includes_limit_and_empty_result
- assert !Topic.includes(:replies).limit(0).exists?
- assert !Topic.includes(:replies).limit(1).where('0 = 1').exists?
+ assert_equal false, Topic.includes(:replies).limit(0).exists?
+ assert_equal false, Topic.includes(:replies).limit(1).where('0 = 1').exists?
end
def test_exists_with_distinct_association_includes_and_limit
author = Author.first
- assert !author.unique_categorized_posts.includes(:special_comments).limit(0).exists?
- assert author.unique_categorized_posts.includes(:special_comments).limit(1).exists?
+ assert_equal false, author.unique_categorized_posts.includes(:special_comments).limit(0).exists?
+ assert_equal true, author.unique_categorized_posts.includes(:special_comments).limit(1).exists?
end
def test_exists_with_distinct_association_includes_limit_and_order
author = Author.first
- assert !author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(0).exists?
- assert author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(1).exists?
+ assert_equal false, author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(0).exists?
+ assert_equal true, author.unique_categorized_posts.includes(:special_comments).order('comments.taggings_count DESC').limit(1).exists?
end
def test_exists_with_empty_table_and_no_args_given
Topic.delete_all
- assert !Topic.exists?
+ assert_equal false, Topic.exists?
end
def test_exists_with_aggregate_having_three_mappings
existing_address = customers(:david).address
- assert Customer.exists?(:address => existing_address)
+ assert_equal true, Customer.exists?(:address => existing_address)
end
def test_exists_with_aggregate_having_three_mappings_with_one_difference
existing_address = customers(:david).address
- assert !Customer.exists?(:address =>
+ assert_equal false, Customer.exists?(:address =>
Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
- assert !Customer.exists?(:address =>
+ assert_equal false, Customer.exists?(:address =>
Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
- assert !Customer.exists?(:address =>
+ assert_equal false, Customer.exists?(:address =>
Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
end
@@ -146,14 +151,14 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_by_ids_with_limit_and_offset
- assert_equal 2, Entrant.all.merge!(:limit => 2).find([1,3,2]).size
- assert_equal 1, Entrant.all.merge!(:limit => 3, :offset => 2).find([1,3,2]).size
+ assert_equal 2, Entrant.limit(2).find([1,3,2]).size
+ assert_equal 1, Entrant.limit(3).offset(2).find([1,3,2]).size
# Also test an edge case: If you have 11 results, and you set a
# limit of 3 and offset of 9, then you should find that there
# will be only 2 results, regardless of the limit.
devs = Developer.all
- last_devs = Developer.all.merge!(:limit => 3, :offset => 9).find devs.map(&:id)
+ last_devs = Developer.limit(3).offset(9).find devs.map(&:id)
assert_equal 2, last_devs.size
end
@@ -306,7 +311,7 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_only_some_columns
- topic = Topic.all.merge!(:select => "author_name").find(1)
+ topic = Topic.select("author_name").find(1)
assert_raise(ActiveModel::MissingAttributeError) {topic.title}
assert_raise(ActiveModel::MissingAttributeError) {topic.title?}
assert_nil topic.read_attribute("title")
@@ -318,23 +323,23 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_on_array_conditions
- assert Topic.all.merge!(:where => ["approved = ?", false]).find(1)
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => ["approved = ?", true]).find(1) }
+ assert Topic.where(["approved = ?", false]).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(["approved = ?", true]).find(1) }
end
def test_find_on_hash_conditions
- assert Topic.all.merge!(:where => { :approved => false }).find(1)
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => { :approved => true }).find(1) }
+ assert Topic.where(approved: false).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(approved: true).find(1) }
end
def test_find_on_hash_conditions_with_explicit_table_name
- assert Topic.all.merge!(:where => { 'topics.approved' => false }).find(1)
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => { 'topics.approved' => true }).find(1) }
+ assert Topic.where('topics.approved' => false).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => true).find(1) }
end
def test_find_on_hash_conditions_with_hashed_table_name
- assert Topic.all.merge!(:where => {:topics => { :approved => false }}).find(1)
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => {:topics => { :approved => true }}).find(1) }
+ assert Topic.where(topics: { approved: false }).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(topics: { approved: true }).find(1) }
end
def test_find_with_hash_conditions_on_joined_table
@@ -344,7 +349,7 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_with_hash_conditions_on_joined_table_and_with_range
- firms = DependentFirm.all.merge!(:joins => :account, :where => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }})
+ firms = DependentFirm.joins(:account).where(name: 'RailsCore', accounts: { credit_limit: 55..60 })
assert_equal 1, firms.size
assert_equal companies(:rails_core), firms.first
end
@@ -362,71 +367,71 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_on_hash_conditions_with_range
- assert_equal [1,2], Topic.all.merge!(:where => { :id => 1..2 }).to_a.map(&:id).sort
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => { :id => 2..3 }).find(1) }
+ assert_equal [1,2], Topic.where(id: 1..2).to_a.map(&:id).sort
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2..3).find(1) }
end
def test_find_on_hash_conditions_with_end_exclusive_range
- assert_equal [1,2,3], Topic.all.merge!(:where => { :id => 1..3 }).to_a.map(&:id).sort
- assert_equal [1,2], Topic.all.merge!(:where => { :id => 1...3 }).to_a.map(&:id).sort
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => { :id => 2...3 }).find(3) }
+ assert_equal [1,2,3], Topic.where(id: 1..3).to_a.map(&:id).sort
+ assert_equal [1,2], Topic.where(id: 1...3).to_a.map(&:id).sort
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2...3).find(3) }
end
def test_find_on_hash_conditions_with_multiple_ranges
- assert_equal [1,2,3], Comment.all.merge!(:where => { :id => 1..3, :post_id => 1..2 }).to_a.map(&:id).sort
- assert_equal [1], Comment.all.merge!(:where => { :id => 1..1, :post_id => 1..10 }).to_a.map(&:id).sort
+ assert_equal [1,2,3], Comment.where(id: 1..3, post_id: 1..2).to_a.map(&:id).sort
+ assert_equal [1], Comment.where(id: 1..1, post_id: 1..10).to_a.map(&:id).sort
end
def test_find_on_hash_conditions_with_array_of_integers_and_ranges
- assert_equal [1,2,3,5,6,7,8,9], Comment.all.merge!(:where => {:id => [1..2, 3, 5, 6..8, 9]}).to_a.map(&:id).sort
+ assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [1..2, 3, 5, 6..8, 9]).to_a.map(&:id).sort
end
def test_find_on_multiple_hash_conditions
- assert Topic.all.merge!(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false }).find(1)
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }).find(1) }
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }).find(1) }
- assert_raise(ActiveRecord::RecordNotFound) { Topic.all.merge!(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }).find(1) }
+ assert Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: false).find(1)
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) }
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "HHC", replies_count: 1, approved: false).find(1) }
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) }
end
def test_condition_interpolation
assert_kind_of Firm, Company.where("name = '%s'", "37signals").first
- assert_nil Company.all.merge!(:where => ["name = '%s'", "37signals!"]).first
- assert_nil Company.all.merge!(:where => ["name = '%s'", "37signals!' OR 1=1"]).first
- assert_kind_of Time, Topic.all.merge!(:where => ["id = %d", 1]).first.written_on
+ assert_nil Company.where(["name = '%s'", "37signals!"]).first
+ assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
+ assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
end
def test_condition_array_interpolation
- assert_kind_of Firm, Company.all.merge!(:where => ["name = '%s'", "37signals"]).first
- assert_nil Company.all.merge!(:where => ["name = '%s'", "37signals!"]).first
- assert_nil Company.all.merge!(:where => ["name = '%s'", "37signals!' OR 1=1"]).first
- assert_kind_of Time, Topic.all.merge!(:where => ["id = %d", 1]).first.written_on
+ assert_kind_of Firm, Company.where(["name = '%s'", "37signals"]).first
+ assert_nil Company.where(["name = '%s'", "37signals!"]).first
+ assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
+ assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
end
def test_condition_hash_interpolation
- assert_kind_of Firm, Company.all.merge!(:where => { :name => "37signals"}).first
- assert_nil Company.all.merge!(:where => { :name => "37signals!"}).first
- assert_kind_of Time, Topic.all.merge!(:where => {:id => 1}).first.written_on
+ assert_kind_of Firm, Company.where(name: "37signals").first
+ assert_nil Company.where(name: "37signals!").first
+ assert_kind_of Time, Topic.where(id: 1).first.written_on
end
def test_hash_condition_find_malformed
assert_raise(ActiveRecord::StatementInvalid) {
- Company.all.merge!(:where => { :id => 2, :dhh => true }).first
+ Company.where(id: 2, dhh: true).first
}
end
def test_hash_condition_find_with_escaped_characters
Company.create("name" => "Ain't noth'n like' \#stuff")
- assert Company.all.merge!(:where => { :name => "Ain't noth'n like' \#stuff" }).first
+ assert Company.where(name: "Ain't noth'n like' \#stuff").first
end
def test_hash_condition_find_with_array
- p1, p2 = Post.all.merge!(:limit => 2, :order => 'id asc').to_a
- assert_equal [p1, p2], Post.all.merge!(:where => { :id => [p1, p2] }, :order => 'id asc').to_a
- assert_equal [p1, p2], Post.all.merge!(:where => { :id => [p1, p2.id] }, :order => 'id asc').to_a
+ p1, p2 = Post.limit(2).order('id asc').to_a
+ assert_equal [p1, p2], Post.where(id: [p1, p2]).order('id asc').to_a
+ assert_equal [p1, p2], Post.where(id: [p1, p2.id]).order('id asc').to_a
end
def test_hash_condition_find_with_nil
- topic = Topic.all.merge!(:where => { :last_read => nil } ).first
+ topic = Topic.where(last_read: nil).first
assert_not_nil topic
assert_nil topic.last_read
end
@@ -475,61 +480,61 @@ class FinderTest < ActiveRecord::TestCase
def test_condition_utc_time_interpolation_with_default_timezone_local
with_env_tz 'America/New_York' do
- with_active_record_default_timezone :local do
+ with_timezone_config default: :local do
topic = Topic.first
- assert_equal topic, Topic.all.merge!(:where => ['written_on = ?', topic.written_on.getutc]).first
+ assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getutc]).first
end
end
end
def test_hash_condition_utc_time_interpolation_with_default_timezone_local
with_env_tz 'America/New_York' do
- with_active_record_default_timezone :local do
+ with_timezone_config default: :local do
topic = Topic.first
- assert_equal topic, Topic.all.merge!(:where => {:written_on => topic.written_on.getutc}).first
+ assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
end
end
end
def test_condition_local_time_interpolation_with_default_timezone_utc
with_env_tz 'America/New_York' do
- with_active_record_default_timezone :utc do
+ with_timezone_config default: :utc do
topic = Topic.first
- assert_equal topic, Topic.all.merge!(:where => ['written_on = ?', topic.written_on.getlocal]).first
+ assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getlocal]).first
end
end
end
def test_hash_condition_local_time_interpolation_with_default_timezone_utc
with_env_tz 'America/New_York' do
- with_active_record_default_timezone :utc do
+ with_timezone_config default: :utc do
topic = Topic.first
- assert_equal topic, Topic.all.merge!(:where => {:written_on => topic.written_on.getlocal}).first
+ assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
end
end
end
def test_bind_variables
- assert_kind_of Firm, Company.all.merge!(:where => ["name = ?", "37signals"]).first
- assert_nil Company.all.merge!(:where => ["name = ?", "37signals!"]).first
- assert_nil Company.all.merge!(:where => ["name = ?", "37signals!' OR 1=1"]).first
- assert_kind_of Time, Topic.all.merge!(:where => ["id = ?", 1]).first.written_on
+ assert_kind_of Firm, Company.where(["name = ?", "37signals"]).first
+ assert_nil Company.where(["name = ?", "37signals!"]).first
+ assert_nil Company.where(["name = ?", "37signals!' OR 1=1"]).first
+ assert_kind_of Time, Topic.where(["id = ?", 1]).first.written_on
assert_raise(ActiveRecord::PreparedStatementInvalid) {
- Company.all.merge!(:where => ["id=? AND name = ?", 2]).first
+ Company.where(["id=? AND name = ?", 2]).first
}
assert_raise(ActiveRecord::PreparedStatementInvalid) {
- Company.all.merge!(:where => ["id=?", 2, 3, 4]).first
+ Company.where(["id=?", 2, 3, 4]).first
}
end
def test_bind_variables_with_quotes
Company.create("name" => "37signals' go'es agains")
- assert Company.all.merge!(:where => ["name = ?", "37signals' go'es agains"]).first
+ assert Company.where(["name = ?", "37signals' go'es agains"]).first
end
def test_named_bind_variables_with_quotes
Company.create("name" => "37signals' go'es agains")
- assert Company.all.merge!(:where => ["name = :name", {:name => "37signals' go'es agains"}]).first
+ assert Company.where(["name = :name", {name: "37signals' go'es agains"}]).first
end
def test_bind_arity
@@ -547,10 +552,10 @@ class FinderTest < ActiveRecord::TestCase
assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
- assert_kind_of Firm, Company.all.merge!(:where => ["name = :name", { :name => "37signals" }]).first
- assert_nil Company.all.merge!(:where => ["name = :name", { :name => "37signals!" }]).first
- assert_nil Company.all.merge!(:where => ["name = :name", { :name => "37signals!' OR 1=1" }]).first
- assert_kind_of Time, Topic.all.merge!(:where => ["id = :id", { :id => 1 }]).first.written_on
+ assert_kind_of Firm, Company.where(["name = :name", { name: "37signals" }]).first
+ assert_nil Company.where(["name = :name", { name: "37signals!" }]).first
+ assert_nil Company.where(["name = :name", { name: "37signals!' OR 1=1" }]).first
+ assert_kind_of Time, Topic.where(["id = :id", { id: 1 }]).first.written_on
end
class SimpleEnumerable
@@ -613,7 +618,7 @@ class FinderTest < ActiveRecord::TestCase
def test_named_bind_with_postgresql_type_casts
l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
assert_nothing_raised(&l)
- assert_equal "#{ActiveRecord::Base.quote_value('10')}::integer '2009-01-01'::date", l.call
+ assert_equal "#{ActiveRecord::Base.connection.quote('10')}::integer '2009-01-01'::date", l.call
end
def test_string_sanitation
@@ -637,6 +642,13 @@ class FinderTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") }
end
+ def test_find_by_on_attribute_that_is_a_reserved_word
+ dog_alias = 'Dog'
+ dog = Dog.create(alias: dog_alias)
+
+ assert_equal dog, Dog.find_by_alias(dog_alias)
+ end
+
def test_find_by_one_attribute_that_is_an_alias
assert_equal topics(:first), Topic.find_by_heading("The First Topic")
assert_nil Topic.find_by_heading("The First Topic!")
@@ -716,6 +728,15 @@ class FinderTest < ActiveRecord::TestCase
assert_raise(ArgumentError) { Topic.find_by_title_and_author_name("The First Topic") }
end
+ def test_find_last_with_offset
+ devs = Developer.order('id')
+
+ assert_equal devs[2], Developer.offset(2).first
+ assert_equal devs[-3], Developer.offset(2).last
+ assert_equal devs[-3], Developer.offset(2).last
+ assert_equal devs[-3], Developer.offset(2).order('id DESC').first
+ end
+
def test_find_by_nil_attribute
topic = Topic.find_by_last_read nil
assert_not_nil topic
@@ -732,10 +753,9 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_all_with_join
- developers_on_project_one = Developer.all.merge!(
- :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
- :where => 'project_id=1'
- ).to_a
+ developers_on_project_one = Developer.
+ joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').
+ where('project_id=1').to_a
assert_equal 3, developers_on_project_one.length
developer_names = developers_on_project_one.map { |d| d.name }
assert developer_names.include?('David')
@@ -743,20 +763,17 @@ class FinderTest < ActiveRecord::TestCase
end
def test_joins_dont_clobber_id
- first = Firm.all.merge!(
- :joins => 'INNER JOIN companies clients ON clients.firm_id = companies.id',
- :where => 'companies.id = 1'
- ).first
+ first = Firm.
+ joins('INNER JOIN companies clients ON clients.firm_id = companies.id').
+ where('companies.id = 1').first
assert_equal 1, first.id
end
def test_joins_with_string_array
- person_with_reader_and_post = Post.all.merge!(
- :joins => [
- "INNER JOIN categorizations ON categorizations.post_id = posts.id",
- "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
- ]
- )
+ person_with_reader_and_post = Post.
+ joins(["INNER JOIN categorizations ON categorizations.post_id = posts.id",
+ "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
+ ])
assert_equal 1, person_with_reader_and_post.size
end
@@ -781,9 +798,9 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_by_records
- p1, p2 = Post.all.merge!(:limit => 2, :order => 'id asc').to_a
- assert_equal [p1, p2], Post.all.merge!(:where => ['id in (?)', [p1, p2]], :order => 'id asc')
- assert_equal [p1, p2], Post.all.merge!(:where => ['id in (?)', [p1, p2.id]], :order => 'id asc')
+ p1, p2 = Post.limit(2).order('id asc').to_a
+ assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2]]).order('id asc')
+ assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2.id]]).order('id asc')
end
def test_select_value
@@ -810,36 +827,35 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
- assert_equal 2, Post.all.merge!(:includes => { :authors => :author_address }, :order => 'author_addresses.id DESC ', :limit => 2).to_a.size
+ assert_equal 2, Post.includes(authors: :author_address).order('author_addresses.id DESC ').limit(2).to_a.size
- assert_equal 3, Post.all.merge!(:includes => { :author => :author_address, :authors => :author_address},
- :order => 'author_addresses_authors.id DESC ', :limit => 3).to_a.size
+ assert_equal 3, Post.includes(author: :author_address, authors: :author_address).
+ order('author_addresses_authors.id DESC ').limit(3).to_a.size
end
def test_find_with_nil_inside_set_passed_for_one_attribute
- client_of = Company.all.merge!(
- :where => {
- :client_of => [2, 1, nil],
- :name => ['37signals', 'Summit', 'Microsoft'] },
- :order => 'client_of DESC'
- ).map { |x| x.client_of }
+ client_of = Company.
+ where(client_of: [2, 1, nil],
+ name: ['37signals', 'Summit', 'Microsoft']).
+ order('client_of DESC').
+ map { |x| x.client_of }
assert client_of.include?(nil)
assert_equal [2, 1].sort, client_of.compact.sort
end
def test_find_with_nil_inside_set_passed_for_attribute
- client_of = Company.all.merge!(
- :where => { :client_of => [nil] },
- :order => 'client_of DESC'
- ).map { |x| x.client_of }
+ client_of = Company.
+ where(client_of: [nil]).
+ order('client_of DESC').
+ map { |x| x.client_of }
assert_equal [], client_of.compact
end
def test_with_limiting_with_custom_select
posts = Post.references(:authors).merge(
- :includes => :author, :select => ' posts.*, authors.id as "author_id"',
+ :includes => :author, :select => 'posts.*, authors.id as "author_id"',
:limit => 3, :order => 'posts.id'
).to_a
assert_equal 3, posts.size
@@ -857,8 +873,14 @@ class FinderTest < ActiveRecord::TestCase
Toy.reset_primary_key
end
+ def test_find_without_primary_key
+ assert_raises(ActiveRecord::UnknownPrimaryKey) do
+ Matey.find(1)
+ end
+ end
+
def test_finder_with_offset_string
- assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.all.merge!(:offset => "3").to_a }
+ assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.offset("3").to_a }
end
protected
@@ -876,11 +898,4 @@ class FinderTest < ActiveRecord::TestCase
ensure
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
end
-
- def with_active_record_default_timezone(zone)
- old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone
- yield
- ensure
- ActiveRecord::Base.default_timezone = old_zone
- end
end
diff --git a/activerecord/test/cases/fixture_set/file_test.rb b/activerecord/test/cases/fixture_set/file_test.rb
index a029fedbd3..92efa8aca7 100644
--- a/activerecord/test/cases/fixture_set/file_test.rb
+++ b/activerecord/test/cases/fixture_set/file_test.rb
@@ -68,6 +68,61 @@ module ActiveRecord
end
end
+ def test_render_context_helper
+ ActiveRecord::FixtureSet.context_class.class_eval do
+ def fixture_helper
+ "Fixture helper"
+ end
+ end
+ yaml = "one:\n name: <%= fixture_helper %>\n"
+ tmp_yaml ['curious', 'yml'], yaml do |t|
+ golden =
+ [["one", {"name" => "Fixture helper"}]]
+ assert_equal golden, File.open(t.path) { |fh| fh.to_a }
+ end
+ ActiveRecord::FixtureSet.context_class.class_eval do
+ remove_method :fixture_helper
+ end
+ end
+
+ def test_render_context_lookup_scope
+ yaml = <<END
+one:
+ ActiveRecord: <%= defined? ActiveRecord %>
+ ActiveRecord_FixtureSet: <%= defined? ActiveRecord::FixtureSet %>
+ FixtureSet: <%= defined? FixtureSet %>
+ ActiveRecord_FixtureSet_File: <%= defined? ActiveRecord::FixtureSet::File %>
+ File: <%= File.name %>
+END
+
+ golden = [['one', {
+ 'ActiveRecord' => 'constant',
+ 'ActiveRecord_FixtureSet' => 'constant',
+ 'FixtureSet' => nil,
+ 'ActiveRecord_FixtureSet_File' => 'constant',
+ 'File' => 'File'
+ }]]
+
+ tmp_yaml ['curious', 'yml'], yaml do |t|
+ assert_equal golden, File.open(t.path) { |fh| fh.to_a }
+ end
+ end
+
+ # Make sure that each fixture gets its own rendering context so that
+ # fixtures are independent.
+ def test_independent_render_contexts
+ yaml1 = "<% def leaked_method; 'leak'; end %>\n"
+ yaml2 = "one:\n name: <%= leaked_method %>\n"
+ tmp_yaml ['leaky', 'yml'], yaml1 do |t1|
+ tmp_yaml ['curious', 'yml'], yaml2 do |t2|
+ File.open(t1.path) { |fh| fh.to_a }
+ assert_raises(NameError) do
+ File.open(t2.path) { |fh| fh.to_a }
+ end
+ end
+ end
+ end
+
private
def tmp_yaml(name, contents)
t = Tempfile.new name
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index f6cfee0cb8..f3a4887a85 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -84,6 +84,12 @@ class FixturesTest < ActiveRecord::TestCase
assert fixtures.detect { |f| f.name == 'collections' }, "no fixtures named 'collections' in #{fixtures.map(&:name).inspect}"
end
+ def test_create_symbol_fixtures_is_deprecated
+ assert_deprecated do
+ ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, :collections, :collections => 'Course') { Course.connection }
+ end
+ end
+
def test_attributes
topics = create_fixtures("topics").first
assert_equal("The First Topic", topics["first"]["title"])
@@ -190,11 +196,11 @@ class FixturesTest < ActiveRecord::TestCase
end
def test_empty_yaml_fixture
- assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "accounts", 'Account', FIXTURES_ROOT + "/naked/yml/accounts")
+ assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "accounts", Account, FIXTURES_ROOT + "/naked/yml/accounts")
end
def test_empty_yaml_fixture_with_a_comment_in_it
- assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "companies", 'Company', FIXTURES_ROOT + "/naked/yml/companies")
+ assert_not_nil ActiveRecord::FixtureSet.new( Account.connection, "companies", Company, FIXTURES_ROOT + "/naked/yml/companies")
end
def test_nonexistent_fixture_file
@@ -204,19 +210,19 @@ class FixturesTest < ActiveRecord::TestCase
assert Dir[nonexistent_fixture_path+"*"].empty?
assert_raise(Errno::ENOENT) do
- ActiveRecord::FixtureSet.new( Account.connection, "companies", 'Company', nonexistent_fixture_path)
+ ActiveRecord::FixtureSet.new( Account.connection, "companies", Company, nonexistent_fixture_path)
end
end
def test_dirty_dirty_yaml_file
assert_raise(ActiveRecord::Fixture::FormatError) do
- ActiveRecord::FixtureSet.new( Account.connection, "courses", 'Course', FIXTURES_ROOT + "/naked/yml/courses")
+ ActiveRecord::FixtureSet.new( Account.connection, "courses", Course, FIXTURES_ROOT + "/naked/yml/courses")
end
end
def test_omap_fixtures
assert_nothing_raised do
- fixtures = ActiveRecord::FixtureSet.new(Account.connection, 'categories', 'Category', FIXTURES_ROOT + "/categories_ordered")
+ fixtures = ActiveRecord::FixtureSet.new(Account.connection, 'categories', Category, FIXTURES_ROOT + "/categories_ordered")
fixtures.each.with_index do |(name, fixture), i|
assert_equal "fixture_no_#{i}", name
@@ -245,6 +251,60 @@ class FixturesTest < ActiveRecord::TestCase
def test_serialized_fixtures
assert_equal ["Green", "Red", "Orange"], traffic_lights(:uk).state
end
+
+ def test_fixtures_are_set_up_with_database_env_variable
+ db_url_tmp = ENV['DATABASE_URL']
+ ENV['DATABASE_URL'] = "sqlite3:///:memory:"
+ ActiveRecord::Base.stubs(:configurations).returns({})
+ test_case = Class.new(ActiveRecord::TestCase) do
+ fixtures :accounts
+
+ def test_fixtures
+ assert accounts(:signals37)
+ end
+ end
+
+ result = test_case.new(:test_fixtures).run
+
+ assert result.passed?, "Expected #{result.name} to pass:\n#{result}"
+ ensure
+ ENV['DATABASE_URL'] = db_url_tmp
+ end
+end
+
+class HasManyThroughFixture < ActiveSupport::TestCase
+ def make_model(name)
+ Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } }
+ end
+
+ def test_has_many_through
+ pt = make_model "ParrotTreasure"
+ parrot = make_model "Parrot"
+ treasure = make_model "Treasure"
+
+ pt.table_name = "parrots_treasures"
+ pt.belongs_to :parrot, :class => parrot
+ pt.belongs_to :treasure, :class => treasure
+
+ parrot.has_many :parrot_treasures, :class => pt
+ parrot.has_many :treasures, :through => :parrot_treasures
+
+ parrots = File.join FIXTURES_ROOT, 'parrots'
+
+ fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots
+ rows = fs.table_rows
+ assert_equal load_has_and_belongs_to_many['parrots_treasures'], rows['parrots_treasures']
+ end
+
+ def load_has_and_belongs_to_many
+ parrot = make_model "Parrot"
+ parrot.has_and_belongs_to_many :treasures
+
+ parrots = File.join FIXTURES_ROOT, 'parrots'
+
+ fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots
+ fs.table_rows
+ end
end
if Account.connection.respond_to?(:reset_pk_sequence!)
@@ -433,7 +493,7 @@ class OverRideFixtureMethodTest < ActiveRecord::TestCase
end
class CheckSetTableNameFixturesTest < ActiveRecord::TestCase
- set_fixture_class :funny_jokes => 'Joke'
+ 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
@@ -477,10 +537,6 @@ class CustomConnectionFixturesTest < ActiveRecord::TestCase
fixtures :courses
self.use_transactional_fixtures = false
- def test_connection_instance_method_deprecation
- assert_deprecated { courses(:ruby).connection }
- end
-
def test_leaky_destroy
assert_nothing_raised { courses(:ruby) }
courses(:ruby).destroy
@@ -520,7 +576,7 @@ class InvalidTableNameFixturesTest < ActiveRecord::TestCase
end
class CheckEscapedYamlFixturesTest < ActiveRecord::TestCase
- set_fixture_class :funny_jokes => 'Joke'
+ 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
@@ -562,26 +618,30 @@ class FixturesBrokenRollbackTest < ActiveRecord::TestCase
end
private
- def load_fixtures
+ def load_fixtures(config)
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
+ self.class.fixture_path = FIXTURES_ROOT + "/all"
+ self.class.fixtures :all
+
+ assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort
+ ensure
+ ActiveRecord::FixtureSet.reset_cache
end
end
class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase
- self.fixture_path = Pathname.new(FIXTURES_ROOT).join('all')
- fixtures :all
-
def test_all_there
- assert_equal %w(developers people tasks), fixture_table_names.sort
+ self.class.fixture_path = Pathname.new(FIXTURES_ROOT).join('all')
+ self.class.fixtures :all
+
+ assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort
+ ensure
+ ActiveRecord::FixtureSet.reset_cache
end
end
diff --git a/activerecord/test/cases/forbidden_attributes_protection_test.rb b/activerecord/test/cases/forbidden_attributes_protection_test.rb
index 490b599fb6..981a75faf6 100644
--- a/activerecord/test/cases/forbidden_attributes_protection_test.rb
+++ b/activerecord/test/cases/forbidden_attributes_protection_test.rb
@@ -61,4 +61,9 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase
assert_equal 'Guille', person.first_name
assert_equal 'm', person.gender
end
+
+ def test_blank_attributes_should_not_raise
+ person = Person.new
+ assert_nil person.assign_attributes(ProtectedParams.new({}))
+ end
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 7dbb6616f8..3758224b0c 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -20,6 +20,9 @@ Thread.abort_on_exception = true
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
+# Disable available locale checks to avoid warnings running the test suite.
+I18n.enforce_available_locales = false
+
# Connect to the database
ARTest.connect
@@ -49,11 +52,58 @@ ensure
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
end
-def with_active_record_default_timezone(zone)
- old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone
+def with_timezone_config(cfg)
+ verify_default_timezone_config
+
+ old_default_zone = ActiveRecord::Base.default_timezone
+ old_awareness = ActiveRecord::Base.time_zone_aware_attributes
+ old_zone = Time.zone
+
+ if cfg.has_key?(:default)
+ ActiveRecord::Base.default_timezone = cfg[:default]
+ end
+ if cfg.has_key?(:aware_attributes)
+ ActiveRecord::Base.time_zone_aware_attributes = cfg[:aware_attributes]
+ end
+ if cfg.has_key?(:zone)
+ Time.zone = cfg[:zone]
+ end
yield
ensure
- ActiveRecord::Base.default_timezone = old_zone
+ ActiveRecord::Base.default_timezone = old_default_zone
+ ActiveRecord::Base.time_zone_aware_attributes = old_awareness
+ Time.zone = old_zone
+end
+
+# This method makes sure that tests don't leak global state related to time zones.
+EXPECTED_ZONE = nil
+EXPECTED_DEFAULT_TIMEZONE = :utc
+EXPECTED_TIME_ZONE_AWARE_ATTRIBUTES = false
+def verify_default_timezone_config
+ if Time.zone != EXPECTED_ZONE
+ $stderr.puts <<-MSG
+\n#{self.to_s}
+ Global state `Time.zone` was leaked.
+ Expected: #{EXPECTED_ZONE}
+ Got: #{Time.zone}
+ MSG
+ end
+ if ActiveRecord::Base.default_timezone != EXPECTED_DEFAULT_TIMEZONE
+ $stderr.puts <<-MSG
+\n#{self.to_s}
+ Global state `ActiveRecord::Base.default_timezone` was leaked.
+ Expected: #{EXPECTED_DEFAULT_TIMEZONE}
+ Got: #{ActiveRecord::Base.default_timezone}
+ MSG
+ end
+ if ActiveRecord::Base.time_zone_aware_attributes != EXPECTED_TIME_ZONE_AWARE_ATTRIBUTES
+ $stderr.puts <<-MSG
+\n#{self.to_s}
+ Global state `ActiveRecord::Base.time_zone_aware_attributes` was leaked.
+ Expected: #{EXPECTED_TIME_ZONE_AWARE_ATTRIBUTES}
+ Got: #{ActiveRecord::Base.time_zone_aware_attributes}
+ MSG
+ end
end
unless ENV['FIXTURE_DEBUG']
@@ -93,7 +143,7 @@ def load_schema
load SCHEMA_ROOT + "/schema.rb"
- if File.exists?(adapter_specific_schema_file)
+ if File.exist?(adapter_specific_schema_file)
load adapter_specific_schema_file
end
ensure
@@ -102,36 +152,21 @@ end
load_schema
-class << Time
- unless method_defined? :now_before_time_travel
- alias_method :now_before_time_travel, :now
- end
+class SQLSubscriber
+ attr_reader :logged
+ attr_reader :payloads
- def now
- (@now ||= nil) || now_before_time_travel
+ def initialize
+ @logged = []
+ @payloads = []
end
- def travel_to(time, &block)
- @now = time
- block.call
- ensure
- @now = nil
+ def start(name, id, payload)
+ @payloads << payload
+ @logged << [payload[:sql], payload[:name], payload[:binds]]
end
-end
-module LogIntercepter
- attr_accessor :logged, :intercepted
- def self.extended(base)
- base.logged = []
- end
- def log(sql, name, binds = [], &block)
- if @intercepted
- @logged << [sql, name, binds]
- yield
- else
- super(sql, name,binds, &block)
- end
- end
+ def finish(name, id, payload); end
end
module InTimeZone
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index a9be132801..cb0d374ef7 100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -176,14 +176,14 @@ class InheritanceTest < ActiveRecord::TestCase
e = assert_raises(NotImplementedError) do
AbstractCompany.new
end
- assert_equal("AbstractCompany is an abstract class and can not be instantiated.", e.message)
+ assert_equal("AbstractCompany is an abstract class and cannot be instantiated.", e.message)
end
def test_new_with_ar_base
e = assert_raises(NotImplementedError) do
ActiveRecord::Base.new
end
- assert_equal("ActiveRecord::Base is an abstract class and can not be instantiated.", e.message)
+ assert_equal("ActiveRecord::Base is an abstract class and cannot be instantiated.", e.message)
end
def test_new_with_invalid_type
@@ -313,8 +313,12 @@ class InheritanceTest < ActiveRecord::TestCase
assert_kind_of SpecialSubscriber, SpecialSubscriber.find("webster132")
assert_nothing_raised { s = SpecialSubscriber.new("name" => "And breaaaaathe!"); s.id = 'roger'; s.save }
end
-end
+ def test_scope_inherited_properly
+ assert_nothing_raised { Company.of_first_firm }
+ assert_nothing_raised { Client.of_first_firm }
+ end
+end
class InheritanceComputeTypeTest < ActiveRecord::TestCase
fixtures :companies
diff --git a/activerecord/test/cases/integration_test.rb b/activerecord/test/cases/integration_test.rb
index b0a7cda2f3..2e71b1a40d 100644
--- a/activerecord/test/cases/integration_test.rb
+++ b/activerecord/test/cases/integration_test.rb
@@ -1,11 +1,14 @@
+# encoding: utf-8
+
require 'cases/helper'
require 'models/company'
require 'models/developer'
require 'models/car'
require 'models/bulb'
+require 'models/owner'
class IntegrationTest < ActiveRecord::TestCase
- fixtures :companies, :developers
+ fixtures :companies, :developers, :owners
def test_to_param_should_return_string
assert_kind_of String, Client.first.to_param
@@ -22,16 +25,59 @@ class IntegrationTest < ActiveRecord::TestCase
assert_equal '1', client.to_param
end
- def test_cache_key_for_existing_record_is_not_timezone_dependent
- ActiveRecord::Base.time_zone_aware_attributes = true
+ def test_to_param_class_method
+ firm = Firm.find(4)
+ assert_equal '4-flamboyant-software', firm.to_param
+ end
- Time.zone = 'UTC'
- utc_key = Developer.first.cache_key
+ def test_to_param_class_method_truncates
+ firm = Firm.find(4)
+ firm.name = 'a ' * 100
+ assert_equal '4-a-a-a-a-a-a-a-a-a', firm.to_param
+ end
- Time.zone = 'EST'
- est_key = Developer.first.cache_key
+ def test_to_param_class_method_truncates_edge_case
+ firm = Firm.find(4)
+ firm.name = 'David HeinemeierHansson'
+ assert_equal '4-david', firm.to_param
+ end
- assert_equal utc_key, est_key
+ def test_to_param_class_method_squishes
+ firm = Firm.find(4)
+ firm.name = "ab \n" * 100
+ assert_equal '4-ab-ab-ab-ab-ab-ab', firm.to_param
+ end
+
+ def test_to_param_class_method_multibyte_character
+ firm = Firm.find(4)
+ firm.name = "戦場ヶ原 ひたぎ"
+ assert_equal '4', firm.to_param
+ end
+
+ def test_to_param_class_method_uses_default_if_blank
+ firm = Firm.find(4)
+ firm.name = nil
+ assert_equal '4', firm.to_param
+ firm.name = ' '
+ assert_equal '4', firm.to_param
+ end
+
+ def test_to_param_class_method_uses_default_if_not_persisted
+ firm = Firm.new(name: 'Fancy Shirts')
+ assert_equal nil, firm.to_param
+ end
+
+ def test_to_param_with_no_arguments
+ assert_equal 'Firm', Firm.to_param
+ end
+
+ def test_cache_key_for_existing_record_is_not_timezone_dependent
+ utc_key = Developer.first.cache_key
+
+ with_timezone_config zone: "EST" do
+ est_key = Developer.first.cache_key
+ assert_equal utc_key, est_key
+ end
end
def test_cache_key_format_for_existing_record_with_updated_at
@@ -84,4 +130,9 @@ class IntegrationTest < ActiveRecord::TestCase
dev.touch
assert_not_equal key, dev.cache_key
end
+
+ def test_named_timestamps_for_cache_key
+ owner = owners(:blackbeard)
+ assert_equal "owners/#{owner.id}-#{owner.happy_at.utc.to_s(:nsec)}", owner.cache_key(:updated_at, :happy_at)
+ end
end
diff --git a/activerecord/test/cases/invalid_connection_test.rb b/activerecord/test/cases/invalid_connection_test.rb
new file mode 100644
index 0000000000..f6774d7ef4
--- /dev/null
+++ b/activerecord/test/cases/invalid_connection_test.rb
@@ -0,0 +1,22 @@
+require "cases/helper"
+
+class TestAdapterWithInvalidConnection < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ class Bird < ActiveRecord::Base
+ end
+
+ def setup
+ # Can't just use current adapter; sqlite3 will create a database
+ # file on the fly.
+ Bird.establish_connection adapter: 'mysql', database: 'i_do_not_exist'
+ end
+
+ def teardown
+ Bird.remove_connection
+ end
+
+ test "inspect on Model class does not raise" do
+ assert_equal "#{Bird.name} (call '#{Bird.name}.connection' to establish a connection)", Bird.inspect
+ end
+end
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 77891b9156..a16ed963fe 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -8,6 +8,7 @@ require 'models/legacy_thing'
require 'models/reference'
require 'models/string_key_object'
require 'models/car'
+require 'models/bulb'
require 'models/engine'
require 'models/wheel'
require 'models/treasure'
@@ -16,6 +17,7 @@ class LockWithoutDefault < ActiveRecord::Base; end
class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
self.table_name = :lock_without_defaults_cust
+ self.column_defaults # to test @column_defaults caching.
self.locking_column = :custom_lock_version
end
@@ -26,6 +28,18 @@ end
class OptimisticLockingTest < ActiveRecord::TestCase
fixtures :people, :legacy_things, :references, :string_key_objects, :peoples_treasures
+ def test_quote_value_passed_lock_col
+ p1 = Person.find(1)
+ assert_equal 0, p1.lock_version
+
+ Person.expects(:quote_value).with(0, Person.columns_hash[Person.locking_column]).returns('0').once
+
+ p1.first_name = 'anika2'
+ p1.save!
+
+ assert_equal 1, p1.lock_version
+ end
+
def test_non_integer_lock_existing
s1 = StringKeyObject.find("record1")
s2 = StringKeyObject.find("record1")
@@ -242,7 +256,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase
car = Car.create!
assert_difference 'car.wheels.count' do
- car.wheels << Wheel.create!
+ car.wheels << Wheel.create!
end
assert_difference 'car.wheels.count', -1 do
car.destroy
@@ -258,6 +272,10 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert p.treasures.empty?
assert RichPerson.connection.select_all("SELECT * FROM peoples_treasures WHERE rich_person_id = 1").empty?
end
+
+ def test_quoted_locking_column_is_deprecated
+ assert_deprecated { ActiveRecord::Base.quoted_locking_column }
+ end
end
class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb
index 57eac0c175..97c0350911 100644
--- a/activerecord/test/cases/log_subscriber_test.rb
+++ b/activerecord/test/cases/log_subscriber_test.rb
@@ -56,6 +56,13 @@ class LogSubscriberTest < ActiveRecord::TestCase
assert_equal 2, logger.debugs.length
end
+ def test_sql_statements_are_not_squeezed
+ event = Struct.new(:duration, :payload)
+ logger = TestDebugLogSubscriber.new
+ logger.sql(event.new(0, sql: 'ruby rails'))
+ assert_match(/ruby rails/, logger.debugs.first)
+ end
+
def test_ignore_binds_payload_with_nil_column
event = Struct.new(:duration, :payload)
@@ -112,11 +119,11 @@ class LogSubscriberTest < ActiveRecord::TestCase
Thread.new { assert_equal 0, ActiveRecord::LogSubscriber.runtime }.join
end
- def test_binary_data_is_not_logged
- skip if current_adapter?(:Mysql2Adapter)
-
- Binary.create(data: 'some binary data')
- wait
- assert_match(/<16 bytes of binary data>/, @logger.logged(:debug).join)
+ unless current_adapter?(:Mysql2Adapter)
+ def test_binary_data_is_not_logged
+ Binary.create(data: 'some binary data')
+ wait
+ assert_match(/<16 bytes of binary data>/, @logger.logged(:debug).join)
+ end
end
end
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index 54fff8a0f5..294f2eb9fe 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -74,6 +74,29 @@ module ActiveRecord
assert_equal "hello", five.default unless mysql
end
+ if current_adapter?(:PostgreSQLAdapter)
+ def test_add_column_with_array
+ connection.create_table :testings
+ connection.add_column :testings, :foo, :string, :array => true
+
+ columns = connection.columns(:testings)
+ array_column = columns.detect { |c| c.name == "foo" }
+
+ assert array_column.array
+ end
+
+ def test_create_table_with_array_column
+ connection.create_table :testings do |t|
+ t.string :foo, :array => true
+ end
+
+ columns = connection.columns(:testings)
+ array_column = columns.detect { |c| c.name == "foo" }
+
+ assert array_column.array
+ end
+ end
+
def test_create_table_with_limits
connection.create_table :testings do |t|
t.column :foo, :string, :limit => 255
@@ -182,20 +205,18 @@ module ActiveRecord
connection.create_table table_name
end
- def test_add_column_not_null_without_default
- # Sybase, and SQLite3 will not allow you to add a NOT NULL
- # column to a table without a default value.
- if current_adapter?(:SybaseAdapter, :SQLite3Adapter)
- skip "not supported on #{connection.class}"
- end
-
- connection.create_table :testings do |t|
- t.column :foo, :string
- end
- connection.add_column :testings, :bar, :string, :null => false
+ # Sybase, and SQLite3 will not allow you to add a NOT NULL
+ # column to a table without a default value.
+ unless current_adapter?(:SybaseAdapter, :SQLite3Adapter)
+ def test_add_column_not_null_without_default
+ connection.create_table :testings do |t|
+ t.column :foo, :string
+ end
+ connection.add_column :testings, :bar, :string, :null => false
- assert_raise(ActiveRecord::StatementInvalid) do
- connection.execute "insert into testings (foo, bar) values ('hello', NULL)"
+ assert_raise(ActiveRecord::StatementInvalid) do
+ connection.execute "insert into testings (foo, bar) values ('hello', NULL)"
+ end
end
end
@@ -287,6 +308,22 @@ module ActiveRecord
assert_equal 2000, connection.select_values("SELECT money FROM testings").first.to_i
end
+ def test_change_column_null
+ testing_table_with_only_foo_attribute do
+ notnull_migration = Class.new(ActiveRecord::Migration) do
+ def change
+ change_column_null :testings, :foo, false
+ end
+ end
+ notnull_migration.new.suppress_messages do
+ notnull_migration.migrate(:up)
+ assert_equal false, connection.columns(:testings).find{ |c| c.name == "foo"}.null
+ notnull_migration.migrate(:down)
+ assert connection.columns(:testings).find{ |c| c.name == "foo"}.null
+ end
+ end
+ end
+
def test_column_exists
connection.create_table :testings do |t|
t.column :foo, :string
diff --git a/activerecord/test/cases/migration/change_table_test.rb b/activerecord/test/cases/migration/change_table_test.rb
index 8065541bfe..c1d7cd5874 100644
--- a/activerecord/test/cases/migration/change_table_test.rb
+++ b/activerecord/test/cases/migration/change_table_test.rb
@@ -5,7 +5,7 @@ module ActiveRecord
class Migration
class TableTest < ActiveRecord::TestCase
def setup
- @connection = MiniTest::Mock.new
+ @connection = Minitest::Mock.new
end
def teardown
diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb
index ec2926632c..ccf19fb4d0 100644
--- a/activerecord/test/cases/migration/column_attributes_test.rb
+++ b/activerecord/test/cases/migration/column_attributes_test.rb
@@ -16,40 +16,31 @@ module ActiveRecord
end
def test_add_remove_single_field_using_string_arguments
- assert_not TestModel.column_methods_hash.key?(:last_name)
+ assert_no_column TestModel, :last_name
add_column 'test_models', 'last_name', :string
-
- TestModel.reset_column_information
-
- assert TestModel.column_methods_hash.key?(:last_name)
+ assert_column TestModel, :last_name
remove_column 'test_models', 'last_name'
-
- TestModel.reset_column_information
- assert_not TestModel.column_methods_hash.key?(:last_name)
+ assert_no_column TestModel, :last_name
end
def test_add_remove_single_field_using_symbol_arguments
- assert_not TestModel.column_methods_hash.key?(:last_name)
+ assert_no_column TestModel, :last_name
add_column :test_models, :last_name, :string
-
- TestModel.reset_column_information
- assert TestModel.column_methods_hash.key?(:last_name)
+ assert_column TestModel, :last_name
remove_column :test_models, :last_name
-
- TestModel.reset_column_information
- assert_not TestModel.column_methods_hash.key?(:last_name)
+ assert_no_column TestModel, :last_name
end
- def test_unabstracted_database_dependent_types
- skip "not supported" unless current_adapter?(:MysqlAdapter, :Mysql2Adapter)
-
- add_column :test_models, :intelligence_quotient, :tinyint
- TestModel.reset_column_information
- assert_match(/tinyint/, TestModel.columns_hash['intelligence_quotient'].sql_type)
+ if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
+ def test_unabstracted_database_dependent_types
+ add_column :test_models, :intelligence_quotient, :tinyint
+ TestModel.reset_column_information
+ assert_match(/tinyint/, TestModel.columns_hash['intelligence_quotient'].sql_type)
+ end
end
# We specifically do a manual INSERT here, and then test only the SELECT
@@ -104,22 +95,22 @@ module ActiveRecord
assert_equal 7, wealth_column.scale
end
- def test_change_column_preserve_other_column_precision_and_scale
- skip "only on sqlite3" unless current_adapter?(:SQLite3Adapter)
+ if current_adapter?(:SQLite3Adapter)
+ def test_change_column_preserve_other_column_precision_and_scale
+ connection.add_column 'test_models', 'last_name', :string
+ connection.add_column 'test_models', 'wealth', :decimal, :precision => 9, :scale => 7
- connection.add_column 'test_models', 'last_name', :string
- connection.add_column 'test_models', 'wealth', :decimal, :precision => 9, :scale => 7
+ wealth_column = TestModel.columns_hash['wealth']
+ assert_equal 9, wealth_column.precision
+ assert_equal 7, wealth_column.scale
- wealth_column = TestModel.columns_hash['wealth']
- assert_equal 9, wealth_column.precision
- assert_equal 7, wealth_column.scale
-
- connection.change_column 'test_models', 'last_name', :string, :null => false
- TestModel.reset_column_information
+ connection.change_column 'test_models', 'last_name', :string, :null => false
+ TestModel.reset_column_information
- wealth_column = TestModel.columns_hash['wealth']
- assert_equal 9, wealth_column.precision
- assert_equal 7, wealth_column.scale
+ wealth_column = TestModel.columns_hash['wealth']
+ assert_equal 9, wealth_column.precision
+ assert_equal 7, wealth_column.scale
+ end
end
def test_native_types
@@ -168,37 +159,17 @@ module ActiveRecord
assert_equal Date, bob.favorite_day.class
end
- # Oracle adapter stores Time or DateTime with timezone value already in _before_type_cast column
- # therefore no timezone change is done afterwards when default timezone is changed
- unless current_adapter?(:OracleAdapter)
- # Test DateTime column and defaults, including timezone.
- # FIXME: moment of truth may be Time on 64-bit platforms.
- if bob.moment_of_truth.is_a?(DateTime)
-
- with_env_tz 'US/Eastern' do
- bob.reload
- assert_equal DateTime.local_offset, bob.moment_of_truth.offset
- assert_not_equal 0, bob.moment_of_truth.offset
- assert_not_equal "Z", bob.moment_of_truth.zone
- # US/Eastern is -5 hours from GMT
- assert_equal Rational(-5, 24), bob.moment_of_truth.offset
- assert_match(/\A-05:00\Z/, bob.moment_of_truth.zone)
- assert_equal DateTime::ITALY, bob.moment_of_truth.start
- end
- end
- end
-
assert_instance_of TrueClass, bob.male?
assert_kind_of BigDecimal, bob.wealth
end
- def test_out_of_range_limit_should_raise
- skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
-
- assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, :limit => 10 }
+ if current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
+ def test_out_of_range_limit_should_raise
+ assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, :limit => 10 }
- unless current_adapter?(:PostgreSQLAdapter)
- assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :integer, :limit => 0xfffffffff }
+ unless current_adapter?(:PostgreSQLAdapter)
+ assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :integer, :limit => 0xfffffffff }
+ end
end
end
end
diff --git a/activerecord/test/cases/migration/column_positioning_test.rb b/activerecord/test/cases/migration/column_positioning_test.rb
index 913d935f7c..87e29e41ba 100644
--- a/activerecord/test/cases/migration/column_positioning_test.rb
+++ b/activerecord/test/cases/migration/column_positioning_test.rb
@@ -9,10 +9,6 @@ module ActiveRecord
def setup
super
- unless current_adapter?(:MysqlAdapter, :Mysql2Adapter)
- skip "not supported on #{connection.class}"
- end
-
@connection = ActiveRecord::Base.connection
connection.create_table :testings, :id => false do |t|
@@ -28,33 +24,34 @@ module ActiveRecord
ActiveRecord::Base.primary_key_prefix_type = nil
end
- def test_column_positioning
- assert_equal %w(first second third), conn.columns(:testings).map {|c| c.name }
- end
+ if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
+ def test_column_positioning
+ assert_equal %w(first second third), conn.columns(:testings).map {|c| c.name }
+ end
- def test_add_column_with_positioning
- conn.add_column :testings, :new_col, :integer
- assert_equal %w(first second third new_col), conn.columns(:testings).map {|c| c.name }
- end
+ def test_add_column_with_positioning
+ conn.add_column :testings, :new_col, :integer
+ assert_equal %w(first second third new_col), conn.columns(:testings).map {|c| c.name }
+ end
- def test_add_column_with_positioning_first
- conn.add_column :testings, :new_col, :integer, :first => true
- assert_equal %w(new_col first second third), conn.columns(:testings).map {|c| c.name }
- end
+ def test_add_column_with_positioning_first
+ conn.add_column :testings, :new_col, :integer, :first => true
+ assert_equal %w(new_col first second third), conn.columns(:testings).map {|c| c.name }
+ end
- def test_add_column_with_positioning_after
- conn.add_column :testings, :new_col, :integer, :after => :first
- assert_equal %w(first new_col second third), conn.columns(:testings).map {|c| c.name }
- end
+ def test_add_column_with_positioning_after
+ conn.add_column :testings, :new_col, :integer, :after => :first
+ assert_equal %w(first new_col second third), conn.columns(:testings).map {|c| c.name }
+ end
- def test_change_column_with_positioning
- conn.change_column :testings, :second, :integer, :first => true
- assert_equal %w(second first third), conn.columns(:testings).map {|c| c.name }
+ def test_change_column_with_positioning
+ conn.change_column :testings, :second, :integer, :first => true
+ assert_equal %w(second first third), conn.columns(:testings).map {|c| c.name }
- conn.change_column :testings, :second, :integer, :after => :third
- assert_equal %w(first third second), conn.columns(:testings).map {|c| c.name }
+ conn.change_column :testings, :second, :integer, :after => :third
+ assert_equal %w(first third second), conn.columns(:testings).map {|c| c.name }
+ end
end
-
end
end
end
diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb
index 2cad8a6d96..35b656ee43 100644
--- a/activerecord/test/cases/migration/command_recorder_test.rb
+++ b/activerecord/test/cases/migration/command_recorder_test.rb
@@ -4,7 +4,8 @@ module ActiveRecord
class Migration
class CommandRecorderTest < ActiveRecord::TestCase
def setup
- @recorder = CommandRecorder.new
+ connection = ActiveRecord::Base.connection
+ @recorder = CommandRecorder.new(connection)
end
def test_respond_to_delegates
@@ -242,6 +243,16 @@ module ActiveRecord
add = @recorder.inverse_of :remove_belongs_to, [:table, :user]
assert_equal [:add_reference, [:table, :user], nil], add
end
+
+ def test_invert_enable_extension
+ disable = @recorder.inverse_of :enable_extension, ['uuid-ossp']
+ assert_equal [:disable_extension, ['uuid-ossp'], nil], disable
+ end
+
+ def test_invert_disable_extension
+ enable = @recorder.inverse_of :disable_extension, ['uuid-ossp']
+ assert_equal [:enable_extension, ['uuid-ossp'], nil], enable
+ end
end
end
end
diff --git a/activerecord/test/cases/migration/index_test.rb b/activerecord/test/cases/migration/index_test.rb
index 0e375af6e8..8d1daa0a04 100644
--- a/activerecord/test/cases/migration/index_test.rb
+++ b/activerecord/test/cases/migration/index_test.rb
@@ -27,32 +27,28 @@ module ActiveRecord
ActiveRecord::Base.primary_key_prefix_type = nil
end
- def test_rename_index
- skip "not supported on openbase" if current_adapter?(:OpenBaseAdapter)
-
- # keep the names short to make Oracle and similar behave
- connection.add_index(table_name, [:foo], :name => 'old_idx')
- connection.rename_index(table_name, 'old_idx', 'new_idx')
-
- # if the adapter doesn't support the indexes call, pick defaults that let the test pass
- assert_not connection.index_name_exists?(table_name, 'old_idx', false)
- assert connection.index_name_exists?(table_name, 'new_idx', true)
- end
-
- def test_double_add_index
- skip "not supported on openbase" if current_adapter?(:OpenBaseAdapter)
+ unless current_adapter?(:OpenBaseAdapter)
+ def test_rename_index
+ # keep the names short to make Oracle and similar behave
+ connection.add_index(table_name, [:foo], :name => 'old_idx')
+ connection.rename_index(table_name, 'old_idx', 'new_idx')
+
+ # if the adapter doesn't support the indexes call, pick defaults that let the test pass
+ assert_not connection.index_name_exists?(table_name, 'old_idx', false)
+ assert connection.index_name_exists?(table_name, 'new_idx', true)
+ end
- connection.add_index(table_name, [:foo], :name => 'some_idx')
- assert_raises(ArgumentError) {
+ def test_double_add_index
connection.add_index(table_name, [:foo], :name => 'some_idx')
- }
- end
-
- def test_remove_nonexistent_index
- skip "not supported on openbase" if current_adapter?(:OpenBaseAdapter)
+ assert_raises(ArgumentError) {
+ connection.add_index(table_name, [:foo], :name => 'some_idx')
+ }
+ end
- # we do this by name, so OpenBase is a wash as noted above
- assert_raise(ArgumentError) { connection.remove_index(table_name, "no_such_index") }
+ def test_remove_nonexistent_index
+ # we do this by name, so OpenBase is a wash as noted above
+ assert_raise(ArgumentError) { connection.remove_index(table_name, "no_such_index") }
+ end
end
def test_add_index_works_with_long_index_names
@@ -109,16 +105,6 @@ module ActiveRecord
end
end
- def test_deprecated_type_argument
- message = "Passing a string as third argument of `add_index` is deprecated and will" +
- " be removed in Rails 4.1." +
- " Use add_index(:testings, [:foo, :bar], unique: true) instead"
-
- assert_deprecated message do
- connection.add_index :testings, [:foo, :bar], "UNIQUE"
- end
- end
-
def test_unique_index_exists
connection.add_index :testings, :foo, :unique => true
@@ -199,14 +185,14 @@ module ActiveRecord
end
end
- def test_add_partial_index
- skip 'only on pg' unless current_adapter?(:PostgreSQLAdapter)
+ if current_adapter?(:PostgreSQLAdapter)
+ def test_add_partial_index
+ connection.add_index("testings", "last_name", :where => "first_name = 'john doe'")
+ assert connection.index_exists?("testings", "last_name")
- connection.add_index("testings", "last_name", :where => "first_name = 'john doe'")
- assert connection.index_exists?("testings", "last_name")
-
- connection.remove_index("testings", "last_name")
- assert !connection.index_exists?("testings", "last_name")
+ connection.remove_index("testings", "last_name")
+ assert !connection.index_exists?("testings", "last_name")
+ end
end
private
diff --git a/activerecord/test/cases/migration/references_index_test.rb b/activerecord/test/cases/migration/references_index_test.rb
index 3ff89524fe..19eb7d3c9e 100644
--- a/activerecord/test/cases/migration/references_index_test.rb
+++ b/activerecord/test/cases/migration/references_index_test.rb
@@ -50,14 +50,14 @@ module ActiveRecord
assert connection.index_exists?(table_name, :bar_id, :name => :index_testings_on_bar_id, :unique => true)
end
- def test_creates_polymorphic_index
- return skip "Oracle Adapter does not support foreign keys if :polymorphic => true is used" if current_adapter? :OracleAdapter
+ unless current_adapter? :OracleAdapter
+ def test_creates_polymorphic_index
+ connection.create_table table_name do |t|
+ t.references :foo, :polymorphic => true, :index => true
+ end
- connection.create_table table_name do |t|
- t.references :foo, :polymorphic => true, :index => true
+ assert connection.index_exists?(table_name, [:foo_id, :foo_type], :name => :index_testings_on_foo_id_and_foo_type)
end
-
- assert connection.index_exists?(table_name, [:foo_id, :foo_type], :name => :index_testings_on_foo_id_and_foo_type)
end
def test_creates_index_for_existing_table
@@ -87,16 +87,16 @@ module ActiveRecord
assert_not connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id)
end
- def test_creates_polymorphic_index_for_existing_table
- return skip "Oracle Adapter does not support foreign keys if :polymorphic => true is used" if current_adapter? :OracleAdapter
- connection.create_table table_name
- connection.change_table table_name do |t|
- t.references :foo, :polymorphic => true, :index => true
- end
+ unless current_adapter? :OracleAdapter
+ def test_creates_polymorphic_index_for_existing_table
+ connection.create_table table_name
+ connection.change_table table_name do |t|
+ t.references :foo, :polymorphic => true, :index => true
+ end
- assert connection.index_exists?(table_name, [:foo_id, :foo_type], :name => :index_testings_on_foo_id_and_foo_type)
+ assert connection.index_exists?(table_name, [:foo_id, :foo_type], :name => :index_testings_on_foo_id_and_foo_type)
+ end
end
-
end
end
end
diff --git a/activerecord/test/cases/migration/rename_table_test.rb b/activerecord/test/cases/migration/rename_table_test.rb
index 22dbd7c38b..2a7fafc559 100644
--- a/activerecord/test/cases/migration/rename_table_test.rb
+++ b/activerecord/test/cases/migration/rename_table_test.rb
@@ -19,24 +19,24 @@ module ActiveRecord
super
end
- def test_rename_table_for_sqlite_should_work_with_reserved_words
- renamed = false
-
- skip "not supported" unless current_adapter?(:SQLite3Adapter)
-
- add_column :test_models, :url, :string
- connection.rename_table :references, :old_references
- connection.rename_table :test_models, :references
-
- renamed = true
-
- # Using explicit id in insert for compatibility across all databases
- connection.execute "INSERT INTO 'references' (url, created_at, updated_at) VALUES ('http://rubyonrails.com', 0, 0)"
- assert_equal 'http://rubyonrails.com', connection.select_value("SELECT url FROM 'references' WHERE id=1")
- ensure
- return unless renamed
- connection.rename_table :references, :test_models
- connection.rename_table :old_references, :references
+ if current_adapter?(:SQLite3Adapter)
+ def test_rename_table_for_sqlite_should_work_with_reserved_words
+ renamed = false
+
+ add_column :test_models, :url, :string
+ connection.rename_table :references, :old_references
+ connection.rename_table :test_models, :references
+
+ renamed = true
+
+ # Using explicit id in insert for compatibility across all databases
+ connection.execute "INSERT INTO 'references' (url, created_at, updated_at) VALUES ('http://rubyonrails.com', 0, 0)"
+ assert_equal 'http://rubyonrails.com', connection.select_value("SELECT url FROM 'references' WHERE id=1")
+ ensure
+ return unless renamed
+ connection.rename_table :references, :test_models
+ connection.rename_table :old_references, :references
+ end
end
def test_rename_table
@@ -76,14 +76,14 @@ module ActiveRecord
assert_equal ['special_url_idx'], connection.indexes(:octopi).map(&:name)
end
- def test_rename_table_for_postgresql_should_also_rename_default_sequence
- skip 'not supported' unless current_adapter?(:PostgreSQLAdapter)
-
- rename_table :test_models, :octopi
+ if current_adapter?(:PostgreSQLAdapter)
+ def test_rename_table_for_postgresql_should_also_rename_default_sequence
+ rename_table :test_models, :octopi
- pk, seq = connection.pk_and_sequence_for('octopi')
+ pk, seq = connection.pk_and_sequence_for('octopi')
- assert_equal "octopi_#{pk}_seq", seq
+ assert_equal "octopi_#{pk}_seq", seq
+ end
end
end
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 193ffb26e3..0363bf1048 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -63,6 +63,7 @@ class MigrationTest < ActiveRecord::TestCase
def test_migrator_versions
migrations_path = MIGRATIONS_ROOT + "/valid"
+ old_path = ActiveRecord::Migrator.migrations_paths
ActiveRecord::Migrator.migrations_paths = migrations_path
ActiveRecord::Migrator.up(migrations_path)
@@ -74,6 +75,12 @@ class MigrationTest < ActiveRecord::TestCase
assert_equal 0, ActiveRecord::Migrator.current_version
assert_equal 3, ActiveRecord::Migrator.last_version
assert_equal true, ActiveRecord::Migrator.needs_migration?
+ ensure
+ ActiveRecord::Migrator.migrations_paths = old_path
+ end
+
+ def test_migration_version
+ ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/version_check", 20131219224947)
end
def test_create_table_with_force_true_does_not_drop_nonexisting_table
@@ -177,20 +184,18 @@ class MigrationTest < ActiveRecord::TestCase
end
def test_filtering_migrations
- assert !Person.column_methods_hash.include?(:last_name)
+ assert_no_column Person, :last_name
assert !Reminder.table_exists?
name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" }
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", &name_filter)
- Person.reset_column_information
- assert Person.column_methods_hash.include?(:last_name)
+ assert_column Person, :last_name
assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", &name_filter)
- Person.reset_column_information
- assert !Person.column_methods_hash.include?(:last_name)
+ assert_no_column Person, :last_name
assert_raise(ActiveRecord::StatementInvalid) { Reminder.first }
end
@@ -232,106 +237,110 @@ class MigrationTest < ActiveRecord::TestCase
assert migration.went_down, 'have not gone down'
end
- def test_migrator_one_up_with_exception_and_rollback
- unless ActiveRecord::Base.connection.supports_ddl_transactions?
- skip "not supported on #{ActiveRecord::Base.connection.class}"
- end
-
- assert_not Person.column_methods_hash.include?(:last_name)
+ if ActiveRecord::Base.connection.supports_ddl_transactions?
+ def test_migrator_one_up_with_exception_and_rollback
+ assert_no_column Person, :last_name
- migration = Class.new(ActiveRecord::Migration) {
- def version; 100 end
- def migrate(x)
- add_column "people", "last_name", :string
- raise 'Something broke'
- end
- }.new
+ migration = Class.new(ActiveRecord::Migration) {
+ def version; 100 end
+ def migrate(x)
+ add_column "people", "last_name", :string
+ raise 'Something broke'
+ end
+ }.new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
- e = assert_raise(StandardError) { migrator.migrate }
+ e = assert_raise(StandardError) { migrator.migrate }
- assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message
+ assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message
- Person.reset_column_information
- assert_not Person.column_methods_hash.include?(:last_name),
- "On error, the Migrator should revert schema changes but it did not."
- end
-
- def test_migrator_one_up_with_exception_and_rollback_using_run
- unless ActiveRecord::Base.connection.supports_ddl_transactions?
- skip "not supported on #{ActiveRecord::Base.connection.class}"
+ assert_no_column Person, :last_name,
+ "On error, the Migrator should revert schema changes but it did not."
end
- assert_not Person.column_methods_hash.include?(:last_name)
-
- migration = Class.new(ActiveRecord::Migration) {
- def version; 100 end
- def migrate(x)
- add_column "people", "last_name", :string
- raise 'Something broke'
- end
- }.new
+ def test_migrator_one_up_with_exception_and_rollback_using_run
+ assert_no_column Person, :last_name
- migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
+ migration = Class.new(ActiveRecord::Migration) {
+ def version; 100 end
+ def migrate(x)
+ add_column "people", "last_name", :string
+ raise 'Something broke'
+ end
+ }.new
- e = assert_raise(StandardError) { migrator.run }
+ migrator = ActiveRecord::Migrator.new(:up, [migration], 100)
- assert_equal "An error has occurred, this migration was canceled:\n\nSomething broke", e.message
+ e = assert_raise(StandardError) { migrator.run }
- Person.reset_column_information
- assert_not Person.column_methods_hash.include?(:last_name),
- "On error, the Migrator should revert schema changes but it did not."
- end
+ assert_equal "An error has occurred, this migration was canceled:\n\nSomething broke", e.message
- def test_migration_without_transaction
- unless ActiveRecord::Base.connection.supports_ddl_transactions?
- skip "not supported on #{ActiveRecord::Base.connection.class}"
+ assert_no_column Person, :last_name,
+ "On error, the Migrator should revert schema changes but it did not."
end
- assert_not Person.column_methods_hash.include?(:last_name)
+ def test_migration_without_transaction
+ assert_no_column Person, :last_name
- migration = Class.new(ActiveRecord::Migration) {
- self.disable_ddl_transaction!
+ migration = Class.new(ActiveRecord::Migration) {
+ self.disable_ddl_transaction!
- def version; 101 end
- def migrate(x)
- add_column "people", "last_name", :string
- raise 'Something broke'
- end
- }.new
+ def version; 101 end
+ def migrate(x)
+ add_column "people", "last_name", :string
+ raise 'Something broke'
+ end
+ }.new
- migrator = ActiveRecord::Migrator.new(:up, [migration], 101)
- e = assert_raise(StandardError) { migrator.migrate }
- assert_equal "An error has occurred, all later migrations canceled:\n\nSomething broke", e.message
+ migrator = ActiveRecord::Migrator.new(:up, [migration], 101)
+ e = assert_raise(StandardError) { migrator.migrate }
+ assert_equal "An error has occurred, all later migrations canceled:\n\nSomething broke", e.message
- Person.reset_column_information
- assert Person.column_methods_hash.include?(:last_name),
- "without ddl transactions, the Migrator should not rollback on error but it did."
- ensure
- Person.reset_column_information
- if Person.column_methods_hash.include?(:last_name)
- Person.connection.remove_column('people', 'last_name')
+ assert_column Person, :last_name,
+ "without ddl transactions, the Migrator should not rollback on error but it did."
+ ensure
+ Person.reset_column_information
+ if Person.column_names.include?('last_name')
+ Person.connection.remove_column('people', 'last_name')
+ end
end
end
def test_schema_migrations_table_name
+ original_schema_migrations_table_name = ActiveRecord::Migrator.schema_migrations_table_name
+
+ assert_equal "schema_migrations", ActiveRecord::Migrator.schema_migrations_table_name
ActiveRecord::Base.table_name_prefix = "prefix_"
ActiveRecord::Base.table_name_suffix = "_suffix"
Reminder.reset_table_name
assert_equal "prefix_schema_migrations_suffix", ActiveRecord::Migrator.schema_migrations_table_name
+ ActiveRecord::Base.schema_migrations_table_name = "changed"
+ Reminder.reset_table_name
+ assert_equal "prefix_changed_suffix", ActiveRecord::Migrator.schema_migrations_table_name
ActiveRecord::Base.table_name_prefix = ""
ActiveRecord::Base.table_name_suffix = ""
Reminder.reset_table_name
- assert_equal "schema_migrations", ActiveRecord::Migrator.schema_migrations_table_name
+ assert_equal "changed", ActiveRecord::Migrator.schema_migrations_table_name
+ ensure
+ ActiveRecord::Base.schema_migrations_table_name = original_schema_migrations_table_name
+ Reminder.reset_table_name
end
- def test_proper_table_name
- assert_equal "table", ActiveRecord::Migrator.proper_table_name('table')
- assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table)
- assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder)
+ def test_proper_table_name_on_migrator
+ assert_deprecated do
+ assert_equal "table", ActiveRecord::Migrator.proper_table_name('table')
+ end
+ assert_deprecated do
+ assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table)
+ end
+ assert_deprecated do
+ assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder)
+ end
Reminder.reset_table_name
- assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder)
+ assert_deprecated do
+ assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder)
+ end
# Use the model's own prefix/suffix if a model is given
ActiveRecord::Base.table_name_prefix = "ARprefix_"
@@ -339,7 +348,9 @@ class MigrationTest < ActiveRecord::TestCase
Reminder.table_name_prefix = 'prefix_'
Reminder.table_name_suffix = '_suffix'
Reminder.reset_table_name
- assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder)
+ assert_deprecated do
+ assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder)
+ end
Reminder.table_name_prefix = ''
Reminder.table_name_suffix = ''
Reminder.reset_table_name
@@ -348,8 +359,39 @@ class MigrationTest < ActiveRecord::TestCase
ActiveRecord::Base.table_name_prefix = "prefix_"
ActiveRecord::Base.table_name_suffix = "_suffix"
Reminder.reset_table_name
- assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table')
- assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table)
+ assert_deprecated do
+ assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table')
+ end
+ assert_deprecated do
+ assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table)
+ end
+ end
+
+ def test_proper_table_name_on_migration
+ migration = ActiveRecord::Migration.new
+ assert_equal "table", migration.proper_table_name('table')
+ assert_equal "table", migration.proper_table_name(:table)
+ assert_equal "reminders", migration.proper_table_name(Reminder)
+ Reminder.reset_table_name
+ assert_equal Reminder.table_name, migration.proper_table_name(Reminder)
+
+ # Use the model's own prefix/suffix if a model is given
+ ActiveRecord::Base.table_name_prefix = "ARprefix_"
+ ActiveRecord::Base.table_name_suffix = "_ARsuffix"
+ Reminder.table_name_prefix = 'prefix_'
+ Reminder.table_name_suffix = '_suffix'
+ Reminder.reset_table_name
+ assert_equal "prefix_reminders_suffix", migration.proper_table_name(Reminder)
+ Reminder.table_name_prefix = ''
+ Reminder.table_name_suffix = ''
+ Reminder.reset_table_name
+
+ # Use AR::Base's prefix/suffix if string or symbol is given
+ ActiveRecord::Base.table_name_prefix = "prefix_"
+ ActiveRecord::Base.table_name_suffix = "_suffix"
+ Reminder.reset_table_name
+ assert_equal "prefix_table_suffix", migration.proper_table_name('table', migration.table_name_options)
+ assert_equal "prefix_table_suffix", migration.proper_table_name(:table, migration.table_name_options)
end
def test_rename_table_with_prefix_and_suffix
@@ -405,62 +447,88 @@ class MigrationTest < ActiveRecord::TestCase
Person.connection.drop_table :binary_testings rescue nil
end
- def test_create_table_with_custom_sequence_name
- skip "not supported" unless current_adapter? :OracleAdapter
+ def test_create_table_with_query
+ Person.connection.drop_table :table_from_query_testings rescue nil
+ Person.connection.create_table(:person, force: true)
- # table name is 29 chars, the standard sequence name will
- # be 33 chars and should be shortened
- assert_nothing_raised do
- begin
- Person.connection.create_table :table_with_name_thats_just_ok do |t|
- t.column :foo, :string, :null => false
+ Person.connection.create_table :table_from_query_testings, as: "SELECT id FROM person"
+
+ columns = Person.connection.columns(:table_from_query_testings)
+ assert_equal 1, columns.length
+ assert_equal "id", columns.first.name
+
+ Person.connection.drop_table :table_from_query_testings rescue nil
+ end
+
+ def test_create_table_with_query_from_relation
+ Person.connection.drop_table :table_from_query_testings rescue nil
+ Person.connection.create_table(:person, force: true)
+
+ Person.connection.create_table :table_from_query_testings, as: Person.select(:id)
+
+ columns = Person.connection.columns(:table_from_query_testings)
+ assert_equal 1, columns.length
+ assert_equal "id", columns.first.name
+
+ Person.connection.drop_table :table_from_query_testings rescue nil
+ end
+
+ if current_adapter? :OracleAdapter
+ def test_create_table_with_custom_sequence_name
+ # table name is 29 chars, the standard sequence name will
+ # be 33 chars and should be shortened
+ assert_nothing_raised do
+ begin
+ Person.connection.create_table :table_with_name_thats_just_ok do |t|
+ t.column :foo, :string, :null => false
+ end
+ ensure
+ Person.connection.drop_table :table_with_name_thats_just_ok rescue nil
end
- ensure
- Person.connection.drop_table :table_with_name_thats_just_ok rescue nil
end
- end
- # should be all good w/ a custom sequence name
- assert_nothing_raised do
- begin
- Person.connection.create_table :table_with_name_thats_just_ok,
- :sequence_name => 'suitably_short_seq' do |t|
- t.column :foo, :string, :null => false
- end
+ # should be all good w/ a custom sequence name
+ assert_nothing_raised do
+ begin
+ Person.connection.create_table :table_with_name_thats_just_ok,
+ :sequence_name => 'suitably_short_seq' do |t|
+ t.column :foo, :string, :null => false
+ end
- Person.connection.execute("select suitably_short_seq.nextval from dual")
+ Person.connection.execute("select suitably_short_seq.nextval from dual")
- ensure
- Person.connection.drop_table :table_with_name_thats_just_ok,
- :sequence_name => 'suitably_short_seq' rescue nil
+ ensure
+ Person.connection.drop_table :table_with_name_thats_just_ok,
+ :sequence_name => 'suitably_short_seq' rescue nil
+ end
end
- end
- # confirm the custom sequence got dropped
- assert_raise(ActiveRecord::StatementInvalid) do
- Person.connection.execute("select suitably_short_seq.nextval from dual")
+ # confirm the custom sequence got dropped
+ assert_raise(ActiveRecord::StatementInvalid) do
+ Person.connection.execute("select suitably_short_seq.nextval from dual")
+ end
end
end
- def test_out_of_range_limit_should_raise
- skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
-
- Person.connection.drop_table :test_limits rescue nil
- assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do
- Person.connection.create_table :test_integer_limits, :force => true do |t|
- t.column :bigone, :integer, :limit => 10
+ if current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
+ def test_out_of_range_limit_should_raise
+ Person.connection.drop_table :test_limits rescue nil
+ assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do
+ Person.connection.create_table :test_integer_limits, :force => true do |t|
+ t.column :bigone, :integer, :limit => 10
+ end
end
- end
- unless current_adapter?(:PostgreSQLAdapter)
- assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do
- Person.connection.create_table :test_text_limits, :force => true do |t|
- t.column :bigtext, :text, :limit => 0xfffffffff
+ unless current_adapter?(:PostgreSQLAdapter)
+ assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do
+ Person.connection.create_table :test_text_limits, :force => true do |t|
+ t.column :bigtext, :text, :limit => 0xfffffffff
+ end
end
end
- end
- Person.connection.drop_table :test_limits rescue nil
+ Person.connection.drop_table :test_limits rescue nil
+ end
end
protected
@@ -665,8 +733,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase
@existing_migrations = Dir[@migrations_path + "/*.rb"]
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
- assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
- assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
+ assert File.exist?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
+ assert File.exist?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
assert_equal [@migrations_path + "/4_people_have_hobbies.bukkits.rb", @migrations_path + "/5_people_have_descriptions.bukkits.rb"], copied.map(&:filename)
expected = "# This migration comes from bukkits (originally 1)"
@@ -689,10 +757,10 @@ class CopyMigrationsTest < ActiveRecord::TestCase
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy"
sources[:omg] = MIGRATIONS_ROOT + "/to_copy2"
ActiveRecord::Migration.copy(@migrations_path, sources)
- assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
- assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
- assert File.exists?(@migrations_path + "/6_create_articles.omg.rb")
- assert File.exists?(@migrations_path + "/7_create_comments.omg.rb")
+ assert File.exist?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
+ assert File.exist?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
+ assert File.exist?(@migrations_path + "/6_create_articles.omg.rb")
+ assert File.exist?(@migrations_path + "/7_create_comments.omg.rb")
files_count = Dir[@migrations_path + "/*.rb"].length
ActiveRecord::Migration.copy(@migrations_path, sources)
@@ -705,10 +773,10 @@ class CopyMigrationsTest < ActiveRecord::TestCase
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
@existing_migrations = Dir[@migrations_path + "/*.rb"]
- Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
+ travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
- assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
- assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
expected = [@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb",
@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb"]
assert_equal expected, copied.map(&:filename)
@@ -730,12 +798,12 @@ class CopyMigrationsTest < ActiveRecord::TestCase
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps2"
- Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
+ travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
copied = ActiveRecord::Migration.copy(@migrations_path, sources)
- assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
- assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
- assert File.exists?(@migrations_path + "/20100726101012_create_articles.omg.rb")
- assert File.exists?(@migrations_path + "/20100726101013_create_comments.omg.rb")
+ assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100726101012_create_articles.omg.rb")
+ assert File.exist?(@migrations_path + "/20100726101013_create_comments.omg.rb")
assert_equal 4, copied.length
files_count = Dir[@migrations_path + "/*.rb"].length
@@ -750,10 +818,10 @@ class CopyMigrationsTest < ActiveRecord::TestCase
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
@existing_migrations = Dir[@migrations_path + "/*.rb"]
- Time.travel_to(Time.utc(2010, 2, 20, 10, 10, 10)) do
+ travel_to(Time.utc(2010, 2, 20, 10, 10, 10)) do
ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
- assert File.exists?(@migrations_path + "/20100301010102_people_have_hobbies.bukkits.rb")
- assert File.exists?(@migrations_path + "/20100301010103_people_have_descriptions.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100301010102_people_have_hobbies.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100301010103_people_have_descriptions.bukkits.rb")
files_count = Dir[@migrations_path + "/*.rb"].length
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
@@ -770,7 +838,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase
@existing_migrations = Dir[@migrations_path + "/*.rb"]
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/magic"})
- assert File.exists?(@migrations_path + "/4_currencies_have_symbols.bukkits.rb")
+ assert File.exist?(@migrations_path + "/4_currencies_have_symbols.bukkits.rb")
assert_equal [@migrations_path + "/4_currencies_have_symbols.bukkits.rb"], copied.map(&:filename)
expected = "# coding: ISO-8859-15\n# This migration comes from bukkits (originally 1)"
@@ -825,10 +893,10 @@ class CopyMigrationsTest < ActiveRecord::TestCase
@migrations_path = MIGRATIONS_ROOT + "/non_existing"
@existing_migrations = []
- Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
+ travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
- assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
- assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
assert_equal 2, copied.length
end
ensure
@@ -840,13 +908,22 @@ class CopyMigrationsTest < ActiveRecord::TestCase
@migrations_path = MIGRATIONS_ROOT + "/empty"
@existing_migrations = []
- Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
+ travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
- assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
- assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
+ assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
assert_equal 2, copied.length
end
ensure
clear
end
+
+ def test_check_pending_with_stdlib_logger
+ old, ActiveRecord::Base.logger = ActiveRecord::Base.logger, ::Logger.new($stdout)
+ quietly do
+ assert_nothing_raised { ActiveRecord::Migration::CheckPending.new(Proc.new {}).call({}) }
+ end
+ ensure
+ ActiveRecord::Base.logger = old
+ end
end
diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb
index b5a69c4a92..3f9854200d 100644
--- a/activerecord/test/cases/migrator_test.rb
+++ b/activerecord/test/cases/migrator_test.rb
@@ -91,12 +91,6 @@ module ActiveRecord
assert_equal 'AddExpressions', migrations[0].name
end
- def test_deprecated_constructor
- assert_deprecated do
- ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid")
- end
- end
-
def test_relative_migrations
list = Dir.chdir(MIGRATIONS_ROOT) do
ActiveRecord::Migrator.migrations("valid/")
diff --git a/activerecord/test/cases/mixin_test.rb b/activerecord/test/cases/mixin_test.rb
index f927c13979..ad0d5cce27 100644
--- a/activerecord/test/cases/mixin_test.rb
+++ b/activerecord/test/cases/mixin_test.rb
@@ -3,42 +3,11 @@ 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
+ travel_to Time.now
end
def test_update
@@ -68,12 +37,13 @@ class TouchTest < ActiveRecord::TestCase
old_updated_at = stamped.updated_at
- Time.forced_now_time = 5.minutes.from_now
- stamped.lft_will_change!
- stamped.save
+ travel 5.minutes do
+ stamped.lft_will_change!
+ stamped.save
- assert_equal Time.now, stamped.updated_at
- assert_equal old_updated_at, stamped.created_at
+ assert_equal Time.now, stamped.updated_at
+ assert_equal old_updated_at, stamped.created_at
+ end
end
def test_create_turned_off
diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb
index 08b3408665..9124105e6d 100644
--- a/activerecord/test/cases/modules_test.rb
+++ b/activerecord/test/cases/modules_test.rb
@@ -1,6 +1,7 @@
require "cases/helper"
require 'models/company_in_module'
require 'models/shop'
+require 'models/developer'
class ModulesTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :projects, :developers, :collections, :products, :variants
diff --git a/activerecord/test/cases/multiparameter_attributes_test.rb b/activerecord/test/cases/multiparameter_attributes_test.rb
index 1209f5460f..c70a8f296f 100644
--- a/activerecord/test/cases/multiparameter_attributes_test.rb
+++ b/activerecord/test/cases/multiparameter_attributes_test.rb
@@ -5,12 +5,6 @@ require 'models/customer'
class MultiParameterAttributeTest < ActiveRecord::TestCase
fixtures :topics
- def setup
- ActiveRecord::Base.time_zone_aware_attributes = false
- ActiveRecord::Base.default_timezone = :local
- Time.zone = nil
- end
-
def test_multiparameter_attributes_on_date
attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" }
topic = Topic.find(1)
@@ -82,13 +76,15 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
end
def test_multiparameter_attributes_on_time
- attributes = {
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
- }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
+ with_timezone_config default: :local do
+ attributes = {
+ "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
+ "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
+ end
end
def test_multiparameter_attributes_on_time_with_no_date
@@ -148,13 +144,15 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
end
def test_multiparameter_attributes_on_time_will_ignore_hour_if_missing
- attributes = {
- "written_on(1i)" => "2004", "written_on(2i)" => "12", "written_on(3i)" => "12",
- "written_on(5i)" => "12", "written_on(6i)" => "02"
- }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.local(2004, 12, 12, 0, 12, 2), topic.written_on
+ with_timezone_config default: :local do
+ attributes = {
+ "written_on(1i)" => "2004", "written_on(2i)" => "12", "written_on(3i)" => "12",
+ "written_on(5i)" => "12", "written_on(6i)" => "02"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.local(2004, 12, 12, 0, 12, 2), topic.written_on
+ end
end
def test_multiparameter_attributes_on_time_will_ignore_hour_if_blank
@@ -176,6 +174,7 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
topic.attributes = attributes
assert_nil topic.written_on
end
+
def test_multiparameter_attributes_on_time_with_seconds_will_ignore_date_if_empty
attributes = {
"written_on(1i)" => "", "written_on(2i)" => "", "written_on(3i)" => "",
@@ -187,56 +186,56 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
end
def test_multiparameter_attributes_on_time_with_utc
- ActiveRecord::Base.default_timezone = :utc
- attributes = {
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
- }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
+ with_timezone_config default: :utc do
+ attributes = {
+ "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
+ "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
+ end
end
def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
- Time.zone = ActiveSupport::TimeZone[-28800]
- attributes = {
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
- }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.utc(2004, 6, 24, 23, 24, 0), topic.written_on
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on.time
- assert_equal Time.zone, topic.written_on.time_zone
+ with_timezone_config default: :utc, aware_attributes: true, zone: -28800 do
+ attributes = {
+ "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
+ "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.utc(2004, 6, 24, 23, 24, 0), topic.written_on
+ assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on.time
+ assert_equal Time.zone, topic.written_on.time_zone
+ end
end
def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes_false
- Time.zone = ActiveSupport::TimeZone[-28800]
- attributes = {
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
- }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
- assert_equal false, topic.written_on.respond_to?(:time_zone)
+ with_timezone_config default: :local, aware_attributes: false, zone: -28800 do
+ attributes = {
+ "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
+ "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
+ assert_equal false, topic.written_on.respond_to?(:time_zone)
+ end
end
def test_multiparameter_attributes_on_time_with_skip_time_zone_conversion_for_attributes
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
- Time.zone = ActiveSupport::TimeZone[-28800]
- Topic.skip_time_zone_conversion_for_attributes = [:written_on]
- attributes = {
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
- }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
- assert_equal false, topic.written_on.respond_to?(:time_zone)
+ with_timezone_config default: :utc, aware_attributes: true, zone: -28800 do
+ Topic.skip_time_zone_conversion_for_attributes = [:written_on]
+ attributes = {
+ "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
+ "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
+ assert_equal false, topic.written_on.respond_to?(:time_zone)
+ end
ensure
Topic.skip_time_zone_conversion_for_attributes = []
end
@@ -244,36 +243,37 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
# Oracle, and Sybase do not have a TIME datatype.
unless current_adapter?(:OracleAdapter, :SybaseAdapter)
def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
- Time.zone = ActiveSupport::TimeZone[-28800]
+ with_timezone_config default: :utc, aware_attributes: true, zone: -28800 do
+ attributes = {
+ "bonus_time(1i)" => "2000", "bonus_time(2i)" => "1", "bonus_time(3i)" => "1",
+ "bonus_time(4i)" => "16", "bonus_time(5i)" => "24"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.utc(2000, 1, 1, 16, 24, 0), topic.bonus_time
+ assert topic.bonus_time.utc?
+ end
+ end
+ end
+
+ def test_multiparameter_attributes_on_time_with_empty_seconds
+ with_timezone_config default: :local do
attributes = {
- "bonus_time(1i)" => "2000", "bonus_time(2i)" => "1", "bonus_time(3i)" => "1",
- "bonus_time(4i)" => "16", "bonus_time(5i)" => "24"
+ "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
+ "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => ""
}
topic = Topic.find(1)
topic.attributes = attributes
- assert_equal Time.utc(2000, 1, 1, 16, 24, 0), topic.bonus_time
- assert topic.bonus_time.utc?
+ assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
end
end
- def test_multiparameter_attributes_on_time_with_empty_seconds
- attributes = {
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => ""
- }
- topic = Topic.find(1)
- topic.attributes = attributes
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
- end
-
- def test_multiparameter_attributes_setting_time_attribute
- return skip "Oracle does not have TIME data type" if current_adapter? :OracleAdapter
-
- topic = Topic.new( "bonus_time(4i)"=> "01", "bonus_time(5i)" => "05" )
- assert_equal 1, topic.bonus_time.hour
- assert_equal 5, topic.bonus_time.min
+ unless current_adapter? :OracleAdapter
+ def test_multiparameter_attributes_setting_time_attribute
+ topic = Topic.new( "bonus_time(4i)"=> "01", "bonus_time(5i)" => "05" )
+ assert_equal 1, topic.bonus_time.hour
+ assert_equal 5, topic.bonus_time.min
+ end
end
def test_multiparameter_attributes_setting_date_attribute
diff --git a/activerecord/test/cases/multiple_db_test.rb b/activerecord/test/cases/multiple_db_test.rb
index 2e386a172a..3831de6ae3 100644
--- a/activerecord/test/cases/multiple_db_test.rb
+++ b/activerecord/test/cases/multiple_db_test.rb
@@ -101,7 +101,7 @@ class MultipleDbTest < ActiveRecord::TestCase
College.first.courses.first
end
ensure
- ActiveRecord::Base.establish_connection 'arunit'
+ ActiveRecord::Base.establish_connection :arunit
end
end
end
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index 6fe81e0d96..2f89699df7 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -797,26 +797,6 @@ module NestedAttributesOnACollectionAssociationTests
end
end
- def test_validate_presence_of_parent_fails_without_inverse_of
- Man.accepts_nested_attributes_for(:interests)
- Man.reflect_on_association(:interests).options.delete(:inverse_of)
- Man.reflect_on_association(:interests).clear_inverse_of_cache!
- Interest.reflect_on_association(:man).options.delete(:inverse_of)
- Interest.reflect_on_association(:man).clear_inverse_of_cache!
-
- repair_validations(Interest) do
- Interest.validates_presence_of(:man)
- assert_no_difference ['Man.count', 'Interest.count'] do
- man = Man.create(:name => 'John',
- :interests_attributes => [{:topic=>'Cars'}, {:topic=>'Sports'}])
- assert !man.errors[:"interests.man"].empty?
- end
- end
- ensure
- Man.reflect_on_association(:interests).options[:inverse_of] = :man
- Interest.reflect_on_association(:man).options[:inverse_of] = :interests
- end
-
def test_can_use_symbols_as_object_identifier
@pirate.attributes = { :parrots_attributes => { :foo => { :name => 'Lovely Day' }, :bar => { :name => 'Blown Away' } } }
assert_nothing_raised(NoMethodError) { @pirate.save! }
diff --git a/activerecord/test/cases/nested_attributes_with_callbacks_test.rb b/activerecord/test/cases/nested_attributes_with_callbacks_test.rb
new file mode 100644
index 0000000000..43a69928b6
--- /dev/null
+++ b/activerecord/test/cases/nested_attributes_with_callbacks_test.rb
@@ -0,0 +1,144 @@
+require "cases/helper"
+require "models/pirate"
+require "models/bird"
+
+class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase
+ Pirate.has_many(:birds_with_add_load,
+ :class_name => "Bird",
+ :before_add => proc { |p,b|
+ @@add_callback_called << b
+ p.birds_with_add_load.to_a
+ })
+ Pirate.has_many(:birds_with_add,
+ :class_name => "Bird",
+ :before_add => proc { |p,b| @@add_callback_called << b })
+
+ Pirate.accepts_nested_attributes_for(:birds_with_add_load,
+ :birds_with_add,
+ :allow_destroy => true)
+
+ def setup
+ @@add_callback_called = []
+ @pirate = Pirate.new.tap do |pirate|
+ pirate.catchphrase = "Don't call me!"
+ pirate.birds_attributes = [{:name => 'Bird1'},{:name => 'Bird2'}]
+ pirate.save!
+ end
+ @birds = @pirate.birds.to_a
+ end
+
+ def bird_to_update
+ @birds[0]
+ end
+
+ def bird_to_destroy
+ @birds[1]
+ end
+
+ def existing_birds_attributes
+ @birds.map do |bird|
+ bird.attributes.slice("id","name")
+ end
+ end
+
+ def new_birds
+ @pirate.birds_with_add.to_a - @birds
+ end
+
+ def new_bird_attributes
+ [{'name' => "New Bird"}]
+ end
+
+ def destroy_bird_attributes
+ [{'id' => bird_to_destroy.id.to_s, "_destroy" => true}]
+ end
+
+ def update_new_and_destroy_bird_attributes
+ [{'id' => @birds[0].id.to_s, 'name' => 'New Name'},
+ {'name' => "New Bird"},
+ {'id' => bird_to_destroy.id.to_s, "_destroy" => true}]
+ end
+
+ # Characterizing when :before_add callback is called
+ test ":before_add called for new bird when not loaded" do
+ assert_not @pirate.birds_with_add.loaded?
+ @pirate.birds_with_add_attributes = new_bird_attributes
+ assert_new_bird_with_callback_called
+ end
+
+ test ":before_add called for new bird when loaded" do
+ @pirate.birds_with_add.load_target
+ @pirate.birds_with_add_attributes = new_bird_attributes
+ assert_new_bird_with_callback_called
+ end
+
+ def assert_new_bird_with_callback_called
+ assert_equal(1, new_birds.size)
+ assert_equal(new_birds, @@add_callback_called)
+ end
+
+ test ":before_add not called for identical assignment when not loaded" do
+ assert_not @pirate.birds_with_add.loaded?
+ @pirate.birds_with_add_attributes = existing_birds_attributes
+ assert_callbacks_not_called
+ end
+
+ test ":before_add not called for identical assignment when loaded" do
+ @pirate.birds_with_add.load_target
+ @pirate.birds_with_add_attributes = existing_birds_attributes
+ assert_callbacks_not_called
+ end
+
+ test ":before_add not called for destroy assignment when not loaded" do
+ assert_not @pirate.birds_with_add.loaded?
+ @pirate.birds_with_add_attributes = destroy_bird_attributes
+ assert_callbacks_not_called
+ end
+
+ test ":before_add not called for deletion assignment when loaded" do
+ @pirate.birds_with_add.load_target
+ @pirate.birds_with_add_attributes = destroy_bird_attributes
+ assert_callbacks_not_called
+ end
+
+ def assert_callbacks_not_called
+ assert_empty new_birds
+ assert_empty @@add_callback_called
+ end
+
+ # Ensuring that the records in the association target are updated,
+ # whether the association is loaded before or not
+ test "Assignment updates records in target when not loaded" do
+ assert_not @pirate.birds_with_add.loaded?
+ @pirate.birds_with_add_attributes = update_new_and_destroy_bird_attributes
+ assert_assignment_affects_records_in_target(:birds_with_add)
+ end
+
+ test "Assignment updates records in target when loaded" do
+ @pirate.birds_with_add.load_target
+ @pirate.birds_with_add_attributes = update_new_and_destroy_bird_attributes
+ assert_assignment_affects_records_in_target(:birds_with_add)
+ end
+
+ test("Assignment updates records in target when not loaded" +
+ " and callback loads target") do
+ assert_not @pirate.birds_with_add_load.loaded?
+ @pirate.birds_with_add_load_attributes = update_new_and_destroy_bird_attributes
+ assert_assignment_affects_records_in_target(:birds_with_add_load)
+ end
+
+ test("Assignment updates records in target when loaded" +
+ " and callback loads target") do
+ @pirate.birds_with_add_load.load_target
+ @pirate.birds_with_add_load_attributes = update_new_and_destroy_bird_attributes
+ assert_assignment_affects_records_in_target(:birds_with_add_load)
+ end
+
+ def assert_assignment_affects_records_in_target(association_name)
+ association = @pirate.send(association_name)
+ assert association.detect {|b| b == bird_to_update }.name_changed?,
+ 'Update record not updated'
+ assert association.detect {|b| b == bird_to_destroy }.marked_for_destruction?,
+ 'Destroy record not marked for destruction'
+ end
+end
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index c4a72ed3bc..6f1e518f45 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -139,6 +139,33 @@ class PersistenceTest < ActiveRecord::TestCase
end
end
+ def test_becomes
+ assert_kind_of Reply, topics(:first).becomes(Reply)
+ assert_equal "The First Topic", topics(:first).becomes(Reply).title
+ end
+
+ def test_becomes_includes_errors
+ company = Company.new(:name => nil)
+ assert !company.valid?
+ original_errors = company.errors
+ client = company.becomes(Client)
+ assert_equal original_errors, client.errors
+ end
+
+ def test_dupd_becomes_persists_changes_from_the_original
+ original = topics(:first)
+ copy = original.dup.becomes(Reply)
+ copy.save!
+ assert_equal "The First Topic", Topic.find(copy.id).title
+ end
+
+ def test_becomes_includes_changed_attributes
+ company = Company.new(name: "37signals")
+ client = company.becomes(Client)
+ assert_equal "37signals", client.name
+ assert_equal %w{name}, client.changed
+ end
+
def test_delete_many
original_count = Topic.count
Topic.delete(deleting = [1, 2])
@@ -406,10 +433,6 @@ class PersistenceTest < ActiveRecord::TestCase
assert !Topic.find(1).approved?
end
- def test_update_attribute_does_not_choke_on_nil
- assert Topic.find(1).update(nil)
- end
-
def test_update_attribute_for_readonly_attribute
minivan = Minivan.find('m1')
assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
@@ -688,6 +711,17 @@ class PersistenceTest < ActiveRecord::TestCase
assert_equal topic.title, Topic.find(1234).title
end
+ def test_update_attributes_parameters
+ topic = Topic.find(1)
+ assert_nothing_raised do
+ topic.update_attributes({})
+ end
+
+ assert_raises(ArgumentError) do
+ topic.update_attributes(nil)
+ end
+ end
+
def test_update!
Reply.validates_presence_of(:title)
reply = Reply.find(2)
diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb
index a8a9b06ec4..626c6aeaf8 100644
--- a/activerecord/test/cases/pooled_connections_test.rb
+++ b/activerecord/test/cases/pooled_connections_test.rb
@@ -16,22 +16,6 @@ class PooledConnectionsTest < ActiveRecord::TestCase
@per_test_teardown.each {|td| td.call }
end
- def checkout_connections
- ActiveRecord::Base.establish_connection(@connection.merge({:pool => 2, :checkout_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
def checkout_checkin_connections(pool_size, threads)
ActiveRecord::Base.establish_connection(@connection.merge({:pool => pool_size, :checkout_timeout => 0.5}))
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index aa125c70c5..1b915387be 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -185,19 +185,19 @@ end
class PrimaryKeyWithNoConnectionTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
- def test_set_primary_key_with_no_connection
- return skip("disconnect wipes in-memory db") if in_memory_db?
+ unless in_memory_db?
+ def test_set_primary_key_with_no_connection
+ connection = ActiveRecord::Base.remove_connection
- connection = ActiveRecord::Base.remove_connection
+ model = Class.new(ActiveRecord::Base)
+ model.primary_key = 'foo'
- model = Class.new(ActiveRecord::Base)
- model.primary_key = 'foo'
+ assert_equal 'foo', model.primary_key
- assert_equal 'foo', model.primary_key
+ ActiveRecord::Base.establish_connection(connection)
- ActiveRecord::Base.establish_connection(connection)
-
- assert_equal 'foo', model.primary_key
+ assert_equal 'foo', model.primary_key
+ end
end
end
@@ -212,7 +212,6 @@ if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
ensure
con.reconnect!
end
-
end
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 136fda664c..5566563116 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -134,6 +134,15 @@ class QueryCacheTest < ActiveRecord::TestCase
end
end
+ def test_find_queries_with_multi_cache_blocks
+ Task.cache do
+ Task.cache do
+ assert_queries(2) { Task.find(1); Task.find(2) }
+ end
+ assert_queries(0) { Task.find(1); Task.find(1); Task.find(2) }
+ end
+ end
+
def test_count_queries_with_cache
Task.cache do
assert_queries(1) { Task.count; Task.count }
diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb
index 3dd11ae89d..e2439b9a24 100644
--- a/activerecord/test/cases/quoting_test.rb
+++ b/activerecord/test/cases/quoting_test.rb
@@ -53,50 +53,40 @@ module ActiveRecord
end
def test_quoted_time_utc
- before = ActiveRecord::Base.default_timezone
- ActiveRecord::Base.default_timezone = :utc
- t = Time.now
- assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t)
- ensure
- ActiveRecord::Base.default_timezone = before
+ with_timezone_config default: :utc do
+ t = Time.now
+ assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t)
+ end
end
def test_quoted_time_local
- before = ActiveRecord::Base.default_timezone
- ActiveRecord::Base.default_timezone = :local
- t = Time.now
- assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t)
- ensure
- ActiveRecord::Base.default_timezone = before
+ with_timezone_config default: :local do
+ t = Time.now
+ assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t)
+ end
end
def test_quoted_time_crazy
- before = ActiveRecord::Base.default_timezone
- ActiveRecord::Base.default_timezone = :asdfasdf
- t = Time.now
- assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t)
- ensure
- ActiveRecord::Base.default_timezone = before
+ with_timezone_config default: :asdfasdf do
+ t = Time.now
+ assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t)
+ end
end
def test_quoted_datetime_utc
- before = ActiveRecord::Base.default_timezone
- ActiveRecord::Base.default_timezone = :utc
- t = DateTime.now
- assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t)
- ensure
- ActiveRecord::Base.default_timezone = before
+ with_timezone_config default: :utc do
+ t = DateTime.now
+ assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t)
+ end
end
###
# DateTime doesn't define getlocal, so make sure it does nothing
def test_quoted_datetime_local
- before = ActiveRecord::Base.default_timezone
- ActiveRecord::Base.default_timezone = :local
- t = DateTime.now
- assert_equal t.to_s(:db), @quoter.quoted_date(t)
- ensure
- ActiveRecord::Base.default_timezone = before
+ with_timezone_config default: :local do
+ t = DateTime.now
+ assert_equal t.to_s(:db), @quoter.quoted_date(t)
+ end
end
def test_quote_with_quoted_id
@@ -194,25 +184,6 @@ module ActiveRecord
assert_equal "'lo\\\\l'", @quoter.quote('lo\l', FakeColumn.new(:binary))
end
- def test_quote_binary_with_string_to_binary
- col = Class.new(FakeColumn) {
- def string_to_binary(value)
- 'foo'
- end
- }.new(:binary)
- assert_equal "'foo'", @quoter.quote('lo\l', col)
- end
-
- def test_quote_as_mb_chars_binary_column_with_string_to_binary
- col = Class.new(FakeColumn) {
- def string_to_binary(value)
- 'foo'
- end
- }.new(:binary)
- string = ActiveSupport::Multibyte::Chars.new('lo\l')
- assert_equal "'foo'", @quoter.quote(string, col)
- end
-
def test_string_with_crazy_column
assert_equal "'lo\\\\l'", @quoter.quote('lo\l', FakeColumn.new(:foo))
end
diff --git a/activerecord/test/cases/readonly_test.rb b/activerecord/test/cases/readonly_test.rb
index df076c97b4..2afd25c989 100644
--- a/activerecord/test/cases/readonly_test.rb
+++ b/activerecord/test/cases/readonly_test.rb
@@ -1,4 +1,5 @@
require "cases/helper"
+require 'models/author'
require 'models/post'
require 'models/comment'
require 'models/developer'
@@ -7,7 +8,7 @@ require 'models/reader'
require 'models/person'
class ReadOnlyTest < ActiveRecord::TestCase
- fixtures :posts, :comments, :developers, :projects, :developers_projects, :people, :readers
+ fixtures :authors, :posts, :comments, :developers, :projects, :developers_projects, :people, :readers
def test_cant_save_readonly_record
dev = Developer.find(1)
@@ -34,15 +35,12 @@ class ReadOnlyTest < ActiveRecord::TestCase
Developer.readonly.each { |d| assert d.readonly? }
end
+ def test_find_with_joins_option_does_not_imply_readonly
+ Developer.joins(' ').each { |d| assert_not d.readonly? }
+ Developer.joins(' ').readonly(true).each { |d| assert d.readonly? }
- def test_find_with_joins_option_implies_readonly
- # Blank joins don't count.
- Developer.joins(' ').each { |d| assert !d.readonly? }
- Developer.joins(' ').readonly(false).each { |d| assert !d.readonly? }
-
- # Others do.
- Developer.joins(', projects').each { |d| assert d.readonly? }
- Developer.joins(', projects').readonly(false).each { |d| assert !d.readonly? }
+ Developer.joins(', projects').each { |d| assert_not d.readonly? }
+ Developer.joins(', projects').readonly(true).each { |d| assert d.readonly? }
end
def test_has_many_find_readonly
@@ -87,7 +85,7 @@ class ReadOnlyTest < ActiveRecord::TestCase
# conflicting column names
unless current_adapter?(:OracleAdapter)
Post.joins(', developers').scoping do
- assert Post.find(1).readonly?
+ assert_not Post.find(1).readonly?
assert Post.readonly.find(1).readonly?
assert !Post.readonly(false).find(1).readonly?
end
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index b5314bc9be..d7ad5ed29f 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -18,6 +18,11 @@ require 'models/subscription'
require 'models/tag'
require 'models/sponsor'
require 'models/edge'
+require 'models/hotel'
+require 'models/chef'
+require 'models/department'
+require 'models/cake_designer'
+require 'models/drink_designer'
class ReflectionTest < ActiveRecord::TestCase
include ActiveRecord::Reflection
@@ -186,14 +191,6 @@ class ReflectionTest < ActiveRecord::TestCase
ActiveRecord::Base.store_full_sti_class = true
end
- def test_reflection_of_all_associations
- # FIXME these assertions bust a lot
- assert_equal 39, Firm.reflect_on_all_associations.size
- assert_equal 29, Firm.reflect_on_all_associations(:has_many).size
- assert_equal 10, 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
@@ -235,6 +232,17 @@ class ReflectionTest < ActiveRecord::TestCase
assert_equal expected, actual
end
+ def test_scope_chain_does_not_interfere_with_hmt_with_polymorphic_case
+ @hotel = Hotel.create!
+ @department = @hotel.departments.create!
+ @department.chefs.create!(employable: CakeDesigner.create!)
+ @department.chefs.create!(employable: DrinkDesigner.create!)
+
+ assert_equal 1, @hotel.cake_designers.size
+ assert_equal 1, @hotel.drink_designers.size
+ assert_equal 2, @hotel.chefs.size
+ end
+
def test_nested?
assert !Author.reflect_on_association(:comments).nested?
assert Author.reflect_on_association(:tags).nested?
@@ -260,8 +268,9 @@ class ReflectionTest < ActiveRecord::TestCase
reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :edge, nil, {}, Author)
assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.association_primary_key }
- through = ActiveRecord::Reflection::ThroughReflection.new(:fuu, :edge, nil, {}, Author)
- through.stubs(:source_reflection).returns(stub_everything(:options => {}, :class_name => 'Edge'))
+ through = Class.new(ActiveRecord::Reflection::ThroughReflection) {
+ define_method(:source_reflection) { reflection }
+ }.new(:fuu, :edge, nil, {}, Author)
assert_raises(ActiveRecord::UnknownPrimaryKey) { through.association_primary_key }
end
diff --git a/activerecord/test/cases/relation/delegation_test.rb b/activerecord/test/cases/relation/delegation_test.rb
new file mode 100644
index 0000000000..9b2bfed039
--- /dev/null
+++ b/activerecord/test/cases/relation/delegation_test.rb
@@ -0,0 +1,68 @@
+require 'cases/helper'
+require 'models/post'
+require 'models/comment'
+
+module ActiveRecord
+ class DelegationTest < ActiveRecord::TestCase
+ fixtures :posts
+
+ def call_method(target, method)
+ method_arity = target.to_a.method(method).arity
+
+ if method_arity.zero?
+ target.public_send(method)
+ elsif method_arity < 0
+ if method == :shuffle!
+ target.public_send(method)
+ else
+ target.public_send(method, 1)
+ end
+ elsif method_arity == 1
+ target.public_send(method, 1)
+ else
+ raise NotImplementedError
+ end
+ end
+ end
+
+ module DelegationWhitelistBlacklistTests
+ ARRAY_DELEGATES = [
+ :+, :-, :|, :&, :[],
+ :all?, :collect, :detect, :each, :each_cons, :each_with_index,
+ :exclude?, :find_all, :flat_map, :group_by, :include?, :length,
+ :map, :none?, :one?, :partition, :reject, :reverse,
+ :sample, :second, :sort, :sort_by, :third,
+ :to_ary, :to_set, :to_xml, :to_yaml
+ ]
+
+ ARRAY_DELEGATES.each do |method|
+ define_method "test_delegates_#{method}_to_Array" do
+ assert_respond_to target, method
+ end
+ end
+
+ ActiveRecord::Delegation::BLACKLISTED_ARRAY_METHODS.each do |method|
+ define_method "test_#{method}_is_not_delegated_to_Array" do
+ assert_raises(NoMethodError) { call_method(target, method) }
+ end
+ end
+ end
+
+ class DelegationAssociationTest < DelegationTest
+ include DelegationWhitelistBlacklistTests
+
+ def target
+ Post.first.comments
+ end
+ end
+
+ class DelegationRelationTest < DelegationTest
+ include DelegationWhitelistBlacklistTests
+
+ fixtures :comments
+
+ def target
+ Comment.all
+ end
+ end
+end
diff --git a/activerecord/test/cases/relation/merging_test.rb b/activerecord/test/cases/relation/merging_test.rb
new file mode 100644
index 0000000000..23500bf5d8
--- /dev/null
+++ b/activerecord/test/cases/relation/merging_test.rb
@@ -0,0 +1,162 @@
+require 'cases/helper'
+require 'models/author'
+require 'models/comment'
+require 'models/developer'
+require 'models/post'
+require 'models/project'
+
+class RelationMergingTest < ActiveRecord::TestCase
+ fixtures :developers, :comments, :authors, :posts
+
+ def test_relation_merging
+ devs = Developer.where("salary >= 80000").merge(Developer.limit(2)).merge(Developer.order('id ASC').where("id < 3"))
+ assert_equal [developers(:david), developers(:jamis)], devs.to_a
+
+ dev_with_count = Developer.limit(1).merge(Developer.order('id DESC')).merge(Developer.select('developers.*'))
+ assert_equal [developers(:poor_jamis)], dev_with_count.to_a
+ end
+
+ def test_relation_to_sql
+ sql = Post.connection.unprepared_statement do
+ Post.first.comments.to_sql
+ end
+ assert_no_match(/\?/, sql)
+ end
+
+ def test_relation_merging_with_arel_equalities_keeps_last_equality
+ devs = Developer.where(Developer.arel_table[:salary].eq(80000)).merge(
+ Developer.where(Developer.arel_table[:salary].eq(9000))
+ )
+ assert_equal [developers(:poor_jamis)], devs.to_a
+ end
+
+ def test_relation_merging_with_arel_equalities_keeps_last_equality_with_non_attribute_left_hand
+ salary_attr = Developer.arel_table[:salary]
+ devs = Developer.where(
+ Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(80000)
+ ).merge(
+ Developer.where(
+ Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(9000)
+ )
+ )
+ assert_equal [developers(:poor_jamis)], devs.to_a
+ end
+
+ def test_relation_merging_with_eager_load
+ relations = []
+ relations << Post.order('comments.id DESC').merge(Post.eager_load(:last_comment)).merge(Post.all)
+ relations << Post.eager_load(:last_comment).merge(Post.order('comments.id DESC')).merge(Post.all)
+
+ relations.each do |posts|
+ post = posts.find { |p| p.id == 1 }
+ assert_equal Post.find(1).last_comment, post.last_comment
+ end
+ end
+
+ def test_relation_merging_with_locks
+ devs = Developer.lock.where("salary >= 80000").order("id DESC").merge(Developer.limit(2))
+ assert devs.locked.present?
+ end
+
+ def test_relation_merging_with_preload
+ [Post.all.merge(Post.preload(:author)), Post.preload(:author).merge(Post.all)].each do |posts|
+ assert_queries(2) { assert posts.first.author }
+ end
+ end
+
+ def test_relation_merging_with_joins
+ comments = Comment.joins(:post).where(:body => 'Thank you for the welcome').merge(Post.where(:body => 'Such a lovely day'))
+ assert_equal 1, comments.count
+ end
+
+ def test_relation_merging_with_association
+ assert_queries(2) do # one for loading post, and another one merged query
+ post = Post.where(:body => 'Such a lovely day').first
+ comments = Comment.where(:body => 'Thank you for the welcome').merge(post.comments)
+ assert_equal 1, comments.count
+ end
+ end
+
+ test "merge collapses wheres from the LHS only" do
+ left = Post.where(title: "omg").where(comments_count: 1)
+ right = Post.where(title: "wtf").where(title: "bbq")
+
+ expected = [left.where_values[1]] + right.where_values
+ merged = left.merge(right)
+
+ assert_equal expected, merged.where_values
+ assert !merged.to_sql.include?("omg")
+ assert merged.to_sql.include?("wtf")
+ assert merged.to_sql.include?("bbq")
+ end
+
+ def test_merging_removes_rhs_bind_parameters
+ left = Post.where(id: Arel::Nodes::BindParam.new('?'))
+ column = Post.columns_hash['id']
+ left.bind_values += [[column, 20]]
+ right = Post.where(id: 10)
+
+ merged = left.merge(right)
+ assert_equal [], merged.bind_values
+ end
+
+ def test_merging_keeps_lhs_bind_parameters
+ column = Post.columns_hash['id']
+ binds = [[column, 20]]
+
+ right = Post.where(id: Arel::Nodes::BindParam.new('?'))
+ right.bind_values += binds
+ left = Post.where(id: 10)
+
+ merged = left.merge(right)
+ assert_equal binds, merged.bind_values
+ end
+
+ def test_merging_reorders_bind_params
+ post = Post.first
+ id_column = Post.columns_hash['id']
+ title_column = Post.columns_hash['title']
+
+ bv = Post.connection.substitute_at id_column, 0
+
+ right = Post.where(id: bv)
+ right.bind_values += [[id_column, post.id]]
+
+ left = Post.where(title: bv)
+ left.bind_values += [[title_column, post.title]]
+
+ merged = left.merge(right)
+ assert_equal post, merged.first
+ end
+end
+
+class MergingDifferentRelationsTest < ActiveRecord::TestCase
+ fixtures :posts, :authors
+
+ test "merging where relations" do
+ hello_by_bob = Post.where(body: "hello").joins(:author).
+ merge(Author.where(name: "Bob")).order("posts.id").pluck("posts.id")
+
+ assert_equal [posts(:misc_by_bob).id,
+ posts(:other_by_bob).id], hello_by_bob
+ end
+
+ test "merging order relations" do
+ posts_by_author_name = Post.limit(3).joins(:author).
+ merge(Author.order(:name)).pluck("authors.name")
+
+ assert_equal ["Bob", "Bob", "David"], posts_by_author_name
+
+ posts_by_author_name = Post.limit(3).joins(:author).
+ merge(Author.order("name")).pluck("authors.name")
+
+ assert_equal ["Bob", "Bob", "David"], posts_by_author_name
+ end
+
+ test "merging order relations (using a hash argument)" do
+ posts_by_author_name = Post.limit(4).joins(:author).
+ merge(Author.order(name: :desc)).pluck("authors.name")
+
+ assert_equal ["Mary", "Mary", "Mary", "David"], posts_by_author_name
+ end
+end
diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb
new file mode 100644
index 0000000000..7cb2a19bee
--- /dev/null
+++ b/activerecord/test/cases/relation/mutation_test.rb
@@ -0,0 +1,144 @@
+require 'cases/helper'
+require 'models/post'
+
+module ActiveRecord
+ class RelationMutationTest < ActiveSupport::TestCase
+ class FakeKlass < Struct.new(:table_name, :name)
+ extend ActiveRecord::Delegation::DelegateCache
+ inherited self
+
+ def connection
+ Post.connection
+ end
+
+ def relation_delegate_class(klass)
+ self.class.relation_delegate_class(klass)
+ end
+ end
+
+ def relation
+ @relation ||= Relation.new FakeKlass.new('posts'), Post.arel_table
+ end
+
+ (Relation::MULTI_VALUE_METHODS - [:references, :extending, :order, :unscope]).each do |method|
+ test "##{method}!" do
+ assert relation.public_send("#{method}!", :foo).equal?(relation)
+ assert_equal [:foo], relation.public_send("#{method}_values")
+ end
+ end
+
+ test '#order!' do
+ assert relation.order!('name ASC').equal?(relation)
+ assert_equal ['name ASC'], relation.order_values
+ end
+
+ test '#order! with symbol prepends the table name' do
+ assert relation.order!(:name).equal?(relation)
+ node = relation.order_values.first
+ assert node.ascending?
+ assert_equal :name, node.expr.name
+ assert_equal "posts", node.expr.relation.name
+ end
+
+ test '#order! on non-string does not attempt regexp match for references' do
+ obj = Object.new
+ obj.expects(:=~).never
+ assert relation.order!(obj)
+ assert_equal [obj], relation.order_values
+ end
+
+ test '#references!' do
+ assert relation.references!(:foo).equal?(relation)
+ assert relation.references_values.include?('foo')
+ end
+
+ test 'extending!' do
+ mod, mod2 = Module.new, Module.new
+
+ assert relation.extending!(mod).equal?(relation)
+ assert_equal [mod], relation.extending_values
+ assert relation.is_a?(mod)
+
+ relation.extending!(mod2)
+ assert_equal [mod, mod2], relation.extending_values
+ end
+
+ test 'extending! with empty args' do
+ relation.extending!
+ assert_equal [], relation.extending_values
+ end
+
+ (Relation::SINGLE_VALUE_METHODS - [:from, :lock, :reordering, :reverse_order, :create_with]).each do |method|
+ test "##{method}!" do
+ assert relation.public_send("#{method}!", :foo).equal?(relation)
+ assert_equal :foo, relation.public_send("#{method}_value")
+ end
+ end
+
+ test '#from!' do
+ assert relation.from!('foo').equal?(relation)
+ assert_equal ['foo', nil], relation.from_value
+ end
+
+ test '#lock!' do
+ assert relation.lock!('foo').equal?(relation)
+ assert_equal 'foo', relation.lock_value
+ end
+
+ test '#reorder!' do
+ relation = self.relation.order('foo')
+
+ assert relation.reorder!('bar').equal?(relation)
+ assert_equal ['bar'], relation.order_values
+ assert relation.reordering_value
+ end
+
+ test '#reorder! with symbol prepends the table name' do
+ assert relation.reorder!(:name).equal?(relation)
+ node = relation.order_values.first
+
+ assert node.ascending?
+ assert_equal :name, node.expr.name
+ assert_equal "posts", node.expr.relation.name
+ end
+
+ test 'reverse_order!' do
+ assert relation.reverse_order!.equal?(relation)
+ assert relation.reverse_order_value
+ relation.reverse_order!
+ assert !relation.reverse_order_value
+ end
+
+ test 'create_with!' do
+ assert relation.create_with!(foo: 'bar').equal?(relation)
+ assert_equal({foo: 'bar'}, relation.create_with_value)
+ end
+
+ test 'test_merge!' do
+ assert relation.merge!(where: :foo).equal?(relation)
+ assert_equal [:foo], relation.where_values
+ end
+
+ test 'merge with a proc' do
+ assert_equal [:foo], relation.merge(-> { where(:foo) }).where_values
+ end
+
+ test 'none!' do
+ assert relation.none!.equal?(relation)
+ assert_equal [NullRelation], relation.extending_values
+ assert relation.is_a?(NullRelation)
+ end
+
+ test 'distinct!' do
+ relation.distinct! :foo
+ assert_equal :foo, relation.distinct_value
+ assert_equal :foo, relation.uniq_value # deprecated access
+ end
+
+ test 'uniq! was replaced by distinct!' do
+ relation.uniq! :foo
+ assert_equal :foo, relation.distinct_value
+ assert_equal :foo, relation.uniq_value # deprecated access
+ end
+ end
+end
diff --git a/activerecord/test/cases/relation/predicate_builder_test.rb b/activerecord/test/cases/relation/predicate_builder_test.rb
new file mode 100644
index 0000000000..14a8d97d36
--- /dev/null
+++ b/activerecord/test/cases/relation/predicate_builder_test.rb
@@ -0,0 +1,14 @@
+require "cases/helper"
+require 'models/topic'
+
+module ActiveRecord
+ class PredicateBuilderTest < ActiveRecord::TestCase
+ def test_registering_new_handlers
+ PredicateBuilder.register_handler(Regexp, proc do |column, value|
+ Arel::Nodes::InfixOperation.new('~', column, value.source)
+ end)
+
+ assert_match %r{["`]topics["`].["`]title["`] ~ 'rails'}i, Topic.where(title: /rails/).to_sql
+ end
+ end
+end
diff --git a/activerecord/test/cases/relation/where_chain_test.rb b/activerecord/test/cases/relation/where_chain_test.rb
index 92d1e013e8..fd2420cb88 100644
--- a/activerecord/test/cases/relation/where_chain_test.rb
+++ b/activerecord/test/cases/relation/where_chain_test.rb
@@ -23,6 +23,12 @@ module ActiveRecord
assert_equal([expected], relation.where_values)
end
+ def test_not_with_nil
+ assert_raise ArgumentError do
+ Post.where.not(nil)
+ end
+ end
+
def test_not_in
expected = Arel::Nodes::NotIn.new(Post.arel_table[@name], %w[hello goodbye])
relation = Post.where.not(title: %w[hello goodbye])
@@ -76,5 +82,35 @@ module ActiveRecord
expected = Arel::Nodes::NotEqual.new(Post.arel_table[@name], 'ruby on rails')
assert_equal(expected, relation.where_values[1])
end
+
+ def test_rewhere_with_one_condition
+ relation = Post.where(title: 'hello').where(title: 'world').rewhere(title: 'alone')
+
+ expected = Arel::Nodes::Equality.new(Post.arel_table[@name], 'alone')
+ assert_equal 1, relation.where_values.size
+ assert_equal expected, relation.where_values.first
+ end
+
+ def test_rewhere_with_multiple_overwriting_conditions
+ relation = Post.where(title: 'hello').where(body: 'world').rewhere(title: 'alone', body: 'again')
+
+ title_expected = Arel::Nodes::Equality.new(Post.arel_table['title'], 'alone')
+ body_expected = Arel::Nodes::Equality.new(Post.arel_table['body'], 'again')
+
+ assert_equal 2, relation.where_values.size
+ assert_equal title_expected, relation.where_values.first
+ assert_equal body_expected, relation.where_values.second
+ end
+
+ def test_rewhere_with_one_overwriting_condition_and_one_unrelated
+ relation = Post.where(title: 'hello').where(body: 'world').rewhere(title: 'alone')
+
+ title_expected = Arel::Nodes::Equality.new(Post.arel_table['title'], 'alone')
+ body_expected = Arel::Nodes::Equality.new(Post.arel_table['body'], 'world')
+
+ assert_equal 2, relation.where_values.size
+ assert_equal body_expected, relation.where_values.first
+ assert_equal title_expected, relation.where_values.second
+ end
end
end
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index d333be3560..937f226b1d 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -24,6 +24,10 @@ module ActiveRecord
}
end
+ def test_rewhere_on_root
+ assert_equal posts(:welcome), Post.rewhere(title: 'Welcome to the weblog').first
+ end
+
def test_belongs_to_shallow_where
author = Author.new
author.id = 1
@@ -31,6 +35,21 @@ module ActiveRecord
assert_equal Post.where(author_id: 1).to_sql, Post.where(author: author).to_sql
end
+ def test_belongs_to_nil_where
+ assert_equal Post.where(author_id: nil).to_sql, Post.where(author: nil).to_sql
+ end
+
+ def test_belongs_to_array_value_where
+ assert_equal Post.where(author_id: [1,2]).to_sql, Post.where(author: [1,2]).to_sql
+ end
+
+ def test_belongs_to_nested_relation_where
+ expected = Post.where(author_id: Author.where(id: [1,2])).to_sql
+ actual = Post.where(author: Author.where(id: [1,2])).to_sql
+
+ assert_equal expected, actual
+ end
+
def test_belongs_to_nested_where
parent = Comment.new
parent.id = 1
@@ -51,6 +70,25 @@ module ActiveRecord
assert_equal expected.to_sql, actual.to_sql
end
+ def test_polymorphic_nested_array_where
+ treasure = Treasure.new
+ treasure.id = 1
+ hidden = HiddenTreasure.new
+ hidden.id = 2
+
+ expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: [treasure, hidden])
+ actual = PriceEstimate.where(estimate_of: [treasure, hidden])
+
+ assert_equal expected.to_sql, actual.to_sql
+ end
+
+ def test_polymorphic_nested_relation_where
+ expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: Treasure.where(id: [1,2]))
+ actual = PriceEstimate.where(estimate_of: Treasure.where(id: [1,2]))
+
+ assert_equal expected.to_sql, actual.to_sql
+ end
+
def test_polymorphic_sti_shallow_where
treasure = HiddenTreasure.new
treasure.id = 1
@@ -81,6 +119,31 @@ module ActiveRecord
assert_equal expected.to_sql, actual.to_sql
end
+ def test_decorated_polymorphic_where
+ treasure_decorator = Struct.new(:model) do
+ def self.method_missing(method, *args, &block)
+ Treasure.send(method, *args, &block)
+ end
+
+ def is_a?(klass)
+ model.is_a?(klass)
+ end
+
+ def method_missing(method, *args, &block)
+ model.send(method, *args, &block)
+ end
+ end
+
+ treasure = Treasure.new
+ treasure.id = 1
+ decorated_treasure = treasure_decorator.new(treasure)
+
+ expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: 1)
+ actual = PriceEstimate.where(estimate_of: decorated_treasure)
+
+ assert_equal expected.to_sql, actual.to_sql
+ end
+
def test_aliased_attribute
expected = Topic.where(heading: 'The First Topic')
actual = Topic.where(title: 'The First Topic')
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 03c7009568..15611656fd 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -9,6 +9,13 @@ module ActiveRecord
fixtures :posts, :comments, :authors
class FakeKlass < Struct.new(:table_name, :name)
+ extend ActiveRecord::Delegation::DelegateCache
+
+ inherited self
+
+ def self.connection
+ Post.connection
+ end
end
def test_construction
@@ -73,8 +80,8 @@ module ActiveRecord
end
def test_table_name_delegates_to_klass
- relation = Relation.new FakeKlass.new('foo'), :b
- assert_equal 'foo', relation.table_name
+ relation = Relation.new FakeKlass.new('posts'), :b
+ assert_equal 'posts', relation.table_name
end
def test_scope_for_create
@@ -108,6 +115,12 @@ module ActiveRecord
assert_equal({}, relation.scope_for_create)
end
+ def test_bad_constants_raise_errors
+ assert_raises(NameError) do
+ ActiveRecord::Relation::HelloWorld
+ end
+ end
+
def test_empty_eager_loading?
relation = Relation.new FakeKlass, :b
assert !relation.eager_loading?
@@ -168,141 +181,55 @@ module ActiveRecord
end
test 'merging a hash interpolates conditions' do
- klass = stub_everything
- klass.stubs(:sanitize_sql).with(['foo = ?', 'bar']).returns('foo = bar')
+ klass = Class.new(FakeKlass) do
+ def self.sanitize_sql(args)
+ raise unless args == ['foo = ?', 'bar']
+ 'foo = bar'
+ end
+ end
relation = Relation.new(klass, :b)
relation.merge!(where: ['foo = ?', 'bar'])
assert_equal ['foo = bar'], relation.where_values
end
- def test_relation_merging_with_merged_joins
+ def test_merging_readonly_false
+ relation = Relation.new FakeKlass, :b
+ readonly_false_relation = relation.readonly(false)
+ # test merging in both directions
+ assert_equal false, relation.merge(readonly_false_relation).readonly_value
+ assert_equal false, readonly_false_relation.merge(relation).readonly_value
+ end
+
+ def test_relation_merging_with_merged_joins_as_symbols
special_comments_with_ratings = SpecialComment.joins(:ratings)
posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings)
assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length
end
- def test_respond_to_for_non_selected_element
- post = Post.select(:title).first
- assert_equal false, post.respond_to?(:body), "post should not respond_to?(:body) since invoking it raises exception"
-
- post = Post.select("'title' as post_title").first
- assert_equal false, post.respond_to?(:title), "post should not respond_to?(:body) since invoking it raises exception"
- end
-
- end
-
- class RelationMutationTest < ActiveSupport::TestCase
- class FakeKlass < Struct.new(:table_name, :name)
- def quoted_table_name
- %{"#{table_name}"}
- end
- end
-
- def relation
- @relation ||= Relation.new FakeKlass.new('posts'), :b
- end
-
- (Relation::MULTI_VALUE_METHODS - [:references, :extending, :order]).each do |method|
- test "##{method}!" do
- assert relation.public_send("#{method}!", :foo).equal?(relation)
- assert_equal [:foo], relation.public_send("#{method}_values")
- end
- end
-
- test "#order!" do
- assert relation.order!('name ASC').equal?(relation)
- assert_equal ['name ASC'], relation.order_values
- end
-
- test "#order! with symbol prepends the table name" do
- assert relation.order!(:name).equal?(relation)
- assert_equal ['"posts".name ASC'], relation.order_values
- end
-
- test '#references!' do
- assert relation.references!(:foo).equal?(relation)
- assert relation.references_values.include?('foo')
- end
-
- test 'extending!' do
- mod, mod2 = Module.new, Module.new
-
- assert relation.extending!(mod).equal?(relation)
- assert_equal [mod], relation.extending_values
- assert relation.is_a?(mod)
-
- relation.extending!(mod2)
- assert_equal [mod, mod2], relation.extending_values
- end
-
- test 'extending! with empty args' do
- relation.extending!
- assert_equal [], relation.extending_values
- end
-
- (Relation::SINGLE_VALUE_METHODS - [:from, :lock, :reordering, :reverse_order, :create_with]).each do |method|
- test "##{method}!" do
- assert relation.public_send("#{method}!", :foo).equal?(relation)
- assert_equal :foo, relation.public_send("#{method}_value")
- end
- end
-
- test '#from!' do
- assert relation.from!('foo').equal?(relation)
- assert_equal ['foo', nil], relation.from_value
- end
-
- test '#lock!' do
- assert relation.lock!('foo').equal?(relation)
- assert_equal 'foo', relation.lock_value
- end
+ def test_relation_merging_with_joins_as_join_dependency_pick_proper_parent
+ post = Post.create!(title: "haha", body: "huhu")
+ comment = post.comments.create!(body: "hu")
+ 3.times { comment.ratings.create! }
- test '#reorder!' do
- relation = self.relation.order('foo')
+ relation = Post.joins(:comments).merge Comment.joins(:ratings)
- assert relation.reorder!('bar').equal?(relation)
- assert_equal ['bar'], relation.order_values
- assert relation.reordering_value
+ assert_equal 3, relation.where(id: post.id).pluck(:id).size
end
- test 'reverse_order!' do
- assert relation.reverse_order!.equal?(relation)
- assert relation.reverse_order_value
- relation.reverse_order!
- assert !relation.reverse_order_value
- end
-
- test 'create_with!' do
- assert relation.create_with!(foo: 'bar').equal?(relation)
- assert_equal({foo: 'bar'}, relation.create_with_value)
- end
-
- test 'merge!' do
- assert relation.merge!(where: :foo).equal?(relation)
- assert_equal [:foo], relation.where_values
- end
-
- test 'merge with a proc' do
- assert_equal [:foo], relation.merge(-> { where(:foo) }).where_values
- end
-
- test 'none!' do
- assert relation.none!.equal?(relation)
- assert_equal [NullRelation], relation.extending_values
- assert relation.is_a?(NullRelation)
- end
+ def test_respond_to_for_non_selected_element
+ post = Post.select(:title).first
+ assert_equal false, post.respond_to?(:body), "post should not respond_to?(:body) since invoking it raises exception"
- test "distinct!" do
- relation.distinct! :foo
- assert_equal :foo, relation.distinct_value
- assert_equal :foo, relation.uniq_value # deprecated access
+ silence_warnings { post = Post.select("'title' as post_title").first }
+ assert_equal false, post.respond_to?(:title), "post should not respond_to?(:body) since invoking it raises exception"
end
- test "uniq! was replaced by distinct!" do
- relation.uniq! :foo
- assert_equal :foo, relation.distinct_value
- assert_equal :foo, relation.uniq_value # deprecated access
+ def test_relation_merging_with_merged_joins_as_strings
+ join_string = "LEFT OUTER JOIN #{Rating.quoted_table_name} ON #{SpecialComment.quoted_table_name}.id = #{Rating.quoted_table_name}.comment_id"
+ special_comments_with_ratings = SpecialComment.joins join_string
+ posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings)
+ assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length
end
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index b64ff13d29..031da8e6d6 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -42,6 +42,11 @@ class RelationTest < ActiveRecord::TestCase
end
def test_two_scopes_with_includes_should_not_drop_any_include
+ # heat habtm cache
+ car = Car.incl_engines.incl_tyres.first
+ car.tyres.length
+ car.engines.length
+
car = Car.incl_engines.incl_tyres.first
assert_no_queries { car.tyres.length }
assert_no_queries { car.engines.length }
@@ -139,6 +144,18 @@ class RelationTest < ActiveRecord::TestCase
assert_equal relation.to_a, Topic.select('a.*').from(relation, :a).to_a
end
+ def test_finding_with_subquery_with_binds
+ relation = Post.first.comments
+ assert_equal relation.to_a, Comment.select('*').from(relation).to_a
+ assert_equal relation.to_a, Comment.select('subquery.*').from(relation).to_a
+ assert_equal relation.to_a, Comment.select('a.*').from(relation, :a).to_a
+ end
+
+ def test_finding_with_subquery_without_select
+ relation = Topic.where(:approved => true)
+ assert_equal relation.to_a, Topic.from(relation).to_a
+ end
+
def test_finding_with_conditions
assert_equal ["David"], Author.where(:name => 'David').map(&:name)
assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name)
@@ -170,6 +187,10 @@ class RelationTest < ActiveRecord::TestCase
assert_equal topics(:fourth).title, topics.first.title
end
+ def test_order_with_hash_and_symbol_generates_the_same_sql
+ assert_equal Topic.order(:id).to_sql, Topic.order(:id => :asc).to_sql
+ end
+
def test_raising_exception_on_invalid_hash_params
assert_raise(ArgumentError) { Topic.order(:name, "id DESC", :id => :DeSc) }
end
@@ -180,7 +201,7 @@ class RelationTest < ActiveRecord::TestCase
end
def test_finding_with_order_concatenated
- topics = Topic.order('title').order('author_name')
+ topics = Topic.order('author_name').order('title')
assert_equal 4, topics.to_a.size
assert_equal topics(:fourth).title, topics.first.title
end
@@ -258,7 +279,7 @@ class RelationTest < ActiveRecord::TestCase
def test_none_chained_to_methods_firing_queries_straight_to_db
assert_no_queries do
- assert_equal [], Developer.none.pluck(:id) # => uses select_all
+ assert_equal [], Developer.none.pluck(:id, :name)
assert_equal 0, Developer.none.delete_all
assert_equal 0, Developer.none.update_all(:name => 'David')
assert_equal 0, Developer.none.delete(1)
@@ -278,8 +299,9 @@ class RelationTest < ActiveRecord::TestCase
def test_null_relation_calculations_methods
assert_no_queries do
- assert_equal 0, Developer.none.count
- assert_equal nil, Developer.none.calculate(:average, 'salary')
+ assert_equal 0, Developer.none.count
+ assert_equal 0, Developer.none.calculate(:count, nil, {})
+ assert_equal nil, Developer.none.calculate(:average, 'salary')
end
end
@@ -288,6 +310,10 @@ class RelationTest < ActiveRecord::TestCase
assert_equal({}, Developer.none.where_values_hash)
end
+ def test_null_relation_where_values_hash
+ assert_equal({ 'salary' => 100_000 }, Developer.none.where(salary: 100_000).where_values_hash)
+ end
+
def test_joins_with_nil_argument
assert_nothing_raised { DependentFirm.joins(nil).first }
end
@@ -367,7 +393,7 @@ class RelationTest < ActiveRecord::TestCase
def test_respond_to_dynamic_finders
relation = Topic.all
- ["find_by_title", "find_by_title_and_author_name", "find_or_create_by_title", "find_or_initialize_by_title_and_author_name"].each do |method|
+ ["find_by_title", "find_by_title_and_author_name"].each do |method|
assert_respond_to relation, method, "Topic.all should respond to #{method.inspect}"
end
end
@@ -465,6 +491,14 @@ class RelationTest < ActiveRecord::TestCase
assert_equal Developer.where(name: 'David').map(&:id).sort, developers
end
+ def test_includes_with_select
+ query = Post.select('comments_count AS ranking').order('ranking').includes(:comments)
+ .where(comments: { id: 1 })
+
+ assert_equal ['comments_count AS ranking'], query.select_values
+ assert_equal 1, query.to_a.size
+ end
+
def test_loading_with_one_association
posts = Post.preload(:comments)
post = posts.find { |p| p.id == 1 }
@@ -480,6 +514,14 @@ class RelationTest < ActiveRecord::TestCase
assert_equal Post.find(1).last_comment, post.last_comment
end
+ def test_to_sql_on_eager_join
+ expected = assert_sql {
+ Post.eager_load(:last_comment).order('comments.id DESC').to_a
+ }.first
+ actual = Post.eager_load(:last_comment).order('comments.id DESC').to_sql
+ assert_equal expected, actual
+ end
+
def test_loading_with_one_association_with_non_preload
posts = Post.eager_load(:last_comment).order('comments.id DESC')
post = posts.find { |p| p.id == 1 }
@@ -597,6 +639,36 @@ class RelationTest < ActiveRecord::TestCase
relation = Author.where(:id => Author.where(:id => david.id))
assert_equal [david], relation.to_a
}
+
+ assert_queries(1) {
+ relation = Author.where('id in (?)', Author.where(id: david).select(:id))
+ assert_equal [david], relation.to_a
+ }
+
+ assert_queries(1) do
+ relation = Author.where('id in (:author_ids)', author_ids: Author.where(id: david).select(:id))
+ assert_equal [david], relation.to_a
+ end
+ end
+
+ def test_find_all_using_where_with_relation_with_bound_values
+ david = authors(:david)
+ davids_posts = david.posts.order(:id).to_a
+
+ assert_queries(1) do
+ relation = Post.where(id: david.posts.select(:id))
+ assert_equal davids_posts, relation.order(:id).to_a
+ end
+
+ assert_queries(1) do
+ relation = Post.where('id in (?)', david.posts.select(:id))
+ assert_equal davids_posts, relation.order(:id).to_a, 'should process Relation as bind variables'
+ end
+
+ assert_queries(1) do
+ relation = Post.where('id in (:post_ids)', post_ids: david.posts.select(:id))
+ assert_equal davids_posts, relation.order(:id).to_a, 'should process Relation as named bind variables'
+ end
end
def test_find_all_using_where_with_relation_and_alternate_primary_key
@@ -707,75 +779,6 @@ class RelationTest < ActiveRecord::TestCase
assert_raises(ArgumentError) { Developer.select }
end
- def test_relation_merging
- devs = Developer.where("salary >= 80000").merge(Developer.limit(2)).merge(Developer.order('id ASC').where("id < 3"))
- assert_equal [developers(:david), developers(:jamis)], devs.to_a
-
- dev_with_count = Developer.limit(1).merge(Developer.order('id DESC')).merge(Developer.select('developers.*'))
- assert_equal [developers(:poor_jamis)], dev_with_count.to_a
- end
-
- def test_relation_to_sql
- sql = Post.connection.unprepared_statement do
- Post.first.comments.to_sql
- end
- assert_no_match(/\?/, sql)
- end
-
- def test_relation_merging_with_arel_equalities_keeps_last_equality
- devs = Developer.where(Developer.arel_table[:salary].eq(80000)).merge(
- Developer.where(Developer.arel_table[:salary].eq(9000))
- )
- assert_equal [developers(:poor_jamis)], devs.to_a
- end
-
- def test_relation_merging_with_arel_equalities_keeps_last_equality_with_non_attribute_left_hand
- salary_attr = Developer.arel_table[:salary]
- devs = Developer.where(
- Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(80000)
- ).merge(
- Developer.where(
- Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(9000)
- )
- )
- assert_equal [developers(:poor_jamis)], devs.to_a
- end
-
- def test_relation_merging_with_eager_load
- relations = []
- relations << Post.order('comments.id DESC').merge(Post.eager_load(:last_comment)).merge(Post.all)
- relations << Post.eager_load(:last_comment).merge(Post.order('comments.id DESC')).merge(Post.all)
-
- relations.each do |posts|
- post = posts.find { |p| p.id == 1 }
- assert_equal Post.find(1).last_comment, post.last_comment
- end
- end
-
- def test_relation_merging_with_locks
- devs = Developer.lock.where("salary >= 80000").order("id DESC").merge(Developer.limit(2))
- assert devs.locked.present?
- end
-
- def test_relation_merging_with_preload
- [Post.all.merge(Post.preload(:author)), Post.preload(:author).merge(Post.all)].each do |posts|
- assert_queries(2) { assert posts.first.author }
- end
- end
-
- def test_relation_merging_with_joins
- comments = Comment.joins(:post).where(:body => 'Thank you for the welcome').merge(Post.where(:body => 'Such a lovely day'))
- assert_equal 1, comments.count
- end
-
- def test_relation_merging_with_association
- assert_queries(2) do # one for loading post, and another one merged query
- post = Post.where(:body => 'Such a lovely day').first
- comments = Comment.where(:body => 'Thank you for the welcome').merge(post.comments)
- assert_equal 1, comments.count
- end
- end
-
def test_count
posts = Post.all
@@ -1174,20 +1177,20 @@ class RelationTest < ActiveRecord::TestCase
end
def test_default_scope_order_with_scope_order
- assert_equal 'honda', CoolCar.order_using_new_style.limit(1).first.name
- assert_equal 'honda', FastCar.order_using_new_style.limit(1).first.name
+ assert_equal 'zyke', CoolCar.order_using_new_style.limit(1).first.name
+ assert_equal 'zyke', FastCar.order_using_new_style.limit(1).first.name
end
def test_order_using_scoping
car1 = CoolCar.order('id DESC').scoping do
- CoolCar.all.merge!(:order => 'id asc').first
+ CoolCar.all.merge!(order: 'id asc').first
end
- assert_equal 'honda', car1.name
+ assert_equal 'zyke', car1.name
car2 = FastCar.order('id DESC').scoping do
- FastCar.all.merge!(:order => 'id asc').first
+ FastCar.all.merge!(order: 'id asc').first
end
- assert_equal 'honda', car2.name
+ assert_equal 'zyke', car2.name
end
def test_unscoped_block_style
@@ -1207,33 +1210,12 @@ class RelationTest < ActiveRecord::TestCase
assert_equal "id", Post.all.primary_key
end
- def test_eager_loading_with_conditions_on_joins
- scope = Post.includes(:comments)
-
- # This references the comments table, and so it should cause the comments to be eager
- # loaded via a JOIN, rather than by subsequent queries.
- scope = scope.joins(
- Post.arel_table.create_join(
- Post.arel_table,
- Post.arel_table.create_on(Comment.arel_table[:id].eq(3))
- )
- )
-
+ def test_disable_implicit_join_references_is_deprecated
assert_deprecated do
- assert scope.eager_loading?
+ ActiveRecord::Base.disable_implicit_join_references = true
end
end
- def test_turn_off_eager_loading_with_conditions_on_joins
- original_value = ActiveRecord::Base.disable_implicit_join_references
- ActiveRecord::Base.disable_implicit_join_references = true
-
- scope = Topic.where(author_email_address: 'my.example@gmail.com').includes(:replies)
- assert_not scope.eager_loading?
- ensure
- ActiveRecord::Base.disable_implicit_join_references = original_value
- end
-
def test_ordering_with_extra_spaces
assert_equal authors(:david), Author.order('id DESC , name DESC').last
end
@@ -1352,6 +1334,24 @@ class RelationTest < ActiveRecord::TestCase
assert_equal [], scope.references_values
end
+ def test_automatically_added_reorder_references
+ scope = Post.reorder('comments.body')
+ assert_equal %w(comments), scope.references_values
+
+ scope = Post.reorder('comments.body', 'yaks.body')
+ assert_equal %w(comments yaks), scope.references_values
+
+ # Don't infer yaks, let's not go down that road again...
+ scope = Post.reorder('comments.body, yaks.body')
+ assert_equal %w(comments), scope.references_values
+
+ scope = Post.reorder('comments.body asc')
+ assert_equal %w(comments), scope.references_values
+
+ scope = Post.reorder('foo(comments.body)')
+ assert_equal [], scope.references_values
+ end
+
def test_presence
topics = Topic.all
@@ -1511,29 +1511,6 @@ class RelationTest < ActiveRecord::TestCase
assert !Post.all.respond_to?(:by_lifo)
end
- class OMGTopic < ActiveRecord::Base
- self.table_name = 'topics'
-
- def self.__omg__
- "omgtopic"
- end
- end
-
- test "delegations do not clash across classes" do
- begin
- class ::Array
- def __omg__
- "array"
- end
- end
-
- assert_equal "array", Topic.all.__omg__
- assert_equal "omgtopic", OMGTopic.all.__omg__
- ensure
- Array.send(:remove_method, :__omg__)
- end
- end
-
test "merge collapses wheres from the LHS only" do
left = Post.where(title: "omg").where(comments_count: 1)
right = Post.where(title: "wtf").where(title: "bbq")
@@ -1568,4 +1545,21 @@ class RelationTest < ActiveRecord::TestCase
merged = left.merge(right)
assert_equal binds, merged.bind_values
end
+
+ def test_merging_reorders_bind_params
+ post = Post.first
+ id_column = Post.columns_hash['id']
+ title_column = Post.columns_hash['title']
+
+ bv = Post.connection.substitute_at id_column, 0
+
+ right = Post.where(id: bv)
+ right.bind_values += [[id_column, post.id]]
+
+ left = Post.where(title: bv)
+ left.bind_values += [[title_column, post.title]]
+
+ merged = left.merge(right)
+ assert_equal post, merged.first
+ end
end
diff --git a/activerecord/test/cases/result_test.rb b/activerecord/test/cases/result_test.rb
new file mode 100644
index 0000000000..b6c583dbf5
--- /dev/null
+++ b/activerecord/test/cases/result_test.rb
@@ -0,0 +1,32 @@
+require "cases/helper"
+
+module ActiveRecord
+ class ResultTest < ActiveRecord::TestCase
+ def result
+ Result.new(['col_1', 'col_2'], [
+ ['row 1 col 1', 'row 1 col 2'],
+ ['row 2 col 1', 'row 2 col 2']
+ ])
+ end
+
+ def test_to_hash_returns_row_hashes
+ assert_equal [
+ {'col_1' => 'row 1 col 1', 'col_2' => 'row 1 col 2'},
+ {'col_1' => 'row 2 col 1', 'col_2' => 'row 2 col 2'}
+ ], result.to_hash
+ end
+
+ def test_each_with_block_returns_row_hashes
+ result.each do |row|
+ assert_equal ['col_1', 'col_2'], row.keys
+ end
+ end
+
+ def test_each_without_block_returns_an_enumerator
+ result.each.with_index do |row, index|
+ assert_equal ['col_1', 'col_2'], row.keys
+ assert_kind_of Integer, index
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb
index 082570c55b..766b2ff2ef 100644
--- a/activerecord/test/cases/sanitize_test.rb
+++ b/activerecord/test/cases/sanitize_test.rb
@@ -1,5 +1,7 @@
require "cases/helper"
require 'models/binary'
+require 'models/author'
+require 'models/post'
class SanitizeTest < ActiveRecord::TestCase
def setup
@@ -9,7 +11,7 @@ class SanitizeTest < ActiveRecord::TestCase
quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
quoted_column_name = ActiveRecord::Base.connection.quote_column_name("name")
quoted_table_name = ActiveRecord::Base.connection.quote_table_name("adorable_animals")
- expected_value = "#{quoted_table_name}.#{quoted_column_name} = #{quoted_bambi}"
+ expected_value = "#{quoted_table_name}.#{quoted_column_name} = #{quoted_bambi}"
assert_equal expected_value, Binary.send(:sanitize_sql_hash, {adorable_animals: {name: 'Bambi'}})
end
@@ -31,4 +33,17 @@ class SanitizeTest < ActiveRecord::TestCase
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
+
+ def test_sanitize_sql_array_handles_relations
+ david = Author.create!(name: 'David')
+ david_posts = david.posts.select(:id)
+
+ sub_query_pattern = /\(\bselect\b.*?\bwhere\b.*?\)/i
+
+ select_author_sql = Post.send(:sanitize_sql_array, ['id in (?)', david_posts])
+ assert_match(sub_query_pattern, select_author_sql, 'should sanitize `Relation` as subquery for bind variables')
+
+ select_author_sql = Post.send(:sanitize_sql_array, ['id in (:post_ids)', post_ids: david_posts])
+ assert_match(sub_query_pattern, select_author_sql, 'should sanitize `Relation` as subquery for named bind variables')
+ end
end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index a48ae1036f..741827446d 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -202,6 +202,11 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_match %r(primary_key: "movieid"), match[1], "non-standard primary key not preserved"
end
+ def test_schema_dump_should_use_false_as_default
+ output = standard_dump
+ assert_match %r{t\.boolean\s+"has_fun",.+default: false}, output
+ end
+
if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
def test_schema_dump_should_not_add_default_value_for_mysql_text_field
output = standard_dump
@@ -247,19 +252,20 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_match %r{t.integer\s+"bigint_default",\s+limit: 8,\s+default: 0}, output
end
- def test_schema_dump_includes_extensions
- connection = ActiveRecord::Base.connection
- skip unless connection.supports_extensions?
+ if ActiveRecord::Base.connection.supports_extensions?
+ def test_schema_dump_includes_extensions
+ connection = ActiveRecord::Base.connection
- connection.stubs(:extensions).returns(['hstore'])
- output = standard_dump
- assert_match "# These are extensions that must be enabled", output
- assert_match %r{enable_extension "hstore"}, output
+ connection.stubs(:extensions).returns(['hstore'])
+ output = standard_dump
+ assert_match "# These are extensions that must be enabled", output
+ assert_match %r{enable_extension "hstore"}, output
- connection.stubs(:extensions).returns([])
- output = standard_dump
- assert_no_match "# These are extensions that must be enabled", output
- assert_no_match %r{enable_extension}, output
+ connection.stubs(:extensions).returns([])
+ output = standard_dump
+ assert_no_match "# These are extensions that must be enabled", output
+ assert_no_match %r{enable_extension}, output
+ end
end
def test_schema_dump_includes_xml_shorthand_definition
@@ -299,7 +305,7 @@ class SchemaDumperTest < ActiveRecord::TestCase
def test_schema_dump_includes_uuid_shorthand_definition
output = standard_dump
- if %r{create_table "poistgresql_uuids"} =~ output
+ if %r{create_table "postgresql_uuids"} =~ output
assert_match %r{t.uuid "guid"}, output
end
end
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index 0f69443839..71754cf0a2 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -54,9 +54,14 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal 'Jamis', DeveloperCalledJamis.create!.name
end
- def test_default_scoping_with_threads
- 2.times do
- Thread.new { assert DeveloperOrderedBySalary.all.to_sql.include?('salary DESC') }.join
+ unless in_memory_db?
+ def test_default_scoping_with_threads
+ 2.times do
+ Thread.new {
+ assert DeveloperOrderedBySalary.all.to_sql.include?('salary DESC')
+ DeveloperOrderedBySalary.connection.close
+ }.join
+ end
end
end
@@ -79,7 +84,7 @@ class DefaultScopingTest < ActiveRecord::TestCase
end
def test_scope_overwrites_default
- expected = Developer.all.merge!(:order => ' name DESC, salary DESC').to_a.collect { |dev| dev.name }
+ expected = Developer.all.merge!(order: 'salary DESC, name DESC').to_a.collect { |dev| dev.name }
received = DeveloperOrderedBySalary.by_name.to_a.collect { |dev| dev.name }
assert_equal expected, received
end
@@ -91,14 +96,14 @@ class DefaultScopingTest < ActiveRecord::TestCase
end
def test_order_after_reorder_combines_orders
- expected = Developer.order('id DESC, name DESC').collect { |dev| [dev.name, dev.id] }
+ expected = Developer.order('name DESC, id DESC').collect { |dev| [dev.name, dev.id] }
received = Developer.order('name ASC').reorder('name DESC').order('id DESC').collect { |dev| [dev.name, dev.id] }
assert_equal expected, received
end
def test_unscope_overrides_default_scope
expected = Developer.all.collect { |dev| [dev.name, dev.id] }
- received = Developer.order('name ASC, id DESC').unscope(:order).collect { |dev| [dev.name, dev.id] }
+ received = DeveloperCalledJamis.unscope(:where).collect { |dev| [dev.name, dev.id] }
assert_equal expected, received
end
@@ -117,17 +122,25 @@ class DefaultScopingTest < ActiveRecord::TestCase
end
def test_unscope_with_where_attributes
- expected = Developer.order('salary DESC').collect { |dev| dev.name }
- received = DeveloperOrderedBySalary.where(name: 'David').unscope(where: :name).collect { |dev| dev.name }
+ expected = Developer.order('salary DESC').collect(&:name)
+ received = DeveloperOrderedBySalary.where(name: 'David').unscope(where: :name).collect(&:name)
assert_equal expected, received
- expected_2 = Developer.order('salary DESC').collect { |dev| dev.name }
- received_2 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope({:where => :name}, :select).collect { |dev| dev.name }
+ expected_2 = Developer.order('salary DESC').collect(&:name)
+ received_2 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope({:where => :name}, :select).collect(&:name)
assert_equal expected_2, received_2
- expected_3 = Developer.order('salary DESC').collect { |dev| dev.name }
- received_3 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope(:select, :where).collect { |dev| dev.name }
+ expected_3 = Developer.order('salary DESC').collect(&:name)
+ received_3 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope(:select, :where).collect(&:name)
assert_equal expected_3, received_3
+
+ expected_4 = Developer.order('salary DESC').collect(&:name)
+ received_4 = DeveloperOrderedBySalary.where.not("name" => "Jamis").unscope(where: :name).collect(&:name)
+ assert_equal expected_4, received_4
+
+ expected_5 = Developer.order('salary DESC').collect(&:name)
+ received_5 = DeveloperOrderedBySalary.where.not("name" => ["Jamis", "David"]).unscope(where: :name).collect(&:name)
+ assert_equal expected_5, received_5
end
def test_unscope_multiple_where_clauses
@@ -153,9 +166,8 @@ class DefaultScopingTest < ActiveRecord::TestCase
end
def test_order_to_unscope_reordering
- expected = DeveloperOrderedBySalary.all.collect { |dev| [dev.name, dev.id] }
- received = DeveloperOrderedBySalary.order('salary DESC, name ASC').reverse_order.unscope(:order).collect { |dev| [dev.name, dev.id] }
- assert_equal expected, received
+ scope = DeveloperOrderedBySalary.order('salary DESC, name ASC').reverse_order.unscope(:order)
+ assert !(scope.to_sql =~ /order/i)
end
def test_unscope_reverse_order
@@ -166,7 +178,7 @@ class DefaultScopingTest < ActiveRecord::TestCase
def test_unscope_select
expected = Developer.order('salary ASC').collect { |dev| dev.name }
- received = Developer.order('salary DESC').reverse_order.select(:name => "Jamis").unscope(:select).collect { |dev| dev.name }
+ received = Developer.order('salary DESC').reverse_order.select(:name).unscope(:select).collect { |dev| dev.name }
assert_equal expected, received
expected_2 = Developer.all.collect { |dev| dev.id }
@@ -250,9 +262,15 @@ class DefaultScopingTest < ActiveRecord::TestCase
end
end
+ def test_unscope_merging
+ merged = Developer.where(name: "Jamis").merge(Developer.unscope(:where))
+ assert merged.where_values.empty?
+ assert !merged.where(name: "Jon").where_values.empty?
+ end
+
def test_order_in_default_scope_should_not_prevail
- expected = Developer.all.merge!(:order => 'salary').to_a.collect { |dev| dev.salary }
- received = DeveloperOrderedBySalary.all.merge!(:order => 'salary').to_a.collect { |dev| dev.salary }
+ expected = Developer.all.merge!(order: 'salary desc').to_a.collect { |dev| dev.salary }
+ received = DeveloperOrderedBySalary.all.merge!(order: 'salary').to_a.collect { |dev| dev.salary }
assert_equal expected, received
end
@@ -350,21 +368,21 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal 1, DeveloperWithIncludes.where(:audit_logs => { :message => 'foo' }).count
end
- def test_default_scope_is_threadsafe
- if in_memory_db?
- skip "in memory db can't share a db between threads"
- end
-
- threads = []
- assert_not_equal 1, ThreadsafeDeveloper.unscoped.count
-
- threads << Thread.new do
- Thread.current[:long_default_scope] = true
- assert_equal 1, ThreadsafeDeveloper.all.to_a.count
- end
- threads << Thread.new do
- assert_equal 1, ThreadsafeDeveloper.all.to_a.count
+ unless in_memory_db?
+ def test_default_scope_is_threadsafe
+ threads = []
+ assert_not_equal 1, ThreadsafeDeveloper.unscoped.count
+
+ threads << Thread.new do
+ Thread.current[:long_default_scope] = true
+ assert_equal 1, ThreadsafeDeveloper.all.to_a.count
+ ThreadsafeDeveloper.connection.close
+ end
+ threads << Thread.new do
+ assert_equal 1, ThreadsafeDeveloper.all.to_a.count
+ ThreadsafeDeveloper.connection.close
+ end
+ threads.each(&:join)
end
- threads.each(&:join)
end
end
diff --git a/activerecord/test/cases/scoping/named_scoping_test.rb b/activerecord/test/cases/scoping/named_scoping_test.rb
index afe32af1d1..72c9787b84 100644
--- a/activerecord/test/cases/scoping/named_scoping_test.rb
+++ b/activerecord/test/cases/scoping/named_scoping_test.rb
@@ -60,11 +60,6 @@ class NamedScopingTest < ActiveRecord::TestCase
assert Topic.approved.respond_to?(:length)
end
- def test_respond_to_respects_include_private_parameter
- assert !Topic.approved.respond_to?(:tables_in_string)
- assert Topic.approved.respond_to?(:tables_in_string, true)
- end
-
def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified
assert !Topic.all.merge!(:where => {:approved => true}).to_a.empty?
@@ -440,24 +435,13 @@ class NamedScopingTest < ActiveRecord::TestCase
end
end
- def test_eager_scopes_are_deprecated
- klass = Class.new(ActiveRecord::Base)
- klass.table_name = 'posts'
-
- assert_deprecated do
- klass.scope :welcome_2, klass.where(:id => posts(:welcome).id)
- end
- assert_equal [posts(:welcome).title], klass.welcome_2.map(&:title)
- end
-
- def test_eager_default_scope_relations_are_deprecated
+ def test_eager_default_scope_relations_are_remove
klass = Class.new(ActiveRecord::Base)
klass.table_name = 'posts'
- assert_deprecated do
+ assert_raises(ArgumentError) do
klass.send(:default_scope, klass.where(:id => posts(:welcome).id))
end
- assert_equal [posts(:welcome).title], klass.all.map(&:title)
end
def test_subclass_merges_scopes_properly
diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb
index 765e92ccca..bc67da8d27 100644
--- a/activerecord/test/cases/serialized_attribute_test.rb
+++ b/activerecord/test/cases/serialized_attribute_test.rb
@@ -19,12 +19,6 @@ class SerializedAttributeTest < ActiveRecord::TestCase
assert_equal %w(content), Topic.serialized_attributes.keys
end
- def test_serialized_attributes_are_class_level_settings
- topic = Topic.new
- assert_raise(NoMethodError) { topic.serialized_attributes = [] }
- assert_deprecated { topic.serialized_attributes }
- end
-
def test_serialized_attribute
Topic.serialize("content", MyObject)
@@ -217,16 +211,15 @@ class SerializedAttributeTest < ActiveRecord::TestCase
end
def test_serialize_attribute_via_select_method_when_time_zone_available
- ActiveRecord::Base.time_zone_aware_attributes = true
- Topic.serialize(:content, MyObject)
+ with_timezone_config aware_attributes: true do
+ Topic.serialize(:content, MyObject)
- myobj = MyObject.new('value1', 'value2')
- topic = Topic.create(content: myobj)
+ myobj = MyObject.new('value1', 'value2')
+ topic = Topic.create(content: myobj)
- assert_equal(myobj, Topic.select(:content).find(topic.id).content)
- assert_raise(ActiveModel::MissingAttributeError) { Topic.select(:id).find(topic.id).content }
- ensure
- ActiveRecord::Base.time_zone_aware_attributes = false
+ assert_equal(myobj, Topic.select(:content).find(topic.id).content)
+ assert_raise(ActiveModel::MissingAttributeError) { Topic.select(:id).find(topic.id).content }
+ end
end
def test_serialize_attribute_can_be_serialized_in_an_integer_column
@@ -249,10 +242,7 @@ class SerializedAttributeTest < ActiveRecord::TestCase
myobj = MyObject.new('value1', 'value2')
Topic.create(content: myobj)
Topic.create(content: myobj)
-
- Topic.all.each do |topic|
- type = topic.instance_variable_get("@columns_hash")["content"]
- assert !type.instance_variable_get("@column").is_a?(ActiveRecord::AttributeMethods::Serialization::Type)
- end
+ type = Topic.column_types["content"]
+ assert !type.instance_variable_get("@column").is_a?(ActiveRecord::AttributeMethods::Serialization::Type)
end
end
diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb
index 3e32d866ee..6f632b4d8d 100644
--- a/activerecord/test/cases/store_test.rb
+++ b/activerecord/test/cases/store_test.rb
@@ -151,8 +151,19 @@ class StoreTest < ActiveRecord::TestCase
assert_equal [:color, :homepage, :favorite_food], Admin::User.stored_attributes[:settings]
end
- test "stores_attributes are class level settings" do
- assert_raise(NoMethodError) { @john.stored_attributes = Hash.new }
- assert_raise(NoMethodError) { @john.stored_attributes }
+ test "stored_attributes are tracked per class" do
+ first_model = Class.new(ActiveRecord::Base) do
+ store_accessor :data, :color
+ end
+ second_model = Class.new(ActiveRecord::Base) do
+ store_accessor :data, :width, :height
+ end
+
+ assert_equal [:color], first_model.stored_attributes[:data]
+ assert_equal [:width, :height], second_model.stored_attributes[:data]
+ end
+
+ test "YAML coder initializes the store when a Nil value is given" do
+ assert_equal({}, @john.params)
end
end
diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb
index e9000fef25..bf9e14fa4f 100644
--- a/activerecord/test/cases/tasks/database_tasks_test.rb
+++ b/activerecord/test/cases/tasks/database_tasks_test.rb
@@ -1,4 +1,5 @@
require 'cases/helper'
+require 'active_record/tasks/database_tasks'
module ActiveRecord
module DatabaseTasksSetupper
@@ -128,11 +129,22 @@ module ActiveRecord
)
end
- def test_creates_test_database_when_environment_is_database
+ def test_creates_test_and_development_databases_when_env_was_not_specified
ActiveRecord::Tasks::DatabaseTasks.expects(:create).
with('database' => 'dev-db')
ActiveRecord::Tasks::DatabaseTasks.expects(:create).
with('database' => 'test-db')
+ ENV.expects(:[]).with('RAILS_ENV').returns(nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.create_current(
+ ActiveSupport::StringInquirer.new('development')
+ )
+ end
+
+ def test_creates_only_development_database_when_rails_env_is_development
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create).
+ with('database' => 'dev-db')
+ ENV.expects(:[]).with('RAILS_ENV').returns('development')
ActiveRecord::Tasks::DatabaseTasks.create_current(
ActiveSupport::StringInquirer.new('development')
@@ -142,7 +154,7 @@ module ActiveRecord
def test_establishes_connection_for_the_given_environment
ActiveRecord::Tasks::DatabaseTasks.stubs(:create).returns true
- ActiveRecord::Base.expects(:establish_connection).with('development')
+ ActiveRecord::Base.expects(:establish_connection).with(:development)
ActiveRecord::Tasks::DatabaseTasks.create_current(
ActiveSupport::StringInquirer.new('development')
@@ -238,11 +250,22 @@ module ActiveRecord
)
end
- def test_creates_test_database_when_environment_is_database
+ def test_drops_test_and_development_databases_when_env_was_not_specified
ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
with('database' => 'dev-db')
ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
with('database' => 'test-db')
+ ENV.expects(:[]).with('RAILS_ENV').returns(nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.drop_current(
+ ActiveSupport::StringInquirer.new('development')
+ )
+ end
+
+ def test_drops_only_development_database_when_rails_env_is_development
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
+ with('database' => 'dev-db')
+ ENV.expects(:[]).with('RAILS_ENV').returns('development')
ActiveRecord::Tasks::DatabaseTasks.drop_current(
ActiveSupport::StringInquirer.new('development')
diff --git a/activerecord/test/cases/tasks/firebird_rake_test.rb b/activerecord/test/cases/tasks/firebird_rake_test.rb
deleted file mode 100644
index c54989ae34..0000000000
--- a/activerecord/test/cases/tasks/firebird_rake_test.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-require 'cases/helper'
-
-unless defined?(FireRuby::Database)
-module FireRuby
- module Database; end
-end
-end
-
-module ActiveRecord
- module FirebirdSetupper
- def setup
- @database = 'db.firebird'
- @connection = stub :connection
- @configuration = {
- 'adapter' => 'firebird',
- 'database' => @database
- }
- ActiveRecord::Base.stubs(:connection).returns(@connection)
- ActiveRecord::Base.stubs(:establish_connection).returns(true)
-
- @tasks = Class.new(ActiveRecord::Tasks::FirebirdDatabaseTasks) do
- def initialize(configuration)
- ActiveSupport::Deprecation.silence { super }
- end
- end
- ActiveRecord::Tasks::DatabaseTasks.stubs(:class_for_adapter).returns(@tasks) unless defined? ActiveRecord::ConnectionAdapters::FirebirdAdapter
- end
- end
-
- class FirebirdDBCreateTest < ActiveRecord::TestCase
- include FirebirdSetupper
-
- def test_db_retrieves_create
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class FirebirdDBDropTest < ActiveRecord::TestCase
- include FirebirdSetupper
-
- def test_db_retrieves_drop
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.drop @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class FirebirdDBCharsetAndCollationTest < ActiveRecord::TestCase
- include FirebirdSetupper
-
- def test_db_retrieves_collation
- assert_raise NoMethodError do
- ActiveRecord::Tasks::DatabaseTasks.collation @configuration
- end
- end
-
- def test_db_retrieves_charset
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.charset @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class FirebirdStructureDumpTest < ActiveRecord::TestCase
- include FirebirdSetupper
-
- def setup
- super
- FireRuby::Database.stubs(:db_string_for).returns(@database)
- end
-
- def test_structure_dump
- filename = "filebird.sql"
- Kernel.expects(:system).with("isql -a #{@database} > #{filename}")
-
- ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename)
- end
- end
-
- class FirebirdStructureLoadTest < ActiveRecord::TestCase
- include FirebirdSetupper
-
- def setup
- super
- FireRuby::Database.stubs(:db_string_for).returns(@database)
- end
-
- def test_structure_load
- filename = "firebird.sql"
- Kernel.expects(:system).with("isql -i #{filename} #{@database}")
-
- ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
- end
- end
-end
diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb
index 816bd62751..3e3a2828f3 100644
--- a/activerecord/test/cases/tasks/mysql_rake_test.rb
+++ b/activerecord/test/cases/tasks/mysql_rake_test.rb
@@ -65,99 +65,98 @@ module ActiveRecord
end
end
- class MysqlDBCreateAsRootTest < ActiveRecord::TestCase
- def setup
- unless current_adapter?(:MysqlAdapter)
- return skip("only tested on mysql")
+ if current_adapter?(:MysqlAdapter)
+ class MysqlDBCreateAsRootTest < ActiveRecord::TestCase
+ def setup
+ @connection = stub("Connection", create_database: true)
+ @error = Mysql::Error.new "Invalid permissions"
+ @configuration = {
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db',
+ 'username' => 'pat',
+ 'password' => 'wossname'
+ }
+
+ $stdin.stubs(:gets).returns("secret\n")
+ $stdout.stubs(:print).returns(nil)
+ @error.stubs(:errno).returns(1045)
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).
+ raises(@error).
+ then.returns(true)
end
- @connection = stub("Connection", create_database: true)
- @error = Mysql::Error.new "Invalid permissions"
- @configuration = {
- 'adapter' => 'mysql',
- 'database' => 'my-app-db',
- 'username' => 'pat',
- 'password' => 'wossname'
- }
-
- $stdin.stubs(:gets).returns("secret\n")
- $stdout.stubs(:print).returns(nil)
- @error.stubs(:errno).returns(1045)
- ActiveRecord::Base.stubs(:connection).returns(@connection)
- ActiveRecord::Base.stubs(:establish_connection).
- raises(@error).
- then.returns(true)
- end
+ if defined?(::Mysql)
+ def test_root_password_is_requested
+ assert_permissions_granted_for "pat"
+ $stdin.expects(:gets).returns("secret\n")
- def test_root_password_is_requested
- assert_permissions_granted_for "pat"
- skip "only if mysql is available" unless defined?(::Mysql)
- $stdin.expects(:gets).returns("secret\n")
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+ end
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
+ def test_connection_established_as_root
+ assert_permissions_granted_for "pat"
+ ActiveRecord::Base.expects(:establish_connection).with(
+ 'adapter' => 'mysql',
+ 'database' => nil,
+ 'username' => 'root',
+ 'password' => 'secret'
+ )
- def test_connection_established_as_root
- assert_permissions_granted_for "pat"
- ActiveRecord::Base.expects(:establish_connection).with(
- 'adapter' => 'mysql',
- 'database' => nil,
- 'username' => 'root',
- 'password' => 'secret'
- )
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
+ def test_database_created_by_root
+ assert_permissions_granted_for "pat"
+ @connection.expects(:create_database).
+ with('my-app-db', :charset => 'utf8', :collation => 'utf8_unicode_ci')
- def test_database_created_by_root
- assert_permissions_granted_for "pat"
- @connection.expects(:create_database).
- with('my-app-db', :charset => 'utf8', :collation => 'utf8_unicode_ci')
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
+ def test_grant_privileges_for_normal_user
+ assert_permissions_granted_for "pat"
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
- def test_grant_privileges_for_normal_user
- assert_permissions_granted_for "pat"
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
+ def test_do_not_grant_privileges_for_root_user
+ @configuration['username'] = 'root'
+ @configuration['password'] = ''
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
- def test_do_not_grant_privileges_for_root_user
- @configuration['username'] = 'root'
- @configuration['password'] = ''
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
+ def test_connection_established_as_normal_user
+ assert_permissions_granted_for "pat"
+ ActiveRecord::Base.expects(:establish_connection).returns do
+ ActiveRecord::Base.expects(:establish_connection).with(
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db',
+ 'username' => 'pat',
+ 'password' => 'secret'
+ )
- def test_connection_established_as_normal_user
- assert_permissions_granted_for "pat"
- ActiveRecord::Base.expects(:establish_connection).returns do
- ActiveRecord::Base.expects(:establish_connection).with(
- 'adapter' => 'mysql',
- 'database' => 'my-app-db',
- 'username' => 'pat',
- 'password' => 'secret'
- )
+ raise @error
+ end
- raise @error
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
end
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
+ def test_sends_output_to_stderr_when_other_errors
+ @error.stubs(:errno).returns(42)
- def test_sends_output_to_stderr_when_other_errors
- @error.stubs(:errno).returns(42)
+ $stderr.expects(:puts).at_least_once.returns(nil)
- $stderr.expects(:puts).at_least_once.returns(nil)
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ private
+ def assert_permissions_granted_for(db_user)
+ db_name = @configuration['database']
+ db_password = @configuration['password']
+ @connection.expects(:execute).with("GRANT ALL PRIVILEGES ON #{db_name}.* TO '#{db_user}'@'localhost' IDENTIFIED BY '#{db_password}' WITH GRANT OPTION;")
+ end
end
-
- private
- def assert_permissions_granted_for(db_user)
- db_name = @configuration['database']
- db_password = @configuration['password']
- @connection.expects(:execute).with("GRANT ALL PRIVILEGES ON #{db_name}.* TO '#{db_user}'@'localhost' IDENTIFIED BY '#{db_password}' WITH GRANT OPTION;")
- end
end
class MySQLDBDropTest < ActiveRecord::TestCase
@@ -280,6 +279,15 @@ module ActiveRecord
assert_match(/Could not dump the database structure/, warnings)
end
+
+ def test_structure_dump_with_port_number
+ filename = "awesome-file.sql"
+ Kernel.expects(:system).with("mysqldump", "--port", "10000", "--result-file", filename, "--no-data", "test-db").returns(true)
+
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(
+ @configuration.merge('port' => 10000),
+ filename)
+ end
end
class MySQLStructureLoadTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/tasks/oracle_rake_test.rb b/activerecord/test/cases/tasks/oracle_rake_test.rb
deleted file mode 100644
index 5f840febbc..0000000000
--- a/activerecord/test/cases/tasks/oracle_rake_test.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require 'cases/helper'
-
-module ActiveRecord
- module OracleSetupper
- def setup
- @database = 'db.oracle'
- @connection = stub :connection
- @configuration = {
- 'adapter' => 'oracle',
- 'database' => @database
- }
- ActiveRecord::Base.stubs(:connection).returns(@connection)
- ActiveRecord::Base.stubs(:establish_connection).returns(true)
-
- @tasks = Class.new(ActiveRecord::Tasks::OracleDatabaseTasks) do
- def initialize(configuration)
- ActiveSupport::Deprecation.silence { super }
- end
- end
- ActiveRecord::Tasks::DatabaseTasks.stubs(:class_for_adapter).returns(@tasks) unless defined? ActiveRecord::ConnectionAdapters::OracleAdapter
- end
- end
-
- class OracleDBCreateTest < ActiveRecord::TestCase
- include OracleSetupper
-
- def test_db_retrieves_create
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class OracleDBDropTest < ActiveRecord::TestCase
- include OracleSetupper
-
- def test_db_retrieves_drop
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.drop @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class OracleDBCharsetAndCollationTest < ActiveRecord::TestCase
- include OracleSetupper
-
- def test_db_retrieves_collation
- assert_raise NoMethodError do
- ActiveRecord::Tasks::DatabaseTasks.collation @configuration
- end
- end
-
- def test_db_retrieves_charset
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.charset @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class OracleStructureDumpTest < ActiveRecord::TestCase
- include OracleSetupper
-
- def setup
- super
- @connection.stubs(:structure_dump).returns("select sysdate from dual;")
- end
-
- def test_structure_dump
- filename = "oracle.sql"
- ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename)
- assert File.exists?(filename)
- ensure
- FileUtils.rm_f(filename)
- end
- end
-
- class OracleStructureLoadTest < ActiveRecord::TestCase
- include OracleSetupper
-
- def test_structure_load
- filename = "oracle.sql"
-
- open(filename, 'w') { |f| f.puts("select sysdate from dual;") }
- @connection.stubs(:execute).with("select sysdate from dual;\n")
- ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
- ensure
- FileUtils.rm_f(filename)
- end
- end
-end
diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb
index f31896bc7f..6ea225178f 100644
--- a/activerecord/test/cases/tasks/postgresql_rake_test.rb
+++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb
@@ -206,7 +206,7 @@ module ActiveRecord
@connection.expects(:schema_search_path).returns("foo")
ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename)
- assert File.exists?(filename)
+ assert File.exist?(filename)
ensure
FileUtils.rm(filename)
end
@@ -231,6 +231,13 @@ module ActiveRecord
ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
end
+
+ def test_structure_load_accepts_path_with_spaces
+ filename = "awesome file.sql"
+ Kernel.expects(:system).with("psql -q -f awesome\\ file.sql my-app-db")
+
+ ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
+ end
end
end
diff --git a/activerecord/test/cases/tasks/sqlite_rake_test.rb b/activerecord/test/cases/tasks/sqlite_rake_test.rb
index 7209c0f14d..da3471adf9 100644
--- a/activerecord/test/cases/tasks/sqlite_rake_test.rb
+++ b/activerecord/test/cases/tasks/sqlite_rake_test.rb
@@ -159,8 +159,8 @@ module ActiveRecord
filename = "awesome-file.sql"
ActiveRecord::Tasks::DatabaseTasks.structure_dump @configuration, filename, '/rails/root'
- assert File.exists?(dbfile)
- assert File.exists?(filename)
+ assert File.exist?(dbfile)
+ assert File.exist?(filename)
ensure
FileUtils.rm_f(filename)
FileUtils.rm_f(dbfile)
@@ -182,7 +182,7 @@ module ActiveRecord
open(filename, 'w') { |f| f.puts("select datetime('now', 'localtime');") }
ActiveRecord::Tasks::DatabaseTasks.structure_load @configuration, filename, '/rails/root'
- assert File.exists?(dbfile)
+ assert File.exist?(dbfile)
ensure
FileUtils.rm_f(filename)
FileUtils.rm_f(dbfile)
diff --git a/activerecord/test/cases/tasks/sqlserver_rake_test.rb b/activerecord/test/cases/tasks/sqlserver_rake_test.rb
deleted file mode 100644
index 0f1264b8ce..0000000000
--- a/activerecord/test/cases/tasks/sqlserver_rake_test.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-require 'cases/helper'
-
-module ActiveRecord
- module SqlserverSetupper
- def setup
- @database = 'db.sqlserver'
- @connection = stub :connection
- @configuration = {
- 'adapter' => 'sqlserver',
- 'database' => @database,
- 'host' => 'localhost',
- 'username' => 'username',
- 'password' => 'password',
- }
- ActiveRecord::Base.stubs(:connection).returns(@connection)
- ActiveRecord::Base.stubs(:establish_connection).returns(true)
-
- @tasks = Class.new(ActiveRecord::Tasks::SqlserverDatabaseTasks) do
- def initialize(configuration)
- ActiveSupport::Deprecation.silence { super }
- end
- end
- ActiveRecord::Tasks::DatabaseTasks.stubs(:class_for_adapter).returns(@tasks) unless defined? ActiveRecord::ConnectionAdapters::SQLServerAdapter
- end
- end
-
- class SqlserverDBCreateTest < ActiveRecord::TestCase
- include SqlserverSetupper
-
- def test_db_retrieves_create
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class SqlserverDBDropTest < ActiveRecord::TestCase
- include SqlserverSetupper
-
- def test_db_retrieves_drop
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.drop @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class SqlserverDBCharsetAndCollationTest < ActiveRecord::TestCase
- include SqlserverSetupper
-
- def test_db_retrieves_collation
- assert_raise NoMethodError do
- ActiveRecord::Tasks::DatabaseTasks.collation @configuration
- end
- end
-
- def test_db_retrieves_charset
- message = capture(:stderr) do
- ActiveRecord::Tasks::DatabaseTasks.charset @configuration
- end
- assert_match(/not supported/, message)
- end
- end
-
- class SqlserverStructureDumpTest < ActiveRecord::TestCase
- include SqlserverSetupper
-
- def test_structure_dump
- filename = "sqlserver.sql"
- Kernel.expects(:system).with("smoscript -s localhost -d #{@database} -u username -p password -f #{filename} -A -U")
-
- ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename)
- end
- end
-
- class SqlserverStructureLoadTest < ActiveRecord::TestCase
- include SqlserverSetupper
-
- def test_structure_load
- filename = "sqlserver.sql"
- Kernel.expects(:system).with("sqlcmd -S localhost -d #{@database} -U username -P password -i #{filename}")
-
- ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
- end
- end
-end
diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb
index f3f7054794..4476ce3410 100644
--- a/activerecord/test/cases/test_case.rb
+++ b/activerecord/test/cases/test_case.rb
@@ -1,9 +1,108 @@
-ActiveSupport::Deprecation.silence do
- require 'active_record/test_case'
-end
+require 'active_support/test_case'
+
+module ActiveRecord
+ # = Active Record Test Case
+ #
+ # Defines some test assertions to test against SQL queries.
+ class TestCase < ActiveSupport::TestCase #:nodoc:
+ def teardown
+ SQLCounter.clear_log
+ end
+
+ def assert_date_from_db(expected, actual, message = nil)
+ # SybaseAdapter doesn't have a separate column type just for dates,
+ # so the time is in the string and incorrectly formatted
+ if current_adapter?(:SybaseAdapter)
+ assert_equal expected.to_s, actual.to_date.to_s, message
+ else
+ assert_equal expected.to_s, actual.to_s, message
+ end
+ end
+
+ def assert_sql(*patterns_to_match)
+ SQLCounter.clear_log
+ yield
+ SQLCounter.log_all
+ ensure
+ failed_patterns = []
+ patterns_to_match.each do |pattern|
+ failed_patterns << pattern unless SQLCounter.log_all.any?{ |sql| pattern === sql }
+ end
+ assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}"
+ end
+
+ def assert_queries(num = 1, options = {})
+ ignore_none = options.fetch(:ignore_none) { num == :any }
+ SQLCounter.clear_log
+ x = yield
+ the_log = ignore_none ? SQLCounter.log_all : SQLCounter.log
+ if num == :any
+ assert_operator the_log.size, :>=, 1, "1 or more queries expected, but none were executed."
+ else
+ mesg = "#{the_log.size} instead of #{num} queries were executed.#{the_log.size == 0 ? '' : "\nQueries:\n#{the_log.join("\n")}"}"
+ assert_equal num, the_log.size, mesg
+ end
+ x
+ end
+
+ def assert_no_queries(options = {}, &block)
+ options.reverse_merge! ignore_none: true
+ assert_queries(0, options, &block)
+ end
+
+ def assert_column(model, column_name, msg=nil)
+ assert has_column?(model, column_name), msg
+ end
+
+ def assert_no_column(model, column_name, msg=nil)
+ assert_not has_column?(model, column_name), msg
+ end
+
+ def has_column?(model, column_name)
+ model.reset_column_information
+ model.column_names.include?(column_name.to_s)
+ end
+ end
-ActiveRecord::TestCase.class_eval do
- def sqlite3? connection
- connection.class.name.split('::').last == "SQLite3Adapter"
+ class SQLCounter
+ class << self
+ attr_accessor :ignored_sql, :log, :log_all
+ def clear_log; self.log = []; self.log_all = []; end
+ end
+
+ self.clear_log
+
+ self.ignored_sql = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/]
+
+ # FIXME: this needs to be refactored so specific database can add their own
+ # ignored SQL, or better yet, use a different notification for the queries
+ # instead examining the SQL content.
+ oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im, /^\s*select .* from all_constraints/im, /^\s*select .* from all_tab_cols/im]
+ mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/, /^SHOW CREATE TABLE /i]
+ postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i]
+ sqlite3_ignored = [/^\s*SELECT name\b.*\bFROM sqlite_master/im]
+
+ [oracle_ignored, mysql_ignored, postgresql_ignored, sqlite3_ignored].each do |db_ignored_sql|
+ ignored_sql.concat db_ignored_sql
+ end
+
+ attr_reader :ignore
+
+ def initialize(ignore = Regexp.union(self.class.ignored_sql))
+ @ignore = ignore
+ end
+
+ def call(name, start, finish, message_id, values)
+ sql = values[:sql]
+
+ # FIXME: this seems bad. we should probably have a better way to indicate
+ # the query was cached
+ return if 'CACHE' == values[:name]
+
+ self.class.log_all << sql
+ self.class.log << sql unless ignore =~ sql
+ end
end
+
+ ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
end
diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb
index ff1b01556d..717e0e1866 100644
--- a/activerecord/test/cases/timestamp_test.rb
+++ b/activerecord/test/cases/timestamp_test.rb
@@ -11,6 +11,7 @@ class TimestampTest < ActiveRecord::TestCase
def setup
@developer = Developer.first
+ @owner = Owner.first
@developer.update_columns(updated_at: Time.now.prev_month)
@previously_updated_at = @developer.updated_at
end
@@ -92,6 +93,53 @@ class TimestampTest < ActiveRecord::TestCase
assert_nothing_raised { Car.first.touch }
end
+ def test_touching_a_no_touching_object
+ Developer.no_touching do
+ assert @developer.no_touching?
+ assert !@owner.no_touching?
+ @developer.touch
+ end
+
+ assert !@developer.no_touching?
+ assert !@owner.no_touching?
+ assert_equal @previously_updated_at, @developer.updated_at
+ end
+
+ def test_touching_related_objects
+ @owner = Owner.first
+ @previously_updated_at = @owner.updated_at
+
+ Owner.no_touching do
+ @owner.pets.first.touch
+ end
+
+ assert_equal @previously_updated_at, @owner.updated_at
+ end
+
+ def test_global_no_touching
+ ActiveRecord::Base.no_touching do
+ assert @developer.no_touching?
+ assert @owner.no_touching?
+ @developer.touch
+ end
+
+ assert !@developer.no_touching?
+ assert !@owner.no_touching?
+ assert_equal @previously_updated_at, @developer.updated_at
+ end
+
+ def test_no_touching_threadsafe
+ Thread.new do
+ Developer.no_touching do
+ assert @developer.no_touching?
+
+ sleep(1)
+ end
+ end
+
+ assert !@developer.no_touching?
+ end
+
def test_saving_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at
pet = Pet.first
owner = pet.owner
@@ -224,36 +272,62 @@ class TimestampTest < ActiveRecord::TestCase
assert_not_equal time, old_pet.updated_at
end
- def test_changing_parent_of_a_record_touches_both_new_and_old_polymorphic_parent_record
- klass = Class.new(ActiveRecord::Base) do
- def self.name; 'Toy'; end
+ def test_changing_parent_of_a_record_touches_both_new_and_old_polymorphic_parent_record_changes_within_same_class
+ car_class = Class.new(ActiveRecord::Base) do
+ def self.name; 'Car'; end
end
- wheel_klass = Class.new(ActiveRecord::Base) do
+ wheel_class = Class.new(ActiveRecord::Base) do
def self.name; 'Wheel'; end
belongs_to :wheelable, :polymorphic => true, :touch => true
end
- toy1 = klass.find(1)
- toy2 = klass.find(2)
+ car1 = car_class.find(1)
+ car2 = car_class.find(2)
- wheel = wheel_klass.new
- wheel.wheelable = toy1
- wheel.save!
+ wheel = wheel_class.create!(wheelable: car1)
time = 3.days.ago.at_beginning_of_hour
- toy1.update_columns(updated_at: time)
- toy2.update_columns(updated_at: time)
+ car1.update_columns(updated_at: time)
+ car2.update_columns(updated_at: time)
- wheel.wheelable = toy2
+ wheel.wheelable = car2
wheel.save!
- toy1.reload
- toy2.reload
+ assert_not_equal time, car1.reload.updated_at
+ assert_not_equal time, car2.reload.updated_at
+ end
+
+ def test_changing_parent_of_a_record_touches_both_new_and_old_polymorphic_parent_record_changes_with_other_class
+ car_class = Class.new(ActiveRecord::Base) do
+ def self.name; 'Car'; end
+ end
+
+ toy_class = Class.new(ActiveRecord::Base) do
+ def self.name; 'Toy'; end
+ end
+
+ wheel_class = Class.new(ActiveRecord::Base) do
+ def self.name; 'Wheel'; end
+ belongs_to :wheelable, :polymorphic => true, :touch => true
+ end
+
+ car = car_class.find(1)
+ toy = toy_class.find(3)
+
+ wheel = wheel_class.create!(wheelable: car)
+
+ time = 3.days.ago.at_beginning_of_hour
+
+ car.update_columns(updated_at: time)
+ toy.update_columns(updated_at: time)
+
+ wheel.wheelable = toy
+ wheel.save!
- assert_not_equal time, toy1.updated_at
- assert_not_equal time, toy2.updated_at
+ assert_not_equal time, car.reload.updated_at
+ assert_not_equal time, toy.reload.updated_at
end
def test_clearing_association_touches_the_old_record
@@ -278,31 +352,31 @@ class TimestampTest < ActiveRecord::TestCase
def test_timestamp_attributes_for_create
toy = Toy.first
- assert_equal toy.send(:timestamp_attributes_for_create), [:created_at, :created_on]
+ assert_equal [:created_at, :created_on], toy.send(:timestamp_attributes_for_create)
end
def test_timestamp_attributes_for_update
toy = Toy.first
- assert_equal toy.send(:timestamp_attributes_for_update), [:updated_at, :updated_on]
+ assert_equal [:updated_at, :updated_on], toy.send(:timestamp_attributes_for_update)
end
def test_all_timestamp_attributes
toy = Toy.first
- assert_equal toy.send(:all_timestamp_attributes), [:created_at, :created_on, :updated_at, :updated_on]
+ assert_equal [:created_at, :created_on, :updated_at, :updated_on], toy.send(:all_timestamp_attributes)
end
def test_timestamp_attributes_for_create_in_model
toy = Toy.first
- assert_equal toy.send(:timestamp_attributes_for_create_in_model), [:created_at]
+ assert_equal [:created_at], toy.send(:timestamp_attributes_for_create_in_model)
end
def test_timestamp_attributes_for_update_in_model
toy = Toy.first
- assert_equal toy.send(:timestamp_attributes_for_update_in_model), [:updated_at]
+ assert_equal [:updated_at], toy.send(:timestamp_attributes_for_update_in_model)
end
def test_all_timestamp_attributes_in_model
toy = Toy.first
- assert_equal toy.send(:all_timestamp_attributes_in_model), [:created_at, :updated_at]
+ assert_equal [:created_at, :updated_at], toy.send(:all_timestamp_attributes_in_model)
end
end
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index 9485de88a6..5644a35385 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -182,9 +182,9 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
end
def test_call_after_rollback_when_commit_fails
- @first.class.connection.class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction)
+ @first.class.connection.singleton_class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction)
begin
- @first.class.connection.class.class_eval do
+ @first.class.connection.singleton_class.class_eval do
def commit_db_transaction; raise "boom!"; end
end
@@ -194,8 +194,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
assert !@first.save rescue nil
assert_equal [:after_rollback], @first.history
ensure
- @first.class.connection.class.send(:remove_method, :commit_db_transaction)
- @first.class.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction)
+ @first.class.connection.singleton_class.send(:remove_method, :commit_db_transaction)
+ @first.class.connection.singleton_class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction)
end
end
diff --git a/activerecord/test/cases/transaction_isolation_test.rb b/activerecord/test/cases/transaction_isolation_test.rb
index 4f1cb99b68..f89c26532d 100644
--- a/activerecord/test/cases/transaction_isolation_test.rb
+++ b/activerecord/test/cases/transaction_isolation_test.rb
@@ -1,113 +1,105 @@
require 'cases/helper'
-class TransactionIsolationUnsupportedTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+unless ActiveRecord::Base.connection.supports_transaction_isolation?
+ class TransactionIsolationUnsupportedTest < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
- class Tag < ActiveRecord::Base
- end
-
- setup do
- if ActiveRecord::Base.connection.supports_transaction_isolation?
- skip "database supports transaction isolation; test is irrelevant"
+ class Tag < ActiveRecord::Base
end
- end
- test "setting the isolation level raises an error" do
- assert_raises(ActiveRecord::TransactionIsolationError) do
- Tag.transaction(isolation: :serializable) { }
+ test "setting the isolation level raises an error" do
+ assert_raises(ActiveRecord::TransactionIsolationError) do
+ Tag.transaction(isolation: :serializable) { }
+ end
end
end
end
-class TransactionIsolationTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
-
- class Tag < ActiveRecord::Base
- self.table_name = 'tags'
- end
-
- class Tag2 < ActiveRecord::Base
- self.table_name = 'tags'
- end
+if ActiveRecord::Base.connection.supports_transaction_isolation?
+ class TransactionIsolationTest < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
- setup do
- unless ActiveRecord::Base.connection.supports_transaction_isolation?
- skip "database does not support setting transaction isolation"
+ class Tag < ActiveRecord::Base
+ self.table_name = 'tags'
end
- Tag.establish_connection 'arunit'
- Tag2.establish_connection 'arunit'
- Tag.destroy_all
- end
-
- # It is impossible to properly test read uncommitted. The SQL standard only
- # specifies what must not happen at a certain level, not what must happen. At
- # the read uncommitted level, there is nothing that must not happen.
- test "read uncommitted" do
- unless ActiveRecord::Base.connection.transaction_isolation_levels.include?(:read_uncommitted)
- skip "database does not support read uncommitted isolation level"
+ class Tag2 < ActiveRecord::Base
+ self.table_name = 'tags'
end
- Tag.transaction(isolation: :read_uncommitted) do
- assert_equal 0, Tag.count
- Tag2.create
- assert_equal 1, Tag.count
+
+ setup do
+ Tag.establish_connection :arunit
+ Tag2.establish_connection :arunit
+ Tag.destroy_all
end
- end
- # We are testing that a dirty read does not happen
- test "read committed" do
- Tag.transaction(isolation: :read_committed) do
- assert_equal 0, Tag.count
+ # It is impossible to properly test read uncommitted. The SQL standard only
+ # specifies what must not happen at a certain level, not what must happen. At
+ # the read uncommitted level, there is nothing that must not happen.
+ if ActiveRecord::Base.connection.transaction_isolation_levels.include?(:read_uncommitted)
+ test "read uncommitted" do
+ Tag.transaction(isolation: :read_uncommitted) do
+ assert_equal 0, Tag.count
+ Tag2.create
+ assert_equal 1, Tag.count
+ end
+ end
+ end
- Tag2.transaction do
- Tag2.create
+ # We are testing that a dirty read does not happen
+ test "read committed" do
+ Tag.transaction(isolation: :read_committed) do
assert_equal 0, Tag.count
+
+ Tag2.transaction do
+ Tag2.create
+ assert_equal 0, Tag.count
+ end
end
+
+ assert_equal 1, Tag.count
end
- assert_equal 1, Tag.count
- end
+ # We are testing that a nonrepeatable read does not happen
+ if ActiveRecord::Base.connection.transaction_isolation_levels.include?(:repeatable_read)
+ test "repeatable read" do
+ tag = Tag.create(name: 'jon')
- # We are testing that a nonrepeatable read does not happen
- test "repeatable read" do
- unless ActiveRecord::Base.connection.transaction_isolation_levels.include?(:repeatable_read)
- skip "database does not support repeatable read isolation level"
- end
- tag = Tag.create(name: 'jon')
+ Tag.transaction(isolation: :repeatable_read) do
+ tag.reload
+ Tag2.find(tag.id).update(name: 'emily')
- Tag.transaction(isolation: :repeatable_read) do
- tag.reload
- Tag2.find(tag.id).update(name: 'emily')
+ tag.reload
+ assert_equal 'jon', tag.name
+ end
- tag.reload
- assert_equal 'jon', tag.name
+ tag.reload
+ assert_equal 'emily', tag.name
+ end
end
- tag.reload
- assert_equal 'emily', tag.name
- end
-
- # We are only testing that there are no errors because it's too hard to
- # test serializable. Databases behave differently to enforce the serializability
- # constraint.
- test "serializable" do
- Tag.transaction(isolation: :serializable) do
- Tag.create
+ # We are only testing that there are no errors because it's too hard to
+ # test serializable. Databases behave differently to enforce the serializability
+ # constraint.
+ test "serializable" do
+ Tag.transaction(isolation: :serializable) do
+ Tag.create
+ end
end
- end
- test "setting isolation when joining a transaction raises an error" do
- Tag.transaction do
- assert_raises(ActiveRecord::TransactionIsolationError) do
- Tag.transaction(isolation: :serializable) { }
+ test "setting isolation when joining a transaction raises an error" do
+ Tag.transaction do
+ assert_raises(ActiveRecord::TransactionIsolationError) do
+ Tag.transaction(isolation: :serializable) { }
+ end
end
end
- end
- test "setting isolation when starting a nested transaction raises error" do
- Tag.transaction do
- assert_raises(ActiveRecord::TransactionIsolationError) do
- Tag.transaction(requires_new: true, isolation: :serializable) { }
+ test "setting isolation when starting a nested transaction raises error" do
+ Tag.transaction do
+ assert_raises(ActiveRecord::TransactionIsolationError) do
+ Tag.transaction(requires_new: true, isolation: :serializable) { }
+ end
end
end
end
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index 6d66342fa5..89dab16975 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -117,6 +117,20 @@ class TransactionTest < ActiveRecord::TestCase
assert !Topic.find(1).approved?
end
+ def test_raising_exception_in_nested_transaction_restore_state_in_save
+ topic = Topic.new
+
+ def topic.after_save_for_transaction
+ raise 'Make the transaction rollback'
+ end
+
+ assert_raises(RuntimeError) do
+ Topic.transaction { topic.save }
+ end
+
+ assert topic.new_record?, "#{topic.inspect} should be new record"
+ end
+
def test_update_should_rollback_on_failure
author = Author.find(1)
posts_count = author.posts.size
@@ -361,6 +375,36 @@ class TransactionTest < ActiveRecord::TestCase
assert_equal "Three", @three
end if Topic.connection.supports_savepoints?
+ def test_using_named_savepoints
+ Topic.transaction do
+ @first.approved = true
+ @first.save!
+ Topic.connection.create_savepoint("first")
+
+ @first.approved = false
+ @first.save!
+ Topic.connection.rollback_to_savepoint("first")
+ assert @first.reload.approved?
+
+ @first.approved = false
+ @first.save!
+ Topic.connection.release_savepoint("first")
+ assert_not @first.reload.approved?
+ end
+ end if Topic.connection.supports_savepoints?
+
+ def test_releasing_named_savepoints
+ Topic.transaction do
+ Topic.connection.create_savepoint("another")
+ Topic.connection.release_savepoint("another")
+
+ # The savepoint is now gone and we can't remove it again.
+ assert_raises(ActiveRecord::StatementInvalid) do
+ Topic.connection.release_savepoint("another")
+ end
+ end
+ end
+
def test_rollback_when_commit_raises
Topic.connection.expects(:begin_db_transaction)
Topic.connection.expects(:commit_db_transaction).raises('OH NOES')
@@ -377,7 +421,9 @@ class TransactionTest < ActiveRecord::TestCase
topic = Topic.new(:title => 'test')
topic.freeze
e = assert_raise(RuntimeError) { topic.save }
- assert_equal "can't modify frozen Hash", e.message
+ assert_match(/frozen/i, e.message) # Not good enough, but we can't do much
+ # about it since there is no specific error
+ # for frozen objects.
assert !topic.persisted?, 'not persisted'
assert_nil topic.id
assert topic.frozen?, 'not frozen'
@@ -410,16 +456,6 @@ class TransactionTest < ActiveRecord::TestCase
assert !@second.destroyed?, 'not destroyed'
end
- if current_adapter?(:PostgreSQLAdapter) && defined?(PGconn::PQTRANS_IDLE)
- def test_outside_transaction_works
- assert assert_deprecated { Topic.connection.outside_transaction? }
- Topic.connection.begin_db_transaction
- assert assert_deprecated { !Topic.connection.outside_transaction? }
- Topic.connection.rollback_db_transaction
- assert assert_deprecated { Topic.connection.outside_transaction? }
- end
- end
-
def test_sqlite_add_column_in_transaction
return true unless current_adapter?(:SQLite3Adapter)
@@ -449,6 +485,13 @@ class TransactionTest < ActiveRecord::TestCase
raise ActiveRecord::Rollback
end
end
+ ensure
+ begin
+ Topic.connection.remove_column('topics', 'stuff')
+ rescue
+ ensure
+ Topic.reset_column_information
+ end
end
def test_transactions_state_from_rollback
@@ -535,16 +578,16 @@ if current_adapter?(:PostgreSQLAdapter)
class ConcurrentTransactionTest < TransactionTest
# 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
+ unless in_memory_db?
+ def test_transaction_per_thread
+ threads = 3.times.map do
Thread.new do
Topic.transaction do
topic = Topic.find(1)
topic.approved = !topic.approved?
- topic.save!
+ assert topic.save!
topic.approved = !topic.approved?
- topic.save!
+ assert topic.save!
end
Topic.connection.close
end
@@ -603,14 +646,5 @@ if current_adapter?(:PostgreSQLAdapter)
assert_equal original_salary, Developer.find(1).salary
end
-
- test "#transaction_joinable= is deprecated" do
- Developer.transaction do
- conn = Developer.connection
- assert conn.current_transaction.joinable?
- assert_deprecated { conn.transaction_joinable = false }
- assert !conn.current_transaction.joinable?
- end
- end
end
end
diff --git a/activerecord/test/cases/validations/association_validation_test.rb b/activerecord/test/cases/validations/association_validation_test.rb
index 7ac34bc71e..602f633c45 100644
--- a/activerecord/test/cases/validations/association_validation_test.rb
+++ b/activerecord/test/cases/validations/association_validation_test.rb
@@ -10,29 +10,33 @@ require 'models/interest'
class AssociationValidationTest < ActiveRecord::TestCase
fixtures :topics, :owners
- repair_validations(Topic, Reply, Owner)
+ repair_validations(Topic, Reply)
def test_validates_size_of_association
- assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
- o = Owner.new('name' => 'nopets')
- assert !o.save
- assert o.errors[:pets].any?
- o.pets.build('name' => 'apet')
- assert o.valid?
+ repair_validations Owner do
+ assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
+ o = Owner.new('name' => 'nopets')
+ assert !o.save
+ assert o.errors[:pets].any?
+ o.pets.build('name' => 'apet')
+ assert o.valid?
+ end
end
def test_validates_size_of_association_using_within
- assert_nothing_raised { Owner.validates_size_of :pets, :within => 1..2 }
- o = Owner.new('name' => 'nopets')
- assert !o.save
- assert o.errors[:pets].any?
-
- o.pets.build('name' => 'apet')
- assert o.valid?
-
- 2.times { o.pets.build('name' => 'apet') }
- assert !o.save
- assert o.errors[:pets].any?
+ repair_validations Owner do
+ assert_nothing_raised { Owner.validates_size_of :pets, :within => 1..2 }
+ o = Owner.new('name' => 'nopets')
+ assert !o.save
+ assert o.errors[:pets].any?
+
+ o.pets.build('name' => 'apet')
+ assert o.valid?
+
+ 2.times { o.pets.build('name' => 'apet') }
+ assert !o.save
+ assert o.errors[:pets].any?
+ end
end
def test_validates_associated_many
@@ -91,12 +95,14 @@ class AssociationValidationTest < ActiveRecord::TestCase
end
def test_validates_size_of_association_utf8
- assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
- o = Owner.new('name' => 'あいうえおかきくけこ')
- assert !o.save
- assert o.errors[:pets].any?
- o.pets.build('name' => 'あいうえおかきくけこ')
- assert o.valid?
+ repair_validations Owner do
+ assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
+ o = Owner.new('name' => 'あいうえおかきくけこ')
+ assert !o.save
+ assert o.errors[:pets].any?
+ o.pets.build('name' => 'あいうえおかきくけこ')
+ assert o.valid?
+ end
end
def test_validates_presence_of_belongs_to_association__parent_is_new_record
@@ -118,21 +124,4 @@ class AssociationValidationTest < ActiveRecord::TestCase
end
end
- def test_validates_associated_models_in_the_same_context
- Topic.validates_presence_of :title, :on => :custom_context
- Topic.validates_associated :replies
- Reply.validates_presence_of :title, :on => :custom_context
-
- t = Topic.new('title' => '')
- r = t.replies.new('title' => '')
-
- assert t.valid?
- assert !t.valid?(:custom_context)
-
- t.title = "Longer"
- assert !t.valid?(:custom_context), "Should NOT be valid if the associated object is not valid in the same context."
-
- r.title = "Longer"
- assert t.valid?(:custom_context), "Should be valid if the associated object is not valid in the same context."
- end
end
diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
index 32d2bf746f..a73c3bf1af 100644
--- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
+++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
@@ -55,22 +55,30 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase
end
test "translation for 'taken' can be overridden" do
- I18n.backend.store_translations "en", {errors: {attributes: {title: {taken: "Custom taken message" }}}}
- assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ reset_i18n_load_path do
+ I18n.backend.store_translations "en", {errors: {attributes: {title: {taken: "Custom taken message" }}}}
+ assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ end
end
test "translation for 'taken' can be overridden in activerecord scope" do
- I18n.backend.store_translations "en", {activerecord: {errors: {messages: {taken: "Custom taken message" }}}}
- assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ reset_i18n_load_path do
+ I18n.backend.store_translations "en", {activerecord: {errors: {messages: {taken: "Custom taken message" }}}}
+ assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ end
end
test "translation for 'taken' can be overridden in activerecord model scope" do
- I18n.backend.store_translations "en", {activerecord: {errors: {models: {topic: {taken: "Custom taken message" }}}}}
- assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ reset_i18n_load_path do
+ I18n.backend.store_translations "en", {activerecord: {errors: {models: {topic: {taken: "Custom taken message" }}}}}
+ assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ end
end
test "translation for 'taken' can be overridden in activerecord attributes scope" do
- I18n.backend.store_translations "en", {activerecord: {errors: {models: {topic: {attributes: {title: {taken: "Custom taken message" }}}}}}}
- assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ reset_i18n_load_path do
+ I18n.backend.store_translations "en", {activerecord: {errors: {models: {topic: {attributes: {title: {taken: "Custom taken message" }}}}}}}
+ assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ end
end
end
diff --git a/activerecord/test/cases/validations/presence_validation_test.rb b/activerecord/test/cases/validations/presence_validation_test.rb
index 1de8934406..3790d3c8cf 100644
--- a/activerecord/test/cases/validations/presence_validation_test.rb
+++ b/activerecord/test/cases/validations/presence_validation_test.rb
@@ -3,6 +3,8 @@ require "cases/helper"
require 'models/man'
require 'models/face'
require 'models/interest'
+require 'models/speedometer'
+require 'models/dashboard'
class PresenceValidationTest < ActiveRecord::TestCase
class Boy < Man; end
@@ -48,4 +50,18 @@ class PresenceValidationTest < ActiveRecord::TestCase
i2.mark_for_destruction
assert b.invalid?
end
+
+ def test_validates_presence_doesnt_convert_to_array
+ Speedometer.validates_presence_of :dashboard
+
+ dash = Dashboard.new
+
+ # dashboard has to_a method
+ def dash.to_a; ['(/)', '(\)']; end
+
+ s = Speedometer.new
+ s.dashboard = dash
+
+ assert_nothing_raised { s.valid? }
+ end
end
diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb
index 2b33f01783..74c696c858 100644
--- a/activerecord/test/cases/validations/uniqueness_validation_test.rb
+++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb
@@ -35,6 +35,11 @@ class Employee < ActiveRecord::Base
validates_uniqueness_of :nicknames
end
+class TopicWithUniqEvent < Topic
+ belongs_to :event, foreign_key: :parent_id
+ validates :event, uniqueness: true
+end
+
class UniquenessValidationTest < ActiveRecord::TestCase
fixtures :topics, 'warehouse-things', :developers
@@ -58,6 +63,14 @@ class UniquenessValidationTest < ActiveRecord::TestCase
assert t2.save, "Should now save t2 as unique"
end
+ def test_validate_uniqueness_with_alias_attribute
+ Topic.alias_attribute :new_title, :title
+ Topic.validates_uniqueness_of(:new_title)
+
+ topic = Topic.new(new_title: 'abc')
+ assert topic.valid?
+ end
+
def test_validates_uniqueness_with_nil_value
Topic.validates_uniqueness_of(:title)
@@ -365,15 +378,29 @@ class UniquenessValidationTest < ActiveRecord::TestCase
}
end
- def test_validate_uniqueness_with_array_column
- return skip "Uniqueness on arrays has only been tested in PostgreSQL so far." if !current_adapter? :PostgreSQLAdapter
+ if current_adapter? :PostgreSQLAdapter
+ def test_validate_uniqueness_with_array_column
+ e1 = Employee.create("nicknames" => ["john", "johnny"], "commission_by_quarter" => [1000, 1200])
+ assert e1.persisted?, "Saving e1"
- e1 = Employee.create("nicknames" => ["john", "johnny"], "commission_by_quarter" => [1000, 1200])
- assert e1.persisted?, "Saving e1"
+ e2 = Employee.create("nicknames" => ["john", "johnny"], "commission_by_quarter" => [2200])
+ assert !e2.persisted?, "e2 shouldn't be valid"
+ assert e2.errors[:nicknames].any?, "Should have errors for nicknames"
+ assert_equal ["has already been taken"], e2.errors[:nicknames], "Should have uniqueness message for nicknames"
+ end
+ end
+
+ def test_validate_uniqueness_on_existing_relation
+ event = Event.create
+ assert TopicWithUniqEvent.create(event: event).valid?
+
+ topic = TopicWithUniqEvent.new(event: event)
+ assert_not topic.valid?
+ assert_equal ['has already been taken'], topic.errors[:event]
+ end
- e2 = Employee.create("nicknames" => ["john", "johnny"], "commission_by_quarter" => [2200])
- assert !e2.persisted?, "e2 shouldn't be valid"
- assert e2.errors[:nicknames].any?, "Should have errors for nicknames"
- assert_equal ["has already been taken"], e2.errors[:nicknames], "Should have uniqueness message for nicknames"
+ def test_validate_uniqueness_on_empty_relation
+ topic = TopicWithUniqEvent.new
+ assert topic.valid?
end
end
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb
index 3f587d177b..de618902aa 100644
--- a/activerecord/test/cases/validations_test.rb
+++ b/activerecord/test/cases/validations_test.rb
@@ -56,13 +56,11 @@ class ValidationsTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::RecordInvalid) { WrongReply.create! }
assert_raise(ActiveRecord::RecordInvalid) { WrongReply.new.save! }
- begin
- r = WrongReply.new
+ r = WrongReply.new
+ invalid = assert_raise ActiveRecord::RecordInvalid do
r.save!
- flunk
- rescue ActiveRecord::RecordInvalid => invalid
- assert_equal r, invalid.record
end
+ assert_equal r, invalid.record
end
def test_exception_on_create_bang_many
@@ -93,7 +91,7 @@ class ValidationsTest < ActiveRecord::TestCase
assert reply.save(:validate => false)
end
- def test_validates_acceptance_of_with_non_existant_table
+ def test_validates_acceptance_of_with_non_existent_table
Object.const_set :IncorporealModel, Class.new(ActiveRecord::Base)
assert_nothing_raised ActiveRecord::StatementInvalid do
diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb
index 68fa15de50..78fa2f935a 100644
--- a/activerecord/test/cases/xml_serialization_test.rb
+++ b/activerecord/test/cases/xml_serialization_test.rb
@@ -161,21 +161,17 @@ end
class DefaultXmlSerializationTimezoneTest < ActiveRecord::TestCase
def test_should_serialize_datetime_with_timezone
- timezone, Time.zone = Time.zone, "Pacific Time (US & Canada)"
-
- toy = Toy.create(:name => 'Mickey', :updated_at => Time.utc(2006, 8, 1))
- assert_match %r{<updated-at type=\"dateTime\">2006-07-31T17:00:00-07:00</updated-at>}, toy.to_xml
- ensure
- Time.zone = timezone
+ with_timezone_config zone: "Pacific Time (US & Canada)" do
+ toy = Toy.create(:name => 'Mickey', :updated_at => Time.utc(2006, 8, 1))
+ assert_match %r{<updated-at type=\"dateTime\">2006-07-31T17:00:00-07:00</updated-at>}, toy.to_xml
+ end
end
def test_should_serialize_datetime_with_timezone_reloaded
- timezone, Time.zone = Time.zone, "Pacific Time (US & Canada)"
-
- toy = Toy.create(:name => 'Minnie', :updated_at => Time.utc(2006, 8, 1)).reload
- assert_match %r{<updated-at type=\"dateTime\">2006-07-31T17:00:00-07:00</updated-at>}, toy.to_xml
- ensure
- Time.zone = timezone
+ with_timezone_config zone: "Pacific Time (US & Canada)" do
+ toy = Toy.create(:name => 'Minnie', :updated_at => Time.utc(2006, 8, 1)).reload
+ assert_match %r{<updated-at type=\"dateTime\">2006-07-31T17:00:00-07:00</updated-at>}, toy.to_xml
+ end
end
end
diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb
index 302913e095..15815d56e4 100644
--- a/activerecord/test/cases/yaml_serialization_test.rb
+++ b/activerecord/test/cases/yaml_serialization_test.rb
@@ -5,16 +5,10 @@ class YamlSerializationTest < ActiveRecord::TestCase
fixtures :topics
def test_to_yaml_with_time_with_zone_should_not_raise_exception
- tz = Time.zone
- Time.zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"]
- ActiveRecord::Base.time_zone_aware_attributes = true
-
- topic = Topic.new(:written_on => DateTime.now)
- assert_nothing_raised { topic.to_yaml }
-
- ensure
- Time.zone = tz
- ActiveRecord::Base.time_zone_aware_attributes = false
+ with_timezone_config aware_attributes: true, zone: "Pacific Time (US & Canada)" do
+ topic = Topic.new(:written_on => DateTime.now)
+ assert_nothing_raised { topic.to_yaml }
+ end
end
def test_roundtrip
@@ -49,4 +43,8 @@ class YamlSerializationTest < ActiveRecord::TestCase
t = Psych.load Psych.dump topic
assert_equal topic.attributes, t.attributes
end
+
+ def test_active_record_relation_serialization
+ [Topic.all].to_yaml
+ end
end
diff --git a/activerecord/test/fixtures/all/admin b/activerecord/test/fixtures/all/admin
new file mode 120000
index 0000000000..984d12a043
--- /dev/null
+++ b/activerecord/test/fixtures/all/admin
@@ -0,0 +1 @@
+../to_be_linked/ \ No newline at end of file
diff --git a/activerecord/test/fixtures/owners.yml b/activerecord/test/fixtures/owners.yml
index 2d21ce433c..3b7b29bb34 100644
--- a/activerecord/test/fixtures/owners.yml
+++ b/activerecord/test/fixtures/owners.yml
@@ -2,6 +2,7 @@ blackbeard:
owner_id: 1
name: blackbeard
essay_id: A Modest Proposal
+ happy_at: '2150-10-10 16:00:00'
ashley:
owner_id: 2
diff --git a/activerecord/test/fixtures/sponsors.yml b/activerecord/test/fixtures/sponsors.yml
index bfc6b238b1..2da541c539 100644
--- a/activerecord/test/fixtures/sponsors.yml
+++ b/activerecord/test/fixtures/sponsors.yml
@@ -8,5 +8,5 @@ boring_club_sponsor_for_groucho:
sponsorable_type: Member
crazy_club_sponsor_for_groucho:
sponsor_club: crazy_club
- sponsorable_id: 2
+ sponsorable_id: 3
sponsorable_type: Member
diff --git a/activerecord/test/fixtures/tasks.yml b/activerecord/test/fixtures/tasks.yml
index 402ca85faf..c38b32b0e5 100644
--- a/activerecord/test/fixtures/tasks.yml
+++ b/activerecord/test/fixtures/tasks.yml
@@ -1,4 +1,4 @@
-# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
first_task:
id: 1
starting: 2005-03-30t06:30:00.00+01:00
diff --git a/activerecord/test/fixtures/to_be_linked/accounts.yml b/activerecord/test/fixtures/to_be_linked/accounts.yml
new file mode 100644
index 0000000000..9e341a15af
--- /dev/null
+++ b/activerecord/test/fixtures/to_be_linked/accounts.yml
@@ -0,0 +1,2 @@
+signals37:
+ name: 37signals
diff --git a/activerecord/test/fixtures/to_be_linked/users.yml b/activerecord/test/fixtures/to_be_linked/users.yml
new file mode 100644
index 0000000000..e2884beda5
--- /dev/null
+++ b/activerecord/test/fixtures/to_be_linked/users.yml
@@ -0,0 +1,10 @@
+david:
+ name: David
+ account: signals37
+
+jamis:
+ name: Jamis
+ account: signals37
+ settings:
+ :symbol: symbol
+ string: string
diff --git a/activerecord/test/migrations/version_check/20131219224947_migration_version_check.rb b/activerecord/test/migrations/version_check/20131219224947_migration_version_check.rb
new file mode 100644
index 0000000000..9d46485a31
--- /dev/null
+++ b/activerecord/test/migrations/version_check/20131219224947_migration_version_check.rb
@@ -0,0 +1,8 @@
+class MigrationVersionCheck < ActiveRecord::Migration
+ def self.up
+ raise "incorrect migration version" unless version == 20131219224947
+ end
+
+ def self.down
+ end
+end
diff --git a/activerecord/test/models/admin/user.rb b/activerecord/test/models/admin/user.rb
index 4c3b71e8f9..48a110bd23 100644
--- a/activerecord/test/models/admin/user.rb
+++ b/activerecord/test/models/admin/user.rb
@@ -14,6 +14,7 @@ class Admin::User < ActiveRecord::Base
end
belongs_to :account
+ store :params, accessors: [ :token ], coder: YAML
store :settings, :accessors => [ :color, :homepage ]
store_accessor :settings, :favorite_food
store :preferences, :accessors => [ :remember_login ]
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index a96899ae10..c197951c71 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -8,12 +8,14 @@ class Author < ActiveRecord::Base
has_many :posts_sorted_by_id_limited, -> { order('posts.id').limit(1) }, :class_name => "Post"
has_many :posts_with_categories, -> { includes(:categories) }, :class_name => "Post"
has_many :posts_with_comments_and_categories, -> { includes(:comments, :categories).order("posts.id") }, :class_name => "Post"
- has_many :posts_containing_the_letter_a, :class_name => "Post"
has_many :posts_with_special_categorizations, :class_name => 'PostWithSpecialCategorization'
- has_many :posts_with_extension, :class_name => "Post"
has_one :post_about_thinking, -> { where("posts.title like '%thinking%'") }, :class_name => 'Post'
has_one :post_about_thinking_with_last_comment, -> { where("posts.title like '%thinking%'").includes(:last_comment) }, :class_name => 'Post'
- has_many :comments, :through => :posts
+ has_many :comments, through: :posts do
+ def ratings
+ Rating.joins(:comment).merge(self)
+ end
+ end
has_many :comments_containing_the_letter_e, :through => :posts, :source => :comments
has_many :comments_with_order_and_conditions, -> { order('comments.body').where("comments.body like 'Thank%'") }, :through => :posts, :source => :comments
has_many :comments_with_include, -> { includes(:post) }, :through => :posts, :source => :comments
@@ -27,8 +29,14 @@ class Author < ActiveRecord::Base
has_many :thinking_posts, -> { where(:title => 'So I was thinking') }, :dependent => :delete_all, :class_name => 'Post'
has_many :welcome_posts, -> { where(:title => 'Welcome to the weblog') }, :class_name => 'Post'
+ has_many :welcome_posts_with_one_comment,
+ -> { where(title: 'Welcome to the weblog').where('comments_count = ?', 1) },
+ class_name: 'Post'
+ has_many :welcome_posts_with_comments,
+ -> { where(title: 'Welcome to the weblog').where(Post.arel_table[:comments_count].gt(0)) },
+ class_name: 'Post'
+
has_many :comments_desc, -> { order('comments.id DESC') }, :through => :posts, :source => :comments
- has_many :limited_comments, -> { limit(1) }, :through => :posts, :source => :comments
has_many :funky_comments, :through => :posts, :source => :comments
has_many :ordered_uniq_comments, -> { distinct.order('comments.id') }, :through => :posts, :source => :comments
has_many :ordered_uniq_comments_desc, -> { distinct.order('comments.id DESC') }, :through => :posts, :source => :comments
@@ -85,7 +93,7 @@ class Author < ActiveRecord::Base
has_many :author_favorites
has_many :favorite_authors, -> { order('name') }, :through => :author_favorites
- has_many :taggings, :through => :posts
+ has_many :taggings, :through => :posts, :source => :taggings
has_many :taggings_2, :through => :posts, :source => :tagging
has_many :tags, :through => :posts
has_many :post_categories, :through => :posts, :source => :categories
diff --git a/activerecord/test/models/auto_id.rb b/activerecord/test/models/auto_id.rb
index d720e2be5e..82c6544bd5 100644
--- a/activerecord/test/models/auto_id.rb
+++ b/activerecord/test/models/auto_id.rb
@@ -1,4 +1,4 @@
class AutoId < ActiveRecord::Base
- def self.table_name () "auto_id_tests" end
- def self.primary_key () "auto_id" end
+ self.table_name = "auto_id_tests"
+ self.primary_key = "auto_id"
end
diff --git a/activerecord/test/models/book.rb b/activerecord/test/models/book.rb
index 5458a28cc9..4cb2c7606b 100644
--- a/activerecord/test/models/book.rb
+++ b/activerecord/test/models/book.rb
@@ -2,8 +2,16 @@ class Book < ActiveRecord::Base
has_many :authors
has_many :citations, :foreign_key => 'book1_id'
- has_many :references, -> { distinct }, :through => :citations, :source => :reference_of
+ has_many :references, -> { distinct }, through: :citations, source: :reference_of
has_many :subscriptions
- has_many :subscribers, :through => :subscriptions
+ has_many :subscribers, through: :subscriptions
+
+ enum status: [:proposed, :written, :published]
+ enum read_status: {unread: 0, reading: 2, read: 3}
+
+ def published!
+ super
+ "do publish work..."
+ end
end
diff --git a/activerecord/test/models/bulb.rb b/activerecord/test/models/bulb.rb
index 0109ef4f83..831a0d5387 100644
--- a/activerecord/test/models/bulb.rb
+++ b/activerecord/test/models/bulb.rb
@@ -37,3 +37,15 @@ class CustomBulb < Bulb
self.frickinawesome = true if name == 'Dude'
end
end
+
+class FunkyBulb < Bulb
+ before_destroy do
+ raise "before_destroy was called"
+ end
+end
+
+class FailedBulb < Bulb
+ before_destroy do
+ false
+ end
+end
diff --git a/activerecord/test/models/cake_designer.rb b/activerecord/test/models/cake_designer.rb
new file mode 100644
index 0000000000..9c57ef573a
--- /dev/null
+++ b/activerecord/test/models/cake_designer.rb
@@ -0,0 +1,3 @@
+class CakeDesigner < ActiveRecord::Base
+ has_one :chef, as: :employable
+end
diff --git a/activerecord/test/models/car.rb b/activerecord/test/models/car.rb
index ac42f444e1..c4a15a79e2 100644
--- a/activerecord/test/models/car.rb
+++ b/activerecord/test/models/car.rb
@@ -1,11 +1,11 @@
class Car < ActiveRecord::Base
-
has_many :bulbs
+ has_many :all_bulbs, -> { unscope where: :name }, class_name: "Bulb"
+ has_many :funky_bulbs, class_name: 'FunkyBulb', dependent: :destroy
+ has_many :failed_bulbs, class_name: 'FailedBulb', dependent: :destroy
has_many :foo_bulbs, -> { where(:name => 'foo') }, :class_name => "Bulb"
- has_many :frickinawesome_bulbs, -> { where :frickinawesome => true }, :class_name => "Bulb"
has_one :bulb
- has_one :frickinawesome_bulb, -> { where :frickinawesome => true }, :class_name => "Bulb"
has_many :tyres
has_many :engines, :dependent => :destroy
diff --git a/activerecord/test/models/chef.rb b/activerecord/test/models/chef.rb
new file mode 100644
index 0000000000..67a4e54f06
--- /dev/null
+++ b/activerecord/test/models/chef.rb
@@ -0,0 +1,3 @@
+class Chef < ActiveRecord::Base
+ belongs_to :employable, polymorphic: true
+end
diff --git a/activerecord/test/models/citation.rb b/activerecord/test/models/citation.rb
index 545aa8110d..3d87eb795c 100644
--- a/activerecord/test/models/citation.rb
+++ b/activerecord/test/models/citation.rb
@@ -1,6 +1,3 @@
class Citation < ActiveRecord::Base
belongs_to :reference_of, :class_name => "Book", :foreign_key => :book2_id
-
- belongs_to :book1, :class_name => "Book", :foreign_key => :book1_id
- belongs_to :book2, :class_name => "Book", :foreign_key => :book2_id
end
diff --git a/activerecord/test/models/club.rb b/activerecord/test/models/club.rb
index 7d7c205041..566e0873f1 100644
--- a/activerecord/test/models/club.rb
+++ b/activerecord/test/models/club.rb
@@ -1,8 +1,7 @@
class Club < ActiveRecord::Base
has_one :membership
- has_many :memberships, :automatic_inverse_of => false
+ has_many :memberships, :inverse_of => false
has_many :members, :through => :memberships
- has_many :current_memberships
has_one :sponsor
has_one :sponsored_member, :through => :sponsor, :source => :sponsorable, :source_type => "Member"
belongs_to :category
diff --git a/activerecord/test/models/column_name.rb b/activerecord/test/models/column_name.rb
index ec07205a3a..460eb4fe20 100644
--- a/activerecord/test/models/column_name.rb
+++ b/activerecord/test/models/column_name.rb
@@ -1,3 +1,3 @@
class ColumnName < ActiveRecord::Base
- def self.table_name () "colnametests" end
-end \ No newline at end of file
+ self.table_name = "colnametests"
+end
diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb
index dcda62e71d..76411ecb37 100644
--- a/activerecord/test/models/company.rb
+++ b/activerecord/test/models/company.rb
@@ -11,6 +11,11 @@ class Company < AbstractCompany
has_many :contracts
has_many :developers, :through => :contracts
+ scope :of_first_firm, lambda {
+ joins(:account => :firm).
+ where('firms.id' => 1)
+ }
+
def arbitrary_method
"I am Jack's profound disappointment"
end
@@ -35,17 +40,13 @@ module Namespaced
end
class Firm < Company
- ActiveSupport::Deprecation.silence do
- has_many :clients, -> { order "id" }, :dependent => :destroy, :counter_sql =>
- "SELECT COUNT(*) FROM companies WHERE firm_id = 1 " +
- "AND (#{QUOTED_TYPE} = 'Client' OR #{QUOTED_TYPE} = 'SpecialClient' OR #{QUOTED_TYPE} = 'VerySpecialClient' )",
- :before_remove => :log_before_remove,
- :after_remove => :log_after_remove
- end
+ to_param :name
+
+ has_many :clients, -> { order "id" }, :dependent => :destroy, :before_remove => :log_before_remove, :after_remove => :log_after_remove
has_many :unsorted_clients, :class_name => "Client"
has_many :unsorted_clients_with_symbol, :class_name => :Client
has_many :clients_sorted_desc, -> { order "id DESC" }, :class_name => "Client"
- has_many :clients_of_firm, -> { order "id" }, :foreign_key => "client_of", :class_name => "Client"
+ has_many :clients_of_firm, -> { order "id" }, :foreign_key => "client_of", :class_name => "Client", :inverse_of => :firm
has_many :clients_ordered_by_name, -> { order "name" }, :class_name => "Client"
has_many :unvalidated_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :validate => false
has_many :dependent_clients_of_firm, -> { order "id" }, :foreign_key => "client_of", :class_name => "Client", :dependent => :destroy
@@ -54,21 +55,7 @@ class Firm < Company
has_many :clients_with_interpolated_conditions, ->(firm) { where "rating > #{firm.rating}" }, :class_name => "Client"
has_many :clients_like_ms, -> { where("name = 'Microsoft'").order("id") }, :class_name => "Client"
has_many :clients_like_ms_with_hash_conditions, -> { where(:name => 'Microsoft').order("id") }, :class_name => "Client"
- ActiveSupport::Deprecation.silence do
- has_many :clients_using_sql, :class_name => "Client", :finder_sql => proc { "SELECT * FROM companies WHERE client_of = #{id}" }
- has_many :clients_using_counter_sql, :class_name => "Client",
- :finder_sql => proc { "SELECT * FROM companies WHERE client_of = #{id} " },
- :counter_sql => proc { "SELECT COUNT(*) FROM companies WHERE client_of = #{id}" }
- has_many :clients_using_zero_counter_sql, :class_name => "Client",
- :finder_sql => proc { "SELECT * FROM companies WHERE client_of = #{id}" },
- :counter_sql => proc { "SELECT 0 FROM companies WHERE client_of = #{id}" }
- has_many :no_clients_using_counter_sql, :class_name => "Client",
- :finder_sql => 'SELECT * FROM companies WHERE client_of = 1000',
- :counter_sql => 'SELECT COUNT(*) FROM companies WHERE client_of = 1000'
- has_many :clients_using_finder_sql, :class_name => "Client", :finder_sql => 'SELECT * FROM companies WHERE 1=1'
- end
has_many :plain_clients, :class_name => 'Client'
- has_many :readonly_clients, -> { readonly }, :class_name => 'Client'
has_many :clients_using_primary_key, :class_name => 'Client',
:primary_key => 'name', :foreign_key => 'firm_name'
has_many :clients_using_primary_key_with_delete_all, :class_name => 'Client',
@@ -114,13 +101,6 @@ class DependentFirm < Company
has_one :company, :foreign_key => 'client_of', :dependent => :nullify
end
-class RestrictedFirm < Company
- ActiveSupport::Deprecation.silence do
- has_one :account, -> { order("id") }, :foreign_key => "firm_id", :dependent => :restrict
- has_many :companies, -> { order("id") }, :foreign_key => 'client_of', :dependent => :restrict
- end
-end
-
class RestrictedWithExceptionFirm < Company
has_one :account, -> { order("id") }, :foreign_key => "firm_id", :dependent => :restrict_with_exception
has_many :companies, -> { order("id") }, :foreign_key => 'client_of', :dependent => :restrict_with_exception
@@ -141,9 +121,13 @@ class Client < Company
belongs_to :firm_with_primary_key_symbols, :class_name => "Firm", :primary_key => :name, :foreign_key => :firm_name
belongs_to :readonly_firm, -> { readonly }, :class_name => "Firm", :foreign_key => "firm_id"
belongs_to :bob_firm, -> { where :name => "Bob" }, :class_name => "Firm", :foreign_key => "client_of"
- has_many :accounts, :through => :firm
+ has_many :accounts, :through => :firm, :source => :accounts
belongs_to :account
+ validate do
+ firm
+ end
+
class RaisedOnSave < RuntimeError; end
attr_accessor :raise_on_save
before_save do
@@ -193,7 +177,6 @@ class ExclusivelyDependentFirm < Company
has_one :account, :foreign_key => "firm_id", :dependent => :delete
has_many :dependent_sanitized_conditional_clients_of_firm, -> { order("id").where("name = 'BigShot Inc.'") }, :foreign_key => "client_of", :class_name => "Client", :dependent => :delete_all
has_many :dependent_conditional_clients_of_firm, -> { order("id").where("name = ?", 'BigShot Inc.') }, :foreign_key => "client_of", :class_name => "Client", :dependent => :delete_all
- has_many :dependent_hash_conditional_clients_of_firm, -> { order("id").where(:name => 'BigShot Inc.') }, :foreign_key => "client_of", :class_name => "Client", :dependent => :delete_all
end
class SpecialClient < Client
diff --git a/activerecord/test/models/company_in_module.rb b/activerecord/test/models/company_in_module.rb
index 461bb0de09..38b0b6aafa 100644
--- a/activerecord/test/models/company_in_module.rb
+++ b/activerecord/test/models/company_in_module.rb
@@ -10,10 +10,6 @@ module MyApplication
has_many :clients_sorted_desc, -> { order("id DESC") }, :class_name => "Client"
has_many :clients_of_firm, -> { order "id" }, :foreign_key => "client_of", :class_name => "Client"
has_many :clients_like_ms, -> { where("name = 'Microsoft'").order("id") }, :class_name => "Client"
- ActiveSupport::Deprecation.silence do
- has_many :clients_using_sql, :class_name => "Client", :finder_sql => 'SELECT * FROM companies WHERE client_of = #{id}'
- end
-
has_one :account, :class_name => 'MyApplication::Billing::Account', :dependent => :destroy
end
diff --git a/activerecord/test/models/contract.rb b/activerecord/test/models/contract.rb
index 2cf5aa7a85..cdf7b267b5 100644
--- a/activerecord/test/models/contract.rb
+++ b/activerecord/test/models/contract.rb
@@ -1,6 +1,7 @@
class Contract < ActiveRecord::Base
belongs_to :company
belongs_to :developer
+ belongs_to :firm, :foreign_key => 'company_id'
before_save :hi
after_save :bye
diff --git a/activerecord/test/models/department.rb b/activerecord/test/models/department.rb
new file mode 100644
index 0000000000..08004a0ed3
--- /dev/null
+++ b/activerecord/test/models/department.rb
@@ -0,0 +1,4 @@
+class Department < ActiveRecord::Base
+ has_many :chefs
+ belongs_to :hotel
+end
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 81bc87bd42..2e2d8a0d37 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -1,11 +1,5 @@
require 'ostruct'
-module DeveloperProjectsAssociationExtension
- def find_most_recent
- order("id DESC").first
- end
-end
-
module DeveloperProjectsAssociationExtension2
def find_least_recent
order("id ASC").first
@@ -42,8 +36,14 @@ class Developer < ActiveRecord::Base
end
has_and_belongs_to_many :special_projects, :join_table => 'developers_projects', :association_foreign_key => 'project_id'
+ has_and_belongs_to_many :sym_special_projects,
+ :join_table => :developers_projects,
+ :association_foreign_key => 'project_id',
+ :class_name => 'SpecialProject'
has_many :audit_logs
+ has_many :contracts
+ has_many :firms, :through => :contracts, :source => :firm
scope :jamises, -> { where(:name => 'Jamis') }
diff --git a/activerecord/test/models/drink_designer.rb b/activerecord/test/models/drink_designer.rb
new file mode 100644
index 0000000000..2db968ef11
--- /dev/null
+++ b/activerecord/test/models/drink_designer.rb
@@ -0,0 +1,3 @@
+class DrinkDesigner < ActiveRecord::Base
+ has_one :chef, as: :employable
+end
diff --git a/activerecord/test/models/hotel.rb b/activerecord/test/models/hotel.rb
new file mode 100644
index 0000000000..b352cd22f3
--- /dev/null
+++ b/activerecord/test/models/hotel.rb
@@ -0,0 +1,6 @@
+class Hotel < ActiveRecord::Base
+ has_many :departments
+ has_many :chefs, through: :departments
+ has_many :cake_designers, source_type: 'CakeDesigner', source: :employable, through: :chefs
+ has_many :drink_designers, source_type: 'DrinkDesigner', source: :employable, through: :chefs
+end
diff --git a/activerecord/test/models/interest.rb b/activerecord/test/models/interest.rb
index f772bb1c7f..d5d9226204 100644
--- a/activerecord/test/models/interest.rb
+++ b/activerecord/test/models/interest.rb
@@ -1,5 +1,5 @@
class Interest < ActiveRecord::Base
- belongs_to :man, :inverse_of => :interests, :automatic_inverse_of => false
+ belongs_to :man, :inverse_of => :interests
belongs_to :polymorphic_man, :polymorphic => true, :inverse_of => :polymorphic_interests
belongs_to :zine, :inverse_of => :interests
end
diff --git a/activerecord/test/models/man.rb b/activerecord/test/models/man.rb
index 49f002aa9a..f4d127730c 100644
--- a/activerecord/test/models/man.rb
+++ b/activerecord/test/models/man.rb
@@ -1,9 +1,10 @@
class Man < ActiveRecord::Base
has_one :face, :inverse_of => :man
has_one :polymorphic_face, :class_name => 'Face', :as => :polymorphic_man, :inverse_of => :polymorphic_man
- has_many :interests, :inverse_of => :man, :automatic_inverse_of => false
+ has_many :interests, :inverse_of => :man
has_many :polymorphic_interests, :class_name => 'Interest', :as => :polymorphic_man, :inverse_of => :polymorphic_man
# These are "broken" inverse_of associations for the purposes of testing
has_one :dirty_face, :class_name => 'Face', :inverse_of => :dirty_man
has_many :secret_interests, :class_name => 'Interest', :inverse_of => :secret_man
+ has_one :mixed_case_monkey
end
diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb
index b81304b8e0..72095f9236 100644
--- a/activerecord/test/models/member.rb
+++ b/activerecord/test/models/member.rb
@@ -2,14 +2,13 @@ class Member < ActiveRecord::Base
has_one :current_membership
has_one :selected_membership
has_one :membership
- has_many :fellow_members, :through => :club, :source => :members
has_one :club, :through => :current_membership
has_one :selected_club, :through => :selected_membership, :source => :club
has_one :favourite_club, -> { where "memberships.favourite = ?", true }, :through => :membership, :source => :club
has_one :hairy_club, -> { where :clubs => {:name => "Moustache and Eyebrow Fancier Club"} }, :through => :membership, :source => :club
has_one :sponsor, :as => :sponsorable
has_one :sponsor_club, :through => :sponsor
- has_one :member_detail, :automatic_inverse_of => false
+ has_one :member_detail, :inverse_of => false
has_one :organization, :through => :member_detail
belongs_to :member_type
diff --git a/activerecord/test/models/member_detail.rb b/activerecord/test/models/member_detail.rb
index a256c73c7e..9d253aa126 100644
--- a/activerecord/test/models/member_detail.rb
+++ b/activerecord/test/models/member_detail.rb
@@ -1,5 +1,5 @@
class MemberDetail < ActiveRecord::Base
- belongs_to :member, :automatic_inverse_of => false
+ belongs_to :member, :inverse_of => false
belongs_to :organization
has_one :member_type, :through => :member
diff --git a/activerecord/test/models/membership.rb b/activerecord/test/models/membership.rb
index bcbb7e42c5..df7167ee93 100644
--- a/activerecord/test/models/membership.rb
+++ b/activerecord/test/models/membership.rb
@@ -8,6 +8,11 @@ class CurrentMembership < Membership
belongs_to :club
end
+class SuperMembership < Membership
+ belongs_to :member, -> { order('members.id DESC') }
+ belongs_to :club
+end
+
class SelectedMembership < Membership
def self.default_scope
select("'1' as foo")
diff --git a/activerecord/test/models/mixed_case_monkey.rb b/activerecord/test/models/mixed_case_monkey.rb
index 763baefd91..4d37371777 100644
--- a/activerecord/test/models/mixed_case_monkey.rb
+++ b/activerecord/test/models/mixed_case_monkey.rb
@@ -1,3 +1,5 @@
class MixedCaseMonkey < ActiveRecord::Base
self.primary_key = 'monkeyID'
+
+ belongs_to :man
end
diff --git a/activerecord/test/models/movie.rb b/activerecord/test/models/movie.rb
index 6384b4c801..c441be2bef 100644
--- a/activerecord/test/models/movie.rb
+++ b/activerecord/test/models/movie.rb
@@ -1,5 +1,3 @@
class Movie < ActiveRecord::Base
- def self.primary_key
- "movieid"
- end
+ self.primary_key = "movieid"
end
diff --git a/activerecord/test/models/parrot.rb b/activerecord/test/models/parrot.rb
index c4ee2bd19d..e76e83f314 100644
--- a/activerecord/test/models/parrot.rb
+++ b/activerecord/test/models/parrot.rb
@@ -21,3 +21,9 @@ end
class DeadParrot < Parrot
belongs_to :killer, :class_name => 'Pirate'
end
+
+class FunkyParrot < Parrot
+ before_destroy do
+ raise "before_destroy was called"
+ end
+end
diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb
index 2985160d28..1a282dbce4 100644
--- a/activerecord/test/models/person.rb
+++ b/activerecord/test/models/person.rb
@@ -32,6 +32,7 @@ class Person < ActiveRecord::Base
has_many :agents_posts, :through => :agents, :source => :posts
has_many :agents_posts_authors, :through => :agents_posts, :source => :author
+ has_many :essays, primary_key: "first_name", foreign_key: "writer_id"
scope :males, -> { where(:gender => 'M') }
scope :females, -> { where(:gender => 'F') }
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 93a7a2073c..faf539a562 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -1,4 +1,10 @@
class Post < ActiveRecord::Base
+ class CategoryPost < ActiveRecord::Base
+ self.table_name = "categories_posts"
+ belongs_to :category
+ belongs_to :post
+ end
+
module NamedExtension
def author
'lifo'
@@ -59,6 +65,9 @@ class Post < ActiveRecord::Base
has_many :author_favorites, :through => :author
has_many :author_categorizations, :through => :author, :source => :categorizations
has_many :author_addresses, :through => :author
+ has_many :author_address_extra_with_address,
+ through: :author_with_address,
+ source: :author_address_extra
has_many :comments_with_interpolated_conditions,
->(p) { where "#{"#{p.aliased_table_name}." rescue ""}body = ?", 'Thank you for the welcome' },
@@ -72,6 +81,8 @@ class Post < ActiveRecord::Base
has_many :special_comments_ratings, :through => :special_comments, :source => :ratings
has_many :special_comments_ratings_taggings, :through => :special_comments_ratings, :source => :taggings
+ has_many :category_posts, :class_name => 'CategoryPost'
+ has_many :scategories, through: :category_posts, source: :category
has_and_belongs_to_many :categories
has_and_belongs_to_many :special_categories, :join_table => "categories_posts", :association_foreign_key => 'category_id'
@@ -122,7 +133,6 @@ class Post < ActiveRecord::Base
has_many :secure_readers
has_many :readers_with_person, -> { includes(:person) }, :class_name => "Reader"
has_many :people, :through => :readers
- has_many :secure_people, :through => :secure_readers
has_many :single_people, :through => :readers
has_many :people_with_callbacks, :source=>:person, :through => :readers,
:before_add => lambda {|owner, reader| log(:added, :before, reader.first_name) },
diff --git a/activerecord/test/models/project.rb b/activerecord/test/models/project.rb
index f893754b9f..7f42a4b1f8 100644
--- a/activerecord/test/models/project.rb
+++ b/activerecord/test/models/project.rb
@@ -1,25 +1,11 @@
class Project < ActiveRecord::Base
has_and_belongs_to_many :developers, -> { distinct.order 'developers.name desc, developers.id desc' }
has_and_belongs_to_many :readonly_developers, -> { readonly }, :class_name => "Developer"
- has_and_belongs_to_many :selected_developers, -> { distinct.select "developers.*" }, :class_name => "Developer"
has_and_belongs_to_many :non_unique_developers, -> { order 'developers.name desc, developers.id desc' }, :class_name => 'Developer'
has_and_belongs_to_many :limited_developers, -> { limit 1 }, :class_name => "Developer"
has_and_belongs_to_many :developers_named_david, -> { where("name = 'David'").distinct }, :class_name => "Developer"
has_and_belongs_to_many :developers_named_david_with_hash_conditions, -> { where(:name => 'David').distinct }, :class_name => "Developer"
has_and_belongs_to_many :salaried_developers, -> { where "salary > 0" }, :class_name => "Developer"
-
- ActiveSupport::Deprecation.silence do
- has_and_belongs_to_many :developers_with_finder_sql, :class_name => "Developer", :finder_sql => proc { "SELECT t.*, j.* FROM developers_projects j, developers t WHERE t.id = j.developer_id AND j.project_id = #{id} ORDER BY t.id" }
- has_and_belongs_to_many :developers_with_multiline_finder_sql, :class_name => "Developer", :finder_sql => proc {
- "SELECT
- t.*, j.*
- FROM
- developers_projects j,
- developers t WHERE t.id = j.developer_id AND j.project_id = #{id} ORDER BY t.id"
- }
- has_and_belongs_to_many :developers_by_sql, :class_name => "Developer", :delete_sql => proc { |record| "DELETE FROM developers_projects WHERE project_id = #{id} AND developer_id = #{record.id}" }
- end
-
has_and_belongs_to_many :developers_with_callbacks, :class_name => "Developer", :before_add => Proc.new {|o, r| o.developers_log << "before_adding#{r.id || '<new>'}"},
:after_add => Proc.new {|o, r| o.developers_log << "after_adding#{r.id || '<new>'}"},
:before_remove => Proc.new {|o, r| o.developers_log << "before_removing#{r.id}"},
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index 17035bf338..f81ffe1d90 100644
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
@@ -34,7 +34,6 @@ class Topic < ActiveRecord::Base
has_many :replies, :dependent => :destroy, :foreign_key => "parent_id"
has_many :approved_replies, -> { approved }, class_name: 'Reply', foreign_key: "parent_id", counter_cache: 'replies_count'
- has_many :replies_with_primary_key, :class_name => "Reply", :dependent => :destroy, :primary_key => "title", :foreign_key => "parent_title"
has_many :unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
has_many :silly_unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
@@ -107,6 +106,10 @@ class ImportantTopic < Topic
serialize :important, Hash
end
+class DefaultRejectedTopic < Topic
+ default_scope -> { where(approved: false) }
+end
+
class BlankTopic < Topic
# declared here to make sure that dynamic finder with a bang can find a model that responds to `blank?`
def blank?
diff --git a/activerecord/test/schema/oracle_specific_schema.rb b/activerecord/test/schema/oracle_specific_schema.rb
index 3314687445..a7817772f4 100644
--- a/activerecord/test/schema/oracle_specific_schema.rb
+++ b/activerecord/test/schema/oracle_specific_schema.rb
@@ -3,7 +3,6 @@ ActiveRecord::Schema.define do
execute "drop table test_oracle_defaults" rescue nil
execute "drop sequence test_oracle_defaults_seq" rescue nil
execute "drop sequence companies_nonstd_seq" rescue nil
- execute "drop synonym subjects" rescue nil
execute "drop table defaults" rescue nil
execute "drop sequence defaults_seq" rescue nil
@@ -22,8 +21,6 @@ create sequence test_oracle_defaults_seq minvalue 10000
execute "create sequence companies_nonstd_seq minvalue 10000"
- execute "create synonym subjects for topics"
-
execute <<-SQL
CREATE TABLE defaults (
id integer not null,
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index 6b7012a172..a86a188bcf 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -1,6 +1,6 @@
ActiveRecord::Schema.define do
- %w(postgresql_ranges postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings postgresql_uuids postgresql_ltrees
+ %w(postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings postgresql_uuids postgresql_ltrees
postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent postgresql_json_data_type).each do |table_name|
execute "DROP TABLE IF EXISTS #{quote_table_name table_name}"
end
@@ -74,18 +74,6 @@ _SQL
);
_SQL
- execute <<_SQL if supports_ranges?
- CREATE TABLE postgresql_ranges (
- id SERIAL PRIMARY KEY,
- date_range daterange,
- num_range numrange,
- ts_range tsrange,
- tstz_range tstzrange,
- int4_range int4range,
- int8_range int8range
- );
-_SQL
-
execute <<_SQL
CREATE TABLE postgresql_tsvectors (
id SERIAL PRIMARY KEY,
@@ -221,4 +209,3 @@ _SQL
t.text :text, limit: 100_000
end
end
-
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 188a3f0164..ddfc1ac0d6 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
ActiveRecord::Schema.define do
def except(adapter_names_to_exclude)
unless [adapter_names_to_exclude].flatten.include?(adapter_name)
@@ -25,111 +27,114 @@ ActiveRecord::Schema.define do
# #
# ------------------------------------------------------------------- #
- create_table :accounts, :force => true do |t|
+ create_table :accounts, force: true do |t|
t.integer :firm_id
t.string :firm_name
t.integer :credit_limit
end
- create_table :admin_accounts, :force => true do |t|
+ create_table :admin_accounts, force: true do |t|
t.string :name
end
- create_table :admin_users, :force => true do |t|
+ create_table :admin_users, force: true do |t|
t.string :name
- t.string :settings, :null => true, :limit => 1024
+ t.string :settings, null: true, limit: 1024
# MySQL does not allow default values for blobs. Fake it out with a
# big varchar below.
- t.string :preferences, :null => true, :default => '', :limit => 1024
- t.string :json_data, :null => true, :limit => 1024
- t.string :json_data_empty, :null => true, :default => "", :limit => 1024
+ t.string :preferences, null: true, default: '', limit: 1024
+ t.string :json_data, null: true, limit: 1024
+ t.string :json_data_empty, null: true, default: "", limit: 1024
+ t.text :params
t.references :account
end
- create_table :aircraft, :force => true do |t|
+ create_table :aircraft, force: true do |t|
t.string :name
end
- create_table :audit_logs, :force => true do |t|
- t.column :message, :string, :null=>false
- t.column :developer_id, :integer, :null=>false
+ create_table :audit_logs, force: true do |t|
+ t.column :message, :string, null: false
+ t.column :developer_id, :integer, null: false
t.integer :unvalidated_developer_id
end
- create_table :authors, :force => true do |t|
- t.string :name, :null => false
+ create_table :authors, force: true do |t|
+ t.string :name, null: false
t.integer :author_address_id
t.integer :author_address_extra_id
t.string :organization_id
t.string :owned_essay_id
end
- create_table :author_addresses, :force => true do |t|
+ create_table :author_addresses, force: true do |t|
end
- create_table :author_favorites, :force => true do |t|
+ create_table :author_favorites, force: true do |t|
t.column :author_id, :integer
t.column :favorite_author_id, :integer
end
- create_table :auto_id_tests, :force => true, :id => false do |t|
+ create_table :auto_id_tests, force: true, id: false do |t|
t.primary_key :auto_id
t.integer :value
end
- create_table :binaries, :force => true do |t|
+ create_table :binaries, force: true do |t|
t.string :name
t.binary :data
- t.binary :short_data, :limit => 2048
+ t.binary :short_data, limit: 2048
end
- create_table :birds, :force => true do |t|
+ create_table :birds, force: true do |t|
t.string :name
t.string :color
t.integer :pirate_id
end
- create_table :books, :force => true do |t|
+ create_table :books, force: true do |t|
t.integer :author_id
t.column :name, :string
+ t.column :status, :integer, default: 0
+ t.column :read_status, :integer, default: 0
end
- create_table :booleans, :force => true do |t|
+ create_table :booleans, force: true do |t|
t.boolean :value
- t.boolean :has_fun, :null => false, :default => false
+ t.boolean :has_fun, null: false, default: false
end
- create_table :bulbs, :force => true do |t|
+ create_table :bulbs, force: true do |t|
t.integer :car_id
t.string :name
t.boolean :frickinawesome
t.string :color
end
- create_table "CamelCase", :force => true do |t|
+ create_table "CamelCase", force: true do |t|
t.string :name
end
- create_table :cars, :force => true do |t|
+ create_table :cars, force: true do |t|
t.string :name
t.integer :engines_count
t.integer :wheels_count
- t.column :lock_version, :integer, :null => false, :default => 0
+ t.column :lock_version, :integer, null: false, default: 0
t.timestamps
end
- create_table :categories, :force => true do |t|
- t.string :name, :null => false
+ create_table :categories, force: true do |t|
+ t.string :name, null: false
t.string :type
t.integer :categorizations_count
end
- create_table :categories_posts, :force => true, :id => false do |t|
- t.integer :category_id, :null => false
- t.integer :post_id, :null => false
+ create_table :categories_posts, force: true, id: false do |t|
+ t.integer :category_id, null: false
+ t.integer :post_id, null: false
end
- create_table :categorizations, :force => true do |t|
+ create_table :categorizations, force: true do |t|
t.column :category_id, :integer
t.string :named_category_name
t.column :post_id, :integer
@@ -137,98 +142,98 @@ ActiveRecord::Schema.define do
t.column :special, :boolean
end
- create_table :citations, :force => true do |t|
+ create_table :citations, force: true do |t|
t.column :book1_id, :integer
t.column :book2_id, :integer
end
- create_table :clubs, :force => true do |t|
+ create_table :clubs, force: true do |t|
t.string :name
t.integer :category_id
end
- create_table :collections, :force => true do |t|
+ create_table :collections, force: true do |t|
t.string :name
end
- create_table :colnametests, :force => true do |t|
- t.integer :references, :null => false
+ create_table :colnametests, force: true do |t|
+ t.integer :references, null: false
end
- create_table :comments, :force => true do |t|
- t.integer :post_id, :null => false
+ create_table :comments, force: true do |t|
+ t.integer :post_id, null: false
# use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in
# Oracle SELECT WHERE clause which causes many unit test failures
if current_adapter?(:OracleAdapter)
- t.string :body, :null => false, :limit => 4000
+ t.string :body, null: false, limit: 4000
else
- t.text :body, :null => false
+ t.text :body, null: false
end
t.string :type
- t.integer :taggings_count, :default => 0
- t.integer :children_count, :default => 0
+ t.integer :taggings_count, default: 0
+ t.integer :children_count, default: 0
t.integer :parent_id
end
- create_table :companies, :force => true do |t|
+ create_table :companies, force: true do |t|
t.string :type
t.integer :firm_id
t.string :firm_name
t.string :name
t.integer :client_of
- t.integer :rating, :default => 1
+ t.integer :rating, default: 1
t.integer :account_id
- t.string :description, :default => ""
+ t.string :description, default: ""
end
- add_index :companies, [:firm_id, :type, :rating], :name => "company_index"
- add_index :companies, [:firm_id, :type], :name => "company_partial_index", :where => "rating > 10"
- add_index :companies, :name, :name => 'company_name_index', :using => :btree
+ add_index :companies, [:firm_id, :type, :rating], name: "company_index"
+ add_index :companies, [:firm_id, :type], name: "company_partial_index", where: "rating > 10"
+ add_index :companies, :name, name: 'company_name_index', using: :btree
- create_table :vegetables, :force => true do |t|
+ create_table :vegetables, force: true do |t|
t.string :name
t.integer :seller_id
t.string :custom_type
end
- create_table :computers, :force => true do |t|
- t.integer :developer, :null => false
- t.integer :extendedWarranty, :null => false
+ create_table :computers, force: true do |t|
+ t.integer :developer, null: false
+ t.integer :extendedWarranty, null: false
end
- create_table :contracts, :force => true do |t|
+ create_table :contracts, force: true do |t|
t.integer :developer_id
t.integer :company_id
end
- create_table :customers, :force => true do |t|
+ create_table :customers, force: true do |t|
t.string :name
- t.integer :balance, :default => 0
+ t.integer :balance, default: 0
t.string :address_street
t.string :address_city
t.string :address_country
t.string :gps_location
end
- create_table :dashboards, :force => true, :id => false do |t|
+ create_table :dashboards, force: true, id: false do |t|
t.string :dashboard_id
t.string :name
end
- create_table :developers, :force => true do |t|
+ create_table :developers, force: true do |t|
t.string :name
- t.integer :salary, :default => 70000
+ t.integer :salary, default: 70000
t.datetime :created_at
t.datetime :updated_at
t.datetime :created_on
t.datetime :updated_on
end
- create_table :developers_projects, :force => true, :id => false do |t|
- t.integer :developer_id, :null => false
- t.integer :project_id, :null => false
+ create_table :developers_projects, force: true, id: false do |t|
+ t.integer :developer_id, null: false
+ t.integer :project_id, null: false
t.date :joined_on
- t.integer :access_level, :default => 1
+ t.integer :access_level, default: 1
end
create_table :dog_lovers, force: true do |t|
@@ -237,28 +242,29 @@ ActiveRecord::Schema.define do
t.integer :dogs_count, default: 0
end
- create_table :dogs, :force => true do |t|
+ create_table :dogs, force: true do |t|
t.integer :trainer_id
t.integer :breeder_id
t.integer :dog_lover_id
+ t.string :alias
end
- create_table :edges, :force => true, :id => false do |t|
- t.column :source_id, :integer, :null => false
- t.column :sink_id, :integer, :null => false
+ create_table :edges, force: true, id: false do |t|
+ t.column :source_id, :integer, null: false
+ t.column :sink_id, :integer, null: false
end
- add_index :edges, [:source_id, :sink_id], :unique => true, :name => 'unique_edge_index'
+ add_index :edges, [:source_id, :sink_id], unique: true, name: 'unique_edge_index'
- create_table :engines, :force => true do |t|
+ create_table :engines, force: true do |t|
t.integer :car_id
end
- create_table :entrants, :force => true do |t|
- t.string :name, :null => false
- t.integer :course_id, :null => false
+ create_table :entrants, force: true do |t|
+ t.string :name, null: false
+ t.integer :course_id, null: false
end
- create_table :essays, :force => true do |t|
+ create_table :essays, force: true do |t|
t.string :name
t.string :writer_id
t.string :writer_type
@@ -266,153 +272,153 @@ ActiveRecord::Schema.define do
t.string :author_id
end
- create_table :events, :force => true do |t|
- t.string :title, :limit => 5
+ create_table :events, force: true do |t|
+ t.string :title, limit: 5
end
- create_table :eyes, :force => true do |t|
+ create_table :eyes, force: true do |t|
end
- create_table :funny_jokes, :force => true do |t|
+ create_table :funny_jokes, force: true do |t|
t.string :name
end
- create_table :cold_jokes, :force => true do |t|
+ create_table :cold_jokes, force: true do |t|
t.string :name
end
- create_table :friendships, :force => true do |t|
+ create_table :friendships, force: true do |t|
t.integer :friend_id
t.integer :follower_id
end
- create_table :goofy_string_id, :force => true, :id => false do |t|
- t.string :id, :null => false
+ create_table :goofy_string_id, force: true, id: false do |t|
+ t.string :id, null: false
t.string :info
end
- create_table :having, :force => true do |t|
+ create_table :having, force: true do |t|
t.string :where
end
- create_table :guids, :force => true do |t|
+ create_table :guids, force: true do |t|
t.column :key, :string
end
- create_table :inept_wizards, :force => true do |t|
- t.column :name, :string, :null => false
- t.column :city, :string, :null => false
+ create_table :inept_wizards, force: true do |t|
+ t.column :name, :string, null: false
+ t.column :city, :string, null: false
t.column :type, :string
end
- create_table :integer_limits, :force => true do |t|
+ create_table :integer_limits, force: true do |t|
t.integer :"c_int_without_limit"
(1..8).each do |i|
- t.integer :"c_int_#{i}", :limit => i
+ t.integer :"c_int_#{i}", limit: i
end
end
- create_table :invoices, :force => true do |t|
+ create_table :invoices, force: true do |t|
t.integer :balance
t.datetime :updated_at
end
- create_table :iris, :force => true do |t|
+ create_table :iris, force: true do |t|
t.references :eye
t.string :color
end
- create_table :items, :force => true do |t|
+ create_table :items, force: true do |t|
t.column :name, :string
end
- create_table :jobs, :force => true do |t|
+ create_table :jobs, force: true do |t|
t.integer :ideal_reference_id
end
- create_table :keyboards, :force => true, :id => false do |t|
+ create_table :keyboards, force: true, id: false do |t|
t.primary_key :key_number
t.string :name
end
- create_table :legacy_things, :force => true do |t|
+ create_table :legacy_things, force: true do |t|
t.integer :tps_report_number
- t.integer :version, :null => false, :default => 0
+ t.integer :version, null: false, default: 0
end
- create_table :lessons, :force => true do |t|
+ create_table :lessons, force: true do |t|
t.string :name
end
- create_table :lessons_students, :id => false, :force => true do |t|
+ create_table :lessons_students, id: false, force: true do |t|
t.references :lesson
t.references :student
end
- create_table :lint_models, :force => true
+ create_table :lint_models, force: true
- create_table :line_items, :force => true do |t|
+ create_table :line_items, force: true do |t|
t.integer :invoice_id
t.integer :amount
end
- create_table :lock_without_defaults, :force => true do |t|
+ create_table :lock_without_defaults, force: true do |t|
t.column :lock_version, :integer
end
- create_table :lock_without_defaults_cust, :force => true do |t|
+ create_table :lock_without_defaults_cust, force: true do |t|
t.column :custom_lock_version, :integer
end
- create_table :mateys, :id => false, :force => true do |t|
+ create_table :mateys, id: false, force: true do |t|
t.column :pirate_id, :integer
t.column :target_id, :integer
t.column :weight, :integer
end
- create_table :members, :force => true do |t|
+ create_table :members, force: true do |t|
t.string :name
t.integer :member_type_id
end
- create_table :member_details, :force => true do |t|
+ create_table :member_details, force: true do |t|
t.integer :member_id
t.integer :organization_id
t.string :extra_data
end
- create_table :member_friends, :force => true, :id => false do |t|
+ create_table :member_friends, force: true, id: false do |t|
t.integer :member_id
t.integer :friend_id
end
- create_table :memberships, :force => true do |t|
+ create_table :memberships, force: true do |t|
t.datetime :joined_on
t.integer :club_id, :member_id
- t.boolean :favourite, :default => false
+ t.boolean :favourite, default: false
t.string :type
end
- create_table :member_types, :force => true do |t|
+ create_table :member_types, force: true do |t|
t.string :name
end
- create_table :minivans, :force => true, :id => false do |t|
+ create_table :minivans, force: true, id: false do |t|
t.string :minivan_id
t.string :name
t.string :speedometer_id
t.string :color
end
- create_table :minimalistics, :force => true do |t|
+ create_table :minimalistics, force: true do |t|
end
- create_table :mixed_case_monkeys, :force => true, :id => false do |t|
+ create_table :mixed_case_monkeys, force: true, id: false do |t|
t.primary_key :monkeyID
t.integer :fleaCount
end
- create_table :mixins, :force => true do |t|
+ create_table :mixins, force: true do |t|
t.integer :parent_id
t.integer :pos
t.datetime :created_at
@@ -423,52 +429,52 @@ ActiveRecord::Schema.define do
t.string :type
end
- create_table :movies, :force => true, :id => false do |t|
+ create_table :movies, force: true, id: false do |t|
t.primary_key :movieid
t.string :name
end
- create_table :numeric_data, :force => true do |t|
- t.decimal :bank_balance, :precision => 10, :scale => 2
- t.decimal :big_bank_balance, :precision => 15, :scale => 2
- t.decimal :world_population, :precision => 10, :scale => 0
- t.decimal :my_house_population, :precision => 2, :scale => 0
- t.decimal :decimal_number_with_default, :precision => 3, :scale => 2, :default => 2.78
+ create_table :numeric_data, force: true do |t|
+ t.decimal :bank_balance, precision: 10, scale: 2
+ t.decimal :big_bank_balance, precision: 15, scale: 2
+ t.decimal :world_population, precision: 10, scale: 0
+ t.decimal :my_house_population, precision: 2, scale: 0
+ t.decimal :decimal_number_with_default, precision: 3, scale: 2, default: 2.78
t.float :temperature
# Oracle/SQLServer supports precision up to 38
- if current_adapter?(:OracleAdapter,:SQLServerAdapter)
- t.decimal :atoms_in_universe, :precision => 38, :scale => 0
+ if current_adapter?(:OracleAdapter, :SQLServerAdapter)
+ t.decimal :atoms_in_universe, precision: 38, scale: 0
else
- t.decimal :atoms_in_universe, :precision => 55, :scale => 0
+ t.decimal :atoms_in_universe, precision: 55, scale: 0
end
end
- create_table :orders, :force => true do |t|
+ create_table :orders, force: true do |t|
t.string :name
t.integer :billing_customer_id
t.integer :shipping_customer_id
end
- create_table :organizations, :force => true do |t|
+ create_table :organizations, force: true do |t|
t.string :name
end
- create_table :owners, :primary_key => :owner_id ,:force => true do |t|
+ create_table :owners, primary_key: :owner_id, force: true do |t|
t.string :name
t.column :updated_at, :datetime
t.column :happy_at, :datetime
t.string :essay_id
end
- create_table :paint_colors, :force => true do |t|
+ create_table :paint_colors, force: true do |t|
t.integer :non_poly_one_id
end
- create_table :paint_textures, :force => true do |t|
+ create_table :paint_textures, force: true do |t|
t.integer :non_poly_two_id
end
- create_table :parrots, :force => true do |t|
+ create_table :parrots, force: true do |t|
t.column :name, :string
t.column :color, :string
t.column :parrot_sti_class, :string
@@ -479,43 +485,43 @@ ActiveRecord::Schema.define do
t.column :updated_on, :datetime
end
- create_table :parrots_pirates, :id => false, :force => true do |t|
+ create_table :parrots_pirates, id: false, force: true do |t|
t.column :parrot_id, :integer
t.column :pirate_id, :integer
end
- create_table :parrots_treasures, :id => false, :force => true do |t|
+ create_table :parrots_treasures, id: false, force: true do |t|
t.column :parrot_id, :integer
t.column :treasure_id, :integer
end
- create_table :people, :force => true do |t|
- t.string :first_name, :null => false
+ create_table :people, force: true do |t|
+ t.string :first_name, null: false
t.references :primary_contact
- t.string :gender, :limit => 1
+ t.string :gender, limit: 1
t.references :number1_fan
- t.integer :lock_version, :null => false, :default => 0
+ t.integer :lock_version, null: false, default: 0
t.string :comments
- t.integer :followers_count, :default => 0
- t.integer :friends_too_count, :default => 0
+ t.integer :followers_count, default: 0
+ t.integer :friends_too_count, default: 0
t.references :best_friend
t.references :best_friend_of
t.integer :insures, null: false, default: 0
t.timestamps
end
- create_table :peoples_treasures, :id => false, :force => true do |t|
+ create_table :peoples_treasures, id: false, force: true do |t|
t.column :rich_person_id, :integer
t.column :treasure_id, :integer
end
- create_table :pets, :primary_key => :pet_id ,:force => true do |t|
+ create_table :pets, primary_key: :pet_id, force: true do |t|
t.string :name
t.integer :owner_id, :integer
t.timestamps
end
- create_table :pirates, :force => true do |t|
+ create_table :pirates, force: true do |t|
t.column :catchphrase, :string
t.column :parrot_id, :integer
t.integer :non_validated_parrot_id
@@ -523,74 +529,74 @@ ActiveRecord::Schema.define do
t.column :updated_on, :datetime
end
- create_table :posts, :force => true do |t|
+ create_table :posts, force: true do |t|
t.integer :author_id
- t.string :title, :null => false
+ t.string :title, null: false
# use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in
# Oracle SELECT WHERE clause which causes many unit test failures
if current_adapter?(:OracleAdapter)
- t.string :body, :null => false, :limit => 4000
+ t.string :body, null: false, limit: 4000
else
- t.text :body, :null => false
+ t.text :body, null: false
end
t.string :type
- t.integer :comments_count, :default => 0
- t.integer :taggings_count, :default => 0
- t.integer :taggings_with_delete_all_count, :default => 0
- t.integer :taggings_with_destroy_count, :default => 0
- t.integer :tags_count, :default => 0
- t.integer :tags_with_destroy_count, :default => 0
- t.integer :tags_with_nullify_count, :default => 0
+ t.integer :comments_count, default: 0
+ t.integer :taggings_count, default: 0
+ t.integer :taggings_with_delete_all_count, default: 0
+ t.integer :taggings_with_destroy_count, default: 0
+ t.integer :tags_count, default: 0
+ t.integer :tags_with_destroy_count, default: 0
+ t.integer :tags_with_nullify_count, default: 0
end
- create_table :price_estimates, :force => true do |t|
+ create_table :price_estimates, force: true do |t|
t.string :estimate_of_type
t.integer :estimate_of_id
t.integer :price
end
- create_table :products, :force => true do |t|
+ create_table :products, force: true do |t|
t.references :collection
t.string :name
end
- create_table :projects, :force => true do |t|
+ create_table :projects, force: true do |t|
t.string :name
t.string :type
end
- create_table :randomly_named_table, :force => true do |t|
+ create_table :randomly_named_table, force: true do |t|
t.string :some_attribute
t.integer :another_attribute
end
- create_table :ratings, :force => true do |t|
+ create_table :ratings, force: true do |t|
t.integer :comment_id
t.integer :value
end
- create_table :readers, :force => true do |t|
- t.integer :post_id, :null => false
- t.integer :person_id, :null => false
- t.boolean :skimmer, :default => false
+ create_table :readers, force: true do |t|
+ t.integer :post_id, null: false
+ t.integer :person_id, null: false
+ t.boolean :skimmer, default: false
t.integer :first_post_id
end
- create_table :references, :force => true do |t|
+ create_table :references, force: true do |t|
t.integer :person_id
t.integer :job_id
t.boolean :favourite
- t.integer :lock_version, :default => 0
+ t.integer :lock_version, default: 0
end
- create_table :shape_expressions, :force => true do |t|
+ create_table :shape_expressions, force: true do |t|
t.string :paint_type
t.integer :paint_id
t.string :shape_type
t.integer :shape_id
end
- create_table :ships, :force => true do |t|
+ create_table :ships, force: true do |t|
t.string :name
t.integer :pirate_id
t.integer :update_only_pirate_id
@@ -600,51 +606,51 @@ ActiveRecord::Schema.define do
t.datetime :updated_on
end
- create_table :ship_parts, :force => true do |t|
+ create_table :ship_parts, force: true do |t|
t.string :name
t.integer :ship_id
end
- create_table :speedometers, :force => true, :id => false do |t|
+ create_table :speedometers, force: true, id: false do |t|
t.string :speedometer_id
t.string :name
t.string :dashboard_id
end
- create_table :sponsors, :force => true do |t|
+ create_table :sponsors, force: true do |t|
t.integer :club_id
t.integer :sponsorable_id
t.string :sponsorable_type
end
- create_table :string_key_objects, :id => false, :primary_key => :id, :force => true do |t|
+ create_table :string_key_objects, id: false, primary_key: :id, force: true do |t|
t.string :id
t.string :name
- t.integer :lock_version, :null => false, :default => 0
+ t.integer :lock_version, null: false, default: 0
end
- create_table :students, :force => true do |t|
+ create_table :students, force: true do |t|
t.string :name
end
- create_table :subscribers, :force => true, :id => false do |t|
- t.string :nick, :null => false
+ create_table :subscribers, force: true, id: false do |t|
+ t.string :nick, null: false
t.string :name
- t.column :books_count, :integer, :null => false, :default => 0
+ t.column :books_count, :integer, null: false, default: 0
end
- add_index :subscribers, :nick, :unique => true
+ add_index :subscribers, :nick, unique: true
- create_table :subscriptions, :force => true do |t|
+ create_table :subscriptions, force: true do |t|
t.string :subscriber_id
t.integer :book_id
end
- create_table :tags, :force => true do |t|
+ create_table :tags, force: true do |t|
t.column :name, :string
- t.column :taggings_count, :integer, :default => 0
+ t.column :taggings_count, :integer, default: 0
end
- create_table :taggings, :force => true do |t|
+ create_table :taggings, force: true do |t|
t.column :tag_id, :integer
t.column :super_tag_id, :integer
t.column :taggable_type, :string
@@ -652,12 +658,12 @@ ActiveRecord::Schema.define do
t.string :comment
end
- create_table :tasks, :force => true do |t|
+ create_table :tasks, force: true do |t|
t.datetime :starting
t.datetime :ending
end
- create_table :topics, :force => true do |t|
+ create_table :topics, force: true do |t|
t.string :title
t.string :author_name
t.string :author_email_address
@@ -667,15 +673,15 @@ ActiveRecord::Schema.define do
# use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in
# Oracle SELECT WHERE clause which causes many unit test failures
if current_adapter?(:OracleAdapter)
- t.string :content, :limit => 4000
- t.string :important, :limit => 4000
+ t.string :content, limit: 4000
+ t.string :important, limit: 4000
else
t.text :content
t.text :important
end
- t.boolean :approved, :default => true
- t.integer :replies_count, :default => 0
- t.integer :unique_replies_count, :default => 0
+ t.boolean :approved, default: true
+ t.integer :replies_count, default: 0
+ t.integer :unique_replies_count, default: 0
t.integer :parent_id
t.string :parent_title
t.string :type
@@ -683,54 +689,54 @@ ActiveRecord::Schema.define do
t.timestamps
end
- create_table :toys, :primary_key => :toy_id ,:force => true do |t|
+ create_table :toys, primary_key: :toy_id, force: true do |t|
t.string :name
t.integer :pet_id, :integer
t.timestamps
end
- create_table :traffic_lights, :force => true do |t|
+ create_table :traffic_lights, force: true do |t|
t.string :location
t.string :state
- t.text :long_state, :null => false
+ t.text :long_state, null: false
t.datetime :created_at
t.datetime :updated_at
end
- create_table :treasures, :force => true do |t|
+ create_table :treasures, force: true do |t|
t.column :name, :string
t.column :type, :string
t.column :looter_id, :integer
t.column :looter_type, :string
end
- create_table :tyres, :force => true do |t|
+ create_table :tyres, force: true do |t|
t.integer :car_id
end
- create_table :variants, :force => true do |t|
+ create_table :variants, force: true do |t|
t.references :product
t.string :name
end
- create_table :vertices, :force => true do |t|
+ create_table :vertices, force: true do |t|
t.column :label, :string
end
- create_table 'warehouse-things', :force => true do |t|
+ create_table 'warehouse-things', force: true do |t|
t.integer :value
end
[:circles, :squares, :triangles, :non_poly_ones, :non_poly_twos].each do |t|
- create_table(t, :force => true) { }
+ create_table(t, force: true) { }
end
# NOTE - the following 4 tables are used by models that have :inverse_of options on the associations
- create_table :men, :force => true do |t|
+ create_table :men, force: true do |t|
t.string :name
end
- create_table :faces, :force => true do |t|
+ create_table :faces, force: true do |t|
t.string :description
t.integer :man_id
t.integer :polymorphic_man_id
@@ -739,7 +745,7 @@ ActiveRecord::Schema.define do
t.string :horrible_polymorphic_man_type
end
- create_table :interests, :force => true do |t|
+ create_table :interests, force: true do |t|
t.string :topic
t.integer :man_id
t.integer :polymorphic_man_id
@@ -747,50 +753,67 @@ ActiveRecord::Schema.define do
t.integer :zine_id
end
- create_table :wheels, :force => true do |t|
- t.references :wheelable, :polymorphic => true
+ create_table :wheels, force: true do |t|
+ t.references :wheelable, polymorphic: true
end
- create_table :zines, :force => true do |t|
+ create_table :zines, force: true do |t|
t.string :title
end
- create_table :countries, :force => true, :id => false, :primary_key => 'country_id' do |t|
+ create_table :countries, force: true, id: false, primary_key: 'country_id' do |t|
t.string :country_id
t.string :name
end
- create_table :treaties, :force => true, :id => false, :primary_key => 'treaty_id' do |t|
+ create_table :treaties, force: true, id: false, primary_key: 'treaty_id' do |t|
t.string :treaty_id
t.string :name
end
- create_table :countries_treaties, :force => true, :id => false do |t|
- t.string :country_id, :null => false
- t.string :treaty_id, :null => false
+ create_table :countries_treaties, force: true, id: false do |t|
+ t.string :country_id, null: false
+ t.string :treaty_id, null: false
end
- create_table :liquid, :force => true do |t|
+ create_table :liquid, force: true do |t|
t.string :name
end
- create_table :molecules, :force => true do |t|
+ create_table :molecules, force: true do |t|
t.integer :liquid_id
t.string :name
end
- create_table :electrons, :force => true do |t|
+ create_table :electrons, force: true do |t|
t.integer :molecule_id
t.string :name
end
- create_table :weirds, :force => true do |t|
+ create_table :weirds, force: true do |t|
t.string 'a$b'
+ t.string 'なまえ'
t.string 'from'
end
+ create_table :hotels, force: true do |t|
+ end
+ create_table :departments, force: true do |t|
+ t.integer :hotel_id
+ end
+ create_table :cake_designers, force: true do |t|
+ end
+ create_table :drink_designers, force: true do |t|
+ end
+ create_table :chefs, force: true do |t|
+ t.integer :employable_id
+ t.string :employable_type
+ t.integer :department_id
+ end
+
+
except 'SQLite' do
# fk_test_has_fk should be before fk_test_has_pk
- create_table :fk_test_has_fk, :force => true do |t|
- t.integer :fk_id, :null => false
+ create_table :fk_test_has_fk, force: true do |t|
+ t.integer :fk_id, null: false
end
- create_table :fk_test_has_pk, :force => true do |t|
+ create_table :fk_test_has_pk, force: true do |t|
end
execute "ALTER TABLE fk_test_has_fk ADD CONSTRAINT fk_name FOREIGN KEY (#{quote_column_name 'fk_id'}) REFERENCES #{quote_table_name 'fk_test_has_pk'} (#{quote_column_name 'id'})"
@@ -799,11 +822,11 @@ ActiveRecord::Schema.define do
end
end
-Course.connection.create_table :courses, :force => true do |t|
- t.column :name, :string, :null => false
+Course.connection.create_table :courses, force: true do |t|
+ t.column :name, :string, null: false
t.column :college_id, :integer
end
-College.connection.create_table :colleges, :force => true do |t|
- t.column :name, :string, :null => false
+College.connection.create_table :colleges, force: true do |t|
+ t.column :name, :string, null: false
end
diff --git a/activerecord/test/schema/sqlite_specific_schema.rb b/activerecord/test/schema/sqlite_specific_schema.rb
index e9ddeb32cf..b7aff4f47d 100644
--- a/activerecord/test/schema/sqlite_specific_schema.rb
+++ b/activerecord/test/schema/sqlite_specific_schema.rb
@@ -1,9 +1,6 @@
ActiveRecord::Schema.define do
- # For sqlite 3.1.0+, make a table with an autoincrement column
- if supports_autoincrement?
- create_table :table_with_autoincrement, :force => true do |t|
- t.column :name, :string
- end
+ create_table :table_with_autoincrement, :force => true do |t|
+ t.column :name, :string
end
execute "DROP TABLE fk_test_has_fk" rescue nil
diff --git a/activerecord/test/support/connection.rb b/activerecord/test/support/connection.rb
index 196b3a9493..d11fd9cfc1 100644
--- a/activerecord/test/support/connection.rb
+++ b/activerecord/test/support/connection.rb
@@ -15,7 +15,7 @@ module ARTest
puts "Using #{connection_name}"
ActiveRecord::Base.logger = ActiveSupport::Logger.new("debug.log", 0, 100 * 1024 * 1024)
ActiveRecord::Base.configurations = connection_config
- ActiveRecord::Base.establish_connection 'arunit'
- ARUnit2Model.establish_connection 'arunit2'
+ ActiveRecord::Base.establish_connection :arunit
+ ARUnit2Model.establish_connection :arunit2
end
end