activerecord 1.15.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (185) hide show
  1. data/CHANGELOG +2454 -34
  2. data/README +1 -1
  3. data/RUNNING_UNIT_TESTS +3 -34
  4. data/Rakefile +98 -77
  5. data/install.rb +1 -1
  6. data/lib/active_record.rb +13 -22
  7. data/lib/active_record/aggregations.rb +38 -49
  8. data/lib/active_record/associations.rb +452 -333
  9. data/lib/active_record/associations/association_collection.rb +66 -20
  10. data/lib/active_record/associations/association_proxy.rb +9 -8
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -51
  12. data/lib/active_record/associations/has_many_association.rb +21 -57
  13. data/lib/active_record/associations/has_many_through_association.rb +38 -18
  14. data/lib/active_record/associations/has_one_association.rb +30 -14
  15. data/lib/active_record/attribute_methods.rb +253 -0
  16. data/lib/active_record/base.rb +719 -494
  17. data/lib/active_record/calculations.rb +62 -63
  18. data/lib/active_record/callbacks.rb +57 -83
  19. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +38 -9
  20. data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -15
  21. data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
  22. data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -12
  23. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +191 -62
  24. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -34
  25. data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -17
  26. data/lib/active_record/connection_adapters/mysql_adapter.rb +119 -37
  27. data/lib/active_record/connection_adapters/postgresql_adapter.rb +473 -210
  28. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  29. data/lib/active_record/connection_adapters/sqlite_adapter.rb +91 -107
  30. data/lib/active_record/fixtures.rb +503 -113
  31. data/lib/active_record/locking/optimistic.rb +72 -34
  32. data/lib/active_record/migration.rb +80 -57
  33. data/lib/active_record/observer.rb +13 -10
  34. data/lib/active_record/query_cache.rb +16 -57
  35. data/lib/active_record/reflection.rb +35 -38
  36. data/lib/active_record/schema.rb +5 -5
  37. data/lib/active_record/schema_dumper.rb +35 -13
  38. data/lib/active_record/serialization.rb +98 -0
  39. data/lib/active_record/serializers/json_serializer.rb +71 -0
  40. data/lib/active_record/{xml_serialization.rb → serializers/xml_serializer.rb} +90 -83
  41. data/lib/active_record/timestamp.rb +20 -21
  42. data/lib/active_record/transactions.rb +39 -43
  43. data/lib/active_record/validations.rb +256 -107
  44. data/lib/active_record/version.rb +3 -3
  45. data/lib/activerecord.rb +1 -0
  46. data/test/aaa_create_tables_test.rb +15 -2
  47. data/test/abstract_unit.rb +24 -17
  48. data/test/active_schema_test_mysql.rb +20 -8
  49. data/test/adapter_test.rb +23 -5
  50. data/test/adapter_test_sqlserver.rb +15 -1
  51. data/test/aggregations_test.rb +16 -1
  52. data/test/all.sh +2 -2
  53. data/test/associations/ar_joins_test.rb +0 -0
  54. data/test/associations/callbacks_test.rb +51 -30
  55. data/test/associations/cascaded_eager_loading_test.rb +1 -29
  56. data/test/associations/eager_singularization_test.rb +145 -0
  57. data/test/associations/eager_test.rb +42 -6
  58. data/test/associations/extension_test.rb +6 -1
  59. data/test/associations/inner_join_association_test.rb +88 -0
  60. data/test/associations/join_model_test.rb +47 -16
  61. data/test/associations_test.rb +449 -226
  62. data/test/attribute_methods_test.rb +97 -0
  63. data/test/base_test.rb +251 -105
  64. data/test/binary_test.rb +22 -27
  65. data/test/calculations_test.rb +37 -5
  66. data/test/callbacks_test.rb +23 -0
  67. data/test/connection_test_firebird.rb +2 -2
  68. data/test/connection_test_mysql.rb +30 -0
  69. data/test/connections/native_mysql/connection.rb +3 -0
  70. data/test/connections/native_sqlite/connection.rb +5 -14
  71. data/test/connections/native_sqlite3/connection.rb +5 -14
  72. data/test/connections/native_sqlite3/in_memory_connection.rb +1 -1
  73. data/test/{copy_table_sqlite.rb → copy_table_test_sqlite.rb} +8 -3
  74. data/test/datatype_test_postgresql.rb +178 -27
  75. data/test/{empty_date_time_test.rb → date_time_test.rb} +13 -1
  76. data/test/defaults_test.rb +8 -1
  77. data/test/deprecated_finder_test.rb +7 -128
  78. data/test/finder_test.rb +192 -54
  79. data/test/fixtures/all/developers.yml +0 -0
  80. data/test/fixtures/all/people.csv +0 -0
  81. data/test/fixtures/all/tasks.yml +0 -0
  82. data/test/fixtures/author.rb +12 -5
  83. data/test/fixtures/binaries.yml +130 -435
  84. data/test/fixtures/category.rb +6 -0
  85. data/test/fixtures/company.rb +8 -1
  86. data/test/fixtures/computer.rb +1 -0
  87. data/test/fixtures/contact.rb +16 -0
  88. data/test/fixtures/customer.rb +2 -2
  89. data/test/fixtures/db_definitions/db2.drop.sql +1 -0
  90. data/test/fixtures/db_definitions/db2.sql +4 -0
  91. data/test/fixtures/db_definitions/firebird.drop.sql +3 -1
  92. data/test/fixtures/db_definitions/firebird.sql +6 -0
  93. data/test/fixtures/db_definitions/frontbase.drop.sql +1 -0
  94. data/test/fixtures/db_definitions/frontbase.sql +5 -0
  95. data/test/fixtures/db_definitions/openbase.sql +41 -25
  96. data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
  97. data/test/fixtures/db_definitions/oracle.sql +5 -0
  98. data/test/fixtures/db_definitions/postgresql.drop.sql +7 -0
  99. data/test/fixtures/db_definitions/postgresql.sql +87 -58
  100. data/test/fixtures/db_definitions/postgresql2.sql +1 -2
  101. data/test/fixtures/db_definitions/schema.rb +280 -0
  102. data/test/fixtures/db_definitions/schema2.rb +11 -0
  103. data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
  104. data/test/fixtures/db_definitions/sqlite.sql +4 -0
  105. data/test/fixtures/db_definitions/sybase.drop.sql +1 -0
  106. data/test/fixtures/db_definitions/sybase.sql +4 -0
  107. data/test/fixtures/developer.rb +10 -0
  108. data/test/fixtures/example.log +1 -0
  109. data/test/fixtures/flowers.jpg +0 -0
  110. data/test/fixtures/item.rb +7 -0
  111. data/test/fixtures/items.yml +4 -0
  112. data/test/fixtures/joke.rb +0 -3
  113. data/test/fixtures/matey.rb +4 -0
  114. data/test/fixtures/mateys.yml +4 -0
  115. data/test/fixtures/minimalistic.rb +2 -0
  116. data/test/fixtures/minimalistics.yml +2 -0
  117. data/test/fixtures/mixins.yml +2 -100
  118. data/test/fixtures/parrot.rb +13 -0
  119. data/test/fixtures/parrots.yml +27 -0
  120. data/test/fixtures/parrots_pirates.yml +7 -0
  121. data/test/fixtures/pirate.rb +5 -0
  122. data/test/fixtures/pirates.yml +9 -0
  123. data/test/fixtures/post.rb +1 -0
  124. data/test/fixtures/project.rb +3 -2
  125. data/test/fixtures/reserved_words/distinct.yml +5 -0
  126. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  127. data/test/fixtures/reserved_words/group.yml +14 -0
  128. data/test/fixtures/reserved_words/select.yml +8 -0
  129. data/test/fixtures/reserved_words/values.yml +7 -0
  130. data/test/fixtures/ship.rb +3 -0
  131. data/test/fixtures/ships.yml +5 -0
  132. data/test/fixtures/tagging.rb +4 -0
  133. data/test/fixtures/taggings.yml +8 -1
  134. data/test/fixtures/topic.rb +13 -1
  135. data/test/fixtures/treasure.rb +4 -0
  136. data/test/fixtures/treasures.yml +10 -0
  137. data/test/fixtures_test.rb +205 -24
  138. data/test/inheritance_test.rb +7 -1
  139. data/test/json_serialization_test.rb +180 -0
  140. data/test/lifecycle_test.rb +1 -1
  141. data/test/locking_test.rb +85 -2
  142. data/test/migration_test.rb +206 -40
  143. data/test/mixin_test.rb +13 -515
  144. data/test/pk_test.rb +3 -6
  145. data/test/query_cache_test.rb +104 -0
  146. data/test/reflection_test.rb +16 -0
  147. data/test/reserved_word_test_mysql.rb +177 -0
  148. data/test/schema_dumper_test.rb +38 -3
  149. data/test/serialization_test.rb +47 -0
  150. data/test/transactions_test.rb +74 -23
  151. data/test/unconnected_test.rb +1 -1
  152. data/test/validations_test.rb +322 -32
  153. data/test/xml_serialization_test.rb +121 -44
  154. metadata +48 -41
  155. data/examples/associations.rb +0 -87
  156. data/examples/shared_setup.rb +0 -15
  157. data/examples/validation.rb +0 -85
  158. data/lib/active_record/acts/list.rb +0 -256
  159. data/lib/active_record/acts/nested_set.rb +0 -211
  160. data/lib/active_record/acts/tree.rb +0 -96
  161. data/lib/active_record/connection_adapters/db2_adapter.rb +0 -228
  162. data/lib/active_record/connection_adapters/firebird_adapter.rb +0 -728
  163. data/lib/active_record/connection_adapters/frontbase_adapter.rb +0 -861
  164. data/lib/active_record/connection_adapters/openbase_adapter.rb +0 -350
  165. data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -690
  166. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +0 -591
  167. data/lib/active_record/connection_adapters/sybase_adapter.rb +0 -662
  168. data/lib/active_record/deprecated_associations.rb +0 -104
  169. data/lib/active_record/deprecated_finders.rb +0 -44
  170. data/lib/active_record/vendor/simple.rb +0 -693
  171. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  172. data/lib/active_record/wrappings.rb +0 -58
  173. data/test/connections/native_sqlserver/connection.rb +0 -23
  174. data/test/connections/native_sqlserver_odbc/connection.rb +0 -25
  175. data/test/deprecated_associations_test.rb +0 -396
  176. data/test/fixtures/db_definitions/mysql.drop.sql +0 -32
  177. data/test/fixtures/db_definitions/mysql.sql +0 -234
  178. data/test/fixtures/db_definitions/mysql2.drop.sql +0 -2
  179. data/test/fixtures/db_definitions/mysql2.sql +0 -5
  180. data/test/fixtures/db_definitions/sqlserver.drop.sql +0 -34
  181. data/test/fixtures/db_definitions/sqlserver.sql +0 -243
  182. data/test/fixtures/db_definitions/sqlserver2.drop.sql +0 -2
  183. data/test/fixtures/db_definitions/sqlserver2.sql +0 -5
  184. data/test/fixtures/mixin.rb +0 -63
  185. data/test/mixin_nested_set_test.rb +0 -196
@@ -6,6 +6,13 @@ require 'fixtures/subscriber'
6
6
  class InheritanceTest < Test::Unit::TestCase
7
7
  fixtures :companies, :projects, :subscribers, :accounts
8
8
 
9
+ def test_company_descends_from_active_record
10
+ assert_raise(NoMethodError) { ActiveRecord::Base.descends_from_active_record? }
11
+ assert AbstractCompany.descends_from_active_record?, 'AbstractCompany should descend from ActiveRecord::Base'
12
+ assert Company.descends_from_active_record?, 'Company should descend from ActiveRecord::Base'
13
+ assert !Class.new(Company).descends_from_active_record?, 'Company subclass should not descend from ActiveRecord::Base'
14
+ end
15
+
9
16
  def test_a_bad_type_column
10
17
  #SQLServer need to turn Identity Insert On before manually inserting into the Identity column
11
18
  if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
@@ -144,7 +151,6 @@ class InheritanceTest < Test::Unit::TestCase
144
151
  switch_to_alt_inheritance_column
145
152
  test_eager_load_belongs_to_something_inherited
146
153
  switch_to_default_inheritance_column
147
- ActiveRecord::Base.logger.debug "cocksucker"
148
154
  end
149
155
 
150
156
  def test_inheritance_without_mapping
@@ -0,0 +1,180 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/contact'
3
+ require 'fixtures/post'
4
+ require 'fixtures/author'
5
+ require 'fixtures/tagging'
6
+ require 'fixtures/tag'
7
+ require 'fixtures/comment'
8
+
9
+ class JsonSerializationTest < Test::Unit::TestCase
10
+ def setup
11
+ @contact = Contact.new(
12
+ :name => 'Konata Izumi',
13
+ :age => 16,
14
+ :avatar => 'binarydata',
15
+ :created_at => Time.utc(2006, 8, 1),
16
+ :awesome => true,
17
+ :preferences => { :shows => 'anime' }
18
+ )
19
+ end
20
+
21
+ def test_should_encode_all_encodable_attributes
22
+ json = @contact.to_json
23
+
24
+ assert_match %r{"name": "Konata Izumi"}, json
25
+ assert_match %r{"age": 16}, json
26
+ assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
27
+ assert_match %r{"awesome": true}, json
28
+ assert_match %r{"preferences": \{"shows": "anime"\}}, json
29
+ end
30
+
31
+ def test_should_allow_attribute_filtering_with_only
32
+ json = @contact.to_json(:only => [:name, :age])
33
+
34
+ assert_match %r{"name": "Konata Izumi"}, json
35
+ assert_match %r{"age": 16}, json
36
+ assert_no_match %r{"awesome": true}, json
37
+ assert !json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
38
+ assert_no_match %r{"preferences": \{"shows": "anime"\}}, json
39
+ end
40
+
41
+ def test_should_allow_attribute_filtering_with_except
42
+ json = @contact.to_json(:except => [:name, :age])
43
+
44
+ assert_no_match %r{"name": "Konata Izumi"}, json
45
+ assert_no_match %r{"age": 16}, json
46
+ assert_match %r{"awesome": true}, json
47
+ assert json.include?(%("created_at": #{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
48
+ assert_match %r{"preferences": \{"shows": "anime"\}}, json
49
+ end
50
+
51
+ def test_methods_are_called_on_object
52
+ # Define methods on fixture.
53
+ def @contact.label; "Has cheezburger"; end
54
+ def @contact.favorite_quote; "Constraints are liberating"; end
55
+
56
+ # Single method.
57
+ assert_match %r{"label": "Has cheezburger"}, @contact.to_json(:only => :name, :methods => :label)
58
+
59
+ # Both methods.
60
+ methods_json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote])
61
+ assert_match %r{"label": "Has cheezburger"}, methods_json
62
+ assert_match %r{"favorite_quote": "Constraints are liberating"}, methods_json
63
+ end
64
+ end
65
+
66
+ class DatabaseConnectedJsonEncodingTest < Test::Unit::TestCase
67
+ fixtures :authors, :posts, :comments, :tags, :taggings
68
+
69
+ def setup
70
+ @david = authors(:david)
71
+ @mary = authors(:mary)
72
+ end
73
+
74
+ def test_includes_uses_association_name
75
+ json = @david.to_json(:include => :posts)
76
+
77
+ assert_match %r{"posts": \[}, json
78
+
79
+ assert_match %r{"id": 1}, json
80
+ assert_match %r{"name": "David"}, json
81
+
82
+ assert_match %r{"author_id": 1}, json
83
+ assert_match %r{"title": "Welcome to the weblog"}, json
84
+ assert_match %r{"body": "Such a lovely day"}, json
85
+
86
+ assert_match %r{"title": "So I was thinking"}, json
87
+ assert_match %r{"body": "Like I hopefully always am"}, json
88
+ end
89
+
90
+ def test_includes_uses_association_name_and_applies_attribute_filters
91
+ json = @david.to_json(:include => { :posts => { :only => :title } })
92
+
93
+ assert_match %r{"name": "David"}, json
94
+ assert_match %r{"posts": \[}, json
95
+
96
+ assert_match %r{"title": "Welcome to the weblog"}, json
97
+ assert_no_match %r{"body": "Such a lovely day"}, json
98
+
99
+ assert_match %r{"title": "So I was thinking"}, json
100
+ assert_no_match %r{"body": "Like I hopefully always am"}, json
101
+ end
102
+
103
+ def test_includes_fetches_second_level_associations
104
+ json = @david.to_json(:include => { :posts => { :include => { :comments => { :only => :body } } } })
105
+
106
+ assert_match %r{"name": "David"}, json
107
+ assert_match %r{"posts": \[}, json
108
+
109
+ assert_match %r{"comments": \[}, json
110
+ assert_match %r{\{"body": "Thank you again for the welcome"\}}, json
111
+ assert_match %r{\{"body": "Don't think too hard"\}}, json
112
+ assert_no_match %r{"post_id": }, json
113
+ end
114
+
115
+ def test_includes_fetches_nth_level_associations
116
+ json = @david.to_json(
117
+ :include => {
118
+ :posts => {
119
+ :include => {
120
+ :taggings => {
121
+ :include => {
122
+ :tag => { :only => :name }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ })
128
+
129
+ assert_match %r{"name": "David"}, json
130
+ assert_match %r{"posts": \[}, json
131
+
132
+ assert_match %r{"taggings": \[}, json
133
+ assert_match %r{"tag": \{"name": "General"\}}, json
134
+ end
135
+
136
+ def test_should_not_call_methods_on_associations_that_dont_respond
137
+ def @david.favorite_quote; "Constraints are liberating"; end
138
+ json = @david.to_json(:include => :posts, :methods => :favorite_quote)
139
+
140
+ assert !@david.posts.first.respond_to?(:favorite_quote)
141
+ assert_match %r{"favorite_quote": "Constraints are liberating"}, json
142
+ assert_equal %r{"favorite_quote": }.match(json).size, 1
143
+ end
144
+
145
+ def test_should_allow_only_option_for_list_of_authors
146
+ authors = [@david, @mary]
147
+
148
+ assert_equal %([{"name": "David"}, {"name": "Mary"}]), authors.to_json(:only => :name)
149
+ end
150
+
151
+ def test_should_allow_except_option_for_list_of_authors
152
+ authors = [@david, @mary]
153
+
154
+ assert_equal %([{"id": 1}, {"id": 2}]), authors.to_json(:except => [:name, :author_address_id])
155
+ end
156
+
157
+ def test_should_allow_includes_for_list_of_authors
158
+ authors = [@david, @mary]
159
+ json = authors.to_json(
160
+ :only => :name,
161
+ :include => {
162
+ :posts => { :only => :id }
163
+ }
164
+ )
165
+
166
+ ['"name": "David"', '"posts": [', '{"id": 1}', '{"id": 2}', '{"id": 4}',
167
+ '{"id": 5}', '{"id": 6}', '"name": "Mary"', '"posts": [{"id": 7}]'].each do |fragment|
168
+ assert json.include?(fragment), json
169
+ end
170
+ end
171
+
172
+ def test_should_allow_options_for_hash_of_authors
173
+ authors_hash = {
174
+ 1 => @david,
175
+ 2 => @mary
176
+ }
177
+
178
+ assert_equal %({1: {"name": "David"}}), authors_hash.to_json(:only => [1, :name])
179
+ end
180
+ end
@@ -27,7 +27,7 @@ class TopicManualObserver
27
27
  end
28
28
 
29
29
  class TopicaObserver < ActiveRecord::Observer
30
- def self.observed_class() Topic end
30
+ observe :topic
31
31
 
32
32
  attr_reader :topic
33
33
 
@@ -1,5 +1,6 @@
1
1
  require 'abstract_unit'
2
2
  require 'fixtures/person'
3
+ require 'fixtures/reader'
3
4
  require 'fixtures/legacy_thing'
4
5
 
5
6
  class LockWithoutDefault < ActiveRecord::Base; end
@@ -9,9 +10,18 @@ class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
9
10
  set_locking_column :custom_lock_version
10
11
  end
11
12
 
13
+ class ReadonlyFirstNamePerson < Person
14
+ attr_readonly :first_name
15
+ end
16
+
12
17
  class OptimisticLockingTest < Test::Unit::TestCase
13
18
  fixtures :people, :legacy_things
14
19
 
20
+ # need to disable transactional fixtures, because otherwise the sqlite3
21
+ # adapter (at least) chokes when we try and change the schema in the middle
22
+ # of a test (see test_increment_counter_*).
23
+ self.use_transactional_fixtures = false
24
+
15
25
  def test_lock_existing
16
26
  p1 = Person.find(1)
17
27
  p2 = Person.find(1)
@@ -24,6 +34,20 @@ class OptimisticLockingTest < Test::Unit::TestCase
24
34
 
25
35
  assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
26
36
  end
37
+
38
+ def test_lock_repeating
39
+ p1 = Person.find(1)
40
+ p2 = Person.find(1)
41
+ assert_equal 0, p1.lock_version
42
+ assert_equal 0, p2.lock_version
43
+
44
+ p1.save!
45
+ assert_equal 1, p1.lock_version
46
+ assert_equal 0, p2.lock_version
47
+
48
+ assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
49
+ assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
50
+ end
27
51
 
28
52
  def test_lock_new
29
53
  p1 = Person.new(:first_name => 'anika')
@@ -73,6 +97,65 @@ class OptimisticLockingTest < Test::Unit::TestCase
73
97
  t1 = LockWithCustomColumnWithoutDefault.new
74
98
  assert_equal 0, t1.custom_lock_version
75
99
  end
100
+
101
+ def test_readonly_attributes
102
+ assert_equal Set.new([ 'first_name' ]), ReadonlyFirstNamePerson.readonly_attributes
103
+
104
+ p = ReadonlyFirstNamePerson.create(:first_name => "unchangeable name")
105
+ p.reload
106
+ assert_equal "unchangeable name", p.first_name
107
+
108
+ p.update_attributes(:first_name => "changed name")
109
+ p.reload
110
+ assert_equal "unchangeable name", p.first_name
111
+ end
112
+
113
+ { :lock_version => Person, :custom_lock_version => LegacyThing }.each do |name, model|
114
+ define_method("test_increment_counter_updates_#{name}") do
115
+ counter_test model, 1 do |id|
116
+ model.increment_counter :test_count, id
117
+ end
118
+ end
119
+
120
+ define_method("test_decrement_counter_updates_#{name}") do
121
+ counter_test model, -1 do |id|
122
+ model.decrement_counter :test_count, id
123
+ end
124
+ end
125
+
126
+ define_method("test_update_counters_updates_#{name}") do
127
+ counter_test model, 1 do |id|
128
+ model.update_counters id, :test_count => 1
129
+ end
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ def add_counter_column_to(model)
136
+ model.connection.add_column model.table_name, :test_count, :integer, :null => false, :default => 0
137
+ model.reset_column_information
138
+ # OpenBase does not set a value to existing rows when adding a not null default column
139
+ model.update_all(:test_count => 0) if current_adapter?(:OpenBaseAdapter)
140
+ end
141
+
142
+ def remove_counter_column_from(model)
143
+ model.connection.remove_column model.table_name, :test_count
144
+ model.reset_column_information
145
+ end
146
+
147
+ def counter_test(model, expected_count)
148
+ add_counter_column_to(model)
149
+ object = model.find(:first)
150
+ assert_equal 0, object.test_count
151
+ assert_equal 0, object.send(model.locking_column)
152
+ yield object.id
153
+ object.reload
154
+ assert_equal expected_count, object.test_count
155
+ assert_equal 1, object.send(model.locking_column)
156
+ ensure
157
+ remove_counter_column_from(model)
158
+ end
76
159
  end
77
160
 
78
161
 
@@ -81,9 +164,9 @@ end
81
164
  # blocks, so separate script called by Kernel#system is needed.
82
165
  # (See exec vs. async_exec in the PostgreSQL adapter.)
83
166
 
84
- # TODO: The SQL Server and Sybase adapters currently have no support for pessimistic locking
167
+ # TODO: The SQL Server, Sybase, and OpenBase adapters currently have no support for pessimistic locking
85
168
 
86
- unless current_adapter?(:SQLServerAdapter, :SybaseAdapter)
169
+ unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :OpenBaseAdapter)
87
170
  class PessimisticLockingTest < Test::Unit::TestCase
88
171
  self.use_transactional_fixtures = false
89
172
  fixtures :people, :readers
@@ -24,6 +24,8 @@ if ActiveRecord::Base.connection.supports_migrations?
24
24
 
25
25
  class MigrationTest < Test::Unit::TestCase
26
26
  self.use_transactional_fixtures = false
27
+
28
+ fixtures :people
27
29
 
28
30
  def setup
29
31
  ActiveRecord::Migration.verbose = true
@@ -40,7 +42,7 @@ if ActiveRecord::Base.connection.supports_migrations?
40
42
  Reminder.reset_column_information
41
43
 
42
44
  %w(last_name key bio age height wealth birthday favorite_day
43
- male administrator).each do |column|
45
+ moment_of_truth male administrator funny).each do |column|
44
46
  Person.connection.remove_column('people', column) rescue nil
45
47
  end
46
48
  Person.connection.remove_column("people", "first_name") rescue nil
@@ -59,7 +61,8 @@ if ActiveRecord::Base.connection.supports_migrations?
59
61
  assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
60
62
 
61
63
  # Orcl nds shrt indx nms. Sybs 2.
62
- unless current_adapter?(:OracleAdapter, :SybaseAdapter)
64
+ # OpenBase does not have named indexes. You must specify a single column name
65
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter)
63
66
  assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
64
67
  assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
65
68
  assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
@@ -72,11 +75,15 @@ if ActiveRecord::Base.connection.supports_migrations?
72
75
 
73
76
  # quoting
74
77
  # Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
75
- assert_nothing_raised { Person.connection.add_index("people", ["key"], :name => "key_idx", :unique => true) }
76
- assert_nothing_raised { Person.connection.remove_index("people", :name => "key_idx", :unique => true) }
77
-
78
+ # OpenBase does not have named indexes. You must specify a single column name
79
+ unless current_adapter?(:OpenBaseAdapter)
80
+ assert_nothing_raised { Person.connection.add_index("people", ["key"], :name => "key_idx", :unique => true) }
81
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "key_idx", :unique => true) }
82
+ end
83
+
78
84
  # Sybase adapter does not support indexes on :boolean columns
79
- unless current_adapter?(:SybaseAdapter)
85
+ # OpenBase does not have named indexes. You must specify a single column
86
+ unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter)
80
87
  assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
81
88
  assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
82
89
  end
@@ -108,11 +115,15 @@ if ActiveRecord::Base.connection.supports_migrations?
108
115
  end
109
116
 
110
117
  def test_create_table_with_defaults
118
+ # MySQL doesn't allow defaults on TEXT or BLOB columns.
119
+ mysql = current_adapter?(:MysqlAdapter)
120
+
111
121
  Person.connection.create_table :testings do |t|
112
122
  t.column :one, :string, :default => "hello"
113
123
  t.column :two, :boolean, :default => true
114
124
  t.column :three, :boolean, :default => false
115
125
  t.column :four, :integer, :default => 1
126
+ t.column :five, :text, :default => "hello" unless mysql
116
127
  end
117
128
 
118
129
  columns = Person.connection.columns(:testings)
@@ -120,11 +131,13 @@ if ActiveRecord::Base.connection.supports_migrations?
120
131
  two = columns.detect { |c| c.name == "two" }
121
132
  three = columns.detect { |c| c.name == "three" }
122
133
  four = columns.detect { |c| c.name == "four" }
134
+ five = columns.detect { |c| c.name == "five" } unless mysql
123
135
 
124
136
  assert_equal "hello", one.default
125
137
  assert_equal true, two.default
126
138
  assert_equal false, three.default
127
139
  assert_equal 1, four.default
140
+ assert_equal "hello", five.default unless mysql
128
141
 
129
142
  ensure
130
143
  Person.connection.drop_table :testings rescue nil
@@ -167,9 +180,8 @@ if ActiveRecord::Base.connection.supports_migrations?
167
180
  Person.connection.drop_table :testings rescue nil
168
181
  end
169
182
 
170
- # SQL Server and Sybase will not allow you to add a NOT NULL column
171
- # to a table without specifying a default value, so the
172
- # following test must be skipped
183
+ # SQL Server, Sybase, and SQLite3 will not allow you to add a NOT NULL
184
+ # column to a table without a default value.
173
185
  unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter)
174
186
  def test_add_column_not_null_without_default
175
187
  Person.connection.create_table :testings do |t|
@@ -197,7 +209,12 @@ if ActiveRecord::Base.connection.supports_migrations?
197
209
  assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
198
210
 
199
211
  assert_raises(ActiveRecord::StatementInvalid) do
200
- Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) values (2, 'hello', NULL)"
212
+ unless current_adapter?(:OpenBaseAdapter)
213
+ Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) values (2, 'hello', NULL)"
214
+ else
215
+ Person.connection.insert("INSERT INTO testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) VALUES (2, 'hello', NULL)",
216
+ "Testing Insert","id",2)
217
+ end
201
218
  end
202
219
  ensure
203
220
  Person.connection.drop_table :testings rescue nil
@@ -207,8 +224,6 @@ if ActiveRecord::Base.connection.supports_migrations?
207
224
  # functionality. This allows us to more easily catch INSERT being broken,
208
225
  # but SELECT actually working fine.
209
226
  def test_native_decimal_insert_manual_vs_automatic
210
- # SQLite3 always uses float in violation of SQL
211
- # 16 decimal places
212
227
  correct_value = '0012345678901234567890.0123456789'.to_d
213
228
 
214
229
  Person.delete_all
@@ -218,6 +233,8 @@ if ActiveRecord::Base.connection.supports_migrations?
218
233
  # Do a manual insertion
219
234
  if current_adapter?(:OracleAdapter)
220
235
  Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
236
+ elsif current_adapter?(:OpenBaseAdapter)
237
+ Person.connection.execute "insert into people (wealth) values ('12345678901234567890.0123456789')"
221
238
  else
222
239
  Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)"
223
240
  end
@@ -230,6 +247,7 @@ if ActiveRecord::Base.connection.supports_migrations?
230
247
  unless current_adapter?(:SQLite3Adapter)
231
248
  assert_equal correct_value, row.wealth
232
249
  end
250
+
233
251
  # Reset to old state
234
252
  Person.delete_all
235
253
 
@@ -244,6 +262,7 @@ if ActiveRecord::Base.connection.supports_migrations?
244
262
  unless current_adapter?(:SQLite3Adapter)
245
263
  assert_equal correct_value, row.wealth
246
264
  end
265
+
247
266
  # Reset to old state
248
267
  Person.connection.del_column "people", "wealth" rescue nil
249
268
  Person.reset_column_information
@@ -258,10 +277,19 @@ if ActiveRecord::Base.connection.supports_migrations?
258
277
  Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
259
278
  Person.connection.add_column "people", "birthday", :datetime
260
279
  Person.connection.add_column "people", "favorite_day", :date
280
+ Person.connection.add_column "people", "moment_of_truth", :datetime
261
281
  Person.connection.add_column "people", "male", :boolean
262
- assert_nothing_raised { Person.create :first_name => 'bob', :last_name => 'bobsen', :bio => "I was born ....", :age => 18, :height => 1.78, :wealth => BigDecimal.new("12345678901234567890.0123456789"), :birthday => 18.years.ago, :favorite_day => 10.days.ago, :male => true }
263
- bob = Person.find(:first)
282
+ Person.reset_column_information
264
283
 
284
+ assert_nothing_raised do
285
+ Person.create :first_name => 'bob', :last_name => 'bobsen',
286
+ :bio => "I was born ....", :age => 18, :height => 1.78,
287
+ :wealth => BigDecimal.new("12345678901234567890.0123456789"),
288
+ :birthday => 18.years.ago, :favorite_day => 10.days.ago,
289
+ :moment_of_truth => "1782-10-10 21:40:18", :male => true
290
+ end
291
+
292
+ bob = Person.find(:first)
265
293
  assert_equal 'bob', bob.first_name
266
294
  assert_equal 'bobsen', bob.last_name
267
295
  assert_equal "I was born ....", bob.bio
@@ -269,10 +297,11 @@ if ActiveRecord::Base.connection.supports_migrations?
269
297
 
270
298
  # Test for 30 significent digits (beyond the 16 of float), 10 of them
271
299
  # after the decimal place.
300
+
272
301
  unless current_adapter?(:SQLite3Adapter)
273
302
  assert_equal BigDecimal.new("0012345678901234567890.0123456789"), bob.wealth
274
303
  end
275
-
304
+
276
305
  assert_equal true, bob.male?
277
306
 
278
307
  assert_equal String, bob.first_name.class
@@ -288,10 +317,34 @@ if ActiveRecord::Base.connection.supports_migrations?
288
317
  assert_equal Date, bob.favorite_day.class
289
318
  end
290
319
 
320
+ # Test DateTime column and defaults, including timezone.
321
+ # FIXME: moment of truth may be Time on 64-bit platforms.
322
+ if bob.moment_of_truth.is_a?(DateTime)
323
+ assert_equal DateTime.now.offset, bob.moment_of_truth.offset
324
+ assert_not_equal 0, bob.moment_of_truth.offset
325
+ assert_not_equal "Z", bob.moment_of_truth.zone
326
+ assert_equal DateTime::ITALY, bob.moment_of_truth.start
327
+ end
328
+
291
329
  assert_equal TrueClass, bob.male?.class
292
330
  assert_kind_of BigDecimal, bob.wealth
293
331
  end
294
332
 
333
+ if current_adapter?(:MysqlAdapter)
334
+ def test_unabstracted_database_dependent_types
335
+ Person.delete_all
336
+
337
+ ActiveRecord::Migration.add_column :people, :intelligence_quotient, :tinyint
338
+ Person.reset_column_information
339
+ Person.create :intelligence_quotient => 300
340
+ jonnyg = Person.find(:first)
341
+ assert_equal 127, jonnyg.intelligence_quotient
342
+ jonnyg.destroy
343
+ ensure
344
+ ActiveRecord::Migration.remove_column :people, :intelligence_quotient rescue nil
345
+ end
346
+ end
347
+
295
348
  def test_add_remove_single_field_using_string_arguments
296
349
  assert !Person.column_methods_hash.include?(:last_name)
297
350
 
@@ -325,6 +378,7 @@ if ActiveRecord::Base.connection.supports_migrations?
325
378
 
326
379
  begin
327
380
  Person.connection.add_column "people", "girlfriend", :string
381
+ Person.reset_column_information
328
382
  Person.create :girlfriend => 'bobette'
329
383
 
330
384
  Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
@@ -342,9 +396,11 @@ if ActiveRecord::Base.connection.supports_migrations?
342
396
 
343
397
  def test_rename_column_using_symbol_arguments
344
398
  begin
399
+ names_before = Person.find(:all).map(&:first_name)
345
400
  Person.connection.rename_column :people, :first_name, :nick_name
346
401
  Person.reset_column_information
347
402
  assert Person.column_names.include?("nick_name")
403
+ assert_equal names_before, Person.find(:all).map(&:nick_name)
348
404
  ensure
349
405
  Person.connection.remove_column("people","nick_name")
350
406
  Person.connection.add_column("people","first_name", :string)
@@ -353,15 +409,38 @@ if ActiveRecord::Base.connection.supports_migrations?
353
409
 
354
410
  def test_rename_column
355
411
  begin
412
+ names_before = Person.find(:all).map(&:first_name)
356
413
  Person.connection.rename_column "people", "first_name", "nick_name"
357
414
  Person.reset_column_information
358
415
  assert Person.column_names.include?("nick_name")
416
+ assert_equal names_before, Person.find(:all).map(&:nick_name)
359
417
  ensure
360
418
  Person.connection.remove_column("people","nick_name")
361
419
  Person.connection.add_column("people","first_name", :string)
362
420
  end
363
421
  end
364
422
 
423
+ def test_rename_column_with_sql_reserved_word
424
+ begin
425
+ assert_nothing_raised { Person.connection.rename_column "people", "first_name", "group" }
426
+ Person.reset_column_information
427
+ assert Person.column_names.include?("group")
428
+ ensure
429
+ Person.connection.remove_column("people", "group") rescue nil
430
+ Person.connection.add_column("people", "first_name", :string) rescue nil
431
+ end
432
+ end
433
+
434
+ def test_change_type_of_not_null_column
435
+ assert_nothing_raised do
436
+ Topic.connection.change_column "topics", "written_on", :datetime, :null => false
437
+ Topic.reset_column_information
438
+
439
+ Topic.connection.change_column "topics", "written_on", :datetime, :null => false
440
+ Topic.reset_column_information
441
+ end
442
+ end
443
+
365
444
  def test_rename_table
366
445
  begin
367
446
  ActiveRecord::Base.connection.create_table :octopuses do |t|
@@ -382,6 +461,19 @@ if ActiveRecord::Base.connection.supports_migrations?
382
461
  ActiveRecord::Base.connection.drop_table :octopi rescue nil
383
462
  end
384
463
  end
464
+
465
+ def test_change_column_nullability
466
+ Person.delete_all
467
+ Person.connection.add_column "people", "funny", :boolean
468
+ Person.reset_column_information
469
+ assert Person.columns_hash["funny"].null, "Column 'funny' must initially allow nulls"
470
+ Person.connection.change_column "people", "funny", :boolean, :null => false, :default => true
471
+ Person.reset_column_information
472
+ assert !Person.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point"
473
+ Person.connection.change_column "people", "funny", :boolean, :null => true
474
+ Person.reset_column_information
475
+ assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
476
+ end
385
477
 
386
478
  def test_rename_table_with_an_index
387
479
  begin
@@ -420,7 +512,7 @@ if ActiveRecord::Base.connection.supports_migrations?
420
512
  old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
421
513
  assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
422
514
  assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
423
- new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
515
+ new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
424
516
  assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
425
517
  assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
426
518
  assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
@@ -435,6 +527,8 @@ if ActiveRecord::Base.connection.supports_migrations?
435
527
  Person.reset_column_information
436
528
  assert !Person.new.contributor?
437
529
  assert_nil Person.new.contributor
530
+ ensure
531
+ Person.connection.remove_column("people", "contributor") rescue nil
438
532
  end
439
533
 
440
534
  def test_change_column_with_new_default
@@ -445,6 +539,8 @@ if ActiveRecord::Base.connection.supports_migrations?
445
539
  assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
446
540
  Person.reset_column_information
447
541
  assert !Person.new.administrator?
542
+ ensure
543
+ Person.connection.remove_column("people", "administrator") rescue nil
448
544
  end
449
545
 
450
546
  def test_change_column_default
@@ -452,7 +548,19 @@ if ActiveRecord::Base.connection.supports_migrations?
452
548
  Person.reset_column_information
453
549
  assert_equal "Tester", Person.new.first_name
454
550
  end
455
-
551
+
552
+ def test_change_column_quotes_column_names
553
+ Person.connection.create_table :testings do |t|
554
+ t.column :select, :string
555
+ end
556
+
557
+ assert_nothing_raised { Person.connection.change_column :testings, :select, :string, :limit => 10 }
558
+
559
+ assert_nothing_raised { Person.connection.execute "insert into testings (#{Person.connection.quote_column_name('select')}) values ('7 chars')" }
560
+ ensure
561
+ Person.connection.drop_table :testings rescue nil
562
+ end
563
+
456
564
  def test_change_column_default_to_null
457
565
  Person.connection.change_column_default "people", "first_name", nil
458
566
  Person.reset_column_information
@@ -463,8 +571,8 @@ if ActiveRecord::Base.connection.supports_migrations?
463
571
  assert !Reminder.table_exists?
464
572
 
465
573
  WeNeedReminders.up
466
-
467
- assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
574
+
575
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
468
576
  assert_equal "hello world", Reminder.find(:first).content
469
577
 
470
578
  WeNeedReminders.down
@@ -506,7 +614,7 @@ if ActiveRecord::Base.connection.supports_migrations?
506
614
  assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
507
615
 
508
616
  # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with
509
- # precision/scale explictly left out. By the SQL standard, numbers
617
+ # precision/scale explicitly left out. By the SQL standard, numbers
510
618
  # assigned to this field should be truncated but that's seldom respected.
511
619
  if current_adapter?(:PostgreSQLAdapter, :SQLite2Adapter)
512
620
  # - PostgreSQL changes the SQL spec on columns declared simply as
@@ -685,29 +793,27 @@ if ActiveRecord::Base.connection.supports_migrations?
685
793
  Reminder.reset_sequence_name
686
794
  end
687
795
 
688
- # FrontBase does not support default values on BLOB/CLOB columns
689
- unless current_adapter?(:FrontBaseAdapter)
690
- def test_create_table_with_binary_column
691
- Person.connection.drop_table :binary_testings rescue nil
796
+ def test_create_table_with_binary_column
797
+ Person.connection.drop_table :binary_testings rescue nil
692
798
 
693
- assert_nothing_raised {
694
- Person.connection.create_table :binary_testings do |t|
695
- t.column "data", :binary, :default => "", :null => false
696
- end
697
- }
698
-
699
- columns = Person.connection.columns(:binary_testings)
700
- data_column = columns.detect { |c| c.name == "data" }
701
-
702
- if current_adapter?(:OracleAdapter)
703
- assert_equal "empty_blob()", data_column.default
704
- else
705
- assert_equal "", data_column.default
799
+ assert_nothing_raised {
800
+ Person.connection.create_table :binary_testings do |t|
801
+ t.column "data", :binary, :null => false
706
802
  end
803
+ }
804
+
805
+ columns = Person.connection.columns(:binary_testings)
806
+ data_column = columns.detect { |c| c.name == "data" }
707
807
 
708
- Person.connection.drop_table :binary_testings rescue nil
808
+ if current_adapter?(:MysqlAdapter)
809
+ assert_equal '', data_column.default
810
+ else
811
+ assert_nil data_column.default
709
812
  end
813
+
814
+ Person.connection.drop_table :binary_testings rescue nil
710
815
  end
816
+
711
817
  def test_migrator_with_duplicates
712
818
  assert_raises(ActiveRecord::DuplicateMigrationVersionError) do
713
819
  ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_duplicate/', nil)
@@ -720,11 +826,12 @@ if ActiveRecord::Base.connection.supports_migrations?
720
826
  assert_equal 4, ActiveRecord::Migrator.current_version
721
827
 
722
828
  ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_missing_versions/', 2)
829
+ Person.reset_column_information
723
830
  assert !Reminder.table_exists?
724
831
  assert Person.column_methods_hash.include?(:last_name)
725
832
  assert_equal 2, ActiveRecord::Migrator.current_version
726
833
  end
727
-
834
+
728
835
  def test_create_table_with_custom_sequence_name
729
836
  return unless current_adapter? :OracleAdapter
730
837
 
@@ -761,7 +868,66 @@ if ActiveRecord::Base.connection.supports_migrations?
761
868
  Person.connection.execute("select suitably_short_seq.nextval from dual")
762
869
  end
763
870
  end
764
-
765
871
  end
872
+
873
+ uses_mocha 'Sexy migration tests' do
874
+ class SexyMigrationsTest < Test::Unit::TestCase
875
+ def test_references_column_type_adds_id
876
+ with_new_table do |t|
877
+ t.expects(:column).with('customer_id', :integer, {})
878
+ t.references :customer
879
+ end
880
+ end
881
+
882
+ def test_references_column_type_with_polymorphic_adds_type
883
+ with_new_table do |t|
884
+ t.expects(:column).with('taggable_type', :string, {})
885
+ t.expects(:column).with('taggable_id', :integer, {})
886
+ t.references :taggable, :polymorphic => true
887
+ end
888
+ end
889
+
890
+ def test_belongs_to_works_like_references
891
+ with_new_table do |t|
892
+ t.expects(:column).with('customer_id', :integer, {})
893
+ t.belongs_to :customer
894
+ end
895
+ end
896
+
897
+ def test_timestamps_creates_updated_at_and_created_at
898
+ with_new_table do |t|
899
+ t.expects(:column).with(:created_at, :datetime)
900
+ t.expects(:column).with(:updated_at, :datetime)
901
+ t.timestamps
902
+ end
903
+ end
904
+
905
+ def test_integer_creates_integer_column
906
+ with_new_table do |t|
907
+ t.expects(:column).with(:foo, 'integer', {})
908
+ t.expects(:column).with(:bar, 'integer', {})
909
+ t.integer :foo, :bar
910
+ end
911
+ end
912
+
913
+ def test_string_creates_string_column
914
+ with_new_table do |t|
915
+ t.expects(:column).with(:foo, 'string', {})
916
+ t.expects(:column).with(:bar, 'string', {})
917
+ t.string :foo, :bar
918
+ end
919
+ end
920
+
921
+ protected
922
+ def with_new_table
923
+ Person.connection.create_table :delete_me do |t|
924
+ yield t
925
+ end
926
+ ensure
927
+ Person.connection.drop_table :delete_me rescue nil
928
+ end
929
+
930
+ end # SexyMigrationsTest
931
+ end # uses_mocha
766
932
  end
767
933