diff options
Diffstat (limited to 'activerecord/test/cases')
65 files changed, 2034 insertions, 1524 deletions
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index dd355e8d0c..595edc6263 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -195,22 +195,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/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb index 1844a2e0dc..a61d61eef7 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 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/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index ecdbefcd03..9536cceb1d 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -113,6 +113,11 @@ 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 + private def assert_cycle field, array # test creation diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index 81aa977c59..90cca7d3e6 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -98,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'] + if ARTest.config['with_manual_interventions'] + def test_reconnection_after_actual_disconnection_with_verify + original_connection_pid = @connection.query('select pg_backend_pid()') - 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 3dbab08a99..01de202d11 100644 --- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -184,16 +184,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,57 +230,185 @@ _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_nil @empty_range.int4_range - end + if ActiveRecord::Base.connection.supports_ranges? + 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_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_nil @empty_range.int8_range - 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_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_nil @empty_range.date_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_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_nil @empty_range.num_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_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_nil @empty_range.ts_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') + 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 + new_tstzrange = Time.parse('2010-01-01 14:30:00 CDT')...Time.parse('2011-02-02 14:30:00 CET') + @first_range.tstz_range = new_tstzrange + assert @first_range.save + assert @first_range.reload + assert_equal new_tstzrange, @first_range.tstz_range + @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_nil @first_range.tstz_range + end + + def test_create_tsrange + 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 + 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) + @first_range.ts_range = new_tsrange + assert @first_range.save + assert @first_range.reload + assert_equal new_tsrange, @first_range.ts_range + @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_nil @first_range.ts_range + end + + def test_create_numrange + 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 + new_numrange = BigDecimal.new('0.5')...BigDecimal.new('1') + @first_range.num_range = new_numrange + assert @first_range.save + assert @first_range.reload + assert_equal new_numrange, @first_range.num_range + @first_range.num_range = BigDecimal.new('0.5')...BigDecimal.new('0.5') + assert @first_range.save + assert @first_range.reload + assert_nil @first_range.num_range + end + + def test_create_daterange + 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 + new_daterange = Date.new(2012, 2, 3)...Date.new(2012, 2, 10) + @first_range.date_range = new_daterange + assert @first_range.save + assert @first_range.reload + assert_equal new_daterange, @first_range.date_range + @first_range.date_range = Date.new(2012, 2, 3)...Date.new(2012, 2, 3) + assert @first_range.save + assert @first_range.reload + assert_nil @first_range.date_range + end + + def test_create_int4range + 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 + new_int4range = 6...10 + @first_range.int4_range = new_int4range + assert @first_range.save + assert @first_range.reload + assert_equal new_int4range, @first_range.int4_range + @first_range.int4_range = 3...3 + assert @first_range.save + assert @first_range.reload + assert_nil @first_range.int4_range + end + + def test_create_int8range + 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_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_nil @empty_range.tstz_range + def test_update_int8range + new_int8range = 60000...10000000 + @first_range.int8_range = new_int8range + assert @first_range.save + assert @first_range.reload + assert_equal new_int8range, @first_range.int8_range + @first_range.int8_range = 39999...39999 + assert @first_range.save + assert @first_range.reload + assert_nil @first_range.int8_range + end end def test_money_values @@ -306,141 +424,6 @@ _SQL assert_equal(-2.25, column.type_cast("($2.25)")) 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') - @first_range.tstz_range = new_tstzrange - assert @first_range.save - assert @first_range.reload - assert_equal new_tstzrange, @first_range.tstz_range - @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_nil @first_range.tstz_range - 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) - @first_range.ts_range = new_tsrange - assert @first_range.save - assert @first_range.reload - assert_equal new_tsrange, @first_range.ts_range - @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_nil @first_range.ts_range - 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') - @first_range.num_range = new_numrange - assert @first_range.save - assert @first_range.reload - assert_equal new_numrange, @first_range.num_range - @first_range.num_range = BigDecimal.new('0.5')...BigDecimal.new('0.5') - assert @first_range.save - assert @first_range.reload - assert_nil @first_range.num_range - 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) - @first_range.date_range = new_daterange - assert @first_range.save - assert @first_range.reload - assert_equal new_daterange, @first_range.date_range - @first_range.date_range = Date.new(2012, 2, 3)...Date.new(2012, 2, 3) - assert @first_range.save - assert @first_range.reload - assert_nil @first_range.date_range - 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 - @first_range.int4_range = new_int4range - assert @first_range.save - assert @first_range.reload - assert_equal new_int4range, @first_range.int4_range - @first_range.int4_range = 3...3 - assert @first_range.save - assert @first_range.reload - assert_nil @first_range.int4_range - 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 - @first_range.int8_range = new_int8range - assert @first_range.save - assert @first_range.reload - assert_equal new_int8range, @first_range.int8_range - @first_range.int8_range = 39999...39999 - assert @first_range.save - assert @first_range.reload - assert_nil @first_range.int8_range - end - def test_update_tsvector new_text_vector = "'new' 'text' 'vector'" @first_tsvector.text_vector = new_text_vector @@ -589,38 +572,28 @@ _SQL 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 - - @connection.reconnect! + with_timezone_config default: :utc, aware_attributes: true do + @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.local(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 f61f196c71..2845413575 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,173 +34,193 @@ 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 - raise ActiveRecord::Rollback # reset the schema change + 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 - ensure - Hstore.reset_column_information - end - 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 + def test_type_cast_hstore + assert @column - def test_type_cast_hstore - assert @column + data = "\"1\"=>\"2\"" + hash = @column.class.string_to_hstore data + assert_equal({'1' => '2'}, hash) + assert_equal({'1' => '2'}, @column.type_cast(data)) - data = "\"1\"=>\"2\"" - hash = @column.class.string_to_hstore data - assert_equal({'1' => '2'}, hash) - assert_equal({'1' => '2'}, @column.type_cast(data)) + 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 - 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_with_store_accessors + x = Hstore.new(language: "fr", timezone: "GMT") + assert_equal "fr", x.language + assert_equal "GMT", x.timezone - def test_gen1 - 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_gen2 - assert_equal(%q(","=>""), @column.class.hstore_to_string({','=>''})) - end + x.language = "de" + x.save! - def test_gen3 - assert_equal(%q("="=>""), @column.class.hstore_to_string({'='=>''})) - end + x = Hstore.first + assert_equal "de", x.language + assert_equal "GMT", x.timezone + end - def test_gen4 - assert_equal(%q(">"=>""), @column.class.hstore_to_string({'>'=>''})) - end + def test_gen1 + assert_equal(%q(" "=>""), @column.class.hstore_to_string({' '=>''})) + 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_gen2 + assert_equal(%q(","=>""), @column.class.hstore_to_string({','=>''})) + end - def test_parse2 - assert_equal({" " => " "}, @column.type_cast("\\ =>\\ ")) - end + def test_gen3 + assert_equal(%q("="=>""), @column.class.hstore_to_string({'='=>''})) + end - def test_parse3 - assert_equal({"=" => ">"}, @column.type_cast("==>>")) - end + def test_gen4 + 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_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_parse5 - assert_equal({"=a"=>"q=w"}, @column.type_cast('"=a"=>q\=w')) - end + def test_parse2 + assert_equal({" " => " "}, @column.type_cast("\\ =>\\ ")) + end - def test_parse6 - assert_equal({"\"a"=>"q>w"}, @column.type_cast('"\"a"=>q>w')) - end + def test_parse3 + assert_equal({"=" => ">"}, @column.type_cast("==>>")) + end - def test_parse7 - assert_equal({"\"a"=>"q\"w"}, @column.type_cast('\"a=>q"w')) - end + def test_parse4 + assert_equal({"=a"=>"q=w"}, @column.type_cast('\=a=>q=w')) + 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_parse5 + assert_equal({"=a"=>"q=w"}, @column.type_cast('"=a"=>q\=w')) + end + def test_parse6 + 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_parse7 + 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_rewrite + @connection.execute "insert into hstores (tags) VALUES ('1=>2')" + x = Hstore.first + x.tags = { '"a\'' => 'b' } + assert x.save! + end - def test_create - assert_cycle('a' => 'b', '1' => '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_nil - assert_cycle('a' => nil) - 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_quotes - assert_cycle('a' => 'b"ar', '1"foo' => '2') - end + def test_create + assert_cycle('a' => 'b', '1' => '2') + end - def test_whitespace - assert_cycle('a b' => 'b ar', '1"foo' => '2') - end + def test_nil + assert_cycle('a' => nil) + end - def test_backslash - assert_cycle('a\\b' => 'b\\ar', '1"foo' => '2') - end + def test_quotes + assert_cycle('a' => 'b"ar', '1"foo' => '2') + end - def test_comma - assert_cycle('a, b' => 'bar', '1"foo' => '2') - end + def test_whitespace + assert_cycle('a b' => 'b ar', '1"foo' => '2') + end - def test_arrow - assert_cycle('a=>b' => 'bar', '1"foo' => '2') - end + def test_backslash + assert_cycle('a\\b' => 'b\\ar', '1"foo' => '2') + end - def test_quoting_special_characters - assert_cycle('ca' => 'cà', 'ac' => 'àc') - end + def test_comma + assert_cycle('a, b' => 'bar', '1"foo' => '2') + end - def test_multiline - assert_cycle("a\nb" => "c\nd") + 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 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 adac1d3c13..c33c7ef968 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 @@ -96,4 +106,19 @@ class PostgresqlJSONTest < ActiveRecord::TestCase x.payload = ['v1', {'k2' => 'v2'}, 'v3'] 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 end diff --git a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb index c5fd40accc..1497b0abc7 100644 --- a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb +++ b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb @@ -14,20 +14,20 @@ module ActiveRecord end 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 def test_dealloc_does_not_raise_on_inactive_connection 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 a753a23c09..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 @@ -35,33 +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, default: "uuid_generate_v1\(\)"/, schema.string) - assert_match(/t\.uuid "other_uuid", default: "uuid_generate_v4\(\)"/, 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 @@ -74,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 @@ -86,12 +89,14 @@ 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 @@ -110,6 +115,11 @@ class PostgresqlUUIDTestInverseOf < 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_uuid_posts', id: :uuid) do |t| t.string 'title' @@ -128,9 +138,11 @@ class PostgresqlUUIDTestInverseOf < ActiveRecord::TestCase end end - def test_collection_association_with_uuid - post = UuidPost.create! - comment = post.uuid_comments.create! - assert post.uuid_comments.find(comment.id) + 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/sqlite3/sqlite3_create_folder_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb index 5a4fe63580..f545fc2011 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb @@ -12,7 +12,7 @@ module ActiveRecord :adapter => 'sqlite3', :timeout => 100 - assert Dir.exists? dir.join('db') + assert Dir.exist? dir.join('db') assert File.exist? dir.join('db/foo.sqlite3') 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/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 874ae77ff7..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 @@ -1185,4 +1186,12 @@ class EagerAssociationTest < ActiveRecord::TestCase 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/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index caa916346a..dfc8a68e8c 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -101,11 +101,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_do_not_call_callbacks_for_delete_all - bulb_count = Bulb.count car = Car.create(:name => 'honda') car.funky_bulbs.create! assert_nothing_raised { car.reload.funky_bulbs.delete_all } - assert_equal bulb_count + 1, Bulb.count, "bulbs should have been deleted using :nullify strategey" + assert_equal 0, Bulb.count, "bulbs should have been deleted using :delete_all strategey" end def test_building_the_associated_object_with_implicit_sti_base_class @@ -782,13 +781,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 @@ -864,7 +863,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 1, firm.dependent_clients_of_firm.size assert_equal 1, Client.find_by_id(client_id).client_of - # :nullify 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 @@ -872,7 +871,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [], Client.destroyed_client_ids[firm.id] # Should be destroyed since the association is dependent. - assert_nil Client.find_by_id(client_id).client_of + assert_nil Client.find_by_id(client_id) end def test_delete_all_with_option_delete_all 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 3b61b91d62..47592f312e 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -514,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)} @@ -1085,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 9cd4db8dc9..1f78c73f71 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -509,19 +509,44 @@ class HasOneAssociationsTest < ActiveRecord::TestCase 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 end diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb index 9fe5ff50d9..dffee42e7d 100644 --- a/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/activerecord/test/cases/associations/inner_join_association_test.rb @@ -70,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 diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index 8c81e00865..893030345f 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -603,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/base_test.rb b/activerecord/test/cases/base_test.rb index d4433ef889..cde188f6c3 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -78,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[/[^:]*$/] @@ -234,7 +218,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 @@ -247,7 +231,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) @@ -262,18 +246,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) @@ -493,25 +479,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 @@ -558,6 +544,19 @@ class BasicsTest < ActiveRecord::TestCase assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ] end + 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') @@ -608,10 +607,24 @@ class BasicsTest < ActiveRecord::TestCase end 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 weird = Weird.create('a$b' => 'value') weird.reload @@ -634,12 +647,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 @@ -827,19 +842,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 @@ -1347,34 +1361,33 @@ class BasicsTest < ActiveRecord::TestCase assert_equal 1, post.comments.length end - def test_marshal_between_processes - skip "can't marshal between processes when using an in-memory db" if in_memory_db? - skip "fork isn't supported" unless Process.respond_to?(:fork) + 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 - # 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 + }) - self.class.const_set("Post", Class.new(ActiveRecord::Base) { - has_many :comments - }) + rd, wr = IO.pipe - rd, wr = IO.pipe + ActiveRecord::Base.connection_handler.clear_all_connections! - 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 - fork do - rd.close - post = Post.new - post.comments.build - wr.write Marshal.dump(post) wr.close + assert Marshal.load rd.read + rd.close end - - wr.close - assert Marshal.load rd.read - rd.close end def test_marshalling_new_record_round_trip_with_associations 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/column_test.rb b/activerecord/test/cases/column_test.rb index 5ab2f18e9d..2a6d8cc2ab 100644 --- a/activerecord/test/cases/column_test.rb +++ b/activerecord/test/cases/column_test.rb @@ -112,13 +112,11 @@ module ActiveRecord end def test_string_to_time_with_timezone - old = ActiveRecord::Base.default_timezone [:utc, :local].each do |zone| - ActiveRecord::Base.default_timezone = zone - assert_equal Time.utc(2013, 9, 4, 0, 0, 0), Column.string_to_time("Wed, 04 Sep 2013 03:00:00 EAT") + 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 - rescue - ActiveRecord::Base.default_timezone = old end end end diff --git a/activerecord/test/cases/connection_management_test.rb b/activerecord/test/cases/connection_management_test.rb index df17732fff..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 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/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index b277ef0317..9d7f57bf85 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' + with_timezone_config aware_attributes: false do + target = Class.new(ActiveRecord::Base) + target.table_name = 'pirates' - target.time_zone_aware_attributes = false + # 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 diff --git a/activerecord/test/cases/disconnected_test.rb b/activerecord/test/cases/disconnected_test.rb index 1fecfd077e..9e268dad74 100644 --- a/activerecord/test/cases/disconnected_test.rb +++ b/activerecord/test/cases/disconnected_test.rb @@ -7,7 +7,6 @@ class TestDisconnectedAdapter < ActiveRecord::TestCase self.use_transactional_fixtures = false def setup - skip "in-memory database mustn't disconnect" if in_memory_db? @connection = ActiveRecord::Base.connection end @@ -17,11 +16,13 @@ class TestDisconnectedAdapter < ActiveRecord::TestCase ActiveRecord::Base.establish_connection(spec) end - test "can't execute statements while disconnected" do - @connection.execute "SELECT count(*) from products" - @connection.disconnect! - assert_raises(ActiveRecord::StatementInvalid) do + 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/enum_test.rb b/activerecord/test/cases/enum_test.rb new file mode 100644 index 0000000000..35e8a98156 --- /dev/null +++ b/activerecord/test/cases/enum_test.rb @@ -0,0 +1,66 @@ +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 symbol" 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 "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 +end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 1b9ef14ec9..735f804184 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -11,6 +11,7 @@ require 'models/project' require 'models/developer' require 'models/customer' require 'models/toy' +require 'models/matey' class FinderTest < ActiveRecord::TestCase fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers, :categories, :categorizations @@ -149,14 +150,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 @@ -309,7 +310,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") @@ -321,23 +322,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 @@ -347,7 +348,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 @@ -365,71 +366,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 @@ -478,61 +479,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 @@ -550,10 +551,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 @@ -735,10 +736,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') @@ -746,20 +746,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 @@ -784,9 +781,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 @@ -813,34 +810,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 + skip 'broken test' if current_adapter?(:MysqlAdapter) + posts = Post.references(:authors).merge( :includes => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3, :order => 'posts.id' @@ -860,8 +858,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 diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 739e2b2f19..34e8f1be0f 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -49,11 +49,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 +140,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 diff --git a/activerecord/test/cases/integration_test.rb b/activerecord/test/cases/integration_test.rb index f5daca2fa8..07ffcef875 100644 --- a/activerecord/test/cases/integration_test.rb +++ b/activerecord/test/cases/integration_test.rb @@ -3,9 +3,10 @@ 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,18 +23,53 @@ 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 + + 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 + + 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_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 - Time.zone = 'EST' - est_key = Developer.first.cache_key + def test_to_param_class_method_uses_default_if_not_persisted + firm = Firm.new(name: 'Fancy Shirts') + assert_equal nil, firm.to_param + end - assert_equal utc_key, est_key - ensure - Time.zone = 'UTC' + 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 @@ -86,4 +122,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 index f2d8f18ec7..f6774d7ef4 100644 --- a/activerecord/test/cases/invalid_connection_test.rb +++ b/activerecord/test/cases/invalid_connection_test.rb @@ -17,6 +17,6 @@ class TestAdapterWithInvalidConnection < ActiveRecord::TestCase end test "inspect on Model class does not raise" do - assert_equal "#{Bird.name}(no database connection)", Bird.inspect + assert_equal "#{Bird.name} (call '#{Bird.name}.connection' to establish a connection)", Bird.inspect end end diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb index 3bdc5a1302..97c0350911 100644 --- a/activerecord/test/cases/log_subscriber_test.rb +++ b/activerecord/test/cases/log_subscriber_test.rb @@ -119,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 e37dca856d..e43e256d24 100644 --- a/activerecord/test/cases/migration/change_schema_test.rb +++ b/activerecord/test/cases/migration/change_schema_test.rb @@ -74,8 +74,8 @@ module ActiveRecord assert_equal "hello", five.default unless mysql end - def test_add_column_with_array - if current_adapter?(:PostgreSQLAdapter) + if current_adapter?(:PostgreSQLAdapter) + def test_add_column_with_array connection.create_table :testings connection.add_column :testings, :foo, :string, :array => true @@ -83,13 +83,9 @@ module ActiveRecord array_column = columns.detect { |c| c.name == "foo" } assert array_column.array - else - skip "array option only supported in PostgreSQLAdapter" end - end - def test_create_table_with_array_column - if current_adapter?(:PostgreSQLAdapter) + def test_create_table_with_array_column connection.create_table :testings do |t| t.string :foo, :array => true end @@ -98,8 +94,6 @@ module ActiveRecord array_column = columns.detect { |c| c.name == "foo" } assert array_column.array - else - skip "array option only supported in PostgreSQLAdapter" end end @@ -211,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 diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb index aa606ac8bb..ccf19fb4d0 100644 --- a/activerecord/test/cases/migration/column_attributes_test.rb +++ b/activerecord/test/cases/migration/column_attributes_test.rb @@ -35,12 +35,12 @@ module ActiveRecord 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 @@ -95,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 @@ -163,13 +163,13 @@ module ActiveRecord 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/index_test.rb b/activerecord/test/cases/migration/index_test.rb index 04521a5f5a..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 @@ -189,14 +185,14 @@ module ActiveRecord end end - def test_add_partial_index - skip 'only on pg' unless current_adapter?(:PostgreSQLAdapter) - - connection.add_index("testings", "last_name", :where => "first_name = 'john doe'") - assert connection.index_exists?("testings", "last_name") + 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.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 931caff727..f74e903348 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -230,95 +230,94 @@ 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_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 - - migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + 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 - e = assert_raise(StandardError) { migrator.migrate } + migrator = ActiveRecord::Migrator.new(:up, [migration], 100) - assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message + e = assert_raise(StandardError) { migrator.migrate } - assert_no_column Person, :last_name, - "On error, the Migrator should revert schema changes but it did not." - end + assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message - 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_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 + 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 } - assert_no_column Person, :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_no_column Person, :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 - 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') + 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_on_migrator @@ -441,62 +440,62 @@ 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 - - # 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 + 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 @@ -701,8 +700,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)" @@ -725,10 +724,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) @@ -743,8 +742,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase Time.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) @@ -768,10 +767,10 @@ class CopyMigrationsTest < ActiveRecord::TestCase Time.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 @@ -788,8 +787,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase Time.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"}) @@ -806,7 +805,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)" @@ -863,8 +862,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase Time.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 @@ -878,8 +877,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase Time.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 diff --git a/activerecord/test/cases/multiparameter_attributes_test.rb b/activerecord/test/cases/multiparameter_attributes_test.rb index ce21760645..c70a8f296f 100644 --- a/activerecord/test/cases/multiparameter_attributes_test.rb +++ b/activerecord/test/cases/multiparameter_attributes_test.rb @@ -5,16 +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 teardown - ActiveRecord::Base.default_timezone = :utc - end - def test_multiparameter_attributes_on_date attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" } topic = Topic.find(1) @@ -86,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 @@ -152,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 @@ -180,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)" => "", @@ -191,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 @@ -248,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/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/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index 44b2064110..e2439b9a24 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -53,28 +53,28 @@ module ActiveRecord end def test_quoted_time_utc - with_active_record_default_timezone :utc do + 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 - with_active_record_default_timezone :local do + 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 - with_active_record_default_timezone :asdfasdf do + 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 - with_active_record_default_timezone :utc do + with_timezone_config default: :utc do t = DateTime.now assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t) end @@ -83,7 +83,7 @@ module ActiveRecord ### # DateTime doesn't define getlocal, so make sure it does nothing def test_quoted_datetime_local - with_active_record_default_timezone :local do + with_timezone_config default: :local do t = DateTime.now assert_equal t.to_s(:db), @quoter.quoted_date(t) end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 0e5c7df2cc..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 @@ -227,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? diff --git a/activerecord/test/cases/relation/delegation_test.rb b/activerecord/test/cases/relation/delegation_test.rb index c171c5e14e..7f99b6841f 100644 --- a/activerecord/test/cases/relation/delegation_test.rb +++ b/activerecord/test/cases/relation/delegation_test.rb @@ -61,8 +61,10 @@ module ActiveRecord end class DelegationRelationTest < DelegationTest + fixtures :comments + def target - Comment.where.not(body: nil) + Comment.where(body: 'Normal type') end [:map, :collect].each do |method| @@ -88,7 +90,7 @@ module ActiveRecord end [:select!, :uniq!].each do |method| - test "##{method} is triggers an immutable error" do + test "##{method} triggers an immutable error" do assert_raises ActiveRecord::ImmutableRelation do assert_responds(target, method) 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..782c8bc1fd --- /dev/null +++ b/activerecord/test/cases/relation/merging_test.rb @@ -0,0 +1,150 @@ +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")).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 + end +end diff --git a/activerecord/test/cases/relation/where_chain_test.rb b/activerecord/test/cases/relation/where_chain_test.rb index 92d1e013e8..d44b4dfe3d 100644 --- a/activerecord/test/cases/relation/where_chain_test.rb +++ b/activerecord/test/cases/relation/where_chain_test.rb @@ -76,5 +76,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 3e460fa3d6..56e4605ccc 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 diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index ec43ded690..baa3acf3fb 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -274,7 +274,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) @@ -639,6 +639,31 @@ class RelationTest < ActiveRecord::TestCase 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 @@ -749,75 +774,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 @@ -1572,56 +1528,4 @@ class RelationTest < ActiveRecord::TestCase 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") - - 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 diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb index 4c0762deca..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 @@ -33,8 +35,15 @@ class SanitizeTest < ActiveRecord::TestCase end def test_sanitize_sql_array_handles_relations - assert_match(/\(\bselect\b.*?\bwhere\b.*?\)/i, - Binary.send(:sanitize_sql_array, ["id in (?)", Binary.where(id: 1)]), - "should sanitize `Relation` as subquery") + 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 32f86f9c88..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 diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb index cd7d91ff85..2fbe19ab06 100644 --- a/activerecord/test/cases/scoping/default_scoping_test.rb +++ b/activerecord/test/cases/scoping/default_scoping_test.rb @@ -54,14 +54,14 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal 'Jamis', DeveloperCalledJamis.create!.name end - def test_default_scoping_with_threads - skip "in-memory database mustn't disconnect" if in_memory_db? - - 2.times do - Thread.new { - assert DeveloperOrderedBySalary.all.to_sql.include?('salary DESC') - DeveloperOrderedBySalary.connection.close - }.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 @@ -103,7 +103,7 @@ class DefaultScopingTest < ActiveRecord::TestCase 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 @@ -122,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 @@ -354,23 +362,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 - ThreadsafeDeveloper.connection.close - end - threads << Thread.new do - assert_equal 1, ThreadsafeDeveloper.all.to_a.count - ThreadsafeDeveloper.connection.close + 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/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index 7fe065ee88..bc67da8d27 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -211,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 diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb index c2c56abacd..0c9f7ccd55 100644 --- a/activerecord/test/cases/store_test.rb +++ b/activerecord/test/cases/store_test.rb @@ -150,4 +150,16 @@ class StoreTest < ActiveRecord::TestCase test "all stored attributes are returned" do assert_equal [:color, :homepage, :favorite_food], Admin::User.stored_attributes[:settings] end + + 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 end diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb index df1dad1622..d16cf40555 100644 --- a/activerecord/test/cases/tasks/mysql_rake_test.rb +++ b/activerecord/test/cases/tasks/mysql_rake_test.rb @@ -67,99 +67,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 @@ -282,6 +281,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/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb index 3e02763ed0..88ce666619 100644 --- a/activerecord/test/cases/tasks/postgresql_rake_test.rb +++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb @@ -210,7 +210,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 @@ -235,6 +235,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 e5f66c092b..eecc3527d2 100644 --- a/activerecord/test/cases/tasks/sqlite_rake_test.rb +++ b/activerecord/test/cases/tasks/sqlite_rake_test.rb @@ -165,8 +165,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) @@ -188,7 +188,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/test_case.rb b/activerecord/test/cases/test_case.rb index 8c6d189b0c..910f46d693 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -78,7 +78,7 @@ module ActiveRecord # 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] - mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/] + 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] diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb index ff1b01556d..8c45f2a3f8 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 diff --git a/activerecord/test/cases/transaction_isolation_test.rb b/activerecord/test/cases/transaction_isolation_test.rb index 4f1cb99b68..84c16fb109 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 980981903a..89dab16975 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -485,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 @@ -571,23 +578,23 @@ 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 - skip "in memory db can't share a db between threads" if in_memory_db? - - threads = 3.times.map do - Thread.new do - Topic.transaction do - topic = Topic.find(1) - topic.approved = !topic.approved? - assert topic.save! - topic.approved = !topic.approved? - assert topic.save! + 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? + assert topic.save! + topic.approved = !topic.approved? + assert topic.save! + end + Topic.connection.close end - Topic.connection.close end - end - threads.each { |t| t.join } + threads.each { |t| t.join } + end end # Test for dirty reads among simultaneous transactions. diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb index 2b33f01783..56d8db0be9 100644 --- a/activerecord/test/cases/validations/uniqueness_validation_test.rb +++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb @@ -365,15 +365,15 @@ 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 - - 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" + 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" + + 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 end 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 |