Lots going on
[lyrix.git] / vendor / rails / activerecord / test / migration_test.rb
blobd1e2059c9a181bed7cbfcf028d37cae5e11aea07
1 require 'abstract_unit'
2 require 'bigdecimal/util'
4 require 'fixtures/person'
5 require 'fixtures/topic'
6 require File.dirname(__FILE__) + '/fixtures/migrations/1_people_have_last_names'
7 require File.dirname(__FILE__) + '/fixtures/migrations/2_we_need_reminders'
8 require File.dirname(__FILE__) + '/fixtures/migrations_with_decimal/1_give_me_big_numbers'
10 if ActiveRecord::Base.connection.supports_migrations?
11   class BigNumber < ActiveRecord::Base; end
13   class Reminder < ActiveRecord::Base; end
15   class ActiveRecord::Migration
16     class <<self
17       attr_accessor :message_count
18       def puts(text="")
19         self.message_count ||= 0
20         self.message_count += 1
21       end
22     end
23   end
25   class MigrationTest < Test::Unit::TestCase
26     self.use_transactional_fixtures = false
28     def setup
29       ActiveRecord::Migration.verbose = true
30       PeopleHaveLastNames.message_count = 0
31     end
33     def teardown
34       ActiveRecord::Base.connection.initialize_schema_information
35       ActiveRecord::Base.connection.update "UPDATE #{ActiveRecord::Migrator.schema_info_table_name} SET version = 0"
37       %w(reminders people_reminders prefix_reminders_suffix).each do |table|
38         Reminder.connection.drop_table(table) rescue nil
39       end
40       Reminder.reset_column_information
42       %w(last_name key bio age height wealth birthday favorite_day
43          moment_of_truth male administrator).each do |column|
44         Person.connection.remove_column('people', column) rescue nil
45       end
46       Person.connection.remove_column("people", "first_name") rescue nil
47       Person.connection.remove_column("people", "middle_name") rescue nil
48       Person.connection.add_column("people", "first_name", :string, :limit => 40)
49       Person.reset_column_information
50     end
52     def test_add_index
53       # Limit size of last_name and key columns to support Firebird index limitations
54       Person.connection.add_column "people", "last_name", :string, :limit => 100
55       Person.connection.add_column "people", "key", :string, :limit => 100
56       Person.connection.add_column "people", "administrator", :boolean
58       assert_nothing_raised { Person.connection.add_index("people", "last_name") }
59       assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
61       # Orcl nds shrt indx nms.  Sybs 2.
62       unless current_adapter?(:OracleAdapter, :SybaseAdapter)
63         assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
64         assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
65         assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
66         assert_nothing_raised { Person.connection.remove_index("people", :name => "index_people_on_last_name_and_first_name") }
67         assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
68         assert_nothing_raised { Person.connection.remove_index("people", "last_name_and_first_name") }
69         assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
70         assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
71       end
73       # quoting
74       # Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
75       assert_nothing_raised { Person.connection.add_index("people", ["key"], :name => "key_idx", :unique => true) }
76       assert_nothing_raised { Person.connection.remove_index("people", :name => "key_idx", :unique => true) }
78       # Sybase adapter does not support indexes on :boolean columns
79       unless current_adapter?(:SybaseAdapter)
80         assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
81         assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
82       end
83     end
85     def test_create_table_adds_id
86       Person.connection.create_table :testings do |t|
87         t.column :foo, :string
88       end
90       assert_equal %w(foo id),
91         Person.connection.columns(:testings).map { |c| c.name }.sort
92     ensure
93       Person.connection.drop_table :testings rescue nil
94     end
96     def test_create_table_with_not_null_column
97       assert_nothing_raised do
98         Person.connection.create_table :testings do |t|
99           t.column :foo, :string, :null => false
100         end
101       end
103       assert_raises(ActiveRecord::StatementInvalid) do
104         Person.connection.execute "insert into testings (foo) values (NULL)"
105       end
106     ensure
107       Person.connection.drop_table :testings rescue nil
108     end
110     def test_create_table_with_defaults
111       # MySQL doesn't allow defaults on TEXT or BLOB columns.
112       mysql = current_adapter?(:MysqlAdapter)
114       Person.connection.create_table :testings do |t|
115         t.column :one, :string, :default => "hello"
116         t.column :two, :boolean, :default => true
117         t.column :three, :boolean, :default => false
118         t.column :four, :integer, :default => 1
119         t.column :five, :text, :default => "hello" unless mysql
120       end
122       columns = Person.connection.columns(:testings)
123       one = columns.detect { |c| c.name == "one" }
124       two = columns.detect { |c| c.name == "two" }
125       three = columns.detect { |c| c.name == "three" }
126       four = columns.detect { |c| c.name == "four" }
127       five = columns.detect { |c| c.name == "five" } unless mysql
129       assert_equal "hello", one.default
130       assert_equal true, two.default
131       assert_equal false, three.default
132       assert_equal 1, four.default
133       assert_equal "hello", five.default unless mysql
135     ensure
136       Person.connection.drop_table :testings rescue nil
137     end
139     def test_create_table_with_limits
140       assert_nothing_raised do
141         Person.connection.create_table :testings do |t|
142           t.column :foo, :string, :limit => 255
144           t.column :default_int, :integer
146           t.column :one_int,   :integer, :limit => 1
147           t.column :four_int,  :integer, :limit => 4
148           t.column :eight_int, :integer, :limit => 8
149         end
150       end
152       columns = Person.connection.columns(:testings)
153       foo = columns.detect { |c| c.name == "foo" }
154       assert_equal 255, foo.limit
156       default = columns.detect { |c| c.name == "default_int" }
157       one     = columns.detect { |c| c.name == "one_int"     }
158       four    = columns.detect { |c| c.name == "four_int"    }
159       eight   = columns.detect { |c| c.name == "eight_int"   }
161       if current_adapter?(:PostgreSQLAdapter)
162         assert_equal 'integer', default.sql_type
163         assert_equal 'smallint', one.sql_type
164         assert_equal 'integer', four.sql_type
165         assert_equal 'bigint', eight.sql_type
166       elsif current_adapter?(:OracleAdapter)
167         assert_equal 'NUMBER(38)', default.sql_type
168         assert_equal 'NUMBER(1)', one.sql_type
169         assert_equal 'NUMBER(4)', four.sql_type
170         assert_equal 'NUMBER(8)', eight.sql_type
171       end
172     ensure
173       Person.connection.drop_table :testings rescue nil
174     end
176     # SQL Server, Sybase, and SQLite3 will not allow you to add a NOT NULL
177     # column to a table without a default value.
178     unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter)
179       def test_add_column_not_null_without_default
180         Person.connection.create_table :testings do |t|
181           t.column :foo, :string
182         end
183         Person.connection.add_column :testings, :bar, :string, :null => false
185         assert_raises(ActiveRecord::StatementInvalid) do
186           Person.connection.execute "insert into testings (foo, bar) values ('hello', NULL)"
187         end
188       ensure
189         Person.connection.drop_table :testings rescue nil
190       end
191     end
193     def test_add_column_not_null_with_default
194       Person.connection.create_table :testings do |t|
195         t.column :foo, :string
196       end
197       
198       con = Person.connection     
199       Person.connection.enable_identity_insert("testings", true) if current_adapter?(:SybaseAdapter)
200       Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')"
201       Person.connection.enable_identity_insert("testings", false) if current_adapter?(:SybaseAdapter)
202       assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
204       assert_raises(ActiveRecord::StatementInvalid) do
205         Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) values (2, 'hello', NULL)"
206       end
207     ensure
208       Person.connection.drop_table :testings rescue nil
209     end
211     # We specifically do a manual INSERT here, and then test only the SELECT
212     # functionality. This allows us to more easily catch INSERT being broken,
213     # but SELECT actually working fine.
214     def test_native_decimal_insert_manual_vs_automatic
215       correct_value = '0012345678901234567890.0123456789'.to_d
217       Person.delete_all
218       Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
219       Person.reset_column_information
221       # Do a manual insertion
222       if current_adapter?(:OracleAdapter)
223         Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
224       else
225         Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)"
226       end
228       # SELECT
229       row = Person.find(:first)
230       assert_kind_of BigDecimal, row.wealth
232       # If this assert fails, that means the SELECT is broken!
233       unless current_adapter?(:SQLite3Adapter)
234         assert_equal correct_value, row.wealth
235       end
237       # Reset to old state
238       Person.delete_all
240       # Now use the Rails insertion
241       assert_nothing_raised { Person.create :wealth => BigDecimal.new("12345678901234567890.0123456789") }
243       # SELECT
244       row = Person.find(:first)
245       assert_kind_of BigDecimal, row.wealth
247       # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
248       unless current_adapter?(:SQLite3Adapter)
249         assert_equal correct_value, row.wealth
250       end
252       # Reset to old state
253       Person.connection.del_column "people", "wealth" rescue nil
254       Person.reset_column_information
255     end
257     def test_native_types
258       Person.delete_all
259       Person.connection.add_column "people", "last_name", :string
260       Person.connection.add_column "people", "bio", :text
261       Person.connection.add_column "people", "age", :integer
262       Person.connection.add_column "people", "height", :float
263       Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
264       Person.connection.add_column "people", "birthday", :datetime
265       Person.connection.add_column "people", "favorite_day", :date
266       Person.connection.add_column "people", "moment_of_truth", :datetime
267       Person.connection.add_column "people", "male", :boolean
269       assert_nothing_raised do
270         Person.create :first_name => 'bob', :last_name => 'bobsen',
271           :bio => "I was born ....", :age => 18, :height => 1.78,
272           :wealth => BigDecimal.new("12345678901234567890.0123456789"),
273           :birthday => 18.years.ago, :favorite_day => 10.days.ago,
274           :moment_of_truth => "1582-10-10 21:40:18", :male => true
275       end
277       bob = Person.find(:first)
278       assert_equal 'bob', bob.first_name
279       assert_equal 'bobsen', bob.last_name
280       assert_equal "I was born ....", bob.bio
281       assert_equal 18, bob.age
283       # Test for 30 significent digits (beyond the 16 of float), 10 of them
284       # after the decimal place.
285      
286       unless current_adapter?(:SQLite3Adapter)
287         assert_equal BigDecimal.new("0012345678901234567890.0123456789"), bob.wealth
288       end
289       
290       assert_equal true, bob.male?
292       assert_equal String, bob.first_name.class
293       assert_equal String, bob.last_name.class
294       assert_equal String, bob.bio.class
295       assert_equal Fixnum, bob.age.class
296       assert_equal Time, bob.birthday.class
298       if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
299         # Sybase, and Oracle don't differentiate between date/time
300         assert_equal Time, bob.favorite_day.class
301       else
302         assert_equal Date, bob.favorite_day.class
303       end
305       # Test DateTime column and defaults, including timezone.
306       # FIXME: moment of truth may be Time on 64-bit platforms.
307       if bob.moment_of_truth.is_a?(DateTime)
308         assert_equal DateTime.now.offset, bob.moment_of_truth.offset
309         assert_not_equal 0, bob.moment_of_truth.offset
310         assert_not_equal "Z", bob.moment_of_truth.zone
311       end
313       assert_equal TrueClass, bob.male?.class
314       assert_kind_of BigDecimal, bob.wealth
315     end
317     if current_adapter?(:MysqlAdapter)
318       def test_unabstracted_database_dependent_types
319         Person.delete_all
321         ActiveRecord::Migration.add_column :people, :intelligence_quotient, :tinyint
322         Person.create :intelligence_quotient => 300
323         jonnyg = Person.find(:first) 
324         assert_equal 127, jonnyg.intelligence_quotient
325         jonnyg.destroy
326       ensure
327         ActiveRecord::Migration.remove_column :people, :intelligece_quotient rescue nil
328       end
329     end
331     def test_add_remove_single_field_using_string_arguments
332       assert !Person.column_methods_hash.include?(:last_name)
334       ActiveRecord::Migration.add_column 'people', 'last_name', :string
336       Person.reset_column_information
337       assert Person.column_methods_hash.include?(:last_name)
339       ActiveRecord::Migration.remove_column 'people', 'last_name'
341       Person.reset_column_information
342       assert !Person.column_methods_hash.include?(:last_name)
343     end
345     def test_add_remove_single_field_using_symbol_arguments
346       assert !Person.column_methods_hash.include?(:last_name)
348       ActiveRecord::Migration.add_column :people, :last_name, :string
350       Person.reset_column_information
351       assert Person.column_methods_hash.include?(:last_name)
353       ActiveRecord::Migration.remove_column :people, :last_name
355       Person.reset_column_information
356       assert !Person.column_methods_hash.include?(:last_name)
357     end
359     def test_add_rename
360       Person.delete_all
362       begin
363         Person.connection.add_column "people", "girlfriend", :string
364         Person.create :girlfriend => 'bobette'
366         Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
368         Person.reset_column_information
369         bob = Person.find(:first)
371         assert_equal "bobette", bob.exgirlfriend
372       ensure
373         Person.connection.remove_column("people", "girlfriend") rescue nil
374         Person.connection.remove_column("people", "exgirlfriend") rescue nil
375       end
377     end
379     def test_rename_column_using_symbol_arguments
380       begin
381         Person.connection.rename_column :people, :first_name, :nick_name
382         Person.reset_column_information
383         assert Person.column_names.include?("nick_name")
384       ensure
385         Person.connection.remove_column("people","nick_name")
386         Person.connection.add_column("people","first_name", :string)
387       end
388     end
390     def test_rename_column
391       begin
392         Person.connection.rename_column "people", "first_name", "nick_name"
393         Person.reset_column_information
394         assert Person.column_names.include?("nick_name")
395       ensure
396         Person.connection.remove_column("people","nick_name")
397         Person.connection.add_column("people","first_name", :string)
398       end
399     end
401     def test_rename_column_with_sql_reserved_word
402       begin
403         assert_nothing_raised { Person.connection.rename_column "people", "first_name", "group" }
404         Person.reset_column_information
405         assert Person.column_names.include?("group")
406       ensure
407         Person.connection.remove_column("people", "group") rescue nil
408         Person.connection.add_column("people", "first_name", :string) rescue nil
409       end
410     end
412     def test_rename_table
413       begin
414         ActiveRecord::Base.connection.create_table :octopuses do |t|
415           t.column :url, :string
416         end
417         ActiveRecord::Base.connection.rename_table :octopuses, :octopi
419         # Using explicit id in insert for compatibility across all databases
420         con = ActiveRecord::Base.connection     
421         con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
422         assert_nothing_raised { con.execute "INSERT INTO octopi (#{con.quote_column_name('id')}, #{con.quote_column_name('url')}) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')" }
423         con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
425         assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
427       ensure
428         ActiveRecord::Base.connection.drop_table :octopuses rescue nil
429         ActiveRecord::Base.connection.drop_table :octopi rescue nil
430       end
431     end
433     def test_rename_table_with_an_index
434       begin
435         ActiveRecord::Base.connection.create_table :octopuses do |t|
436           t.column :url, :string
437         end
438         ActiveRecord::Base.connection.add_index :octopuses, :url
439         
440         ActiveRecord::Base.connection.rename_table :octopuses, :octopi
442         # Using explicit id in insert for compatibility across all databases
443         con = ActiveRecord::Base.connection     
444         con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
445         assert_nothing_raised { con.execute "INSERT INTO octopi (#{con.quote_column_name('id')}, #{con.quote_column_name('url')}) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')" }
446         con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
448         assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
449         assert ActiveRecord::Base.connection.indexes(:octopi).first.columns.include?("url")
450       ensure
451         ActiveRecord::Base.connection.drop_table :octopuses rescue nil
452         ActiveRecord::Base.connection.drop_table :octopi rescue nil
453       end
454     end
456     def test_change_column
457       Person.connection.add_column 'people', 'age', :integer
458       old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
459       assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
461       assert_nothing_raised { Person.connection.change_column "people", "age", :string }
463       new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
464       assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
465       assert new_columns.find { |c| c.name == 'age' and c.type == :string }
467       old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
468       assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
469       assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
470       new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")     
471       assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
472       assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
473       assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
474     end
475     
476     def test_change_column_with_nil_default
477       Person.connection.add_column "people", "contributor", :boolean, :default => true
478       Person.reset_column_information
479       assert Person.new.contributor?
480       
481       assert_nothing_raised { Person.connection.change_column "people", "contributor", :boolean, :default => nil }
482       Person.reset_column_information
483       assert !Person.new.contributor?
484       assert_nil Person.new.contributor
485     ensure
486       Person.connection.remove_column("people", "contributor") rescue nil
487     end
489     def test_change_column_with_new_default
490       Person.connection.add_column "people", "administrator", :boolean, :default => true
491       Person.reset_column_information
492       assert Person.new.administrator?
494       assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
495       Person.reset_column_information
496       assert !Person.new.administrator?
497     ensure
498       Person.connection.remove_column("people", "administrator") rescue nil
499     end
500     
501     def test_change_column_default
502       Person.connection.change_column_default "people", "first_name", "Tester"
503       Person.reset_column_information
504       assert_equal "Tester", Person.new.first_name
505     end
506     
507     def test_change_column_default_to_null
508       Person.connection.change_column_default "people", "first_name", nil
509       Person.reset_column_information
510       assert_nil Person.new.first_name
511     end
513     def test_add_table
514       assert !Reminder.table_exists?
516       WeNeedReminders.up
518       assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
519       assert_equal "hello world", Reminder.find(:first).content
521       WeNeedReminders.down
522       assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
523     end
525     def test_add_table_with_decimals
526       Person.connection.drop_table :big_numbers rescue nil
528       assert !BigNumber.table_exists?
529       GiveMeBigNumbers.up
531       assert BigNumber.create(
532         :bank_balance => 1586.43,
533         :big_bank_balance => BigDecimal("1000234000567.95"),
534         :world_population => 6000000000,
535         :my_house_population => 3,
536         :value_of_e => BigDecimal("2.7182818284590452353602875")
537       )
539       b = BigNumber.find(:first)
540       assert_not_nil b
542       assert_not_nil b.bank_balance
543       assert_not_nil b.big_bank_balance
544       assert_not_nil b.world_population
545       assert_not_nil b.my_house_population
546       assert_not_nil b.value_of_e
548       # TODO: set world_population >= 2**62 to cover 64-bit platforms and test
549       # is_a?(Bignum)
550       assert_kind_of Integer, b.world_population
551       assert_equal 6000000000, b.world_population
552       assert_kind_of Fixnum, b.my_house_population
553       assert_equal 3, b.my_house_population
554       assert_kind_of BigDecimal, b.bank_balance
555       assert_equal BigDecimal("1586.43"), b.bank_balance
556       assert_kind_of BigDecimal, b.big_bank_balance
557       assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
559       # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with
560       # precision/scale explictly left out.  By the SQL standard, numbers
561       # assigned to this field should be truncated but that's seldom respected.
562       if current_adapter?(:PostgreSQLAdapter, :SQLite2Adapter)
563         # - PostgreSQL changes the SQL spec on columns declared simply as
564         # "decimal" to something more useful: instead of being given a scale
565         # of 0, they take on the compile-time limit for precision and scale,
566         # so the following should succeed unless you have used really wacky
567         # compilation options
568         # - SQLite2 has the default behavior of preserving all data sent in,
569         # so this happens there too
570         assert_kind_of BigDecimal, b.value_of_e
571         assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
572       elsif current_adapter?(:SQLiteAdapter)
573         # - SQLite3 stores a float, in violation of SQL
574         assert_kind_of BigDecimal, b.value_of_e
575         assert_equal BigDecimal("2.71828182845905"), b.value_of_e
576       elsif current_adapter?(:SQLServer)
577         # - SQL Server rounds instead of truncating
578         assert_kind_of Fixnum, b.value_of_e
579         assert_equal 3, b.value_of_e
580       else
581         # - SQL standard is an integer
582         assert_kind_of Fixnum, b.value_of_e
583         assert_equal 2, b.value_of_e
584       end
586       GiveMeBigNumbers.down
587       assert_raises(ActiveRecord::StatementInvalid) { BigNumber.find(:first) }
588     end
590     def test_migrator
591       assert !Person.column_methods_hash.include?(:last_name)
592       assert !Reminder.table_exists?
594       ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')
596       assert_equal 3, ActiveRecord::Migrator.current_version
597       Person.reset_column_information
598       assert Person.column_methods_hash.include?(:last_name)
599       assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
600       assert_equal "hello world", Reminder.find(:first).content
602       ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/')
604       assert_equal 0, ActiveRecord::Migrator.current_version
605       Person.reset_column_information
606       assert !Person.column_methods_hash.include?(:last_name)
607       assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
608     end
610     def test_migrator_one_up
611       assert !Person.column_methods_hash.include?(:last_name)
612       assert !Reminder.table_exists?
614       ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
616       Person.reset_column_information
617       assert Person.column_methods_hash.include?(:last_name)
618       assert !Reminder.table_exists?
620       ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 2)
622       assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
623       assert_equal "hello world", Reminder.find(:first).content
624     end
626     def test_migrator_one_down
627       ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')
629       ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
631       Person.reset_column_information
632       assert Person.column_methods_hash.include?(:last_name)
633       assert !Reminder.table_exists?
634     end
636     def test_migrator_one_up_one_down
637       ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
638       ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
640       assert !Person.column_methods_hash.include?(:last_name)
641       assert !Reminder.table_exists?
642     end
644     def test_migrator_verbosity
645       ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
646       assert PeopleHaveLastNames.message_count > 0
647       PeopleHaveLastNames.message_count = 0
649       ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
650       assert PeopleHaveLastNames.message_count > 0
651       PeopleHaveLastNames.message_count = 0
652     end
654     def test_migrator_verbosity_off
655       PeopleHaveLastNames.verbose = false
656       ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
657       assert PeopleHaveLastNames.message_count.zero?
658       ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
659       assert PeopleHaveLastNames.message_count.zero?
660     end
662     def test_migrator_going_down_due_to_version_target
663       ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
664       ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
666       assert !Person.column_methods_hash.include?(:last_name)
667       assert !Reminder.table_exists?
669       ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations/')
671       Person.reset_column_information
672       assert Person.column_methods_hash.include?(:last_name)
673       assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
674       assert_equal "hello world", Reminder.find(:first).content
675     end
677     def test_schema_info_table_name
678       ActiveRecord::Base.table_name_prefix = "prefix_"
679       ActiveRecord::Base.table_name_suffix = "_suffix"
680       Reminder.reset_table_name
681       assert_equal "prefix_schema_info_suffix", ActiveRecord::Migrator.schema_info_table_name
682       ActiveRecord::Base.table_name_prefix = ""
683       ActiveRecord::Base.table_name_suffix = ""
684       Reminder.reset_table_name
685       assert_equal "schema_info", ActiveRecord::Migrator.schema_info_table_name
686     ensure
687       ActiveRecord::Base.table_name_prefix = ""
688       ActiveRecord::Base.table_name_suffix = ""
689     end
691     def test_proper_table_name
692       assert_equal "table", ActiveRecord::Migrator.proper_table_name('table')
693       assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table)
694       assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder)
695       Reminder.reset_table_name
696       assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder)
698       # Use the model's own prefix/suffix if a model is given
699       ActiveRecord::Base.table_name_prefix = "ARprefix_"
700       ActiveRecord::Base.table_name_suffix = "_ARsuffix"
701       Reminder.table_name_prefix = 'prefix_'
702       Reminder.table_name_suffix = '_suffix'
703       Reminder.reset_table_name
704       assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder)
705       Reminder.table_name_prefix = ''
706       Reminder.table_name_suffix = ''
707       Reminder.reset_table_name
709       # Use AR::Base's prefix/suffix if string or symbol is given
710       ActiveRecord::Base.table_name_prefix = "prefix_"
711       ActiveRecord::Base.table_name_suffix = "_suffix"
712       Reminder.reset_table_name
713       assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table')
714       assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table)
715       ActiveRecord::Base.table_name_prefix = ""
716       ActiveRecord::Base.table_name_suffix = ""
717       Reminder.reset_table_name
718     end
720     def test_add_drop_table_with_prefix_and_suffix
721       assert !Reminder.table_exists?
722       ActiveRecord::Base.table_name_prefix = 'prefix_'
723       ActiveRecord::Base.table_name_suffix = '_suffix'
724       Reminder.reset_table_name
725       Reminder.reset_sequence_name
726       WeNeedReminders.up
727       assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
728       assert_equal "hello world", Reminder.find(:first).content
730       WeNeedReminders.down
731       assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
732     ensure
733       ActiveRecord::Base.table_name_prefix = ''
734       ActiveRecord::Base.table_name_suffix = ''
735       Reminder.reset_table_name
736       Reminder.reset_sequence_name
737     end
739     def test_create_table_with_binary_column
740       Person.connection.drop_table :binary_testings rescue nil
742       assert_nothing_raised {
743         Person.connection.create_table :binary_testings do |t|
744           t.column "data", :binary, :null => false
745         end
746       }
748       columns = Person.connection.columns(:binary_testings)
749       data_column = columns.detect { |c| c.name == "data" }
751       assert_nil data_column.default
753       Person.connection.drop_table :binary_testings rescue nil
754     end
756     def test_migrator_with_duplicates
757       assert_raises(ActiveRecord::DuplicateMigrationVersionError) do
758         ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_duplicate/', nil)
759       end
760     end
762     def test_migrator_with_missing_version_numbers
763       ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_missing_versions/', 500)
764       assert !Person.column_methods_hash.include?(:middle_name)
765         assert_equal 4, ActiveRecord::Migrator.current_version
766                         
767                         ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_missing_versions/', 2)
768                         assert !Reminder.table_exists?
769       assert Person.column_methods_hash.include?(:last_name)                    
770                         assert_equal 2, ActiveRecord::Migrator.current_version
771     end
772     
773     def test_create_table_with_custom_sequence_name
774       return unless current_adapter? :OracleAdapter
776       # table name is 29 chars, the standard sequence name will
777       # be 33 chars and fail
778       assert_raises(ActiveRecord::StatementInvalid) do
779         begin
780           Person.connection.create_table :table_with_name_thats_just_ok do |t|
781             t.column :foo, :string, :null => false
782           end
783         ensure
784           Person.connection.drop_table :table_with_name_thats_just_ok rescue nil
785         end
786       end
788       # should be all good w/ a custom sequence name
789       assert_nothing_raised do
790         begin
791           Person.connection.create_table :table_with_name_thats_just_ok,
792                                          :sequence_name => 'suitably_short_seq' do |t|
793             t.column :foo, :string, :null => false
794           end
796           Person.connection.execute("select suitably_short_seq.nextval from dual")
798         ensure
799           Person.connection.drop_table :table_with_name_thats_just_ok,
800                                        :sequence_name => 'suitably_short_seq' rescue nil
801         end
802       end
804       # confirm the custom sequence got dropped
805       assert_raises(ActiveRecord::StatementInvalid) do
806         Person.connection.execute("select suitably_short_seq.nextval from dual")
807       end
808     end
810   end