ibm_db 1.1.1-mswin32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. data/CHANGES +155 -0
  2. data/LICENSE +18 -0
  3. data/MANIFEST +14 -0
  4. data/README +274 -0
  5. data/ext/Makefile.nt32 +181 -0
  6. data/ext/extconf.rb +58 -0
  7. data/ext/ibm_db.c +6553 -0
  8. data/ext/ruby_ibm_db.h +214 -0
  9. data/init.rb +42 -0
  10. data/lib/IBM_DB.rb +2 -0
  11. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2218 -0
  12. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
  13. data/lib/mswin32/ibm_db.so +0 -0
  14. data/test/cases/adapter_test.rb +180 -0
  15. data/test/cases/associations/cascaded_eager_loading_test.rb +133 -0
  16. data/test/cases/associations/eager_test.rb +842 -0
  17. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +874 -0
  18. data/test/cases/associations/has_many_through_associations_test.rb +281 -0
  19. data/test/cases/associations/join_model_test.rb +801 -0
  20. data/test/cases/attribute_methods_test.rb +312 -0
  21. data/test/cases/base_test.rb +2114 -0
  22. data/test/cases/calculations_test.rb +346 -0
  23. data/test/cases/finder_test.rb +1092 -0
  24. data/test/cases/fixtures_test.rb +660 -0
  25. data/test/cases/migration_test.rb +1618 -0
  26. data/test/cases/schema_dumper_test.rb +197 -0
  27. data/test/cases/validations_test.rb +1604 -0
  28. data/test/connections/native_ibm_db/connection.rb +40 -0
  29. data/test/ibm_db_test.rb +25 -0
  30. data/test/models/warehouse_thing.rb +5 -0
  31. data/test/schema/i5/ibm_db_specific_schema.rb +134 -0
  32. data/test/schema/ids/ibm_db_specific_schema.rb +137 -0
  33. data/test/schema/luw/ibm_db_specific_schema.rb +134 -0
  34. data/test/schema/schema.rb +499 -0
  35. data/test/schema/zOS/ibm_db_specific_schema.rb +205 -0
  36. metadata +115 -0
@@ -0,0 +1,1618 @@
1
+ require "cases/helper"
2
+ require 'bigdecimal/util'
3
+ require 'mocha'
4
+
5
+ require 'models/person'
6
+ require 'models/topic'
7
+ require 'models/developer'
8
+
9
+ require MIGRATIONS_ROOT + "/valid/1_people_have_last_names"
10
+ require MIGRATIONS_ROOT + "/valid/2_we_need_reminders"
11
+ require MIGRATIONS_ROOT + "/decimal/1_give_me_big_numbers"
12
+ require MIGRATIONS_ROOT + "/interleaved/pass_3/2_i_raise_on_down"
13
+
14
+ if ActiveRecord::Base.connection.supports_migrations?
15
+ class BigNumber < ActiveRecord::Base; end
16
+
17
+ class Reminder < ActiveRecord::Base; end
18
+
19
+ class ActiveRecord::Migration
20
+ class <<self
21
+ attr_accessor :message_count
22
+ def puts(text="")
23
+ self.message_count ||= 0
24
+ self.message_count += 1
25
+ end
26
+ end
27
+ end
28
+
29
+ class MigrationTest < ActiveRecord::TestCase
30
+ self.use_transactional_fixtures = false
31
+
32
+ if (current_adapter?(:IBM_DBAdapter))
33
+ #Rename is supported only for server zOS 9 , DB2 COBRA and Informix
34
+ server_type = ActiveRecord::Base.connection.servertype.class.name
35
+ @ibm_db_rename_supported = server_type.include?('::IBM_DB2_LUW_COBRA') ||
36
+ server_type.class.name.include?('::IBM_IDS') ||
37
+ (server_type.include?('IBM_DB2_ZOS') && !server_type.include?('IBM_DB2_ZOS_8'))
38
+ end
39
+
40
+ fixtures :people
41
+
42
+ def setup
43
+ ActiveRecord::Migration.verbose = true
44
+ PeopleHaveLastNames.message_count = 0
45
+ end
46
+
47
+ def teardown
48
+ ActiveRecord::Base.connection.initialize_schema_migrations_table
49
+ ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}"
50
+
51
+ %w(reminders people_reminders prefix_reminders_suffix).each do |table|
52
+ Reminder.connection.drop_table(table) rescue nil
53
+ end
54
+ Reminder.reset_column_information
55
+
56
+ %w(last_name key bio age height wealth birthday favorite_day
57
+ moment_of_truth male administrator funny).each do |column|
58
+ Person.connection.remove_column('people', column) rescue nil
59
+ end
60
+ Person.connection.remove_column("people", "first_name") rescue nil
61
+ Person.connection.remove_column("people", "middle_name") rescue nil
62
+ Person.connection.add_column("people", "first_name", :string, :limit => 40)
63
+ Person.reset_column_information
64
+ end
65
+
66
+ def test_add_index
67
+ # Limit size of last_name and key columns to support Firebird index limitations
68
+ Person.connection.add_column "people", "last_name", :string, :limit => 100
69
+ Person.connection.add_column "people", "key", :string, :limit => 100
70
+ Person.connection.add_column "people", "administrator", :boolean
71
+
72
+ assert_nothing_raised { Person.connection.add_index("people", "last_name") }
73
+ assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
74
+
75
+ # Orcl nds shrt indx nms. Sybs 2.
76
+ # OpenBase does not have named indexes. You must specify a single column name
77
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter)
78
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
79
+ assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
80
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
81
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "index_people_on_last_name_and_first_name") }
82
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
83
+ assert_nothing_raised { Person.connection.remove_index("people", "last_name_and_first_name") }
84
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
85
+ assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
86
+ end
87
+
88
+ # quoting
89
+ # Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
90
+ # OpenBase does not have named indexes. You must specify a single column name
91
+ unless current_adapter?(:OpenBaseAdapter)
92
+ unless current_adapter?(:IBM_DBAdapter)
93
+ 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)
94
+ else
95
+ Person.update_all "#{Person.connection.quote_column_name 'key'}=#{Person.connection.quote_column_name 'first_name'}" #some databases (including sqlite2 won't add a unique index if existing data non unique)
96
+ end
97
+ assert_nothing_raised { Person.connection.add_index("people", ["key"], :name => "key_idx", :unique => true) }
98
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "key_idx", :unique => true) }
99
+ end
100
+
101
+ # Sybase adapter does not support indexes on :boolean columns
102
+ # OpenBase does not have named indexes. You must specify a single column
103
+ unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter)
104
+ assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
105
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
106
+ end
107
+ end
108
+
109
+ def testing_table_with_only_foo_attribute
110
+ Person.connection.create_table :testings, :id => false do |t|
111
+ t.column :foo, :string
112
+ end
113
+
114
+ yield Person.connection
115
+ ensure
116
+ Person.connection.drop_table :testings rescue nil
117
+ end
118
+ protected :testing_table_with_only_foo_attribute
119
+
120
+ def test_create_table_without_id
121
+ testing_table_with_only_foo_attribute do |connection|
122
+ assert_equal connection.columns(:testings).size, 1
123
+ end
124
+ end
125
+
126
+ unless current_adapter?(:IBM_DBAdapter)
127
+ # Cannot add a primary key to a table with some rows already in it as it violates the unique constraint
128
+ # Secondly GENERATED BY DEFAULT AS IDENTITY cannot be applied in a alter table command.
129
+ # as this will be wrong sql syntax for DB2
130
+ def test_add_column_with_primary_key_attribute
131
+ testing_table_with_only_foo_attribute do |connection|
132
+ assert_nothing_raised { connection.add_column :testings, :id, :primary_key }
133
+ assert_equal connection.columns(:testings).size, 2
134
+ end
135
+ end
136
+ end
137
+
138
+ def test_create_table_adds_id
139
+ Person.connection.create_table :testings do |t|
140
+ t.column :foo, :string
141
+ end
142
+
143
+ assert_equal %w(foo id),
144
+ Person.connection.columns(:testings).map { |c| c.name }.sort
145
+ ensure
146
+ Person.connection.drop_table :testings rescue nil
147
+ end
148
+
149
+ def test_create_table_with_not_null_column
150
+ assert_nothing_raised do
151
+ Person.connection.create_table :testings do |t|
152
+ t.column :foo, :string, :null => false
153
+ end
154
+ end
155
+
156
+ assert_raise(ActiveRecord::StatementInvalid) do
157
+ Person.connection.execute "insert into testings (foo) values (NULL)"
158
+ end
159
+ ensure
160
+ Person.connection.drop_table :testings rescue nil
161
+ end
162
+
163
+ def test_create_table_with_defaults
164
+ # MySQL doesn't allow defaults on TEXT or BLOB columns.
165
+ mysql = current_adapter?(:MysqlAdapter)
166
+ ibm_ids_zOS = ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')||
167
+ ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_DB2_ZOS')
168
+
169
+ Person.connection.create_table :testings do |t|
170
+ t.column :one, :string, :default => "hello"
171
+ t.column :two, :boolean, :default => true
172
+ t.column :three, :boolean, :default => false
173
+ t.column :four, :integer, :default => 1
174
+ t.column :five, :text, :default => "hello" unless mysql || ibm_ids_zOS
175
+ end
176
+
177
+ columns = Person.connection.columns(:testings)
178
+ one = columns.detect { |c| c.name == "one" }
179
+ two = columns.detect { |c| c.name == "two" }
180
+ three = columns.detect { |c| c.name == "three" }
181
+ four = columns.detect { |c| c.name == "four" }
182
+ five = columns.detect { |c| c.name == "five" } unless mysql || ibm_ids_zOS
183
+
184
+ assert_equal "hello", one.default
185
+ assert_equal true, two.default
186
+ assert_equal false, three.default
187
+ assert_equal 1, four.default
188
+ assert_equal "hello", five.default unless mysql || ibm_ids_zOS
189
+
190
+ ensure
191
+ Person.connection.drop_table :testings rescue nil
192
+ end
193
+
194
+ if current_adapter?(:IBM_DBAdapter)
195
+ def test_no_limits_datatypes_IBM_DB
196
+ ibm_ids = ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')
197
+ clasz = Class.new(ActiveRecord::Base)
198
+ clasz.table_name = 'test_no_limits_datatypes_IBM_DB'
199
+ assert_nothing_raised do
200
+ clasz.connection.create_table clasz.table_name do |t|
201
+ t.column "test_varchar", :string, :limit => 10
202
+ t.column "test_integer", :integer, :limit => 5
203
+ t.column "test_boolean", :boolean, :limit => 5
204
+ t.column "test_double", :double, :limit => 10
205
+ t.column "test_date", :date, :limit => 10
206
+ t.column "test_time", :time, :limit => 10
207
+ t.column "test_tstamp", :timestamp, :limit => 10
208
+ t.column "test_xml", :xml, :limit => 10 unless ibm_ids
209
+ t.column "test_clob", :text, :limit => 10000
210
+ t.column "test_decfloat", :decfloat, :limit => 100
211
+ end
212
+ end
213
+ ensure
214
+ clasz.connection.drop_table(clasz.table_name) rescue nil
215
+ end
216
+
217
+ #Sexy migration test for column of type xml and char
218
+ def test_short_hand_migrations_for_ibm_db_datatypes
219
+ ibm_ids = ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')
220
+ clasz = Class.new(ActiveRecord::Base)
221
+ clasz.table_name = 'test_short_hand_migrations'
222
+ assert_nothing_raised do
223
+ clasz.connection.create_table clasz.table_name do |t|
224
+ t.xml :xml_col unless ibm_ids
225
+ t.char :char_col, :limit=>10
226
+ t.decfloat :dec_col, :precision=>16
227
+ end
228
+ end
229
+ assert_nothing_raised do
230
+ clasz.connection.change_table clasz.table_name do |t|
231
+ t.xml :xml_col1 unless ibm_ids
232
+ t.char :char_col1, :limit=>50
233
+ t.decfloat :dec_col1, :precision=>34
234
+ end
235
+ end
236
+ ensure
237
+ clasz.connection.drop_table(clasz.table_name) rescue nil
238
+ end
239
+ end
240
+
241
+ def test_create_table_with_limits
242
+ assert_nothing_raised do
243
+ Person.connection.create_table :testings do |t|
244
+ t.column :foo, :string, :limit => 255
245
+
246
+ t.column :default_int, :integer
247
+
248
+ t.column :one_int, :integer, :limit => 1
249
+ t.column :four_int, :integer, :limit => 4
250
+ t.column :eight_int, :integer, :limit => 8
251
+ t.column :eleven_int, :integer, :limit => 11
252
+ end
253
+ end
254
+
255
+ columns = Person.connection.columns(:testings)
256
+ foo = columns.detect { |c| c.name == "foo" }
257
+ assert_equal 255, foo.limit
258
+
259
+ default = columns.detect { |c| c.name == "default_int" }
260
+ one = columns.detect { |c| c.name == "one_int" }
261
+ four = columns.detect { |c| c.name == "four_int" }
262
+ eight = columns.detect { |c| c.name == "eight_int" }
263
+ eleven = columns.detect { |c| c.name == "eleven_int" }
264
+
265
+ if current_adapter?(:PostgreSQLAdapter)
266
+ assert_equal 'integer', default.sql_type
267
+ assert_equal 'smallint', one.sql_type
268
+ assert_equal 'integer', four.sql_type
269
+ assert_equal 'bigint', eight.sql_type
270
+ assert_equal 'integer', eleven.sql_type
271
+ elsif current_adapter?(:MysqlAdapter)
272
+ assert_match 'int(11)', default.sql_type
273
+ assert_match 'tinyint', one.sql_type
274
+ assert_match 'int', four.sql_type
275
+ assert_match 'bigint', eight.sql_type
276
+ assert_match 'int(11)', eleven.sql_type
277
+ elsif current_adapter?(:OracleAdapter)
278
+ assert_equal 'NUMBER(38)', default.sql_type
279
+ assert_equal 'NUMBER(1)', one.sql_type
280
+ assert_equal 'NUMBER(4)', four.sql_type
281
+ assert_equal 'NUMBER(8)', eight.sql_type
282
+ end
283
+ ensure
284
+ Person.connection.drop_table :testings rescue nil
285
+ end
286
+
287
+ def test_create_table_with_primary_key_prefix_as_table_name_with_underscore
288
+ ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
289
+
290
+ Person.connection.create_table :testings do |t|
291
+ t.column :foo, :string
292
+ end
293
+
294
+ assert_equal %w(foo testings_id), Person.connection.columns(:testings).map { |c| c.name }.sort
295
+ ensure
296
+ Person.connection.drop_table :testings rescue nil
297
+ ActiveRecord::Base.primary_key_prefix_type = nil
298
+ end
299
+
300
+ def test_create_table_with_primary_key_prefix_as_table_name
301
+ ActiveRecord::Base.primary_key_prefix_type = :table_name
302
+
303
+ Person.connection.create_table :testings do |t|
304
+ t.column :foo, :string
305
+ end
306
+
307
+ assert_equal %w(foo testingsid), Person.connection.columns(:testings).map { |c| c.name }.sort
308
+ ensure
309
+ Person.connection.drop_table :testings rescue nil
310
+ ActiveRecord::Base.primary_key_prefix_type = nil
311
+ end
312
+
313
+ def test_create_table_with_force_true_does_not_drop_nonexisting_table
314
+ if Person.connection.table_exists?(:testings2)
315
+ Person.connection.drop_table :testings2
316
+ end
317
+
318
+ # using a copy as we need the drop_table method to
319
+ # continue to work for the ensure block of the test
320
+ temp_conn = Person.connection.dup
321
+ temp_conn.expects(:drop_table).never
322
+ temp_conn.create_table :testings2, :force => true do |t|
323
+ t.column :foo, :string
324
+ end
325
+ ensure
326
+ Person.connection.drop_table :testings2 rescue nil
327
+ end
328
+
329
+ def test_create_table_with_timestamps_should_create_datetime_columns
330
+ table_name = :testings
331
+
332
+ Person.connection.create_table table_name do |t|
333
+ t.timestamps
334
+ end
335
+ created_columns = Person.connection.columns(table_name)
336
+
337
+ created_at_column = created_columns.detect {|c| c.name == 'created_at' }
338
+ updated_at_column = created_columns.detect {|c| c.name == 'updated_at' }
339
+
340
+ assert created_at_column.null
341
+ assert updated_at_column.null
342
+ ensure
343
+ Person.connection.drop_table table_name rescue nil
344
+ end
345
+
346
+ def test_create_table_with_timestamps_should_create_datetime_columns_with_options
347
+ table_name = :testings
348
+
349
+ Person.connection.create_table table_name do |t|
350
+ t.timestamps :null => false
351
+ end
352
+ created_columns = Person.connection.columns(table_name)
353
+
354
+ created_at_column = created_columns.detect {|c| c.name == 'created_at' }
355
+ updated_at_column = created_columns.detect {|c| c.name == 'updated_at' }
356
+
357
+ assert !created_at_column.null
358
+ assert !updated_at_column.null
359
+ ensure
360
+ Person.connection.drop_table table_name rescue nil
361
+ end
362
+
363
+ # Sybase, and SQLite3 will not allow you to add a NOT NULL
364
+ # column to a table without a default value.
365
+ unless current_adapter?(:SybaseAdapter, :SQLiteAdapter, :IBM_DBAdapter)
366
+ def test_add_column_not_null_without_default
367
+ Person.connection.create_table :testings do |t|
368
+ t.column :foo, :string
369
+ end
370
+ Person.connection.add_column :testings, :bar, :string, :null => false
371
+
372
+ assert_raise(ActiveRecord::StatementInvalid) do
373
+ Person.connection.execute "insert into testings (foo, bar) values ('hello', NULL)"
374
+ end
375
+ ensure
376
+ Person.connection.drop_table :testings rescue nil
377
+ end
378
+ end
379
+
380
+ def test_add_column_not_null_with_default
381
+ Person.connection.create_table :testings do |t|
382
+ t.column :foo, :string
383
+ end
384
+
385
+ con = Person.connection
386
+ Person.connection.enable_identity_insert("testings", true) if current_adapter?(:SybaseAdapter)
387
+ Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')"
388
+ Person.connection.enable_identity_insert("testings", false) if current_adapter?(:SybaseAdapter)
389
+ assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
390
+
391
+ assert_raise(ActiveRecord::StatementInvalid) do
392
+ unless current_adapter?(:OpenBaseAdapter)
393
+ 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)"
394
+ else
395
+ 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)",
396
+ "Testing Insert","id",2)
397
+ end
398
+ end
399
+ ensure
400
+ Person.connection.drop_table :testings rescue nil
401
+ end
402
+
403
+ # We specifically do a manual INSERT here, and then test only the SELECT
404
+ # functionality. This allows us to more easily catch INSERT being broken,
405
+ # but SELECT actually working fine.
406
+ def test_native_decimal_insert_manual_vs_automatic
407
+ correct_value = '0012345678901234567890.0123456789'.to_d
408
+
409
+ Person.delete_all
410
+ Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
411
+ Person.reset_column_information
412
+
413
+ # Do a manual insertion
414
+ if current_adapter?(:OracleAdapter)
415
+ Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
416
+ elsif current_adapter?(:OpenBaseAdapter) || (current_adapter?(:MysqlAdapter) && Mysql.client_version < 50003) #before mysql 5.0.3 decimals stored as strings
417
+ Person.connection.execute "insert into people (wealth) values ('12345678901234567890.0123456789')"
418
+ else
419
+ Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)"
420
+ end
421
+
422
+ # SELECT
423
+ row = Person.find(:first)
424
+ assert_kind_of BigDecimal, row.wealth
425
+
426
+ # If this assert fails, that means the SELECT is broken!
427
+ unless current_adapter?(:SQLite3Adapter)
428
+ assert_equal correct_value, row.wealth
429
+ end
430
+
431
+ # Reset to old state
432
+ Person.delete_all
433
+
434
+ # Now use the Rails insertion
435
+ assert_nothing_raised { Person.create :wealth => BigDecimal.new("12345678901234567890.0123456789") }
436
+
437
+ # SELECT
438
+ row = Person.find(:first)
439
+ assert_kind_of BigDecimal, row.wealth
440
+
441
+ # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
442
+ unless current_adapter?(:SQLite3Adapter)
443
+ assert_equal correct_value, row.wealth
444
+ end
445
+
446
+ # Reset to old state
447
+ Person.connection.del_column "people", "wealth" rescue nil
448
+ Person.reset_column_information
449
+ end
450
+
451
+ def test_add_column_with_precision_and_scale
452
+ Person.connection.add_column 'people', 'wealth', :decimal, :precision => 9, :scale => 7
453
+ Person.reset_column_information
454
+
455
+ wealth_column = Person.columns_hash['wealth']
456
+ assert_equal 9, wealth_column.precision
457
+ assert_equal 7, wealth_column.scale
458
+ end
459
+
460
+ def test_native_types
461
+ Person.delete_all
462
+ Person.connection.add_column "people", "last_name", :string
463
+ Person.connection.add_column "people", "bio", :text
464
+ Person.connection.add_column "people", "age", :integer
465
+ Person.connection.add_column "people", "height", :float
466
+ Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
467
+ Person.connection.add_column "people", "birthday", :datetime
468
+ Person.connection.add_column "people", "favorite_day", :date
469
+ Person.connection.add_column "people", "moment_of_truth", :datetime
470
+ Person.connection.add_column "people", "male", :boolean
471
+ Person.reset_column_information
472
+
473
+ assert_nothing_raised do
474
+ Person.create :first_name => 'bob', :last_name => 'bobsen',
475
+ :bio => "I was born ....", :age => 18, :height => 1.78,
476
+ :wealth => BigDecimal.new("12345678901234567890.0123456789"),
477
+ :birthday => 18.years.ago, :favorite_day => 10.days.ago,
478
+ :moment_of_truth => "1782-10-10 21:40:18", :male => true
479
+ end
480
+
481
+ bob = Person.find(:first)
482
+ assert_equal 'bob', bob.first_name
483
+ assert_equal 'bobsen', bob.last_name
484
+ assert_equal "I was born ....", bob.bio
485
+ assert_equal 18, bob.age
486
+
487
+ # Test for 30 significent digits (beyond the 16 of float), 10 of them
488
+ # after the decimal place.
489
+
490
+ unless current_adapter?(:SQLite3Adapter)
491
+ assert_equal BigDecimal.new("0012345678901234567890.0123456789"), bob.wealth
492
+ end
493
+
494
+ assert_equal true, bob.male?
495
+
496
+ assert_equal String, bob.first_name.class
497
+ assert_equal String, bob.last_name.class
498
+ assert_equal String, bob.bio.class
499
+ assert_equal Fixnum, bob.age.class
500
+ assert_equal Time, bob.birthday.class
501
+
502
+ if current_adapter?(:OracleAdapter, :SybaseAdapter)
503
+ # Sybase, and Oracle don't differentiate between date/time
504
+ assert_equal Time, bob.favorite_day.class
505
+ else
506
+ assert_equal Date, bob.favorite_day.class
507
+ end
508
+
509
+ # Test DateTime column and defaults, including timezone.
510
+ # FIXME: moment of truth may be Time on 64-bit platforms.
511
+ if bob.moment_of_truth.is_a?(DateTime)
512
+
513
+ with_env_tz 'US/Eastern' do
514
+ assert_equal DateTime.local_offset, bob.moment_of_truth.offset
515
+ assert_not_equal 0, bob.moment_of_truth.offset
516
+ assert_not_equal "Z", bob.moment_of_truth.zone
517
+ # US/Eastern is -5 hours from GMT
518
+ assert_equal Rational(-5, 24), bob.moment_of_truth.offset
519
+ assert_match /\A-05:?00\Z/, bob.moment_of_truth.zone #ruby 1.8.6 uses HH:MM, prior versions use HHMM
520
+ assert_equal DateTime::ITALY, bob.moment_of_truth.start
521
+ end
522
+ end
523
+
524
+ assert_equal TrueClass, bob.male?.class
525
+ assert_kind_of BigDecimal, bob.wealth
526
+ end
527
+
528
+ if current_adapter?(:MysqlAdapter)
529
+ def test_unabstracted_database_dependent_types
530
+ Person.delete_all
531
+
532
+ ActiveRecord::Migration.add_column :people, :intelligence_quotient, :tinyint
533
+ Person.reset_column_information
534
+ assert_match /tinyint/, Person.columns_hash['intelligence_quotient'].sql_type
535
+ ensure
536
+ ActiveRecord::Migration.remove_column :people, :intelligence_quotient rescue nil
537
+ end
538
+ end
539
+
540
+ def test_add_remove_single_field_using_string_arguments
541
+ assert !Person.column_methods_hash.include?(:last_name)
542
+
543
+ ActiveRecord::Migration.add_column 'people', 'last_name', :string
544
+
545
+ Person.reset_column_information
546
+ assert Person.column_methods_hash.include?(:last_name)
547
+
548
+ ActiveRecord::Migration.remove_column 'people', 'last_name'
549
+
550
+ Person.reset_column_information
551
+ assert !Person.column_methods_hash.include?(:last_name)
552
+ end
553
+
554
+ def test_add_remove_single_field_using_symbol_arguments
555
+ assert !Person.column_methods_hash.include?(:last_name)
556
+
557
+ ActiveRecord::Migration.add_column :people, :last_name, :string
558
+
559
+ Person.reset_column_information
560
+ assert Person.column_methods_hash.include?(:last_name)
561
+
562
+ ActiveRecord::Migration.remove_column :people, :last_name
563
+
564
+ Person.reset_column_information
565
+ assert !Person.column_methods_hash.include?(:last_name)
566
+ end
567
+
568
+ if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
569
+ def test_add_rename
570
+ Person.delete_all
571
+
572
+ begin
573
+ Person.connection.add_column "people", "girlfriend", :string
574
+ Person.reset_column_information
575
+ Person.create :girlfriend => 'bobette'
576
+
577
+ Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
578
+
579
+ Person.reset_column_information
580
+ bob = Person.find(:first)
581
+
582
+ assert_equal "bobette", bob.exgirlfriend
583
+ ensure
584
+ Person.connection.remove_column("people", "girlfriend") rescue nil
585
+ Person.connection.remove_column("people", "exgirlfriend") rescue nil
586
+ end
587
+
588
+ end
589
+
590
+ def test_rename_column_using_symbol_arguments
591
+ begin
592
+ names_before = Person.find(:all).map(&:first_name)
593
+ Person.connection.rename_column :people, :first_name, :nick_name
594
+ Person.reset_column_information
595
+ assert Person.column_names.include?("nick_name")
596
+ assert_equal names_before, Person.find(:all).map(&:nick_name)
597
+ ensure
598
+ Person.connection.remove_column("people","nick_name")
599
+ Person.connection.add_column("people","first_name", :string)
600
+ end
601
+ end
602
+
603
+ def test_rename_column
604
+ begin
605
+ names_before = Person.find(:all).map(&:first_name)
606
+ Person.connection.rename_column "people", "first_name", "nick_name"
607
+ Person.reset_column_information
608
+ assert Person.column_names.include?("nick_name")
609
+ assert_equal names_before, Person.find(:all).map(&:nick_name)
610
+ ensure
611
+ Person.connection.remove_column("people","nick_name")
612
+ Person.connection.add_column("people","first_name", :string)
613
+ end
614
+ end
615
+
616
+ def test_rename_column_preserves_default_value_not_null
617
+ begin
618
+ default_before = Developer.connection.columns("developers").find { |c| c.name == "salary" }.default
619
+ assert_equal 70000, default_before
620
+ Developer.connection.rename_column "developers", "salary", "anual_salary"
621
+ Developer.reset_column_information
622
+ assert Developer.column_names.include?("anual_salary")
623
+ default_after = Developer.connection.columns("developers").find { |c| c.name == "anual_salary" }.default
624
+ assert_equal 70000, default_after
625
+ ensure
626
+ Developer.connection.rename_column "developers", "anual_salary", "salary"
627
+ Developer.reset_column_information
628
+ end
629
+ end
630
+
631
+ def test_rename_nonexistent_column
632
+ ActiveRecord::Base.connection.create_table(:hats) do |table|
633
+ table.column :hat_name, :string, :default => nil
634
+ end
635
+ exception = if current_adapter?(:PostgreSQLAdapter)
636
+ ActiveRecord::StatementInvalid
637
+ else
638
+ ActiveRecord::ActiveRecordError
639
+ end
640
+ assert_raise(exception) do
641
+ Person.connection.rename_column "hats", "nonexistent", "should_fail"
642
+ end
643
+ ensure
644
+ ActiveRecord::Base.connection.drop_table(:hats)
645
+ end
646
+
647
+ def test_rename_column_with_sql_reserved_word
648
+ begin
649
+ assert_nothing_raised { Person.connection.rename_column "people", "first_name", "group" }
650
+ Person.reset_column_information
651
+ assert Person.column_names.include?("group")
652
+ ensure
653
+ Person.connection.remove_column("people", "group") rescue nil
654
+ Person.connection.add_column("people", "first_name", :string) rescue nil
655
+ end
656
+ end
657
+ end
658
+
659
+ unless (current_adapter?(:IBM_DBAdapter)) #Cannot alter a object when there is another object depending on it
660
+ def test_rename_column_with_an_index
661
+ ActiveRecord::Base.connection.create_table(:hats) do |table|
662
+ table.column :hat_name, :string, :limit => 100
663
+ table.column :hat_size, :integer
664
+ end
665
+ Person.connection.add_index :hats, :hat_name
666
+ assert_nothing_raised do
667
+ Person.connection.rename_column "hats", "hat_name", "name"
668
+ end
669
+ ensure
670
+ ActiveRecord::Base.connection.drop_table(:hats)
671
+ end
672
+ end
673
+
674
+ def test_remove_column_with_index
675
+ ActiveRecord::Base.connection.create_table(:hats) do |table|
676
+ table.column :hat_name, :string, :limit => 100
677
+ table.column :hat_size, :integer
678
+ end
679
+ ActiveRecord::Base.connection.add_index "hats", "hat_size"
680
+
681
+ assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
682
+ ensure
683
+ ActiveRecord::Base.connection.drop_table(:hats)
684
+ end
685
+
686
+ unless (current_adapter?(:IBM_DBAdapter)) #Cannot alter a object when there is another object depending on it
687
+ def test_remove_column_with_multi_column_index
688
+ ActiveRecord::Base.connection.create_table(:hats) do |table|
689
+ table.column :hat_name, :string, :limit => 100
690
+ table.column :hat_size, :integer
691
+ table.column :hat_style, :string, :limit => 100
692
+ end
693
+ ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
694
+
695
+ assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
696
+ ensure
697
+ ActiveRecord::Base.connection.drop_table(:hats)
698
+ end
699
+ end
700
+
701
+ unless current_adapter?(:IBM_DBAdapter) #incompatible types changes
702
+ def test_change_type_of_not_null_column
703
+ assert_nothing_raised do
704
+ Topic.connection.change_column "topics", "written_on", :datetime, :null => false
705
+ Topic.reset_column_information
706
+
707
+ Topic.connection.change_column "topics", "written_on", :datetime, :null => false
708
+ Topic.reset_column_information
709
+ end
710
+ end
711
+ end
712
+
713
+ def test_rename_table
714
+ begin
715
+ ActiveRecord::Base.connection.create_table :octopuses do |t|
716
+ t.column :url, :string
717
+ end
718
+ ActiveRecord::Base.connection.rename_table :octopuses, :octopi
719
+
720
+ # Using explicit id in insert for compatibility across all databases
721
+ con = ActiveRecord::Base.connection
722
+ con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
723
+ 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')" }
724
+ con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
725
+
726
+ assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
727
+
728
+ ensure
729
+ ActiveRecord::Base.connection.drop_table :octopuses rescue nil
730
+ ActiveRecord::Base.connection.drop_table :octopi rescue nil
731
+ end
732
+ end
733
+
734
+ def test_change_column_nullability
735
+ Person.delete_all
736
+ Person.connection.add_column "people", "funny", :boolean
737
+ Person.reset_column_information
738
+ assert Person.columns_hash["funny"].null, "Column 'funny' must initially allow nulls"
739
+ unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
740
+ Person.connection.change_column "people", "funny", :boolean, :null => false, :default => true
741
+ Person.reset_column_information
742
+ assert !Person.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point"
743
+ Person.connection.change_column "people", "funny", :boolean, :null => true
744
+ Person.reset_column_information
745
+ assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
746
+ end
747
+ end
748
+
749
+ def test_rename_table_with_an_index
750
+ begin
751
+ ActiveRecord::Base.connection.create_table :octopuses do |t|
752
+ t.column :url, :string
753
+ end
754
+ ActiveRecord::Base.connection.add_index :octopuses, :url
755
+
756
+ ActiveRecord::Base.connection.rename_table :octopuses, :octopi
757
+
758
+ # Using explicit id in insert for compatibility across all databases
759
+ con = ActiveRecord::Base.connection
760
+ con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
761
+ 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')" }
762
+ con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
763
+
764
+ assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
765
+ assert ActiveRecord::Base.connection.indexes(:octopi).first.columns.include?("url")
766
+ ensure
767
+ ActiveRecord::Base.connection.drop_table :octopuses rescue nil
768
+ ActiveRecord::Base.connection.drop_table :octopi rescue nil
769
+ end
770
+ end
771
+
772
+ unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
773
+ def test_change_column
774
+ Person.connection.add_column 'people', 'age', :integer
775
+ old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
776
+ assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
777
+
778
+ assert_nothing_raised { Person.connection.change_column "people", "age", :string }
779
+
780
+ new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
781
+ assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
782
+ assert new_columns.find { |c| c.name == 'age' and c.type == :string }
783
+
784
+ old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
785
+ assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
786
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
787
+ new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
788
+ assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
789
+ assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
790
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
791
+ end
792
+ end
793
+
794
+ def test_change_column_with_nil_default
795
+ Person.connection.add_column "people", "contributor", :boolean, :default => true
796
+ Person.reset_column_information
797
+ assert Person.new.contributor?
798
+ unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
799
+ assert_nothing_raised { Person.connection.change_column "people", "contributor", :boolean, :default => nil }
800
+ Person.reset_column_information
801
+ assert !Person.new.contributor?
802
+ assert_nil Person.new.contributor
803
+ end
804
+ ensure
805
+ Person.connection.remove_column("people", "contributor") rescue nil
806
+ end
807
+
808
+ def test_change_column_with_new_default
809
+ Person.connection.add_column "people", "administrator", :boolean, :default => true
810
+ Person.reset_column_information
811
+ assert Person.new.administrator?
812
+ unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
813
+ assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
814
+ Person.reset_column_information
815
+ assert !Person.new.administrator?
816
+ end
817
+ ensure
818
+ Person.connection.remove_column("people", "administrator") rescue nil
819
+ end
820
+
821
+ def test_change_column_default
822
+ Person.connection.change_column_default "people", "first_name", "Tester"
823
+ Person.reset_column_information
824
+ assert_equal "Tester", Person.new.first_name
825
+ end
826
+
827
+ def test_change_column_quotes_column_names
828
+ Person.connection.create_table :testings do |t|
829
+ t.column :select, :string
830
+ end
831
+ unless current_adapter?(:IBM_DBAdapter) # altering a string column to smaller size
832
+ assert_nothing_raised { Person.connection.change_column :testings, :select, :string, :limit => 10 }
833
+ end
834
+
835
+ assert_nothing_raised { Person.connection.execute "insert into testings (#{Person.connection.quote_column_name('select')}) values ('7 chars')" }
836
+ ensure
837
+ Person.connection.drop_table :testings rescue nil
838
+ end
839
+
840
+ def test_keeping_default_and_notnull_constaint_on_change
841
+ Person.connection.create_table :testings do |t|
842
+ t.column :title, :string
843
+ end
844
+ person_klass = Class.new(Person)
845
+ person_klass.set_table_name 'testings'
846
+
847
+ person_klass.connection.add_column "testings", "wealth", :integer, :null => false, :default => 99
848
+ person_klass.reset_column_information
849
+ assert_equal 99, person_klass.columns_hash["wealth"].default
850
+ assert_equal false, person_klass.columns_hash["wealth"].null
851
+ assert_nothing_raised {person_klass.connection.execute("insert into testings (title) values ('tester')")}
852
+
853
+ # change column default to see that column doesn't lose its not null definition
854
+ person_klass.connection.change_column_default "testings", "wealth", 100
855
+ person_klass.reset_column_information
856
+ assert_equal 100, person_klass.columns_hash["wealth"].default
857
+ assert_equal false, person_klass.columns_hash["wealth"].null
858
+
859
+ # rename column to see that column doesn't lose its not null and/or default definition
860
+ if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
861
+ person_klass.connection.rename_column "testings", "wealth", "money"
862
+ person_klass.reset_column_information
863
+ assert_nil person_klass.columns_hash["wealth"]
864
+ assert_equal 100, person_klass.columns_hash["money"].default
865
+ assert_equal false, person_klass.columns_hash["money"].null
866
+ end
867
+
868
+ # change column
869
+ unless (current_adapter?(:IBM_DBAdapter) && !@ibm_db_rename_supported)
870
+ person_klass.connection.change_column "testings", "money", :integer, :null => false, :default => 1000
871
+ person_klass.reset_column_information
872
+ assert_equal 1000, person_klass.columns_hash["money"].default
873
+ assert_equal false, person_klass.columns_hash["money"].null
874
+ else
875
+ person_klass.connection.change_column "testings", "wealth", :decimal, :precision => 15, :scale => 1,:null => false, :default => 1000
876
+ person_klass.reset_column_information
877
+ assert_equal 1000, person_klass.columns_hash["wealth"].default
878
+ assert_equal false, person_klass.columns_hash["wealth"].null
879
+ end
880
+
881
+ # change column, make it nullable and clear default
882
+ unless (current_adapter?(:IBM_DBAdapter) && !@ibm_db_rename_supported)
883
+ person_klass.connection.change_column "testings", "money", :integer, :null => true, :default => nil
884
+ person_klass.reset_column_information
885
+ assert_nil person_klass.columns_hash["money"].default
886
+ assert_equal true, person_klass.columns_hash["money"].null
887
+ else
888
+ person_klass.connection.change_column "testings", "wealth", :decimal, :precision => 20, :scale => 2, :null => true, :default => nil
889
+ person_klass.reset_column_information
890
+ assert_nil person_klass.columns_hash["wealth"].default
891
+ assert_equal true, person_klass.columns_hash["wealth"].null
892
+ end
893
+
894
+ # change_column_null, make it not nullable and set null values to a default value
895
+ unless (current_adapter?(:IBM_DBAdapter) && !@ibm_db_rename_supported)
896
+ person_klass.connection.execute('UPDATE testings SET money = NULL')
897
+ person_klass.connection.change_column_null "testings", "money", false, 2000
898
+ person_klass.reset_column_information
899
+ assert_nil person_klass.columns_hash["money"].default
900
+ assert_equal false, person_klass.columns_hash["money"].null
901
+ assert_equal [2000], Person.connection.select_values("SELECT money FROM testings").map { |s| s.to_i }.sort
902
+ else
903
+ # Trying to set the value of the column wealth to NULL and
904
+ # in the next statement a not null constraint is being applied which is wrong.
905
+ #person_klass.connection.execute('UPDATE testings SET wealth = NULL')
906
+ person_klass.connection.change_column_null "testings", "wealth", false, 2000
907
+ person_klass.reset_column_information
908
+ assert_equal false, person_klass.columns_hash["wealth"].null
909
+ assert_equal 2000, person_klass.columns_hash["wealth"].default
910
+ end
911
+ ensure
912
+ Person.connection.drop_table :testings rescue nil
913
+ end
914
+
915
+ def test_change_column_default_to_null
916
+ if current_adapter?(:IBM_DBAdapter)
917
+ #Ensure that first_name had some default value else an error is thrown saying operation not valid
918
+ Person.connection.change_column_default "people", "first_name", "foo"
919
+ end
920
+ Person.connection.change_column_default "people", "first_name", nil
921
+ Person.reset_column_information
922
+ assert_nil Person.new.first_name
923
+ end
924
+
925
+ def test_add_table
926
+ assert !Reminder.table_exists?
927
+
928
+ WeNeedReminders.up
929
+
930
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
931
+ assert_equal "hello world", Reminder.find(:first).content
932
+
933
+ WeNeedReminders.down
934
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
935
+ end
936
+
937
+ def test_add_table_with_decimals
938
+ Person.connection.drop_table :big_numbers rescue nil
939
+
940
+ assert !BigNumber.table_exists?
941
+ GiveMeBigNumbers.up
942
+
943
+ assert BigNumber.create(
944
+ :bank_balance => 1586.43,
945
+ :big_bank_balance => BigDecimal("1000234000567.95"),
946
+ :world_population => 6000000000,
947
+ :my_house_population => 3,
948
+ :value_of_e => BigDecimal("2.7182818284590452353602875")
949
+ )
950
+
951
+ b = BigNumber.find(:first)
952
+ assert_not_nil b
953
+
954
+ assert_not_nil b.bank_balance
955
+ assert_not_nil b.big_bank_balance
956
+ assert_not_nil b.world_population
957
+ assert_not_nil b.my_house_population
958
+ assert_not_nil b.value_of_e
959
+
960
+ # TODO: set world_population >= 2**62 to cover 64-bit platforms and test
961
+ # is_a?(Bignum)
962
+ unless current_adapter?(:IBM_DBAdapter) # incompatible types retrieved
963
+ assert_kind_of Integer, b.world_population
964
+ else
965
+ assert_kind_of BigDecimal, b.world_population
966
+ end
967
+ assert_equal 6000000000, b.world_population
968
+ unless current_adapter?(:IBM_DBAdapter) # incompatible types retrieved
969
+ assert_kind_of Fixnum, b.my_house_population
970
+ else
971
+ assert_kind_of BigDecimal, b.my_house_population
972
+ end
973
+ assert_equal 3, b.my_house_population
974
+ assert_kind_of BigDecimal, b.bank_balance
975
+ assert_equal BigDecimal("1586.43"), b.bank_balance
976
+ assert_kind_of BigDecimal, b.big_bank_balance
977
+ assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
978
+
979
+ # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with
980
+ # precision/scale explicitly left out. By the SQL standard, numbers
981
+ # assigned to this field should be truncated but that's seldom respected.
982
+ if current_adapter?(:PostgreSQLAdapter, :SQLite2Adapter)
983
+ # - PostgreSQL changes the SQL spec on columns declared simply as
984
+ # "decimal" to something more useful: instead of being given a scale
985
+ # of 0, they take on the compile-time limit for precision and scale,
986
+ # so the following should succeed unless you have used really wacky
987
+ # compilation options
988
+ # - SQLite2 has the default behavior of preserving all data sent in,
989
+ # so this happens there too
990
+ assert_kind_of BigDecimal, b.value_of_e
991
+ assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
992
+ elsif current_adapter?(:SQLiteAdapter)
993
+ # - SQLite3 stores a float, in violation of SQL
994
+ assert_kind_of BigDecimal, b.value_of_e
995
+ assert_equal BigDecimal("2.71828182845905"), b.value_of_e
996
+ else
997
+ # - SQL standard is an integer
998
+ unless current_adapter?(:IBM_DBAdapter) # incompatible types retrieved
999
+ assert_kind_of Fixnum, b.value_of_e
1000
+ else
1001
+ assert_kind_of BigDecimal, b.value_of_e
1002
+ end
1003
+ assert_equal 2, b.value_of_e
1004
+ end
1005
+
1006
+ GiveMeBigNumbers.down
1007
+ assert_raise(ActiveRecord::StatementInvalid) { BigNumber.find(:first) }
1008
+ end
1009
+
1010
+ def test_migrator
1011
+ assert !Person.column_methods_hash.include?(:last_name)
1012
+ assert !Reminder.table_exists?
1013
+
1014
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid")
1015
+
1016
+ assert_equal 3, ActiveRecord::Migrator.current_version
1017
+ Person.reset_column_information
1018
+ assert Person.column_methods_hash.include?(:last_name)
1019
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
1020
+ assert_equal "hello world", Reminder.find(:first).content
1021
+
1022
+ ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid")
1023
+
1024
+ assert_equal 0, ActiveRecord::Migrator.current_version
1025
+ Person.reset_column_information
1026
+ assert !Person.column_methods_hash.include?(:last_name)
1027
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
1028
+ end
1029
+
1030
+ def test_migrator_one_up
1031
+ assert !Person.column_methods_hash.include?(:last_name)
1032
+ assert !Reminder.table_exists?
1033
+
1034
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1035
+
1036
+ Person.reset_column_information
1037
+ assert Person.column_methods_hash.include?(:last_name)
1038
+ assert !Reminder.table_exists?
1039
+
1040
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 2)
1041
+
1042
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
1043
+ assert_equal "hello world", Reminder.find(:first).content
1044
+ end
1045
+
1046
+ def test_migrator_one_down
1047
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid")
1048
+
1049
+ ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 1)
1050
+
1051
+ Person.reset_column_information
1052
+ assert Person.column_methods_hash.include?(:last_name)
1053
+ assert !Reminder.table_exists?
1054
+ end
1055
+
1056
+ def test_migrator_one_up_one_down
1057
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1058
+ ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
1059
+
1060
+ assert !Person.column_methods_hash.include?(:last_name)
1061
+ assert !Reminder.table_exists?
1062
+ end
1063
+
1064
+ def test_migrator_double_up
1065
+ assert_equal(0, ActiveRecord::Migrator.current_version)
1066
+ ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1)
1067
+ assert_nothing_raised { ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1) }
1068
+ assert_equal(1, ActiveRecord::Migrator.current_version)
1069
+ end
1070
+
1071
+ def test_migrator_double_down
1072
+ assert_equal(0, ActiveRecord::Migrator.current_version)
1073
+ ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/valid", 1)
1074
+ ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT + "/valid", 1)
1075
+ assert_nothing_raised { ActiveRecord::Migrator.run(:down, MIGRATIONS_ROOT + "/valid", 1) }
1076
+ assert_equal(0, ActiveRecord::Migrator.current_version)
1077
+ end
1078
+
1079
+ if ActiveRecord::Base.connection.supports_ddl_transactions?
1080
+ def test_migrator_one_up_with_exception_and_rollback
1081
+ assert !Person.column_methods_hash.include?(:last_name)
1082
+
1083
+ e = assert_raise(StandardError) do
1084
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/broken", 100)
1085
+ end
1086
+
1087
+ assert_equal "An error has occurred, this and all later migrations canceled:\n\nSomething broke", e.message
1088
+
1089
+ Person.reset_column_information
1090
+ assert !Person.column_methods_hash.include?(:last_name)
1091
+ end
1092
+ end
1093
+
1094
+ def test_finds_migrations
1095
+ migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid").migrations
1096
+
1097
+ [[1, 'PeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i|
1098
+ assert_equal migrations[i].version, pair.first
1099
+ assert_equal migrations[i].name, pair.last
1100
+ end
1101
+ end
1102
+
1103
+ def test_finds_pending_migrations
1104
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2", 1)
1105
+ migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/interleaved/pass_2").pending_migrations
1106
+ assert_equal 1, migrations.size
1107
+ assert_equal migrations[0].version, 3
1108
+ assert_equal migrations[0].name, 'InnocentJointable'
1109
+ end
1110
+
1111
+ def test_only_loads_pending_migrations
1112
+ # migrate up to 1
1113
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1114
+
1115
+ # now unload the migrations that have been defined
1116
+ PeopleHaveLastNames.unloadable
1117
+ ActiveSupport::Dependencies.remove_unloadable_constants!
1118
+
1119
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", nil)
1120
+
1121
+ assert !defined? PeopleHaveLastNames
1122
+
1123
+ %w(WeNeedReminders, InnocentJointable).each do |migration|
1124
+ assert defined? migration
1125
+ end
1126
+
1127
+ ensure
1128
+ load(MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
1129
+ end
1130
+
1131
+ def test_migrator_interleaved_migrations
1132
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_1")
1133
+
1134
+ assert_nothing_raised do
1135
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2")
1136
+ end
1137
+
1138
+ Person.reset_column_information
1139
+ assert Person.column_methods_hash.include?(:last_name)
1140
+
1141
+ assert_nothing_raised do
1142
+ ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/interleaved/pass_3")
1143
+ end
1144
+ end
1145
+
1146
+ def test_migrator_db_has_no_schema_migrations_table
1147
+ ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations;")
1148
+ assert_nothing_raised do
1149
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 1)
1150
+ end
1151
+ end
1152
+
1153
+ def test_migrator_verbosity
1154
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1155
+ assert PeopleHaveLastNames.message_count > 0
1156
+ PeopleHaveLastNames.message_count = 0
1157
+
1158
+ ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
1159
+ assert PeopleHaveLastNames.message_count > 0
1160
+ PeopleHaveLastNames.message_count = 0
1161
+ end
1162
+
1163
+ def test_migrator_verbosity_off
1164
+ PeopleHaveLastNames.verbose = false
1165
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1166
+ assert PeopleHaveLastNames.message_count.zero?
1167
+ ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
1168
+ assert PeopleHaveLastNames.message_count.zero?
1169
+ end
1170
+
1171
+ def test_migrator_going_down_due_to_version_target
1172
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1173
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
1174
+
1175
+ assert !Person.column_methods_hash.include?(:last_name)
1176
+ assert !Reminder.table_exists?
1177
+
1178
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid")
1179
+
1180
+ Person.reset_column_information
1181
+ assert Person.column_methods_hash.include?(:last_name)
1182
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
1183
+ assert_equal "hello world", Reminder.find(:first).content
1184
+ end
1185
+
1186
+ def test_migrator_rollback
1187
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid")
1188
+ assert_equal(3, ActiveRecord::Migrator.current_version)
1189
+
1190
+ ActiveRecord::Migrator.rollback(MIGRATIONS_ROOT + "/valid")
1191
+ assert_equal(2, ActiveRecord::Migrator.current_version)
1192
+
1193
+ ActiveRecord::Migrator.rollback(MIGRATIONS_ROOT + "/valid")
1194
+ assert_equal(1, ActiveRecord::Migrator.current_version)
1195
+
1196
+ ActiveRecord::Migrator.rollback(MIGRATIONS_ROOT + "/valid")
1197
+ assert_equal(0, ActiveRecord::Migrator.current_version)
1198
+
1199
+ ActiveRecord::Migrator.rollback(MIGRATIONS_ROOT + "/valid")
1200
+ assert_equal(0, ActiveRecord::Migrator.current_version)
1201
+ end
1202
+
1203
+ def test_schema_migrations_table_name
1204
+ ActiveRecord::Base.table_name_prefix = "prefix_"
1205
+ ActiveRecord::Base.table_name_suffix = "_suffix"
1206
+ Reminder.reset_table_name
1207
+ assert_equal "prefix_schema_migrations_suffix", ActiveRecord::Migrator.schema_migrations_table_name
1208
+ ActiveRecord::Base.table_name_prefix = ""
1209
+ ActiveRecord::Base.table_name_suffix = ""
1210
+ Reminder.reset_table_name
1211
+ assert_equal "schema_migrations", ActiveRecord::Migrator.schema_migrations_table_name
1212
+ ensure
1213
+ ActiveRecord::Base.table_name_prefix = ""
1214
+ ActiveRecord::Base.table_name_suffix = ""
1215
+ end
1216
+
1217
+ def test_proper_table_name
1218
+ assert_equal "table", ActiveRecord::Migrator.proper_table_name('table')
1219
+ assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table)
1220
+ assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder)
1221
+ Reminder.reset_table_name
1222
+ assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder)
1223
+
1224
+ # Use the model's own prefix/suffix if a model is given
1225
+ ActiveRecord::Base.table_name_prefix = "ARprefix_"
1226
+ ActiveRecord::Base.table_name_suffix = "_ARsuffix"
1227
+ Reminder.table_name_prefix = 'prefix_'
1228
+ Reminder.table_name_suffix = '_suffix'
1229
+ Reminder.reset_table_name
1230
+ assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder)
1231
+ Reminder.table_name_prefix = ''
1232
+ Reminder.table_name_suffix = ''
1233
+ Reminder.reset_table_name
1234
+
1235
+ # Use AR::Base's prefix/suffix if string or symbol is given
1236
+ ActiveRecord::Base.table_name_prefix = "prefix_"
1237
+ ActiveRecord::Base.table_name_suffix = "_suffix"
1238
+ Reminder.reset_table_name
1239
+ assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table')
1240
+ assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table)
1241
+ ActiveRecord::Base.table_name_prefix = ""
1242
+ ActiveRecord::Base.table_name_suffix = ""
1243
+ Reminder.reset_table_name
1244
+ end
1245
+
1246
+ def test_add_drop_table_with_prefix_and_suffix
1247
+ assert !Reminder.table_exists?
1248
+ ActiveRecord::Base.table_name_prefix = 'prefix_'
1249
+ ActiveRecord::Base.table_name_suffix = '_suffix'
1250
+ Reminder.reset_table_name
1251
+ Reminder.reset_sequence_name
1252
+ WeNeedReminders.up
1253
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
1254
+ assert_equal "hello world", Reminder.find(:first).content
1255
+
1256
+ WeNeedReminders.down
1257
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
1258
+ ensure
1259
+ ActiveRecord::Base.table_name_prefix = ''
1260
+ ActiveRecord::Base.table_name_suffix = ''
1261
+ Reminder.reset_table_name
1262
+ Reminder.reset_sequence_name
1263
+ end
1264
+
1265
+ def test_create_table_with_binary_column
1266
+ Person.connection.drop_table :binary_testings rescue nil
1267
+
1268
+ assert_nothing_raised {
1269
+ Person.connection.create_table :binary_testings do |t|
1270
+ t.column "data", :binary, :null => false
1271
+ end
1272
+ }
1273
+
1274
+ columns = Person.connection.columns(:binary_testings)
1275
+ data_column = columns.detect { |c| c.name == "data" }
1276
+
1277
+ if current_adapter?(:MysqlAdapter)
1278
+ assert_equal '', data_column.default
1279
+ else
1280
+ assert_nil data_column.default
1281
+ end
1282
+
1283
+ Person.connection.drop_table :binary_testings rescue nil
1284
+ end
1285
+
1286
+ def test_migrator_with_duplicates
1287
+ assert_raise(ActiveRecord::DuplicateMigrationVersionError) do
1288
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/duplicate", nil)
1289
+ end
1290
+ end
1291
+
1292
+ def test_migrator_with_duplicate_names
1293
+ assert_raise(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do
1294
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/duplicate_names", nil)
1295
+ end
1296
+ end
1297
+
1298
+ def test_migrator_with_missing_version_numbers
1299
+ assert_raise(ActiveRecord::UnknownMigrationVersionError) do
1300
+ ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/missing", 500)
1301
+ end
1302
+ end
1303
+
1304
+ def test_create_table_with_custom_sequence_name
1305
+ return unless current_adapter? :OracleAdapter
1306
+
1307
+ # table name is 29 chars, the standard sequence name will
1308
+ # be 33 chars and fail
1309
+ assert_raise(ActiveRecord::StatementInvalid) do
1310
+ begin
1311
+ Person.connection.create_table :table_with_name_thats_just_ok do |t|
1312
+ t.column :foo, :string, :null => false
1313
+ end
1314
+ ensure
1315
+ Person.connection.drop_table :table_with_name_thats_just_ok rescue nil
1316
+ end
1317
+ end
1318
+
1319
+ # should be all good w/ a custom sequence name
1320
+ assert_nothing_raised do
1321
+ begin
1322
+ Person.connection.create_table :table_with_name_thats_just_ok,
1323
+ :sequence_name => 'suitably_short_seq' do |t|
1324
+ t.column :foo, :string, :null => false
1325
+ end
1326
+
1327
+ Person.connection.execute("select suitably_short_seq.nextval from dual")
1328
+
1329
+ ensure
1330
+ Person.connection.drop_table :table_with_name_thats_just_ok,
1331
+ :sequence_name => 'suitably_short_seq' rescue nil
1332
+ end
1333
+ end
1334
+
1335
+ # confirm the custom sequence got dropped
1336
+ assert_raise(ActiveRecord::StatementInvalid) do
1337
+ Person.connection.execute("select suitably_short_seq.nextval from dual")
1338
+ end
1339
+ end
1340
+
1341
+ protected
1342
+ def with_env_tz(new_tz = 'US/Eastern')
1343
+ old_tz, ENV['TZ'] = ENV['TZ'], new_tz
1344
+ yield
1345
+ ensure
1346
+ old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
1347
+ end
1348
+
1349
+ end
1350
+
1351
+ class SexyMigrationsTest < ActiveRecord::TestCase
1352
+ def test_references_column_type_adds_id
1353
+ with_new_table do |t|
1354
+ t.expects(:column).with('customer_id', :integer, {})
1355
+ t.references :customer
1356
+ end
1357
+ end
1358
+
1359
+ def test_references_column_type_with_polymorphic_adds_type
1360
+ with_new_table do |t|
1361
+ t.expects(:column).with('taggable_type', :string, {})
1362
+ t.expects(:column).with('taggable_id', :integer, {})
1363
+ t.references :taggable, :polymorphic => true
1364
+ end
1365
+ end
1366
+
1367
+ def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
1368
+ with_new_table do |t|
1369
+ t.expects(:column).with('taggable_type', :string, {:null => false})
1370
+ t.expects(:column).with('taggable_id', :integer, {:null => false})
1371
+ t.references :taggable, :polymorphic => true, :null => false
1372
+ end
1373
+ end
1374
+
1375
+ def test_belongs_to_works_like_references
1376
+ with_new_table do |t|
1377
+ t.expects(:column).with('customer_id', :integer, {})
1378
+ t.belongs_to :customer
1379
+ end
1380
+ end
1381
+
1382
+ def test_timestamps_creates_updated_at_and_created_at
1383
+ with_new_table do |t|
1384
+ t.expects(:column).with(:created_at, :datetime, kind_of(Hash))
1385
+ t.expects(:column).with(:updated_at, :datetime, kind_of(Hash))
1386
+ t.timestamps
1387
+ end
1388
+ end
1389
+
1390
+ def test_integer_creates_integer_column
1391
+ with_new_table do |t|
1392
+ t.expects(:column).with(:foo, 'integer', {})
1393
+ t.expects(:column).with(:bar, 'integer', {})
1394
+ t.integer :foo, :bar
1395
+ end
1396
+ end
1397
+
1398
+ def test_string_creates_string_column
1399
+ with_new_table do |t|
1400
+ t.expects(:column).with(:foo, 'string', {})
1401
+ t.expects(:column).with(:bar, 'string', {})
1402
+ t.string :foo, :bar
1403
+ end
1404
+ end
1405
+
1406
+ protected
1407
+ def with_new_table
1408
+ Person.connection.create_table :delete_me, :force => true do |t|
1409
+ yield t
1410
+ end
1411
+ ensure
1412
+ Person.connection.drop_table :delete_me rescue nil
1413
+ end
1414
+
1415
+ end # SexyMigrationsTest
1416
+
1417
+ class ChangeTableMigrationsTest < ActiveRecord::TestCase
1418
+ def setup
1419
+ @connection = Person.connection
1420
+ @connection.create_table :delete_me, :force => true do |t|
1421
+ end
1422
+ end
1423
+
1424
+ def teardown
1425
+ Person.connection.drop_table :delete_me rescue nil
1426
+ end
1427
+
1428
+ def test_references_column_type_adds_id
1429
+ with_change_table do |t|
1430
+ @connection.expects(:add_column).with(:delete_me, 'customer_id', :integer, {})
1431
+ t.references :customer
1432
+ end
1433
+ end
1434
+
1435
+ def test_remove_references_column_type_removes_id
1436
+ with_change_table do |t|
1437
+ @connection.expects(:remove_column).with(:delete_me, 'customer_id')
1438
+ t.remove_references :customer
1439
+ end
1440
+ end
1441
+
1442
+ def test_add_belongs_to_works_like_add_references
1443
+ with_change_table do |t|
1444
+ @connection.expects(:add_column).with(:delete_me, 'customer_id', :integer, {})
1445
+ t.belongs_to :customer
1446
+ end
1447
+ end
1448
+
1449
+ def test_remove_belongs_to_works_like_remove_references
1450
+ with_change_table do |t|
1451
+ @connection.expects(:remove_column).with(:delete_me, 'customer_id')
1452
+ t.remove_belongs_to :customer
1453
+ end
1454
+ end
1455
+
1456
+ def test_references_column_type_with_polymorphic_adds_type
1457
+ with_change_table do |t|
1458
+ @connection.expects(:add_column).with(:delete_me, 'taggable_type', :string, {})
1459
+ @connection.expects(:add_column).with(:delete_me, 'taggable_id', :integer, {})
1460
+ t.references :taggable, :polymorphic => true
1461
+ end
1462
+ end
1463
+
1464
+ def test_remove_references_column_type_with_polymorphic_removes_type
1465
+ with_change_table do |t|
1466
+ @connection.expects(:remove_column).with(:delete_me, 'taggable_type')
1467
+ @connection.expects(:remove_column).with(:delete_me, 'taggable_id')
1468
+ t.remove_references :taggable, :polymorphic => true
1469
+ end
1470
+ end
1471
+
1472
+ def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
1473
+ with_change_table do |t|
1474
+ @connection.expects(:add_column).with(:delete_me, 'taggable_type', :string, {:null => false})
1475
+ @connection.expects(:add_column).with(:delete_me, 'taggable_id', :integer, {:null => false})
1476
+ t.references :taggable, :polymorphic => true, :null => false
1477
+ end
1478
+ end
1479
+
1480
+ def test_remove_references_column_type_with_polymorphic_and_options_null_is_false_removes_table_flag
1481
+ with_change_table do |t|
1482
+ @connection.expects(:remove_column).with(:delete_me, 'taggable_type')
1483
+ @connection.expects(:remove_column).with(:delete_me, 'taggable_id')
1484
+ t.remove_references :taggable, :polymorphic => true, :null => false
1485
+ end
1486
+ end
1487
+
1488
+ def test_timestamps_creates_updated_at_and_created_at
1489
+ with_change_table do |t|
1490
+ @connection.expects(:add_timestamps).with(:delete_me)
1491
+ t.timestamps
1492
+ end
1493
+ end
1494
+
1495
+ def test_remove_timestamps_creates_updated_at_and_created_at
1496
+ with_change_table do |t|
1497
+ @connection.expects(:remove_timestamps).with(:delete_me)
1498
+ t.remove_timestamps
1499
+ end
1500
+ end
1501
+
1502
+ def string_column
1503
+ if current_adapter?(:PostgreSQLAdapter)
1504
+ "character varying(255)"
1505
+ else
1506
+ 'varchar(255)'
1507
+ end
1508
+ end
1509
+
1510
+ def integer_column
1511
+ if current_adapter?(:MysqlAdapter)
1512
+ 'int(11)'
1513
+ else
1514
+ 'integer'
1515
+ end
1516
+ end
1517
+
1518
+ def test_integer_creates_integer_column
1519
+ with_change_table do |t|
1520
+ @connection.expects(:add_column).with(:delete_me, :foo, integer_column, {})
1521
+ @connection.expects(:add_column).with(:delete_me, :bar, integer_column, {})
1522
+ t.integer :foo, :bar
1523
+ end
1524
+ end
1525
+
1526
+ def test_string_creates_string_column
1527
+ with_change_table do |t|
1528
+ @connection.expects(:add_column).with(:delete_me, :foo, string_column, {})
1529
+ @connection.expects(:add_column).with(:delete_me, :bar, string_column, {})
1530
+ t.string :foo, :bar
1531
+ end
1532
+ end
1533
+
1534
+ def test_column_creates_column
1535
+ with_change_table do |t|
1536
+ @connection.expects(:add_column).with(:delete_me, :bar, :integer, {})
1537
+ t.column :bar, :integer
1538
+ end
1539
+ end
1540
+
1541
+ def test_column_creates_column_with_options
1542
+ with_change_table do |t|
1543
+ @connection.expects(:add_column).with(:delete_me, :bar, :integer, {:null => false})
1544
+ t.column :bar, :integer, :null => false
1545
+ end
1546
+ end
1547
+
1548
+ def test_index_creates_index
1549
+ with_change_table do |t|
1550
+ @connection.expects(:add_index).with(:delete_me, :bar, {})
1551
+ t.index :bar
1552
+ end
1553
+ end
1554
+
1555
+ def test_index_creates_index_with_options
1556
+ with_change_table do |t|
1557
+ @connection.expects(:add_index).with(:delete_me, :bar, {:unique => true})
1558
+ t.index :bar, :unique => true
1559
+ end
1560
+ end
1561
+
1562
+ def test_change_changes_column
1563
+ with_change_table do |t|
1564
+ @connection.expects(:change_column).with(:delete_me, :bar, :string, {})
1565
+ t.change :bar, :string
1566
+ end
1567
+ end
1568
+
1569
+ def test_change_changes_column_with_options
1570
+ with_change_table do |t|
1571
+ @connection.expects(:change_column).with(:delete_me, :bar, :string, {:null => true})
1572
+ t.change :bar, :string, :null => true
1573
+ end
1574
+ end
1575
+
1576
+ def test_change_default_changes_column
1577
+ with_change_table do |t|
1578
+ @connection.expects(:change_column_default).with(:delete_me, :bar, :string)
1579
+ t.change_default :bar, :string
1580
+ end
1581
+ end
1582
+
1583
+ def test_remove_drops_single_column
1584
+ with_change_table do |t|
1585
+ @connection.expects(:remove_column).with(:delete_me, [:bar])
1586
+ t.remove :bar
1587
+ end
1588
+ end
1589
+
1590
+ def test_remove_drops_multiple_columns
1591
+ with_change_table do |t|
1592
+ @connection.expects(:remove_column).with(:delete_me, [:bar, :baz])
1593
+ t.remove :bar, :baz
1594
+ end
1595
+ end
1596
+
1597
+ def test_remove_index_removes_index_with_options
1598
+ with_change_table do |t|
1599
+ @connection.expects(:remove_index).with(:delete_me, {:unique => true})
1600
+ t.remove_index :unique => true
1601
+ end
1602
+ end
1603
+
1604
+ def test_rename_renames_column
1605
+ with_change_table do |t|
1606
+ @connection.expects(:rename_column).with(:delete_me, :bar, :baz)
1607
+ t.rename :bar, :baz
1608
+ end
1609
+ end
1610
+
1611
+ protected
1612
+ def with_change_table
1613
+ Person.connection.change_table :delete_me do |t|
1614
+ yield t
1615
+ end
1616
+ end
1617
+ end
1618
+ end