activerecord 1.13.2 → 1.14.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.
- data/CHANGELOG +452 -10
- data/RUNNING_UNIT_TESTS +1 -1
- data/lib/active_record.rb +5 -2
- data/lib/active_record/acts/list.rb +1 -1
- data/lib/active_record/acts/tree.rb +29 -25
- data/lib/active_record/aggregations.rb +3 -2
- data/lib/active_record/associations.rb +783 -337
- data/lib/active_record/associations/association_collection.rb +7 -12
- data/lib/active_record/associations/association_proxy.rb +62 -24
- data/lib/active_record/associations/belongs_to_association.rb +27 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +38 -38
- data/lib/active_record/associations/has_many_association.rb +61 -56
- data/lib/active_record/associations/has_many_through_association.rb +144 -0
- data/lib/active_record/associations/has_one_association.rb +22 -16
- data/lib/active_record/base.rb +482 -182
- data/lib/active_record/calculations.rb +225 -0
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +162 -47
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +34 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +107 -61
- data/lib/active_record/connection_adapters/mysql_adapter.rb +29 -6
- data/lib/active_record/connection_adapters/openbase_adapter.rb +349 -0
- data/lib/active_record/connection_adapters/{oci_adapter.rb → oracle_adapter.rb} +125 -59
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +24 -21
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +47 -8
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +36 -16
- data/lib/active_record/connection_adapters/sybase_adapter.rb +684 -0
- data/lib/active_record/fixtures.rb +42 -17
- data/lib/active_record/locking.rb +36 -15
- data/lib/active_record/migration.rb +111 -8
- data/lib/active_record/observer.rb +25 -1
- data/lib/active_record/reflection.rb +103 -41
- data/lib/active_record/schema.rb +2 -2
- data/lib/active_record/schema_dumper.rb +55 -18
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/validations.rb +65 -40
- data/lib/active_record/vendor/db2.rb +10 -5
- data/lib/active_record/vendor/simple.rb +693 -702
- data/lib/active_record/version.rb +2 -2
- data/rakefile +4 -4
- data/test/aaa_create_tables_test.rb +25 -6
- data/test/abstract_unit.rb +39 -1
- data/test/adapter_test.rb +31 -4
- data/test/associations_cascaded_eager_loading_test.rb +106 -0
- data/test/associations_go_eager_test.rb +85 -16
- data/test/associations_join_model_test.rb +338 -0
- data/test/associations_test.rb +129 -50
- data/test/base_test.rb +204 -49
- data/test/binary_test.rb +1 -1
- data/test/calculations_test.rb +169 -0
- data/test/callbacks_test.rb +5 -23
- data/test/class_inheritable_attributes_test.rb +1 -1
- data/test/column_alias_test.rb +1 -1
- data/test/connections/native_mysql/connection.rb +1 -0
- data/test/connections/native_openbase/connection.rb +22 -0
- data/test/connections/{native_oci → native_oracle}/connection.rb +7 -9
- data/test/connections/native_sqlite/connection.rb +1 -1
- data/test/connections/native_sqlite3/connection.rb +1 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -0
- data/test/connections/native_sybase/connection.rb +24 -0
- data/test/defaults_test.rb +18 -0
- data/test/deprecated_associations_test.rb +2 -2
- data/test/deprecated_finder_test.rb +0 -6
- data/test/finder_test.rb +26 -23
- data/test/fixtures/accounts.yml +10 -0
- data/test/fixtures/author.rb +31 -6
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_posts.yml +4 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +11 -0
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +17 -5
- data/test/fixtures/company_in_module.rb +19 -5
- data/test/fixtures/db_definitions/db2.drop.sql +3 -0
- data/test/fixtures/db_definitions/db2.sql +121 -100
- data/test/fixtures/db_definitions/db22.sql +2 -2
- data/test/fixtures/db_definitions/firebird.drop.sql +4 -0
- data/test/fixtures/db_definitions/firebird.sql +26 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +3 -0
- data/test/fixtures/db_definitions/mysql.sql +21 -1
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +282 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/{oci.drop.sql → oracle.drop.sql} +6 -0
- data/test/fixtures/db_definitions/{oci.sql → oracle.sql} +25 -4
- data/test/fixtures/db_definitions/{oci2.drop.sql → oracle2.drop.sql} +0 -0
- data/test/fixtures/db_definitions/{oci2.sql → oracle2.sql} +0 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +22 -1
- data/test/fixtures/db_definitions/schema.rb +32 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlite.sql +18 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +23 -3
- data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
- data/test/fixtures/db_definitions/sybase.sql +204 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developers.yml +6 -1
- data/test/fixtures/developers_projects.yml +4 -0
- data/test/fixtures/funny_jokes.yml +14 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/mixin.rb +1 -1
- data/test/fixtures/person.rb +4 -1
- data/test/fixtures/post.rb +26 -1
- data/test/fixtures/project.rb +1 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +2 -1
- data/test/fixtures/tag.rb +5 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/tasks.yml +2 -2
- data/test/fixtures/topic.rb +2 -2
- data/test/fixtures/topics.yml +1 -0
- data/test/fixtures_test.rb +47 -13
- data/test/inheritance_test.rb +2 -2
- data/test/locking_test.rb +15 -1
- data/test/method_scoping_test.rb +248 -13
- data/test/migration_test.rb +68 -11
- data/test/mixin_nested_set_test.rb +1 -1
- data/test/modules_test.rb +6 -1
- data/test/readonly_test.rb +1 -1
- data/test/reflection_test.rb +63 -9
- data/test/schema_dumper_test.rb +41 -0
- data/test/{synonym_test_oci.rb → synonym_test_oracle.rb} +1 -1
- data/test/threaded_connections_test.rb +10 -0
- data/test/unconnected_test.rb +12 -5
- data/test/validations_test.rb +197 -10
- metadata +295 -260
- data/test/fixtures/db_definitions/create_oracle_db.bat +0 -0
- data/test/fixtures/db_definitions/create_oracle_db.sh +0 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
data/test/migration_test.rb
CHANGED
@@ -6,10 +6,22 @@ require File.dirname(__FILE__) + '/fixtures/migrations/2_we_need_reminders'
|
|
6
6
|
if ActiveRecord::Base.connection.supports_migrations?
|
7
7
|
class Reminder < ActiveRecord::Base; end
|
8
8
|
|
9
|
+
class ActiveRecord::Migration
|
10
|
+
class <<self
|
11
|
+
attr_accessor :message_count
|
12
|
+
def puts(text="")
|
13
|
+
self.message_count ||= 0
|
14
|
+
self.message_count += 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
9
19
|
class MigrationTest < Test::Unit::TestCase
|
10
20
|
self.use_transactional_fixtures = false
|
11
21
|
|
12
22
|
def setup
|
23
|
+
ActiveRecord::Migration.verbose = true
|
24
|
+
PeopleHaveLastNames.message_count = 0
|
13
25
|
end
|
14
26
|
|
15
27
|
def teardown
|
@@ -31,7 +43,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
31
43
|
Person.connection.remove_column("people", "administrator") rescue nil
|
32
44
|
Person.reset_column_information
|
33
45
|
end
|
34
|
-
|
46
|
+
|
35
47
|
def test_add_index
|
36
48
|
Person.connection.add_column "people", "last_name", :string
|
37
49
|
Person.connection.add_column "people", "administrator", :boolean
|
@@ -42,8 +54,11 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
42
54
|
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
|
43
55
|
assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
|
44
56
|
|
45
|
-
|
46
|
-
|
57
|
+
# Sybase adapter does not support indexes on :boolean columns
|
58
|
+
unless current_adapter?(:SybaseAdapter)
|
59
|
+
assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
|
60
|
+
assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
|
61
|
+
end
|
47
62
|
end
|
48
63
|
|
49
64
|
def test_create_table_adds_id
|
@@ -84,7 +99,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
84
99
|
four = columns.detect { |c| c.name == "four" }
|
85
100
|
|
86
101
|
assert_equal "hello", one.default
|
87
|
-
if current_adapter?(:
|
102
|
+
if current_adapter?(:OracleAdapter)
|
88
103
|
# Oracle doesn't support native booleans
|
89
104
|
assert_equal true, two.default == 1
|
90
105
|
assert_equal false, three.default != 0
|
@@ -98,10 +113,10 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
98
113
|
Person.connection.drop_table :testings rescue nil
|
99
114
|
end
|
100
115
|
|
101
|
-
# SQL Server will not allow you to add a NOT NULL column
|
116
|
+
# SQL Server and Sybase will not allow you to add a NOT NULL column
|
102
117
|
# to a table without specifying a default value, so the
|
103
118
|
# following test must be skipped
|
104
|
-
unless current_adapter?(:SQLServerAdapter)
|
119
|
+
unless current_adapter?(:SQLServerAdapter) || current_adapter?(:SybaseAdapter)
|
105
120
|
def test_add_column_not_null_without_default
|
106
121
|
Person.connection.create_table :testings do |t|
|
107
122
|
t.column :foo, :string
|
@@ -153,8 +168,8 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
153
168
|
assert_equal Fixnum, bob.age.class
|
154
169
|
assert_equal Time, bob.birthday.class
|
155
170
|
|
156
|
-
if current_adapter?(:SQLServerAdapter)
|
157
|
-
# SQL Server and Oracle don't differentiate between date/time
|
171
|
+
if current_adapter?(:SQLServerAdapter) || current_adapter?(:OracleAdapter) || current_adapter?(:SybaseAdapter)
|
172
|
+
# SQL Server, Sybase, and Oracle don't differentiate between date/time
|
158
173
|
assert_equal Time, bob.favorite_day.class
|
159
174
|
else
|
160
175
|
assert_equal Date, bob.favorite_day.class
|
@@ -241,7 +256,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
241
256
|
ActiveRecord::Base.connection.rename_table :octopuses, :octopi
|
242
257
|
|
243
258
|
assert_nothing_raised do
|
244
|
-
if current_adapter?(:
|
259
|
+
if current_adapter?(:OracleAdapter)
|
245
260
|
# Oracle requires the explicit sequence for the pk
|
246
261
|
ActiveRecord::Base.connection.execute "INSERT INTO octopi (id, url) VALUES (octopi_seq.nextval, 'http://www.foreverflying.com/octopus-black7.jpg')"
|
247
262
|
else
|
@@ -258,8 +273,15 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
258
273
|
end
|
259
274
|
|
260
275
|
def test_change_column
|
261
|
-
Person.connection.add_column
|
262
|
-
|
276
|
+
Person.connection.add_column 'people', 'age', :integer
|
277
|
+
old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
|
278
|
+
assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
|
279
|
+
|
280
|
+
assert_nothing_raised { Person.connection.change_column "people", "age", :string }
|
281
|
+
|
282
|
+
new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
|
283
|
+
assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
|
284
|
+
assert new_columns.find { |c| c.name == 'age' and c.type == :string }
|
263
285
|
end
|
264
286
|
|
265
287
|
def test_change_column_with_new_default
|
@@ -338,6 +360,24 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
338
360
|
assert !Reminder.table_exists?
|
339
361
|
end
|
340
362
|
|
363
|
+
def test_migrator_verbosity
|
364
|
+
ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
|
365
|
+
assert PeopleHaveLastNames.message_count > 0
|
366
|
+
PeopleHaveLastNames.message_count = 0
|
367
|
+
|
368
|
+
ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
|
369
|
+
assert PeopleHaveLastNames.message_count > 0
|
370
|
+
PeopleHaveLastNames.message_count = 0
|
371
|
+
end
|
372
|
+
|
373
|
+
def test_migrator_verbosity_off
|
374
|
+
PeopleHaveLastNames.verbose = false
|
375
|
+
ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
|
376
|
+
assert PeopleHaveLastNames.message_count.zero?
|
377
|
+
ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
|
378
|
+
assert PeopleHaveLastNames.message_count.zero?
|
379
|
+
end
|
380
|
+
|
341
381
|
def test_migrator_going_down_due_to_version_target
|
342
382
|
ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
|
343
383
|
ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
|
@@ -415,6 +455,23 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
415
455
|
Reminder.reset_sequence_name
|
416
456
|
end
|
417
457
|
|
458
|
+
def test_create_table_with_binary_column
|
459
|
+
Person.connection.drop_table :binary_testings rescue nil
|
460
|
+
|
461
|
+
assert_nothing_raised {
|
462
|
+
Person.connection.create_table :binary_testings do |t|
|
463
|
+
t.column "data", :binary, :default => "", :null => false
|
464
|
+
end
|
465
|
+
}
|
466
|
+
|
467
|
+
columns = Person.connection.columns(:binary_testings)
|
468
|
+
data_column = columns.detect { |c| c.name == "data" }
|
469
|
+
|
470
|
+
assert_equal "", data_column.default
|
471
|
+
|
472
|
+
Person.connection.drop_table :binary_testings rescue nil
|
473
|
+
end
|
474
|
+
|
418
475
|
def test_migrator_with_duplicates
|
419
476
|
assert_raises(ActiveRecord::DuplicateMigrationVersionError) do
|
420
477
|
ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_duplicate/', nil)
|
@@ -9,7 +9,7 @@ class MixinNestedSetTest < Test::Unit::TestCase
|
|
9
9
|
def test_mixing_in_methods
|
10
10
|
ns = NestedSet.new
|
11
11
|
assert( ns.respond_to?( :all_children ) )
|
12
|
-
assert_equal( ns.scope_condition, "
|
12
|
+
assert_equal( ns.scope_condition, "root_id IS NULL" )
|
13
13
|
|
14
14
|
check_method_mixins ns
|
15
15
|
end
|
data/test/modules_test.rb
CHANGED
@@ -18,6 +18,11 @@ class ModulesTest < Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_associations_spanning_cross_modules
|
21
|
-
|
21
|
+
account = MyApplication::Billing::Account.find(:first, :order => 'id')
|
22
|
+
assert_kind_of MyApplication::Business::Firm, account.firm
|
23
|
+
assert_kind_of MyApplication::Billing::Firm, account.qualified_billing_firm
|
24
|
+
assert_kind_of MyApplication::Billing::Firm, account.unqualified_billing_firm
|
25
|
+
assert_kind_of MyApplication::Billing::Nested::Firm, account.nested_qualified_billing_firm
|
26
|
+
assert_kind_of MyApplication::Billing::Nested::Firm, account.nested_unqualified_billing_firm
|
22
27
|
end
|
23
28
|
end
|
data/test/readonly_test.rb
CHANGED
@@ -79,7 +79,7 @@ class ReadOnlyTest < Test::Unit::TestCase
|
|
79
79
|
|
80
80
|
# Oracle barfs on this because the join includes unqualified and
|
81
81
|
# conflicting column names
|
82
|
-
unless current_adapter?(:
|
82
|
+
unless current_adapter?(:OracleAdapter)
|
83
83
|
Post.with_scope(:find => { :joins => ', developers' }) do
|
84
84
|
assert Post.find(1).readonly?
|
85
85
|
assert Post.find(1, :readonly => true).readonly?
|
data/test/reflection_test.rb
CHANGED
@@ -3,14 +3,21 @@ require 'fixtures/topic'
|
|
3
3
|
require 'fixtures/customer'
|
4
4
|
require 'fixtures/company'
|
5
5
|
require 'fixtures/company_in_module'
|
6
|
+
require 'fixtures/subscriber'
|
6
7
|
|
7
8
|
class ReflectionTest < Test::Unit::TestCase
|
8
|
-
fixtures :topics, :customers, :companies
|
9
|
+
fixtures :topics, :customers, :companies, :subscribers
|
9
10
|
|
10
11
|
def setup
|
11
12
|
@first = Topic.find(1)
|
12
13
|
end
|
13
14
|
|
15
|
+
def test_column_null_not_null
|
16
|
+
subscriber = Subscriber.find(:first)
|
17
|
+
assert subscriber.column_for_attribute("name").null
|
18
|
+
assert !subscriber.column_for_attribute("nick").null
|
19
|
+
end
|
20
|
+
|
14
21
|
def test_read_attribute_names
|
15
22
|
assert_equal(
|
16
23
|
%w( id title author_name author_email_address bonus_time written_on last_read content approved replies_count parent_id type ).sort,
|
@@ -60,10 +67,9 @@ class ReflectionTest < Test::Unit::TestCase
|
|
60
67
|
:composed_of, :gps_location, { }, Customer
|
61
68
|
)
|
62
69
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
)
|
70
|
+
assert Customer.reflect_on_all_aggregations.include?(reflection_for_gps_location)
|
71
|
+
assert Customer.reflect_on_all_aggregations.include?(reflection_for_balance)
|
72
|
+
assert Customer.reflect_on_all_aggregations.include?(reflection_for_address)
|
67
73
|
|
68
74
|
assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address)
|
69
75
|
|
@@ -71,7 +77,7 @@ class ReflectionTest < Test::Unit::TestCase
|
|
71
77
|
end
|
72
78
|
|
73
79
|
def test_has_many_reflection
|
74
|
-
reflection_for_clients = ActiveRecord::Reflection::AssociationReflection.new(:has_many, :clients, { :order => "id", :dependent =>
|
80
|
+
reflection_for_clients = ActiveRecord::Reflection::AssociationReflection.new(:has_many, :clients, { :order => "id", :dependent => :destroy }, Firm)
|
75
81
|
|
76
82
|
assert_equal reflection_for_clients, Firm.reflect_on_association(:clients)
|
77
83
|
|
@@ -83,7 +89,7 @@ class ReflectionTest < Test::Unit::TestCase
|
|
83
89
|
end
|
84
90
|
|
85
91
|
def test_has_one_reflection
|
86
|
-
reflection_for_account = ActiveRecord::Reflection::AssociationReflection.new(:has_one, :account, { :foreign_key => "firm_id", :dependent =>
|
92
|
+
reflection_for_account = ActiveRecord::Reflection::AssociationReflection.new(:has_one, :account, { :foreign_key => "firm_id", :dependent => :destroy }, Firm)
|
87
93
|
assert_equal reflection_for_account, Firm.reflect_on_association(:account)
|
88
94
|
|
89
95
|
assert_equal Account, Firm.reflect_on_association(:account).klass
|
@@ -91,7 +97,55 @@ class ReflectionTest < Test::Unit::TestCase
|
|
91
97
|
end
|
92
98
|
|
93
99
|
def test_association_reflection_in_modules
|
94
|
-
|
95
|
-
|
100
|
+
assert_reflection MyApplication::Business::Firm,
|
101
|
+
:clients_of_firm,
|
102
|
+
:klass => MyApplication::Business::Client,
|
103
|
+
:class_name => 'Client',
|
104
|
+
:table_name => 'companies'
|
105
|
+
|
106
|
+
assert_reflection MyApplication::Billing::Account,
|
107
|
+
:firm,
|
108
|
+
:klass => MyApplication::Business::Firm,
|
109
|
+
:class_name => 'MyApplication::Business::Firm',
|
110
|
+
:table_name => 'companies'
|
111
|
+
|
112
|
+
assert_reflection MyApplication::Billing::Account,
|
113
|
+
:qualified_billing_firm,
|
114
|
+
:klass => MyApplication::Billing::Firm,
|
115
|
+
:class_name => 'MyApplication::Billing::Firm',
|
116
|
+
:table_name => 'companies'
|
117
|
+
|
118
|
+
assert_reflection MyApplication::Billing::Account,
|
119
|
+
:unqualified_billing_firm,
|
120
|
+
:klass => MyApplication::Billing::Firm,
|
121
|
+
:class_name => 'Firm',
|
122
|
+
:table_name => 'companies'
|
123
|
+
|
124
|
+
assert_reflection MyApplication::Billing::Account,
|
125
|
+
:nested_qualified_billing_firm,
|
126
|
+
:klass => MyApplication::Billing::Nested::Firm,
|
127
|
+
:class_name => 'MyApplication::Billing::Nested::Firm',
|
128
|
+
:table_name => 'companies'
|
129
|
+
|
130
|
+
assert_reflection MyApplication::Billing::Account,
|
131
|
+
:nested_unqualified_billing_firm,
|
132
|
+
:klass => MyApplication::Billing::Nested::Firm,
|
133
|
+
:class_name => 'Nested::Firm',
|
134
|
+
:table_name => 'companies'
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_reflection_of_all_associations
|
138
|
+
assert_equal 13, Firm.reflect_on_all_associations.size
|
139
|
+
assert_equal 11, Firm.reflect_on_all_associations(:has_many).size
|
140
|
+
assert_equal 2, Firm.reflect_on_all_associations(:has_one).size
|
141
|
+
assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
|
96
142
|
end
|
143
|
+
|
144
|
+
private
|
145
|
+
def assert_reflection(klass, association, options)
|
146
|
+
assert reflection = klass.reflect_on_association(association)
|
147
|
+
options.each do |method, value|
|
148
|
+
assert_equal(value, reflection.send(method))
|
149
|
+
end
|
150
|
+
end
|
97
151
|
end
|
data/test/schema_dumper_test.rb
CHANGED
@@ -14,6 +14,47 @@ if ActiveRecord::Base.connection.respond_to?(:tables)
|
|
14
14
|
assert_match %r{create_table "authors"}, output
|
15
15
|
assert_no_match %r{create_table "schema_info"}, output
|
16
16
|
end
|
17
|
+
|
18
|
+
def test_schema_dump_includes_not_null_columns
|
19
|
+
stream = StringIO.new
|
20
|
+
|
21
|
+
ActiveRecord::SchemaDumper.ignore_tables = [/^[^s]/]
|
22
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
23
|
+
output = stream.string
|
24
|
+
assert_match %r{:null => false}, output
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_schema_dump_with_string_ignored_table
|
28
|
+
stream = StringIO.new
|
29
|
+
|
30
|
+
ActiveRecord::SchemaDumper.ignore_tables = ['accounts']
|
31
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
32
|
+
output = stream.string
|
33
|
+
assert_no_match %r{create_table "accounts"}, output
|
34
|
+
assert_match %r{create_table "authors"}, output
|
35
|
+
assert_no_match %r{create_table "schema_info"}, output
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def test_schema_dump_with_regexp_ignored_table
|
40
|
+
stream = StringIO.new
|
41
|
+
|
42
|
+
ActiveRecord::SchemaDumper.ignore_tables = [/^account/]
|
43
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
44
|
+
output = stream.string
|
45
|
+
assert_no_match %r{create_table "accounts"}, output
|
46
|
+
assert_match %r{create_table "authors"}, output
|
47
|
+
assert_no_match %r{create_table "schema_info"}, output
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def test_schema_dump_illegal_ignored_table_value
|
52
|
+
stream = StringIO.new
|
53
|
+
ActiveRecord::SchemaDumper.ignore_tables = [5]
|
54
|
+
assert_raise(StandardError) do
|
55
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
56
|
+
end
|
57
|
+
end
|
17
58
|
end
|
18
59
|
|
19
60
|
end
|
@@ -9,6 +9,16 @@ class ThreadedConnectionsTest < Test::Unit::TestCase
|
|
9
9
|
def setup
|
10
10
|
@connection = ActiveRecord::Base.remove_connection
|
11
11
|
@connections = []
|
12
|
+
@allow_concurrency = ActiveRecord::Base.allow_concurrency
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
# clear the connection cache
|
17
|
+
ActiveRecord::Base.send(:clear_all_cached_connections!)
|
18
|
+
# set allow_concurrency to saved value
|
19
|
+
ActiveRecord::Base.allow_concurrency = @allow_concurrency
|
20
|
+
# reestablish old connection
|
21
|
+
ActiveRecord::Base.establish_connection(@connection)
|
12
22
|
end
|
13
23
|
|
14
24
|
def gather_connections(use_threaded_connections)
|
data/test/unconnected_test.rb
CHANGED
@@ -7,19 +7,26 @@ class TestUnconnectedAdaptor < Test::Unit::TestCase
|
|
7
7
|
self.use_transactional_fixtures = false
|
8
8
|
|
9
9
|
def setup
|
10
|
-
@
|
10
|
+
@underlying = ActiveRecord::Base.connection
|
11
|
+
@specification = ActiveRecord::Base.remove_connection
|
11
12
|
end
|
12
13
|
|
13
14
|
def teardown
|
14
|
-
|
15
|
+
@underlying = nil
|
16
|
+
ActiveRecord::Base.establish_connection(@specification)
|
15
17
|
end
|
16
18
|
|
17
|
-
def
|
19
|
+
def test_connection_no_longer_established
|
18
20
|
assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
19
|
-
TestRecord.find(1)
|
21
|
+
TestRecord.find(1)
|
20
22
|
end
|
23
|
+
|
21
24
|
assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
22
|
-
TestRecord.new.save
|
25
|
+
TestRecord.new.save
|
23
26
|
end
|
24
27
|
end
|
28
|
+
|
29
|
+
def test_underlying_adapter_no_longer_active
|
30
|
+
assert !@underlying.active?, "Removed adapter should no longer be active"
|
31
|
+
end
|
25
32
|
end
|
data/test/validations_test.rb
CHANGED
@@ -156,11 +156,11 @@ class ValidationsTest < Test::Unit::TestCase
|
|
156
156
|
def test_errors_on_boundary_breaking
|
157
157
|
developer = Developer.new("name" => "xs")
|
158
158
|
assert !developer.save
|
159
|
-
assert_equal "is too short (
|
159
|
+
assert_equal "is too short (minimum is 3 characters)", developer.errors.on("name")
|
160
160
|
|
161
161
|
developer.name = "All too very long for this boundary, it really is"
|
162
162
|
assert !developer.save
|
163
|
-
assert_equal "is too long (
|
163
|
+
assert_equal "is too long (maximum is 20 characters)", developer.errors.on("name")
|
164
164
|
|
165
165
|
developer.name = "Just right"
|
166
166
|
assert developer.save
|
@@ -280,6 +280,30 @@ class ValidationsTest < Test::Unit::TestCase
|
|
280
280
|
assert r3.valid?, "Saving r3"
|
281
281
|
end
|
282
282
|
|
283
|
+
def test_validate_uniqueness_with_scope_array
|
284
|
+
Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
|
285
|
+
|
286
|
+
t = Topic.create("title" => "The earth is actually flat!")
|
287
|
+
|
288
|
+
r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
|
289
|
+
assert r1.valid?, "Saving r1"
|
290
|
+
|
291
|
+
r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
|
292
|
+
assert !r2.valid?, "Saving r2. Double reply by same author."
|
293
|
+
|
294
|
+
r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
|
295
|
+
assert r2.save, "Saving r2 the second time."
|
296
|
+
|
297
|
+
r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
|
298
|
+
assert !r3.valid?, "Saving r3"
|
299
|
+
|
300
|
+
r3.author_name = "jj"
|
301
|
+
assert r3.save, "Saving r3 the second time."
|
302
|
+
|
303
|
+
r3.author_name = "jeremy"
|
304
|
+
assert !r3.save, "Saving r3 the third time."
|
305
|
+
end
|
306
|
+
|
283
307
|
def test_validate_format
|
284
308
|
Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data")
|
285
309
|
|
@@ -296,6 +320,34 @@ class ValidationsTest < Test::Unit::TestCase
|
|
296
320
|
|
297
321
|
assert_raise(ArgumentError) { Topic.validates_format_of(:title, :content) }
|
298
322
|
end
|
323
|
+
|
324
|
+
# testing ticket #3142
|
325
|
+
def test_validate_format_numeric
|
326
|
+
Topic.validates_format_of(:title, :content, :with => /^[1-9][0-9]*$/, :message => "is bad data")
|
327
|
+
|
328
|
+
t = Topic.create("title" => "72x", "content" => "6789")
|
329
|
+
assert !t.valid?, "Shouldn't be valid"
|
330
|
+
assert !t.save, "Shouldn't save because it's invalid"
|
331
|
+
assert_equal "is bad data", t.errors.on(:title)
|
332
|
+
assert_nil t.errors.on(:content)
|
333
|
+
|
334
|
+
t.title = "-11"
|
335
|
+
assert !t.valid?, "Shouldn't be valid"
|
336
|
+
|
337
|
+
t.title = "03"
|
338
|
+
assert !t.valid?, "Shouldn't be valid"
|
339
|
+
|
340
|
+
t.title = "z44"
|
341
|
+
assert !t.valid?, "Shouldn't be valid"
|
342
|
+
|
343
|
+
t.title = "5v7"
|
344
|
+
assert !t.valid?, "Shouldn't be valid"
|
345
|
+
|
346
|
+
t.title = "1"
|
347
|
+
|
348
|
+
assert t.save
|
349
|
+
assert_nil t.errors.on(:title)
|
350
|
+
end
|
299
351
|
|
300
352
|
def test_validates_inclusion_of
|
301
353
|
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) )
|
@@ -350,17 +402,17 @@ class ValidationsTest < Test::Unit::TestCase
|
|
350
402
|
t.title = "not"
|
351
403
|
assert !t.valid?
|
352
404
|
assert t.errors.on(:title)
|
353
|
-
assert_equal "is too short (
|
405
|
+
assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
|
354
406
|
|
355
407
|
t.title = ""
|
356
408
|
assert !t.valid?
|
357
409
|
assert t.errors.on(:title)
|
358
|
-
assert_equal "is too short (
|
410
|
+
assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
|
359
411
|
|
360
412
|
t.title = nil
|
361
413
|
assert !t.valid?
|
362
414
|
assert t.errors.on(:title)
|
363
|
-
assert_equal "is too short (
|
415
|
+
assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
|
364
416
|
end
|
365
417
|
|
366
418
|
def test_optionally_validates_length_of_using_minimum
|
@@ -382,7 +434,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
382
434
|
t.title = "notvalid"
|
383
435
|
assert !t.valid?
|
384
436
|
assert t.errors.on(:title)
|
385
|
-
assert_equal "is too long (
|
437
|
+
assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
|
386
438
|
|
387
439
|
t.title = ""
|
388
440
|
assert t.valid?
|
@@ -406,14 +458,14 @@ class ValidationsTest < Test::Unit::TestCase
|
|
406
458
|
|
407
459
|
t = Topic.new("title" => "a!", "content" => "I'm ooooooooh so very long")
|
408
460
|
assert !t.valid?
|
409
|
-
assert_equal "is too short (
|
410
|
-
assert_equal "is too long (
|
461
|
+
assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
|
462
|
+
assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
|
411
463
|
|
412
464
|
t.title = nil
|
413
465
|
t.content = nil
|
414
466
|
assert !t.valid?
|
415
|
-
assert_equal "is too short (
|
416
|
-
assert_equal "is too short (
|
467
|
+
assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
|
468
|
+
assert_equal "is too short (minimum is 3 characters)", t.errors.on(:content)
|
417
469
|
|
418
470
|
t.title = "abe"
|
419
471
|
t.content = "mad"
|
@@ -590,6 +642,141 @@ class ValidationsTest < Test::Unit::TestCase
|
|
590
642
|
assert_equal "hoo 5", t.errors["title"]
|
591
643
|
end
|
592
644
|
|
645
|
+
def kcode_scope(kcode)
|
646
|
+
orig_kcode = $KCODE
|
647
|
+
$KCODE = kcode
|
648
|
+
begin
|
649
|
+
yield
|
650
|
+
ensure
|
651
|
+
$KCODE = orig_kcode
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
def test_validates_length_of_using_minimum_utf8
|
656
|
+
kcode_scope('UTF8') do
|
657
|
+
Topic.validates_length_of :title, :minimum => 5
|
658
|
+
|
659
|
+
t = Topic.create("title" => "一二三四五", "content" => "whatever")
|
660
|
+
assert t.valid?
|
661
|
+
|
662
|
+
t.title = "一二三四"
|
663
|
+
assert !t.valid?
|
664
|
+
assert t.errors.on(:title)
|
665
|
+
assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
def test_validates_length_of_using_maximum_utf8
|
670
|
+
kcode_scope('UTF8') do
|
671
|
+
Topic.validates_length_of :title, :maximum => 5
|
672
|
+
|
673
|
+
t = Topic.create("title" => "一二三四五", "content" => "whatever")
|
674
|
+
assert t.valid?
|
675
|
+
|
676
|
+
t.title = "一二34五六"
|
677
|
+
assert !t.valid?
|
678
|
+
assert t.errors.on(:title)
|
679
|
+
assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
|
680
|
+
end
|
681
|
+
end
|
682
|
+
|
683
|
+
def test_validates_length_of_using_within_utf8
|
684
|
+
kcode_scope('UTF8') do
|
685
|
+
Topic.validates_length_of(:title, :content, :within => 3..5)
|
686
|
+
|
687
|
+
t = Topic.new("title" => "一二", "content" => "12三四五六七")
|
688
|
+
assert !t.valid?
|
689
|
+
assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
|
690
|
+
assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
|
691
|
+
t.title = "一二三"
|
692
|
+
t.content = "12三"
|
693
|
+
assert t.valid?
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
def test_optionally_validates_length_of_using_within_utf8
|
698
|
+
kcode_scope('UTF8') do
|
699
|
+
Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true
|
700
|
+
|
701
|
+
t = Topic.create('title' => '一二三', 'content' => '一二三四五')
|
702
|
+
assert t.valid?
|
703
|
+
|
704
|
+
t.title = nil
|
705
|
+
assert t.valid?
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
def test_optionally_validates_length_of_using_within_on_create_utf8
|
710
|
+
kcode_scope('UTF8') do
|
711
|
+
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "長すぎます: %d"
|
712
|
+
|
713
|
+
t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
|
714
|
+
assert !t.save
|
715
|
+
assert t.errors.on(:title)
|
716
|
+
assert_equal "長すぎます: 10", t.errors[:title]
|
717
|
+
|
718
|
+
t.title = "一二三四五六七八九"
|
719
|
+
assert t.save
|
720
|
+
|
721
|
+
t.title = "一二3"
|
722
|
+
assert t.save
|
723
|
+
|
724
|
+
t.content = "一二三四五六七八九十"
|
725
|
+
assert t.save
|
726
|
+
|
727
|
+
t.content = t.title = "一二三四五六"
|
728
|
+
assert t.save
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
def test_optionally_validates_length_of_using_within_on_update_utf8
|
733
|
+
kcode_scope('UTF8') do
|
734
|
+
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "短すぎます: %d"
|
735
|
+
|
736
|
+
t = Topic.create("title" => "一二三4", "content" => "whatever")
|
737
|
+
assert !t.save
|
738
|
+
assert t.errors.on(:title)
|
739
|
+
|
740
|
+
t.title = "1二三4"
|
741
|
+
assert !t.save
|
742
|
+
assert t.errors.on(:title)
|
743
|
+
assert_equal "短すぎます: 5", t.errors[:title]
|
744
|
+
|
745
|
+
t.title = "valid"
|
746
|
+
t.content = "一二三四五六七八九十A"
|
747
|
+
assert !t.save
|
748
|
+
assert t.errors.on(:content)
|
749
|
+
|
750
|
+
t.content = "一二345"
|
751
|
+
assert t.save
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
def test_validates_length_of_using_is_utf8
|
756
|
+
kcode_scope('UTF8') do
|
757
|
+
Topic.validates_length_of :title, :is => 5
|
758
|
+
|
759
|
+
t = Topic.create("title" => "一二345", "content" => "whatever")
|
760
|
+
assert t.valid?
|
761
|
+
|
762
|
+
t.title = "一二345六"
|
763
|
+
assert !t.valid?
|
764
|
+
assert t.errors.on(:title)
|
765
|
+
assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
|
766
|
+
end
|
767
|
+
end
|
768
|
+
|
769
|
+
def test_validates_size_of_association_utf8
|
770
|
+
kcode_scope('UTF8') do
|
771
|
+
assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 }
|
772
|
+
t = Topic.new('title' => 'あいうえお', 'content' => 'かきくけこ')
|
773
|
+
assert !t.save
|
774
|
+
assert t.errors.on(:replies)
|
775
|
+
t.replies.create('title' => 'あいうえお', 'content' => 'かきくけこ')
|
776
|
+
assert t.valid?
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|
593
780
|
def test_validates_associated_many
|
594
781
|
Topic.validates_associated( :replies )
|
595
782
|
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|