aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases')
-rw-r--r--activerecord/test/cases/adapter_test.rb17
-rw-r--r--activerecord/test/cases/adapters/postgresql/composite_test.rb14
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb31
-rw-r--r--activerecord/test/cases/adapters/postgresql/create_unlogged_tables_test.rb74
-rw-r--r--activerecord/test/cases/adapters/postgresql/enum_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/foreign_table_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/money_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/range_test.rb708
-rw-r--r--activerecord/test/cases/adapters/postgresql/rename_table_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb14
-rw-r--r--activerecord/test/cases/adapters/postgresql/transaction_test.rb1
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb8
-rw-r--r--activerecord/test/cases/adapters/sqlite3/bind_parameter_test.rb20
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb14
-rw-r--r--activerecord/test/cases/arel/visitors/ibm_db_test.rb39
-rw-r--r--activerecord/test/cases/arel/visitors/informix_test.rb39
-rw-r--r--activerecord/test/cases/arel/visitors/mssql_test.rb39
-rw-r--r--activerecord/test/cases/arel/visitors/mysql_test.rb49
-rw-r--r--activerecord/test/cases/arel/visitors/oracle12_test.rb39
-rw-r--r--activerecord/test/cases/arel/visitors/oracle_test.rb39
-rw-r--r--activerecord/test/cases/arel/visitors/postgres_test.rb39
-rw-r--r--activerecord/test/cases/arel/visitors/sqlite_test.rb45
-rw-r--r--activerecord/test/cases/arel/visitors/to_sql_test.rb59
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb9
-rw-r--r--activerecord/test/cases/associations/eager_test.rb28
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb4
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb10
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb8
-rw-r--r--activerecord/test/cases/associations/has_one_through_associations_test.rb7
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb15
-rw-r--r--activerecord/test/cases/base_test.rb8
-rw-r--r--activerecord/test/cases/bind_parameter_test.rb6
-rw-r--r--activerecord/test/cases/calculations_test.rb4
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb129
-rw-r--r--activerecord/test/cases/core_test.rb12
-rw-r--r--activerecord/test/cases/defaults_test.rb7
-rw-r--r--activerecord/test/cases/enum_test.rb32
-rw-r--r--activerecord/test/cases/filter_attributes_test.rb56
-rw-r--r--activerecord/test/cases/finder_test.rb32
-rw-r--r--activerecord/test/cases/fixtures_test.rb22
-rw-r--r--activerecord/test/cases/helper.rb9
-rw-r--r--activerecord/test/cases/hot_compatibility_test.rb2
-rw-r--r--activerecord/test/cases/instrumentation_test.rb4
-rw-r--r--activerecord/test/cases/migration_test.rb30
-rw-r--r--activerecord/test/cases/numeric_data_test.rb34
-rw-r--r--activerecord/test/cases/primary_keys_test.rb2
-rw-r--r--activerecord/test/cases/query_cache_test.rb16
-rw-r--r--activerecord/test/cases/relation/where_clause_test.rb4
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb7
-rw-r--r--activerecord/test/cases/statement_invalid_test.rb42
-rw-r--r--activerecord/test/cases/tasks/mysql_rake_test.rb2
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb11
-rw-r--r--activerecord/test/cases/view_test.rb12
53 files changed, 1367 insertions, 499 deletions
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index 64c2b51f83..e40ae3090c 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -109,6 +109,11 @@ module ActiveRecord
end
end
+ def test_exec_query_returns_an_empty_result
+ result = @connection.exec_query "INSERT INTO subscribers(nick) VALUES('me')"
+ assert_instance_of(ActiveRecord::Result, result)
+ end
+
if current_adapter?(:Mysql2Adapter)
def test_charset
assert_not_nil @connection.charset
@@ -286,18 +291,6 @@ module ActiveRecord
assert_equal "special_db_type", @connection.type_to_sql(:special_db_type)
end
- unless current_adapter?(:PostgreSQLAdapter)
- def test_log_invalid_encoding
- error = assert_raises RuntimeError do
- @connection.send :log, "SELECT 'ы' FROM DUAL" do
- raise (+"ы").force_encoding(Encoding::ASCII_8BIT)
- end
- end
-
- assert_equal "ы", error.message
- end
- end
-
def test_supports_multi_insert_is_deprecated
assert_deprecated { @connection.supports_multi_insert? }
end
diff --git a/activerecord/test/cases/adapters/postgresql/composite_test.rb b/activerecord/test/cases/adapters/postgresql/composite_test.rb
index b0ce2694a3..683066cdb3 100644
--- a/activerecord/test/cases/adapters/postgresql/composite_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/composite_test.rb
@@ -15,13 +15,13 @@ module PostgresqlCompositeBehavior
@connection = ActiveRecord::Base.connection
@connection.transaction do
- @connection.execute <<-SQL
- CREATE TYPE full_address AS
- (
- city VARCHAR(90),
- street VARCHAR(90)
- );
- SQL
+ @connection.execute <<~SQL
+ CREATE TYPE full_address AS
+ (
+ city VARCHAR(90),
+ street VARCHAR(90)
+ );
+ SQL
@connection.create_table("postgresql_composites") do |t|
t.column :address, :full_address
end
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index 70aa189893..40ab158c05 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -146,34 +146,15 @@ module ActiveRecord
end
end
- # Must have PostgreSQL >= 9.2, or with_manual_interventions set to
- # true for this test to run.
- #
- # When prompted, restart the PostgreSQL server with the
- # "-m fast" option or kill the individual connection assuming
- # you know the incantation to do that.
- # To restart PostgreSQL 9.1 on macOS, 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
original_connection_pid = @connection.query("select pg_backend_pid()")
# Sanity check.
assert_predicate @connection, :active?
- if @connection.send(:postgresql_version) >= 90200
- secondary_connection = ActiveRecord::Base.connection_pool.checkout
- secondary_connection.query("select pg_terminate_backend(#{original_connection_pid.first.first})")
- ActiveRecord::Base.connection_pool.checkin(secondary_connection)
- elsif ARTest.config["with_manual_interventions"]
- puts "Kill the connection now (e.g. by restarting the PostgreSQL " \
- 'server with the "-m fast" option) and then press enter.'
- $stdin.gets
- else
- # We're not capable of terminating the backend ourselves, and
- # we're not allowed to seek assistance; bail out without
- # actually testing anything.
- return
- end
+ secondary_connection = ActiveRecord::Base.connection_pool.checkout
+ secondary_connection.query("select pg_terminate_backend(#{original_connection_pid.first.first})")
+ ActiveRecord::Base.connection_pool.checkin(secondary_connection)
@connection.verify!
@@ -230,7 +211,7 @@ module ActiveRecord
def test_get_and_release_advisory_lock
lock_id = 5295901941911233559
- list_advisory_locks = <<-SQL
+ list_advisory_locks = <<~SQL
SELECT locktype,
(classid::bigint << 32) | objid::bigint AS lock_id
FROM pg_locks
@@ -261,6 +242,10 @@ module ActiveRecord
end
end
+ def test_supports_ranges_is_deprecated
+ assert_deprecated { @connection.supports_ranges? }
+ end
+
private
def with_warning_suppression
diff --git a/activerecord/test/cases/adapters/postgresql/create_unlogged_tables_test.rb b/activerecord/test/cases/adapters/postgresql/create_unlogged_tables_test.rb
new file mode 100644
index 0000000000..a02bae1453
--- /dev/null
+++ b/activerecord/test/cases/adapters/postgresql/create_unlogged_tables_test.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "support/schema_dumping_helper"
+
+class UnloggedTablesTest < ActiveRecord::PostgreSQLTestCase
+ include SchemaDumpingHelper
+
+ TABLE_NAME = "things"
+ LOGGED_FIELD = "relpersistence"
+ LOGGED_QUERY = "SELECT #{LOGGED_FIELD} FROM pg_class WHERE relname = '#{TABLE_NAME}'"
+ LOGGED = "p"
+ UNLOGGED = "u"
+ TEMPORARY = "t"
+
+ class Thing < ActiveRecord::Base
+ self.table_name = TABLE_NAME
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = false
+ end
+
+ teardown do
+ @connection.drop_table TABLE_NAME, if_exists: true
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = false
+ end
+
+ def test_logged_by_default
+ @connection.create_table(TABLE_NAME) do |t|
+ end
+ assert_equal @connection.execute(LOGGED_QUERY).first[LOGGED_FIELD], LOGGED
+ end
+
+ def test_unlogged_in_test_environment_when_unlogged_setting_enabled
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
+
+ @connection.create_table(TABLE_NAME) do |t|
+ end
+ assert_equal @connection.execute(LOGGED_QUERY).first[LOGGED_FIELD], UNLOGGED
+ end
+
+ def test_not_included_in_schema_dump
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
+
+ @connection.create_table(TABLE_NAME) do |t|
+ end
+ assert_no_match(/unlogged/i, dump_table_schema(TABLE_NAME))
+ end
+
+ def test_not_changed_in_change_table
+ @connection.create_table(TABLE_NAME) do |t|
+ end
+
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
+
+ @connection.change_table(TABLE_NAME) do |t|
+ t.column :name, :string
+ end
+ assert_equal @connection.execute(LOGGED_QUERY).first[LOGGED_FIELD], LOGGED
+ end
+
+ def test_gracefully_handles_temporary_tables
+ @connection.create_table(TABLE_NAME, temporary: true) do |t|
+ end
+
+ # Temporary tables are already unlogged, though this query results in a
+ # different result ("t" vs. "u"). This test is really just checking that we
+ # didn't try to run `CREATE TEMPORARY UNLOGGED TABLE`, which would result in
+ # a PostgreSQL error.
+ assert_equal @connection.execute(LOGGED_QUERY).first[LOGGED_FIELD], TEMPORARY
+ end
+end
diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb
index 6789ff63e7..416a2b141b 100644
--- a/activerecord/test/cases/adapters/postgresql/enum_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb
@@ -13,7 +13,7 @@ class PostgresqlEnumTest < ActiveRecord::PostgreSQLTestCase
def setup
@connection = ActiveRecord::Base.connection
@connection.transaction do
- @connection.execute <<-SQL
+ @connection.execute <<~SQL
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
SQL
@connection.create_table("postgresql_enums") do |t|
diff --git a/activerecord/test/cases/adapters/postgresql/foreign_table_test.rb b/activerecord/test/cases/adapters/postgresql/foreign_table_test.rb
index 4fa315ad23..69339c8a31 100644
--- a/activerecord/test/cases/adapters/postgresql/foreign_table_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/foreign_table_test.rb
@@ -22,18 +22,18 @@ if ActiveRecord::Base.connection.supports_foreign_tables?
enable_extension!("postgres_fdw", @connection)
foreign_db_config = ARTest.connection_config["arunit2"]
- @connection.execute <<-SQL
+ @connection.execute <<~SQL
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (dbname '#{foreign_db_config["database"]}')
SQL
- @connection.execute <<-SQL
+ @connection.execute <<~SQL
CREATE USER MAPPING FOR CURRENT_USER
SERVER foreign_server
SQL
- @connection.execute <<-SQL
+ @connection.execute <<~SQL
CREATE FOREIGN TABLE foreign_professors (
id int,
name character varying NOT NULL
@@ -45,7 +45,7 @@ if ActiveRecord::Base.connection.supports_foreign_tables?
def teardown
disable_extension!("postgres_fdw", @connection)
- @connection.execute <<-SQL
+ @connection.execute <<~SQL
DROP SERVER IF EXISTS foreign_server CASCADE
SQL
end
diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb
index 75e5aaed53..1aa0348879 100644
--- a/activerecord/test/cases/adapters/postgresql/money_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/money_test.rb
@@ -37,7 +37,7 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase
def test_default
assert_equal BigDecimal("150.55"), PostgresqlMoney.column_defaults["depth"]
assert_equal BigDecimal("150.55"), PostgresqlMoney.new.depth
- assert_equal "$150.55", PostgresqlMoney.new.depth_before_type_cast
+ assert_equal "150.55", PostgresqlMoney.new.depth_before_type_cast
end
def test_money_values
diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb
index 433598500d..478cd5aa76 100644
--- a/activerecord/test/cases/adapters/postgresql/range_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/range_test.rb
@@ -3,418 +3,416 @@
require "cases/helper"
require "support/connection_helper"
-if ActiveRecord::Base.connection.respond_to?(:supports_ranges?) && ActiveRecord::Base.connection.supports_ranges?
- class PostgresqlRange < ActiveRecord::Base
- self.table_name = "postgresql_ranges"
- self.time_zone_aware_types += [:tsrange, :tstzrange]
- end
-
- class PostgresqlRangeTest < ActiveRecord::PostgreSQLTestCase
- self.use_transactional_tests = false
- include ConnectionHelper
- include InTimeZone
-
- def setup
- @connection = PostgresqlRange.connection
- begin
- @connection.transaction do
- @connection.execute <<_SQL
- CREATE TYPE floatrange AS RANGE (
- subtype = float8,
- subtype_diff = float8mi
- );
-_SQL
-
- @connection.create_table("postgresql_ranges") do |t|
- t.daterange :date_range
- t.numrange :num_range
- t.tsrange :ts_range
- t.tstzrange :tstz_range
- t.int4range :int4_range
- t.int8range :int8_range
- end
-
- @connection.add_column "postgresql_ranges", "float_range", "floatrange"
- end
- PostgresqlRange.reset_column_information
- rescue ActiveRecord::StatementInvalid
- skip "do not test on PG without range"
- end
-
- insert_range(id: 101,
- date_range: "[''2012-01-02'', ''2012-01-04'']",
- num_range: "[0.1, 0.2]",
- ts_range: "[''2010-01-01 14:30'', ''2011-01-01 14:30'']",
- tstz_range: "[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']",
- int4_range: "[1, 10]",
- int8_range: "[10, 100]",
- float_range: "[0.5, 0.7]")
-
- insert_range(id: 102,
- date_range: "[''2012-01-02'', ''2012-01-04'')",
- num_range: "[0.1, 0.2)",
- ts_range: "[''2010-01-01 14:30'', ''2011-01-01 14:30'')",
- tstz_range: "[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'')",
- int4_range: "[1, 10)",
- int8_range: "[10, 100)",
- float_range: "[0.5, 0.7)")
-
- insert_range(id: 103,
- date_range: "[''2012-01-02'',]",
- num_range: "[0.1,]",
- ts_range: "[''2010-01-01 14:30'',]",
- tstz_range: "[''2010-01-01 14:30:00+05'',]",
- int4_range: "[1,]",
- int8_range: "[10,]",
- float_range: "[0.5,]")
-
- insert_range(id: 104,
- date_range: "[,]",
- num_range: "[,]",
- ts_range: "[,]",
- tstz_range: "[,]",
- int4_range: "[,]",
- int8_range: "[,]",
- float_range: "[,]")
-
- insert_range(id: 105,
- date_range: "[''2012-01-02'', ''2012-01-02'')",
- num_range: "[0.1, 0.1)",
- ts_range: "[''2010-01-01 14:30'', ''2010-01-01 14:30'')",
- tstz_range: "[''2010-01-01 14:30:00+05'', ''2010-01-01 06:30:00-03'')",
- int4_range: "[1, 1)",
- int8_range: "[10, 10)",
- float_range: "[0.5, 0.5)")
-
- @new_range = PostgresqlRange.new
- @first_range = PostgresqlRange.find(101)
- @second_range = PostgresqlRange.find(102)
- @third_range = PostgresqlRange.find(103)
- @fourth_range = PostgresqlRange.find(104)
- @empty_range = PostgresqlRange.find(105)
- end
+class PostgresqlRange < ActiveRecord::Base
+ self.table_name = "postgresql_ranges"
+ self.time_zone_aware_types += [:tsrange, :tstzrange]
+end
- teardown do
- @connection.drop_table "postgresql_ranges", if_exists: true
- @connection.execute "DROP TYPE IF EXISTS floatrange"
- reset_connection
- end
+class PostgresqlRangeTest < ActiveRecord::PostgreSQLTestCase
+ self.use_transactional_tests = false
+ include ConnectionHelper
+ include InTimeZone
+
+ def setup
+ @connection = PostgresqlRange.connection
+ begin
+ @connection.transaction do
+ @connection.execute <<~SQL
+ CREATE TYPE floatrange AS RANGE (
+ subtype = float8,
+ subtype_diff = float8mi
+ );
+ SQL
- 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
+ @connection.create_table("postgresql_ranges") do |t|
+ t.daterange :date_range
+ t.numrange :num_range
+ t.tsrange :ts_range
+ t.tstzrange :tstz_range
+ t.int4range :int4_range
+ t.int8range :int8_range
+ end
- def test_int4range_values
- assert_equal 1...11, @first_range.int4_range
- assert_equal 1...10, @second_range.int4_range
- assert_equal 1...Float::INFINITY, @third_range.int4_range
- assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int4_range)
- assert_nil @empty_range.int4_range
- end
+ @connection.add_column "postgresql_ranges", "float_range", "floatrange"
+ end
+ PostgresqlRange.reset_column_information
+ rescue ActiveRecord::StatementInvalid
+ skip "do not test on PG without range"
+ end
+
+ insert_range(id: 101,
+ date_range: "[''2012-01-02'', ''2012-01-04'']",
+ num_range: "[0.1, 0.2]",
+ ts_range: "[''2010-01-01 14:30'', ''2011-01-01 14:30'']",
+ tstz_range: "[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']",
+ int4_range: "[1, 10]",
+ int8_range: "[10, 100]",
+ float_range: "[0.5, 0.7]")
+
+ insert_range(id: 102,
+ date_range: "[''2012-01-02'', ''2012-01-04'')",
+ num_range: "[0.1, 0.2)",
+ ts_range: "[''2010-01-01 14:30'', ''2011-01-01 14:30'')",
+ tstz_range: "[''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'')",
+ int4_range: "[1, 10)",
+ int8_range: "[10, 100)",
+ float_range: "[0.5, 0.7)")
+
+ insert_range(id: 103,
+ date_range: "[''2012-01-02'',]",
+ num_range: "[0.1,]",
+ ts_range: "[''2010-01-01 14:30'',]",
+ tstz_range: "[''2010-01-01 14:30:00+05'',]",
+ int4_range: "[1,]",
+ int8_range: "[10,]",
+ float_range: "[0.5,]")
+
+ insert_range(id: 104,
+ date_range: "[,]",
+ num_range: "[,]",
+ ts_range: "[,]",
+ tstz_range: "[,]",
+ int4_range: "[,]",
+ int8_range: "[,]",
+ float_range: "[,]")
+
+ insert_range(id: 105,
+ date_range: "[''2012-01-02'', ''2012-01-02'')",
+ num_range: "[0.1, 0.1)",
+ ts_range: "[''2010-01-01 14:30'', ''2010-01-01 14:30'')",
+ tstz_range: "[''2010-01-01 14:30:00+05'', ''2010-01-01 06:30:00-03'')",
+ int4_range: "[1, 1)",
+ int8_range: "[10, 10)",
+ float_range: "[0.5, 0.5)")
+
+ @new_range = PostgresqlRange.new
+ @first_range = PostgresqlRange.find(101)
+ @second_range = PostgresqlRange.find(102)
+ @third_range = PostgresqlRange.find(103)
+ @fourth_range = PostgresqlRange.find(104)
+ @empty_range = PostgresqlRange.find(105)
+ end
- def test_int8range_values
- assert_equal 10...101, @first_range.int8_range
- assert_equal 10...100, @second_range.int8_range
- assert_equal 10...Float::INFINITY, @third_range.int8_range
- assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.int8_range)
- assert_nil @empty_range.int8_range
- end
+ teardown do
+ @connection.drop_table "postgresql_ranges", if_exists: true
+ @connection.execute "DROP TYPE IF EXISTS floatrange"
+ reset_connection
+ 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, 2)...Date.new(2012, 1, 4), @second_range.date_range
- assert_equal Date.new(2012, 1, 2)...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_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_numrange_values
- assert_equal BigDecimal("0.1")..BigDecimal("0.2"), @first_range.num_range
- assert_equal BigDecimal("0.1")...BigDecimal("0.2"), @second_range.num_range
- assert_equal BigDecimal("0.1")...BigDecimal("Infinity"), @third_range.num_range
- assert_equal BigDecimal("-Infinity")...BigDecimal("Infinity"), @fourth_range.num_range
- assert_nil @empty_range.num_range
- end
+ def test_int4range_values
+ assert_equal 1...11, @first_range.int4_range
+ assert_equal 1...10, @second_range.int4_range
+ assert_equal 1...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_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_int8range_values
+ assert_equal 10...101, @first_range.int8_range
+ assert_equal 10...100, @second_range.int8_range
+ assert_equal 10...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_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_daterange_values
+ assert_equal Date.new(2012, 1, 2)...Date.new(2012, 1, 5), @first_range.date_range
+ assert_equal Date.new(2012, 1, 2)...Date.new(2012, 1, 4), @second_range.date_range
+ assert_equal Date.new(2012, 1, 2)...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_custom_range_values
- assert_equal 0.5..0.7, @first_range.float_range
- assert_equal 0.5...0.7, @second_range.float_range
- assert_equal 0.5...Float::INFINITY, @third_range.float_range
- assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.float_range)
- assert_nil @empty_range.float_range
- end
+ def test_numrange_values
+ assert_equal BigDecimal("0.1")..BigDecimal("0.2"), @first_range.num_range
+ assert_equal BigDecimal("0.1")...BigDecimal("0.2"), @second_range.num_range
+ assert_equal BigDecimal("0.1")...BigDecimal("Infinity"), @third_range.num_range
+ assert_equal BigDecimal("-Infinity")...BigDecimal("Infinity"), @fourth_range.num_range
+ assert_nil @empty_range.num_range
+ end
- def test_timezone_awareness_tzrange
- tz = "Pacific Time (US & Canada)"
+ 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
- in_time_zone tz do
- PostgresqlRange.reset_column_information
- time_string = Time.current.to_s
- time = Time.zone.parse(time_string)
+ 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
- record = PostgresqlRange.new(tstz_range: time_string..time_string)
- assert_equal time..time, record.tstz_range
- assert_equal ActiveSupport::TimeZone[tz], record.tstz_range.begin.time_zone
+ def test_custom_range_values
+ assert_equal 0.5..0.7, @first_range.float_range
+ assert_equal 0.5...0.7, @second_range.float_range
+ assert_equal 0.5...Float::INFINITY, @third_range.float_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.float_range)
+ assert_nil @empty_range.float_range
+ end
- record.save!
- record.reload
+ def test_timezone_awareness_tzrange
+ tz = "Pacific Time (US & Canada)"
- assert_equal time..time, record.tstz_range
- assert_equal ActiveSupport::TimeZone[tz], record.tstz_range.begin.time_zone
- end
- end
+ in_time_zone tz do
+ PostgresqlRange.reset_column_information
+ time_string = Time.current.to_s
+ time = Time.zone.parse(time_string)
- def test_create_tstzrange
- tstzrange = Time.parse("2010-01-01 14:30:00 +0100")...Time.parse("2011-02-02 14:30:00 CDT")
- round_trip(@new_range, :tstz_range, tstzrange)
- assert_equal @new_range.tstz_range, tstzrange
- assert_equal @new_range.tstz_range, Time.parse("2010-01-01 13:30:00 UTC")...Time.parse("2011-02-02 19:30:00 UTC")
- end
+ record = PostgresqlRange.new(tstz_range: time_string..time_string)
+ assert_equal time..time, record.tstz_range
+ assert_equal ActiveSupport::TimeZone[tz], record.tstz_range.begin.time_zone
- def test_update_tstzrange
- assert_equal_round_trip(@first_range, :tstz_range,
- Time.parse("2010-01-01 14:30:00 CDT")...Time.parse("2011-02-02 14:30:00 CET"))
- assert_nil_round_trip(@first_range, :tstz_range,
- Time.parse("2010-01-01 14:30:00 +0100")...Time.parse("2010-01-01 13:30:00 +0000"))
- end
+ record.save!
+ record.reload
- def test_create_tsrange
- tz = ::ActiveRecord::Base.default_timezone
- assert_equal_round_trip(@new_range, :ts_range,
- Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0))
+ assert_equal time..time, record.tstz_range
+ assert_equal ActiveSupport::TimeZone[tz], record.tstz_range.begin.time_zone
end
+ end
- def test_update_tsrange
- tz = ::ActiveRecord::Base.default_timezone
- assert_equal_round_trip(@first_range, :ts_range,
- Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0))
- assert_nil_round_trip(@first_range, :ts_range,
- Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2010, 1, 1, 14, 30, 0))
- end
+ def test_create_tstzrange
+ tstzrange = Time.parse("2010-01-01 14:30:00 +0100")...Time.parse("2011-02-02 14:30:00 CDT")
+ round_trip(@new_range, :tstz_range, tstzrange)
+ assert_equal @new_range.tstz_range, tstzrange
+ assert_equal @new_range.tstz_range, Time.parse("2010-01-01 13:30:00 UTC")...Time.parse("2011-02-02 19:30:00 UTC")
+ end
- def test_timezone_awareness_tsrange
- tz = "Pacific Time (US & Canada)"
+ def test_update_tstzrange
+ assert_equal_round_trip(@first_range, :tstz_range,
+ Time.parse("2010-01-01 14:30:00 CDT")...Time.parse("2011-02-02 14:30:00 CET"))
+ assert_nil_round_trip(@first_range, :tstz_range,
+ Time.parse("2010-01-01 14:30:00 +0100")...Time.parse("2010-01-01 13:30:00 +0000"))
+ end
- in_time_zone tz do
- PostgresqlRange.reset_column_information
- time_string = Time.current.to_s
- time = Time.zone.parse(time_string)
+ def test_create_tsrange
+ tz = ::ActiveRecord::Base.default_timezone
+ assert_equal_round_trip(@new_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0))
+ end
- record = PostgresqlRange.new(ts_range: time_string..time_string)
- assert_equal time..time, record.ts_range
- assert_equal ActiveSupport::TimeZone[tz], record.ts_range.begin.time_zone
+ def test_update_tsrange
+ tz = ::ActiveRecord::Base.default_timezone
+ assert_equal_round_trip(@first_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 2, 2, 14, 30, 0))
+ assert_nil_round_trip(@first_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2010, 1, 1, 14, 30, 0))
+ end
- record.save!
- record.reload
+ def test_timezone_awareness_tsrange
+ tz = "Pacific Time (US & Canada)"
- assert_equal time..time, record.ts_range
- assert_equal ActiveSupport::TimeZone[tz], record.ts_range.begin.time_zone
- end
- end
+ in_time_zone tz do
+ PostgresqlRange.reset_column_information
+ time_string = Time.current.to_s
+ time = Time.zone.parse(time_string)
- def test_create_tstzrange_preserve_usec
- tstzrange = Time.parse("2010-01-01 14:30:00.670277 +0100")...Time.parse("2011-02-02 14:30:00.745125 CDT")
- round_trip(@new_range, :tstz_range, tstzrange)
- assert_equal @new_range.tstz_range, tstzrange
- assert_equal @new_range.tstz_range, Time.parse("2010-01-01 13:30:00.670277 UTC")...Time.parse("2011-02-02 19:30:00.745125 UTC")
- end
+ record = PostgresqlRange.new(ts_range: time_string..time_string)
+ assert_equal time..time, record.ts_range
+ assert_equal ActiveSupport::TimeZone[tz], record.ts_range.begin.time_zone
- def test_update_tstzrange_preserve_usec
- assert_equal_round_trip(@first_range, :tstz_range,
- Time.parse("2010-01-01 14:30:00.245124 CDT")...Time.parse("2011-02-02 14:30:00.451274 CET"))
- assert_nil_round_trip(@first_range, :tstz_range,
- Time.parse("2010-01-01 14:30:00.245124 +0100")...Time.parse("2010-01-01 13:30:00.245124 +0000"))
- end
+ record.save!
+ record.reload
- def test_create_tsrange_preseve_usec
- tz = ::ActiveRecord::Base.default_timezone
- assert_equal_round_trip(@new_range, :ts_range,
- Time.send(tz, 2010, 1, 1, 14, 30, 0, 125435)...Time.send(tz, 2011, 2, 2, 14, 30, 0, 225435))
+ assert_equal time..time, record.ts_range
+ assert_equal ActiveSupport::TimeZone[tz], record.ts_range.begin.time_zone
end
+ end
- def test_update_tsrange_preserve_usec
- tz = ::ActiveRecord::Base.default_timezone
- assert_equal_round_trip(@first_range, :ts_range,
- Time.send(tz, 2010, 1, 1, 14, 30, 0, 142432)...Time.send(tz, 2011, 2, 2, 14, 30, 0, 224242))
- assert_nil_round_trip(@first_range, :ts_range,
- Time.send(tz, 2010, 1, 1, 14, 30, 0, 142432)...Time.send(tz, 2010, 1, 1, 14, 30, 0, 142432))
- end
+ def test_create_tstzrange_preserve_usec
+ tstzrange = Time.parse("2010-01-01 14:30:00.670277 +0100")...Time.parse("2011-02-02 14:30:00.745125 CDT")
+ round_trip(@new_range, :tstz_range, tstzrange)
+ assert_equal @new_range.tstz_range, tstzrange
+ assert_equal @new_range.tstz_range, Time.parse("2010-01-01 13:30:00.670277 UTC")...Time.parse("2011-02-02 19:30:00.745125 UTC")
+ end
- def test_timezone_awareness_tsrange_preserve_usec
- tz = "Pacific Time (US & Canada)"
+ def test_update_tstzrange_preserve_usec
+ assert_equal_round_trip(@first_range, :tstz_range,
+ Time.parse("2010-01-01 14:30:00.245124 CDT")...Time.parse("2011-02-02 14:30:00.451274 CET"))
+ assert_nil_round_trip(@first_range, :tstz_range,
+ Time.parse("2010-01-01 14:30:00.245124 +0100")...Time.parse("2010-01-01 13:30:00.245124 +0000"))
+ end
- in_time_zone tz do
- PostgresqlRange.reset_column_information
- time_string = "2017-09-26 07:30:59.132451 -0700"
- time = Time.zone.parse(time_string)
- assert time.usec > 0
+ def test_create_tsrange_preseve_usec
+ tz = ::ActiveRecord::Base.default_timezone
+ assert_equal_round_trip(@new_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0, 125435)...Time.send(tz, 2011, 2, 2, 14, 30, 0, 225435))
+ end
- record = PostgresqlRange.new(ts_range: time_string..time_string)
- assert_equal time..time, record.ts_range
- assert_equal ActiveSupport::TimeZone[tz], record.ts_range.begin.time_zone
- assert_equal time.usec, record.ts_range.begin.usec
+ def test_update_tsrange_preserve_usec
+ tz = ::ActiveRecord::Base.default_timezone
+ assert_equal_round_trip(@first_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0, 142432)...Time.send(tz, 2011, 2, 2, 14, 30, 0, 224242))
+ assert_nil_round_trip(@first_range, :ts_range,
+ Time.send(tz, 2010, 1, 1, 14, 30, 0, 142432)...Time.send(tz, 2010, 1, 1, 14, 30, 0, 142432))
+ end
- record.save!
- record.reload
+ def test_timezone_awareness_tsrange_preserve_usec
+ tz = "Pacific Time (US & Canada)"
- assert_equal time..time, record.ts_range
- assert_equal ActiveSupport::TimeZone[tz], record.ts_range.begin.time_zone
- assert_equal time.usec, record.ts_range.begin.usec
- end
- end
+ in_time_zone tz do
+ PostgresqlRange.reset_column_information
+ time_string = "2017-09-26 07:30:59.132451 -0700"
+ time = Time.zone.parse(time_string)
+ assert time.usec > 0
- def test_create_numrange
- assert_equal_round_trip(@new_range, :num_range,
- BigDecimal("0.5")...BigDecimal("1"))
- end
+ record = PostgresqlRange.new(ts_range: time_string..time_string)
+ assert_equal time..time, record.ts_range
+ assert_equal ActiveSupport::TimeZone[tz], record.ts_range.begin.time_zone
+ assert_equal time.usec, record.ts_range.begin.usec
- def test_update_numrange
- assert_equal_round_trip(@first_range, :num_range,
- BigDecimal("0.5")...BigDecimal("1"))
- assert_nil_round_trip(@first_range, :num_range,
- BigDecimal("0.5")...BigDecimal("0.5"))
- end
+ record.save!
+ record.reload
- def test_create_daterange
- assert_equal_round_trip(@new_range, :date_range,
- Range.new(Date.new(2012, 1, 1), Date.new(2013, 1, 1), true))
+ assert_equal time..time, record.ts_range
+ assert_equal ActiveSupport::TimeZone[tz], record.ts_range.begin.time_zone
+ assert_equal time.usec, record.ts_range.begin.usec
end
+ end
- def test_update_daterange
- assert_equal_round_trip(@first_range, :date_range,
- Date.new(2012, 2, 3)...Date.new(2012, 2, 10))
- assert_nil_round_trip(@first_range, :date_range,
- Date.new(2012, 2, 3)...Date.new(2012, 2, 3))
- end
+ def test_create_numrange
+ assert_equal_round_trip(@new_range, :num_range,
+ BigDecimal("0.5")...BigDecimal("1"))
+ end
- def test_create_int4range
- assert_equal_round_trip(@new_range, :int4_range, Range.new(3, 50, true))
- end
+ def test_update_numrange
+ assert_equal_round_trip(@first_range, :num_range,
+ BigDecimal("0.5")...BigDecimal("1"))
+ assert_nil_round_trip(@first_range, :num_range,
+ BigDecimal("0.5")...BigDecimal("0.5"))
+ end
- def test_update_int4range
- assert_equal_round_trip(@first_range, :int4_range, 6...10)
- assert_nil_round_trip(@first_range, :int4_range, 3...3)
- end
+ def test_create_daterange
+ assert_equal_round_trip(@new_range, :date_range,
+ Range.new(Date.new(2012, 1, 1), Date.new(2013, 1, 1), true))
+ end
- def test_create_int8range
- assert_equal_round_trip(@new_range, :int8_range, Range.new(30, 50, true))
- end
+ def test_update_daterange
+ assert_equal_round_trip(@first_range, :date_range,
+ Date.new(2012, 2, 3)...Date.new(2012, 2, 10))
+ assert_nil_round_trip(@first_range, :date_range,
+ Date.new(2012, 2, 3)...Date.new(2012, 2, 3))
+ end
- def test_update_int8range
- assert_equal_round_trip(@first_range, :int8_range, 60000...10000000)
- assert_nil_round_trip(@first_range, :int8_range, 39999...39999)
- end
+ def test_create_int4range
+ assert_equal_round_trip(@new_range, :int4_range, Range.new(3, 50, true))
+ end
- def test_exclude_beginning_for_subtypes_without_succ_method_is_not_supported
- assert_raises(ArgumentError) { PostgresqlRange.create!(num_range: "(0.1, 0.2]") }
- assert_raises(ArgumentError) { PostgresqlRange.create!(float_range: "(0.5, 0.7]") }
- assert_raises(ArgumentError) { PostgresqlRange.create!(int4_range: "(1, 10]") }
- assert_raises(ArgumentError) { PostgresqlRange.create!(int8_range: "(10, 100]") }
- assert_raises(ArgumentError) { PostgresqlRange.create!(date_range: "(''2012-01-02'', ''2012-01-04'']") }
- assert_raises(ArgumentError) { PostgresqlRange.create!(ts_range: "(''2010-01-01 14:30'', ''2011-01-01 14:30'']") }
- assert_raises(ArgumentError) { PostgresqlRange.create!(tstz_range: "(''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']") }
- end
+ def test_update_int4range
+ assert_equal_round_trip(@first_range, :int4_range, 6...10)
+ assert_nil_round_trip(@first_range, :int4_range, 3...3)
+ end
- def test_where_by_attribute_with_range
- range = 1..100
- record = PostgresqlRange.create!(int4_range: range)
- assert_equal record, PostgresqlRange.where(int4_range: range).take
- end
+ def test_create_int8range
+ assert_equal_round_trip(@new_range, :int8_range, Range.new(30, 50, true))
+ end
- def test_where_by_attribute_with_range_in_array
- range = 1..100
- record = PostgresqlRange.create!(int4_range: range)
- assert_equal record, PostgresqlRange.where(int4_range: [range]).take
- end
+ def test_update_int8range
+ assert_equal_round_trip(@first_range, :int8_range, 60000...10000000)
+ assert_nil_round_trip(@first_range, :int8_range, 39999...39999)
+ end
- def test_update_all_with_ranges
- PostgresqlRange.create!
+ def test_exclude_beginning_for_subtypes_without_succ_method_is_not_supported
+ assert_raises(ArgumentError) { PostgresqlRange.create!(num_range: "(0.1, 0.2]") }
+ assert_raises(ArgumentError) { PostgresqlRange.create!(float_range: "(0.5, 0.7]") }
+ assert_raises(ArgumentError) { PostgresqlRange.create!(int4_range: "(1, 10]") }
+ assert_raises(ArgumentError) { PostgresqlRange.create!(int8_range: "(10, 100]") }
+ assert_raises(ArgumentError) { PostgresqlRange.create!(date_range: "(''2012-01-02'', ''2012-01-04'']") }
+ assert_raises(ArgumentError) { PostgresqlRange.create!(ts_range: "(''2010-01-01 14:30'', ''2011-01-01 14:30'']") }
+ assert_raises(ArgumentError) { PostgresqlRange.create!(tstz_range: "(''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']") }
+ end
- PostgresqlRange.update_all(int8_range: 1..100)
+ def test_where_by_attribute_with_range
+ range = 1..100
+ record = PostgresqlRange.create!(int4_range: range)
+ assert_equal record, PostgresqlRange.where(int4_range: range).take
+ end
- assert_equal 1...101, PostgresqlRange.first.int8_range
- end
+ def test_where_by_attribute_with_range_in_array
+ range = 1..100
+ record = PostgresqlRange.create!(int4_range: range)
+ assert_equal record, PostgresqlRange.where(int4_range: [range]).take
+ end
- def test_ranges_correctly_escape_input
- range = "-1,2]'; DROP TABLE postgresql_ranges; --".."a"
- PostgresqlRange.update_all(int8_range: range)
+ def test_update_all_with_ranges
+ PostgresqlRange.create!
- assert_nothing_raised do
- PostgresqlRange.first
- end
- end
+ PostgresqlRange.update_all(int8_range: 1..100)
- def test_infinity_values
- PostgresqlRange.create!(int4_range: 1..Float::INFINITY,
- int8_range: -Float::INFINITY..0,
- float_range: -Float::INFINITY..Float::INFINITY)
+ assert_equal 1...101, PostgresqlRange.first.int8_range
+ end
- record = PostgresqlRange.first
+ def test_ranges_correctly_escape_input
+ range = "-1,2]'; DROP TABLE postgresql_ranges; --".."a"
+ PostgresqlRange.update_all(int8_range: range)
- assert_equal(1...Float::INFINITY, record.int4_range)
- assert_equal(-Float::INFINITY...1, record.int8_range)
- assert_equal(-Float::INFINITY...Float::INFINITY, record.float_range)
+ assert_nothing_raised do
+ PostgresqlRange.first
end
+ end
- private
- def assert_equal_round_trip(range, attribute, value)
- round_trip(range, attribute, value)
- assert_equal value, range.public_send(attribute)
- end
-
- def assert_nil_round_trip(range, attribute, value)
- round_trip(range, attribute, value)
- assert_nil range.public_send(attribute)
- end
+ def test_infinity_values
+ PostgresqlRange.create!(int4_range: 1..Float::INFINITY,
+ int8_range: -Float::INFINITY..0,
+ float_range: -Float::INFINITY..Float::INFINITY)
- def round_trip(range, attribute, value)
- range.public_send "#{attribute}=", value
- assert range.save
- assert range.reload
- end
+ record = PostgresqlRange.first
- def insert_range(values)
- @connection.execute <<-SQL
- INSERT INTO postgresql_ranges (
- id,
- date_range,
- num_range,
- ts_range,
- tstz_range,
- int4_range,
- int8_range,
- float_range
- ) VALUES (
- #{values[:id]},
- '#{values[:date_range]}',
- '#{values[:num_range]}',
- '#{values[:ts_range]}',
- '#{values[:tstz_range]}',
- '#{values[:int4_range]}',
- '#{values[:int8_range]}',
- '#{values[:float_range]}'
- )
- SQL
- end
+ assert_equal(1...Float::INFINITY, record.int4_range)
+ assert_equal(-Float::INFINITY...1, record.int8_range)
+ assert_equal(-Float::INFINITY...Float::INFINITY, record.float_range)
end
+
+ private
+ def assert_equal_round_trip(range, attribute, value)
+ round_trip(range, attribute, value)
+ assert_equal value, range.public_send(attribute)
+ end
+
+ def assert_nil_round_trip(range, attribute, value)
+ round_trip(range, attribute, value)
+ assert_nil range.public_send(attribute)
+ end
+
+ def round_trip(range, attribute, value)
+ range.public_send "#{attribute}=", value
+ assert range.save
+ assert range.reload
+ end
+
+ def insert_range(values)
+ @connection.execute <<~SQL
+ INSERT INTO postgresql_ranges (
+ id,
+ date_range,
+ num_range,
+ ts_range,
+ tstz_range,
+ int4_range,
+ int8_range,
+ float_range
+ ) VALUES (
+ #{values[:id]},
+ '#{values[:date_range]}',
+ '#{values[:num_range]}',
+ '#{values[:ts_range]}',
+ '#{values[:tstz_range]}',
+ '#{values[:int4_range]}',
+ '#{values[:int8_range]}',
+ '#{values[:float_range]}'
+ )
+ SQL
+ end
end
diff --git a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
index 100d247113..7eccaf4aa2 100644
--- a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
@@ -27,7 +27,7 @@ class PostgresqlRenameTableTest < ActiveRecord::PostgreSQLTestCase
private
def num_indices_named(name)
- @connection.execute(<<-SQL).values.length
+ @connection.execute(<<~SQL).values.length
SELECT 1 FROM "pg_index"
JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid"
WHERE "pg_class"."relname" = '#{name}'
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index a36d066c80..931a9bd0be 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -146,7 +146,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
def test_habtm_table_name_with_schema
ActiveRecord::Base.connection.drop_schema "music", if_exists: true
ActiveRecord::Base.connection.create_schema "music"
- ActiveRecord::Base.connection.execute <<-SQL
+ ActiveRecord::Base.connection.execute <<~SQL
CREATE TABLE music.albums (id serial primary key);
CREATE TABLE music.songs (id serial primary key);
CREATE TABLE music.albums_songs (album_id integer, song_id integer);
@@ -507,6 +507,7 @@ class SchemaIndexOpclassTest < ActiveRecord::PostgreSQLTestCase
@connection = ActiveRecord::Base.connection
@connection.create_table "trains" do |t|
t.string :name
+ t.string :position
t.text :description
end
end
@@ -530,6 +531,17 @@ class SchemaIndexOpclassTest < ActiveRecord::PostgreSQLTestCase
assert_match(/opclass: \{ description: :text_pattern_ops \}/, output)
end
+
+ def test_opclass_class_parsing_on_non_reserved_and_cannot_be_function_or_type_keyword
+ @connection.enable_extension("pg_trgm")
+ @connection.execute "CREATE INDEX trains_position ON trains USING gin(position gin_trgm_ops)"
+ @connection.execute "CREATE INDEX trains_name_and_position ON trains USING btree(name, position text_pattern_ops)"
+
+ output = dump_table_schema "trains"
+
+ assert_match(/opclass: :gin_trgm_ops/, output)
+ assert_match(/opclass: \{ position: :text_pattern_ops \}/, output)
+ end
end
class SchemaIndexNullsOrderTest < ActiveRecord::PostgreSQLTestCase
diff --git a/activerecord/test/cases/adapters/postgresql/transaction_test.rb b/activerecord/test/cases/adapters/postgresql/transaction_test.rb
index 984b2f5ea4..919ff3d158 100644
--- a/activerecord/test/cases/adapters/postgresql/transaction_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/transaction_test.rb
@@ -94,7 +94,6 @@ module ActiveRecord
end
test "raises LockWaitTimeout when lock wait timeout exceeded" do
- skip unless ActiveRecord::Base.connection.postgresql_version >= 90300
assert_raises(ActiveRecord::LockWaitTimeout) do
s = Sample.create!(value: 1)
latch1 = Concurrent::CountDownLatch.new
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index 71d07e2f4c..9912763c1b 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -198,10 +198,10 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase
# Create custom PostgreSQL function to generate UUIDs
# to test dumping tables which columns have defaults with custom functions
- connection.execute <<-SQL
- CREATE OR REPLACE FUNCTION my_uuid_generator() RETURNS uuid
- AS $$ SELECT * FROM #{uuid_function} $$
- LANGUAGE SQL VOLATILE;
+ connection.execute <<~SQL
+ CREATE OR REPLACE FUNCTION my_uuid_generator() RETURNS uuid
+ AS $$ SELECT * FROM #{uuid_function} $$
+ LANGUAGE SQL VOLATILE;
SQL
# Create such a table with custom function as default value generator
diff --git a/activerecord/test/cases/adapters/sqlite3/bind_parameter_test.rb b/activerecord/test/cases/adapters/sqlite3/bind_parameter_test.rb
new file mode 100644
index 0000000000..93a7dafebd
--- /dev/null
+++ b/activerecord/test/cases/adapters/sqlite3/bind_parameter_test.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "models/topic"
+
+module ActiveRecord
+ module ConnectionAdapters
+ class SQLite3Adapter
+ class BindParameterTest < ActiveRecord::SQLite3TestCase
+ def test_too_many_binds
+ topics = Topic.where(id: (1..999).to_a << 2**63)
+ assert_equal Topic.count, topics.count
+
+ topics = Topic.where.not(id: (1..999).to_a << 2**63)
+ assert_equal 0, topics.count
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index 89052019f8..8536dcf183 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -55,11 +55,11 @@ module ActiveRecord
owner = Owner.create!(name: "hello".encode("ascii-8bit"))
owner.reload
select = Owner.columns.map { |c| "typeof(#{c.name})" }.join ", "
- result = Owner.connection.exec_query <<-esql
+ result = Owner.connection.exec_query <<~SQL
SELECT #{select}
FROM #{Owner.table_name}
WHERE #{Owner.primary_key} = #{owner.id}
- esql
+ SQL
assert_not(result.rows.first.include?("blob"), "should not store blobs")
ensure
@@ -160,13 +160,13 @@ module ActiveRecord
end
def test_quote_binary_column_escapes_it
- DualEncoding.connection.execute(<<-eosql)
+ DualEncoding.connection.execute(<<~SQL)
CREATE TABLE IF NOT EXISTS dual_encodings (
id integer PRIMARY KEY AUTOINCREMENT,
name varchar(255),
data binary
)
- eosql
+ SQL
str = (+"\x80").force_encoding("ASCII-8BIT")
binary = DualEncoding.new name: "いただきます!", data: str
binary.save!
@@ -261,7 +261,7 @@ module ActiveRecord
end
def test_tables_logs_name
- sql = <<-SQL
+ sql = <<~SQL
SELECT name FROM sqlite_master WHERE name <> 'sqlite_sequence' AND type IN ('table')
SQL
assert_logged [[sql.squish, "SCHEMA", []]] do
@@ -271,7 +271,7 @@ module ActiveRecord
def test_table_exists_logs_name
with_example_table do
- sql = <<-SQL
+ sql = <<~SQL
SELECT name FROM sqlite_master WHERE name <> 'sqlite_sequence' AND name = 'ex' AND type IN ('table')
SQL
assert_logged [[sql.squish, "SCHEMA", []]] do
@@ -585,7 +585,7 @@ module ActiveRecord
end
def with_example_table(definition = nil, table_name = "ex", &block)
- definition ||= <<-SQL
+ definition ||= <<~SQL
id integer PRIMARY KEY AUTOINCREMENT,
number integer
SQL
diff --git a/activerecord/test/cases/arel/visitors/ibm_db_test.rb b/activerecord/test/cases/arel/visitors/ibm_db_test.rb
index 7163cb34d3..2ddbec3266 100644
--- a/activerecord/test/cases/arel/visitors/ibm_db_test.rb
+++ b/activerecord/test/cases/arel/visitors/ibm_db_test.rb
@@ -29,6 +29,45 @@ module Arel
sql = compile(stmt)
sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT \"users\".\"id\" FROM \"users\" FETCH FIRST 1 ROWS ONLY)"
end
+
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ DECODE("users"."name", 'Aaron Patterson', 0, 1) = 0
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ DECODE("users"."first_name", "users"."last_name", 0, 1) = 0
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ DECODE("users"."first_name", "users"."last_name", 0, 1) = 1
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NOT NULL }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/visitors/informix_test.rb b/activerecord/test/cases/arel/visitors/informix_test.rb
index b0b031cca3..b6c2dd6ae7 100644
--- a/activerecord/test/cases/arel/visitors/informix_test.rb
+++ b/activerecord/test/cases/arel/visitors/informix_test.rb
@@ -54,6 +54,45 @@ module Arel
sql = compile(stmt)
sql.must_be_like 'SELECT FROM "posts" INNER JOIN "comments"'
end
+
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ CASE WHEN "users"."name" = 'Aaron Patterson' OR ("users"."name" IS NULL AND 'Aaron Patterson' IS NULL) THEN 0 ELSE 1 END = 0
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ CASE WHEN "users"."first_name" = "users"."last_name" OR ("users"."first_name" IS NULL AND "users"."last_name" IS NULL) THEN 0 ELSE 1 END = 0
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ CASE WHEN "users"."first_name" = "users"."last_name" OR ("users"."first_name" IS NULL AND "users"."last_name" IS NULL) THEN 0 ELSE 1 END = 1
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NOT NULL }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/visitors/mssql_test.rb b/activerecord/test/cases/arel/visitors/mssql_test.rb
index 340376c3d6..74f34b4dad 100644
--- a/activerecord/test/cases/arel/visitors/mssql_test.rb
+++ b/activerecord/test/cases/arel/visitors/mssql_test.rb
@@ -94,6 +94,45 @@ module Arel
sql = compile(stmt)
sql.must_be_like "SELECT COUNT(1) as count_id FROM (SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10) AS subquery"
end
+
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ EXISTS (VALUES ("users"."name") INTERSECT VALUES ('Aaron Patterson'))
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ EXISTS (VALUES ("users"."first_name") INTERSECT VALUES ("users"."last_name"))
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ NOT EXISTS (VALUES ("users"."first_name") INTERSECT VALUES ("users"."last_name"))
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NOT NULL }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/visitors/mysql_test.rb b/activerecord/test/cases/arel/visitors/mysql_test.rb
index 9d3bad8516..5f37587957 100644
--- a/activerecord/test/cases/arel/visitors/mysql_test.rb
+++ b/activerecord/test/cases/arel/visitors/mysql_test.rb
@@ -13,16 +13,6 @@ module Arel
@visitor.accept(node, Collectors::SQLString.new).value
end
- it "squashes parenthesis on multiple unions" do
- subnode = Nodes::Union.new Arel.sql("left"), Arel.sql("right")
- node = Nodes::Union.new subnode, Arel.sql("topright")
- assert_equal 1, compile(node).scan("(").length
-
- subnode = Nodes::Union.new Arel.sql("left"), Arel.sql("right")
- node = Nodes::Union.new Arel.sql("topleft"), subnode
- assert_equal 1, compile(node).scan("(").length
- end
-
###
# :'(
# http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214
@@ -75,6 +65,45 @@ module Arel
}
end
end
+
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ "users"."name" <=> 'Aaron Patterson'
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ "users"."first_name" <=> "users"."last_name"
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" <=> NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ NOT "users"."first_name" <=> "users"."last_name"
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ NOT "users"."name" <=> NULL }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/visitors/oracle12_test.rb b/activerecord/test/cases/arel/visitors/oracle12_test.rb
index 83a2ee36ca..4ce5cab4db 100644
--- a/activerecord/test/cases/arel/visitors/oracle12_test.rb
+++ b/activerecord/test/cases/arel/visitors/oracle12_test.rb
@@ -56,6 +56,45 @@ module Arel
}
end
end
+
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ DECODE("users"."name", 'Aaron Patterson', 0, 1) = 0
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ DECODE("users"."first_name", "users"."last_name", 0, 1) = 0
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ DECODE("users"."first_name", "users"."last_name", 0, 1) = 1
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NOT NULL }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/visitors/oracle_test.rb b/activerecord/test/cases/arel/visitors/oracle_test.rb
index e1dfe40cf9..893edc7f74 100644
--- a/activerecord/test/cases/arel/visitors/oracle_test.rb
+++ b/activerecord/test/cases/arel/visitors/oracle_test.rb
@@ -192,6 +192,45 @@ module Arel
}
end
end
+
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ DECODE("users"."name", 'Aaron Patterson', 0, 1) = 0
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ DECODE("users"."first_name", "users"."last_name", 0, 1) = 0
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ DECODE("users"."first_name", "users"."last_name", 0, 1) = 1
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NOT NULL }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/visitors/postgres_test.rb b/activerecord/test/cases/arel/visitors/postgres_test.rb
index f7f2c76b6f..0f9efb20b4 100644
--- a/activerecord/test/cases/arel/visitors/postgres_test.rb
+++ b/activerecord/test/cases/arel/visitors/postgres_test.rb
@@ -276,6 +276,45 @@ module Arel
}
end
end
+
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ "users"."name" IS NOT DISTINCT FROM 'Aaron Patterson'
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ "users"."first_name" IS NOT DISTINCT FROM "users"."last_name"
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NOT DISTINCT FROM NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ "users"."first_name" IS DISTINCT FROM "users"."last_name"
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS DISTINCT FROM NULL }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/visitors/sqlite_test.rb b/activerecord/test/cases/arel/visitors/sqlite_test.rb
index 6650b6ff3a..ee4e07a675 100644
--- a/activerecord/test/cases/arel/visitors/sqlite_test.rb
+++ b/activerecord/test/cases/arel/visitors/sqlite_test.rb
@@ -6,7 +6,11 @@ module Arel
module Visitors
class SqliteTest < Arel::Spec
before do
- @visitor = SQLite.new Table.engine.connection_pool
+ @visitor = SQLite.new Table.engine.connection
+ end
+
+ def compile(node)
+ @visitor.accept(node, Collectors::SQLString.new).value
end
it "defaults limit to -1" do
@@ -27,6 +31,45 @@ module Arel
node = Nodes::False.new()
assert_equal "0", @visitor.accept(node, Collectors::SQLString.new).value
end
+
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ "users"."name" IS 'Aaron Patterson'
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ "users"."first_name" IS "users"."last_name"
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ "users"."first_name" IS NOT "users"."last_name"
+ }
+ end
+
+ it "should handle nil" do
+ @table = Table.new(:users)
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NOT NULL }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/arel/visitors/to_sql_test.rb b/activerecord/test/cases/arel/visitors/to_sql_test.rb
index b6426a211e..4bfa799a96 100644
--- a/activerecord/test/cases/arel/visitors/to_sql_test.rb
+++ b/activerecord/test/cases/arel/visitors/to_sql_test.rb
@@ -155,6 +155,43 @@ module Arel
end
end
+ describe "Nodes::IsNotDistinctFrom" do
+ it "should construct a valid generic SQL statement" do
+ test = Table.new(:users)[:name].is_not_distinct_from "Aaron Patterson"
+ compile(test).must_be_like %{
+ CASE WHEN "users"."name" = 'Aaron Patterson' OR ("users"."name" IS NULL AND 'Aaron Patterson' IS NULL) THEN 0 ELSE 1 END = 0
+ }
+ end
+
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_not_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ CASE WHEN "users"."first_name" = "users"."last_name" OR ("users"."first_name" IS NULL AND "users"."last_name" IS NULL) THEN 0 ELSE 1 END = 0
+ }
+ end
+
+ it "should handle nil" do
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsNotDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NULL }
+ end
+ end
+
+ describe "Nodes::IsDistinctFrom" do
+ it "should handle column names on both sides" do
+ test = Table.new(:users)[:first_name].is_distinct_from Table.new(:users)[:last_name]
+ compile(test).must_be_like %{
+ CASE WHEN "users"."first_name" = "users"."last_name" OR ("users"."first_name" IS NULL AND "users"."last_name" IS NULL) THEN 0 ELSE 1 END = 1
+ }
+ end
+
+ it "should handle nil" do
+ val = Nodes.build_quoted(nil, @table[:active])
+ sql = compile Nodes::IsDistinctFrom.new(@table[:name], val)
+ sql.must_be_like %{ "users"."name" IS NOT NULL }
+ end
+ end
+
it "should visit string subclass" do
[
Class.new(String).new(":'("),
@@ -480,6 +517,28 @@ module Arel
end
end
+ describe "Nodes::Union" do
+ it "squashes parenthesis on multiple unions" do
+ subnode = Nodes::Union.new Arel.sql("left"), Arel.sql("right")
+ node = Nodes::Union.new subnode, Arel.sql("topright")
+ assert_equal("( left UNION right UNION topright )", compile(node))
+ subnode = Nodes::Union.new Arel.sql("left"), Arel.sql("right")
+ node = Nodes::Union.new Arel.sql("topleft"), subnode
+ assert_equal("( topleft UNION left UNION right )", compile(node))
+ end
+ end
+
+ describe "Nodes::UnionAll" do
+ it "squashes parenthesis on multiple union alls" do
+ subnode = Nodes::UnionAll.new Arel.sql("left"), Arel.sql("right")
+ node = Nodes::UnionAll.new subnode, Arel.sql("topright")
+ assert_equal("( left UNION ALL right UNION ALL topright )", compile(node))
+ subnode = Nodes::UnionAll.new Arel.sql("left"), Arel.sql("right")
+ node = Nodes::UnionAll.new Arel.sql("topleft"), subnode
+ assert_equal("( topleft UNION ALL left UNION ALL right )", compile(node))
+ end
+ end
+
describe "Nodes::NotIn" do
it "should know how to visit" do
node = @attr.not_in [1, 2, 3]
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 93dd427951..d1e4ebe86b 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -32,9 +32,12 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
:posts, :tags, :taggings, :comments, :sponsors, :members
def test_belongs_to
- firm = Client.find(3).firm
- assert_not_nil firm
- assert_equal companies(:first_firm).name, firm.name
+ client = Client.find(3)
+ first_firm = companies(:first_firm)
+ assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) do
+ assert_equal first_firm, client.firm
+ assert_equal first_firm.name, client.firm.name
+ end
end
def test_assigning_belongs_to_on_destroyed_object
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 39034746c9..b37e59038e 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -34,7 +34,7 @@ class EagerLoadingTooManyIdsTest < ActiveRecord::TestCase
fixtures :citations
def test_preloading_too_many_ids
- assert_equal Citation.count, Citation.preload(:citations).to_a.size
+ assert_equal Citation.count, Citation.preload(:reference_of).to_a.size
end
def test_eager_loading_too_may_ids
@@ -1618,32 +1618,6 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
end
- # Associations::Preloader#preloaders_on works with hash-like objects
- test "preloading works with an object that responds to :to_hash" do
- CustomHash = Class.new(Hash)
-
- assert_nothing_raised do
- Post.preload(CustomHash.new(comments: [{ author: :essays }])).first
- end
- end
-
- # Associations::Preloader#preloaders_on works with string-like objects
- test "preloading works with an object that responds to :to_str" do
- CustomString = Class.new(String)
-
- assert_nothing_raised do
- Post.preload(CustomString.new("comments")).first
- end
- end
-
- # Associations::Preloader#preloaders_on does not work with ranges
- test "preloading fails when Range is passed" do
- exception = assert_raises(ArgumentError) do
- Post.preload(1..10).first
- end
- assert_equal("1..10 was not recognized for preload", exception.message)
- end
-
private
def find_all_ordered(klass, include = nil)
klass.order("#{klass.table_name}.#{klass.primary_key}").includes(include).to_a
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index d13e1a86e9..6024a9e354 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -2002,8 +2002,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_has_many_through_respects_hash_conditions
- assert_equal authors(:david).hello_posts, authors(:david).hello_posts_with_hash_conditions
- assert_equal authors(:david).hello_post_comments, authors(:david).hello_post_comments_with_hash_conditions
+ assert_equal authors(:david).hello_posts.sort_by(&:id), authors(:david).hello_posts_with_hash_conditions.sort_by(&:id)
+ assert_equal authors(:david).hello_post_comments.sort_by(&:id), authors(:david).hello_post_comments_with_hash_conditions.sort_by(&:id)
end
def test_include_uses_array_include_after_loaded
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 7b405c74c4..cf514957ca 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -586,6 +586,16 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_not_includes posts(:welcome).reload.people.reload, people(:michael)
end
+ def test_replace_association_with_duplicates
+ post = posts(:thinking)
+ person = people(:david)
+
+ assert_difference "post.people.count", 2 do
+ post.people = [person]
+ post.people = [person, person]
+ end
+ end
+
def test_replace_order_is_preserved
posts(:welcome).people.clear
posts(:welcome).people = [people(:david), people(:michael)]
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index adfb3ce072..bf574f6637 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -22,8 +22,12 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
end
def test_has_one
- assert_equal companies(:first_firm).account, Account.find(1)
- assert_equal Account.find(1).credit_limit, companies(:first_firm).account.credit_limit
+ firm = companies(:first_firm)
+ first_account = Account.find(1)
+ assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) do
+ assert_equal first_account, firm.account
+ assert_equal first_account.credit_limit, firm.account.credit_limit
+ end
end
def test_has_one_does_not_use_order_by
diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb
index 0309663943..69b4872519 100644
--- a/activerecord/test/cases/associations/has_one_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb
@@ -35,6 +35,13 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
assert_equal clubs(:boring_club), @member.club
end
+ def test_has_one_through_executes_limited_query
+ boring_club = clubs(:boring_club)
+ assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) do
+ assert_equal boring_club, @member.general_club
+ end
+ end
+
def test_creating_association_creates_through_record
new_member = Member.create(name: "Chris")
new_member.club = Club.create(name: "LRUG")
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 0bfd46a522..12a4027a4e 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -56,6 +56,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert_equal "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]", t.attribute_for_inspect(:content)
end
+ test "attribute_for_inspect with a non-primary key id attribute" do
+ t = topics(:first).becomes(TitlePrimaryKeyTopic)
+ t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
+
+ assert_equal "1", t.attribute_for_inspect(:id)
+ end
+
test "attribute_present" do
t = Topic.new
t.title = "hello there!"
@@ -310,6 +317,12 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert_equal "New topic", topic.title
end
+ test "write_attribute raises ActiveModel::MissingAttributeError when the attribute does not exist" do
+ topic = Topic.first
+ assert_raises(ActiveModel::MissingAttributeError) { topic.update_columns(no_column_exists: "Hello!") }
+ assert_raises(ActiveModel::UnknownAttributeError) { topic.update(no_column_exists: "Hello!") }
+ end
+
test "read_attribute" do
topic = Topic.new
topic.title = "Don't change the topic"
@@ -436,7 +449,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
end
test "custom field attribute predicate" do
- object = Company.find_by_sql(<<-SQL).first
+ object = Company.find_by_sql(<<~SQL).first
SELECT c1.*, c2.type as string_value, c2.rating as int_value
FROM companies c1, companies c2
WHERE c1.firm_id = c2.id
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 09e5517449..63a73101c4 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1447,6 +1447,14 @@ class BasicsTest < ActiveRecord::TestCase
assert_not_respond_to developer, :first_name=
end
+ test "when ignored attribute is loaded, cast type should be preferred over DB type" do
+ developer = AttributedDeveloper.create
+ developer.update_column :name, "name"
+
+ loaded_developer = AttributedDeveloper.where(id: developer.id).select("*").first
+ assert_equal "Developer: name", loaded_developer.name
+ end
+
test "ignored columns not included in SELECT" do
query = Developer.all.to_sql.downcase
diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb
index 9c1f7aaef2..bd5f157ca1 100644
--- a/activerecord/test/cases/bind_parameter_test.rb
+++ b/activerecord/test/cases/bind_parameter_test.rb
@@ -36,8 +36,12 @@ if ActiveRecord::Base.connection.prepared_statements
def test_too_many_binds
bind_params_length = @connection.send(:bind_params_length)
- topics = Topic.where(id: (1 .. bind_params_length + 1).to_a)
+
+ topics = Topic.where(id: (1 .. bind_params_length).to_a << 2**63)
assert_equal Topic.count, topics.count
+
+ topics = Topic.where.not(id: (1 .. bind_params_length).to_a << 2**63)
+ assert_equal 0, topics.count
end
def test_bind_from_join_in_subquery
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 5c9ed42173..97bce90c8b 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -218,8 +218,8 @@ class CalculationsTest < ActiveRecord::TestCase
Account.select("credit_limit, firm_name").count
}
- assert_match %r{accounts}i, e.message
- assert_match "credit_limit, firm_name", e.message
+ assert_match %r{accounts}i, e.sql
+ assert_match "credit_limit, firm_name", e.sql
end
def test_apply_distinct_in_count
diff --git a/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb b/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb
index d4e8cbee81..393b577c1d 100644
--- a/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb
+++ b/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb
@@ -120,6 +120,77 @@ module ActiveRecord
ENV["RAILS_ENV"] = previous_env
end
+ def test_switching_connections_with_database_url
+ previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
+ previous_url, ENV["DATABASE_URL"] = ENV["DATABASE_URL"], "postgres://localhost/foo"
+
+ ActiveRecord::Base.connected_to(database: { writing: "postgres://localhost/bar" }) do
+ handler = ActiveRecord::Base.connection_handler
+ assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
+
+ assert_not_nil pool = handler.retrieve_connection_pool("primary")
+ assert_equal({ adapter: "postgresql", database: "bar", host: "localhost" }, pool.spec.config)
+ end
+ ensure
+ ActiveRecord::Base.establish_connection(:arunit)
+ ENV["RAILS_ENV"] = previous_env
+ ENV["DATABASE_URL"] = previous_url
+ end
+
+ def test_switching_connections_with_database_config_hash
+ previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
+ config = { adapter: "sqlite3", database: "db/readonly.sqlite3" }
+
+ ActiveRecord::Base.connected_to(database: { writing: config }) do
+ handler = ActiveRecord::Base.connection_handler
+ assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
+
+ assert_not_nil pool = handler.retrieve_connection_pool("primary")
+ assert_equal(config, pool.spec.config)
+ end
+ ensure
+ ActiveRecord::Base.establish_connection(:arunit)
+ ENV["RAILS_ENV"] = previous_env
+ end
+
+ def test_switching_connections_with_database_and_role_raises
+ error = assert_raises(ArgumentError) do
+ ActiveRecord::Base.connected_to(database: :readonly, role: :writing) { }
+ end
+ assert_equal "connected_to can only accept a `database` or a `role` argument, but not both arguments.", error.message
+ end
+
+ def test_switching_connections_without_database_and_role_raises
+ error = assert_raises(ArgumentError) do
+ ActiveRecord::Base.connected_to { }
+ end
+ assert_equal "must provide a `database` or a `role`.", error.message
+ end
+
+ def test_switching_connections_with_database_symbol
+ previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
+
+ config = {
+ "default_env" => {
+ "readonly" => { adapter: "sqlite3", database: "db/readonly.sqlite3" },
+ "primary" => { adapter: "sqlite3", database: "db/primary.sqlite3" }
+ }
+ }
+ @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
+
+ ActiveRecord::Base.connected_to(database: :readonly) do
+ handler = ActiveRecord::Base.connection_handler
+ assert_equal handler, ActiveRecord::Base.connection_handlers[:readonly]
+
+ assert_not_nil pool = handler.retrieve_connection_pool("primary")
+ assert_equal(config["default_env"]["readonly"], pool.spec.config)
+ end
+ ensure
+ ActiveRecord::Base.configurations = @prev_configs
+ ActiveRecord::Base.establish_connection(:arunit)
+ ENV["RAILS_ENV"] = previous_env
+ end
+
def test_connects_to_with_single_configuration
config = {
"development" => { "adapter" => "sqlite3", "database" => "db/primary.sqlite3" },
@@ -150,6 +221,27 @@ module ActiveRecord
ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit)
end
+
+ def test_connects_to_returns_array_of_established_connections
+ config = {
+ "development" => { "adapter" => "sqlite3", "database" => "db/primary.sqlite3" },
+ "development_readonly" => { "adapter" => "sqlite3", "database" => "db/readonly.sqlite3" }
+ }
+ @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
+
+ result = ActiveRecord::Base.connects_to database: { writing: :development, reading: :development_readonly }
+
+ assert_equal(
+ [
+ ActiveRecord::Base.connection_handlers[:writing].retrieve_connection_pool("primary"),
+ ActiveRecord::Base.connection_handlers[:reading].retrieve_connection_pool("primary")
+ ],
+ result
+ )
+ ensure
+ ActiveRecord::Base.configurations = @prev_configs
+ ActiveRecord::Base.establish_connection(:arunit)
+ end
end
def test_connection_pools
@@ -188,6 +280,43 @@ module ActiveRecord
assert_nil @rw_handler.retrieve_connection_pool("foo")
assert_nil @ro_handler.retrieve_connection_pool("foo")
end
+
+ def test_connection_handlers_are_per_thread_and_not_per_fiber
+ original_handlers = ActiveRecord::Base.connection_handlers
+
+ ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler, reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new }
+
+ reading_handler = ActiveRecord::Base.connection_handlers[:reading]
+
+ reading = ActiveRecord::Base.with_handler(:reading) do
+ Person.connection_handler
+ end
+
+ assert_not_equal reading, ActiveRecord::Base.connection_handler
+ assert_equal reading, reading_handler
+ ensure
+ ActiveRecord::Base.connection_handlers = original_handlers
+ end
+
+ def test_connection_handlers_swapping_connections_in_fiber
+ original_handlers = ActiveRecord::Base.connection_handlers
+
+ ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler, reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new }
+
+ reading_handler = ActiveRecord::Base.connection_handlers[:reading]
+
+ enum = Enumerator.new do |r|
+ r << ActiveRecord::Base.connection_handler
+ end
+
+ reading = ActiveRecord::Base.with_handler(:reading) do
+ enum.next
+ end
+
+ assert_equal reading, reading_handler
+ ensure
+ ActiveRecord::Base.connection_handlers = original_handlers
+ end
end
end
end
diff --git a/activerecord/test/cases/core_test.rb b/activerecord/test/cases/core_test.rb
index f7fbf3ee8a..36e3d543cd 100644
--- a/activerecord/test/cases/core_test.rb
+++ b/activerecord/test/cases/core_test.rb
@@ -30,6 +30,11 @@ class CoreTest < ActiveRecord::TestCase
assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.all.merge!(select: "id, title", where: "id = 1").first.inspect
end
+ def test_inspect_instance_with_non_primary_key_id_attribute
+ topic = topics(:first).becomes(TitlePrimaryKeyTopic)
+ assert_match(/id: 1/, topic.inspect)
+ end
+
def test_inspect_class_without_table
assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect
end
@@ -110,4 +115,11 @@ class CoreTest < ActiveRecord::TestCase
PP.pp(subtopic.new, StringIO.new(actual))
assert_equal "inspecting topic\n", actual
end
+
+ def test_pretty_print_with_non_primary_key_id_attribute
+ topic = topics(:first).becomes(TitlePrimaryKeyTopic)
+ actual = +""
+ PP.pp(topic, StringIO.new(actual))
+ assert_match(/id: 1/, actual)
+ end
end
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index 0f957d41cf..5d02e59ef6 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -106,6 +106,13 @@ if current_adapter?(:Mysql2Adapter)
class MysqlDefaultExpressionTest < ActiveRecord::TestCase
include SchemaDumpingHelper
+ if supports_default_expression?
+ test "schema dump includes default expression" do
+ output = dump_table_schema("defaults")
+ assert_match %r/t\.binary\s+"uuid",\s+limit: 36,\s+default: -> { "\(uuid\(\)\)" }/i, output
+ end
+ end
+
if subsecond_precision_supported?
test "schema dump datetime includes default expression" do
output = dump_table_schema("datetime_defaults")
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index b4593ccdf2..fef06e6edd 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -274,6 +274,24 @@ class EnumTest < ActiveRecord::TestCase
end
assert_match(/must be either a hash, an array of symbols, or an array of strings./, e.message)
+
+ e = assert_raises(ArgumentError) do
+ Class.new(ActiveRecord::Base) do
+ self.table_name = "books"
+ enum status: { "" => 1, "active" => 2 }
+ end
+ end
+
+ assert_match(/Enum label name must not be blank/, e.message)
+
+ e = assert_raises(ArgumentError) do
+ Class.new(ActiveRecord::Base) do
+ self.table_name = "books"
+ enum status: ["active", ""]
+ end
+ end
+
+ assert_match(/Enum label name must not be blank/, e.message)
end
test "reserved enum names" do
@@ -420,6 +438,20 @@ class EnumTest < ActiveRecord::TestCase
assert_equal ["drafted", "uploaded"], book2.status_change
end
+ test "attempting to modify enum raises error" do
+ e = assert_raises(RuntimeError) do
+ Book.statuses["bad_enum"] = 40
+ end
+
+ assert_match(/can't modify frozen/, e.message)
+
+ e = assert_raises(RuntimeError) do
+ Book.statuses.delete("published")
+ end
+
+ assert_match(/can't modify frozen/, e.message)
+ end
+
test "declare multiple enums at a time" do
klass = Class.new(ActiveRecord::Base) do
self.table_name = "books"
diff --git a/activerecord/test/cases/filter_attributes_test.rb b/activerecord/test/cases/filter_attributes_test.rb
index af5badd87d..47161a547a 100644
--- a/activerecord/test/cases/filter_attributes_test.rb
+++ b/activerecord/test/cases/filter_attributes_test.rb
@@ -4,6 +4,7 @@ require "cases/helper"
require "models/admin"
require "models/admin/user"
require "models/admin/account"
+require "models/user"
require "pp"
class FilterAttributesTest < ActiveRecord::TestCase
@@ -30,6 +31,32 @@ class FilterAttributesTest < ActiveRecord::TestCase
end
end
+ test "string filter_attributes perform pertial match" do
+ ActiveRecord::Base.filter_attributes = ["n"]
+ Admin::Account.all.each do |account|
+ assert_includes account.inspect, "name: [FILTERED]"
+ assert_equal 1, account.inspect.scan("[FILTERED]").length
+ end
+ end
+
+ test "regex filter_attributes are accepted" do
+ ActiveRecord::Base.filter_attributes = [/\An\z/]
+ account = Admin::Account.find_by(name: "37signals")
+ assert_includes account.inspect, 'name: "37signals"'
+ assert_equal 0, account.inspect.scan("[FILTERED]").length
+
+ ActiveRecord::Base.filter_attributes = [/\An/]
+ account = Admin::Account.find_by(name: "37signals")
+ assert_includes account.reload.inspect, "name: [FILTERED]"
+ assert_equal 1, account.inspect.scan("[FILTERED]").length
+ end
+
+ test "proc filter_attributes are accepted" do
+ ActiveRecord::Base.filter_attributes = [ lambda { |key, value| value.reverse! if key == "name" } ]
+ account = Admin::Account.find_by(name: "37signals")
+ assert_includes account.inspect, 'name: "slangis73"'
+ end
+
test "filter_attributes could be overwritten by models" do
Admin::Account.all.each do |account|
assert_includes account.inspect, "name: [FILTERED]"
@@ -37,7 +64,6 @@ class FilterAttributesTest < ActiveRecord::TestCase
end
begin
- previous_account_filter_attributes = Admin::Account.filter_attributes
Admin::Account.filter_attributes = []
# Above changes should not impact other models
@@ -51,7 +77,7 @@ class FilterAttributesTest < ActiveRecord::TestCase
assert_equal 0, account.inspect.scan("[FILTERED]").length
end
ensure
- Admin::Account.filter_attributes = previous_account_filter_attributes
+ Admin::Account.remove_instance_variable(:@filter_attributes)
end
end
@@ -63,6 +89,18 @@ class FilterAttributesTest < ActiveRecord::TestCase
assert_equal 0, account.inspect.scan("[FILTERED]").length
end
+ test "filter_attributes should handle [FILTERED] value properly" do
+ begin
+ User.filter_attributes = ["auth"]
+ user = User.new(token: "[FILTERED]", auth_token: "[FILTERED]")
+
+ assert_includes user.inspect, "auth_token: [FILTERED]"
+ assert_includes user.inspect, 'token: "[FILTERED]"'
+ ensure
+ User.remove_instance_variable(:@filter_attributes)
+ end
+ end
+
test "filter_attributes on pretty_print" do
user = admin_users(:david)
actual = "".dup
@@ -81,4 +119,18 @@ class FilterAttributesTest < ActiveRecord::TestCase
assert_not_includes actual, "name: [FILTERED]"
assert_equal 0, actual.scan("[FILTERED]").length
end
+
+ test "filter_attributes on pretty_print should handle [FILTERED] value properly" do
+ begin
+ User.filter_attributes = ["auth"]
+ user = User.new(token: "[FILTERED]", auth_token: "[FILTERED]")
+ actual = "".dup
+ PP.pp(user, StringIO.new(actual))
+
+ assert_includes actual, "auth_token: [FILTERED]"
+ assert_includes actual, 'token: "[FILTERED]"'
+ ensure
+ User.remove_instance_variable(:@filter_attributes)
+ end
+ end
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 355fb4517f..21e84d850b 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -20,6 +20,7 @@ require "models/matey"
require "models/dog"
require "models/car"
require "models/tyre"
+require "models/subscriber"
class FinderTest < ActiveRecord::TestCase
fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :author_addresses, :customers, :categories, :categorizations, :cars
@@ -167,6 +168,7 @@ class FinderTest < ActiveRecord::TestCase
assert_equal true, Topic.exists?(id: [1, 9999])
assert_equal false, Topic.exists?(45)
+ assert_equal false, Topic.exists?(9999999999999999999999999999999)
assert_equal false, Topic.exists?(Topic.new.id)
assert_raise(NoMethodError) { Topic.exists?([1, 2]) }
@@ -211,17 +213,23 @@ class FinderTest < ActiveRecord::TestCase
assert_equal false, relation.exists?(false)
end
+ def test_exists_with_string
+ assert_equal false, Subscriber.exists?("foo")
+ assert_equal false, Subscriber.exists?(" ")
+
+ Subscriber.create!(id: "foo")
+ Subscriber.create!(id: " ")
+
+ assert_equal true, Subscriber.exists?("foo")
+ assert_equal true, Subscriber.exists?(" ")
+ end
+
def test_exists_passing_active_record_object_is_not_permitted
assert_raises(ArgumentError) do
Topic.exists?(Topic.new)
end
end
- def test_exists_returns_false_when_parameter_has_invalid_type
- assert_equal false, Topic.exists?("foo")
- assert_equal false, Topic.exists?(("9" * 53).to_i) # number that's bigger than int
- end
-
def test_exists_does_not_select_columns_without_alias
assert_sql(/SELECT\W+1 AS one FROM ["`]topics["`]/i) do
Topic.exists?
@@ -246,6 +254,10 @@ class FinderTest < ActiveRecord::TestCase
assert_equal true, Topic.first.replies.exists?
end
+ def test_exists_with_empty_hash_arg
+ assert_equal true, Topic.exists?({})
+ end
+
# Ensure +exists?+ runs without an error by excluding distinct value.
# See https://github.com/rails/rails/pull/26981.
def test_exists_with_order_and_distinct
@@ -729,6 +741,16 @@ class FinderTest < ActiveRecord::TestCase
assert_equal expected, clients.limit(5).first(2)
end
+ def test_implicit_order_column_is_configurable
+ old_implicit_order_column = Topic.implicit_order_column
+ Topic.implicit_order_column = "title"
+
+ assert_equal topics(:fifth), Topic.first
+ assert_equal topics(:third), Topic.last
+ ensure
+ Topic.implicit_order_column = old_implicit_order_column
+ end
+
def test_take_and_first_and_last_with_integer_should_return_an_array
assert_kind_of Array, Topic.take(5)
assert_kind_of Array, Topic.first(5)
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 82ca15b415..a5592fc86a 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -473,11 +473,11 @@ class FixturesTest < ActiveRecord::TestCase
end
def test_empty_yaml_fixture
- assert_not_nil ActiveRecord::FixtureSet.new(Account.connection, "accounts", Account, FIXTURES_ROOT + "/naked/yml/accounts")
+ assert_not_nil ActiveRecord::FixtureSet.new(nil, "accounts", Account, FIXTURES_ROOT + "/naked/yml/accounts")
end
def test_empty_yaml_fixture_with_a_comment_in_it
- assert_not_nil ActiveRecord::FixtureSet.new(Account.connection, "companies", Company, FIXTURES_ROOT + "/naked/yml/companies")
+ assert_not_nil ActiveRecord::FixtureSet.new(nil, "companies", Company, FIXTURES_ROOT + "/naked/yml/companies")
end
def test_nonexistent_fixture_file
@@ -487,14 +487,14 @@ class FixturesTest < ActiveRecord::TestCase
assert_empty Dir[nonexistent_fixture_path + "*"]
assert_raise(Errno::ENOENT) do
- ActiveRecord::FixtureSet.new(Account.connection, "companies", Company, nonexistent_fixture_path)
+ ActiveRecord::FixtureSet.new(nil, "companies", Company, nonexistent_fixture_path)
end
end
def test_dirty_dirty_yaml_file
fixture_path = FIXTURES_ROOT + "/naked/yml/courses"
error = assert_raise(ActiveRecord::Fixture::FormatError) do
- ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, fixture_path)
+ ActiveRecord::FixtureSet.new(nil, "courses", Course, fixture_path)
end
assert_equal "fixture is not a hash: #{fixture_path}.yml", error.to_s
end
@@ -502,7 +502,7 @@ class FixturesTest < ActiveRecord::TestCase
def test_yaml_file_with_one_invalid_fixture
fixture_path = FIXTURES_ROOT + "/naked/yml/courses_with_invalid_key"
error = assert_raise(ActiveRecord::Fixture::FormatError) do
- ActiveRecord::FixtureSet.new(Account.connection, "courses", Course, fixture_path)
+ ActiveRecord::FixtureSet.new(nil, "courses", Course, fixture_path)
end
assert_equal "fixture key is not a hash: #{fixture_path}.yml, keys: [\"two\"]", error.to_s
end
@@ -525,7 +525,7 @@ class FixturesTest < ActiveRecord::TestCase
def test_omap_fixtures
assert_nothing_raised do
- fixtures = ActiveRecord::FixtureSet.new(Account.connection, "categories", Category, FIXTURES_ROOT + "/categories_ordered")
+ fixtures = ActiveRecord::FixtureSet.new(nil, "categories", Category, FIXTURES_ROOT + "/categories_ordered")
fixtures.each.with_index do |(name, fixture), i|
assert_equal "fixture_no_#{i}", name
@@ -596,7 +596,7 @@ class HasManyThroughFixture < ActiveRecord::TestCase
parrots = File.join FIXTURES_ROOT, "parrots"
- fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots
+ fs = ActiveRecord::FixtureSet.new(nil, "parrots", parrot, parrots)
rows = fs.table_rows
assert_equal load_has_and_belongs_to_many["parrots_treasures"], rows["parrots_treasures"]
end
@@ -614,18 +614,22 @@ class HasManyThroughFixture < ActiveRecord::TestCase
parrots = File.join FIXTURES_ROOT, "parrots"
- fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots
+ fs = ActiveRecord::FixtureSet.new(nil, "parrots", parrot, parrots)
rows = fs.table_rows
assert_equal load_has_and_belongs_to_many["parrots_treasures"], rows["parrot_treasures"]
end
+ def test_has_and_belongs_to_many_order
+ assert_equal ["parrots", "parrots_treasures"], load_has_and_belongs_to_many.keys
+ end
+
def load_has_and_belongs_to_many
parrot = make_model "Parrot"
parrot.has_and_belongs_to_many :treasures
parrots = File.join FIXTURES_ROOT, "parrots"
- fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots
+ fs = ActiveRecord::FixtureSet.new(nil, "parrots", parrot, parrots)
fs.table_rows
end
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 68be685e4b..730cd663a2 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -48,6 +48,15 @@ def mysql_enforcing_gtid_consistency?
current_adapter?(:Mysql2Adapter) && "ON" == ActiveRecord::Base.connection.show_variable("enforce_gtid_consistency")
end
+def supports_default_expression?
+ if current_adapter?(:PostgreSQLAdapter)
+ true
+ elsif current_adapter?(:Mysql2Adapter)
+ conn = ActiveRecord::Base.connection
+ !conn.mariadb? && conn.version >= "8.0.13"
+ end
+end
+
def supports_savepoints?
ActiveRecord::Base.connection.supports_savepoints?
end
diff --git a/activerecord/test/cases/hot_compatibility_test.rb b/activerecord/test/cases/hot_compatibility_test.rb
index e7778af55b..7b388ebc5e 100644
--- a/activerecord/test/cases/hot_compatibility_test.rb
+++ b/activerecord/test/cases/hot_compatibility_test.rb
@@ -56,7 +56,7 @@ class HotCompatibilityTest < ActiveRecord::TestCase
assert_equal "bar", record.foo
end
- if current_adapter?(:PostgreSQLAdapter)
+ if current_adapter?(:PostgreSQLAdapter) && ActiveRecord::Base.connection.prepared_statements
test "cleans up after prepared statement failure in a transaction" do
with_two_connections do |original_connection, ddl_connection|
record = @klass.create! bar: "bar"
diff --git a/activerecord/test/cases/instrumentation_test.rb b/activerecord/test/cases/instrumentation_test.rb
index e6e8468757..c09ea32991 100644
--- a/activerecord/test/cases/instrumentation_test.rb
+++ b/activerecord/test/cases/instrumentation_test.rb
@@ -5,6 +5,10 @@ require "models/book"
module ActiveRecord
class InstrumentationTest < ActiveRecord::TestCase
+ def setup
+ ActiveRecord::Base.connection.schema_cache.add(Book.table_name)
+ end
+
def test_payload_name_on_load
Book.create(name: "test book")
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 5d060c8899..661163b4a1 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -127,6 +127,36 @@ class MigrationTest < ActiveRecord::TestCase
assert_equal 20131219224947, migrator.current_version
end
+ def test_create_table_raises_if_already_exists
+ connection = Person.connection
+ connection.create_table :testings, force: true do |t|
+ t.string :foo
+ end
+
+ assert_raise(ActiveRecord::StatementInvalid) do
+ connection.create_table :testings do |t|
+ t.string :foo
+ end
+ end
+ ensure
+ connection.drop_table :testings, if_exists: true
+ end
+
+ def test_create_table_with_if_not_exists_true
+ connection = Person.connection
+ connection.create_table :testings, force: true do |t|
+ t.string :foo
+ end
+
+ assert_nothing_raised do
+ connection.create_table :testings, if_not_exists: true do |t|
+ t.string :foo
+ end
+ end
+ ensure
+ connection.drop_table :testings, if_exists: true
+ end
+
def test_create_table_with_force_true_does_not_drop_nonexisting_table
# using a copy as we need the drop_table method to
# continue to work for the ensure block of the test
diff --git a/activerecord/test/cases/numeric_data_test.rb b/activerecord/test/cases/numeric_data_test.rb
index 14db63890e..079e664ee4 100644
--- a/activerecord/test/cases/numeric_data_test.rb
+++ b/activerecord/test/cases/numeric_data_test.rb
@@ -24,8 +24,10 @@ class NumericDataTest < ActiveRecord::TestCase
)
assert m.save
- m1 = NumericData.find(m.id)
- assert_not_nil m1
+ m1 = NumericData.find_by(
+ bank_balance: 1586.43,
+ big_bank_balance: BigDecimal("1000234000567.95")
+ )
assert_kind_of Integer, m1.world_population
assert_equal 2**62, m1.world_population
@@ -49,8 +51,10 @@ class NumericDataTest < ActiveRecord::TestCase
)
assert m.save
- m1 = NumericData.find(m.id)
- assert_not_nil m1
+ m1 = NumericData.find_by(
+ bank_balance: 1586.43122334,
+ big_bank_balance: BigDecimal("234000567.952344")
+ )
assert_kind_of Integer, m1.world_population
assert_equal 2**62, m1.world_population
@@ -64,4 +68,26 @@ class NumericDataTest < ActiveRecord::TestCase
assert_kind_of BigDecimal, m1.big_bank_balance
assert_equal BigDecimal("234000567.95"), m1.big_bank_balance
end
+
+ if current_adapter?(:PostgreSQLAdapter)
+ def test_numeric_fields_with_nan
+ m = NumericData.new(
+ bank_balance: BigDecimal("NaN"),
+ big_bank_balance: BigDecimal("NaN"),
+ world_population: 2**62,
+ my_house_population: 3
+ )
+ assert_predicate m.bank_balance, :nan?
+ assert_predicate m.big_bank_balance, :nan?
+ assert m.save
+
+ m1 = NumericData.find_by(
+ bank_balance: BigDecimal("NaN"),
+ big_bank_balance: BigDecimal("NaN")
+ )
+
+ assert_predicate m1.bank_balance, :nan?
+ assert_predicate m1.big_bank_balance, :nan?
+ end
+ end
end
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 4ed7469039..4759d3b6b2 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -354,7 +354,6 @@ class CompositePrimaryKeyTest < ActiveRecord::TestCase
end
def test_composite_primary_key_out_of_order
- skip if current_adapter?(:SQLite3Adapter)
assert_equal ["code", "region"], @connection.primary_keys("barcodes_reverse")
end
@@ -376,7 +375,6 @@ class CompositePrimaryKeyTest < ActiveRecord::TestCase
end
def test_dumping_composite_primary_key_out_of_order
- skip if current_adapter?(:SQLite3Adapter)
schema = dump_table_schema "barcodes_reverse"
assert_match %r{create_table "barcodes_reverse", primary_key: \["code", "region"\]}, schema
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 565190c476..02ead8d914 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -55,6 +55,22 @@ class QueryCacheTest < ActiveRecord::TestCase
assert_cache :off
end
+ def test_query_cache_is_applied_to_connections_in_all_handlers
+ ActiveRecord::Base.connected_to(role: :reading) do
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["arunit"])
+ end
+
+ mw = middleware { |env|
+ ro_conn = ActiveRecord::Base.connection_handlers[:reading].connection_pool_list.first.connection
+ assert_predicate ActiveRecord::Base.connection, :query_cache_enabled
+ assert_predicate ro_conn, :query_cache_enabled
+ }
+
+ mw.call({})
+ ensure
+ ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler }
+ end
+
def test_query_cache_across_threads
with_temporary_connection_pool do
begin
diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb
index 8703d238a0..0b06cec40b 100644
--- a/activerecord/test/cases/relation/where_clause_test.rb
+++ b/activerecord/test/cases/relation/where_clause_test.rb
@@ -92,12 +92,16 @@ class ActiveRecord::Relation
original = WhereClause.new([
table["id"].in([1, 2, 3]),
table["id"].eq(1),
+ table["id"].is_not_distinct_from(1),
+ table["id"].is_distinct_from(2),
"sql literal",
random_object
])
expected = WhereClause.new([
table["id"].not_in([1, 2, 3]),
table["id"].not_eq(1),
+ table["id"].is_distinct_from(1),
+ table["id"].is_not_distinct_from(2),
Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new("sql literal")),
Arel::Nodes::Not.new(random_object)
])
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index db13f20a39..dda3efa47c 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -229,11 +229,14 @@ class SchemaDumperTest < ActiveRecord::TestCase
if ActiveRecord::Base.connection.supports_expression_index?
def test_schema_dump_expression_indices
index_definition = dump_table_schema("companies").split(/\n/).grep(/t\.index.*company_expression_index/).first.strip
+ index_definition.sub!(/, name: "company_expression_index"\z/, "")
if current_adapter?(:PostgreSQLAdapter)
- assert_match %r{CASE.+lower\(\(name\)::text\)}i, index_definition
+ assert_match %r{CASE.+lower\(\(name\)::text\).+END\) DESC"\z}i, index_definition
+ elsif current_adapter?(:Mysql2Adapter)
+ assert_match %r{CASE.+lower\(`name`\).+END\) DESC"\z}i, index_definition
elsif current_adapter?(:SQLite3Adapter)
- assert_match %r{CASE.+lower\(name\)}i, index_definition
+ assert_match %r{CASE.+lower\(name\).+END\) DESC"\z}i, index_definition
else
assert false
end
diff --git a/activerecord/test/cases/statement_invalid_test.rb b/activerecord/test/cases/statement_invalid_test.rb
new file mode 100644
index 0000000000..16ea69c1bd
--- /dev/null
+++ b/activerecord/test/cases/statement_invalid_test.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "models/book"
+
+module ActiveRecord
+ class StatementInvalidTest < ActiveRecord::TestCase
+ fixtures :books
+
+ class MockDatabaseError < StandardError
+ def result
+ 0
+ end
+
+ def error_number
+ 0
+ end
+ end
+
+ test "message contains no sql" do
+ sql = Book.where(author_id: 96, cover: "hard").to_sql
+ error = assert_raises(ActiveRecord::StatementInvalid) do
+ Book.connection.send(:log, sql, Book.name) do
+ raise MockDatabaseError
+ end
+ end
+ assert_not error.message.include?("SELECT")
+ end
+
+ test "statement and binds are set on select" do
+ sql = Book.where(author_id: 96, cover: "hard").to_sql
+ binds = [Minitest::Mock.new, Minitest::Mock.new]
+ error = assert_raises(ActiveRecord::StatementInvalid) do
+ Book.connection.send(:log, sql, Book.name, binds) do
+ raise MockDatabaseError
+ end
+ end
+ assert_equal error.sql, sql
+ assert_equal error.binds, binds
+ end
+ end
+end
diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb
index 4d6dff68f9..552e623fd4 100644
--- a/activerecord/test/cases/tasks/mysql_rake_test.rb
+++ b/activerecord/test/cases/tasks/mysql_rake_test.rb
@@ -272,7 +272,7 @@ if current_adapter?(:Mysql2Adapter)
def test_db_retrieves_collation
ActiveRecord::Base.stub(:connection, @connection) do
- assert_called_with(@connection, :collation) do
+ assert_called(@connection, :collation) do
ActiveRecord::Tasks::DatabaseTasks.collation @configuration
end
end
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index c0be45eee7..aa6b7915a2 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -591,6 +591,17 @@ class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase
assert_equal [:before_commit, :after_commit], @topic.history
end
+ def test_commit_run_transactions_callbacks_with_nested_transactions
+ @topic.transaction do
+ @topic.transaction(requires_new: true) do
+ @topic.content = "foo"
+ @topic.save!
+ @topic.class.connection.add_transaction_record(@topic)
+ end
+ end
+ assert_equal [:before_commit, :after_commit], @topic.history
+ end
+
def test_rollback_does_not_run_transactions_callbacks_without_enrollment
@topic.transaction do
@topic.content = "foo"
diff --git a/activerecord/test/cases/view_test.rb b/activerecord/test/cases/view_test.rb
index 7e2d66c62a..36b9df7ba5 100644
--- a/activerecord/test/cases/view_test.rb
+++ b/activerecord/test/cases/view_test.rb
@@ -20,7 +20,7 @@ module ViewBehavior
def setup
super
@connection = ActiveRecord::Base.connection
- create_view "ebooks'", <<-SQL
+ create_view "ebooks'", <<~SQL
SELECT id, name, status FROM books WHERE format = 'ebook'
SQL
end
@@ -106,7 +106,7 @@ if ActiveRecord::Base.connection.supports_views?
setup do
@connection = ActiveRecord::Base.connection
- @connection.execute <<-SQL
+ @connection.execute <<~SQL
CREATE VIEW paperbacks
AS SELECT name, status FROM books WHERE format = 'paperback'
SQL
@@ -156,8 +156,7 @@ if ActiveRecord::Base.connection.supports_views?
end
# sqlite dose not support CREATE, INSERT, and DELETE for VIEW
- if current_adapter?(:Mysql2Adapter, :SQLServerAdapter) ||
- current_adapter?(:PostgreSQLAdapter) && ActiveRecord::Base.connection.postgresql_version >= 90300
+ if current_adapter?(:Mysql2Adapter, :SQLServerAdapter, :PostgreSQLAdapter)
class UpdateableViewTest < ActiveRecord::TestCase
self.use_transactional_tests = false
@@ -169,7 +168,7 @@ if ActiveRecord::Base.connection.supports_views?
setup do
@connection = ActiveRecord::Base.connection
- @connection.execute <<-SQL
+ @connection.execute <<~SQL
CREATE VIEW printed_books
AS SELECT id, name, status, format FROM books WHERE format = 'paperback'
SQL
@@ -207,8 +206,7 @@ if ActiveRecord::Base.connection.supports_views?
end # end of `if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter, :SQLServerAdapter)`
end # end of `if ActiveRecord::Base.connection.supports_views?`
-if ActiveRecord::Base.connection.respond_to?(:supports_materialized_views?) &&
- ActiveRecord::Base.connection.supports_materialized_views?
+if ActiveRecord::Base.connection.supports_materialized_views?
class MaterializedViewTest < ActiveRecord::PostgreSQLTestCase
include ViewBehavior