activerecord 1.14.4 → 1.15.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 (159) hide show
  1. data/CHANGELOG +400 -1
  2. data/README +2 -2
  3. data/RUNNING_UNIT_TESTS +21 -3
  4. data/Rakefile +55 -10
  5. data/lib/active_record.rb +10 -4
  6. data/lib/active_record/acts/list.rb +15 -4
  7. data/lib/active_record/acts/nested_set.rb +11 -12
  8. data/lib/active_record/acts/tree.rb +13 -14
  9. data/lib/active_record/aggregations.rb +46 -22
  10. data/lib/active_record/associations.rb +213 -162
  11. data/lib/active_record/associations/association_collection.rb +45 -15
  12. data/lib/active_record/associations/association_proxy.rb +32 -13
  13. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +18 -18
  14. data/lib/active_record/associations/has_many_association.rb +37 -17
  15. data/lib/active_record/associations/has_many_through_association.rb +120 -30
  16. data/lib/active_record/associations/has_one_association.rb +1 -1
  17. data/lib/active_record/attribute_methods.rb +75 -0
  18. data/lib/active_record/base.rb +282 -203
  19. data/lib/active_record/calculations.rb +95 -54
  20. data/lib/active_record/callbacks.rb +13 -24
  21. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +12 -1
  22. data/lib/active_record/connection_adapters/abstract/connection_specification.rb.rej +21 -0
  23. data/lib/active_record/connection_adapters/abstract/database_statements.rb +30 -4
  24. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -9
  25. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +121 -37
  26. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -23
  27. data/lib/active_record/connection_adapters/abstract_adapter.rb +8 -0
  28. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -11
  29. data/lib/active_record/connection_adapters/firebird_adapter.rb +364 -50
  30. data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
  31. data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -33
  32. data/lib/active_record/connection_adapters/openbase_adapter.rb +4 -3
  33. data/lib/active_record/connection_adapters/oracle_adapter.rb +151 -127
  34. data/lib/active_record/connection_adapters/postgresql_adapter.rb +125 -48
  35. data/lib/active_record/connection_adapters/sqlite_adapter.rb +38 -10
  36. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +183 -155
  37. data/lib/active_record/connection_adapters/sybase_adapter.rb +190 -212
  38. data/lib/active_record/deprecated_associations.rb +24 -10
  39. data/lib/active_record/deprecated_finders.rb +4 -1
  40. data/lib/active_record/fixtures.rb +37 -23
  41. data/lib/active_record/locking/optimistic.rb +106 -0
  42. data/lib/active_record/locking/pessimistic.rb +77 -0
  43. data/lib/active_record/migration.rb +8 -5
  44. data/lib/active_record/observer.rb +73 -34
  45. data/lib/active_record/reflection.rb +21 -7
  46. data/lib/active_record/schema_dumper.rb +33 -5
  47. data/lib/active_record/timestamp.rb +23 -34
  48. data/lib/active_record/transactions.rb +37 -30
  49. data/lib/active_record/validations.rb +46 -30
  50. data/lib/active_record/vendor/mysql.rb +20 -5
  51. data/lib/active_record/version.rb +2 -2
  52. data/lib/active_record/wrappings.rb +1 -2
  53. data/lib/active_record/xml_serialization.rb +308 -0
  54. data/test/aaa_create_tables_test.rb +5 -1
  55. data/test/abstract_unit.rb +18 -8
  56. data/test/{active_schema_mysql.rb → active_schema_test_mysql.rb} +2 -2
  57. data/test/adapter_test.rb +9 -7
  58. data/test/adapter_test_sqlserver.rb +81 -0
  59. data/test/aggregations_test.rb +29 -0
  60. data/test/{association_callbacks_test.rb → associations/callbacks_test.rb} +10 -8
  61. data/test/{associations_cascaded_eager_loading_test.rb → associations/cascaded_eager_loading_test.rb} +35 -3
  62. data/test/{associations_go_eager_test.rb → associations/eager_test.rb} +36 -2
  63. data/test/{associations_extensions_test.rb → associations/extension_test.rb} +5 -0
  64. data/test/{associations_join_model_test.rb → associations/join_model_test.rb} +118 -8
  65. data/test/associations_test.rb +339 -45
  66. data/test/attribute_methods_test.rb +49 -0
  67. data/test/base_test.rb +321 -67
  68. data/test/calculations_test.rb +48 -10
  69. data/test/callbacks_test.rb +13 -0
  70. data/test/connection_test_firebird.rb +8 -0
  71. data/test/connections/native_db2/connection.rb +18 -17
  72. data/test/connections/native_firebird/connection.rb +19 -17
  73. data/test/connections/native_frontbase/connection.rb +27 -0
  74. data/test/connections/native_mysql/connection.rb +18 -15
  75. data/test/connections/native_openbase/connection.rb +14 -15
  76. data/test/connections/native_oracle/connection.rb +16 -12
  77. data/test/connections/native_postgresql/connection.rb +16 -17
  78. data/test/connections/native_sqlite/connection.rb +3 -6
  79. data/test/connections/native_sqlite3/connection.rb +3 -6
  80. data/test/connections/native_sqlserver/connection.rb +16 -17
  81. data/test/connections/native_sqlserver_odbc/connection.rb +18 -19
  82. data/test/connections/native_sybase/connection.rb +16 -17
  83. data/test/datatype_test_postgresql.rb +52 -0
  84. data/test/defaults_test.rb +52 -10
  85. data/test/deprecated_associations_test.rb +151 -107
  86. data/test/deprecated_finder_test.rb +83 -66
  87. data/test/empty_date_time_test.rb +25 -0
  88. data/test/finder_test.rb +118 -11
  89. data/test/fixtures/accounts.yml +6 -1
  90. data/test/fixtures/author.rb +27 -4
  91. data/test/fixtures/categorizations.yml +8 -2
  92. data/test/fixtures/category.rb +1 -2
  93. data/test/fixtures/comments.yml +0 -6
  94. data/test/fixtures/companies.yml +6 -1
  95. data/test/fixtures/company.rb +23 -1
  96. data/test/fixtures/company_in_module.rb +8 -10
  97. data/test/fixtures/customer.rb +2 -2
  98. data/test/fixtures/customers.yml +9 -0
  99. data/test/fixtures/db_definitions/db2.drop.sql +1 -0
  100. data/test/fixtures/db_definitions/db2.sql +9 -0
  101. data/test/fixtures/db_definitions/firebird.drop.sql +3 -0
  102. data/test/fixtures/db_definitions/firebird.sql +13 -1
  103. data/test/fixtures/db_definitions/frontbase.drop.sql +31 -0
  104. data/test/fixtures/db_definitions/frontbase.sql +262 -0
  105. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  106. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  107. data/test/fixtures/db_definitions/mysql.drop.sql +1 -0
  108. data/test/fixtures/db_definitions/mysql.sql +23 -14
  109. data/test/fixtures/db_definitions/openbase.sql +13 -1
  110. data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
  111. data/test/fixtures/db_definitions/oracle.sql +29 -2
  112. data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
  113. data/test/fixtures/db_definitions/postgresql.sql +13 -3
  114. data/test/fixtures/db_definitions/schema.rb +29 -1
  115. data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
  116. data/test/fixtures/db_definitions/sqlite.sql +12 -3
  117. data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
  118. data/test/fixtures/db_definitions/sqlserver.sql +35 -0
  119. data/test/fixtures/db_definitions/sybase.drop.sql +2 -0
  120. data/test/fixtures/db_definitions/sybase.sql +13 -4
  121. data/test/fixtures/developer.rb +12 -0
  122. data/test/fixtures/edge.rb +5 -0
  123. data/test/fixtures/edges.yml +6 -0
  124. data/test/fixtures/funny_jokes.yml +3 -7
  125. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  126. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  127. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  128. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  129. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  130. data/test/fixtures/mixin.rb +15 -0
  131. data/test/fixtures/mixins.yml +38 -0
  132. data/test/fixtures/post.rb +3 -2
  133. data/test/fixtures/project.rb +3 -1
  134. data/test/fixtures/topic.rb +6 -1
  135. data/test/fixtures/topics.yml +4 -4
  136. data/test/fixtures/vertex.rb +9 -0
  137. data/test/fixtures/vertices.yml +4 -0
  138. data/test/fixtures_test.rb +45 -0
  139. data/test/inheritance_test.rb +67 -6
  140. data/test/lifecycle_test.rb +40 -19
  141. data/test/locking_test.rb +170 -26
  142. data/test/method_scoping_test.rb +2 -2
  143. data/test/migration_test.rb +387 -110
  144. data/test/migration_test_firebird.rb +124 -0
  145. data/test/mixin_nested_set_test.rb +14 -2
  146. data/test/mixin_test.rb +56 -18
  147. data/test/modules_test.rb +8 -2
  148. data/test/multiple_db_test.rb +2 -2
  149. data/test/pk_test.rb +1 -0
  150. data/test/reflection_test.rb +8 -2
  151. data/test/schema_authorization_test_postgresql.rb +75 -0
  152. data/test/schema_dumper_test.rb +40 -4
  153. data/test/table_name_test_sqlserver.rb +23 -0
  154. data/test/threaded_connections_test.rb +19 -16
  155. data/test/transactions_test.rb +86 -72
  156. data/test/validations_test.rb +126 -56
  157. data/test/xml_serialization_test.rb +125 -0
  158. metadata +45 -11
  159. data/lib/active_record/locking.rb +0 -79
@@ -0,0 +1,124 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/course'
3
+
4
+ class FirebirdMigrationTest < Test::Unit::TestCase
5
+ self.use_transactional_fixtures = false
6
+
7
+ def setup
8
+ # using Course connection for tests -- need a db that doesn't already have a BOOLEAN domain
9
+ @connection = Course.connection
10
+ @fireruby_connection = @connection.instance_variable_get(:@connection)
11
+ end
12
+
13
+ def teardown
14
+ @connection.drop_table :foo rescue nil
15
+ @connection.execute("DROP DOMAIN D_BOOLEAN") rescue nil
16
+ end
17
+
18
+ def test_create_table_with_custom_sequence_name
19
+ assert_nothing_raised do
20
+ @connection.create_table(:foo, :sequence => 'foo_custom_seq') do |f|
21
+ f.column :bar, :string
22
+ end
23
+ end
24
+ assert !sequence_exists?('foo_seq')
25
+ assert sequence_exists?('foo_custom_seq')
26
+
27
+ assert_nothing_raised { @connection.drop_table(:foo, :sequence => 'foo_custom_seq') }
28
+ assert !sequence_exists?('foo_custom_seq')
29
+ ensure
30
+ FireRuby::Generator.new('foo_custom_seq', @fireruby_connection).drop rescue nil
31
+ end
32
+
33
+ def test_create_table_without_sequence
34
+ assert_nothing_raised do
35
+ @connection.create_table(:foo, :sequence => false) do |f|
36
+ f.column :bar, :string
37
+ end
38
+ end
39
+ assert !sequence_exists?('foo_seq')
40
+ assert_nothing_raised { @connection.drop_table :foo }
41
+
42
+ assert_nothing_raised do
43
+ @connection.create_table(:foo, :id => false) do |f|
44
+ f.column :bar, :string
45
+ end
46
+ end
47
+ assert !sequence_exists?('foo_seq')
48
+ assert_nothing_raised { @connection.drop_table :foo }
49
+ end
50
+
51
+ def test_create_table_with_boolean_column
52
+ assert !boolean_domain_exists?
53
+ assert_nothing_raised do
54
+ @connection.create_table :foo do |f|
55
+ f.column :bar, :string
56
+ f.column :baz, :boolean
57
+ end
58
+ end
59
+ assert boolean_domain_exists?
60
+ end
61
+
62
+ def test_add_boolean_column
63
+ assert !boolean_domain_exists?
64
+ @connection.create_table :foo do |f|
65
+ f.column :bar, :string
66
+ end
67
+
68
+ assert_nothing_raised { @connection.add_column :foo, :baz, :boolean }
69
+ assert boolean_domain_exists?
70
+ assert_equal :boolean, @connection.columns(:foo).find { |c| c.name == "baz" }.type
71
+ end
72
+
73
+ def test_change_column_to_boolean
74
+ assert !boolean_domain_exists?
75
+ # Manually create table with a SMALLINT column, which can be changed to a BOOLEAN
76
+ @connection.execute "CREATE TABLE foo (bar SMALLINT)"
77
+ assert_equal :integer, @connection.columns(:foo).find { |c| c.name == "bar" }.type
78
+
79
+ assert_nothing_raised { @connection.change_column :foo, :bar, :boolean }
80
+ assert boolean_domain_exists?
81
+ assert_equal :boolean, @connection.columns(:foo).find { |c| c.name == "bar" }.type
82
+ end
83
+
84
+ def test_rename_table_with_data_and_index
85
+ @connection.create_table :foo do |f|
86
+ f.column :baz, :string, :limit => 50
87
+ end
88
+ 100.times { |i| @connection.execute "INSERT INTO foo VALUES (GEN_ID(foo_seq, 1), 'record #{i+1}')" }
89
+ @connection.add_index :foo, :baz
90
+
91
+ assert_nothing_raised { @connection.rename_table :foo, :bar }
92
+ assert !@connection.tables.include?("foo")
93
+ assert @connection.tables.include?("bar")
94
+ assert_equal "index_bar_on_baz", @connection.indexes("bar").first.name
95
+ assert_equal 100, FireRuby::Generator.new("bar_seq", @fireruby_connection).last
96
+ assert_equal 100, @connection.select_one("SELECT COUNT(*) FROM bar")["count"]
97
+ ensure
98
+ @connection.drop_table :bar rescue nil
99
+ end
100
+
101
+ def test_renaming_table_with_fk_constraint_raises_error
102
+ @connection.create_table :parent do |p|
103
+ p.column :name, :string
104
+ end
105
+ @connection.create_table :child do |c|
106
+ c.column :parent_id, :integer
107
+ end
108
+ @connection.execute "ALTER TABLE child ADD CONSTRAINT fk_child_parent FOREIGN KEY(parent_id) REFERENCES parent(id)"
109
+ assert_raise(ActiveRecord::ActiveRecordError) { @connection.rename_table :child, :descendant }
110
+ ensure
111
+ @connection.drop_table :child rescue nil
112
+ @connection.drop_table :descendant rescue nil
113
+ @connection.drop_table :parent rescue nil
114
+ end
115
+
116
+ private
117
+ def boolean_domain_exists?
118
+ !@connection.select_one("SELECT 1 FROM rdb$fields WHERE rdb$field_name = 'D_BOOLEAN'").nil?
119
+ end
120
+
121
+ def sequence_exists?(sequence_name)
122
+ FireRuby::Generator.exists?(sequence_name, @fireruby_connection)
123
+ end
124
+ end
@@ -178,7 +178,19 @@ class MixinNestedSetTest < Test::Unit::TestCase
178
178
  mixins(:set_1).add_child mixins(:set_4)
179
179
 
180
180
  assert_equal( 3, mixins(:set_1).all_children.length )
181
-
182
-
181
+ end
182
+
183
+ def test_inheritance
184
+ parent = mixins(:sti_set_3100)
185
+ child = mixins(:sti_set_3101)
186
+ grandchild = mixins(:sti_set_3102)
187
+ assert_equal 5, parent.full_set.size
188
+ assert_equal 2, child.full_set.size
189
+ assert_equal 4, parent.all_children.size
190
+ assert_equal 1, child.all_children.size
191
+ assert_equal 2, parent.direct_children.size
192
+ assert_equal 1, child.direct_children.size
193
+ child.destroy
194
+ assert_equal 3, parent.full_set.size
183
195
  end
184
196
  end
@@ -4,6 +4,23 @@ require 'active_record/acts/list'
4
4
  require 'active_record/acts/nested_set'
5
5
  require 'fixtures/mixin'
6
6
 
7
+ # Let us control what Time.now returns for the TouchTest suite
8
+ class Time
9
+ @@forced_now_time = nil
10
+ cattr_accessor :forced_now_time
11
+
12
+ class << self
13
+ def now_with_forcing
14
+ if @@forced_now_time
15
+ @@forced_now_time
16
+ else
17
+ now_without_forcing
18
+ end
19
+ end
20
+ alias_method_chain :now, :forcing
21
+ end
22
+ end
23
+
7
24
  class ListTest < Test::Unit::TestCase
8
25
  fixtures :mixins
9
26
 
@@ -200,10 +217,12 @@ class TreeTest < Test::Unit::TestCase
200
217
  fixtures :mixins
201
218
 
202
219
  def test_has_child
203
- assert_equal true, mixins(:tree_1).has_children?
204
- assert_equal true, mixins(:tree_2).has_children?
205
- assert_equal false, mixins(:tree_3).has_children?
206
- assert_equal false, mixins(:tree_4).has_children?
220
+ assert_deprecated 'has_children?' do
221
+ assert_equal true, mixins(:tree_1).has_children?
222
+ assert_equal true, mixins(:tree_2).has_children?
223
+ assert_equal false, mixins(:tree_3).has_children?
224
+ assert_equal false, mixins(:tree_4).has_children?
225
+ end
207
226
  end
208
227
 
209
228
  def test_children
@@ -214,10 +233,12 @@ class TreeTest < Test::Unit::TestCase
214
233
  end
215
234
 
216
235
  def test_has_parent
217
- assert_equal false, mixins(:tree_1).has_parent?
218
- assert_equal true, mixins(:tree_2).has_parent?
219
- assert_equal true, mixins(:tree_3).has_parent?
220
- assert_equal true, mixins(:tree_4).has_parent?
236
+ assert_deprecated 'has_parent?' do
237
+ assert_equal false, mixins(:tree_1).has_parent?
238
+ assert_equal true, mixins(:tree_2).has_parent?
239
+ assert_equal true, mixins(:tree_3).has_parent?
240
+ assert_equal true, mixins(:tree_4).has_parent?
241
+ end
221
242
  end
222
243
 
223
244
  def test_parent
@@ -304,6 +325,23 @@ end
304
325
 
305
326
  class TouchTest < Test::Unit::TestCase
306
327
  fixtures :mixins
328
+
329
+ def setup
330
+ Time.forced_now_time = Time.now
331
+ end
332
+
333
+ def teardown
334
+ Time.forced_now_time = nil
335
+ end
336
+
337
+ def test_time_mocking
338
+ five_minutes_ago = 5.minutes.ago
339
+ Time.forced_now_time = five_minutes_ago
340
+ assert_equal five_minutes_ago, Time.now
341
+
342
+ Time.forced_now_time = nil
343
+ assert_not_equal five_minutes_ago, Time.now
344
+ end
307
345
 
308
346
  def test_update
309
347
  stamped = Mixin.new
@@ -311,14 +349,14 @@ class TouchTest < Test::Unit::TestCase
311
349
  assert_nil stamped.updated_at
312
350
  assert_nil stamped.created_at
313
351
  stamped.save
314
- assert_not_nil stamped.updated_at
315
- assert_not_nil stamped.created_at
352
+ assert_equal Time.now, stamped.updated_at
353
+ assert_equal Time.now, stamped.created_at
316
354
  end
317
355
 
318
356
  def test_create
319
- @obj = Mixin.create
320
- assert_not_nil @obj.updated_at
321
- assert_not_nil @obj.created_at
357
+ obj = Mixin.create
358
+ assert_equal Time.now, obj.updated_at
359
+ assert_equal Time.now, obj.created_at
322
360
  end
323
361
 
324
362
  def test_many_updates
@@ -327,16 +365,16 @@ class TouchTest < Test::Unit::TestCase
327
365
  assert_nil stamped.updated_at
328
366
  assert_nil stamped.created_at
329
367
  stamped.save
330
- assert_not_nil stamped.created_at
331
- assert_not_nil stamped.updated_at
368
+ assert_equal Time.now, stamped.created_at
369
+ assert_equal Time.now, stamped.updated_at
332
370
 
333
371
  old_updated_at = stamped.updated_at
334
372
 
335
- sleep 1
373
+ Time.forced_now_time = 5.minutes.from_now
336
374
  stamped.save
337
- assert_not_equal stamped.created_at, stamped.updated_at
338
- assert_not_equal old_updated_at, stamped.updated_at
339
375
 
376
+ assert_equal Time.now, stamped.updated_at
377
+ assert_equal old_updated_at, stamped.created_at
340
378
  end
341
379
 
342
380
  def test_create_turned_off
@@ -5,10 +5,9 @@ class ModulesTest < Test::Unit::TestCase
5
5
  fixtures :accounts, :companies, :projects, :developers
6
6
 
7
7
  def test_module_spanning_associations
8
- assert MyApplication::Business::Firm.find(:first).has_clients?, "Firm should have clients"
9
8
  firm = MyApplication::Business::Firm.find(:first)
9
+ assert !firm.clients.empty?, "Firm should have clients"
10
10
  assert_nil firm.class.table_name.match('::'), "Firm shouldn't have the module appear in its table name"
11
- assert_equal 2, firm.clients_count, "Firm should have two clients"
12
11
  end
13
12
 
14
13
  def test_module_spanning_has_and_belongs_to_many_associations
@@ -25,4 +24,11 @@ class ModulesTest < Test::Unit::TestCase
25
24
  assert_kind_of MyApplication::Billing::Nested::Firm, account.nested_qualified_billing_firm
26
25
  assert_kind_of MyApplication::Billing::Nested::Firm, account.nested_unqualified_billing_firm
27
26
  end
27
+
28
+ def test_find_account_and_include_company
29
+ account = MyApplication::Billing::Account.find(1, :include => :firm)
30
+ assert_kind_of MyApplication::Business::Firm, account.instance_variable_get('@firm')
31
+ assert_kind_of MyApplication::Business::Firm, account.firm
32
+ end
33
+
28
34
  end
@@ -39,11 +39,11 @@ class MultipleDbTest < Test::Unit::TestCase
39
39
 
40
40
  def test_associations
41
41
  c1 = Course.find(1)
42
- assert_equal 2, c1.entrants_count
42
+ assert_equal 2, c1.entrants.count
43
43
  e1 = Entrant.find(1)
44
44
  assert_equal e1.course.id, c1.id
45
45
  c2 = Course.find(2)
46
- assert_equal 1, c2.entrants_count
46
+ assert_equal 1, c2.entrants.count
47
47
  e3 = Entrant.find(3)
48
48
  assert_equal e3.course.id, c2.id
49
49
  end
@@ -1,5 +1,6 @@
1
1
  require "#{File.dirname(__FILE__)}/abstract_unit"
2
2
  require 'fixtures/topic'
3
+ require 'fixtures/reply'
3
4
  require 'fixtures/subscriber'
4
5
  require 'fixtures/movie'
5
6
  require 'fixtures/keyboard'
@@ -45,6 +45,12 @@ class ReflectionTest < Test::Unit::TestCase
45
45
  assert_equal :string, @first.column_for_attribute("title").type
46
46
  assert_equal 255, @first.column_for_attribute("title").limit
47
47
  end
48
+
49
+ def test_column_null_not_null
50
+ subscriber = Subscriber.find(:first)
51
+ assert subscriber.column_for_attribute("name").null
52
+ assert !subscriber.column_for_attribute("nick").null
53
+ end
48
54
 
49
55
  def test_human_name_for_column
50
56
  assert_equal "Author name", @first.column_for_attribute("author_name").human_name
@@ -137,8 +143,8 @@ class ReflectionTest < Test::Unit::TestCase
137
143
  end
138
144
 
139
145
  def test_reflection_of_all_associations
140
- assert_equal 13, Firm.reflect_on_all_associations.size
141
- assert_equal 11, Firm.reflect_on_all_associations(:has_many).size
146
+ assert_equal 17, Firm.reflect_on_all_associations.size
147
+ assert_equal 15, Firm.reflect_on_all_associations(:has_many).size
142
148
  assert_equal 2, Firm.reflect_on_all_associations(:has_one).size
143
149
  assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
144
150
  end
@@ -0,0 +1,75 @@
1
+ require 'abstract_unit'
2
+
3
+ class SchemaThing < ActiveRecord::Base
4
+ end
5
+
6
+ class SchemaAuthorizationTest < Test::Unit::TestCase
7
+ self.use_transactional_fixtures = false
8
+
9
+ TABLE_NAME = 'schema_things'
10
+ COLUMNS = [
11
+ 'id serial primary key',
12
+ 'name character varying(50)'
13
+ ]
14
+ USERS = ['rails_pg_schema_user1', 'rails_pg_schema_user2']
15
+
16
+ def setup
17
+ @connection = ActiveRecord::Base.connection
18
+ @connection.execute "SET search_path TO '$user',public"
19
+ set_session_auth
20
+ USERS.each do |u|
21
+ @connection.execute "CREATE ROLE #{u}"
22
+ @connection.execute "CREATE SCHEMA AUTHORIZATION #{u}"
23
+ set_session_auth u
24
+ @connection.execute "CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
25
+ @connection.execute "INSERT INTO #{TABLE_NAME} (name) VALUES ('#{u}')"
26
+ set_session_auth
27
+ end
28
+ end
29
+
30
+ def teardown
31
+ set_session_auth
32
+ @connection.execute "RESET search_path"
33
+ USERS.each do |u|
34
+ @connection.execute "DROP SCHEMA #{u} CASCADE"
35
+ @connection.execute "DROP ROLE #{u}"
36
+ end
37
+ end
38
+
39
+ def test_schema_invisible
40
+ assert_raise(ActiveRecord::StatementInvalid) do
41
+ set_session_auth
42
+ @connection.execute "SELECT * FROM #{TABLE_NAME}"
43
+ end
44
+ end
45
+
46
+ def test_schema_uniqueness
47
+ assert_nothing_raised do
48
+ set_session_auth
49
+ USERS.each do |u|
50
+ set_session_auth u
51
+ assert_equal u, @connection.select_value("SELECT name FROM #{TABLE_NAME} WHERE id = 1")
52
+ set_session_auth
53
+ end
54
+ end
55
+ end
56
+
57
+ def test_sequence_schema_caching
58
+ assert_nothing_raised do
59
+ USERS.each do |u|
60
+ set_session_auth u
61
+ st = SchemaThing.new :name => 'TEST1'
62
+ st.save!
63
+ st = SchemaThing.new :id => 5, :name => 'TEST2'
64
+ st.save!
65
+ set_session_auth
66
+ end
67
+ end
68
+ end
69
+
70
+ private
71
+ def set_session_auth auth = nil
72
+ @connection.execute "SET SESSION AUTHORIZATION #{auth || 'default'}"
73
+ end
74
+
75
+ end
@@ -5,20 +5,48 @@ require 'stringio'
5
5
  if ActiveRecord::Base.connection.respond_to?(:tables)
6
6
 
7
7
  class SchemaDumperTest < Test::Unit::TestCase
8
- def test_schema_dump
8
+ def standard_dump
9
9
  stream = StringIO.new
10
+ ActiveRecord::SchemaDumper.ignore_tables = []
10
11
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
11
- output = stream.string
12
-
12
+ stream.string
13
+ end
14
+
15
+ def test_schema_dump
16
+ output = standard_dump
13
17
  assert_match %r{create_table "accounts"}, output
14
18
  assert_match %r{create_table "authors"}, output
15
19
  assert_no_match %r{create_table "schema_info"}, output
16
20
  end
17
21
 
22
+ def assert_line_up(lines, pattern, required = false)
23
+ return assert(true) if lines.empty?
24
+ matches = lines.map { |line| line.match(pattern) }
25
+ assert matches.all? if required
26
+ matches.compact!
27
+ return assert(true) if matches.empty?
28
+ assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
29
+ end
30
+
31
+ def test_arguments_line_up
32
+ output = standard_dump
33
+ output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }.each do |column_set|
34
+ assert_line_up(column_set, /:(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)/, true)
35
+ assert_line_up(column_set, /:default => /)
36
+ assert_line_up(column_set, /:limit => /)
37
+ assert_line_up(column_set, /:null => /)
38
+ end
39
+ end
40
+
41
+ def test_no_dump_errors
42
+ output = standard_dump
43
+ assert_no_match %r{\# Could not dump table}, output
44
+ end
45
+
18
46
  def test_schema_dump_includes_not_null_columns
19
47
  stream = StringIO.new
20
48
 
21
- ActiveRecord::SchemaDumper.ignore_tables = [/^[^s]/]
49
+ ActiveRecord::SchemaDumper.ignore_tables = [/^[^r]/]
22
50
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
23
51
  output = stream.string
24
52
  assert_match %r{:null => false}, output
@@ -55,6 +83,14 @@ if ActiveRecord::Base.connection.respond_to?(:tables)
55
83
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
56
84
  end
57
85
  end
86
+
87
+ def test_schema_dump_includes_decimal_options
88
+ stream = StringIO.new
89
+ ActiveRecord::SchemaDumper.ignore_tables = [/^[^n]/]
90
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
91
+ output = stream.string
92
+ assert_match %r{:precision => 3,[[:space:]]+:scale => 2,[[:space:]]+:default => 2.78}, output
93
+ end
58
94
  end
59
95
 
60
96
  end