ibm_db 2.5.6-x86-mingw32 → 2.5.7-x86-mingw32

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 (38) hide show
  1. data/CHANGES +6 -0
  2. data/README +1 -1
  3. data/ext/Makefile.nt32 +3 -3
  4. data/ext/Makefile.nt32.191 +212 -0
  5. data/ext/ibm_db.c +30 -5
  6. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +300 -108
  7. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1 -1
  8. data/lib/mswin32/rb18x/ibm_db.so +0 -0
  9. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  10. data/test/cases/adapter_test.rb +25 -22
  11. data/test/cases/associations/belongs_to_associations_test.rb +245 -43
  12. data/test/cases/associations/cascaded_eager_loading_test.rb +28 -26
  13. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +60 -156
  14. data/test/cases/associations/join_model_test.rb +96 -146
  15. data/test/cases/attribute_methods_test.rb +98 -33
  16. data/test/cases/base_test.rb +525 -103
  17. data/test/cases/calculations_test.rb +92 -8
  18. data/test/cases/migration_test.rb +533 -207
  19. data/test/cases/persistence_test.rb +636 -0
  20. data/test/cases/query_cache_test.rb +242 -0
  21. data/test/cases/relations_test.rb +1019 -0
  22. data/test/cases/schema_dumper_test.rb +37 -17
  23. data/test/cases/transaction_callbacks_test.rb +300 -0
  24. data/test/cases/validations/uniqueness_validation_test.rb +38 -22
  25. data/test/cases/xml_serialization_test.rb +276 -0
  26. data/test/config.yml +154 -0
  27. data/test/connections/native_ibm_db/connection.rb +2 -0
  28. data/test/models/warehouse_thing.rb +4 -4
  29. data/test/schema/i5/ibm_db_specific_schema.rb +3 -1
  30. data/test/schema/ids/ibm_db_specific_schema.rb +3 -1
  31. data/test/schema/luw/ibm_db_specific_schema.rb +2 -0
  32. data/test/schema/schema.rb +174 -89
  33. data/test/schema/zOS/ibm_db_specific_schema.rb +3 -1
  34. metadata +10 -7
  35. data/test/cases/associations/eager_test.rb +0 -862
  36. data/test/cases/associations/has_many_through_associations_test.rb +0 -461
  37. data/test/cases/finder_test.rb +0 -1088
  38. data/test/cases/fixtures_test.rb +0 -684
@@ -23,6 +23,18 @@ class CalculationsTest < ActiveRecord::TestCase
23
23
  assert_equal 53.0, value
24
24
  end
25
25
 
26
+ def test_should_return_decimal_average_of_integer_field
27
+ return if current_adapter?(:IBM_DBAdapter) #average cannot be a decimal value when applied on integer field
28
+ value = Account.average(:id)
29
+ assert_equal 3.5, value
30
+ end
31
+
32
+ def test_should_return_integer_average_if_db_returns_such
33
+ Account.connection.stubs :select_value => 3
34
+ value = Account.average(:id)
35
+ assert_equal 3, value
36
+ end
37
+
26
38
  def test_should_return_nil_as_average
27
39
  assert_nil NumericData.average(:bank_balance)
28
40
  end
@@ -55,6 +67,19 @@ class CalculationsTest < ActiveRecord::TestCase
55
67
  [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
56
68
  end
57
69
 
70
+ def test_should_group_by_multiple_fields
71
+ c = Account.count(:all, :group => ['firm_id', :credit_limit])
72
+ [ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) }
73
+ end
74
+
75
+ def test_should_group_by_multiple_fields_having_functions
76
+ c = Topic.group(:author_name, 'COALESCE(type, title)').count(:all)
77
+ assert_equal 1, c[["Carl", "The Third Topic of the day"]]
78
+ assert_equal 1, c[["Mary", "Reply"]]
79
+ assert_equal 1, c[["David", "The First Topic"]]
80
+ assert_equal 1, c[["Carl", "Reply"]]
81
+ end
82
+
58
83
  def test_should_group_by_summed_field
59
84
  c = Account.sum(:credit_limit, :group => :firm_id)
60
85
  assert_equal 50, c[1]
@@ -85,6 +110,51 @@ class CalculationsTest < ActiveRecord::TestCase
85
110
  assert_equal [2, 6], c.keys.compact
86
111
  end
87
112
 
113
+ def test_limit_should_apply_before_count
114
+ accounts = Account.limit(3).where('firm_id IS NOT NULL')
115
+
116
+ assert_equal 3, accounts.count(:firm_id)
117
+ assert_equal 3, accounts.select(:firm_id).count
118
+ end
119
+
120
+ def test_count_should_shortcut_with_limit_zero
121
+ accounts = Account.limit(0)
122
+
123
+ assert_no_queries { assert_equal 0, accounts.count }
124
+ end
125
+
126
+ def test_limit_is_kept
127
+ return if current_adapter?(:OracleAdapter, :IBM_DBAdapter)
128
+
129
+ queries = assert_sql { Account.limit(1).count }
130
+ assert_equal 1, queries.length
131
+ assert_match(/LIMIT/, queries.first)
132
+ end
133
+
134
+ def test_offset_is_kept
135
+ return if current_adapter?(:OracleAdapter,:IBM_DBAdapter)
136
+
137
+ queries = assert_sql { Account.offset(1).count }
138
+ assert_equal 1, queries.length
139
+ assert_match(/OFFSET/, queries.first)
140
+ end
141
+
142
+ def test_limit_with_offset_is_kept
143
+ return if current_adapter?(:OracleAdapter,:IBM_DBAdapter)
144
+
145
+ queries = assert_sql { Account.limit(1).offset(1).count }
146
+ assert_equal 1, queries.length
147
+ assert_match(/LIMIT/, queries.first)
148
+ assert_match(/OFFSET/, queries.first)
149
+ end
150
+
151
+ def test_no_limit_no_offset
152
+ queries = assert_sql { Account.count }
153
+ assert_equal 1, queries.length
154
+ assert_no_match(/LIMIT/, queries.first)
155
+ assert_no_match(/OFFSET/, queries.first)
156
+ end
157
+
88
158
  def test_should_group_by_summed_field_having_condition
89
159
  c = Account.sum(:credit_limit, :group => :firm_id,
90
160
  :having => 'sum(credit_limit) > 50')
@@ -101,6 +171,13 @@ class CalculationsTest < ActiveRecord::TestCase
101
171
  assert_equal 60, c[2]
102
172
  end
103
173
 
174
+ def test_should_group_by_summed_field_having_condition_from_select
175
+ c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("min_credit_limit > 50").sum(:credit_limit)
176
+ assert_nil c[1]
177
+ assert_equal 60, c[2]
178
+ assert_equal 53, c[9]
179
+ end
180
+
104
181
  def test_should_group_by_summed_association
105
182
  c = Account.sum(:credit_limit, :group => :firm)
106
183
  assert_equal 50, c[companies(:first_firm)]
@@ -166,11 +243,7 @@ class CalculationsTest < ActiveRecord::TestCase
166
243
  end
167
244
 
168
245
  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
246
+ ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
174
247
 
175
248
  firm = mock()
176
249
  firm.expects(:id).returns("ABC")
@@ -254,6 +327,17 @@ class CalculationsTest < ActiveRecord::TestCase
254
327
  assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
255
328
  end
256
329
 
330
+ def test_should_not_perform_joined_include_by_default
331
+ assert_equal Account.count, Account.includes(:firm).count
332
+ queries = assert_sql { Account.includes(:firm).count }
333
+ assert_no_match(/join/i, queries.last)
334
+ end
335
+
336
+ def test_should_perform_joined_include_when_referencing_included_tables
337
+ joined_count = Account.includes(:firm).where(:companies => {:name => '37signals'}).count
338
+ assert_equal 1, joined_count
339
+ end
340
+
257
341
  def test_should_count_scoped_select
258
342
  Account.update_all("credit_limit = NULL")
259
343
  assert_equal 0, Account.scoped(:select => "credit_limit").count
@@ -261,8 +345,8 @@ class CalculationsTest < ActiveRecord::TestCase
261
345
 
262
346
  def test_should_count_scoped_select_with_options
263
347
  Account.update_all("credit_limit = NULL")
264
- Account.last.update_attribute('credit_limit', 49)
265
- Account.first.update_attribute('credit_limit', 51)
348
+ Account.last.update_column('credit_limit', 49)
349
+ Account.first.update_column('credit_limit', 51)
266
350
 
267
351
  assert_equal 1, Account.scoped(:select => "credit_limit").count(:conditions => ['credit_limit >= 50'])
268
352
  end
@@ -340,7 +424,7 @@ class CalculationsTest < ActiveRecord::TestCase
340
424
  end
341
425
 
342
426
  def test_from_option_with_specified_index
343
- if Edge.connection.adapter_name == 'MySQL'
427
+ if Edge.connection.adapter_name == 'MySQL' or Edge.connection.adapter_name == 'Mysql2'
344
428
  assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
345
429
  assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
346
430
  Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
@@ -5,10 +5,8 @@ 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"
10
9
  require MIGRATIONS_ROOT + "/decimal/1_give_me_big_numbers"
11
- require MIGRATIONS_ROOT + "/interleaved/pass_3/2_i_raise_on_down"
12
10
 
13
11
  if ActiveRecord::Base.connection.supports_migrations?
14
12
  class BigNumber < ActiveRecord::Base; end
@@ -16,12 +14,13 @@ if ActiveRecord::Base.connection.supports_migrations?
16
14
  class Reminder < ActiveRecord::Base; end
17
15
 
18
16
  class ActiveRecord::Migration
19
- class <<self
17
+ class << self
20
18
  attr_accessor :message_count
21
- def puts(text="")
22
- self.message_count ||= 0
23
- self.message_count += 1
24
- end
19
+ end
20
+
21
+ def puts(text="")
22
+ ActiveRecord::Migration.message_count ||= 0
23
+ ActiveRecord::Migration.message_count += 1
25
24
  end
26
25
  end
27
26
 
@@ -46,6 +45,7 @@ if ActiveRecord::Base.connection.supports_migrations?
46
45
 
47
46
  class MigrationTest < ActiveRecord::TestCase
48
47
  self.use_transactional_fixtures = false
48
+
49
49
  if (current_adapter?(:IBM_DBAdapter))
50
50
  #Rename is supported only for server zOS 9 , DB2 COBRA and Informix
51
51
  server_type = ActiveRecord::Base.connection.servertype.class.name
@@ -58,7 +58,7 @@ if ActiveRecord::Base.connection.supports_migrations?
58
58
 
59
59
  def setup
60
60
  ActiveRecord::Migration.verbose = true
61
- PeopleHaveLastNames.message_count = 0
61
+ ActiveRecord::Migration.message_count = 0
62
62
  end
63
63
 
64
64
  def teardown
@@ -118,7 +118,7 @@ if ActiveRecord::Base.connection.supports_migrations?
118
118
  # Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
119
119
  # OpenBase does not have named indexes. You must specify a single column name
120
120
  unless current_adapter?(:OpenBaseAdapter)
121
- unless current_adapter?(:IBM_DBAdapter) #cannot assign a integer value to string column
121
+ unless current_adapter?(:IBM_DBAdapter)
122
122
  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
123
  else
124
124
  Person.update_all "#{Person.connection.quote_column_name 'key'}=#{Person.connection.quote_column_name 'first_name'}"
@@ -242,9 +242,9 @@ if ActiveRecord::Base.connection.supports_migrations?
242
242
  end
243
243
 
244
244
  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
245
+ # For DB2: Cannot add a primary key to a table with some rows already in it as it violates the unique constraint
246
246
  # Secondly GENERATED BY DEFAULT AS IDENTITY cannot be applied in a alter table command.
247
- # as this will be wrong sql syntax for DB2
247
+ # as this will be wrong sql syntax for DB
248
248
  def test_add_column_with_primary_key_attribute
249
249
  testing_table_with_only_foo_attribute do |connection|
250
250
  assert_nothing_raised { connection.add_column :testings, :id, :primary_key }
@@ -280,16 +280,14 @@ if ActiveRecord::Base.connection.supports_migrations?
280
280
 
281
281
  def test_create_table_with_defaults
282
282
  # 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
-
283
+ mysql = current_adapter?(:MysqlAdapter) || current_adapter?(:Mysql2Adapter)
284
+
287
285
  Person.connection.create_table :testings do |t|
288
286
  t.column :one, :string, :default => "hello"
289
287
  t.column :two, :boolean, :default => true
290
288
  t.column :three, :boolean, :default => false
291
289
  t.column :four, :integer, :default => 1
292
- t.column :five, :text, :default => "hello" unless mysql || ibm_ids_zOS
290
+ t.column :five, :text, :default => "hello" unless mysql
293
291
  end
294
292
 
295
293
  columns = Person.connection.columns(:testings)
@@ -297,65 +295,18 @@ if ActiveRecord::Base.connection.supports_migrations?
297
295
  two = columns.detect { |c| c.name == "two" }
298
296
  three = columns.detect { |c| c.name == "three" }
299
297
  four = columns.detect { |c| c.name == "four" }
300
- five = columns.detect { |c| c.name == "five" } unless mysql || ibm_ids_zOS
298
+ five = columns.detect { |c| c.name == "five" } unless mysql
301
299
 
302
300
  assert_equal "hello", one.default
303
301
  assert_equal true, two.default
304
302
  assert_equal false, three.default
305
303
  assert_equal 1, four.default
306
- assert_equal "hello", five.default unless mysql || ibm_ids_zOS
304
+ assert_equal "hello", five.default unless mysql
307
305
 
308
306
  ensure
309
307
  Person.connection.drop_table :testings rescue nil
310
308
  end
311
309
 
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
310
  def test_create_table_with_limits
360
311
  assert_nothing_raised do
361
312
  Person.connection.create_table :testings do |t|
@@ -487,7 +438,7 @@ if ActiveRecord::Base.connection.supports_migrations?
487
438
 
488
439
  # Sybase, and SQLite3 will not allow you to add a NOT NULL
489
440
  # column to a table without a default value.
490
- unless current_adapter?(:SybaseAdapter, :SQLiteAdapter, :IBM_DBAdapter)
441
+ unless current_adapter?(:SybaseAdapter, :SQLite3Adapter, :IBM_DBAdapter)
491
442
  def test_add_column_not_null_without_default
492
443
  Person.connection.create_table :testings do |t|
493
444
  t.column :foo, :string
@@ -609,7 +560,7 @@ if ActiveRecord::Base.connection.supports_migrations?
609
560
  assert_equal "I was born ....", bob.bio
610
561
  assert_equal 18, bob.age
611
562
 
612
- # Test for 30 significent digits (beyond the 16 of float), 10 of them
563
+ # Test for 30 significant digits (beyond the 16 of float), 10 of them
613
564
  # after the decimal place.
614
565
 
615
566
  unless current_adapter?(:SQLite3Adapter)
@@ -742,17 +693,17 @@ if ActiveRecord::Base.connection.supports_migrations?
742
693
  end
743
694
  end
744
695
 
745
- if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
696
+ if(!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
746
697
  def test_add_rename
747
698
  Person.delete_all
748
-
699
+
749
700
  begin
750
701
  Person.connection.add_column "people", "girlfriend", :string
751
702
  Person.reset_column_information
752
703
  Person.create :girlfriend => 'bobette'
753
-
704
+
754
705
  Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
755
-
706
+
756
707
  Person.reset_column_information
757
708
  bob = Person.find(:first)
758
709
 
@@ -763,7 +714,7 @@ if ActiveRecord::Base.connection.supports_migrations?
763
714
  end
764
715
 
765
716
  end
766
-
717
+
767
718
  def test_rename_column_using_symbol_arguments
768
719
  begin
769
720
  names_before = Person.find(:all).map(&:first_name)
@@ -809,7 +760,7 @@ if ActiveRecord::Base.connection.supports_migrations?
809
760
  ActiveRecord::Base.connection.create_table(:hats) do |table|
810
761
  table.column :hat_name, :string, :default => nil
811
762
  end
812
- exception = if current_adapter?(:PostgreSQLAdapter)
763
+ exception = if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
813
764
  ActiveRecord::StatementInvalid
814
765
  else
815
766
  ActiveRecord::ActiveRecordError
@@ -833,7 +784,7 @@ if ActiveRecord::Base.connection.supports_migrations?
833
784
  end
834
785
  end
835
786
 
836
- unless (current_adapter?(:IBM_DBAdapter)) #Cannot alter a object when there is another object depending on it
787
+ unless current_adapter?(:IBM_DBAdapter)
837
788
  def test_rename_column_with_an_index
838
789
  ActiveRecord::Base.connection.create_table(:hats) do |table|
839
790
  table.column :hat_name, :string, :limit => 100
@@ -848,59 +799,62 @@ if ActiveRecord::Base.connection.supports_migrations?
848
799
  end
849
800
  end
850
801
 
851
- def test_rename_column_with_an_index
802
+ def test_remove_column_with_index
852
803
  ActiveRecord::Base.connection.create_table(:hats) do |table|
853
804
  table.column :hat_name, :string, :limit => 100
854
805
  table.column :hat_size, :integer
855
806
  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
807
+ ActiveRecord::Base.connection.add_index "hats", "hat_size"
808
+
809
+ assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
860
810
  ensure
861
811
  ActiveRecord::Base.connection.drop_table(:hats)
862
812
  end
863
813
 
864
- def test_remove_column_with_index
814
+ def test_remove_column_with_multi_column_index
865
815
  ActiveRecord::Base.connection.create_table(:hats) do |table|
866
816
  table.column :hat_name, :string, :limit => 100
867
817
  table.column :hat_size, :integer
818
+ table.column :hat_style, :string, :limit => 100
868
819
  end
869
- ActiveRecord::Base.connection.add_index "hats", "hat_size"
820
+ ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
870
821
 
871
822
  assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
872
823
  ensure
873
824
  ActiveRecord::Base.connection.drop_table(:hats)
874
825
  end
875
826
 
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
827
+ def test_remove_column_no_second_parameter_raises_exception
828
+ assert_raise(ArgumentError) { Person.connection.remove_column("funny") }
889
829
  end
890
830
 
891
- unless current_adapter?(:IBM_DBAdapter) #incompatible types changes
892
- def test_change_type_of_not_null_column
893
- assert_nothing_raised do
831
+ def test_change_type_of_not_null_column
832
+ assert_nothing_raised do
833
+ unless current_adapter?(:IBM_DBAdapter)
894
834
  Topic.connection.change_column "topics", "written_on", :datetime, :null => false
895
- Topic.reset_column_information
835
+ else
836
+ Topic.connection.change_column_null "topics", "written_on", false
837
+ end
838
+ Topic.reset_column_information
896
839
 
840
+ unless current_adapter?(:IBM_DBAdapter)
897
841
  Topic.connection.change_column "topics", "written_on", :datetime, :null => false
898
- Topic.reset_column_information
842
+ else
843
+ Topic.connection.change_column_null "topics", "written_on", false
899
844
  end
845
+ Topic.reset_column_information
846
+
847
+ unless current_adapter?(:IBM_DBAdapter)
848
+ Topic.connection.change_column "topics", "written_on", :datetime, :null => true
849
+ else
850
+ Topic.connection.change_column_null "topics", "written_on", true
851
+ end
852
+
853
+ Topic.reset_column_information
900
854
  end
901
- end
855
+ end
902
856
 
903
- if current_adapter?(:SQLiteAdapter)
857
+ if current_adapter?(:SQLite3Adapter)
904
858
  def test_rename_table_for_sqlite_should_work_with_reserved_words
905
859
  begin
906
860
  assert_nothing_raised do
@@ -952,14 +906,20 @@ if ActiveRecord::Base.connection.supports_migrations?
952
906
  Person.connection.add_column "people", "funny", :boolean
953
907
  Person.reset_column_information
954
908
  assert Person.columns_hash["funny"].null, "Column 'funny' must initially allow nulls"
955
- unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
909
+ unless current_adapter?(:IBM_DBAdapter)
956
910
  Person.connection.change_column "people", "funny", :boolean, :null => false, :default => true
911
+ else
912
+ Person.connection.change_column_null "people", "funny",false
913
+ end
957
914
  Person.reset_column_information
958
915
  assert !Person.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point"
916
+ unless current_adapter?(:IBM_DBAdapter)
959
917
  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
918
+ else
919
+ Person.connection.change_column_null "people", "funny",true
920
+ end
921
+ Person.reset_column_information
922
+ assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
963
923
  end
964
924
 
965
925
  def test_rename_table_with_an_index
@@ -985,39 +945,44 @@ if ActiveRecord::Base.connection.supports_migrations?
985
945
  end
986
946
  end
987
947
 
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 }
948
+ unless current_adapter?(:IBM_DBAdapter)
949
+ # Cannot convert from type integer to varchar.
950
+ # Safe to not run this test as add_column will be covered in other test cases
951
+ def test_change_column
952
+ Person.connection.add_column 'people', 'age', :integer
953
+ label = "test_change_column Columns"
954
+ old_columns = Person.connection.columns(Person.table_name, label)
955
+ assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
994
956
 
995
- assert_nothing_raised { Person.connection.change_column "people", "age", :string }
957
+ assert_nothing_raised { Person.connection.change_column "people", "age", :string }
996
958
 
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 }
959
+ new_columns = Person.connection.columns(Person.table_name, label)
960
+ assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
961
+ assert new_columns.find { |c| c.name == 'age' and c.type == :string }
1000
962
 
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 }
963
+ old_columns = Topic.connection.columns(Topic.table_name, label)
964
+ assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
965
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
966
+ new_columns = Topic.connection.columns(Topic.table_name, label)
967
+ assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
968
+ assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
969
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
970
+ end
1008
971
  end
1009
- end
1010
-
972
+
1011
973
  def test_change_column_with_nil_default
1012
974
  Person.connection.add_column "people", "contributor", :boolean, :default => true
1013
975
  Person.reset_column_information
1014
976
  assert Person.new.contributor?
1015
- unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
977
+
978
+ unless current_adapter?(:IBM_DBAdapter)
1016
979
  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
980
+ else
981
+ assert_nothing_raised { Person.connection.change_column_default "people", "contributor", nil }
982
+ end
983
+ Person.reset_column_information
984
+ assert !Person.new.contributor?
985
+ assert_nil Person.new.contributor
1021
986
  ensure
1022
987
  Person.connection.remove_column("people", "contributor") rescue nil
1023
988
  end
@@ -1026,11 +991,14 @@ if ActiveRecord::Base.connection.supports_migrations?
1026
991
  Person.connection.add_column "people", "administrator", :boolean, :default => true
1027
992
  Person.reset_column_information
1028
993
  assert Person.new.administrator?
1029
- unless current_adapter?(:IBM_DBAdapter) # incompatible types changes
994
+
995
+ unless current_adapter?(:IBM_DBAdapter)
1030
996
  assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
1031
- Person.reset_column_information
1032
- assert !Person.new.administrator?
1033
- end
997
+ else
998
+ assert_nothing_raised { Person.connection.change_column_default "people", "administrator", false }
999
+ end
1000
+ Person.reset_column_information
1001
+ assert !Person.new.administrator?
1034
1002
  ensure
1035
1003
  Person.connection.remove_column("people", "administrator") rescue nil
1036
1004
  end
@@ -1043,10 +1011,11 @@ if ActiveRecord::Base.connection.supports_migrations?
1043
1011
 
1044
1012
  def test_change_column_quotes_column_names
1045
1013
  Person.connection.create_table :testings do |t|
1046
- if current_adapter?(:IBM_DBAdapter)
1047
- t.column :select, :string, :limit => 5
1048
- else
1014
+ unless current_adapter?(:IBM_DBAdapter)
1049
1015
  t.column :select, :string
1016
+ else
1017
+ # If no limit specified by default column of length 255 is created, which later cannot be scaled down to 10
1018
+ t.column :select, :string, :limit => 5
1050
1019
  end
1051
1020
  end
1052
1021
 
@@ -1087,16 +1056,16 @@ if ActiveRecord::Base.connection.supports_migrations?
1087
1056
  assert_equal false, person_klass.columns_hash["wealth"].null
1088
1057
 
1089
1058
  # 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)
1059
+ if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
1091
1060
  person_klass.connection.rename_column "testings", "wealth", "money"
1092
1061
  person_klass.reset_column_information
1093
1062
  assert_nil person_klass.columns_hash["wealth"]
1094
1063
  assert_equal 100, person_klass.columns_hash["money"].default
1095
1064
  assert_equal false, person_klass.columns_hash["money"].null
1096
- end
1065
+ end
1097
1066
 
1098
1067
  # change column
1099
- unless (current_adapter?(:IBM_DBAdapter) && !@ibm_db_rename_supported)
1068
+ unless current_adapter?(:IBM_DBAdapter)
1100
1069
  person_klass.connection.change_column "testings", "money", :integer, :null => false, :default => 1000
1101
1070
  person_klass.reset_column_information
1102
1071
  assert_equal 1000, person_klass.columns_hash["money"].default
@@ -1106,10 +1075,10 @@ if ActiveRecord::Base.connection.supports_migrations?
1106
1075
  person_klass.reset_column_information
1107
1076
  assert_equal 1000, person_klass.columns_hash["wealth"].default
1108
1077
  assert_equal false, person_klass.columns_hash["wealth"].null
1109
- end
1078
+ end
1110
1079
 
1111
1080
  # change column, make it nullable and clear default
1112
- unless (current_adapter?(:IBM_DBAdapter) && !@ibm_db_rename_supported)
1081
+ unless current_adapter?(:IBM_DBAdapter)
1113
1082
  person_klass.connection.change_column "testings", "money", :integer, :null => true, :default => nil
1114
1083
  person_klass.reset_column_information
1115
1084
  assert_nil person_klass.columns_hash["money"].default
@@ -1119,10 +1088,10 @@ if ActiveRecord::Base.connection.supports_migrations?
1119
1088
  person_klass.reset_column_information
1120
1089
  assert_nil person_klass.columns_hash["wealth"].default
1121
1090
  assert_equal true, person_klass.columns_hash["wealth"].null
1122
- end
1091
+ end
1123
1092
 
1124
1093
  # 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)
1094
+ unless current_adapter?(:IBM_DBAdapter)
1126
1095
  person_klass.connection.execute('UPDATE testings SET money = NULL')
1127
1096
  person_klass.connection.change_column_null "testings", "money", false, 2000
1128
1097
  person_klass.reset_column_information
@@ -1131,12 +1100,15 @@ if ActiveRecord::Base.connection.supports_migrations?
1131
1100
  assert_equal [2000], Person.connection.select_values("SELECT money FROM testings").map { |s| s.to_i }.sort
1132
1101
  else
1133
1102
  # 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')
1103
+ # in the next statement a not null constraint is being applied which is wrong
1104
+ #person_klass.connection.execute('UPDATE testings SET money = NULL')
1136
1105
  person_klass.connection.change_column_null "testings", "wealth", false, 2000
1137
1106
  person_klass.reset_column_information
1107
+ #assert_nil person_klass.columns_hash["wealth"].default #Setting default to 2000 and expecting nil is nor correct
1108
+ assert_not_nil person_klass.columns_hash["wealth"].default
1138
1109
  assert_equal false, person_klass.columns_hash["wealth"].null
1139
- assert_equal 2000, person_klass.columns_hash["wealth"].default
1110
+ #Changing default does not change the already inserted value. Hence expecting 2000 is wrong.
1111
+ assert_equal [99], Person.connection.select_values("SELECT wealth FROM testings").map { |s| s.to_i }.sort
1140
1112
  end
1141
1113
  ensure
1142
1114
  Person.connection.drop_table :testings rescue nil
@@ -1187,6 +1159,18 @@ if ActiveRecord::Base.connection.supports_migrations?
1187
1159
  Person.connection.drop_table :testings rescue nil
1188
1160
  end
1189
1161
 
1162
+ def test_column_exists_on_table_with_no_options_parameter_supplied
1163
+ Person.connection.create_table :testings do |t|
1164
+ t.string :foo
1165
+ end
1166
+ Person.connection.change_table :testings do |t|
1167
+ assert t.column_exists?(:foo)
1168
+ assert !(t.column_exists?(:bar))
1169
+ end
1170
+ ensure
1171
+ Person.connection.drop_table :testings rescue nil
1172
+ end
1173
+
1190
1174
  def test_add_table
1191
1175
  assert !Reminder.table_exists?
1192
1176
 
@@ -1224,17 +1208,17 @@ if ActiveRecord::Base.connection.supports_migrations?
1224
1208
 
1225
1209
  # TODO: set world_population >= 2**62 to cover 64-bit platforms and test
1226
1210
  # is_a?(Bignum)
1227
- unless current_adapter?(:IBM_DBAdapter) # incompatible types retrieved
1211
+ unless current_adapter?(:IBM_DBAdapter)
1228
1212
  assert_kind_of Integer, b.world_population
1229
1213
  else
1230
1214
  assert_kind_of BigDecimal, b.world_population
1231
- end
1215
+ end
1232
1216
  assert_equal 6000000000, b.world_population
1233
- unless current_adapter?(:IBM_DBAdapter) # incompatible types retrieved
1217
+ unless current_adapter?(:IBM_DBAdapter)
1234
1218
  assert_kind_of Fixnum, b.my_house_population
1235
1219
  else
1236
1220
  assert_kind_of BigDecimal, b.my_house_population
1237
- end
1221
+ end
1238
1222
  assert_equal 3, b.my_house_population
1239
1223
  assert_kind_of BigDecimal, b.bank_balance
1240
1224
  assert_equal BigDecimal("1586.43"), b.bank_balance
@@ -1254,17 +1238,17 @@ if ActiveRecord::Base.connection.supports_migrations?
1254
1238
  # so this happens there too
1255
1239
  assert_kind_of BigDecimal, b.value_of_e
1256
1240
  assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
1257
- elsif current_adapter?(:SQLiteAdapter)
1241
+ elsif current_adapter?(:SQLite3Adapter)
1258
1242
  # - SQLite3 stores a float, in violation of SQL
1259
1243
  assert_kind_of BigDecimal, b.value_of_e
1260
1244
  assert_in_delta BigDecimal("2.71828182845905"), b.value_of_e, 0.00000000000001
1261
1245
  else
1262
1246
  # - 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
1247
+ unless current_adapter?(:IBM_DBAdapter)
1248
+ assert_kind_of Fixnum, b.value_of_e
1249
+ else
1250
+ assert_kind_of BigDecimal, b.value_of_e
1251
+ end
1268
1252
  assert_equal 2, b.value_of_e
1269
1253
  end
1270
1254
 
@@ -1292,6 +1276,44 @@ if ActiveRecord::Base.connection.supports_migrations?
1292
1276
  assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
1293
1277
  end
1294
1278
 
1279
+ class MockMigration < ActiveRecord::Migration
1280
+ attr_reader :went_up, :went_down
1281
+ def initialize
1282
+ @went_up = false
1283
+ @went_down = false
1284
+ end
1285
+
1286
+ def up
1287
+ @went_up = true
1288
+ super
1289
+ end
1290
+
1291
+ def down
1292
+ @went_down = true
1293
+ super
1294
+ end
1295
+ end
1296
+
1297
+ def test_instance_based_migration_up
1298
+ migration = MockMigration.new
1299
+ assert !migration.went_up, 'have not gone up'
1300
+ assert !migration.went_down, 'have not gone down'
1301
+
1302
+ migration.migrate :up
1303
+ assert migration.went_up, 'have gone up'
1304
+ assert !migration.went_down, 'have not gone down'
1305
+ end
1306
+
1307
+ def test_instance_based_migration_down
1308
+ migration = MockMigration.new
1309
+ assert !migration.went_up, 'have not gone up'
1310
+ assert !migration.went_down, 'have not gone down'
1311
+
1312
+ migration.migrate :down
1313
+ assert !migration.went_up, 'have gone up'
1314
+ assert migration.went_down, 'have not gone down'
1315
+ end
1316
+
1295
1317
  def test_migrator_one_up
1296
1318
  assert !Person.column_methods_hash.include?(:last_name)
1297
1319
  assert !Reminder.table_exists?
@@ -1359,51 +1381,56 @@ if ActiveRecord::Base.connection.supports_migrations?
1359
1381
  def test_finds_migrations
1360
1382
  migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid").migrations
1361
1383
 
1362
- [[1, 'PeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i|
1384
+ [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i|
1363
1385
  assert_equal migrations[i].version, pair.first
1364
1386
  assert_equal migrations[i].name, pair.last
1365
1387
  end
1366
1388
  end
1367
1389
 
1390
+ def test_finds_migrations_from_two_directories
1391
+ directories = [MIGRATIONS_ROOT + '/valid_with_timestamps', MIGRATIONS_ROOT + '/to_copy_with_timestamps']
1392
+ migrations = ActiveRecord::Migrator.new(:up, directories).migrations
1393
+
1394
+ [[20090101010101, "PeopleHaveHobbies"],
1395
+ [20090101010202, "PeopleHaveDescriptions"],
1396
+ [20100101010101, "ValidWithTimestampsPeopleHaveLastNames"],
1397
+ [20100201010101, "ValidWithTimestampsWeNeedReminders"],
1398
+ [20100301010101, "ValidWithTimestampsInnocentJointable"]].each_with_index do |pair, i|
1399
+ assert_equal pair.first, migrations[i].version
1400
+ assert_equal pair.last, migrations[i].name
1401
+ end
1402
+ end
1403
+
1368
1404
  def test_finds_pending_migrations
1369
1405
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2", 1)
1370
1406
  migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/interleaved/pass_2").pending_migrations
1371
1407
 
1372
1408
  assert_equal 1, migrations.size
1373
1409
  assert_equal migrations[0].version, 3
1374
- assert_equal migrations[0].name, 'InnocentJointable'
1410
+ assert_equal migrations[0].name, 'InterleavedInnocentJointable'
1375
1411
  end
1376
1412
 
1377
1413
  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
1414
+ list = Dir.chdir(MIGRATIONS_ROOT) do
1384
1415
  ActiveRecord::Migrator.up("valid/", 1)
1385
1416
  end
1386
1417
 
1387
- assert defined?(PeopleHaveLastNames)
1418
+ migration_proxy = list.find { |item|
1419
+ item.name == 'ValidPeopleHaveLastNames'
1420
+ }
1421
+ assert migration_proxy, 'should find pending migration'
1388
1422
  end
1389
1423
 
1390
1424
  def test_only_loads_pending_migrations
1391
1425
  # migrate up to 1
1392
1426
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1393
1427
 
1394
- # now unload the migrations that have been defined
1395
- Object.send(:remove_const, :PeopleHaveLastNames)
1396
-
1397
- ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", nil)
1398
-
1399
- assert !defined? PeopleHaveLastNames
1400
-
1401
- %w(WeNeedReminders, InnocentJointable).each do |migration|
1402
- assert defined? migration
1403
- end
1428
+ proxies = ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", nil)
1404
1429
 
1405
- ensure
1406
- load(MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
1430
+ names = proxies.map(&:name)
1431
+ assert !names.include?('ValidPeopleHaveLastNames')
1432
+ assert names.include?('WeNeedReminders')
1433
+ assert names.include?('InnocentJointable')
1407
1434
  end
1408
1435
 
1409
1436
  def test_target_version_zero_should_run_only_once
@@ -1413,16 +1440,9 @@ if ActiveRecord::Base.connection.supports_migrations?
1413
1440
  # migrate down to 0
1414
1441
  ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
1415
1442
 
1416
- # now unload the migrations that have been defined
1417
- PeopleHaveLastNames.unloadable
1418
- ActiveSupport::Dependencies.remove_unloadable_constants!
1419
-
1420
1443
  # 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")
1444
+ proxies = ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
1445
+ assert_equal [], proxies
1426
1446
  end
1427
1447
 
1428
1448
  def test_migrator_db_has_no_schema_migrations_table
@@ -1439,20 +1459,20 @@ if ActiveRecord::Base.connection.supports_migrations?
1439
1459
 
1440
1460
  def test_migrator_verbosity
1441
1461
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1442
- assert PeopleHaveLastNames.message_count > 0
1443
- PeopleHaveLastNames.message_count = 0
1462
+ assert_not_equal 0, ActiveRecord::Migration.message_count
1463
+ ActiveRecord::Migration.message_count = 0
1444
1464
 
1445
1465
  ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
1446
- assert PeopleHaveLastNames.message_count > 0
1447
- PeopleHaveLastNames.message_count = 0
1466
+ assert_not_equal 0, ActiveRecord::Migration.message_count
1467
+ ActiveRecord::Migration.message_count = 0
1448
1468
  end
1449
1469
 
1450
1470
  def test_migrator_verbosity_off
1451
- PeopleHaveLastNames.verbose = false
1471
+ ActiveRecord::Migration.verbose = false
1452
1472
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
1453
- assert PeopleHaveLastNames.message_count.zero?
1473
+ assert_equal 0, ActiveRecord::Migration.message_count
1454
1474
  ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
1455
- assert PeopleHaveLastNames.message_count.zero?
1475
+ assert_equal 0, ActiveRecord::Migration.message_count
1456
1476
  end
1457
1477
 
1458
1478
  def test_migrator_going_down_due_to_version_target
@@ -1715,13 +1735,23 @@ if ActiveRecord::Base.connection.supports_migrations?
1715
1735
  end
1716
1736
  end
1717
1737
 
1718
- if current_adapter?(:PostgreSQLAdapter)
1738
+ if current_adapter?(:PostgreSQLAdapter) || current_adapter?(:SQLite3Adapter) || current_adapter?(:MysqlAdapter) || current_adapter?(:Mysql2Adapter) || current_adapter?(:IBM_DBAdapter)
1719
1739
  def test_xml_creates_xml_column
1740
+ type = (current_adapter?(:PostgreSQLAdapter) || current_adapter?(:IBM_DBAdapter)) ? 'xml' : :text
1741
+
1720
1742
  with_new_table do |t|
1721
- t.expects(:column).with(:data, 'xml', {})
1743
+ t.expects(:column).with(:data, type, {})
1722
1744
  t.xml :data
1723
1745
  end
1724
1746
  end
1747
+ else
1748
+ def test_xml_creates_xml_column
1749
+ with_new_table do |t|
1750
+ assert_raises(NotImplementedError) do
1751
+ t.xml :data
1752
+ end
1753
+ end
1754
+ end
1725
1755
  end
1726
1756
 
1727
1757
  protected
@@ -1736,10 +1766,6 @@ if ActiveRecord::Base.connection.supports_migrations?
1736
1766
  end # SexyMigrationsTest
1737
1767
 
1738
1768
  class MigrationLoggerTest < ActiveRecord::TestCase
1739
- def setup
1740
- Object.send(:remove_const, :InnocentJointable)
1741
- end
1742
-
1743
1769
  def test_migration_should_be_run_without_logger
1744
1770
  previous_logger = ActiveRecord::Base.logger
1745
1771
  ActiveRecord::Base.logger = nil
@@ -1752,10 +1778,6 @@ if ActiveRecord::Base.connection.supports_migrations?
1752
1778
  end
1753
1779
 
1754
1780
  class InterleavedMigrationsTest < ActiveRecord::TestCase
1755
- def setup
1756
- Object.send(:remove_const, :PeopleHaveLastNames)
1757
- end
1758
-
1759
1781
  def test_migrator_interleaved_migrations
1760
1782
  ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_1")
1761
1783
 
@@ -1766,10 +1788,12 @@ if ActiveRecord::Base.connection.supports_migrations?
1766
1788
  Person.reset_column_information
1767
1789
  assert Person.column_methods_hash.include?(:last_name)
1768
1790
 
1769
- Object.send(:remove_const, :PeopleHaveLastNames)
1770
- Object.send(:remove_const, :InnocentJointable)
1771
1791
  assert_nothing_raised do
1772
- ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/interleaved/pass_3")
1792
+ proxies = ActiveRecord::Migrator.down(
1793
+ MIGRATIONS_ROOT + "/interleaved/pass_3")
1794
+ names = proxies.map(&:name)
1795
+ assert names.include?('InterleavedPeopleHaveLastNames')
1796
+ assert names.include?('InterleavedInnocentJointable')
1773
1797
  end
1774
1798
  end
1775
1799
  end
@@ -2010,5 +2034,307 @@ if ActiveRecord::Base.connection.supports_migrations?
2010
2034
  end
2011
2035
  end
2012
2036
  end
2013
- end
2014
2037
 
2038
+ if ActiveRecord::Base.connection.supports_bulk_alter?
2039
+ class BulkAlterTableMigrationsTest < ActiveRecord::TestCase
2040
+ def setup
2041
+ @connection = Person.connection
2042
+ @connection.create_table(:delete_me, :force => true) {|t| }
2043
+ end
2044
+
2045
+ def teardown
2046
+ Person.connection.drop_table(:delete_me) rescue nil
2047
+ end
2048
+
2049
+ def test_adding_multiple_columns
2050
+ assert_queries(1) do
2051
+ with_bulk_change_table do |t|
2052
+ t.column :name, :string
2053
+ t.string :qualification, :experience
2054
+ t.integer :age, :default => 0
2055
+ t.date :birthdate
2056
+ t.timestamps
2057
+ end
2058
+ end
2059
+
2060
+ assert_equal 8, columns.size
2061
+ [:name, :qualification, :experience].each {|s| assert_equal :string, column(s).type }
2062
+ assert_equal 0, column(:age).default
2063
+ end
2064
+
2065
+ def test_removing_columns
2066
+ with_bulk_change_table do |t|
2067
+ t.string :qualification, :experience
2068
+ end
2069
+
2070
+ [:qualification, :experience].each {|c| assert column(c) }
2071
+
2072
+ assert_queries(1) do
2073
+ with_bulk_change_table do |t|
2074
+ t.remove :qualification, :experience
2075
+ t.string :qualification_experience
2076
+ end
2077
+ end
2078
+
2079
+ [:qualification, :experience].each {|c| assert ! column(c) }
2080
+ assert column(:qualification_experience)
2081
+ end
2082
+
2083
+ def test_adding_indexes
2084
+ with_bulk_change_table do |t|
2085
+ t.string :username
2086
+ t.string :name
2087
+ t.integer :age
2088
+ end
2089
+
2090
+ # Adding an index fires a query every time to check if an index already exists or not
2091
+ assert_queries(3) do
2092
+ with_bulk_change_table do |t|
2093
+ t.index :username, :unique => true, :name => :awesome_username_index
2094
+ t.index [:name, :age]
2095
+ end
2096
+ end
2097
+
2098
+ assert_equal 2, indexes.size
2099
+
2100
+ name_age_index = index(:index_delete_me_on_name_and_age)
2101
+ assert_equal ['name', 'age'].sort, name_age_index.columns.sort
2102
+ assert ! name_age_index.unique
2103
+
2104
+ assert index(:awesome_username_index).unique
2105
+ end
2106
+
2107
+ def test_removing_index
2108
+ with_bulk_change_table do |t|
2109
+ t.string :name
2110
+ t.index :name
2111
+ end
2112
+
2113
+ assert index(:index_delete_me_on_name)
2114
+
2115
+ assert_queries(3) do
2116
+ with_bulk_change_table do |t|
2117
+ t.remove_index :name
2118
+ t.index :name, :name => :new_name_index, :unique => true
2119
+ end
2120
+ end
2121
+
2122
+ assert ! index(:index_delete_me_on_name)
2123
+
2124
+ new_name_index = index(:new_name_index)
2125
+ assert new_name_index.unique
2126
+ end
2127
+
2128
+ def test_changing_columns
2129
+ with_bulk_change_table do |t|
2130
+ t.string :name
2131
+ t.date :birthdate
2132
+ end
2133
+
2134
+ assert ! column(:name).default
2135
+ assert_equal :date, column(:birthdate).type
2136
+
2137
+ # One query for columns (delete_me table)
2138
+ # One query for primary key (delete_me table)
2139
+ # One query to do the bulk change
2140
+ assert_queries(3) do
2141
+ with_bulk_change_table do |t|
2142
+ t.change :name, :string, :default => 'NONAME'
2143
+ t.change :birthdate, :datetime
2144
+ end
2145
+ end
2146
+
2147
+ assert_equal 'NONAME', column(:name).default
2148
+ assert_equal :datetime, column(:birthdate).type
2149
+ end
2150
+
2151
+ protected
2152
+
2153
+ def with_bulk_change_table
2154
+ # Reset columns/indexes cache as we're changing the table
2155
+ @columns = @indexes = nil
2156
+
2157
+ Person.connection.change_table(:delete_me, :bulk => true) do |t|
2158
+ yield t
2159
+ end
2160
+ end
2161
+
2162
+ def column(name)
2163
+ columns.detect {|c| c.name == name.to_s }
2164
+ end
2165
+
2166
+ def columns
2167
+ @columns ||= Person.connection.columns('delete_me')
2168
+ end
2169
+
2170
+ def index(name)
2171
+ indexes.detect {|i| i.name == name.to_s }
2172
+ end
2173
+
2174
+ def indexes
2175
+ @indexes ||= Person.connection.indexes('delete_me')
2176
+ end
2177
+ end # AlterTableMigrationsTest
2178
+
2179
+ end
2180
+
2181
+ class CopyMigrationsTest < ActiveRecord::TestCase
2182
+ def setup
2183
+ end
2184
+
2185
+ def clear
2186
+ ActiveRecord::Base.timestamped_migrations = true
2187
+ to_delete = Dir[@migrations_path + "/*.rb"] - @existing_migrations
2188
+ File.delete(*to_delete)
2189
+ end
2190
+
2191
+ def test_copying_migrations_without_timestamps
2192
+ ActiveRecord::Base.timestamped_migrations = false
2193
+ @migrations_path = MIGRATIONS_ROOT + "/valid"
2194
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2195
+
2196
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
2197
+ assert File.exists?(@migrations_path + "/4_people_have_hobbies.rb")
2198
+ assert File.exists?(@migrations_path + "/5_people_have_descriptions.rb")
2199
+ assert_equal [@migrations_path + "/4_people_have_hobbies.rb", @migrations_path + "/5_people_have_descriptions.rb"], copied.map(&:filename)
2200
+
2201
+ files_count = Dir[@migrations_path + "/*.rb"].length
2202
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
2203
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2204
+ assert copied.empty?
2205
+ ensure
2206
+ clear
2207
+ end
2208
+
2209
+ def test_copying_migrations_without_timestamps_from_2_sources
2210
+ ActiveRecord::Base.timestamped_migrations = false
2211
+ @migrations_path = MIGRATIONS_ROOT + "/valid"
2212
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2213
+
2214
+ sources = ActiveSupport::OrderedHash.new
2215
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy"
2216
+ sources[:omg] = MIGRATIONS_ROOT + "/to_copy2"
2217
+ ActiveRecord::Migration.copy(@migrations_path, sources)
2218
+ assert File.exists?(@migrations_path + "/4_people_have_hobbies.rb")
2219
+ assert File.exists?(@migrations_path + "/5_people_have_descriptions.rb")
2220
+ assert File.exists?(@migrations_path + "/6_create_articles.rb")
2221
+ assert File.exists?(@migrations_path + "/7_create_comments.rb")
2222
+
2223
+ files_count = Dir[@migrations_path + "/*.rb"].length
2224
+ ActiveRecord::Migration.copy(@migrations_path, sources)
2225
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2226
+ ensure
2227
+ clear
2228
+ end
2229
+
2230
+ def test_copying_migrations_with_timestamps
2231
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2232
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2233
+
2234
+ Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
2235
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2236
+ assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.rb")
2237
+ assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.rb")
2238
+ expected = [@migrations_path + "/20100726101010_people_have_hobbies.rb",
2239
+ @migrations_path + "/20100726101011_people_have_descriptions.rb"]
2240
+ assert_equal expected, copied.map(&:filename)
2241
+
2242
+ files_count = Dir[@migrations_path + "/*.rb"].length
2243
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2244
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2245
+ assert copied.empty?
2246
+ end
2247
+ ensure
2248
+ clear
2249
+ end
2250
+
2251
+ def test_copying_migrations_with_timestamps_from_2_sources
2252
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2253
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2254
+
2255
+ sources = ActiveSupport::OrderedHash.new
2256
+ sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
2257
+ sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps2"
2258
+
2259
+ Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
2260
+ copied = ActiveRecord::Migration.copy(@migrations_path, sources)
2261
+ assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.rb")
2262
+ assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.rb")
2263
+ assert File.exists?(@migrations_path + "/20100726101012_create_articles.rb")
2264
+ assert File.exists?(@migrations_path + "/20100726101013_create_comments.rb")
2265
+ assert_equal 4, copied.length
2266
+
2267
+ files_count = Dir[@migrations_path + "/*.rb"].length
2268
+ ActiveRecord::Migration.copy(@migrations_path, sources)
2269
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2270
+ end
2271
+ ensure
2272
+ clear
2273
+ end
2274
+
2275
+ def test_copying_migrations_with_timestamps_to_destination_with_timestamps_in_future
2276
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2277
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2278
+
2279
+ Time.travel_to(Time.utc(2010, 2, 20, 10, 10, 10)) do
2280
+ ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2281
+ assert File.exists?(@migrations_path + "/20100301010102_people_have_hobbies.rb")
2282
+ assert File.exists?(@migrations_path + "/20100301010103_people_have_descriptions.rb")
2283
+
2284
+ files_count = Dir[@migrations_path + "/*.rb"].length
2285
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2286
+ assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
2287
+ assert copied.empty?
2288
+ end
2289
+ ensure
2290
+ clear
2291
+ end
2292
+
2293
+ def test_skipping_migrations
2294
+ @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
2295
+ @existing_migrations = Dir[@migrations_path + "/*.rb"]
2296
+
2297
+ sources = ActiveSupport::OrderedHash.new
2298
+ sources[:bukkits] = sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
2299
+
2300
+ skipped = []
2301
+ on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
2302
+ copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
2303
+ assert_equal 2, copied.length
2304
+
2305
+ assert_equal 2, skipped.length
2306
+ assert_equal ["bukkits PeopleHaveHobbies", "bukkits PeopleHaveDescriptions"], skipped
2307
+ ensure
2308
+ clear
2309
+ end
2310
+
2311
+ def test_copying_migrations_to_non_existing_directory
2312
+ @migrations_path = MIGRATIONS_ROOT + "/non_existing"
2313
+ @existing_migrations = []
2314
+
2315
+ Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
2316
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2317
+ assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.rb")
2318
+ assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.rb")
2319
+ assert_equal 2, copied.length
2320
+ end
2321
+ ensure
2322
+ clear
2323
+ Dir.delete(@migrations_path)
2324
+ end
2325
+
2326
+ def test_copying_migrations_to_empty_directory
2327
+ @migrations_path = MIGRATIONS_ROOT + "/empty"
2328
+ @existing_migrations = []
2329
+
2330
+ Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
2331
+ copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
2332
+ assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.rb")
2333
+ assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.rb")
2334
+ assert_equal 2, copied.length
2335
+ end
2336
+ ensure
2337
+ clear
2338
+ end
2339
+ end
2340
+ end