2 require 'bigdecimal/util'
4 require 'models/person'
6 require 'models/developer'
8 require MIGRATIONS_ROOT
+ "/valid/1_people_have_last_names"
9 require MIGRATIONS_ROOT
+ "/valid/2_we_need_reminders"
10 require MIGRATIONS_ROOT
+ "/decimal/1_give_me_big_numbers"
11 require MIGRATIONS_ROOT
+ "/interleaved/pass_3/2_i_raise_on_down"
13 if ActiveRecord
::Base.connection
.supports_migrations
?
14 class BigNumber
< ActiveRecord
::Base; end
16 class Reminder
< ActiveRecord
::Base; end
18 class ActiveRecord
::Migration
20 attr_accessor :message_count
22 self.message_count
||= 0
23 self.message_count
+= 1
28 class MigrationTest
< ActiveRecord
::TestCase
29 self.use_transactional_fixtures
= false
34 ActiveRecord
::Migration.verbose
= true
35 PeopleHaveLastNames
.message_count
= 0
39 ActiveRecord
::Base.connection
.initialize_schema_migrations_table
40 ActiveRecord
::Base.connection
.execute
"DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}"
42 %w(reminders people_reminders prefix_reminders_suffix
).each
do |table
|
43 Reminder
.connection
.drop_table(table
) rescue nil
45 Reminder
.reset_column_information
47 %w(last_name key bio age height wealth birthday favorite_day
48 moment_of_truth male administrator funny
).each
do |column
|
49 Person
.connection
.remove_column('people', column
) rescue nil
51 Person
.connection
.remove_column("people", "first_name") rescue nil
52 Person
.connection
.remove_column("people", "middle_name") rescue nil
53 Person
.connection
.add_column("people", "first_name", :string, :limit => 40)
54 Person
.reset_column_information
58 # Limit size of last_name and key columns to support Firebird index limitations
59 Person
.connection
.add_column
"people", "last_name", :string, :limit => 100
60 Person
.connection
.add_column
"people", "key", :string, :limit => 100
61 Person
.connection
.add_column
"people", "administrator", :boolean
63 assert_nothing_raised
{ Person
.connection
.add_index("people", "last_name") }
64 assert_nothing_raised
{ Person
.connection
.remove_index("people", "last_name") }
66 # Orcl nds shrt indx nms. Sybs 2.
67 # OpenBase does not have named indexes. You must specify a single column name
68 unless current_adapter
?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter)
69 assert_nothing_raised
{ Person
.connection
.add_index("people", ["last_name", "first_name"]) }
70 assert_nothing_raised
{ Person
.connection
.remove_index("people", :column => ["last_name", "first_name"]) }
71 assert_nothing_raised
{ Person
.connection
.add_index("people", ["last_name", "first_name"]) }
72 assert_nothing_raised
{ Person
.connection
.remove_index("people", :name => "index_people_on_last_name_and_first_name") }
73 assert_nothing_raised
{ Person
.connection
.add_index("people", ["last_name", "first_name"]) }
74 assert_nothing_raised
{ Person
.connection
.remove_index("people", "last_name_and_first_name") }
75 assert_nothing_raised
{ Person
.connection
.add_index("people", ["last_name", "first_name"]) }
76 assert_nothing_raised
{ Person
.connection
.remove_index("people", ["last_name", "first_name"]) }
80 # Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
81 # OpenBase does not have named indexes. You must specify a single column name
82 unless current_adapter
?(:OpenBaseAdapter)
83 Person
.update_all
"#{Person.connection.quote_column_name 'key'}=#{Person.connection.quote_column_name 'id'}" #some databases (including sqlite2 won't add a unique index if existing data non unique)
84 assert_nothing_raised
{ Person
.connection
.add_index("people", ["key"], :name => "key_idx", :unique => true) }
85 assert_nothing_raised
{ Person
.connection
.remove_index("people", :name => "key_idx", :unique => true) }
88 # Sybase adapter does not support indexes on :boolean columns
89 # OpenBase does not have named indexes. You must specify a single column
90 unless current_adapter
?(:SybaseAdapter, :OpenBaseAdapter)
91 assert_nothing_raised
{ Person
.connection
.add_index("people", %w(last_name first_name administrator
), :name => "named_admin") }
92 assert_nothing_raised
{ Person
.connection
.remove_index("people", :name => "named_admin") }
96 def test_create_table_adds_id
97 Person
.connection
.create_table
:testings do |t
|
98 t
.column
:foo, :string
101 assert_equal
%w(foo id
),
102 Person
.connection
.columns(:testings).map
{ |c
| c
.name
}.sort
104 Person
.connection
.drop_table
:testings rescue nil
107 def test_create_table_with_not_null_column
108 assert_nothing_raised
do
109 Person
.connection
.create_table
:testings do |t
|
110 t
.column
:foo, :string, :null => false
114 assert_raises(ActiveRecord
::StatementInvalid) do
115 Person
.connection
.execute
"insert into testings (foo) values (NULL)"
118 Person
.connection
.drop_table
:testings rescue nil
121 def test_create_table_with_defaults
122 # MySQL doesn't allow defaults on TEXT or BLOB columns.
123 mysql
= current_adapter
?(:MysqlAdapter)
125 Person
.connection
.create_table
:testings do |t
|
126 t
.column
:one, :string, :default => "hello"
127 t
.column
:two, :boolean, :default => true
128 t
.column
:three, :boolean, :default => false
129 t
.column
:four, :integer, :default => 1
130 t
.column
:five, :text, :default => "hello" unless mysql
133 columns
= Person
.connection
.columns(:testings)
134 one
= columns
.detect
{ |c
| c
.name
== "one" }
135 two
= columns
.detect
{ |c
| c
.name
== "two" }
136 three
= columns
.detect
{ |c
| c
.name
== "three" }
137 four
= columns
.detect
{ |c
| c
.name
== "four" }
138 five
= columns
.detect
{ |c
| c
.name
== "five" } unless mysql
140 assert_equal
"hello", one
.default
141 assert_equal
true, two
.default
142 assert_equal
false, three
.default
143 assert_equal
1, four
.default
144 assert_equal
"hello", five
.default
unless mysql
147 Person
.connection
.drop_table
:testings rescue nil
150 def test_create_table_with_limits
151 assert_nothing_raised
do
152 Person
.connection
.create_table
:testings do |t
|
153 t
.column
:foo, :string, :limit => 255
155 t
.column
:default_int, :integer
157 t
.column
:one_int, :integer, :limit => 1
158 t
.column
:four_int, :integer, :limit => 4
159 t
.column
:eight_int, :integer, :limit => 8
160 t
.column
:eleven_int, :integer, :limit => 11
164 columns
= Person
.connection
.columns(:testings)
165 foo
= columns
.detect
{ |c
| c
.name
== "foo" }
166 assert_equal
255, foo
.limit
168 default
= columns
.detect
{ |c
| c
.name
== "default_int" }
169 one
= columns
.detect
{ |c
| c
.name
== "one_int" }
170 four
= columns
.detect
{ |c
| c
.name
== "four_int" }
171 eight
= columns
.detect
{ |c
| c
.name
== "eight_int" }
172 eleven
= columns
.detect
{ |c
| c
.name
== "eleven_int" }
174 if current_adapter
?(:PostgreSQLAdapter)
175 assert_equal
'integer', default
.sql_type
176 assert_equal
'smallint', one
.sql_type
177 assert_equal
'integer', four
.sql_type
178 assert_equal
'bigint', eight
.sql_type
179 assert_equal
'integer', eleven
.sql_type
180 elsif current_adapter
?(:MysqlAdapter)
181 assert_match
'int(11)', default
.sql_type
182 assert_match
'tinyint', one
.sql_type
183 assert_match
'int', four
.sql_type
184 assert_match
'bigint', eight
.sql_type
185 assert_match
'int(11)', eleven
.sql_type
186 elsif current_adapter
?(:OracleAdapter)
187 assert_equal
'NUMBER(38)', default
.sql_type
188 assert_equal
'NUMBER(1)', one
.sql_type
189 assert_equal
'NUMBER(4)', four
.sql_type
190 assert_equal
'NUMBER(8)', eight
.sql_type
193 Person
.connection
.drop_table
:testings rescue nil
196 def test_create_table_with_primary_key_prefix_as_table_name_with_underscore
197 ActiveRecord
::Base.primary_key_prefix_type
= :table_name_with_underscore
199 Person
.connection
.create_table
:testings do |t
|
200 t
.column
:foo, :string
203 assert_equal
%w(foo testings_id
), Person
.connection
.columns(:testings).map
{ |c
| c
.name
}.sort
205 Person
.connection
.drop_table
:testings rescue nil
206 ActiveRecord
::Base.primary_key_prefix_type
= nil
209 def test_create_table_with_primary_key_prefix_as_table_name
210 ActiveRecord
::Base.primary_key_prefix_type
= :table_name
212 Person
.connection
.create_table
:testings do |t
|
213 t
.column
:foo, :string
216 assert_equal
%w(foo testingsid
), Person
.connection
.columns(:testings).map
{ |c
| c
.name
}.sort
218 Person
.connection
.drop_table
:testings rescue nil
219 ActiveRecord
::Base.primary_key_prefix_type
= nil
222 uses_mocha('test_create_table_with_force_true_does_not_drop_nonexisting_table') do
223 def test_create_table_with_force_true_does_not_drop_nonexisting_table
224 if Person
.connection
.table_exists
?(:testings2)
225 Person
.connection
.drop_table
:testings2
228 # using a copy as we need the drop_table method to
229 # continue to work for the ensure block of the test
230 temp_conn
= Person
.connection
.dup
231 temp_conn
.expects(:drop_table).never
232 temp_conn
.create_table
:testings2, :force => true do |t
|
233 t
.column
:foo, :string
236 Person
.connection
.drop_table
:testings2 rescue nil
240 def test_create_table_with_timestamps_should_create_datetime_columns
241 table_name
= :testings
243 Person
.connection
.create_table table_name
do |t
|
246 created_columns
= Person
.connection
.columns(table_name
)
248 created_at_column
= created_columns
.detect
{|c
| c
.name
== 'created_at' }
249 updated_at_column
= created_columns
.detect
{|c
| c
.name
== 'updated_at' }
251 assert created_at_column
.null
252 assert updated_at_column
.null
254 Person
.connection
.drop_table table_name
rescue nil
257 def test_create_table_with_timestamps_should_create_datetime_columns_with_options
258 table_name
= :testings
260 Person
.connection
.create_table table_name
do |t
|
261 t
.timestamps
:null => false
263 created_columns
= Person
.connection
.columns(table_name
)
265 created_at_column
= created_columns
.detect
{|c
| c
.name
== 'created_at' }
266 updated_at_column
= created_columns
.detect
{|c
| c
.name
== 'updated_at' }
268 assert
!created_at_column
.null
269 assert
!updated_at_column
.null
271 Person
.connection
.drop_table table_name
rescue nil
274 # Sybase, and SQLite3 will not allow you to add a NOT NULL
275 # column to a table without a default value.
276 unless current_adapter
?(:SybaseAdapter, :SQLiteAdapter)
277 def test_add_column_not_null_without_default
278 Person
.connection
.create_table
:testings do |t
|
279 t
.column
:foo, :string
281 Person
.connection
.add_column
:testings, :bar, :string, :null => false
283 assert_raises(ActiveRecord
::StatementInvalid) do
284 Person
.connection
.execute
"insert into testings (foo, bar) values ('hello', NULL)"
287 Person
.connection
.drop_table
:testings rescue nil
291 def test_add_column_not_null_with_default
292 Person
.connection
.create_table
:testings do |t
|
293 t
.column
:foo, :string
296 con
= Person
.connection
297 Person
.connection
.enable_identity_insert("testings", true) if current_adapter
?(:SybaseAdapter)
298 Person
.connection
.execute
"insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')"
299 Person
.connection
.enable_identity_insert("testings", false) if current_adapter
?(:SybaseAdapter)
300 assert_nothing_raised
{Person
.connection
.add_column
:testings, :bar, :string, :null => false, :default => "default" }
302 assert_raises(ActiveRecord
::StatementInvalid) do
303 unless current_adapter
?(:OpenBaseAdapter)
304 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)"
306 Person
.connection
.insert("INSERT INTO testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) VALUES (2, 'hello', NULL)",
307 "Testing Insert","id",2)
311 Person
.connection
.drop_table
:testings rescue nil
314 # We specifically do a manual INSERT here, and then test only the SELECT
315 # functionality. This allows us to more easily catch INSERT being broken,
316 # but SELECT actually working fine.
317 def test_native_decimal_insert_manual_vs_automatic
318 correct_value
= '0012345678901234567890.0123456789'.to_d
321 Person
.connection
.add_column
"people", "wealth", :decimal, :precision => '30', :scale => '10'
322 Person
.reset_column_information
324 # Do a manual insertion
325 if current_adapter
?(:OracleAdapter)
326 Person
.connection
.execute
"insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
327 elsif current_adapter
?(:OpenBaseAdapter) || (current_adapter
?(:MysqlAdapter) && Mysql
.client_version
< 50003) #before mysql 5.0.3 decimals stored as strings
328 Person
.connection
.execute
"insert into people (wealth) values ('12345678901234567890.0123456789')"
330 Person
.connection
.execute
"insert into people (wealth) values (12345678901234567890.0123456789)"
334 row
= Person
.find(:first)
335 assert_kind_of BigDecimal
, row
.wealth
337 # If this assert fails, that means the SELECT is broken!
338 unless current_adapter
?(:SQLite3Adapter)
339 assert_equal correct_value
, row
.wealth
345 # Now use the Rails insertion
346 assert_nothing_raised
{ Person
.create
:wealth => BigDecimal
.new("12345678901234567890.0123456789") }
349 row
= Person
.find(:first)
350 assert_kind_of BigDecimal
, row
.wealth
352 # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
353 unless current_adapter
?(:SQLite3Adapter)
354 assert_equal correct_value
, row
.wealth
358 Person
.connection
.del_column
"people", "wealth" rescue nil
359 Person
.reset_column_information
362 def test_add_column_with_precision_and_scale
363 Person
.connection
.add_column
'people', 'wealth', :decimal, :precision => 9, :scale => 7
364 Person
.reset_column_information
366 wealth_column
= Person
.columns_hash
['wealth']
367 assert_equal
9, wealth_column
.precision
368 assert_equal
7, wealth_column
.scale
371 def test_native_types
373 Person
.connection
.add_column
"people", "last_name", :string
374 Person
.connection
.add_column
"people", "bio", :text
375 Person
.connection
.add_column
"people", "age", :integer
376 Person
.connection
.add_column
"people", "height", :float
377 Person
.connection
.add_column
"people", "wealth", :decimal, :precision => '30', :scale => '10'
378 Person
.connection
.add_column
"people", "birthday", :datetime
379 Person
.connection
.add_column
"people", "favorite_day", :date
380 Person
.connection
.add_column
"people", "moment_of_truth", :datetime
381 Person
.connection
.add_column
"people", "male", :boolean
382 Person
.reset_column_information
384 assert_nothing_raised
do
385 Person
.create
:first_name => 'bob', :last_name => 'bobsen',
386 :bio => "I was born ....", :age => 18, :height => 1.78,
387 :wealth => BigDecimal
.new("12345678901234567890.0123456789"),
388 :birthday => 18.years
.ago
, :favorite_day => 10.days
.ago
,
389 :moment_of_truth => "1782-10-10 21:40:18", :male => true
392 bob
= Person
.find(:first)
393 assert_equal
'bob', bob
.first_name
394 assert_equal
'bobsen', bob
.last_name
395 assert_equal
"I was born ....", bob
.bio
396 assert_equal
18, bob
.age
398 # Test for 30 significent digits (beyond the 16 of float), 10 of them
399 # after the decimal place.
401 unless current_adapter
?(:SQLite3Adapter)
402 assert_equal BigDecimal
.new("0012345678901234567890.0123456789"), bob
.wealth
405 assert_equal
true, bob
.male
?
407 assert_equal String
, bob
.first_name
.class
408 assert_equal String
, bob
.last_name
.class
409 assert_equal String
, bob
.bio
.class
410 assert_equal Fixnum
, bob
.age
.class
411 assert_equal Time
, bob
.birthday
.class
413 if current_adapter
?(:OracleAdapter, :SybaseAdapter)
414 # Sybase, and Oracle don't differentiate between date/time
415 assert_equal Time
, bob
.favorite_day
.class
417 assert_equal Date
, bob
.favorite_day
.class
420 # Test DateTime column and defaults, including timezone.
421 # FIXME: moment of truth may be Time on 64-bit platforms.
422 if bob
.moment_of_truth
.is_a
?(DateTime
)
424 with_env_tz
'US/Eastern' do
425 assert_equal DateTime
.local_offset
, bob
.moment_of_truth
.offset
426 assert_not_equal
0, bob
.moment_of_truth
.offset
427 assert_not_equal
"Z", bob
.moment_of_truth
.zone
428 # US/Eastern is -5 hours from GMT
429 assert_equal
Rational(-5, 24), bob
.moment_of_truth
.offset
430 assert_match
/\A-05:?00\Z/, bob
.moment_of_truth
.zone
#ruby 1.8.6 uses HH:MM, prior versions use HHMM
431 assert_equal DateTime
::ITALY, bob
.moment_of_truth
.start
435 assert_equal TrueClass
, bob
.male
?.class
436 assert_kind_of BigDecimal
, bob
.wealth
439 if current_adapter
?(:MysqlAdapter)
440 def test_unabstracted_database_dependent_types
443 ActiveRecord
::Migration.add_column
:people, :intelligence_quotient, :tinyint
444 Person
.reset_column_information
445 assert_match
/tinyint/, Person
.columns_hash
['intelligence_quotient'].sql_type
447 ActiveRecord
::Migration.remove_column
:people, :intelligence_quotient rescue nil
451 def test_add_remove_single_field_using_string_arguments
452 assert
!Person
.column_methods_hash
.include?(:last_name)
454 ActiveRecord
::Migration.add_column
'people', 'last_name', :string
456 Person
.reset_column_information
457 assert Person
.column_methods_hash
.include?(:last_name)
459 ActiveRecord
::Migration.remove_column
'people', 'last_name'
461 Person
.reset_column_information
462 assert
!Person
.column_methods_hash
.include?(:last_name)
465 def test_add_remove_single_field_using_symbol_arguments
466 assert
!Person
.column_methods_hash
.include?(:last_name)
468 ActiveRecord
::Migration.add_column
:people, :last_name, :string
470 Person
.reset_column_information
471 assert Person
.column_methods_hash
.include?(:last_name)
473 ActiveRecord
::Migration.remove_column
:people, :last_name
475 Person
.reset_column_information
476 assert
!Person
.column_methods_hash
.include?(:last_name)
483 Person
.connection
.add_column
"people", "girlfriend", :string
484 Person
.reset_column_information
485 Person
.create
:girlfriend => 'bobette'
487 Person
.connection
.rename_column
"people", "girlfriend", "exgirlfriend"
489 Person
.reset_column_information
490 bob
= Person
.find(:first)
492 assert_equal
"bobette", bob
.exgirlfriend
494 Person
.connection
.remove_column("people", "girlfriend") rescue nil
495 Person
.connection
.remove_column("people", "exgirlfriend") rescue nil
500 def test_rename_column_using_symbol_arguments
502 names_before
= Person
.find(:all).map(&:first_name)
503 Person
.connection
.rename_column
:people, :first_name, :nick_name
504 Person
.reset_column_information
505 assert Person
.column_names
.include?("nick_name")
506 assert_equal names_before
, Person
.find(:all).map(&:nick_name)
508 Person
.connection
.remove_column("people","nick_name")
509 Person
.connection
.add_column("people","first_name", :string)
513 def test_rename_column
515 names_before
= Person
.find(:all).map(&:first_name)
516 Person
.connection
.rename_column
"people", "first_name", "nick_name"
517 Person
.reset_column_information
518 assert Person
.column_names
.include?("nick_name")
519 assert_equal names_before
, Person
.find(:all).map(&:nick_name)
521 Person
.connection
.remove_column("people","nick_name")
522 Person
.connection
.add_column("people","first_name", :string)
526 def test_rename_column_preserves_default_value_not_null
528 default_before
= Developer
.connection
.columns("developers").find
{ |c
| c
.name
== "salary" }.default
529 assert_equal
70000, default_before
530 Developer
.connection
.rename_column
"developers", "salary", "anual_salary"
531 Developer
.reset_column_information
532 assert Developer
.column_names
.include?("anual_salary")
533 default_after
= Developer
.connection
.columns("developers").find
{ |c
| c
.name
== "anual_salary" }.default
534 assert_equal
70000, default_after
536 Developer
.connection
.rename_column
"developers", "anual_salary", "salary"
537 Developer
.reset_column_information
541 def test_rename_nonexistent_column
542 ActiveRecord
::Base.connection
.create_table(:hats) do |table
|
543 table
.column
:hat_name, :string, :default => nil
545 exception
= if current_adapter
?(:PostgreSQLAdapter)
546 ActiveRecord
::StatementInvalid
548 ActiveRecord
::ActiveRecordError
550 assert_raises(exception
) do
551 Person
.connection
.rename_column
"hats", "nonexistent", "should_fail"
554 ActiveRecord
::Base.connection
.drop_table(:hats)
557 def test_rename_column_with_sql_reserved_word
559 assert_nothing_raised
{ Person
.connection
.rename_column
"people", "first_name", "group" }
560 Person
.reset_column_information
561 assert Person
.column_names
.include?("group")
563 Person
.connection
.remove_column("people", "group") rescue nil
564 Person
.connection
.add_column("people", "first_name", :string) rescue nil
568 def test_rename_column_with_an_index
569 ActiveRecord
::Base.connection
.create_table(:hats) do |table
|
570 table
.column
:hat_name, :string, :limit => 100
571 table
.column
:hat_size, :integer
573 Person
.connection
.add_index
:hats, :hat_name
574 assert_nothing_raised
do
575 Person
.connection
.rename_column
"hats", "hat_name", "name"
578 ActiveRecord
::Base.connection
.drop_table(:hats)
581 def test_remove_column_with_index
582 ActiveRecord
::Base.connection
.create_table(:hats) do |table
|
583 table
.column
:hat_name, :string, :limit => 100
584 table
.column
:hat_size, :integer
586 ActiveRecord
::Base.connection
.add_index
"hats", "hat_size"
588 assert_nothing_raised
{ Person
.connection
.remove_column("hats", "hat_size") }
590 ActiveRecord
::Base.connection
.drop_table(:hats)
593 def test_remove_column_with_multi_column_index
594 ActiveRecord
::Base.connection
.create_table(:hats) do |table
|
595 table
.column
:hat_name, :string, :limit => 100
596 table
.column
:hat_size, :integer
597 table
.column
:hat_style, :string, :limit => 100
599 ActiveRecord
::Base.connection
.add_index
"hats", ["hat_style", "hat_size"], :unique => true
601 assert_nothing_raised
{ Person
.connection
.remove_column("hats", "hat_size") }
603 ActiveRecord
::Base.connection
.drop_table(:hats)
606 def test_change_type_of_not_null_column
607 assert_nothing_raised
do
608 Topic
.connection
.change_column
"topics", "written_on", :datetime, :null => false
609 Topic
.reset_column_information
611 Topic
.connection
.change_column
"topics", "written_on", :datetime, :null => false
612 Topic
.reset_column_information
616 def test_rename_table
618 ActiveRecord
::Base.connection
.create_table
:octopuses do |t
|
619 t
.column
:url, :string
621 ActiveRecord
::Base.connection
.rename_table
:octopuses, :octopi
623 # Using explicit id in insert for compatibility across all databases
624 con
= ActiveRecord
::Base.connection
625 con
.enable_identity_insert("octopi", true) if current_adapter
?(:SybaseAdapter)
626 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')" }
627 con
.enable_identity_insert("octopi", false) if current_adapter
?(:SybaseAdapter)
629 assert_equal
'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord
::Base.connection
.select_value("SELECT url FROM octopi WHERE id=1")
632 ActiveRecord
::Base.connection
.drop_table
:octopuses rescue nil
633 ActiveRecord
::Base.connection
.drop_table
:octopi rescue nil
637 def test_change_column_nullability
639 Person
.connection
.add_column
"people", "funny", :boolean
640 Person
.reset_column_information
641 assert Person
.columns_hash
["funny"].null
, "Column 'funny' must initially allow nulls"
642 Person
.connection
.change_column
"people", "funny", :boolean, :null => false, :default => true
643 Person
.reset_column_information
644 assert
!Person
.columns_hash
["funny"].null
, "Column 'funny' must *not* allow nulls at this point"
645 Person
.connection
.change_column
"people", "funny", :boolean, :null => true
646 Person
.reset_column_information
647 assert Person
.columns_hash
["funny"].null
, "Column 'funny' must allow nulls again at this point"
650 def test_rename_table_with_an_index
652 ActiveRecord
::Base.connection
.create_table
:octopuses do |t
|
653 t
.column
:url, :string
655 ActiveRecord
::Base.connection
.add_index
:octopuses, :url
657 ActiveRecord
::Base.connection
.rename_table
:octopuses, :octopi
659 # Using explicit id in insert for compatibility across all databases
660 con
= ActiveRecord
::Base.connection
661 con
.enable_identity_insert("octopi", true) if current_adapter
?(:SybaseAdapter)
662 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')" }
663 con
.enable_identity_insert("octopi", false) if current_adapter
?(:SybaseAdapter)
665 assert_equal
'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord
::Base.connection
.select_value("SELECT url FROM octopi WHERE id=1")
666 assert ActiveRecord
::Base.connection
.indexes(:octopi).first
.columns
.include?("url")
668 ActiveRecord
::Base.connection
.drop_table
:octopuses rescue nil
669 ActiveRecord
::Base.connection
.drop_table
:octopi rescue nil
673 def test_change_column
674 Person
.connection
.add_column
'people', 'age', :integer
675 old_columns
= Person
.connection
.columns(Person
.table_name
, "#{name} Columns")
676 assert old_columns
.find
{ |c
| c
.name
== 'age' and c
.type
== :integer }
678 assert_nothing_raised
{ Person
.connection
.change_column
"people", "age", :string }
680 new_columns
= Person
.connection
.columns(Person
.table_name
, "#{name} Columns")
681 assert_nil new_columns
.find
{ |c
| c
.name
== 'age' and c
.type
== :integer }
682 assert new_columns
.find
{ |c
| c
.name
== 'age' and c
.type
== :string }
684 old_columns
= Topic
.connection
.columns(Topic
.table_name
, "#{name} Columns")
685 assert old_columns
.find
{ |c
| c
.name
== 'approved' and c
.type
== :boolean and c
.default
== true }
686 assert_nothing_raised
{ Topic
.connection
.change_column
:topics, :approved, :boolean, :default => false }
687 new_columns
= Topic
.connection
.columns(Topic
.table_name
, "#{name} Columns")
688 assert_nil new_columns
.find
{ |c
| c
.name
== 'approved' and c
.type
== :boolean and c
.default
== true }
689 assert new_columns
.find
{ |c
| c
.name
== 'approved' and c
.type
== :boolean and c
.default
== false }
690 assert_nothing_raised
{ Topic
.connection
.change_column
:topics, :approved, :boolean, :default => true }
693 def test_change_column_with_nil_default
694 Person
.connection
.add_column
"people", "contributor", :boolean, :default => true
695 Person
.reset_column_information
696 assert Person
.new
.contributor
?
698 assert_nothing_raised
{ Person
.connection
.change_column
"people", "contributor", :boolean, :default => nil }
699 Person
.reset_column_information
700 assert
!Person
.new
.contributor
?
701 assert_nil Person
.new
.contributor
703 Person
.connection
.remove_column("people", "contributor") rescue nil
706 def test_change_column_with_new_default
707 Person
.connection
.add_column
"people", "administrator", :boolean, :default => true
708 Person
.reset_column_information
709 assert Person
.new
.administrator
?
711 assert_nothing_raised
{ Person
.connection
.change_column
"people", "administrator", :boolean, :default => false }
712 Person
.reset_column_information
713 assert
!Person
.new
.administrator
?
715 Person
.connection
.remove_column("people", "administrator") rescue nil
718 def test_change_column_default
719 Person
.connection
.change_column_default
"people", "first_name", "Tester"
720 Person
.reset_column_information
721 assert_equal
"Tester", Person
.new
.first_name
724 def test_change_column_quotes_column_names
725 Person
.connection
.create_table
:testings do |t
|
726 t
.column
:select, :string
729 assert_nothing_raised
{ Person
.connection
.change_column
:testings, :select, :string, :limit => 10 }
731 assert_nothing_raised
{ Person
.connection
.execute
"insert into testings (#{Person.connection.quote_column_name('select')}) values ('7 chars')" }
733 Person
.connection
.drop_table
:testings rescue nil
736 def test_keeping_default_and_notnull_constaint_on_change
737 Person
.connection
.create_table
:testings do |t
|
738 t
.column
:title, :string
740 person_klass
= Class
.new(Person
)
741 person_klass
.set_table_name
'testings'
743 person_klass
.connection
.add_column
"testings", "wealth", :integer, :null => false, :default => 99
744 person_klass
.reset_column_information
745 assert_equal
99, person_klass
.columns_hash
["wealth"].default
746 assert_equal
false, person_klass
.columns_hash
["wealth"].null
747 assert_nothing_raised
{person_klass
.connection
.execute("insert into testings (title) values ('tester')")}
749 # change column default to see that column doesn't lose its not null definition
750 person_klass
.connection
.change_column_default
"testings", "wealth", 100
751 person_klass
.reset_column_information
752 assert_equal
100, person_klass
.columns_hash
["wealth"].default
753 assert_equal
false, person_klass
.columns_hash
["wealth"].null
755 # rename column to see that column doesn't lose its not null and/or default definition
756 person_klass
.connection
.rename_column
"testings", "wealth", "money"
757 person_klass
.reset_column_information
758 assert_nil person_klass
.columns_hash
["wealth"]
759 assert_equal
100, person_klass
.columns_hash
["money"].default
760 assert_equal
false, person_klass
.columns_hash
["money"].null
763 person_klass
.connection
.change_column
"testings", "money", :integer, :null => false, :default => 1000
764 person_klass
.reset_column_information
765 assert_equal
1000, person_klass
.columns_hash
["money"].default
766 assert_equal
false, person_klass
.columns_hash
["money"].null
768 # change column, make it nullable and clear default
769 person_klass
.connection
.change_column
"testings", "money", :integer, :null => true, :default => nil
770 person_klass
.reset_column_information
771 assert_nil person_klass
.columns_hash
["money"].default
772 assert_equal
true, person_klass
.columns_hash
["money"].null
774 # change_column_null, make it not nullable and set null values to a default value
775 person_klass
.connection
.execute('UPDATE testings SET money = NULL')
776 person_klass
.connection
.change_column_null
"testings", "money", false, 2000
777 person_klass
.reset_column_information
778 assert_nil person_klass
.columns_hash
["money"].default
779 assert_equal
false, person_klass
.columns_hash
["money"].null
780 assert_equal
[2000], Person
.connection
.select_values("SELECT money FROM testings").map
{ |s
| s
.to_i
}.sort
782 Person
.connection
.drop_table
:testings rescue nil
785 def test_change_column_default_to_null
786 Person
.connection
.change_column_default
"people", "first_name", nil
787 Person
.reset_column_information
788 assert_nil Person
.new
.first_name
792 assert
!Reminder
.table_exists
?
796 assert Reminder
.create("content" => "hello world", "remind_at" => Time
.now
)
797 assert_equal
"hello world", Reminder
.find(:first).content
800 assert_raises(ActiveRecord
::StatementInvalid) { Reminder
.find(:first) }
803 def test_add_table_with_decimals
804 Person
.connection
.drop_table
:big_numbers rescue nil
806 assert
!BigNumber
.table_exists
?
809 assert BigNumber
.create(
810 :bank_balance => 1586.43,
811 :big_bank_balance => BigDecimal("1000234000567.95"),
812 :world_population => 6000000000,
813 :my_house_population => 3,
814 :value_of_e => BigDecimal("2.7182818284590452353602875")
817 b
= BigNumber
.find(:first)
820 assert_not_nil b
.bank_balance
821 assert_not_nil b
.big_bank_balance
822 assert_not_nil b
.world_population
823 assert_not_nil b
.my_house_population
824 assert_not_nil b
.value_of_e
826 # TODO: set world_population >= 2**62 to cover 64-bit platforms and test
828 assert_kind_of Integer
, b
.world_population
829 assert_equal
6000000000, b
.world_population
830 assert_kind_of Fixnum
, b
.my_house_population
831 assert_equal
3, b
.my_house_population
832 assert_kind_of BigDecimal
, b
.bank_balance
833 assert_equal
BigDecimal("1586.43"), b
.bank_balance
834 assert_kind_of BigDecimal
, b
.big_bank_balance
835 assert_equal
BigDecimal("1000234000567.95"), b
.big_bank_balance
837 # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with
838 # precision/scale explicitly left out. By the SQL standard, numbers
839 # assigned to this field should be truncated but that's seldom respected.
840 if current_adapter
?(:PostgreSQLAdapter, :SQLite2Adapter)
841 # - PostgreSQL changes the SQL spec on columns declared simply as
842 # "decimal" to something more useful: instead of being given a scale
843 # of 0, they take on the compile-time limit for precision and scale,
844 # so the following should succeed unless you have used really wacky
845 # compilation options
846 # - SQLite2 has the default behavior of preserving all data sent in,
847 # so this happens there too
848 assert_kind_of BigDecimal
, b
.value_of_e
849 assert_equal
BigDecimal("2.7182818284590452353602875"), b
.value_of_e
850 elsif current_adapter
?(:SQLiteAdapter)
851 # - SQLite3 stores a float, in violation of SQL
852 assert_kind_of BigDecimal
, b
.value_of_e
853 assert_equal
BigDecimal("2.71828182845905"), b
.value_of_e
855 # - SQL standard is an integer
856 assert_kind_of Fixnum
, b
.value_of_e
857 assert_equal
2, b
.value_of_e
860 GiveMeBigNumbers
.down
861 assert_raises(ActiveRecord
::StatementInvalid) { BigNumber
.find(:first) }
865 assert
!Person
.column_methods_hash
.include?(:last_name)
866 assert
!Reminder
.table_exists
?
868 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid")
870 assert_equal
3, ActiveRecord
::Migrator.current_version
871 Person
.reset_column_information
872 assert Person
.column_methods_hash
.include?(:last_name)
873 assert Reminder
.create("content" => "hello world", "remind_at" => Time
.now
)
874 assert_equal
"hello world", Reminder
.find(:first).content
876 ActiveRecord
::Migrator.down(MIGRATIONS_ROOT
+ "/valid")
878 assert_equal
0, ActiveRecord
::Migrator.current_version
879 Person
.reset_column_information
880 assert
!Person
.column_methods_hash
.include?(:last_name)
881 assert_raises(ActiveRecord
::StatementInvalid) { Reminder
.find(:first) }
884 def test_migrator_one_up
885 assert
!Person
.column_methods_hash
.include?(:last_name)
886 assert
!Reminder
.table_exists
?
888 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid", 1)
890 Person
.reset_column_information
891 assert Person
.column_methods_hash
.include?(:last_name)
892 assert
!Reminder
.table_exists
?
894 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid", 2)
896 assert Reminder
.create("content" => "hello world", "remind_at" => Time
.now
)
897 assert_equal
"hello world", Reminder
.find(:first).content
900 def test_migrator_one_down
901 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid")
903 ActiveRecord
::Migrator.down(MIGRATIONS_ROOT
+ "/valid", 1)
905 Person
.reset_column_information
906 assert Person
.column_methods_hash
.include?(:last_name)
907 assert
!Reminder
.table_exists
?
910 def test_migrator_one_up_one_down
911 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid", 1)
912 ActiveRecord
::Migrator.down(MIGRATIONS_ROOT
+ "/valid", 0)
914 assert
!Person
.column_methods_hash
.include?(:last_name)
915 assert
!Reminder
.table_exists
?
918 def test_migrator_double_up
919 assert_equal(0, ActiveRecord
::Migrator.current_version
)
920 ActiveRecord
::Migrator.run(:up, MIGRATIONS_ROOT
+ "/valid", 1)
921 assert_nothing_raised
{ ActiveRecord
::Migrator.run(:up, MIGRATIONS_ROOT
+ "/valid", 1) }
922 assert_equal(1, ActiveRecord
::Migrator.current_version
)
925 def test_migrator_double_down
926 assert_equal(0, ActiveRecord
::Migrator.current_version
)
927 ActiveRecord
::Migrator.run(:up, MIGRATIONS_ROOT
+ "/valid", 1)
928 ActiveRecord
::Migrator.run(:down, MIGRATIONS_ROOT
+ "/valid", 1)
929 assert_nothing_raised
{ ActiveRecord
::Migrator.run(:down, MIGRATIONS_ROOT
+ "/valid", 1) }
930 assert_equal(0, ActiveRecord
::Migrator.current_version
)
933 if current_adapter
?(:PostgreSQLAdapter)
934 def test_migrator_one_up_with_exception_and_rollback
935 assert
!Person
.column_methods_hash
.include?(:last_name)
937 e
= assert_raises(StandardError
) do
938 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/broken", 100)
941 assert_equal
"An error has occurred, this and all later migrations canceled:\n\nSomething broke", e
.message
943 Person
.reset_column_information
944 assert
!Person
.column_methods_hash
.include?(:last_name)
948 def test_finds_migrations
949 migrations
= ActiveRecord
::Migrator.new(:up, MIGRATIONS_ROOT
+ "/valid").migrations
950 [['1', 'people_have_last_names'],
951 ['2', 'we_need_reminders'],
952 ['3', 'innocent_jointable']].each_with_index
do |pair
, i
|
953 migrations
[i
].version == pair
.first
954 migrations
[1].name
== pair
.last
958 def test_finds_pending_migrations
959 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/interleaved/pass_2", 1)
960 migrations
= ActiveRecord
::Migrator.new(:up, MIGRATIONS_ROOT
+ "/interleaved/pass_2").pending_migrations
961 assert_equal
1, migrations
.size
962 migrations
[0].version == '3'
963 migrations
[0].name
== 'innocent_jointable'
966 def test_only_loads_pending_migrations
968 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid", 1)
970 # now unload the migrations that have been defined
971 PeopleHaveLastNames
.unloadable
972 ActiveSupport
::Dependencies.remove_unloadable_constants
!
974 ActiveRecord
::Migrator.migrate(MIGRATIONS_ROOT
+ "/valid", nil)
976 assert
!defined? PeopleHaveLastNames
978 %w(WeNeedReminders
, InnocentJointable
).each
do |migration
|
979 assert
defined? migration
983 load(MIGRATIONS_ROOT
+ "/valid/1_people_have_last_names.rb")
986 def test_migrator_interleaved_migrations
987 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/interleaved/pass_1")
989 assert_nothing_raised
do
990 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/interleaved/pass_2")
993 Person
.reset_column_information
994 assert Person
.column_methods_hash
.include?(:last_name)
996 assert_nothing_raised
do
997 ActiveRecord
::Migrator.down(MIGRATIONS_ROOT
+ "/interleaved/pass_3")
1001 def test_migrator_db_has_no_schema_migrations_table
1002 ActiveRecord
::Base.connection
.execute("DROP TABLE schema_migrations;")
1003 assert_nothing_raised
do
1004 ActiveRecord
::Migrator.migrate(MIGRATIONS_ROOT
+ "/valid", 1)
1008 def test_migrator_verbosity
1009 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid", 1)
1010 assert PeopleHaveLastNames
.message_count
> 0
1011 PeopleHaveLastNames
.message_count
= 0
1013 ActiveRecord
::Migrator.down(MIGRATIONS_ROOT
+ "/valid", 0)
1014 assert PeopleHaveLastNames
.message_count
> 0
1015 PeopleHaveLastNames
.message_count
= 0
1018 def test_migrator_verbosity_off
1019 PeopleHaveLastNames
.verbose
= false
1020 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid", 1)
1021 assert PeopleHaveLastNames
.message_count
.zero
?
1022 ActiveRecord
::Migrator.down(MIGRATIONS_ROOT
+ "/valid", 0)
1023 assert PeopleHaveLastNames
.message_count
.zero
?
1026 def test_migrator_going_down_due_to_version_target
1027 ActiveRecord
::Migrator.up(MIGRATIONS_ROOT
+ "/valid", 1)
1028 ActiveRecord
::Migrator.migrate(MIGRATIONS_ROOT
+ "/valid", 0)
1030 assert
!Person
.column_methods_hash
.include?(:last_name)
1031 assert
!Reminder
.table_exists
?
1033 ActiveRecord
::Migrator.migrate(MIGRATIONS_ROOT
+ "/valid")
1035 Person
.reset_column_information
1036 assert Person
.column_methods_hash
.include?(:last_name)
1037 assert Reminder
.create("content" => "hello world", "remind_at" => Time
.now
)
1038 assert_equal
"hello world", Reminder
.find(:first).content
1041 def test_migrator_rollback
1042 ActiveRecord
::Migrator.migrate(MIGRATIONS_ROOT
+ "/valid")
1043 assert_equal(3, ActiveRecord
::Migrator.current_version
)
1045 ActiveRecord
::Migrator.rollback(MIGRATIONS_ROOT
+ "/valid")
1046 assert_equal(2, ActiveRecord
::Migrator.current_version
)
1048 ActiveRecord
::Migrator.rollback(MIGRATIONS_ROOT
+ "/valid")
1049 assert_equal(1, ActiveRecord
::Migrator.current_version
)
1051 ActiveRecord
::Migrator.rollback(MIGRATIONS_ROOT
+ "/valid")
1052 assert_equal(0, ActiveRecord
::Migrator.current_version
)
1054 ActiveRecord
::Migrator.rollback(MIGRATIONS_ROOT
+ "/valid")
1055 assert_equal(0, ActiveRecord
::Migrator.current_version
)
1058 def test_schema_migrations_table_name
1059 ActiveRecord
::Base.table_name_prefix
= "prefix_"
1060 ActiveRecord
::Base.table_name_suffix
= "_suffix"
1061 Reminder
.reset_table_name
1062 assert_equal
"prefix_schema_migrations_suffix", ActiveRecord
::Migrator.schema_migrations_table_name
1063 ActiveRecord
::Base.table_name_prefix
= ""
1064 ActiveRecord
::Base.table_name_suffix
= ""
1065 Reminder
.reset_table_name
1066 assert_equal
"schema_migrations", ActiveRecord
::Migrator.schema_migrations_table_name
1068 ActiveRecord
::Base.table_name_prefix
= ""
1069 ActiveRecord
::Base.table_name_suffix
= ""
1072 def test_proper_table_name
1073 assert_equal
"table", ActiveRecord
::Migrator.proper_table_name('table')
1074 assert_equal
"table", ActiveRecord
::Migrator.proper_table_name(:table)
1075 assert_equal
"reminders", ActiveRecord
::Migrator.proper_table_name(Reminder
)
1076 Reminder
.reset_table_name
1077 assert_equal Reminder
.table_name
, ActiveRecord
::Migrator.proper_table_name(Reminder
)
1079 # Use the model's own prefix/suffix if a model is given
1080 ActiveRecord
::Base.table_name_prefix
= "ARprefix_"
1081 ActiveRecord
::Base.table_name_suffix
= "_ARsuffix"
1082 Reminder
.table_name_prefix
= 'prefix_'
1083 Reminder
.table_name_suffix
= '_suffix'
1084 Reminder
.reset_table_name
1085 assert_equal
"prefix_reminders_suffix", ActiveRecord
::Migrator.proper_table_name(Reminder
)
1086 Reminder
.table_name_prefix
= ''
1087 Reminder
.table_name_suffix
= ''
1088 Reminder
.reset_table_name
1090 # Use AR::Base's prefix/suffix if string or symbol is given
1091 ActiveRecord
::Base.table_name_prefix
= "prefix_"
1092 ActiveRecord
::Base.table_name_suffix
= "_suffix"
1093 Reminder
.reset_table_name
1094 assert_equal
"prefix_table_suffix", ActiveRecord
::Migrator.proper_table_name('table')
1095 assert_equal
"prefix_table_suffix", ActiveRecord
::Migrator.proper_table_name(:table)
1096 ActiveRecord
::Base.table_name_prefix
= ""
1097 ActiveRecord
::Base.table_name_suffix
= ""
1098 Reminder
.reset_table_name
1101 def test_add_drop_table_with_prefix_and_suffix
1102 assert
!Reminder
.table_exists
?
1103 ActiveRecord
::Base.table_name_prefix
= 'prefix_'
1104 ActiveRecord
::Base.table_name_suffix
= '_suffix'
1105 Reminder
.reset_table_name
1106 Reminder
.reset_sequence_name
1108 assert Reminder
.create("content" => "hello world", "remind_at" => Time
.now
)
1109 assert_equal
"hello world", Reminder
.find(:first).content
1111 WeNeedReminders
.down
1112 assert_raises(ActiveRecord
::StatementInvalid) { Reminder
.find(:first) }
1114 ActiveRecord
::Base.table_name_prefix
= ''
1115 ActiveRecord
::Base.table_name_suffix
= ''
1116 Reminder
.reset_table_name
1117 Reminder
.reset_sequence_name
1120 def test_create_table_with_binary_column
1121 Person
.connection
.drop_table
:binary_testings rescue nil
1123 assert_nothing_raised
{
1124 Person
.connection
.create_table
:binary_testings do |t
|
1125 t
.column
"data", :binary, :null => false
1129 columns
= Person
.connection
.columns(:binary_testings)
1130 data_column
= columns
.detect
{ |c
| c
.name
== "data" }
1132 if current_adapter
?(:MysqlAdapter)
1133 assert_equal
'', data_column
.default
1135 assert_nil data_column
.default
1138 Person
.connection
.drop_table
:binary_testings rescue nil
1141 def test_migrator_with_duplicates
1142 assert_raises(ActiveRecord
::DuplicateMigrationVersionError) do
1143 ActiveRecord
::Migrator.migrate(MIGRATIONS_ROOT
+ "/duplicate", nil)
1147 def test_migrator_with_duplicate_names
1148 assert_raises(ActiveRecord
::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do
1149 ActiveRecord
::Migrator.migrate(MIGRATIONS_ROOT
+ "/duplicate_names", nil)
1153 def test_migrator_with_missing_version_numbers
1154 assert_raise(ActiveRecord
::UnknownMigrationVersionError) do
1155 ActiveRecord
::Migrator.migrate(MIGRATIONS_ROOT
+ "/missing", 500)
1159 def test_create_table_with_custom_sequence_name
1160 return unless current_adapter
? :OracleAdapter
1162 # table name is 29 chars, the standard sequence name will
1163 # be 33 chars and fail
1164 assert_raises(ActiveRecord
::StatementInvalid) do
1166 Person
.connection
.create_table
:table_with_name_thats_just_ok do |t
|
1167 t
.column
:foo, :string, :null => false
1170 Person
.connection
.drop_table
:table_with_name_thats_just_ok rescue nil
1174 # should be all good w/ a custom sequence name
1175 assert_nothing_raised
do
1177 Person
.connection
.create_table
:table_with_name_thats_just_ok,
1178 :sequence_name => 'suitably_short_seq' do |t
|
1179 t
.column
:foo, :string, :null => false
1182 Person
.connection
.execute("select suitably_short_seq.nextval from dual")
1185 Person
.connection
.drop_table
:table_with_name_thats_just_ok,
1186 :sequence_name => 'suitably_short_seq' rescue nil
1190 # confirm the custom sequence got dropped
1191 assert_raises(ActiveRecord
::StatementInvalid) do
1192 Person
.connection
.execute("select suitably_short_seq.nextval from dual")
1197 def with_env_tz(new_tz
= 'US/Eastern')
1198 old_tz
, ENV['TZ'] = ENV['TZ'], new_tz
1201 old_tz
? ENV['TZ'] = old_tz
: ENV.delete('TZ')
1206 uses_mocha
'Sexy migration tests' do
1207 class SexyMigrationsTest
< ActiveRecord
::TestCase
1208 def test_references_column_type_adds_id
1209 with_new_table
do |t
|
1210 t
.expects(:column).with('customer_id', :integer, {})
1211 t
.references
:customer
1215 def test_references_column_type_with_polymorphic_adds_type
1216 with_new_table
do |t
|
1217 t
.expects(:column).with('taggable_type', :string, {})
1218 t
.expects(:column).with('taggable_id', :integer, {})
1219 t
.references
:taggable, :polymorphic => true
1223 def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
1224 with_new_table
do |t
|
1225 t
.expects(:column).with('taggable_type', :string, {:null => false})
1226 t
.expects(:column).with('taggable_id', :integer, {:null => false})
1227 t
.references
:taggable, :polymorphic => true, :null => false
1231 def test_belongs_to_works_like_references
1232 with_new_table
do |t
|
1233 t
.expects(:column).with('customer_id', :integer, {})
1234 t
.belongs_to
:customer
1238 def test_timestamps_creates_updated_at_and_created_at
1239 with_new_table
do |t
|
1240 t
.expects(:column).with(:created_at, :datetime, kind_of(Hash
))
1241 t
.expects(:column).with(:updated_at, :datetime, kind_of(Hash
))
1246 def test_integer_creates_integer_column
1247 with_new_table
do |t
|
1248 t
.expects(:column).with(:foo, 'integer', {})
1249 t
.expects(:column).with(:bar, 'integer', {})
1250 t
.integer
:foo, :bar
1254 def test_string_creates_string_column
1255 with_new_table
do |t
|
1256 t
.expects(:column).with(:foo, 'string', {})
1257 t
.expects(:column).with(:bar, 'string', {})
1264 Person
.connection
.create_table
:delete_me, :force => true do |t
|
1268 Person
.connection
.drop_table
:delete_me rescue nil
1271 end # SexyMigrationsTest
1274 uses_mocha
'ChangeTable migration tests' do
1275 class ChangeTableMigrationsTest
< ActiveRecord
::TestCase
1277 @connection = Person
.connection
1278 @connection.create_table
:delete_me, :force => true do |t
|
1283 Person
.connection
.drop_table
:delete_me rescue nil
1286 def test_references_column_type_adds_id
1287 with_change_table
do |t
|
1288 @connection.expects(:add_column).with(:delete_me, 'customer_id', :integer, {})
1289 t
.references
:customer
1293 def test_remove_references_column_type_removes_id
1294 with_change_table
do |t
|
1295 @connection.expects(:remove_column).with(:delete_me, 'customer_id')
1296 t
.remove_references
:customer
1300 def test_add_belongs_to_works_like_add_references
1301 with_change_table
do |t
|
1302 @connection.expects(:add_column).with(:delete_me, 'customer_id', :integer, {})
1303 t
.belongs_to
:customer
1307 def test_remove_belongs_to_works_like_remove_references
1308 with_change_table
do |t
|
1309 @connection.expects(:remove_column).with(:delete_me, 'customer_id')
1310 t
.remove_belongs_to
:customer
1314 def test_references_column_type_with_polymorphic_adds_type
1315 with_change_table
do |t
|
1316 @connection.expects(:add_column).with(:delete_me, 'taggable_type', :string, {})
1317 @connection.expects(:add_column).with(:delete_me, 'taggable_id', :integer, {})
1318 t
.references
:taggable, :polymorphic => true
1322 def test_remove_references_column_type_with_polymorphic_removes_type
1323 with_change_table
do |t
|
1324 @connection.expects(:remove_column).with(:delete_me, 'taggable_type')
1325 @connection.expects(:remove_column).with(:delete_me, 'taggable_id')
1326 t
.remove_references
:taggable, :polymorphic => true
1330 def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
1331 with_change_table
do |t
|
1332 @connection.expects(:add_column).with(:delete_me, 'taggable_type', :string, {:null => false})
1333 @connection.expects(:add_column).with(:delete_me, 'taggable_id', :integer, {:null => false})
1334 t
.references
:taggable, :polymorphic => true, :null => false
1338 def test_remove_references_column_type_with_polymorphic_and_options_null_is_false_removes_table_flag
1339 with_change_table
do |t
|
1340 @connection.expects(:remove_column).with(:delete_me, 'taggable_type')
1341 @connection.expects(:remove_column).with(:delete_me, 'taggable_id')
1342 t
.remove_references
:taggable, :polymorphic => true, :null => false
1346 def test_timestamps_creates_updated_at_and_created_at
1347 with_change_table
do |t
|
1348 @connection.expects(:add_timestamps).with(:delete_me)
1353 def test_remove_timestamps_creates_updated_at_and_created_at
1354 with_change_table
do |t
|
1355 @connection.expects(:remove_timestamps).with(:delete_me)
1361 if current_adapter
?(:PostgreSQLAdapter)
1362 "character varying(255)"
1369 if current_adapter
?(:MysqlAdapter)
1376 def test_integer_creates_integer_column
1377 with_change_table
do |t
|
1378 @connection.expects(:add_column).with(:delete_me, :foo, integer_column
, {})
1379 @connection.expects(:add_column).with(:delete_me, :bar, integer_column
, {})
1380 t
.integer
:foo, :bar
1384 def test_string_creates_string_column
1385 with_change_table
do |t
|
1386 @connection.expects(:add_column).with(:delete_me, :foo, string_column
, {})
1387 @connection.expects(:add_column).with(:delete_me, :bar, string_column
, {})
1392 def test_column_creates_column
1393 with_change_table
do |t
|
1394 @connection.expects(:add_column).with(:delete_me, :bar, :integer, {})
1395 t
.column
:bar, :integer
1399 def test_column_creates_column_with_options
1400 with_change_table
do |t
|
1401 @connection.expects(:add_column).with(:delete_me, :bar, :integer, {:null => false})
1402 t
.column
:bar, :integer, :null => false
1406 def test_index_creates_index
1407 with_change_table
do |t
|
1408 @connection.expects(:add_index).with(:delete_me, :bar, {})
1413 def test_index_creates_index_with_options
1414 with_change_table
do |t
|
1415 @connection.expects(:add_index).with(:delete_me, :bar, {:unique => true})
1416 t
.index
:bar, :unique => true
1420 def test_change_changes_column
1421 with_change_table
do |t
|
1422 @connection.expects(:change_column).with(:delete_me, :bar, :string, {})
1423 t
.change
:bar, :string
1427 def test_change_changes_column_with_options
1428 with_change_table
do |t
|
1429 @connection.expects(:change_column).with(:delete_me, :bar, :string, {:null => true})
1430 t
.change
:bar, :string, :null => true
1434 def test_change_default_changes_column
1435 with_change_table
do |t
|
1436 @connection.expects(:change_column_default).with(:delete_me, :bar, :string)
1437 t
.change_default
:bar, :string
1441 def test_remove_drops_single_column
1442 with_change_table
do |t
|
1443 @connection.expects(:remove_column).with(:delete_me, [:bar])
1448 def test_remove_drops_multiple_columns
1449 with_change_table
do |t
|
1450 @connection.expects(:remove_column).with(:delete_me, [:bar, :baz])
1455 def test_remove_index_removes_index_with_options
1456 with_change_table
do |t
|
1457 @connection.expects(:remove_index).with(:delete_me, {:unique => true})
1458 t
.remove_index
:unique => true
1462 def test_rename_renames_column
1463 with_change_table
do |t
|
1464 @connection.expects(:rename_column).with(:delete_me, :bar, :baz)
1470 def with_change_table
1471 Person
.connection
.change_table
:delete_me do |t
|
1476 end # ChangeTable test