diff options
Diffstat (limited to 'activerecord/test/migration_test.rb')
-rw-r--r-- | activerecord/test/migration_test.rb | 153 |
1 files changed, 135 insertions, 18 deletions
diff --git a/activerecord/test/migration_test.rb b/activerecord/test/migration_test.rb index 9514eb369d..337d4c8861 100644 --- a/activerecord/test/migration_test.rb +++ b/activerecord/test/migration_test.rb @@ -1,10 +1,15 @@ require 'abstract_unit' +require 'bigdecimal/util' + require 'fixtures/person' require 'fixtures/topic' require File.dirname(__FILE__) + '/fixtures/migrations/1_people_have_last_names' require File.dirname(__FILE__) + '/fixtures/migrations/2_we_need_reminders' +require File.dirname(__FILE__) + '/fixtures/migrations_with_decimal/1_give_me_big_numbers' if ActiveRecord::Base.connection.supports_migrations? + class BigNumber < ActiveRecord::Base; end + class Reminder < ActiveRecord::Base; end class ActiveRecord::Migration @@ -29,20 +34,15 @@ if ActiveRecord::Base.connection.supports_migrations? ActiveRecord::Base.connection.initialize_schema_information ActiveRecord::Base.connection.update "UPDATE #{ActiveRecord::Migrator.schema_info_table_name} SET version = 0" - Reminder.connection.drop_table("reminders") rescue nil - Reminder.connection.drop_table("people_reminders") rescue nil - Reminder.connection.drop_table("prefix_reminders_suffix") rescue nil + %w(reminders people_reminders prefix_reminders_suffix).each do |table| + Reminder.connection.drop_table(table) rescue nil + end Reminder.reset_column_information - Person.connection.remove_column("people", "last_name") rescue nil - Person.connection.remove_column("people", "key") rescue nil - Person.connection.remove_column("people", "bio") rescue nil - Person.connection.remove_column("people", "age") rescue nil - Person.connection.remove_column("people", "height") rescue nil - Person.connection.remove_column("people", "birthday") rescue nil - Person.connection.remove_column("people", "favorite_day") rescue nil - Person.connection.remove_column("people", "male") rescue nil - Person.connection.remove_column("people", "administrator") rescue nil + %w(last_name key bio age height wealth birthday favorite_day + mail administrator).each do |column| + Person.connection.remove_column('people', column) rescue nil + end Person.connection.remove_column("people", "first_name") rescue nil Person.connection.add_column("people", "first_name", :string, :limit => 40) Person.reset_column_information @@ -187,23 +187,74 @@ if ActiveRecord::Base.connection.supports_migrations? Person.connection.drop_table :testings rescue nil end + # We specifically do a manual INSERT here, and then test only the SELECT + # functionality. This allows us to more easily catch INSERT being broken, + # but SELECT actually working fine. + def test_native_decimal_insert_manual_vs_automatic + # SQLite3 always uses float in violation of SQL + # 16 decimal places + correct_value = (current_adapter?(:SQLiteAdapter) ? '0.123456789012346E20' : '0012345678901234567890.0123456789').to_d + + Person.delete_all + Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10' + Person.reset_column_information + + # Do a manual insertion + Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)" + + # SELECT + row = Person.find(:first) + assert_kind_of BigDecimal, row.wealth + + # If this assert fails, that means the SELECT is broken! + assert_equal correct_value, row.wealth + + # Reset to old state + Person.delete_all + + # Now use the Rails insertion + assert_nothing_raised { Person.create :wealth => BigDecimal.new("12345678901234567890.0123456789") } + + # SELECT + row = Person.find(:first) + assert_kind_of BigDecimal, row.wealth + + # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken! + assert_equal correct_value, row.wealth + + # Reset to old state + Person.connection.del_column "people", "wealth" rescue nil + Person.reset_column_information + end + def test_native_types Person.delete_all Person.connection.add_column "people", "last_name", :string Person.connection.add_column "people", "bio", :text Person.connection.add_column "people", "age", :integer Person.connection.add_column "people", "height", :float + Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10' Person.connection.add_column "people", "birthday", :datetime Person.connection.add_column "people", "favorite_day", :date Person.connection.add_column "people", "male", :boolean - assert_nothing_raised { Person.create :first_name => 'bob', :last_name => 'bobsen', :bio => "I was born ....", :age => 18, :height => 1.78, :birthday => 18.years.ago, :favorite_day => 10.days.ago, :male => true } + assert_nothing_raised { Person.create :first_name => 'bob', :last_name => 'bobsen', :bio => "I was born ....", :age => 18, :height => 1.78, :wealth => BigDecimal.new("12345678901234567890.0123456789"), :birthday => 18.years.ago, :favorite_day => 10.days.ago, :male => true } bob = Person.find(:first) - assert_equal bob.first_name, 'bob' - assert_equal bob.last_name, 'bobsen' - assert_equal bob.bio, "I was born ...." - assert_equal bob.age, 18 - assert_equal bob.male?, true + assert_equal 'bob', bob.first_name + assert_equal 'bobsen', bob.last_name + assert_equal "I was born ....", bob.bio + assert_equal 18, bob.age + + # Test for 30 significent digits (beyond the 16 of float), 10 of them + # after the decimal place. + if current_adapter?(:SQLiteAdapter) + # SQLite3 uses float in violation of SQL. Test for 16 decimal places. + assert_equal BigDecimal.new('0.123456789012346E20'), bob.wealth + else + assert_equal BigDecimal.new("0012345678901234567890.0123456789"), bob.wealth + end + + assert_equal true, bob.male? assert_equal String, bob.first_name.class assert_equal String, bob.last_name.class @@ -219,6 +270,7 @@ if ActiveRecord::Base.connection.supports_migrations? end assert_equal TrueClass, bob.male?.class + assert_kind_of BigDecimal, bob.wealth end def test_add_remove_single_field_using_string_arguments @@ -351,6 +403,71 @@ if ActiveRecord::Base.connection.supports_migrations? assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) } end + def test_add_table_with_decimals + Person.connection.drop_table :big_numbers rescue nil + + assert !BigNumber.table_exists? + GiveMeBigNumbers.up + + assert BigNumber.create( + :bank_balance => 1586.43, + :big_bank_balance => BigDecimal("1000234000567.95"), + :world_population => 6000000000, + :my_house_population => 3, + :value_of_e => BigDecimal("2.7182818284590452353602875") + ) + + b = BigNumber.find(:first) + assert_not_nil b + + assert_not_nil b.bank_balance + assert_not_nil b.big_bank_balance + assert_not_nil b.world_population + assert_not_nil b.my_house_population + assert_not_nil b.value_of_e + + # TODO: set world_population >= 2**62 to cover 64-bit platforms and test + # is_a?(Bignum) + assert_kind_of Integer, b.world_population + assert_equal 6000000000, b.world_population + assert_kind_of Fixnum, b.my_house_population + assert_equal 3, b.my_house_population + assert_kind_of BigDecimal, b.bank_balance + assert_equal BigDecimal("1586.43"), b.bank_balance + assert_kind_of BigDecimal, b.big_bank_balance + assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance + + # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with + # precision/scale explictly left out. By the SQL standard, numbers + # assigned to this field should be truncated but that's seldom respected. + if current_adapter?(:PostgreSQLAdapter, :SQLite2Adapter) + # - PostgreSQL changes the SQL spec on columns declared simply as + # "decimal" to something more useful: instead of being given a scale + # of 0, they take on the compile-time limit for precision and scale, + # so the following should succeed unless you have used really wacky + # compilation options + # - SQLite2 has the default behavior of preserving all data sent in, + # so this happens there too + assert_kind_of BigDecimal, b.value_of_e + assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e + elsif current_adapter?(:SQLiteAdapter) + # - SQLite3 stores a float, in violation of SQL + assert_kind_of BigDecimal, b.value_of_e + assert_equal BigDecimal("2.71828182845905"), b.value_of_e + elsif current_adapter?(:SQLServer) + # - SQL Server rounds instead of truncating + assert_kind_of Fixnum, b.value_of_e + assert_equal 3, b.value_of_e + else + # - SQL standard is an integer + assert_kind_of Fixnum, b.value_of_e + assert_equal 2, b.value_of_e + end + + GiveMeBigNumbers.down + assert_raises(ActiveRecord::StatementInvalid) { BigNumber.find(:first) } + end + def test_migrator assert !Person.column_methods_hash.include?(:last_name) assert !Reminder.table_exists? |