diff options
Diffstat (limited to 'activerecord/test')
60 files changed, 1096 insertions, 145 deletions
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 3942e7bb41..94497e37c7 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -151,7 +151,20 @@ class AdapterTest < ActiveRecord::TestCase else @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)" end + # should deleted created record as otherwise disable_referential_integrity will try to enable contraints after executed block + # and will fail (at least on Oracle) + @connection.execute "DELETE FROM fk_test_has_fk" end end end + + def test_deprecated_visitor_for + visitor_klass = Class.new(Arel::Visitors::ToSql) + Arel::Visitors::VISITORS['fuuu'] = visitor_klass + pool = stub(:spec => stub(:config => { :adapter => 'fuuu' })) + visitor = assert_deprecated { + ActiveRecord::ConnectionAdapters::AbstractAdapter.visitor_for(pool) + } + assert visitor.is_a?(visitor_klass) + end end diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index 509baacaef..94fc3564df 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -2,7 +2,7 @@ require "cases/helper" class ActiveSchemaTest < ActiveRecord::TestCase def setup - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do alias_method :execute_without_stub, :execute remove_method :execute def execute(sql, name = nil) return sql end @@ -10,7 +10,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def teardown - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do remove_method :execute alias_method :execute, :execute_without_stub end @@ -99,7 +99,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase private def with_real_execute #we need to actually modify some data, so we make execute point to the original method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do alias_method :execute_with_stub, :execute remove_method :execute alias_method :execute, :execute_without_stub @@ -107,7 +107,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase yield ensure #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do remove_method :execute alias_method :execute, :execute_with_stub end diff --git a/activerecord/test/cases/adapters/mysql/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql/case_sensitivity_test.rb new file mode 100644 index 0000000000..5ffd886dab --- /dev/null +++ b/activerecord/test/cases/adapters/mysql/case_sensitivity_test.rb @@ -0,0 +1,35 @@ +require "cases/helper" +require 'models/person' + +class MysqlCaseSensitivityTest < ActiveRecord::TestCase + class CollationTest < ActiveRecord::Base + validates_uniqueness_of :string_cs_column, :case_sensitive => false + validates_uniqueness_of :string_ci_column, :case_sensitive => false + end + + def test_columns_include_collation_different_from_table + assert_equal 'utf8_bin', CollationTest.columns_hash['string_cs_column'].collation + assert_equal 'utf8_general_ci', CollationTest.columns_hash['string_ci_column'].collation + end + + def test_case_sensitive + assert !CollationTest.columns_hash['string_ci_column'].case_sensitive? + assert CollationTest.columns_hash['string_cs_column'].case_sensitive? + end + + def test_case_insensitive_comparison_for_ci_column + CollationTest.create!(:string_ci_column => 'A') + invalid = CollationTest.new(:string_ci_column => 'a') + queries = assert_sql { invalid.save } + ci_uniqueness_query = queries.detect { |q| q.match /string_ci_column/ } + assert_no_match(/lower/i, ci_uniqueness_query) + end + + def test_case_insensitive_comparison_for_cs_column + CollationTest.create!(:string_cs_column => 'A') + invalid = CollationTest.new(:string_cs_column => 'a') + queries = assert_sql { invalid.save } + cs_uniqueness_query = queries.detect { |q| q.match /string_cs_column/ } + assert_match(/lower/i, cs_uniqueness_query) + end +end diff --git a/activerecord/test/cases/adapters/mysql/statement_pool_test.rb b/activerecord/test/cases/adapters/mysql/statement_pool_test.rb new file mode 100644 index 0000000000..83de90f179 --- /dev/null +++ b/activerecord/test/cases/adapters/mysql/statement_pool_test.rb @@ -0,0 +1,23 @@ +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) + + cache = StatementPool.new nil, 10 + cache['foo'] = 'bar' + assert_equal 'bar', cache['foo'] + + pid = fork { + lookup = cache['foo']; + exit!(!lookup) + } + + Process.waitpid pid + assert $?.success?, 'process should exit successfully' + end + end + end +end diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb new file mode 100644 index 0000000000..6bcc113482 --- /dev/null +++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb @@ -0,0 +1,35 @@ +require "cases/helper" +require 'models/person' + +class Mysql2CaseSensitivityTest < ActiveRecord::TestCase + class CollationTest < ActiveRecord::Base + validates_uniqueness_of :string_cs_column, :case_sensitive => false + validates_uniqueness_of :string_ci_column, :case_sensitive => false + end + + def test_columns_include_collation_different_from_table + assert_equal 'utf8_bin', CollationTest.columns_hash['string_cs_column'].collation + assert_equal 'utf8_general_ci', CollationTest.columns_hash['string_ci_column'].collation + end + + def test_case_sensitive + assert !CollationTest.columns_hash['string_ci_column'].case_sensitive? + assert CollationTest.columns_hash['string_cs_column'].case_sensitive? + end + + def test_case_insensitive_comparison_for_ci_column + CollationTest.create!(:string_ci_column => 'A') + invalid = CollationTest.new(:string_ci_column => 'a') + queries = assert_sql { invalid.save } + ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) } + assert_no_match(/lower/i, ci_uniqueness_query) + end + + def test_case_insensitive_comparison_for_cs_column + CollationTest.create!(:string_cs_column => 'A') + invalid = CollationTest.new(:string_cs_column => 'a') + queries = assert_sql { invalid.save } + cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/)} + assert_match(/lower/i, cs_uniqueness_query) + end +end diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 3a7f1badf0..b01eabc840 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -38,6 +38,10 @@ class SchemaTest < ActiveRecord::TestCase set_table_name 'test_schema."Things"' end + class Thing5 < ActiveRecord::Base + set_table_name 'things' + end + def setup @connection = ActiveRecord::Base.connection @connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" @@ -91,6 +95,12 @@ class SchemaTest < ActiveRecord::TestCase end end + def test_table_exists_quoted_table + with_schema_search_path(SCHEMA_NAME) do + assert(@connection.table_exists?('"things.table"'), "table should exist") + end + end + def test_with_schema_prefixed_table_name assert_nothing_raised do assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{TABLE_NAME}") @@ -219,21 +229,6 @@ class SchemaTest < ActiveRecord::TestCase end end - def test_extract_schema_and_table - { - %(table_name) => [nil,'table_name'], - %("table.name") => [nil,'table.name'], - %(schema.table_name) => %w{schema table_name}, - %("schema".table_name) => %w{schema table_name}, - %(schema."table_name") => %w{schema table_name}, - %("schema"."table_name") => %w{schema table_name}, - %("even spaces".table) => ['even spaces','table'], - %(schema."table.name") => ['schema', 'table.name'] - }.each do |given, expect| - assert_equal expect, ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::Utils.extract_schema_and_table(given) - end - end - def test_current_schema { %('$user',public) => 'public', @@ -245,6 +240,21 @@ class SchemaTest < ActiveRecord::TestCase end end + def test_prepared_statements_with_multiple_schemas + + @connection.schema_search_path = SCHEMA_NAME + Thing5.create(:id => 1, :name => "thing inside #{SCHEMA_NAME}", :email => "thing1@localhost", :moment => Time.now) + + @connection.schema_search_path = SCHEMA2_NAME + Thing5.create(:id => 1, :name => "thing inside #{SCHEMA2_NAME}", :email => "thing1@localhost", :moment => Time.now) + + @connection.schema_search_path = SCHEMA_NAME + assert_equal 1, Thing5.count + + @connection.schema_search_path = SCHEMA2_NAME + assert_equal 1, Thing5.count + end + def test_schema_exists? { 'public' => true, diff --git a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb new file mode 100644 index 0000000000..a82c6f67d6 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb @@ -0,0 +1,23 @@ +require 'cases/helper' + +module ActiveRecord::ConnectionAdapters + class PostgreSQLAdapter < AbstractAdapter + class StatementPoolTest < ActiveRecord::TestCase + def test_cache_is_per_pid + return skip('must support fork') unless Process.respond_to?(:fork) + + cache = StatementPool.new nil, 10 + cache['foo'] = 'bar' + assert_equal 'bar', cache['foo'] + + pid = fork { + lookup = cache['foo']; + exit!(!lookup) + } + + Process.waitpid pid + assert $?.success?, 'process should exit successfully' + end + end + end +end diff --git a/activerecord/test/cases/adapters/postgresql/utils_test.rb b/activerecord/test/cases/adapters/postgresql/utils_test.rb new file mode 100644 index 0000000000..5f08f79171 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/utils_test.rb @@ -0,0 +1,18 @@ +class PostgreSQLUtilsTest < ActiveSupport::TestCase + include ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::Utils + + def test_extract_schema_and_table + { + %(table_name) => [nil,'table_name'], + %("table.name") => [nil,'table.name'], + %(schema.table_name) => %w{schema table_name}, + %("schema".table_name) => %w{schema table_name}, + %(schema."table_name") => %w{schema table_name}, + %("schema"."table_name") => %w{schema table_name}, + %("even spaces".table) => ['even spaces','table'], + %(schema."table.name") => ['schema', 'table.name'] + }.each do |given, expect| + assert_equal expect, extract_schema_and_table(given) + 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 6ff04e3eb3..eb6f071dc1 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -1,9 +1,12 @@ # encoding: utf-8 require "cases/helper" +require 'models/owner' module ActiveRecord module ConnectionAdapters class SQLite3AdapterTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + class DualEncoding < ActiveRecord::Base end @@ -19,6 +22,21 @@ module ActiveRecord eosql end + def test_column_types + return skip('only test encoding on 1.9') unless "<3".encoding_aware? + + owner = Owner.create!(:name => "hello".encode('ascii-8bit')) + owner.reload + select = Owner.columns.map { |c| "typeof(#{c.name})" }.join ', ' + result = Owner.connection.exec_query <<-esql + SELECT #{select} + FROM #{Owner.table_name} + WHERE #{Owner.primary_key} = #{owner.id} + esql + + assert(!result.rows.first.include?("blob"), "should not store blobs") + end + def test_exec_insert column = @conn.columns('items').find { |col| col.name == 'number' } vals = [[column, 10]] @@ -139,6 +157,8 @@ module ActiveRecord binary = DualEncoding.new :name => 'いただきます!', :data => str binary.save! assert_equal str, binary.data + + DualEncoding.connection.drop_table('dual_encodings') end def test_execute diff --git a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb new file mode 100644 index 0000000000..ae272e2c4b --- /dev/null +++ b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb @@ -0,0 +1,24 @@ +require 'cases/helper' + +module ActiveRecord::ConnectionAdapters + class SQLiteAdapter + class StatementPoolTest < ActiveRecord::TestCase + def test_cache_is_per_pid + return skip('must support fork') unless Process.respond_to?(:fork) + + cache = StatementPool.new nil, 10 + cache['foo'] = 'bar' + assert_equal 'bar', cache['foo'] + + pid = fork { + lookup = cache['foo']; + exit!(!lookup) + } + + 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 818902beb5..1160d236c9 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -13,6 +13,7 @@ require 'models/comment' require 'models/sponsor' require 'models/member' require 'models/essay' +require 'models/toy' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -352,6 +353,12 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal members(:groucho), sponsor.sponsorable end + 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 + end + def test_field_name_same_as_foreign_key computer = Computer.find(1) assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # ' @@ -690,4 +697,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal nil, comment.reload.parent assert_equal 0, comments(:greetings).reload.children_count end + + def test_polymorphic_with_custom_primary_key + toy = Toy.create! + sponsor = Sponsor.create!(:sponsorable => toy) + + assert_equal toy, sponsor.reload.sponsorable + end end diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index 24830a661a..8dc1423375 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -36,18 +36,32 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase end def test_marshalling_extensions + if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7" + return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \ + "to be a Ruby bug.") + end + david = developers(:david) assert_equal projects(:action_controller), david.projects.find_most_recent - david = Marshal.load(Marshal.dump(david)) + marshalled = Marshal.dump(david) + david = Marshal.load(marshalled) + assert_equal projects(:action_controller), david.projects.find_most_recent end def test_marshalling_named_extensions + if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7" + return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \ + "to be a Ruby bug.") + end + david = developers(:david) assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent - david = Marshal.load(Marshal.dump(david)) + marshalled = Marshal.dump(david) + david = Marshal.load(marshalled) + assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent 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 d8d2a113ff..34d90cc395 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 @@ -650,6 +650,14 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_respond_to categories(:technology).select_testing_posts.find(:first), :correctness_marker end + def test_habtm_selects_all_columns_by_default + assert_equal Project.column_names.sort, developers(:david).projects.first.attributes.keys.sort + end + + def test_habtm_respects_select_query_method + assert_equal ['id'], developers(:david).projects.select(:id).first.attributes.keys + end + def test_join_table_alias assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL').size end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index a2764f3e3b..cddd2a6f8c 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -17,6 +17,7 @@ require 'models/invoice' require 'models/line_item' require 'models/car' require 'models/bulb' +require 'models/engine' class HasManyAssociationsTestForCountWithFinderSql < ActiveRecord::TestCase class Invoice < ActiveRecord::Base @@ -484,6 +485,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 0, authors(:mary).popular_grouped_posts.length end + def test_default_select + assert_equal Comment.column_names.sort, posts(:welcome).comments.first.attributes.keys.sort + end + + def test_select_query_method + assert_equal ['id'], posts(:welcome).comments.select(:id).first.attributes.keys + end + def test_adding force_signal37_to_load_all_clients_of_firm natural = Client.new("name" => "Natural Company") @@ -850,6 +859,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end end + def test_clearing_updates_counter_cache_when_inverse_counter_cache_is_a_symbol_with_dependent_destroy + car = Car.first + car.engines.create! + + assert_difference 'car.reload.engines_count', -1 do + car.engines.clear + end + end + def test_clearing_a_dependent_association_collection firm = companies(:first_firm) client_id = firm.dependent_clients_of_firm.first.id @@ -1568,4 +1586,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal car.id, bulb.attributes_after_initialize['car_id'] end + + def test_replace + car = Car.create(:name => 'honda') + bulb1 = car.bulbs.create + bulb2 = Bulb.create + + assert_equal [bulb1], car.bulbs + car.bulbs.replace([bulb2]) + assert_equal [bulb2], car.bulbs + assert_equal [bulb2], car.reload.bulbs + 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 0b1ba31ac2..b703c96ec1 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -813,4 +813,16 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert !c.save end end + + def test_preloading_empty_through_association_via_joins + person = Person.create!(:first_name => "Gaga") + person = Person.where(:id => person.id).where('readers.id = 1 or 1=1').includes(:posts).to_a.first + + assert person.posts.loaded?, 'person.posts should be loaded' + assert_equal [], person.posts + end + + def test_explicitly_joining_join_table + assert_equal owners(:blackbeard).toys, owners(:blackbeard).toys.with_pet + end end diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index dd450a2a8e..530f5212a2 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -247,7 +247,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Category.where('comments.id' => comments(:more_greetings).id).order('comments.id'), + Category.where('comments.id' => comments(:more_greetings).id).order('categories.id'), [categories(:general), categories(:technology)], :post_comments ) end @@ -356,6 +356,17 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase assert_equal categories(:general), members(:groucho).club_category end + def test_joins_and_includes_from_through_models_not_included_in_association + prev_default_scope = Club.default_scopes + + [:includes, :preload, :joins, :eager_load].each do |q| + Club.default_scopes = [Club.send(q, :category)] + assert_equal categories(:general), members(:groucho).reload.club_category + end + ensure + Club.default_scopes = prev_default_scope + end + def test_has_one_through_has_one_through_with_belongs_to_source_reflection_preload members = assert_queries(4) { Member.includes(:club_category).to_a.sort_by(&:id) } general = categories(:general) diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 49d82ba2df..ffe2993e0f 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -203,6 +203,11 @@ class AssociationProxyTest < ActiveRecord::TestCase assert_equal david.projects, david.projects.reload.reload end end + + def test_proxy_association_accessor + david = developers(:david) + assert_equal david.association(:projects), david.projects.proxy_association + end end class OverridingAssociationsTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb index 3641031d12..e03ed33591 100644 --- a/activerecord/test/cases/attribute_methods/read_test.rb +++ b/activerecord/test/cases/attribute_methods/read_test.rb @@ -35,6 +35,7 @@ module ActiveRecord end def self.serialized_attributes; {}; end + def self.base_class; self; end end end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index b0896fb236..b1b41fed0d 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -113,6 +113,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase # by inspecting it. def test_allocated_object_can_be_inspected topic = Topic.allocate + topic.instance_eval { @attributes = nil } assert_nothing_raised { topic.inspect } assert topic.inspect, "#<Topic not initialized>" end @@ -430,30 +431,6 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert topic.is_test? end - def test_kernel_methods_not_implemented_in_activerecord - %w(test name display y).each do |method| - assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined" - end - end - - def test_defined_kernel_methods_implemented_in_model - %w(test name display y).each do |method| - klass = Class.new ActiveRecord::Base - klass.class_eval "def #{method}() 'defined #{method}' end" - assert klass.instance_method_already_implemented?(method), "##{method} is not defined" - end - end - - def test_defined_kernel_methods_implemented_in_model_abstract_subclass - %w(test name display y).each do |method| - abstract = Class.new ActiveRecord::Base - abstract.class_eval "def #{method}() 'defined #{method}' end" - abstract.abstract_class = true - klass = Class.new abstract - assert klass.instance_method_already_implemented?(method), "##{method} is not defined" - end - end - def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model %w(save create_or_update).each do |method| klass = Class.new ActiveRecord::Base @@ -607,7 +584,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase topic = @target.new(:title => "The pros and cons of programming naked.") assert !topic.respond_to?(:title) exception = assert_raise(NoMethodError) { topic.title } - assert_match %r(^Attempt to call private method), exception.message + assert exception.message.include?("private method") assert_equal "I'm private", topic.send(:title) end @@ -617,7 +594,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase topic = @target.new assert !topic.respond_to?(:title=) exception = assert_raise(NoMethodError) { topic.title = "Pants"} - assert_match %r(^Attempt to call private method), exception.message + assert exception.message.include?("private method") topic.send(:title=, "Very large pants") end @@ -627,7 +604,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase topic = @target.new(:title => "Isaac Newton's pants") assert !topic.respond_to?(:title?) exception = assert_raise(NoMethodError) { topic.title? } - assert_match %r(^Attempt to call private method), exception.message + assert exception.message.include?("private method") assert topic.send(:title?) end @@ -658,6 +635,37 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal %w(preferences), Contact.serialized_attributes.keys end + def test_instance_method_should_be_defined_on_the_base_class + subklass = Class.new(Topic) + + Topic.define_attribute_methods + + instance = subklass.new + instance.id = 5 + assert_equal 5, instance.id + assert subklass.method_defined?(:id), "subklass is missing id method" + + Topic.undefine_attribute_methods + + assert_equal 5, instance.id + 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(:remove_method, :id) + + assert_deprecated do + assert_equal 5, topic.id + end + ensure + Topic.undefine_attribute_methods + end + private def cached_columns @cached_columns ||= (time_related_columns_on_topic + serialized_columns_on_topic).map(&:name) diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 8b4e7dd799..12c1cfb30e 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -21,8 +21,11 @@ require 'models/parrot' require 'models/person' require 'models/edge' require 'models/joke' +require 'models/bulb' +require 'models/bird' require 'rexml/document' require 'active_support/core_ext/exception' +require 'bcrypt' class Category < ActiveRecord::Base; end class Categorization < ActiveRecord::Base; end @@ -66,6 +69,29 @@ end class BasicsTest < ActiveRecord::TestCase fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts + def test_column_names_are_escaped + conn = ActiveRecord::Base.connection + classname = conn.class.name[/[^:]*$/] + badchar = { + 'SQLite3Adapter' => '"', + 'MysqlAdapter' => '`', + 'Mysql2Adapter' => '`', + 'PostgreSQLAdapter' => '"', + 'OracleAdapter' => '"', + }.fetch(classname) { + raise "need a bad char for #{classname}" + } + + quoted = conn.quote_column_name "foo#{badchar}bar" + if current_adapter?(:OracleAdapter) + # Oracle does not allow double quotes in table and column names at all + # therefore quoting removes them + assert_equal("#{badchar}foobar#{badchar}", quoted) + else + assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted) + end + end + def test_columns_should_obey_set_primary_key pk = Subscriber.columns.find { |x| x.name == 'nick' } assert pk.primary, 'nick should be primary key' @@ -143,25 +169,6 @@ class BasicsTest < ActiveRecord::TestCase end end - def test_use_table_engine_for_quoting_where - relation = Topic.where(Topic.arel_table[:id].eq(1)) - engine = relation.table.engine - - fakepool = Class.new(Struct.new(:spec)) { - def with_connection; yield self; end - def connection_pool; self; end - def table_exists?(name); false; end - def quote_table_name(*args); raise "lol quote_table_name"; end - } - - relation.table.engine = fakepool.new(engine.connection_pool.spec) - - error = assert_raises(RuntimeError) { relation.to_a } - assert_match('lol', error.message) - ensure - relation.table.engine = engine - end - def test_preserving_time_objects assert_kind_of( Time, Topic.find(1).bonus_time, @@ -260,6 +267,41 @@ class BasicsTest < ActiveRecord::TestCase end end + def test_create_after_initialize_without_block + cb = CustomBulb.create(:name => 'Dude') + assert_equal('Dude', cb.name) + assert_equal(true, cb.frickinawesome) + end + + def test_create_after_initialize_with_block + cb = CustomBulb.create {|c| c.name = 'Dude' } + assert_equal('Dude', cb.name) + assert_equal(true, cb.frickinawesome) + end + + def test_first_or_create + parrot = Bird.first_or_create(:color => 'green', :name => 'parrot') + assert parrot.persisted? + the_same_parrot = Bird.first_or_create(:color => 'yellow', :name => 'macaw') + assert_equal parrot, the_same_parrot + end + + def test_first_or_create_bang + assert_raises(ActiveRecord::RecordInvalid) { Bird.first_or_create! } + parrot = Bird.first_or_create!(:color => 'green', :name => 'parrot') + assert parrot.persisted? + the_same_parrot = Bird.first_or_create!(:color => 'yellow', :name => 'macaw') + assert_equal parrot, the_same_parrot + end + + def test_first_or_initialize + parrot = Bird.first_or_initialize(:color => 'green', :name => 'parrot') + assert_kind_of Bird, parrot + assert !parrot.persisted? + assert parrot.new_record? + assert parrot.valid? + end + def test_load topics = Topic.find(:all, :order => 'id') assert_equal(4, topics.size) @@ -1614,6 +1656,10 @@ class BasicsTest < ActiveRecord::TestCase assert !LooseDescendant.abstract_class? end + def test_abstract_class_table_name + assert_nil AbstractCompany.table_name + end + def test_base_class assert_equal LoosePerson, LoosePerson.base_class assert_equal LooseDescendant, LooseDescendant.base_class @@ -1813,12 +1859,45 @@ class BasicsTest < ActiveRecord::TestCase end def test_marshal_round_trip + if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7" + return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \ + "to be a Ruby bug.") + end + expected = posts(:welcome) - actual = Marshal.load(Marshal.dump(expected)) + marshalled = Marshal.dump(expected) + actual = Marshal.load(marshalled) assert_equal expected.attributes, actual.attributes end + def test_marshal_new_record_round_trip + if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7" + return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \ + "to be a Ruby bug.") + end + + marshalled = Marshal.dump(Post.new) + post = Marshal.load(marshalled) + + assert post.new_record?, "should be a new record" + end + + def test_marshalling_with_associations + if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7" + return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \ + "to be a Ruby bug.") + end + + post = Post.new + post.comments.build + + marshalled = Marshal.dump(post) + post = Marshal.load(marshalled) + + assert_equal 1, post.comments.length + end + def test_attribute_names assert_equal ["id", "type", "ruby_type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id"], Company.attribute_names @@ -1854,6 +1933,6 @@ class BasicsTest < ActiveRecord::TestCase def test_cache_key_format_for_existing_record_with_nil_updated_at dev = Developer.first dev.update_attribute(:updated_at, nil) - assert_match /\/#{dev.id}$/, dev.cache_key + assert_match(/\/#{dev.id}$/, dev.cache_key) end end diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index a35baee4ed..660098b9ad 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -113,7 +113,27 @@ class EachTest < ActiveRecord::TestCase batch.map! { not_a_post } end end + end + def test_find_in_batches_should_ignore_the_order_default_scope + # First post is with title scope + first_post = PostWithDefaultScope.first + posts = [] + PostWithDefaultScope.find_in_batches do |batch| + posts.concat(batch) + end + # posts.first will be ordered using id only. Title order scope should not apply here + assert_not_equal first_post, posts.first + assert_equal posts(:welcome), posts.first + end + + def test_find_in_batches_should_not_ignore_the_default_scope_if_it_is_other_then_order + special_posts_ids = SpecialPostWithDefaultScope.all.map(&:id).sort + posts = [] + SpecialPostWithDefaultScope.find_in_batches do |batch| + posts.concat(batch) + end + assert_equal special_posts_ids, posts.map(&:id) end end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 224b3f3d1f..c38814713a 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -170,6 +170,13 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 60, c[2] end + def test_should_group_by_summed_field_having_condition_from_select + c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("MIN(credit_limit) > 50").sum(:credit_limit) + assert_nil c[1] + assert_equal 60, c[2] + assert_equal 53, c[9] + end + def test_should_group_by_summed_association c = Account.sum(:credit_limit, :group => :firm) assert_equal 50, c[companies(:first_firm)] diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index d1dddd4c2c..14884e42af 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -58,68 +58,68 @@ module ActiveRecord if current_adapter?(:MysqlAdapter) def test_should_set_default_for_mysql_binary_data_types - binary_column = MysqlColumn.new("title", "a", "binary(1)") + binary_column = MysqlAdapter::Column.new("title", "a", "binary(1)") assert_equal "a", binary_column.default - varbinary_column = MysqlColumn.new("title", "a", "varbinary(1)") + varbinary_column = MysqlAdapter::Column.new("title", "a", "varbinary(1)") assert_equal "a", varbinary_column.default end def test_should_not_set_default_for_blob_and_text_data_types assert_raise ArgumentError do - MysqlColumn.new("title", "a", "blob") + MysqlAdapter::Column.new("title", "a", "blob") end assert_raise ArgumentError do - MysqlColumn.new("title", "Hello", "text") + MysqlAdapter::Column.new("title", "Hello", "text") end - text_column = MysqlColumn.new("title", nil, "text") + text_column = MysqlAdapter::Column.new("title", nil, "text") assert_equal nil, text_column.default - not_null_text_column = MysqlColumn.new("title", nil, "text", false) + not_null_text_column = MysqlAdapter::Column.new("title", nil, "text", false) assert_equal "", not_null_text_column.default end def test_has_default_should_return_false_for_blog_and_test_data_types - blob_column = MysqlColumn.new("title", nil, "blob") + blob_column = MysqlAdapter::Column.new("title", nil, "blob") assert !blob_column.has_default? - text_column = MysqlColumn.new("title", nil, "text") + text_column = MysqlAdapter::Column.new("title", nil, "text") assert !text_column.has_default? end end if current_adapter?(:Mysql2Adapter) def test_should_set_default_for_mysql_binary_data_types - binary_column = Mysql2Column.new("title", "a", "binary(1)") + binary_column = Mysql2Adapter::Column.new("title", "a", "binary(1)") assert_equal "a", binary_column.default - varbinary_column = Mysql2Column.new("title", "a", "varbinary(1)") + varbinary_column = Mysql2Adapter::Column.new("title", "a", "varbinary(1)") assert_equal "a", varbinary_column.default end def test_should_not_set_default_for_blob_and_text_data_types assert_raise ArgumentError do - Mysql2Column.new("title", "a", "blob") + Mysql2Adapter::Column.new("title", "a", "blob") end assert_raise ArgumentError do - Mysql2Column.new("title", "Hello", "text") + Mysql2Adapter::Column.new("title", "Hello", "text") end - text_column = Mysql2Column.new("title", nil, "text") + text_column = Mysql2Adapter::Column.new("title", nil, "text") assert_equal nil, text_column.default - not_null_text_column = Mysql2Column.new("title", nil, "text", false) + not_null_text_column = Mysql2Adapter::Column.new("title", nil, "text", false) assert_equal "", not_null_text_column.default end def test_has_default_should_return_false_for_blog_and_test_data_types - blob_column = Mysql2Column.new("title", nil, "blob") + blob_column = Mysql2Adapter::Column.new("title", nil, "blob") assert !blob_column.has_default? - text_column = Mysql2Column.new("title", nil, "text") + text_column = Mysql2Adapter::Column.new("title", nil, "text") assert !text_column.has_default? 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 abf317768f..bd0d161838 100644 --- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb @@ -6,7 +6,12 @@ module ActiveRecord def setup @handler = ConnectionHandler.new @handler.establish_connection 'america', Base.connection_pool.spec - @klass = Struct.new(:name).new('america') + @klass = Class.new do + def self.name; 'america'; end + end + @subklass = Class.new(@klass) do + def self.name; 'north america'; end + end end def test_retrieve_connection @@ -28,6 +33,20 @@ module ActiveRecord def test_retrieve_connection_pool assert_not_nil @handler.retrieve_connection_pool(@klass) end + + def test_retrieve_connection_pool_uses_superclass_when_no_subclass_connection + assert_not_nil @handler.retrieve_connection_pool(@subklass) + end + + def test_retrieve_connection_pool_uses_superclass_pool_after_subclass_establish_and_remove + @handler.establish_connection 'north america', Base.connection_pool.spec + assert_not_same @handler.retrieve_connection_pool(@klass), + @handler.retrieve_connection_pool(@subklass) + + @handler.remove_connection @subklass + assert_same @handler.retrieve_connection_pool(@klass), + @handler.retrieve_connection_pool(@subklass) + end end end end diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index f92f4e62c5..8a0f453127 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -135,6 +135,10 @@ module ActiveRecord pool.with_connection end end + + def test_pool_sets_connection_visitor + assert @pool.connection.visitor.is_a?(Arel::Visitors::ToSql) + end end end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 5dc5f99582..3088ab012f 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -48,6 +48,15 @@ class FinderTest < ActiveRecord::TestCase assert Topic.exists? 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? + end + def test_does_not_exist_with_empty_table_and_no_args_given Topic.delete_all assert !Topic.exists? @@ -243,6 +252,32 @@ class FinderTest < ActiveRecord::TestCase end end + def test_first_and_last_with_integer_should_use_sql_limit + assert_sql(/LIMIT 2|ROWNUM <= 2/) { Topic.first(2).entries } + assert_sql(/LIMIT 5|ROWNUM <= 5/) { Topic.last(5).entries } + end + + def test_last_with_integer_and_order_should_keep_the_order + assert_equal Topic.order("title").to_a.last(2), Topic.order("title").last(2) + end + + def test_last_with_integer_and_order_should_not_use_sql_limit + query = assert_sql { Topic.order("title").last(5).entries } + assert_equal 1, query.length + assert_no_match(/LIMIT/, query.first) + end + + def test_last_with_integer_and_reorder_should_not_use_sql_limit + query = assert_sql { Topic.reorder("title").last(5).entries } + assert_equal 1, query.length + assert_no_match(/LIMIT/, query.first) + end + + def test_first_and_last_with_integer_should_return_an_array + assert_kind_of Array, Topic.first(5) + assert_kind_of Array, Topic.last(5) + end + def test_unexisting_record_exception_handling assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1).parent diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 842e8a0049..7e2dafcd01 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -20,6 +20,7 @@ require 'models/book' require 'models/admin' require 'models/admin/account' require 'models/admin/user' +require 'tempfile' class FixturesTest < ActiveRecord::TestCase self.use_instantiated_fixtures = true @@ -45,6 +46,21 @@ class FixturesTest < ActiveRecord::TestCase end end + def test_broken_yaml_exception + badyaml = Tempfile.new ['foo', '.yml'] + badyaml.write 'a: : ' + badyaml.flush + + dir = File.dirname badyaml.path + name = File.basename badyaml.path, '.yml' + assert_raises(ActiveRecord::Fixture::FormatError) do + ActiveRecord::Fixtures.create_fixtures(dir, name) + end + ensure + badyaml.close + badyaml.unlink + end + def test_create_fixtures ActiveRecord::Fixtures.create_fixtures(FIXTURES_ROOT, "parrots") assert Parrot.find_by_name('Curious George'), 'George is in the database' @@ -435,14 +451,36 @@ end class CustomConnectionFixturesTest < ActiveRecord::TestCase set_fixture_class :courses => Course fixtures :courses - # Set to false to blow away fixtures cache and ensure our fixtures are loaded - # and thus takes into account our set_fixture_class self.use_transactional_fixtures = false def test_connection assert_kind_of Course, courses(:ruby) assert_equal Course.connection, courses(:ruby).connection end + + def test_leaky_destroy + assert_nothing_raised { courses(:ruby) } + courses(:ruby).destroy + end + + def test_it_twice_in_whatever_order_to_check_for_fixture_leakage + test_leaky_destroy + end +end + +class TransactionalFixturesOnCustomConnectionTest < ActiveRecord::TestCase + set_fixture_class :courses => Course + fixtures :courses + self.use_transactional_fixtures = true + + def test_leaky_destroy + assert_nothing_raised { courses(:ruby) } + courses(:ruby).destroy + end + + def test_it_twice_in_whatever_order_to_check_for_fixture_leakage + test_leaky_destroy + end end class InvalidTableNameFixturesTest < ActiveRecord::TestCase @@ -480,7 +518,9 @@ class ManyToManyFixturesWithClassDefined < ActiveRecord::TestCase end class FixturesBrokenRollbackTest < ActiveRecord::TestCase - def blank_setup; end + def blank_setup + @fixture_connections = [ActiveRecord::Base.connection] + end alias_method :ar_setup_fixtures, :setup_fixtures alias_method :setup_fixtures, :blank_setup alias_method :setup, :blank_setup @@ -587,8 +627,8 @@ class FoxyFixturesTest < ActiveRecord::TestCase end def test_preserves_existing_fixture_data - assert_equal(2.weeks.ago.utc.to_date, pirates(:redbeard).created_on.utc.to_date) - assert_equal(2.weeks.ago.utc.to_date, pirates(:redbeard).updated_on.utc.to_date) + assert_equal(2.weeks.ago.to_date, pirates(:redbeard).created_on.to_date) + assert_equal(2.weeks.ago.to_date, pirates(:redbeard).updated_on.to_date) end def test_generates_unique_ids diff --git a/activerecord/test/cases/identity_map_test.rb b/activerecord/test/cases/identity_map_test.rb index cd9c358799..3efc8bf559 100644 --- a/activerecord/test/cases/identity_map_test.rb +++ b/activerecord/test/cases/identity_map_test.rb @@ -164,7 +164,7 @@ class IdentityMapTest < ActiveRecord::TestCase end ############################################################################## - # Tests checking dirty attribute behaviour with IM # + # Tests checking dirty attribute behavior with IM # ############################################################################## def test_loading_new_instance_should_not_update_dirty_attributes @@ -238,7 +238,7 @@ class IdentityMapTest < ActiveRecord::TestCase end ############################################################################## - # Tests checking Identity Map behaviour with preloaded associations, joins, # + # Tests checking Identity Map behavior with preloaded associations, joins, # # includes etc. # ############################################################################## diff --git a/activerecord/test/cases/invalid_date_test.rb b/activerecord/test/cases/invalid_date_test.rb index 2de50b224c..98cda010ae 100644 --- a/activerecord/test/cases/invalid_date_test.rb +++ b/activerecord/test/cases/invalid_date_test.rb @@ -24,9 +24,9 @@ class InvalidDateTest < ActiveRecord::TestCase topic = Topic.new({"last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s}) # Oracle DATE columns are datetime columns and Oracle adapter returns Time value if current_adapter?(:OracleAdapter) - assert_equal(topic.last_read.to_date, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object") + assert_equal(topic.last_read.to_date, Time.local(*date_src).to_date, "The date should be modified according to the behavior of the Time object") else - assert_equal(topic.last_read, Time.local(*date_src).to_date, "The date should be modified according to the behaviour of the Time object") + assert_equal(topic.last_read, Time.local(*date_src).to_date, "The date should be modified according to the behavior of the Time object") end end end diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index afec64750e..3ae7b63dff 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -27,6 +27,19 @@ module ActiveRecord end end + class LegacyMigration < ActiveRecord::Migration + def self.up + create_table("horses") do |t| + t.column :content, :text + t.column :remind_at, :datetime + end + end + + def self.down + drop_table("horses") + end + end + def teardown if ActiveRecord::Base.connection.table_exists?("horses") ActiveRecord::Base.connection.drop_table("horses") @@ -41,17 +54,39 @@ module ActiveRecord end end - def test_up + def test_migrate_up migration = InvertibleMigration.new migration.migrate(:up) assert migration.connection.table_exists?("horses"), "horses should exist" end - def test_down + def test_migrate_down migration = InvertibleMigration.new migration.migrate :up migration.migrate :down assert !migration.connection.table_exists?("horses") end + + def test_legacy_up + LegacyMigration.migrate :up + assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist" + end + + def test_legacy_down + LegacyMigration.migrate :up + LegacyMigration.migrate :down + assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" + end + + def test_up + LegacyMigration.up + assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist" + end + + def test_down + LegacyMigration.up + LegacyMigration.down + assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" + end end end diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb index 643e949087..75e5dfa49b 100644 --- a/activerecord/test/cases/lifecycle_test.rb +++ b/activerecord/test/cases/lifecycle_test.rb @@ -231,6 +231,18 @@ class LifecycleTest < ActiveRecord::TestCase assert_not_nil observer.topic_ids.last end + test "able to disable observers" do + observer = DeveloperObserver.instance # activate + observer.calls.clear + + ActiveRecord::Base.observers.disable DeveloperObserver do + Developer.create! :name => 'Ancestor', :salary => 100000 + SpecialDeveloper.create! :name => 'Descendent', :salary => 100000 + end + + assert_equal [], observer.calls + end + def test_observer_is_called_once observer = DeveloperObserver.instance # activate observer.calls.clear diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index a0cb5dbdc5..0ab4f30363 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -14,7 +14,7 @@ class MethodScopingTest < ActiveRecord::TestCase def test_set_conditions Developer.send(:with_scope, :find => { :conditions => 'just a test...' }) do - assert_match '(just a test...)', Developer.scoped.arel.to_sql + assert_match '(just a test...)', Developer.scoped.to_sql end end @@ -274,7 +274,7 @@ class NestedScopingTest < ActiveRecord::TestCase Developer.send(:with_scope, :find => { :conditions => 'salary = 80000' }) do Developer.send(:with_scope, :find => { :limit => 10 }) do devs = Developer.scoped - assert_match '(salary = 80000)', devs.arel.to_sql + assert_match '(salary = 80000)', devs.to_sql assert_equal 10, devs.taken end end @@ -308,7 +308,7 @@ class NestedScopingTest < ActiveRecord::TestCase Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do Developer.send(:with_scope, :find => { :conditions => 'salary = 80000' }) do devs = Developer.scoped - assert_match "(name = 'David') AND (salary = 80000)", devs.arel.to_sql + assert_match "(name = 'David') AND (salary = 80000)", devs.to_sql assert_equal(1, Developer.count) end Developer.send(:with_scope, :find => { :conditions => "name = 'Maiha'" }) do @@ -321,7 +321,7 @@ class NestedScopingTest < ActiveRecord::TestCase Developer.send(:with_scope, :find => { :conditions => 'salary = 80000', :limit => 10 }) do Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do devs = Developer.scoped - assert_match "(salary = 80000) AND (name = 'David')", devs.arel.to_sql + assert_match "(salary = 80000) AND (name = 'David')", devs.to_sql assert_equal 10, devs.taken end end diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 36007255fa..d108b456f0 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -104,9 +104,9 @@ module ActiveRecord end def test_invert_rename_index - @recorder.record :rename_index, [:old, :new] + @recorder.record :rename_index, [:table, :old, :new] rename = @recorder.inverse.first - assert_equal [:rename_index, [:new, :old]], rename + assert_equal [:rename_index, [:table, :new, :old]], rename end def test_invert_add_timestamps diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index ed0240cada..4a09a87322 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -182,7 +182,7 @@ class NamedScopeTest < ActiveRecord::TestCase def test_first_and_last_should_allow_integers_for_limit assert_equal Topic.base.first(2), Topic.base.to_a.first(2) - assert_equal Topic.base.last(2), Topic.base.to_a.last(2) + assert_equal Topic.base.last(2), Topic.base.order("id").to_a.last(2) end def test_first_and_last_should_not_use_query_when_results_are_loaded diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index 57d1441128..adfd8e83a1 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -29,6 +29,26 @@ class PersistencesTest < ActiveRecord::TestCase end end + def test_update_all_doesnt_ignore_order + assert_equal authors(:david).id + 1, authors(:mary).id # make sure there is going to be a duplicate PK error + test_update_with_order_succeeds = lambda do |order| + begin + Author.order(order).update_all('id = id + 1') + rescue ActiveRecord::ActiveRecordError + false + end + end + + if test_update_with_order_succeeds.call('id DESC') + assert !test_update_with_order_succeeds.call('id ASC') # test that this wasn't a fluke and using an incorrect order results in an exception + else + # test that we're failing because the current Arel's engine doesn't support UPDATE ORDER BY queries is using subselects instead + assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\Z/i) do + test_update_with_order_succeeds.call('id DESC') + end + end + end + def test_update_all_with_order_and_limit_updates_subset_only author = authors(:david) assert_nothing_raised do @@ -182,9 +202,12 @@ class PersistencesTest < ActiveRecord::TestCase end def test_create_columns_not_equal_attributes - topic = Topic.new - topic.title = 'Another New Topic' - topic.send :write_attribute, 'does_not_exist', 'test' + topic = Topic.allocate.init_with( + 'attributes' => { + 'title' => 'Another New Topic', + 'does_not_exist' => 'test' + } + ) assert_nothing_raised { topic.save } end @@ -229,9 +252,11 @@ class PersistencesTest < ActiveRecord::TestCase topic.title = "Still another topic" topic.save - topicReloaded = Topic.find(topic.id) - topicReloaded.title = "A New Topic" - topicReloaded.send :write_attribute, 'does_not_exist', 'test' + topicReloaded = Topic.allocate + topicReloaded.init_with( + 'attributes' => topic.attributes.merge('does_not_exist' => 'test') + ) + topicReloaded.title = 'A New Topic' assert_nothing_raised { topicReloaded.save } end diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb index 379cf5b44e..434b8a677a 100644 --- a/activerecord/test/cases/pooled_connections_test.rb +++ b/activerecord/test/cases/pooled_connections_test.rb @@ -3,6 +3,8 @@ require "models/project" require "timeout" class PooledConnectionsTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + def setup @per_test_teardown = [] @connection = ActiveRecord::Base.remove_connection diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb index 7e3da145e5..4bb5752096 100644 --- a/activerecord/test/cases/primary_keys_test.rb +++ b/activerecord/test/cases/primary_keys_test.rb @@ -26,7 +26,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase def test_to_key_with_primary_key_after_destroy topic = Topic.find(1) topic.destroy - assert_equal nil, topic.to_key + assert_equal [1], topic.to_key end def test_integer_key @@ -146,3 +146,23 @@ class PrimaryKeysTest < ActiveRecord::TestCase assert_equal k.connection.quote_column_name("bar"), k.quoted_primary_key end 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? + + connection = ActiveRecord::Base.remove_connection + + model = Class.new(ActiveRecord::Base) do + set_primary_key 'foo' + end + + assert_equal 'foo', model.primary_key + + ActiveRecord::Base.establish_connection(connection) + + assert_equal 'foo', model.primary_key + end +end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index ad17f6f83a..b2429d631f 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -13,6 +13,32 @@ class QueryCacheTest < ActiveRecord::TestCase ActiveRecord::Base.connection.disable_query_cache! end + def test_exceptional_middleware_clears_and_disables_cache_on_error + assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + + mw = ActiveRecord::QueryCache.new lambda { |env| + Task.find 1 + Task.find 1 + assert_equal 1, ActiveRecord::Base.connection.query_cache.length + raise "lol borked" + } + assert_raises(RuntimeError) { mw.call({}) } + + assert_equal 0, ActiveRecord::Base.connection.query_cache.length + assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + end + + def test_exceptional_middleware_leaves_enabled_cache_alone + ActiveRecord::Base.connection.enable_query_cache! + + mw = ActiveRecord::QueryCache.new lambda { |env| + raise "lol borked" + } + assert_raises(RuntimeError) { mw.call({}) } + + assert ActiveRecord::Base.connection.query_cache_enabled, 'cache on' + end + def test_middleware_delegates called = false mw = ActiveRecord::QueryCache.new lambda { |env| @@ -121,13 +147,16 @@ class QueryCacheTest < ActiveRecord::TestCase end def test_cache_does_not_wrap_string_results_in_arrays - require 'sqlite3/version' if current_adapter?(:SQLite3Adapter) + if current_adapter?(:SQLite3Adapter) + require 'sqlite3/version' + sqlite3_version = RUBY_PLATFORM =~ /java/ ? Jdbc::SQLite3::VERSION : SQLite3::VERSION + end Task.cache do # Oracle adapter returns count() as Fixnum or Float if current_adapter?(:OracleAdapter) assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") - elsif current_adapter?(:SQLite3Adapter) && SQLite3::VERSION > '1.2.5' || current_adapter?(:Mysql2Adapter) || current_adapter?(:MysqlAdapter) + elsif current_adapter?(:SQLite3Adapter) && sqlite3_version > '1.2.5' || current_adapter?(:Mysql2Adapter) || current_adapter?(:MysqlAdapter) # Future versions of the sqlite3 adapter will return numeric assert_instance_of Fixnum, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") @@ -208,9 +237,9 @@ class QueryCacheBodyProxyTest < ActiveRecord::TestCase test "is polite to it's body and responds to it" do body = Class.new(String) { def to_path; "/path"; end }.new - proxy = ActiveRecord::QueryCache::BodyProxy.new(nil, body) + proxy = ActiveRecord::QueryCache::BodyProxy.new(nil, body, ActiveRecord::Base.connection_id) assert proxy.respond_to?(:to_path) assert_equal proxy.to_path, "/path" end -end
\ No newline at end of file +end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 41312e8661..69e9fc8d61 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -18,6 +18,7 @@ require 'models/subscriber' require 'models/subscription' require 'models/tag' require 'models/sponsor' +require 'models/edge' class ReflectionTest < ActiveRecord::TestCase include ActiveRecord::Reflection @@ -244,7 +245,7 @@ class ReflectionTest < ActiveRecord::TestCase # Normal association assert_equal "id", Author.reflect_on_association(:posts).association_primary_key.to_s assert_equal "name", Author.reflect_on_association(:essay).association_primary_key.to_s - assert_equal "id", Tagging.reflect_on_association(:taggable).association_primary_key.to_s + assert_equal "name", Essay.reflect_on_association(:writer).association_primary_key.to_s # Through association (uses the :primary_key option from the source reflection) assert_equal "nick", Author.reflect_on_association(:subscribers).association_primary_key.to_s @@ -252,11 +253,25 @@ class ReflectionTest < ActiveRecord::TestCase assert_equal "custom_primary_key", Author.reflect_on_association(:tags_with_primary_key).association_primary_key.to_s # nested end + def test_association_primary_key_raises_when_missing_primary_key + reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :edge, {}, Author) + assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.association_primary_key } + + through = ActiveRecord::Reflection::ThroughReflection.new(:fuu, :edge, {}, Author) + through.stubs(:source_reflection).returns(stub_everything(:options => {}, :class_name => 'Edge')) + assert_raises(ActiveRecord::UnknownPrimaryKey) { through.association_primary_key } + end + def test_active_record_primary_key assert_equal "nick", Subscriber.reflect_on_association(:subscriptions).active_record_primary_key.to_s assert_equal "name", Author.reflect_on_association(:essay).active_record_primary_key.to_s end + def test_active_record_primary_key_raises_when_missing_primary_key + reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :author, {}, Edge) + assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.active_record_primary_key } + end + def test_foreign_type assert_equal "sponsorable_type", Sponsor.reflect_on_association(:sponsorable).foreign_type.to_s assert_equal "sponsorable_type", Sponsor.reflect_on_association(:thing).foreign_type.to_s diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb index f2d177d834..1e2093273e 100644 --- a/activerecord/test/cases/relation_scoping_test.rb +++ b/activerecord/test/cases/relation_scoping_test.rb @@ -170,7 +170,7 @@ class NestedRelationScopingTest < ActiveRecord::TestCase Developer.where('salary = 80000').scoping do Developer.limit(10).scoping do devs = Developer.scoped - assert_match '(salary = 80000)', devs.arel.to_sql + assert_match '(salary = 80000)', devs.to_sql assert_equal 10, devs.taken end end @@ -524,4 +524,22 @@ 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.count + end + threads << Thread.new do + assert_equal 1, ThreadsafeDeveloper.all.count + end + threads.each(&:join) + end end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 0aaa0342b1..95408a5f29 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -540,6 +540,29 @@ class RelationTest < ActiveRecord::TestCase } end + def test_find_all_using_where_with_relation_and_alternate_primary_key + cool_first = minivans(:cool_first) + # switching the lines below would succeed in current rails + # assert_queries(2) { + assert_queries(1) { + relation = Minivan.where(:minivan_id => Minivan.where(:name => cool_first.name)) + assert_equal [cool_first], relation.all + } + end + + def test_find_all_using_where_with_relation_does_not_alter_select_values + david = authors(:david) + + subquery = Author.where(:id => david.id) + + assert_queries(1) { + relation = Author.where(:id => subquery) + assert_equal [david], relation.all + } + + assert_equal 0, subquery.select_values.size + end + def test_find_all_using_where_with_relation_with_joins david = authors(:david) assert_queries(1) { @@ -840,6 +863,128 @@ class RelationTest < ActiveRecord::TestCase assert_equal 'hen', hen.name end + def test_first_or_create + parrot = Bird.where(:color => 'green').first_or_create(:name => 'parrot') + assert_kind_of Bird, parrot + assert parrot.persisted? + assert_equal 'parrot', parrot.name + assert_equal 'green', parrot.color + + same_parrot = Bird.where(:color => 'green').first_or_create(:name => 'parakeet') + assert_kind_of Bird, same_parrot + assert same_parrot.persisted? + assert_equal parrot, same_parrot + end + + def test_first_or_create_with_no_parameters + parrot = Bird.where(:color => 'green').first_or_create + assert_kind_of Bird, parrot + assert !parrot.persisted? + assert_equal 'green', parrot.color + end + + def test_first_or_create_with_block + parrot = Bird.where(:color => 'green').first_or_create { |bird| bird.name = 'parrot' } + assert_kind_of Bird, parrot + assert parrot.persisted? + assert_equal 'green', parrot.color + assert_equal 'parrot', parrot.name + + same_parrot = Bird.where(:color => 'green').first_or_create { |bird| bird.name = 'parakeet' } + assert_equal parrot, same_parrot + end + + def test_first_or_create_with_array + several_green_birds = Bird.where(:color => 'green').first_or_create([{:name => 'parrot'}, {:name => 'parakeet'}]) + assert_kind_of Array, several_green_birds + several_green_birds.each { |bird| assert bird.persisted? } + + same_parrot = Bird.where(:color => 'green').first_or_create([{:name => 'hummingbird'}, {:name => 'macaw'}]) + assert_kind_of Bird, same_parrot + assert_equal several_green_birds.first, same_parrot + end + + def test_first_or_create_bang_with_valid_options + parrot = Bird.where(:color => 'green').first_or_create!(:name => 'parrot') + assert_kind_of Bird, parrot + assert parrot.persisted? + assert_equal 'parrot', parrot.name + assert_equal 'green', parrot.color + + same_parrot = Bird.where(:color => 'green').first_or_create!(:name => 'parakeet') + assert_kind_of Bird, same_parrot + assert same_parrot.persisted? + assert_equal parrot, same_parrot + end + + def test_first_or_create_bang_with_invalid_options + assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!(:pirate_id => 1) } + end + + def test_first_or_create_bang_with_no_parameters + assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create! } + end + + def test_first_or_create_bang_with_valid_block + parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.name = 'parrot' } + assert_kind_of Bird, parrot + assert parrot.persisted? + assert_equal 'green', parrot.color + assert_equal 'parrot', parrot.name + + same_parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.name = 'parakeet' } + assert_equal parrot, same_parrot + end + + def test_first_or_create_bang_with_invalid_block + assert_raise(ActiveRecord::RecordInvalid) do + Bird.where(:color => 'green').first_or_create! { |bird| bird.pirate_id = 1 } + end + end + + def test_first_or_create_with_valid_array + several_green_birds = Bird.where(:color => 'green').first_or_create!([{:name => 'parrot'}, {:name => 'parakeet'}]) + assert_kind_of Array, several_green_birds + several_green_birds.each { |bird| assert bird.persisted? } + + same_parrot = Bird.where(:color => 'green').first_or_create!([{:name => 'hummingbird'}, {:name => 'macaw'}]) + assert_kind_of Bird, same_parrot + assert_equal several_green_birds.first, same_parrot + end + + def test_first_or_create_with_invalid_array + assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!([ {:name => 'parrot'}, {:pirate_id => 1} ]) } + end + + def test_first_or_initialize + parrot = Bird.where(:color => 'green').first_or_initialize(:name => 'parrot') + assert_kind_of Bird, parrot + assert !parrot.persisted? + assert parrot.valid? + assert parrot.new_record? + assert_equal 'parrot', parrot.name + assert_equal 'green', parrot.color + end + + def test_first_or_initialize_with_no_parameters + parrot = Bird.where(:color => 'green').first_or_initialize + assert_kind_of Bird, parrot + assert !parrot.persisted? + assert !parrot.valid? + assert parrot.new_record? + assert_equal 'green', parrot.color + end + + def test_first_or_initialize_with_block + parrot = Bird.where(:color => 'green').first_or_initialize { |bird| bird.name = 'parrot' } + assert_kind_of Bird, parrot + assert !parrot.persisted? + assert parrot.valid? + assert parrot.new_record? + assert_equal 'green', parrot.color + assert_equal 'parrot', parrot.name + end + def test_explicit_create_scope hens = Bird.where(:name => 'hen') assert_equal 'hen', hens.new.name @@ -961,4 +1106,46 @@ class RelationTest < ActiveRecord::TestCase assert scope.eager_loading? end + + def test_ordering_with_extra_spaces + assert_equal authors(:david), Author.order('id DESC , name DESC').last + end + + def test_update_all_with_joins + comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id) + count = comments.count + + assert_equal count, comments.update_all(:post_id => posts(:thinking).id) + assert_equal posts(:thinking), comments(:greetings).post + end + + def test_update_all_with_joins_and_limit + comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).limit(1) + assert_equal 1, comments.update_all(:post_id => posts(:thinking).id) + end + + def test_update_all_with_joins_and_limit_and_order + comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('comments.id').limit(1) + assert_equal 1, comments.update_all(:post_id => posts(:thinking).id) + assert_equal posts(:thinking), comments(:greetings).post + assert_equal posts(:welcome), comments(:more_greetings).post + end + + def test_update_all_with_joins_and_offset + all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id) + count = all_comments.count + comments = all_comments.offset(1) + + assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id) + end + + def test_update_all_with_joins_and_offset_and_order + all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('posts.id', 'comments.id') + count = all_comments.count + comments = all_comments.offset(1) + + assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id) + assert_equal posts(:thinking), comments(:more_greetings).post + assert_equal posts(:welcome), comments(:greetings).post + end end diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 4adecf8e83..71ff727b7f 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -1,13 +1,22 @@ require "cases/helper" -require 'stringio' class SchemaDumperTest < ActiveRecord::TestCase + def setup + @stream = StringIO.new + end + def standard_dump - stream = StringIO.new + @stream = StringIO.new ActiveRecord::SchemaDumper.ignore_tables = [] - ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream) - stream.string + ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, @stream) + @stream.string + end + + if "string".encoding_aware? + def test_magic_comment + assert_match "# encoding: #{@stream.external_encoding.name}", standard_dump + end end def test_schema_dump diff --git a/activerecord/test/cases/serialization_test.rb b/activerecord/test/cases/serialization_test.rb index 382d659289..61b04b3e37 100644 --- a/activerecord/test/cases/serialization_test.rb +++ b/activerecord/test/cases/serialization_test.rb @@ -7,12 +7,13 @@ class SerializationTest < ActiveRecord::TestCase def setup @contact_attributes = { - :name => 'aaron stack', - :age => 25, - :avatar => 'binarydata', - :created_at => Time.utc(2006, 8, 1), - :awesome => false, - :preferences => { :gem => '<strong>ruby</strong>' } + :name => 'aaron stack', + :age => 25, + :avatar => 'binarydata', + :created_at => Time.utc(2006, 8, 1), + :awesome => false, + :preferences => { :gem => '<strong>ruby</strong>' }, + :alternative_id => nil } end diff --git a/activerecord/test/cases/session_store/session_test.rb b/activerecord/test/cases/session_store/session_test.rb index 669c0b7b4d..258cee7aba 100644 --- a/activerecord/test/cases/session_store/session_test.rb +++ b/activerecord/test/cases/session_store/session_test.rb @@ -36,6 +36,7 @@ module ActiveRecord end def test_find_by_sess_id_compat + Session.reset_column_information klass = Class.new(Session) do def self.session_id_column 'sessid' @@ -53,6 +54,7 @@ module ActiveRecord assert_equal session.sessid, found.session_id ensure klass.drop_table! + Session.reset_column_information end def test_find_by_session_id diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb new file mode 100644 index 0000000000..3d056d93b6 --- /dev/null +++ b/activerecord/test/cases/store_test.rb @@ -0,0 +1,29 @@ +require 'cases/helper' +require 'models/admin' +require 'models/admin/user' + +class StoreTest < ActiveRecord::TestCase + setup do + @john = Admin::User.create(name: 'John Doe', color: 'black') + end + + test "reading store attributes through accessors" do + assert_equal 'black', @john.color + assert_nil @john.homepage + end + + test "writing store attributes through accessors" do + @john.color = 'red' + @john.homepage = '37signals.com' + + assert_equal 'red', @john.color + assert_equal '37signals.com', @john.homepage + end + + test "accessing attributes not exposed by accessors" do + @john.settings[:icecream] = 'graeters' + @john.save + + assert 'graeters', @john.reload.settings[:icecream] + end +end diff --git a/activerecord/test/cases/unconnected_test.rb b/activerecord/test/cases/unconnected_test.rb index f85fb4e5da..e82ca3f93d 100644 --- a/activerecord/test/cases/unconnected_test.rb +++ b/activerecord/test/cases/unconnected_test.rb @@ -4,7 +4,7 @@ class TestRecord < ActiveRecord::Base end class TestUnconnectedAdapter < ActiveRecord::TestCase - self.use_transactional_fixtures = false unless supports_savepoints? + self.use_transactional_fixtures = false def setup @underlying = ActiveRecord::Base.connection diff --git a/activerecord/test/config.example.yml b/activerecord/test/config.example.yml index 8c1a45430e..f450efd839 100644 --- a/activerecord/test/config.example.yml +++ b/activerecord/test/config.example.yml @@ -37,11 +37,13 @@ connections: db2: arunit: + adapter: ibm_db host: localhost username: arunit password: arunit database: arunit arunit2: + adapter: ibm_db host: localhost username: arunit password: arunit diff --git a/activerecord/test/fixtures/pirates.yml b/activerecord/test/fixtures/pirates.yml index abb91101da..6004f390a4 100644 --- a/activerecord/test/fixtures/pirates.yml +++ b/activerecord/test/fixtures/pirates.yml @@ -5,5 +5,5 @@ blackbeard: redbeard: catchphrase: "Avast!" parrot: louis - created_on: <%= 2.weeks.ago.to_s(:db) %> - updated_on: <%= 2.weeks.ago.to_s(:db) %> + created_on: "<%= 2.weeks.ago.to_s(:db) %>" + updated_on: "<%= 2.weeks.ago.to_s(:db) %>" diff --git a/activerecord/test/fixtures/tasks.yml b/activerecord/test/fixtures/tasks.yml index 01c95b3a4c..402ca85faf 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/Fixtures.html +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html first_task: id: 1 starting: 2005-03-30t06:30:00.00+01:00 diff --git a/activerecord/test/models/admin/user.rb b/activerecord/test/models/admin/user.rb index 74bb21551e..275a03c344 100644 --- a/activerecord/test/models/admin/user.rb +++ b/activerecord/test/models/admin/user.rb @@ -1,3 +1,4 @@ class Admin::User < ActiveRecord::Base belongs_to :account + store :settings, accessors: [ :color, :homepage ] end
\ No newline at end of file diff --git a/activerecord/test/models/bulb.rb b/activerecord/test/models/bulb.rb index efb98b66e7..888afc7604 100644 --- a/activerecord/test/models/bulb.rb +++ b/activerecord/test/models/bulb.rb @@ -33,4 +33,9 @@ class Bulb < ActiveRecord::Base end class CustomBulb < Bulb + after_initialize :set_awesomeness + + def set_awesomeness + self.frickinawesome = true if name == 'Dude' + end end diff --git a/activerecord/test/models/car.rb b/activerecord/test/models/car.rb index 76f20b1061..b9c2e8ec9a 100644 --- a/activerecord/test/models/car.rb +++ b/activerecord/test/models/car.rb @@ -8,7 +8,7 @@ class Car < ActiveRecord::Base has_one :frickinawesome_bulb, :class_name => "Bulb", :conditions => { :frickinawesome => true } has_many :tyres - has_many :engines + has_many :engines, :dependent => :destroy has_many :wheels, :as => :wheelable scope :incl_tyres, includes(:tyres) diff --git a/activerecord/test/models/contact.rb b/activerecord/test/models/contact.rb index e081eee661..3d15c7fbed 100644 --- a/activerecord/test/models/contact.rb +++ b/activerecord/test/models/contact.rb @@ -11,12 +11,13 @@ class Contact < ActiveRecord::Base connection.merge_column('contacts', name, sql_type, options) end - column :name, :string - column :age, :integer - column :avatar, :binary - column :created_at, :datetime - column :awesome, :boolean - column :preferences, :string + column :name, :string + column :age, :integer + column :avatar, :binary + column :created_at, :datetime + column :awesome, :boolean + column :preferences, :string + column :alternative_id, :integer serialize :preferences diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index f182a7fa97..4dc9fff9fd 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -227,3 +227,12 @@ class EagerDeveloperWithCallableDefaultScope < ActiveRecord::Base default_scope OpenStruct.new(:call => includes(:projects)) end + +class ThreadsafeDeveloper < ActiveRecord::Base + self.table_name = 'developers' + + def self.default_scope + sleep 0.05 if Thread.current[:long_default_scope] + limit(1) + end +end diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index affa37b02d..198a963cbc 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -171,4 +171,14 @@ class PostWithDefaultInclude < ActiveRecord::Base self.table_name = 'posts' default_scope includes(:comments) has_many :comments, :foreign_key => :post_id +end + +class PostWithDefaultScope < ActiveRecord::Base + self.table_name = 'posts' + default_scope :order => :title +end + +class SpecialPostWithDefaultScope < ActiveRecord::Base + self.table_name = 'posts' + default_scope where(:id => [1, 5,6]) end
\ No newline at end of file diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 6440dbe8ab..fe424e61b2 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -78,11 +78,12 @@ class Topic < ActiveRecord::Base after_initialize :set_email_address + def approved=(val) + @custom_approved = val + write_attribute(:approved, val) + end + protected - def approved=(val) - @custom_approved = val - write_attribute(:approved, val) - end def default_written_on self.written_on = Time.now unless attribute_present?("written_on") diff --git a/activerecord/test/models/toy.rb b/activerecord/test/models/toy.rb index 79a88db0da..6c45e99671 100644 --- a/activerecord/test/models/toy.rb +++ b/activerecord/test/models/toy.rb @@ -1,4 +1,6 @@ class Toy < ActiveRecord::Base set_primary_key :toy_id belongs_to :pet + + scope :with_pet, joins(:pet) end diff --git a/activerecord/test/schema/mysql2_specific_schema.rb b/activerecord/test/schema/mysql2_specific_schema.rb index c78d99f4af..ab2c7ccc10 100644 --- a/activerecord/test/schema/mysql2_specific_schema.rb +++ b/activerecord/test/schema/mysql2_specific_schema.rb @@ -21,4 +21,15 @@ BEGIN END SQL -end + ActiveRecord::Base.connection.execute <<-SQL +DROP TABLE IF EXISTS collation_tests; +SQL + + ActiveRecord::Base.connection.execute <<-SQL +CREATE TABLE collation_tests ( + string_cs_column VARCHAR(1) COLLATE utf8_bin, + string_ci_column VARCHAR(1) COLLATE utf8_general_ci +) CHARACTER SET utf8 COLLATE utf8_general_ci +SQL + +end
\ No newline at end of file diff --git a/activerecord/test/schema/mysql_specific_schema.rb b/activerecord/test/schema/mysql_specific_schema.rb index 30e1c5a167..a0adfe3752 100644 --- a/activerecord/test/schema/mysql_specific_schema.rb +++ b/activerecord/test/schema/mysql_specific_schema.rb @@ -32,4 +32,15 @@ BEGIN END SQL + ActiveRecord::Base.connection.execute <<-SQL +DROP TABLE IF EXISTS collation_tests; +SQL + + ActiveRecord::Base.connection.execute <<-SQL +CREATE TABLE collation_tests ( + string_cs_column VARCHAR(1) COLLATE utf8_bin, + string_ci_column VARCHAR(1) COLLATE utf8_general_ci +) CHARACTER SET utf8 COLLATE utf8_general_ci +SQL + end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 64e0452100..bb08f5c181 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -37,6 +37,7 @@ ActiveRecord::Schema.define do create_table :admin_users, :force => true do |t| t.string :name + t.text :settings t.references :account end @@ -47,6 +48,7 @@ ActiveRecord::Schema.define do 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| @@ -156,6 +158,7 @@ ActiveRecord::Schema.define do t.string :type t.integer :taggings_count, :default => 0 t.integer :children_count, :default => 0 + t.integer :parent_id end create_table :companies, :force => true do |t| @@ -461,6 +464,7 @@ ActiveRecord::Schema.define do create_table :pirates, :force => true do |t| t.column :catchphrase, :string t.column :parrot_id, :integer + t.integer :non_validated_parrot_id t.column :created_on, :datetime t.column :updated_on, :datetime end @@ -529,6 +533,7 @@ ActiveRecord::Schema.define do create_table :ships, :force => true do |t| t.string :name t.integer :pirate_id + t.integer :update_only_pirate_id t.datetime :created_at t.datetime :created_on t.datetime :updated_at @@ -663,7 +668,9 @@ ActiveRecord::Schema.define do t.string :description t.integer :man_id t.integer :polymorphic_man_id - t.string :polymorphic_man_type + t.string :polymorphic_man_type + t.integer :horrible_polymorphic_man_id + t.string :horrible_polymorphic_man_type end create_table :interests, :force => true do |t| |