db2 2.6.2 → 2.7.0

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 (41) hide show
  1. data/CHANGES +17 -0
  2. data/README +79 -141
  3. data/ext/Makefile.nt32 +3 -3
  4. data/ext/Makefile.nt32.191 +212 -0
  5. data/ext/extconf.rb +75 -14
  6. data/ext/ibm_db.c +504 -47
  7. data/ext/ruby_ibm_db.h +4 -1
  8. data/ext/ruby_ibm_db_cli.c +108 -1
  9. data/ext/ruby_ibm_db_cli.h +54 -1
  10. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +423 -124
  11. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1 -1
  12. data/test/cases/adapter_test.rb +169 -164
  13. data/test/cases/associations/belongs_to_associations_test.rb +268 -43
  14. data/test/cases/associations/cascaded_eager_loading_test.rb +31 -33
  15. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +90 -156
  16. data/test/cases/associations/join_model_test.rb +100 -150
  17. data/test/cases/attribute_methods_test.rb +259 -58
  18. data/test/cases/base_test.rb +785 -138
  19. data/test/cases/calculations_test.rb +128 -8
  20. data/test/cases/migration_test.rb +680 -286
  21. data/test/cases/persistence_test.rb +642 -0
  22. data/test/cases/query_cache_test.rb +257 -0
  23. data/test/cases/relations_test.rb +1182 -0
  24. data/test/cases/schema_dumper_test.rb +41 -17
  25. data/test/cases/transaction_callbacks_test.rb +300 -0
  26. data/test/cases/validations/uniqueness_validation_test.rb +38 -22
  27. data/test/cases/xml_serialization_test.rb +408 -0
  28. data/test/config.yml +154 -0
  29. data/test/connections/native_ibm_db/connection.rb +2 -0
  30. data/test/models/warehouse_thing.rb +4 -4
  31. data/test/schema/i5/ibm_db_specific_schema.rb +3 -1
  32. data/test/schema/ids/ibm_db_specific_schema.rb +3 -1
  33. data/test/schema/luw/ibm_db_specific_schema.rb +2 -0
  34. data/test/schema/schema.rb +196 -92
  35. data/test/schema/zOS/ibm_db_specific_schema.rb +3 -1
  36. metadata +73 -68
  37. data/.gitignore +0 -1
  38. data/test/cases/associations/eager_test.rb +0 -862
  39. data/test/cases/associations/has_many_through_associations_test.rb +0 -461
  40. data/test/cases/finder_test.rb +0 -1088
  41. data/test/cases/fixtures_test.rb +0 -684
@@ -1,5 +1,6 @@
1
1
  require "cases/helper"
2
2
  require 'models/company'
3
+ require "models/contract"
3
4
  require 'models/topic'
4
5
  require 'models/edge'
5
6
  require 'models/club'
@@ -23,6 +24,18 @@ class CalculationsTest < ActiveRecord::TestCase
23
24
  assert_equal 53.0, value
24
25
  end
25
26
 
27
+ def test_should_return_decimal_average_of_integer_field
28
+ return if current_adapter?(:IBM_DBAdapter) #average cannot be a decimal value when applied on integer field
29
+ value = Account.average(:id)
30
+ assert_equal 3.5, value
31
+ end
32
+
33
+ def test_should_return_integer_average_if_db_returns_such
34
+ Account.connection.stubs :select_value => 3
35
+ value = Account.average(:id)
36
+ assert_equal 3, value
37
+ end
38
+
26
39
  def test_should_return_nil_as_average
27
40
  assert_nil NumericData.average(:bank_balance)
28
41
  end
@@ -55,6 +68,19 @@ class CalculationsTest < ActiveRecord::TestCase
55
68
  [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
56
69
  end
57
70
 
71
+ def test_should_group_by_multiple_fields
72
+ c = Account.count(:all, :group => ['firm_id', :credit_limit])
73
+ [ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) }
74
+ end
75
+
76
+ def test_should_group_by_multiple_fields_having_functions
77
+ c = Topic.group(:author_name, 'COALESCE(type, title)').count(:all)
78
+ assert_equal 1, c[["Carl", "The Third Topic of the day"]]
79
+ assert_equal 1, c[["Mary", "Reply"]]
80
+ assert_equal 1, c[["David", "The First Topic"]]
81
+ assert_equal 1, c[["Carl", "Reply"]]
82
+ end
83
+
58
84
  def test_should_group_by_summed_field
59
85
  c = Account.sum(:credit_limit, :group => :firm_id)
60
86
  assert_equal 50, c[1]
@@ -85,6 +111,51 @@ class CalculationsTest < ActiveRecord::TestCase
85
111
  assert_equal [2, 6], c.keys.compact
86
112
  end
87
113
 
114
+ def test_limit_should_apply_before_count
115
+ accounts = Account.limit(3).where('firm_id IS NOT NULL')
116
+
117
+ assert_equal 3, accounts.count(:firm_id)
118
+ assert_equal 3, accounts.select(:firm_id).count
119
+ end
120
+
121
+ def test_count_should_shortcut_with_limit_zero
122
+ accounts = Account.limit(0)
123
+
124
+ assert_no_queries { assert_equal 0, accounts.count }
125
+ end
126
+
127
+ def test_limit_is_kept
128
+ return if current_adapter?(:OracleAdapter, :IBM_DBAdapter)
129
+
130
+ queries = assert_sql { Account.limit(1).count }
131
+ assert_equal 1, queries.length
132
+ assert_match(/LIMIT/, queries.first)
133
+ end
134
+
135
+ def test_offset_is_kept
136
+ return if current_adapter?(:OracleAdapter,:IBM_DBAdapter)
137
+
138
+ queries = assert_sql { Account.offset(1).count }
139
+ assert_equal 1, queries.length
140
+ assert_match(/OFFSET/, queries.first)
141
+ end
142
+
143
+ def test_limit_with_offset_is_kept
144
+ return if current_adapter?(:OracleAdapter,:IBM_DBAdapter)
145
+
146
+ queries = assert_sql { Account.limit(1).offset(1).count }
147
+ assert_equal 1, queries.length
148
+ assert_match(/LIMIT/, queries.first)
149
+ assert_match(/OFFSET/, queries.first)
150
+ end
151
+
152
+ def test_no_limit_no_offset
153
+ queries = assert_sql { Account.count }
154
+ assert_equal 1, queries.length
155
+ assert_no_match(/LIMIT/, queries.first)
156
+ assert_no_match(/OFFSET/, queries.first)
157
+ end
158
+
88
159
  def test_should_group_by_summed_field_having_condition
89
160
  c = Account.sum(:credit_limit, :group => :firm_id,
90
161
  :having => 'sum(credit_limit) > 50')
@@ -101,6 +172,13 @@ class CalculationsTest < ActiveRecord::TestCase
101
172
  assert_equal 60, c[2]
102
173
  end
103
174
 
175
+ def test_should_group_by_summed_field_having_condition_from_select
176
+ c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("MIN(credit_limit) > 50").sum(:credit_limit)
177
+ assert_nil c[1]
178
+ assert_equal 60, c[2]
179
+ assert_equal 53, c[9]
180
+ end
181
+
104
182
  def test_should_group_by_summed_association
105
183
  c = Account.sum(:credit_limit, :group => :firm)
106
184
  assert_equal 50, c[companies(:first_firm)]
@@ -166,11 +244,7 @@ class CalculationsTest < ActiveRecord::TestCase
166
244
  end
167
245
 
168
246
  def test_should_group_by_association_with_non_numeric_foreign_key
169
- if( ActiveRecord::Base.connection.respond_to?(:pstmt_support_on) && ActiveRecord::Base.connection.pstmt_support_on == true )
170
- ActiveRecord::Base.connection.expects(:prepared_select).returns([{"count_all" => 1, "firm_id" => "ABC"}])
171
- else
172
- ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
173
- end
247
+ ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
174
248
 
175
249
  firm = mock()
176
250
  firm.expects(:id).returns("ABC")
@@ -254,6 +328,17 @@ class CalculationsTest < ActiveRecord::TestCase
254
328
  assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
255
329
  end
256
330
 
331
+ def test_should_not_perform_joined_include_by_default
332
+ assert_equal Account.count, Account.includes(:firm).count
333
+ queries = assert_sql { Account.includes(:firm).count }
334
+ assert_no_match(/join/i, queries.last)
335
+ end
336
+
337
+ def test_should_perform_joined_include_when_referencing_included_tables
338
+ joined_count = Account.includes(:firm).where(:companies => {:name => '37signals'}).count
339
+ assert_equal 1, joined_count
340
+ end
341
+
257
342
  def test_should_count_scoped_select
258
343
  Account.update_all("credit_limit = NULL")
259
344
  assert_equal 0, Account.scoped(:select => "credit_limit").count
@@ -261,8 +346,8 @@ class CalculationsTest < ActiveRecord::TestCase
261
346
 
262
347
  def test_should_count_scoped_select_with_options
263
348
  Account.update_all("credit_limit = NULL")
264
- Account.last.update_attribute('credit_limit', 49)
265
- Account.first.update_attribute('credit_limit', 51)
349
+ Account.last.update_column('credit_limit', 49)
350
+ Account.first.update_column('credit_limit', 51)
266
351
 
267
352
  assert_equal 1, Account.scoped(:select => "credit_limit").count(:conditions => ['credit_limit >= 50'])
268
353
  end
@@ -321,6 +406,10 @@ class CalculationsTest < ActiveRecord::TestCase
321
406
  Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
322
407
  end
323
408
 
409
+ def test_sum_array_compatibility
410
+ assert_equal Account.sum(:credit_limit), Account.sum(&:credit_limit)
411
+ end
412
+
324
413
  def test_average_with_from_option
325
414
  assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
326
415
  assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
@@ -340,7 +429,7 @@ class CalculationsTest < ActiveRecord::TestCase
340
429
  end
341
430
 
342
431
  def test_from_option_with_specified_index
343
- if Edge.connection.adapter_name == 'MySQL'
432
+ if Edge.connection.adapter_name == 'MySQL' or Edge.connection.adapter_name == 'Mysql2'
344
433
  assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
345
434
  assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
346
435
  Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
@@ -359,4 +448,35 @@ class CalculationsTest < ActiveRecord::TestCase
359
448
  distinct_authors_for_approved_count = Topic.group(:approved).count(:author_name, :distinct => true)[true]
360
449
  assert_equal distinct_authors_for_approved_count, 2
361
450
  end
451
+
452
+ def test_pluck
453
+ assert_equal [1,2,3,4], Topic.order(:id).pluck(:id)
454
+ end
455
+
456
+ def test_pluck_type_cast
457
+ topic = topics(:first)
458
+ relation = Topic.where(:id => topic.id)
459
+ assert_equal [ topic.approved ], relation.pluck(:approved)
460
+ assert_equal [ topic.last_read ], relation.pluck(:last_read)
461
+ assert_equal [ topic.written_on ], relation.pluck(:written_on)
462
+ end
463
+
464
+ def test_pluck_and_uniq
465
+ assert_equal [50, 53, 55, 60], Account.order(:credit_limit).uniq.pluck(:credit_limit)
466
+ end
467
+
468
+ def test_pluck_in_relation
469
+ company = Company.first
470
+ contract = company.contracts.create!
471
+ assert_equal [contract.id], company.contracts.pluck(:id)
472
+ end
473
+
474
+ def test_pluck_with_serialization
475
+ t = Topic.create!(:content => { :foo => :bar })
476
+ assert_equal [{:foo => :bar}], Topic.where(:id => t.id).pluck(:content)
477
+ end
478
+
479
+ def test_pluck_with_qualified_column_name
480
+ assert_equal [1,2,3,4], Topic.order(:id).pluck("topics.id")
481
+ end
362
482
  end
@@ -5,23 +5,26 @@ require 'models/person'
5
5
  require 'models/topic'
6
6
  require 'models/developer'
7
7
 
8
- require MIGRATIONS_ROOT + "/valid/1_people_have_last_names"
9
8
  require MIGRATIONS_ROOT + "/valid/2_we_need_reminders"
9
+ require MIGRATIONS_ROOT + "/rename/1_we_need_things"
10
+ require MIGRATIONS_ROOT + "/rename/2_rename_things"
10
11
  require MIGRATIONS_ROOT + "/decimal/1_give_me_big_numbers"
11
- require MIGRATIONS_ROOT + "/interleaved/pass_3/2_i_raise_on_down"
12
12
 
13
13
  if ActiveRecord::Base.connection.supports_migrations?
14
14
  class BigNumber < ActiveRecord::Base; end
15
15
 
16
16
  class Reminder < ActiveRecord::Base; end
17
17
 
18
+ class Thing < ActiveRecord::Base; end
19
+
18
20
  class ActiveRecord::Migration
19
- class <<self
21
+ class << self
20
22
  attr_accessor :message_count
21
- def puts(text="")
22
- self.message_count ||= 0
23
- self.message_count += 1
24
- end
23
+ end
24
+
25
+ def puts(text="")
26
+ ActiveRecord::Migration.message_count ||= 0
27
+ ActiveRecord::Migration.message_count += 1
25
28
  end
26
29
  end
27
30
 
@@ -46,6 +49,7 @@ if ActiveRecord::Base.connection.supports_migrations?
46
49
 
47
50
  class MigrationTest < ActiveRecord::TestCase
48
51
  self.use_transactional_fixtures = false
52
+
49
53
  if (current_adapter?(:IBM_DBAdapter))
50
54
  #Rename is supported only for server zOS 9 , DB2 COBRA and Informix
51
55
  server_type = ActiveRecord::Base.connection.servertype.class.name
@@ -58,13 +62,18 @@ if ActiveRecord::Base.connection.supports_migrations?
58
62
 
59
63
  def setup
60
64
  ActiveRecord::Migration.verbose = true
61
- PeopleHaveLastNames.message_count = 0
65
+ ActiveRecord::Migration.message_count = 0
62
66
  end
63
67
 
64
68
  def teardown
65
69
  ActiveRecord::Base.connection.initialize_schema_migrations_table
66
70
  ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}"
67
71
 
72
+ %w(things awesome_things prefix_things_suffix prefix_awesome_things_suffix).each do |table|
73
+ Thing.connection.drop_table(table) rescue nil
74
+ end
75
+ Thing.reset_column_information
76
+
68
77
  %w(reminders people_reminders prefix_reminders_suffix).each do |table|
69
78
  Reminder.connection.drop_table(table) rescue nil
70
79
  end
@@ -118,7 +127,7 @@ if ActiveRecord::Base.connection.supports_migrations?
118
127
  # Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
119
128
  # OpenBase does not have named indexes. You must specify a single column name
120
129
  unless current_adapter?(:OpenBaseAdapter)
121
- unless current_adapter?(:IBM_DBAdapter) #cannot assign a integer value to string column
130
+ unless current_adapter?(:IBM_DBAdapter)
122
131
  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)
123
132
  else
124
133
  Person.update_all "#{Person.connection.quote_column_name 'key'}=#{Person.connection.quote_column_name 'first_name'}"
@@ -133,6 +142,18 @@ if ActiveRecord::Base.connection.supports_migrations?
133
142
  assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
134
143
  assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
135
144
  end
145
+
146
+ # Selected adapters support index sort order
147
+ if current_adapter?(:SQLite3Adapter, :MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
148
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name"], :order => {:last_name => :desc}) }
149
+ assert_nothing_raised { Person.connection.remove_index("people", ["last_name"]) }
150
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :order => {:last_name => :desc}) }
151
+ assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
152
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :order => {:last_name => :desc, :first_name => :asc}) }
153
+ assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
154
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :order => :desc) }
155
+ assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
156
+ end
136
157
  end
137
158
 
138
159
  def test_index_symbol_names
@@ -152,6 +173,13 @@ if ActiveRecord::Base.connection.supports_migrations?
152
173
  Person.connection.remove_index("people", :name => good_index_name)
153
174
  end
154
175
 
176
+ def test_add_index_attribute_length_limit
177
+ Person.connection.add_index :people, [:first_name, :primary_contact_id], :length => {:first_name => 10, :primary_contact_id => nil}, :name => "attribute_length"
178
+ assert Person.connection.index_exists?(:people, [:first_name, :primary_contact_id], :name => "attribute_length")
179
+ ensure
180
+ Person.connection.remove_index(:people, :name => "attribute_length")
181
+ end
182
+
155
183
  def test_remove_nonexistent_index
156
184
  # we do this by name, so OpenBase is a wash as noted above
157
185
  unless current_adapter?(:OpenBaseAdapter)
@@ -242,9 +270,9 @@ if ActiveRecord::Base.connection.supports_migrations?
242
270
  end
243
271
 
244
272
  unless current_adapter?(:IBM_DBAdapter)
245
- # Cannot add a primary key to a table with some rows already in it as it violates the unique constraint
273
+ # For DB2: Cannot add a primary key to a table with some rows already in it as it violates the unique constraint
246
274
  # Secondly GENERATED BY DEFAULT AS IDENTITY cannot be applied in a alter table command.
247
- # as this will be wrong sql syntax for DB2
275
+ # as this will be wrong sql syntax for DB
248
276
  def test_add_column_with_primary_key_attribute
249
277
  testing_table_with_only_foo_attribute do |connection|
250
278
  assert_nothing_raised { connection.add_column :testings, :id, :primary_key }
@@ -280,16 +308,14 @@ if ActiveRecord::Base.connection.supports_migrations?
280
308
 
281
309
  def test_create_table_with_defaults
282
310
  # MySQL doesn't allow defaults on TEXT or BLOB columns.
283
- mysql = current_adapter?(:MysqlAdapter)
284
- ibm_ids_zOS = ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')||
285
- ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_DB2_ZOS')
286
-
311
+ mysql = current_adapter?(:MysqlAdapter) || current_adapter?(:Mysql2Adapter)
312
+
287
313
  Person.connection.create_table :testings do |t|
288
314
  t.column :one, :string, :default => "hello"
289
315
  t.column :two, :boolean, :default => true
290
316
  t.column :three, :boolean, :default => false
291
317
  t.column :four, :integer, :default => 1
292
- t.column :five, :text, :default => "hello" unless mysql || ibm_ids_zOS
318
+ t.column :five, :text, :default => "hello" unless mysql
293
319
  end
294
320
 
295
321
  columns = Person.connection.columns(:testings)
@@ -297,65 +323,18 @@ if ActiveRecord::Base.connection.supports_migrations?
297
323
  two = columns.detect { |c| c.name == "two" }
298
324
  three = columns.detect { |c| c.name == "three" }
299
325
  four = columns.detect { |c| c.name == "four" }
300
- five = columns.detect { |c| c.name == "five" } unless mysql || ibm_ids_zOS
326
+ five = columns.detect { |c| c.name == "five" } unless mysql
301
327
 
302
328
  assert_equal "hello", one.default
303
329
  assert_equal true, two.default
304
330
  assert_equal false, three.default
305
331
  assert_equal 1, four.default
306
- assert_equal "hello", five.default unless mysql || ibm_ids_zOS
332
+ assert_equal "hello", five.default unless mysql
307
333
 
308
334
  ensure
309
335
  Person.connection.drop_table :testings rescue nil
310
336
  end
311
337
 
312
- if current_adapter?(:IBM_DBAdapter)
313
- def test_no_limits_datatypes_IBM_DB
314
- ibm_ids = ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')
315
- clasz = Class.new(ActiveRecord::Base)
316
- clasz.table_name = 'test_no_limits_datatypes_IBM_DB'
317
- assert_nothing_raised do
318
- clasz.connection.create_table clasz.table_name do |t|
319
- t.column "test_varchar", :string, :limit => 10
320
- t.column "test_integer", :integer, :limit => 5
321
- t.column "test_boolean", :boolean, :limit => 5
322
- t.column "test_double", :double, :limit => 10
323
- t.column "test_date", :date, :limit => 10
324
- t.column "test_time", :time, :limit => 10
325
- t.column "test_tstamp", :timestamp, :limit => 10
326
- t.column "test_xml", :xml, :limit => 10 unless ibm_ids
327
- t.column "test_clob", :text, :limit => 10000
328
- t.column "test_decfloat", :decfloat, :limit => 100
329
- end
330
- end
331
- ensure
332
- clasz.connection.drop_table(clasz.table_name) rescue nil
333
- end
334
-
335
- #Sexy migration test for column of type xml and char
336
- def test_short_hand_migrations_for_ibm_db_datatypes
337
- ibm_ids = ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')
338
- clasz = Class.new(ActiveRecord::Base)
339
- clasz.table_name = 'test_short_hand_migrations'
340
- assert_nothing_raised do
341
- clasz.connection.create_table clasz.table_name do |t|
342
- t.xml :xml_col unless ibm_ids
343
- t.char :char_col, :limit=>10
344
- t.decfloat :dec_col, :precision=>16
345
- end
346
- end
347
- assert_nothing_raised do
348
- clasz.connection.change_table clasz.table_name do |t|
349
- t.xml :xml_col1 unless ibm_ids
350
- t.char :char_col1, :limit=>50
351
- t.decfloat :dec_col1, :precision=>34
352
- end
353
- end
354
- ensure
355
- clasz.connection.drop_table(clasz.table_name) rescue nil
356
- end
357
- end
358
-
359
338
  def test_create_table_with_limits
360
339
  assert_nothing_raised do
361
340
  Person.connection.create_table :testings do |t|
@@ -455,8 +434,8 @@ if ActiveRecord::Base.connection.supports_migrations?
455
434
  created_at_column = created_columns.detect {|c| c.name == 'created_at' }
456
435
  updated_at_column = created_columns.detect {|c| c.name == 'updated_at' }
457
436
 
458
- assert created_at_column.null
459
- assert updated_at_column.null
437
+ assert !created_at_column.null
438
+ assert !updated_at_column.null
460
439
  ensure
461
440
  Person.connection.drop_table table_name rescue nil
462
441
  end
@@ -487,7 +466,7 @@ if ActiveRecord::Base.connection.supports_migrations?
487
466
 
488
467
  # Sybase, and SQLite3 will not allow you to add a NOT NULL
489
468
  # column to a table without a default value.
490
- unless current_adapter?(:SybaseAdapter, :SQLiteAdapter, :IBM_DBAdapter)
469
+ unless current_adapter?(:SybaseAdapter, :SQLite3Adapter, :IBM_DBAdapter)
491
470
  def test_add_column_not_null_without_default
492
471
  Person.connection.create_table :testings do |t|
493
472
  t.column :foo, :string
@@ -537,9 +516,13 @@ if ActiveRecord::Base.connection.supports_migrations?
537
516
 
538
517
  # Do a manual insertion
539
518
  if current_adapter?(:OracleAdapter)
540
- Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
519
+ Person.connection.execute "insert into people (id, wealth, created_at, updated_at) values (people_seq.nextval, 12345678901234567890.0123456789, sysdate, sysdate)"
541
520
  elsif current_adapter?(:OpenBaseAdapter) || (current_adapter?(:MysqlAdapter) && Mysql.client_version < 50003) #before mysql 5.0.3 decimals stored as strings
542
- Person.connection.execute "insert into people (wealth) values ('12345678901234567890.0123456789')"
521
+ Person.connection.execute "insert into people (wealth, created_at, updated_at) values ('12345678901234567890.0123456789', 0, 0)"
522
+ elsif current_adapter?(:PostgreSQLAdapter)
523
+ Person.connection.execute "insert into people (wealth, created_at, updated_at) values (12345678901234567890.0123456789, now(), now())"
524
+ elsif current_adapter?(:IBM_DBAdapter)
525
+ Person.connection.execute "insert into people (wealth, created_at, updated_at, lock_version, first_name) values (12345678901234567890.0123456789, CURRENT TIMESTAMP, CURRENT TIMESTAMP, 0, 'Jim')"
543
526
  else
544
527
  Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)"
545
528
  end
@@ -557,7 +540,12 @@ if ActiveRecord::Base.connection.supports_migrations?
557
540
  Person.delete_all
558
541
 
559
542
  # Now use the Rails insertion
560
- assert_nothing_raised { Person.create :wealth => BigDecimal.new("12345678901234567890.0123456789") }
543
+ unless current_adapter?(:IBM_DBAdapter)
544
+ assert_nothing_raised { Person.create :wealth => BigDecimal.new("12345678901234567890.0123456789") }
545
+ else
546
+ # First_name is a not null column, hence ensure a value is specified
547
+ assert_nothing_raised { Person.create ({:wealth => BigDecimal.new("12345678901234567890.0123456789"), :first_name => "James"}) }
548
+ end
561
549
 
562
550
  # SELECT
563
551
  row = Person.find(:first)
@@ -582,6 +570,42 @@ if ActiveRecord::Base.connection.supports_migrations?
582
570
  assert_equal 7, wealth_column.scale
583
571
  end
584
572
 
573
+ # Test SQLite adapter specifically for decimal types with precision and scale
574
+ # attributes, since these need to be maintained in schema but aren't actually
575
+ # used in SQLite itself
576
+ if current_adapter?(:SQLite3Adapter)
577
+ def test_change_column_with_new_precision_and_scale
578
+ Person.delete_all
579
+ Person.connection.add_column 'people', 'wealth', :decimal, :precision => 9, :scale => 7
580
+ Person.reset_column_information
581
+
582
+ Person.connection.change_column 'people', 'wealth', :decimal, :precision => 12, :scale => 8
583
+ Person.reset_column_information
584
+
585
+ wealth_column = Person.columns_hash['wealth']
586
+ assert_equal 12, wealth_column.precision
587
+ assert_equal 8, wealth_column.scale
588
+ end
589
+
590
+ def test_change_column_preserve_other_column_precision_and_scale
591
+ Person.delete_all
592
+ Person.connection.add_column 'people', 'last_name', :string
593
+ Person.connection.add_column 'people', 'wealth', :decimal, :precision => 9, :scale => 7
594
+ Person.reset_column_information
595
+
596
+ wealth_column = Person.columns_hash['wealth']
597
+ assert_equal 9, wealth_column.precision
598
+ assert_equal 7, wealth_column.scale
599
+
600
+ Person.connection.change_column 'people', 'last_name', :string, :null => false
601
+ Person.reset_column_information
602
+
603
+ wealth_column = Person.columns_hash['wealth']
604
+ assert_equal 9, wealth_column.precision
605
+ assert_equal 7, wealth_column.scale
606
+ end
607
+ end
608
+
585
609
  def test_native_types
586
610
  Person.delete_all
587
611
  Person.connection.add_column "people", "last_name", :string
@@ -609,7 +633,7 @@ if ActiveRecord::Base.connection.supports_migrations?
609
633
  assert_equal "I was born ....", bob.bio
610
634
  assert_equal 18, bob.age
611
635
 
612
- # Test for 30 significent digits (beyond the 16 of float), 10 of them
636
+ # Test for 30 significant digits (beyond the 16 of float), 10 of them
613
637
  # after the decimal place.
614
638
 
615
639
  unless current_adapter?(:SQLite3Adapter)
@@ -742,17 +766,17 @@ if ActiveRecord::Base.connection.supports_migrations?
742
766
  end
743
767
  end
744
768
 
745
- if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
769
+ if(!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
746
770
  def test_add_rename
747
771
  Person.delete_all
748
-
772
+
749
773
  begin
750
774
  Person.connection.add_column "people", "girlfriend", :string
751
775
  Person.reset_column_information
752
776
  Person.create :girlfriend => 'bobette'
753
-
777
+
754
778
  Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
755
-
779
+
756
780
  Person.reset_column_information
757
781
  bob = Person.find(:first)
758
782
 
@@ -763,7 +787,7 @@ if ActiveRecord::Base.connection.supports_migrations?
763
787
  end
764
788
 
765
789
  end
766
-
790
+
767
791
  def test_rename_column_using_symbol_arguments
768
792
  begin
769
793
  names_before = Person.find(:all).map(&:first_name)
@@ -809,7 +833,7 @@ if ActiveRecord::Base.connection.supports_migrations?
809
833
  ActiveRecord::Base.connection.create_table(:hats) do |table|
810
834
  table.column :hat_name, :string, :default => nil
811
835
  end
812
- exception = if current_adapter?(:PostgreSQLAdapter)
836
+ exception = if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
813
837
  ActiveRecord::StatementInvalid
814
838
  else
815
839
  ActiveRecord::ActiveRecordError
@@ -833,7 +857,7 @@ if ActiveRecord::Base.connection.supports_migrations?
833
857
  end
834
858
  end
835
859
 
836
- unless (current_adapter?(:IBM_DBAdapter)) #Cannot alter a object when there is another object depending on it
860
+ unless current_adapter?(:IBM_DBAdapter)
837
861
  def test_rename_column_with_an_index
838
862
  ActiveRecord::Base.connection.create_table(:hats) do |table|
839
863
  table.column :hat_name, :string, :limit => 100
@@ -848,59 +872,62 @@ if ActiveRecord::Base.connection.supports_migrations?
848
872
  end
849
873
  end
850
874
 
851
- def test_rename_column_with_an_index
875
+ def test_remove_column_with_index
852
876
  ActiveRecord::Base.connection.create_table(:hats) do |table|
853
877
  table.column :hat_name, :string, :limit => 100
854
878
  table.column :hat_size, :integer
855
879
  end
856
- Person.connection.add_index :hats, :hat_name
857
- assert_nothing_raised do
858
- Person.connection.rename_column "hats", "hat_name", "name"
859
- end
880
+ ActiveRecord::Base.connection.add_index "hats", "hat_size"
881
+
882
+ assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
860
883
  ensure
861
884
  ActiveRecord::Base.connection.drop_table(:hats)
862
885
  end
863
886
 
864
- def test_remove_column_with_index
887
+ def test_remove_column_with_multi_column_index
865
888
  ActiveRecord::Base.connection.create_table(:hats) do |table|
866
889
  table.column :hat_name, :string, :limit => 100
867
890
  table.column :hat_size, :integer
891
+ table.column :hat_style, :string, :limit => 100
868
892
  end
869
- ActiveRecord::Base.connection.add_index "hats", "hat_size"
893
+ ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
870
894
 
871
895
  assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
872
896
  ensure
873
897
  ActiveRecord::Base.connection.drop_table(:hats)
874
898
  end
875
899
 
876
- unless (current_adapter?(:IBM_DBAdapter)) #Cannot alter a object when there is another object depending on it
877
- def test_remove_column_with_multi_column_index
878
- ActiveRecord::Base.connection.create_table(:hats) do |table|
879
- table.column :hat_name, :string, :limit => 100
880
- table.column :hat_size, :integer
881
- table.column :hat_style, :string, :limit => 100
882
- end
883
- ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
884
-
885
- assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
886
- ensure
887
- ActiveRecord::Base.connection.drop_table(:hats)
888
- end
900
+ def test_remove_column_no_second_parameter_raises_exception
901
+ assert_raise(ArgumentError) { Person.connection.remove_column("funny") }
889
902
  end
890
903
 
891
- unless current_adapter?(:IBM_DBAdapter) #incompatible types changes
892
- def test_change_type_of_not_null_column
893
- assert_nothing_raised do
904
+ def test_change_type_of_not_null_column
905
+ assert_nothing_raised do
906
+ unless current_adapter?(:IBM_DBAdapter)
894
907
  Topic.connection.change_column "topics", "written_on", :datetime, :null => false
895
- Topic.reset_column_information
908
+ else
909
+ Topic.connection.change_column_null "topics", "written_on", false
910
+ end
911
+ Topic.reset_column_information
896
912
 
913
+ unless current_adapter?(:IBM_DBAdapter)
897
914
  Topic.connection.change_column "topics", "written_on", :datetime, :null => false
898
- Topic.reset_column_information
915
+ else
916
+ Topic.connection.change_column_null "topics", "written_on", false
899
917
  end
918
+ Topic.reset_column_information
919
+
920
+ unless current_adapter?(:IBM_DBAdapter)
921
+ Topic.connection.change_column "topics", "written_on", :datetime, :null => true
922
+ else
923
+ Topic.connection.change_column_null "topics", "written_on", true
924
+ end
925
+
926
+ Topic.reset_column_information
900
927
  end
901
- end
928
+ end
902
929
 
903
- if current_adapter?(:SQLiteAdapter)
930
+ if current_adapter?(:SQLite3Adapter)
904
931
  def test_rename_table_for_sqlite_should_work_with_reserved_words
905
932
  begin
906
933
  assert_nothing_raised do
@@ -952,14 +979,20 @@ if ActiveRecord::Base.connection.supports_migrations?
952
979
  Person.connection.add_column "people", "funny", :boolean
953
980
  Person.reset_column_information
954
981
  assert Person.columns_hash["funny"].null, "Column 'funny' must initially allow nulls"
955
- unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
982
+ unless current_adapter?(:IBM_DBAdapter)
956
983
  Person.connection.change_column "people", "funny", :boolean, :null => false, :default => true
984
+ else
985
+ Person.connection.change_column_null "people", "funny",false
986
+ end
957
987
  Person.reset_column_information
958
988
  assert !Person.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point"
989
+ unless current_adapter?(:IBM_DBAdapter)
959
990
  Person.connection.change_column "people", "funny", :boolean, :null => true
960
- Person.reset_column_information
961
- assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
962
- end
991
+ else
992
+ Person.connection.change_column_null "people", "funny",true
993
+ end
994
+ Person.reset_column_information
995
+ assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
963
996
  end
964
997
 
965
998
  def test_rename_table_with_an_index
@@ -985,39 +1018,44 @@ if ActiveRecord::Base.connection.supports_migrations?
985
1018
  end
986
1019
  end
987
1020
 
988
- unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
989
- def test_change_column
990
- Person.connection.add_column 'people', 'age', :integer
991
- label = "test_change_column Columns"
992
- old_columns = Person.connection.columns(Person.table_name, label)
993
- assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
1021
+ unless current_adapter?(:IBM_DBAdapter)
1022
+ # Cannot convert from type integer to varchar.
1023
+ # Safe to not run this test as add_column will be covered in other test cases
1024
+ def test_change_column
1025
+ Person.connection.add_column 'people', 'age', :integer
1026
+ label = "test_change_column Columns"
1027
+ old_columns = Person.connection.columns(Person.table_name, label)
1028
+ assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
994
1029
 
995
- assert_nothing_raised { Person.connection.change_column "people", "age", :string }
1030
+ assert_nothing_raised { Person.connection.change_column "people", "age", :string }
996
1031
 
997
- new_columns = Person.connection.columns(Person.table_name, label)
998
- assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
999
- assert new_columns.find { |c| c.name == 'age' and c.type == :string }
1032
+ new_columns = Person.connection.columns(Person.table_name, label)
1033
+ assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
1034
+ assert new_columns.find { |c| c.name == 'age' and c.type == :string }
1000
1035
 
1001
- old_columns = Topic.connection.columns(Topic.table_name, label)
1002
- assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
1003
- assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
1004
- new_columns = Topic.connection.columns(Topic.table_name, label)
1005
- assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
1006
- assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
1007
- assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
1036
+ old_columns = Topic.connection.columns(Topic.table_name, label)
1037
+ assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
1038
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
1039
+ new_columns = Topic.connection.columns(Topic.table_name, label)
1040
+ assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
1041
+ assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
1042
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
1043
+ end
1008
1044
  end
1009
- end
1010
-
1045
+
1011
1046
  def test_change_column_with_nil_default
1012
1047
  Person.connection.add_column "people", "contributor", :boolean, :default => true
1013
1048
  Person.reset_column_information
1014
1049
  assert Person.new.contributor?
1015
- unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
1050
+
1051
+ unless current_adapter?(:IBM_DBAdapter)
1016
1052
  assert_nothing_raised { Person.connection.change_column "people", "contributor", :boolean, :default => nil }
1017
- Person.reset_column_information
1018
- assert !Person.new.contributor?
1019
- assert_nil Person.new.contributor
1020
- end
1053
+ else
1054
+ assert_nothing_raised { Person.connection.change_column_default "people", "contributor", nil }
1055
+ end
1056
+ Person.reset_column_information
1057
+ assert !Person.new.contributor?
1058
+ assert_nil Person.new.contributor
1021
1059
  ensure
1022
1060
  Person.connection.remove_column("people", "contributor") rescue nil
1023
1061
  end
@@ -1026,11 +1064,14 @@ if ActiveRecord::Base.connection.supports_migrations?
1026
1064
  Person.connection.add_column "people", "administrator", :boolean, :default => true
1027
1065
  Person.reset_column_information
1028
1066
  assert Person.new.administrator?
1029
- unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
1067
+
1068
+ unless current_adapter?(:IBM_DBAdapter)
1030
1069
  assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
1031
- Person.reset_column_information
1032
- assert !Person.new.administrator?
1033
- end
1070
+ else
1071
+ assert_nothing_raised { Person.connection.change_column_default "people", "administrator", false }
1072
+ end
1073
+ Person.reset_column_information
1074
+ assert !Person.new.administrator?
1034
1075
  ensure
1035
1076
  Person.connection.remove_column("people", "administrator") rescue nil
1036
1077
  end
@@ -1043,10 +1084,11 @@ if ActiveRecord::Base.connection.supports_migrations?
1043
1084
 
1044
1085
  def test_change_column_quotes_column_names
1045
1086
  Person.connection.create_table :testings do |t|
1046
- if current_adapter?(:IBM_DBAdapter)
1047
- t.column :select, :string, :limit => 5
1048
- else
1087
+ unless current_adapter?(:IBM_DBAdapter)
1049
1088
  t.column :select, :string
1089
+ else
1090
+ # If no limit specified by default column of length 255 is created, which later cannot be scaled down to 10
1091
+ t.column :select, :string, :limit => 5
1050
1092
  end
1051
1093
  end
1052
1094
 
@@ -1067,7 +1109,7 @@ if ActiveRecord::Base.connection.supports_migrations?
1067
1109
  t.column :title, :string
1068
1110
  end
1069
1111
  person_klass = Class.new(Person)
1070
- person_klass.set_table_name 'testings'
1112
+ person_klass.table_name = 'testings'
1071
1113
 
1072
1114
  person_klass.connection.add_column "testings", "wealth", :integer, :null => false, :default => 99
1073
1115
  person_klass.reset_column_information
@@ -1087,16 +1129,16 @@ if ActiveRecord::Base.connection.supports_migrations?
1087
1129
  assert_equal false, person_klass.columns_hash["wealth"].null
1088
1130
 
1089
1131
  # rename column to see that column doesn't lose its not null and/or default definition
1090
- if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
1132
+ if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
1091
1133
  person_klass.connection.rename_column "testings", "wealth", "money"
1092
1134
  person_klass.reset_column_information
1093
1135
  assert_nil person_klass.columns_hash["wealth"]
1094
1136
  assert_equal 100, person_klass.columns_hash["money"].default
1095
1137
  assert_equal false, person_klass.columns_hash["money"].null
1096
- end
1138
+ end
1097
1139
 
1098
1140
  # change column
1099
- unless (current_adapter?(:IBM_DBAdapter) && !@ibm_db_rename_supported)
1141
+ unless current_adapter?(:IBM_DBAdapter)
1100
1142
  person_klass.connection.change_column "testings", "money", :integer, :null => false, :default => 1000
1101
1143
  person_klass.reset_column_information
1102
1144
  assert_equal 1000, person_klass.columns_hash["money"].default
@@ -1106,10 +1148,10 @@ if ActiveRecord::Base.connection.supports_migrations?
1106
1148
  person_klass.reset_column_information
1107
1149
  assert_equal 1000, person_klass.columns_hash["wealth"].default
1108
1150
  assert_equal false, person_klass.columns_hash["wealth"].null
1109
- end
1151
+ end
1110
1152
 
1111
1153
  # change column, make it nullable and clear default
1112
- unless (current_adapter?(:IBM_DBAdapter) && !@ibm_db_rename_supported)
1154
+ unless current_adapter?(:IBM_DBAdapter)
1113
1155
  person_klass.connection.change_column "testings", "money", :integer, :null => true, :default => nil
1114
1156
  person_klass.reset_column_information
1115
1157
  assert_nil person_klass.columns_hash["money"].default
@@ -1119,10 +1161,10 @@ if ActiveRecord::Base.connection.supports_migrations?
1119
1161
  person_klass.reset_column_information
1120
1162
  assert_nil person_klass.columns_hash["wealth"].default
1121
1163
  assert_equal true, person_klass.columns_hash["wealth"].null
1122
- end
1164
+ end
1123
1165
 
1124
1166
  # change_column_null, make it not nullable and set null values to a default value
1125
- unless (current_adapter?(:IBM_DBAdapter) && !@ibm_db_rename_supported)
1167
+ unless current_adapter?(:IBM_DBAdapter)
1126
1168
  person_klass.connection.execute('UPDATE testings SET money = NULL')
1127
1169
  person_klass.connection.change_column_null "testings", "money", false, 2000
1128
1170
  person_klass.reset_column_information
@@ -1131,12 +1173,15 @@ if ActiveRecord::Base.connection.supports_migrations?
1131
1173
  assert_equal [2000], Person.connection.select_values("SELECT money FROM testings").map { |s| s.to_i }.sort
1132
1174
  else
1133
1175
  # Trying to set the value of the column wealth to NULL and
1134
- # in the next statement a not null constraint is being applied which is wrong.
1135
- #person_klass.connection.execute('UPDATE testings SET wealth = NULL')
1176
+ # in the next statement a not null constraint is being applied which is wrong
1177
+ #person_klass.connection.execute('UPDATE testings SET money = NULL')
1136
1178
  person_klass.connection.change_column_null "testings", "wealth", false, 2000
1137
1179
  person_klass.reset_column_information
1180
+ #assert_nil person_klass.columns_hash["wealth"].default #Setting default to 2000 and expecting nil is nor correct
1181
+ assert_not_nil person_klass.columns_hash["wealth"].default
1138
1182
  assert_equal false, person_klass.columns_hash["wealth"].null
1139
- assert_equal 2000, person_klass.columns_hash["wealth"].default
1183
+ #Changing default does not change the already inserted value. Hence expecting 2000 is wrong.
1184
+ assert_equal [99], Person.connection.select_values("SELECT wealth FROM testings").map { |s| s.to_i }.sort
1140
1185
  end
1141
1186
  ensure
1142
1187
  Person.connection.drop_table :testings rescue nil
@@ -1187,6 +1232,18 @@ if ActiveRecord::Base.connection.supports_migrations?
1187
1232
  Person.connection.drop_table :testings rescue nil
1188
1233
  end
1189
1234
 
1235
+ def test_column_exists_on_table_with_no_options_parameter_supplied
1236
+ Person.connection.create_table :testings do |t|
1237
+ t.string :foo
1238
+ end
1239
+ Person.connection.change_table :testings do |t|
1240
+ assert t.column_exists?(:foo)
1241
+ assert !(t.column_exists?(:bar))
1242
+ end
1243
+ ensure
1244
+ Person.connection.drop_table :testings rescue nil
1245
+ end
1246
+
1190
1247
  def test_add_table
1191
1248
  assert !Reminder.table_exists?
1192
1249
 
@@ -1224,17 +1281,17 @@ if ActiveRecord::Base.connection.supports_migrations?
1224
1281
 
1225
1282
  # TODO: set world_population >= 2**62 to cover 64-bit platforms and test
1226
1283
  # is_a?(Bignum)
1227
- unless current_adapter?(:IBM_DBAdapter) # incompatible types retrieved
1284
+ unless current_adapter?(:IBM_DBAdapter)
1228
1285
  assert_kind_of Integer, b.world_population
1229
1286
  else
1230
1287
  assert_kind_of BigDecimal, b.world_population
1231
- end
1288
+ end
1232
1289
  assert_equal 6000000000, b.world_population
1233
- unless current_adapter?(:IBM_DBAdapter) # incompatible types retrieved
1290
+ unless current_adapter?(:IBM_DBAdapter)
1234
1291
  assert_kind_of Fixnum, b.my_house_population
1235
1292
  else
1236
1293
  assert_kind_of BigDecimal, b.my_house_population
1237
- end
1294
+ end
1238
1295
  assert_equal 3, b.my_house_population
1239
1296
  assert_kind_of BigDecimal, b.bank_balance
1240
1297
  assert_equal BigDecimal("1586.43"), b.bank_balance
@@ -1254,17 +1311,17 @@ if ActiveRecord::Base.connection.supports_migrations?
1254
1311
  # so this happens there too
1255
1312
  assert_kind_of BigDecimal, b.value_of_e
1256
1313
  assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
1257
- elsif current_adapter?(:SQLiteAdapter)
1314
+ elsif current_adapter?(:SQLite3Adapter)
1258
1315
  # - SQLite3 stores a float, in violation of SQL
1259
1316
  assert_kind_of BigDecimal, b.value_of_e
1260
1317
  assert_in_delta BigDecimal("2.71828182845905"), b.value_of_e, 0.00000000000001
1261
1318
  else
1262
1319
  # - SQL standard is an integer
1263
- unless current_adapter?(:IBM_DBAdapter) # incompatible types retrieved
1264
- assert_kind_of Fixnum, b.value_of_e
1265
- else
1266
- assert_kind_of BigDecimal, b.value_of_e
1267
- end
1320
+ unless current_adapter?(:IBM_DBAdapter)
1321
+ assert_kind_of Fixnum, b.value_of_e
1322
+ else
1323
+ assert_kind_of BigDecimal, b.value_of_e
1324
+ end
1268
1325
  assert_equal 2, b.value_of_e
1269
1326
  end
1270
1327
 
@@ -1292,6 +1349,62 @@ if ActiveRecord::Base.connection.supports_migrations?
1292
1349
  assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
1293
1350
  end
1294
1351
 
1352
+ def test_filtering_migrations
1353
+ assert !Person.column_methods_hash.include?(:last_name)
1354
+ assert !Reminder.table_exists?
1355
+
1356
+ name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" }
1357
+ ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", &name_filter)
1358
+
1359
+ Person.reset_column_information
1360
+ assert Person.column_methods_hash.include?(:last_name)
1361
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
1362
+
1363
+ ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", &name_filter)
1364
+
1365
+ Person.reset_column_information
1366
+ assert !Person.column_methods_hash.include?(:last_name)
1367
+ assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
1368
+ end
1369
+
1370
+ class MockMigration < ActiveRecord::Migration
1371
+ attr_reader :went_up, :went_down
1372
+ def initialize
1373
+ @went_up = false
1374
+ @went_down = false
1375
+ end
1376
+
1377
+ def up
1378
+ @went_up = true
1379
+ super
1380
+ end
1381
+
1382
+ def down
1383
+ @went_down = true
1384
+ super
1385
+ end
1386
+ end
1387
+
1388
+ def test_instance_based_migration_up
1389
+ migration = MockMigration.new
1390
+ assert !migration.went_up, 'have not gone up'
1391
+ assert !migration.went_down, 'have not gone down'
1392
+
1393
+ migration.migrate :up
1394
+ assert migration.went_up, 'have gone up'
1395
+ assert !migration.went_down, 'have not gone down'
1396
+ end
1397
+
1398
+ def test_instance_based_migration_down
1399
+ migration = MockMigration.new
1400
+ assert !migration.went_up, 'have not gone up'
1401
+ assert !migration.went_down, 'have not gone down'
1402
+
1403
+ migration.migrate :down
1404
+ assert !migration.went_up, 'have gone up'
1405
+ assert migration.went_down, 'have not gone down'
1406
+ end
1407
+
1295
1408
  def test_migrator_one_up
1296
1409
  assert !Person.column_methods_hash.include?(:last_name)
1297
1410
  assert !Reminder.table_exists?
@@ -1359,51 +1472,74 @@ if ActiveRecord::Base.connection.supports_migrations?
1359
1472
  def test_finds_migrations
1360
1473
  migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid").migrations
1361
1474
 
1362
- [[1, 'PeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i|
1475
+ [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i|
1476
+ assert_equal migrations[i].version, pair.first
1477
+ assert_equal migrations[i].name, pair.last
1478
+ end
1479
+ end
1480
+
1481
+ def test_finds_migrations_in_subdirectories
1482
+ migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid_with_subdirectories").migrations
1483
+
1484
+ [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i|
1363
1485
  assert_equal migrations[i].version, pair.first
1364
1486
  assert_equal migrations[i].name, pair.last
1365
1487
  end
1366
1488
  end
1367
1489
 
1490
+ def test_finds_migrations_from_two_directories
1491
+ directories = [MIGRATIONS_ROOT + '/valid_with_timestamps', MIGRATIONS_ROOT + '/to_copy_with_timestamps']
1492
+ migrations = ActiveRecord::Migrator.new(:up, directories).migrations
1493
+
1494
+ [[20090101010101, "PeopleHaveHobbies"],
1495
+ [20090101010202, "PeopleHaveDescriptions"],
1496
+ [20100101010101, "ValidWithTimestampsPeopleHaveLastNames"],
1497
+ [20100201010101, "ValidWithTimestampsWeNeedReminders"],
1498
+ [20100301010101, "ValidWithTimestampsInnocentJointable"]].each_with_index do |pair, i|
1499
+ assert_equal pair.first, migrations[i].version
1500
+ assert_equal pair.last, migrations[i].name
1501
+ end
1502
+ end
1503
+
1504
+ def test_dump_schema_information_outputs_lexically_ordered_versions
1505
+ migration_path = MIGRATIONS_ROOT + '/valid_with_timestamps'
1506
+ ActiveRecord::Migrator.run(:up, migration_path, 20100301010101)
1507
+ ActiveRecord::Migrator.run(:up, migration_path, 20100201010101)
1508
+
1509
+ schema_info = ActiveRecord::Base.connection.dump_schema_information
1510
+ assert_match(/20100201010101.*20100301010101/m, schema_info)
1511
+ end
1512
+
1368
1513
  def test_finds_pending_migrations
1369
1514
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2", 1)
1370
1515
  migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/interleaved/pass_2").pending_migrations
1371
1516
 
1372
1517
  assert_equal 1, migrations.size
1373
1518
  assert_equal migrations[0].version, 3
1374
- assert_equal migrations[0].name, 'InnocentJointable'
1519
+ assert_equal migrations[0].name, 'InterleavedInnocentJointable'
1375
1520
  end
1376
1521
 
1377
1522
  def test_relative_migrations
1378
- $".delete_if do |fname|
1379
- fname == (MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
1380
- end
1381
- Object.send(:remove_const, :PeopleHaveLastNames)
1382
-
1383
- Dir.chdir(MIGRATIONS_ROOT) do
1523
+ list = Dir.chdir(MIGRATIONS_ROOT) do
1384
1524
  ActiveRecord::Migrator.up("valid/", 1)
1385
1525
  end
1386
1526
 
1387
- assert defined?(PeopleHaveLastNames)
1527
+ migration_proxy = list.find { |item|
1528
+ item.name == 'ValidPeopleHaveLastNames'
1529
+ }
1530
+ assert migration_proxy, 'should find pending migration'
1388
1531
  end
1389
1532
 
1390
1533
  def test_only_loads_pending_migrations
1391
1534
  # migrate up to 1
1392
1535
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1393
1536
 
1394
- # now unload the migrations that have been defined
1395
- Object.send(:remove_const, :PeopleHaveLastNames)
1396
-
1397
- ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", nil)
1537
+ proxies = ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", nil)
1398
1538
 
1399
- assert !defined? PeopleHaveLastNames
1400
-
1401
- %w(WeNeedReminders, InnocentJointable).each do |migration|
1402
- assert defined? migration
1403
- end
1404
-
1405
- ensure
1406
- load(MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
1539
+ names = proxies.map(&:name)
1540
+ assert !names.include?('ValidPeopleHaveLastNames')
1541
+ assert names.include?('WeNeedReminders')
1542
+ assert names.include?('InnocentJointable')
1407
1543
  end
1408
1544
 
1409
1545
  def test_target_version_zero_should_run_only_once
@@ -1413,16 +1549,9 @@ if ActiveRecord::Base.connection.supports_migrations?
1413
1549
  # migrate down to 0
1414
1550
  ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
1415
1551
 
1416
- # now unload the migrations that have been defined
1417
- PeopleHaveLastNames.unloadable
1418
- ActiveSupport::Dependencies.remove_unloadable_constants!
1419
-
1420
1552
  # migrate down to 0 again
1421
- ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
1422
-
1423
- assert !defined? PeopleHaveLastNames
1424
- ensure
1425
- load(MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
1553
+ proxies = ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
1554
+ assert_equal [], proxies
1426
1555
  end
1427
1556
 
1428
1557
  def test_migrator_db_has_no_schema_migrations_table
@@ -1439,20 +1568,20 @@ if ActiveRecord::Base.connection.supports_migrations?
1439
1568
 
1440
1569
  def test_migrator_verbosity
1441
1570
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1442
- assert PeopleHaveLastNames.message_count > 0
1443
- PeopleHaveLastNames.message_count = 0
1571
+ assert_not_equal 0, ActiveRecord::Migration.message_count
1572
+ ActiveRecord::Migration.message_count = 0
1444
1573
 
1445
1574
  ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
1446
- assert PeopleHaveLastNames.message_count > 0
1447
- PeopleHaveLastNames.message_count = 0
1575
+ assert_not_equal 0, ActiveRecord::Migration.message_count
1576
+ ActiveRecord::Migration.message_count = 0
1448
1577
  end
1449
1578
 
1450
1579
  def test_migrator_verbosity_off
1451
- PeopleHaveLastNames.verbose = false
1580
+ ActiveRecord::Migration.verbose = false
1452
1581
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1453
- assert PeopleHaveLastNames.message_count.zero?
1582
+ assert_equal 0, ActiveRecord::Migration.message_count
1454
1583
  ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
1455
- assert PeopleHaveLastNames.message_count.zero?
1584
+ assert_equal 0, ActiveRecord::Migration.message_count
1456
1585
  end
1457
1586
 
1458
1587
  def test_migrator_going_down_due_to_version_target
@@ -1555,6 +1684,28 @@ if ActiveRecord::Base.connection.supports_migrations?
1555
1684
  Reminder.reset_table_name
1556
1685
  end
1557
1686
 
1687
+ def test_rename_table_with_prefix_and_suffix
1688
+ assert !Thing.table_exists?
1689
+ ActiveRecord::Base.table_name_prefix = 'prefix_'
1690
+ ActiveRecord::Base.table_name_suffix = '_suffix'
1691
+ Thing.reset_table_name
1692
+ Thing.reset_sequence_name
1693
+ WeNeedThings.up
1694
+
1695
+ assert Thing.create("content" => "hello world")
1696
+ assert_equal "hello world", Thing.find(:first).content
1697
+
1698
+ RenameThings.up
1699
+ Thing.table_name = "prefix_awesome_things_suffix"
1700
+
1701
+ assert_equal "hello world", Thing.find(:first).content
1702
+ ensure
1703
+ ActiveRecord::Base.table_name_prefix = ''
1704
+ ActiveRecord::Base.table_name_suffix = ''
1705
+ Thing.reset_table_name
1706
+ Thing.reset_sequence_name
1707
+ end
1708
+
1558
1709
  def test_add_drop_table_with_prefix_and_suffix
1559
1710
  assert !Reminder.table_exists?
1560
1711
  ActiveRecord::Base.table_name_prefix = 'prefix_'
@@ -1660,86 +1811,7 @@ if ActiveRecord::Base.connection.supports_migrations?
1660
1811
 
1661
1812
  end
1662
1813
 
1663
- class SexyMigrationsTest < ActiveRecord::TestCase
1664
- def test_references_column_type_adds_id
1665
- with_new_table do |t|
1666
- t.expects(:column).with('customer_id', :integer, {})
1667
- t.references :customer
1668
- end
1669
- end
1670
-
1671
- def test_references_column_type_with_polymorphic_adds_type
1672
- with_new_table do |t|
1673
- t.expects(:column).with('taggable_type', :string, {})
1674
- t.expects(:column).with('taggable_id', :integer, {})
1675
- t.references :taggable, :polymorphic => true
1676
- end
1677
- end
1678
-
1679
- def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
1680
- with_new_table do |t|
1681
- t.expects(:column).with('taggable_type', :string, {:null => false})
1682
- t.expects(:column).with('taggable_id', :integer, {:null => false})
1683
- t.references :taggable, :polymorphic => true, :null => false
1684
- end
1685
- end
1686
-
1687
- def test_belongs_to_works_like_references
1688
- with_new_table do |t|
1689
- t.expects(:column).with('customer_id', :integer, {})
1690
- t.belongs_to :customer
1691
- end
1692
- end
1693
-
1694
- def test_timestamps_creates_updated_at_and_created_at
1695
- with_new_table do |t|
1696
- t.expects(:column).with(:created_at, :datetime, kind_of(Hash))
1697
- t.expects(:column).with(:updated_at, :datetime, kind_of(Hash))
1698
- t.timestamps
1699
- end
1700
- end
1701
-
1702
- def test_integer_creates_integer_column
1703
- with_new_table do |t|
1704
- t.expects(:column).with(:foo, 'integer', {})
1705
- t.expects(:column).with(:bar, 'integer', {})
1706
- t.integer :foo, :bar
1707
- end
1708
- end
1709
-
1710
- def test_string_creates_string_column
1711
- with_new_table do |t|
1712
- t.expects(:column).with(:foo, 'string', {})
1713
- t.expects(:column).with(:bar, 'string', {})
1714
- t.string :foo, :bar
1715
- end
1716
- end
1717
-
1718
- if current_adapter?(:PostgreSQLAdapter)
1719
- def test_xml_creates_xml_column
1720
- with_new_table do |t|
1721
- t.expects(:column).with(:data, 'xml', {})
1722
- t.xml :data
1723
- end
1724
- end
1725
- end
1726
-
1727
- protected
1728
- def with_new_table
1729
- Person.connection.create_table :delete_me, :force => true do |t|
1730
- yield t
1731
- end
1732
- ensure
1733
- Person.connection.drop_table :delete_me rescue nil
1734
- end
1735
-
1736
- end # SexyMigrationsTest
1737
-
1738
1814
  class MigrationLoggerTest < ActiveRecord::TestCase
1739
- def setup
1740
- Object.send(:remove_const, :InnocentJointable)
1741
- end
1742
-
1743
1815
  def test_migration_should_be_run_without_logger
1744
1816
  previous_logger = ActiveRecord::Base.logger
1745
1817
  ActiveRecord::Base.logger = nil
@@ -1752,10 +1824,6 @@ if ActiveRecord::Base.connection.supports_migrations?
1752
1824
  end
1753
1825
 
1754
1826
  class InterleavedMigrationsTest < ActiveRecord::TestCase
1755
- def setup
1756
- Object.send(:remove_const, :PeopleHaveLastNames)
1757
- end
1758
-
1759
1827
  def test_migrator_interleaved_migrations
1760
1828
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_1")
1761
1829
 
@@ -1766,10 +1834,12 @@ if ActiveRecord::Base.connection.supports_migrations?
1766
1834
  Person.reset_column_information
1767
1835
  assert Person.column_methods_hash.include?(:last_name)
1768
1836
 
1769
- Object.send(:remove_const, :PeopleHaveLastNames)
1770
- Object.send(:remove_const, :InnocentJointable)
1771
1837
  assert_nothing_raised do
1772
- ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/interleaved/pass_3")
1838
+ proxies = ActiveRecord::Migrator.down(
1839
+ MIGRATIONS_ROOT + "/interleaved/pass_3")
1840
+ names = proxies.map(&:name)
1841
+ assert names.include?('InterleavedPeopleHaveLastNames')
1842
+ assert names.include?('InterleavedInnocentJointable')
1773
1843
  end
1774
1844
  end
1775
1845
  end
@@ -2010,5 +2080,329 @@ if ActiveRecord::Base.connection.supports_migrations?
2010
2080
  end
2011
2081
  end
2012
2082
  end
2013
- end
2014
2083
 
2084
+ if ActiveRecord::Base.connection.supports_bulk_alter?
2085
+ class BulkAlterTableMigrationsTest < ActiveRecord::TestCase
2086
+ def setup
2087
+ @connection = Person.connection
2088
+ @connection.create_table(:delete_me, :force => true) {|t| }
2089
+ end
2090
+
2091
+ def teardown
2092
+ Person.connection.drop_table(:delete_me) rescue nil
2093
+ end
2094
+
2095
+ def test_adding_multiple_columns
2096
+ assert_queries(1) do
2097
+ with_bulk_change_table do |t|
2098
+ t.column :name, :string
2099
+ t.string :qualification, :experience
2100
+ t.integer :age, :default => 0
2101
+ t.date :birthdate
2102
+ t.timestamps
2103
+ end
2104
+ end
2105
+
2106
+ assert_equal 8, columns.size
2107
+ [:name, :qualification, :experience].each {|s| assert_equal :string, column(s).type }
2108
+ assert_equal 0, column(:age).default
2109
+ end
2110
+
2111
+ def test_removing_columns
2112
+ with_bulk_change_table do |t|
2113
+ t.string :qualification, :experience
2114
+ end
2115
+
2116
+ [:qualification, :experience].each {|c| assert column(c) }
2117
+
2118
+ assert_queries(1) do
2119
+ with_bulk_change_table do |t|
2120
+ t.remove :qualification, :experience
2121
+ t.string :qualification_experience
2122
+ end
2123
+ end
2124
+
2125
+ [:qualification, :experience].each {|c| assert ! column(c) }
2126
+ assert column(:qualification_experience)
2127
+ end
2128
+
2129
+ def test_adding_indexes
2130
+ with_bulk_change_table do |t|
2131
+ t.string :username
2132
+ t.string :name
2133
+ t.integer :age
2134
+ end
2135
+
2136
+ # Adding an index fires a query every time to check if an index already exists or not
2137
+ assert_queries(3) do
2138
+ with_bulk_change_table do |t|
2139
+ t.index :username, :unique => true, :name => :awesome_username_index
2140
+ t.index [:name, :age]
2141
+ end
2142
+ end
2143
+
2144
+ assert_equal 2, indexes.size
2145
+
2146
+ name_age_index = index(:index_delete_me_on_name_and_age)
2147
+ assert_equal ['name', 'age'].sort, name_age_index.columns.sort
2148
+ assert ! name_age_index.unique
2149
+
2150
+ assert index(:awesome_username_index).unique
2151
+ end
2152
+
2153
+ def test_removing_index
2154
+ with_bulk_change_table do |t|
2155
+ t.string :name
2156
+ t.index :name
2157
+ end
2158
+
2159
+ assert index(:index_delete_me_on_name)
2160
+
2161
+ assert_queries(3) do
2162
+ with_bulk_change_table do |t|
2163
+ t.remove_index :name
2164
+ t.index :name, :name => :new_name_index, :unique => true
2165
+ end
2166
+ end
2167
+
2168
+ assert ! index(:index_delete_me_on_name)
2169
+
2170
+ new_name_index = index(:new_name_index)
2171
+ assert new_name_index.unique
2172
+ end
2173
+
2174
+ def test_changing_columns
2175
+ with_bulk_change_table do |t|
2176
+ t.string :name
2177
+ t.date :birthdate
2178
+ end
2179
+
2180
+ assert ! column(:name).default
2181
+ assert_equal :date, column(:birthdate).type
2182
+
2183
+ # One query for columns (delete_me table)
2184
+ # One query for primary key (delete_me table)
2185
+ # One query to do the bulk change
2186
+ assert_queries(3) do
2187
+ with_bulk_change_table do |t|
2188
+ t.change :name, :string, :default => 'NONAME'
2189
+ t.change :birthdate, :datetime
2190
+ end
2191
+ end
2192
+
2193
+ assert_equal 'NONAME', column(:name).default
2194
+ assert_equal :datetime, column(:birthdate).type
2195
+ end
2196
+
2197
+ protected
2198
+
2199
+ def with_bulk_change_table
2200
+ # Reset columns/indexes cache as we're changing the table
2201
+ @columns = @indexes = nil
2202
+
2203
+ Person.connection.change_table(:delete_me, :bulk => true) do |t|
2204
+ yield t
2205
+ end
2206
+ end
2207
+
2208
+ def column(name)
2209
+ columns.detect {|c| c.name == name.to_s }
2210
+ end
2211
+
2212
+ def columns
2213
+ @columns ||= Person.connection.columns('delete_me')
2214
+ end
2215
+
2216
+ def index(name)
2217
+ indexes.detect {|i| i.name == name.to_s }
2218
+ end
2219
+
2220
+ def indexes
2221
+ @indexes ||= Person.connection.indexes('delete_me')
2222
+ end
2223
+ end # AlterTableMigrationsTest
2224
+
2225
+ end
2226
+
2227
+ class CopyMigrationsTest < ActiveRecord::TestCase
2228
+ def setup
2229
+ end
2230
+
2231
+ def clear
2232
+ ActiveRecord::Base.timestamped_migrations = true
2233
+ to_delete = Dir[@migrations_path + "/*.rb"] - @existing_migrations
2234
+ File.delete(*to_delete)
2235
+ end
2236
+
2237
+ def test_copying_migrations_without_timestamps
2238
+ ActiveRecord::Base.timestamped_migrations = false
2239
+ @migrations_path = MIGRATIONS_ROOT + "/valid"
2240
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2241
+
2242
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
2243
+ assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
2244
+ assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
2245
+ assert_equal [@migrations_path + "/4_people_have_hobbies.bukkits.rb", @migrations_path + "/5_people_have_descriptions.bukkits.rb"], copied.map(&:filename)
2246
+
2247
+ expected = "# This migration comes from bukkits (originally 1)"
2248
+ assert_equal expected, IO.readlines(@migrations_path + "/4_people_have_hobbies.bukkits.rb")[0].chomp
2249
+
2250
+ files_count = Dir[@migrations_path + "/*.rb"].length
2251
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
2252
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2253
+ assert copied.empty?
2254
+ ensure
2255
+ clear
2256
+ end
2257
+
2258
+ def test_copying_migrations_without_timestamps_from_2_sources
2259
+ ActiveRecord::Base.timestamped_migrations = false
2260
+ @migrations_path = MIGRATIONS_ROOT + "/valid"
2261
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2262
+
2263
+ sources = ActiveSupport::OrderedHash.new
2264
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy"
2265
+ sources[:omg] = MIGRATIONS_ROOT + "/to_copy2"
2266
+ ActiveRecord::Migration.copy(@migrations_path, sources)
2267
+ assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
2268
+ assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
2269
+ assert File.exists?(@migrations_path + "/6_create_articles.omg.rb")
2270
+ assert File.exists?(@migrations_path + "/7_create_comments.omg.rb")
2271
+
2272
+ files_count = Dir[@migrations_path + "/*.rb"].length
2273
+ ActiveRecord::Migration.copy(@migrations_path, sources)
2274
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2275
+ ensure
2276
+ clear
2277
+ end
2278
+
2279
+ def test_copying_migrations_with_timestamps
2280
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2281
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2282
+
2283
+ Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
2284
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2285
+ assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
2286
+ assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
2287
+ expected = [@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb",
2288
+ @migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb"]
2289
+ assert_equal expected, copied.map(&:filename)
2290
+
2291
+ files_count = Dir[@migrations_path + "/*.rb"].length
2292
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2293
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2294
+ assert copied.empty?
2295
+ end
2296
+ ensure
2297
+ clear
2298
+ end
2299
+
2300
+ def test_copying_migrations_with_timestamps_from_2_sources
2301
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2302
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2303
+
2304
+ sources = ActiveSupport::OrderedHash.new
2305
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
2306
+ sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps2"
2307
+
2308
+ Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
2309
+ copied = ActiveRecord::Migration.copy(@migrations_path, sources)
2310
+ assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
2311
+ assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
2312
+ assert File.exists?(@migrations_path + "/20100726101012_create_articles.omg.rb")
2313
+ assert File.exists?(@migrations_path + "/20100726101013_create_comments.omg.rb")
2314
+ assert_equal 4, copied.length
2315
+
2316
+ files_count = Dir[@migrations_path + "/*.rb"].length
2317
+ ActiveRecord::Migration.copy(@migrations_path, sources)
2318
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2319
+ end
2320
+ ensure
2321
+ clear
2322
+ end
2323
+
2324
+ def test_copying_migrations_with_timestamps_to_destination_with_timestamps_in_future
2325
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2326
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2327
+
2328
+ Time.travel_to(Time.utc(2010, 2, 20, 10, 10, 10)) do
2329
+ ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2330
+ assert File.exists?(@migrations_path + "/20100301010102_people_have_hobbies.bukkits.rb")
2331
+ assert File.exists?(@migrations_path + "/20100301010103_people_have_descriptions.bukkits.rb")
2332
+
2333
+ files_count = Dir[@migrations_path + "/*.rb"].length
2334
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2335
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2336
+ assert copied.empty?
2337
+ end
2338
+ ensure
2339
+ clear
2340
+ end
2341
+
2342
+ def test_skipping_migrations
2343
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2344
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2345
+
2346
+ sources = ActiveSupport::OrderedHash.new
2347
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
2348
+ sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_name_collision"
2349
+
2350
+ skipped = []
2351
+ on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
2352
+ copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
2353
+ assert_equal 2, copied.length
2354
+
2355
+ assert_equal 1, skipped.length
2356
+ assert_equal ["omg PeopleHaveHobbies"], skipped
2357
+ ensure
2358
+ clear
2359
+ end
2360
+
2361
+ def test_skip_is_not_called_if_migrations_are_from_the_same_plugin
2362
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2363
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2364
+
2365
+ sources = ActiveSupport::OrderedHash.new
2366
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
2367
+
2368
+ skipped = []
2369
+ on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
2370
+ copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
2371
+ ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
2372
+
2373
+ assert_equal 2, copied.length
2374
+ assert_equal 0, skipped.length
2375
+ ensure
2376
+ clear
2377
+ end
2378
+
2379
+ def test_copying_migrations_to_non_existing_directory
2380
+ @migrations_path = MIGRATIONS_ROOT + "/non_existing"
2381
+ @existing_migrations = []
2382
+
2383
+ Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
2384
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2385
+ assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
2386
+ assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
2387
+ assert_equal 2, copied.length
2388
+ end
2389
+ ensure
2390
+ clear
2391
+ Dir.delete(@migrations_path)
2392
+ end
2393
+
2394
+ def test_copying_migrations_to_empty_directory
2395
+ @migrations_path = MIGRATIONS_ROOT + "/empty"
2396
+ @existing_migrations = []
2397
+
2398
+ Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
2399
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2400
+ assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
2401
+ assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
2402
+ assert_equal 2, copied.length
2403
+ end
2404
+ ensure
2405
+ clear
2406
+ end
2407
+ end
2408
+ end