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/base_test.rb
CHANGED
@@ -17,10 +17,11 @@ class MasterCreditCard < ActiveRecord::Base; end
|
|
17
17
|
class Post < ActiveRecord::Base; end
|
18
18
|
class Computer < ActiveRecord::Base; end
|
19
19
|
class NonExistentTable < ActiveRecord::Base; end
|
20
|
-
class
|
20
|
+
class TestOracleDefault < ActiveRecord::Base; end
|
21
21
|
|
22
22
|
class LoosePerson < ActiveRecord::Base
|
23
23
|
attr_protected :credit_rating, :administrator
|
24
|
+
self.abstract_class = true
|
24
25
|
end
|
25
26
|
|
26
27
|
class LooseDescendant < LoosePerson
|
@@ -133,8 +134,24 @@ class BasicsTest < Test::Unit::TestCase
|
|
133
134
|
topic = Topic.new
|
134
135
|
topic.title = "New Topic"
|
135
136
|
topic.save
|
136
|
-
|
137
|
-
assert_equal("New Topic",
|
137
|
+
topic_reloaded = Topic.find(topic.id)
|
138
|
+
assert_equal("New Topic", topic_reloaded.title)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_save!
|
142
|
+
topic = Topic.new(:title => "New Topic")
|
143
|
+
assert topic.save!
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_hashes_not_mangled
|
147
|
+
new_topic = { :title => "New Topic" }
|
148
|
+
new_topic_values = { :title => "AnotherTopic" }
|
149
|
+
|
150
|
+
topic = Topic.new(new_topic)
|
151
|
+
assert_equal new_topic[:title], topic.title
|
152
|
+
|
153
|
+
topic.attributes= new_topic_values
|
154
|
+
assert_equal new_topic_values[:title], topic.title
|
138
155
|
end
|
139
156
|
|
140
157
|
def test_create_many
|
@@ -249,7 +266,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
249
266
|
if ActiveRecord::Base.generate_read_methods
|
250
267
|
assert_readers(Topic, %w(type replies_count))
|
251
268
|
assert_readers(Firm, %w(type))
|
252
|
-
assert_readers(Client, %w(type))
|
269
|
+
assert_readers(Client, %w(type ruby_type rating?))
|
253
270
|
else
|
254
271
|
[Topic, Firm, Client].each {|klass| assert_equal klass.read_methods, {}}
|
255
272
|
end
|
@@ -273,10 +290,18 @@ class BasicsTest < Test::Unit::TestCase
|
|
273
290
|
# SQL Server doesn't have a separate column type just for dates, so all are returned as time
|
274
291
|
return true if current_adapter?(:SQLServerAdapter)
|
275
292
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
293
|
+
if current_adapter?(:SybaseAdapter)
|
294
|
+
# Sybase ctlib does not (yet?) support the date type; use datetime instead.
|
295
|
+
assert_kind_of(
|
296
|
+
Time, Topic.find(1).last_read,
|
297
|
+
"The last_read attribute should be of the Time class"
|
298
|
+
)
|
299
|
+
else
|
300
|
+
assert_kind_of(
|
301
|
+
Date, Topic.find(1).last_read,
|
302
|
+
"The last_read attribute should be of the Date class"
|
303
|
+
)
|
304
|
+
end
|
280
305
|
end
|
281
306
|
|
282
307
|
def test_preserving_time_objects
|
@@ -434,7 +459,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
434
459
|
assert_equal 2, Topic.update_all("content = 'bulk updated!'")
|
435
460
|
assert_equal "bulk updated!", Topic.find(1).content
|
436
461
|
assert_equal "bulk updated!", Topic.find(2).content
|
437
|
-
assert_equal 2, Topic.update_all(['content = ?', 'bulk updated again!'])
|
462
|
+
assert_equal 2, Topic.update_all(['content = ?', 'bulk updated again!'])
|
438
463
|
assert_equal "bulk updated again!", Topic.find(1).content
|
439
464
|
assert_equal "bulk updated again!", Topic.find(2).content
|
440
465
|
end
|
@@ -515,8 +540,8 @@ class BasicsTest < Test::Unit::TestCase
|
|
515
540
|
|
516
541
|
# Oracle has some funky default handling, so it requires a bit of
|
517
542
|
# extra testing. See ticket #2788.
|
518
|
-
if current_adapter?(:
|
519
|
-
test =
|
543
|
+
if current_adapter?(:OracleAdapter)
|
544
|
+
test = TestOracleDefault.new
|
520
545
|
assert_equal "X", test.test_char
|
521
546
|
assert_equal "hello", test.test_string
|
522
547
|
assert_equal 3, test.test_int
|
@@ -525,7 +550,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
525
550
|
|
526
551
|
def test_utc_as_time_zone
|
527
552
|
# Oracle and SQLServer do not have a TIME datatype.
|
528
|
-
return true if current_adapter?(:SQLServerAdapter) || current_adapter?(:
|
553
|
+
return true if current_adapter?(:SQLServerAdapter) || current_adapter?(:OracleAdapter)
|
529
554
|
|
530
555
|
Topic.default_timezone = :utc
|
531
556
|
attributes = { "bonus_time" => "5:42:00AM" }
|
@@ -544,11 +569,17 @@ class BasicsTest < Test::Unit::TestCase
|
|
544
569
|
|
545
570
|
topic = Topic.find(topic.id)
|
546
571
|
assert_nil topic.last_read
|
547
|
-
|
572
|
+
|
573
|
+
# Sybase adapter does not allow nulls in boolean columns
|
574
|
+
if current_adapter?(:SybaseAdapter)
|
575
|
+
assert topic.approved == false
|
576
|
+
else
|
577
|
+
assert_nil topic.approved
|
578
|
+
end
|
548
579
|
end
|
549
580
|
|
550
581
|
def test_equality
|
551
|
-
assert_equal Topic.find(1), Topic.find(2).
|
582
|
+
assert_equal Topic.find(1), Topic.find(2).topic
|
552
583
|
end
|
553
584
|
|
554
585
|
def test_equality_of_new_records
|
@@ -556,7 +587,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
556
587
|
end
|
557
588
|
|
558
589
|
def test_hashing
|
559
|
-
assert_equal [ Topic.find(1) ], [ Topic.find(2).
|
590
|
+
assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
|
560
591
|
end
|
561
592
|
|
562
593
|
def test_destroy_new_record
|
@@ -638,27 +669,21 @@ class BasicsTest < Test::Unit::TestCase
|
|
638
669
|
end
|
639
670
|
|
640
671
|
def test_multiparameter_attributes_on_date
|
641
|
-
# SQL Server doesn't have a separate column type just for dates, so all are returned as time
|
642
|
-
return true if current_adapter?(:SQLServerAdapter)
|
643
|
-
|
644
672
|
attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" }
|
645
673
|
topic = Topic.find(1)
|
646
674
|
topic.attributes = attributes
|
647
675
|
# note that extra #to_date call allows test to pass for Oracle, which
|
648
676
|
# treats dates/times the same
|
649
|
-
|
677
|
+
assert_date_from_db Date.new(2004, 6, 24), topic.last_read.to_date
|
650
678
|
end
|
651
679
|
|
652
680
|
def test_multiparameter_attributes_on_date_with_empty_date
|
653
|
-
# SQL Server doesn't have a separate column type just for dates, so all are returned as time
|
654
|
-
return true if current_adapter?(:SQLServerAdapter)
|
655
|
-
|
656
681
|
attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "" }
|
657
682
|
topic = Topic.find(1)
|
658
683
|
topic.attributes = attributes
|
659
684
|
# note that extra #to_date call allows test to pass for Oracle, which
|
660
685
|
# treats dates/times the same
|
661
|
-
|
686
|
+
assert_date_from_db Date.new(2004, 6, 1), topic.last_read.to_date
|
662
687
|
end
|
663
688
|
|
664
689
|
def test_multiparameter_attributes_on_date_with_all_empty
|
@@ -699,7 +724,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
699
724
|
|
700
725
|
def test_attributes_on_dummy_time
|
701
726
|
# Oracle and SQL Server do not have a TIME datatype.
|
702
|
-
return true if current_adapter?(:SQLServerAdapter) || current_adapter?(:
|
727
|
+
return true if current_adapter?(:SQLServerAdapter) || current_adapter?(:OracleAdapter)
|
703
728
|
|
704
729
|
attributes = {
|
705
730
|
"bonus_time" => "5:42:00AM"
|
@@ -720,6 +745,18 @@ class BasicsTest < Test::Unit::TestCase
|
|
720
745
|
b_true = Booleantest.find(true_id)
|
721
746
|
assert b_true.value?
|
722
747
|
end
|
748
|
+
|
749
|
+
def test_boolean_cast_from_string
|
750
|
+
b_false = Booleantest.create({ "value" => "0" })
|
751
|
+
false_id = b_false.id
|
752
|
+
b_true = Booleantest.create({ "value" => "1" })
|
753
|
+
true_id = b_true.id
|
754
|
+
|
755
|
+
b_false = Booleantest.find(false_id)
|
756
|
+
assert !b_false.value?
|
757
|
+
b_true = Booleantest.find(true_id)
|
758
|
+
assert b_true.value?
|
759
|
+
end
|
723
760
|
|
724
761
|
def test_clone
|
725
762
|
topic = Topic.find(1)
|
@@ -784,17 +821,6 @@ class BasicsTest < Test::Unit::TestCase
|
|
784
821
|
def test_default
|
785
822
|
default = Default.new
|
786
823
|
|
787
|
-
# CURRENT_TIMESTAMP and NOW() timestamps
|
788
|
-
time_format = "%m/%d/%Y %H:%M"
|
789
|
-
now = Time.now.strftime(time_format)
|
790
|
-
assert_equal now, default.modified_time.strftime(time_format)
|
791
|
-
assert_equal now, default.modified_time_function.strftime(time_format)
|
792
|
-
|
793
|
-
# CURRENT_DATE and NOW() dates
|
794
|
-
today = Date.today
|
795
|
-
assert_equal today, default.modified_date
|
796
|
-
assert_equal today, default.modified_date_function
|
797
|
-
|
798
824
|
# fixed dates / times
|
799
825
|
assert_equal Date.new(2004, 1, 1), default.fixed_date
|
800
826
|
assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
|
@@ -1045,12 +1071,39 @@ class BasicsTest < Test::Unit::TestCase
|
|
1045
1071
|
|
1046
1072
|
def test_count_with_join
|
1047
1073
|
res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
|
1048
|
-
res2 =
|
1074
|
+
res2 = nil
|
1049
1075
|
assert_nothing_raised do
|
1050
1076
|
res2 = Post.count("posts.#{QUOTED_TYPE} = 'Post'",
|
1051
1077
|
"LEFT JOIN comments ON posts.id=comments.post_id")
|
1052
1078
|
end
|
1053
1079
|
assert_equal res, res2
|
1080
|
+
|
1081
|
+
res3 = nil
|
1082
|
+
assert_nothing_raised do
|
1083
|
+
res3 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'",
|
1084
|
+
:joins => "LEFT JOIN comments ON posts.id=comments.post_id")
|
1085
|
+
end
|
1086
|
+
assert_equal res, res3
|
1087
|
+
|
1088
|
+
res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments c WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=c.post_id"
|
1089
|
+
res5 = nil
|
1090
|
+
assert_nothing_raised do
|
1091
|
+
res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=c.post_id",
|
1092
|
+
:joins => "p, comments c",
|
1093
|
+
:select => "p.id")
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
assert_equal res4, res5
|
1097
|
+
|
1098
|
+
res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments c WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=c.post_id"
|
1099
|
+
res7 = nil
|
1100
|
+
assert_nothing_raised do
|
1101
|
+
res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=c.post_id",
|
1102
|
+
:joins => "p, comments c",
|
1103
|
+
:select => "p.id",
|
1104
|
+
:distinct => true)
|
1105
|
+
end
|
1106
|
+
assert_equal res6, res7
|
1054
1107
|
end
|
1055
1108
|
|
1056
1109
|
def test_clear_association_cache_stored
|
@@ -1082,29 +1135,129 @@ class BasicsTest < Test::Unit::TestCase
|
|
1082
1135
|
end
|
1083
1136
|
|
1084
1137
|
def test_scoped_find_conditions
|
1085
|
-
|
1138
|
+
scoped_developers = Developer.with_scope(:find => { :conditions => 'salary > 90000' }) do
|
1086
1139
|
Developer.find(:all, :conditions => 'id < 5')
|
1087
1140
|
end
|
1088
|
-
|
1089
|
-
|
1090
|
-
assert_equal 3, developers.size
|
1141
|
+
assert !scoped_developers.include?(developers(:david)) # David's salary is less than 90,000
|
1142
|
+
assert_equal 3, scoped_developers.size
|
1091
1143
|
end
|
1092
1144
|
|
1093
1145
|
def test_scoped_find_limit_offset
|
1094
|
-
|
1146
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 3, :offset => 2 }) do
|
1095
1147
|
Developer.find(:all, :order => 'id')
|
1096
1148
|
end
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
assert !developers.include?(jamis) # Jamis has id 2
|
1101
|
-
assert_equal 3, developers.size
|
1149
|
+
assert !scoped_developers.include?(developers(:david))
|
1150
|
+
assert !scoped_developers.include?(developers(:jamis))
|
1151
|
+
assert_equal 3, scoped_developers.size
|
1102
1152
|
|
1103
1153
|
# Test without scoped find conditions to ensure we get the whole thing
|
1104
1154
|
developers = Developer.find(:all, :order => 'id')
|
1105
|
-
assert_equal
|
1155
|
+
assert_equal Developer.count, developers.size
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
def test_base_class
|
1159
|
+
assert LoosePerson.abstract_class?
|
1160
|
+
assert !LooseDescendant.abstract_class?
|
1161
|
+
assert_equal LoosePerson, LoosePerson.base_class
|
1162
|
+
assert_equal LooseDescendant, LooseDescendant.base_class
|
1163
|
+
assert_equal TightPerson, TightPerson.base_class
|
1164
|
+
assert_equal TightPerson, TightDescendant.base_class
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
def test_assert_queries
|
1168
|
+
query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
|
1169
|
+
assert_queries(2) { 2.times { query.call } }
|
1170
|
+
assert_queries 1, &query
|
1171
|
+
assert_no_queries { assert true }
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
def test_to_xml
|
1175
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true)
|
1176
|
+
bonus_time_in_current_timezone = topics(:first).bonus_time.xmlschema
|
1177
|
+
written_on_in_current_timezone = topics(:first).written_on.xmlschema
|
1178
|
+
last_read_in_current_timezone = topics(:first).last_read.xmlschema
|
1179
|
+
assert_equal "<topic>", xml.first(7)
|
1180
|
+
assert xml.include?(%(<title>The First Topic</title>))
|
1181
|
+
assert xml.include?(%(<author-name>David</author-name>))
|
1182
|
+
assert xml.include?(%(<id type="integer">1</id>))
|
1183
|
+
assert xml.include?(%(<replies-count type="integer">0</replies-count>))
|
1184
|
+
assert xml.include?(%(<written-on type="datetime">#{written_on_in_current_timezone}</written-on>))
|
1185
|
+
assert xml.include?(%(<content>Have a nice day</content>))
|
1186
|
+
assert xml.include?(%(<author-email-address>david@loudthinking.com</author-email-address>))
|
1187
|
+
assert xml.include?(%(<parent-id></parent-id>))
|
1188
|
+
if current_adapter?(:SybaseAdapter) or current_adapter?(:SQLServerAdapter)
|
1189
|
+
assert xml.include?(%(<last-read type="datetime">#{last_read_in_current_timezone}</last-read>))
|
1190
|
+
else
|
1191
|
+
assert xml.include?(%(<last-read type="date">2004-04-15</last-read>))
|
1192
|
+
end
|
1193
|
+
# Oracle and DB2 don't have true boolean or time-only fields
|
1194
|
+
unless current_adapter?(:OracleAdapter) || current_adapter?(:DB2Adapter)
|
1195
|
+
assert xml.include?(%(<approved type="boolean">false</approved>)), "Approved should be a boolean"
|
1196
|
+
assert xml.include?(%(<bonus-time type="datetime">#{bonus_time_in_current_timezone}</bonus-time>))
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
def test_to_xml_skipping_attributes
|
1201
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => :title)
|
1202
|
+
assert_equal "<topic>", xml.first(7)
|
1203
|
+
assert !xml.include?(%(<title>The First Topic</title>))
|
1204
|
+
assert xml.include?(%(<author-name>David</author-name>))
|
1205
|
+
|
1206
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [ :title, :author_name ])
|
1207
|
+
assert !xml.include?(%(<title>The First Topic</title>))
|
1208
|
+
assert !xml.include?(%(<author-name>David</author-name>))
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
def test_to_xml_including_has_many_association
|
1212
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies)
|
1213
|
+
assert_equal "<topic>", xml.first(7)
|
1214
|
+
assert xml.include?(%(<replies><reply>))
|
1215
|
+
assert xml.include?(%(<title>The Second Topic's of the day</title>))
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
def test_to_xml_including_belongs_to_association
|
1219
|
+
xml = companies(:first_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1220
|
+
assert !xml.include?("<firm>")
|
1221
|
+
|
1222
|
+
xml = companies(:second_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1223
|
+
assert xml.include?("<firm>")
|
1224
|
+
end
|
1225
|
+
|
1226
|
+
def test_to_xml_including_multiple_associations
|
1227
|
+
xml = companies(:first_firm).to_xml(:indent => 0, :skip_instruct => true, :include => [ :clients, :account ])
|
1228
|
+
assert_equal "<firm>", xml.first(6)
|
1229
|
+
assert xml.include?(%(<account>))
|
1230
|
+
assert xml.include?(%(<clients><client>))
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
def test_to_xml_including_multiple_associations_with_options
|
1234
|
+
xml = companies(:first_firm).to_xml(
|
1235
|
+
:indent => 0, :skip_instruct => true,
|
1236
|
+
:include => { :clients => { :only => :name } }
|
1237
|
+
)
|
1238
|
+
|
1239
|
+
assert_equal "<firm>", xml.first(6)
|
1240
|
+
assert xml.include?(%(<client><name>Summit</name></client>))
|
1241
|
+
assert xml.include?(%(<clients><client>))
|
1242
|
+
end
|
1243
|
+
|
1244
|
+
def test_except_attributes
|
1245
|
+
assert_equal(
|
1246
|
+
%w( author_name type id approved replies_count bonus_time written_on content author_email_address parent_id last_read),
|
1247
|
+
topics(:first).attributes(:except => :title).keys
|
1248
|
+
)
|
1249
|
+
|
1250
|
+
assert_equal(
|
1251
|
+
%w( replies_count bonus_time written_on content author_email_address parent_id last_read),
|
1252
|
+
topics(:first).attributes(:except => [ :title, :id, :type, :approved, :author_name ]).keys
|
1253
|
+
)
|
1106
1254
|
end
|
1107
1255
|
|
1256
|
+
def test_include_attributes
|
1257
|
+
assert_equal(%w( title ), topics(:first).attributes(:only => :title).keys)
|
1258
|
+
assert_equal(%w( title author_name type id approved ), topics(:first).attributes(:only => [ :title, :id, :type, :approved, :author_name ]).keys)
|
1259
|
+
end
|
1260
|
+
|
1108
1261
|
# FIXME: this test ought to run, but it needs to run sandboxed so that it
|
1109
1262
|
# doesn't b0rk the current test environment by undefing everything.
|
1110
1263
|
#
|
@@ -1129,7 +1282,9 @@ class BasicsTest < Test::Unit::TestCase
|
|
1129
1282
|
|
1130
1283
|
private
|
1131
1284
|
def assert_readers(model, exceptions)
|
1132
|
-
expected_readers = model.column_names - (model.serialized_attributes.keys +
|
1133
|
-
|
1285
|
+
expected_readers = Set.new(model.column_names - (model.serialized_attributes.keys + ['id']))
|
1286
|
+
expected_readers += expected_readers.map { |col| "#{col}?" }
|
1287
|
+
expected_readers -= exceptions
|
1288
|
+
assert_equal expected_readers, model.read_methods
|
1134
1289
|
end
|
1135
1290
|
end
|
data/test/binary_test.rb
CHANGED
@@ -20,7 +20,7 @@ class BinaryTest < Test::Unit::TestCase
|
|
20
20
|
# Without using prepared statements, it makes no sense to test
|
21
21
|
# BLOB data with DB2 or Firebird, because the length of a statement
|
22
22
|
# is limited to 32KB.
|
23
|
-
unless %w(SQLServer DB2
|
23
|
+
unless %w(SQLServer Sybase DB2 Oracle Firebird).include? ActiveRecord::Base.connection.adapter_name
|
24
24
|
def test_load_save
|
25
25
|
bin = Binary.new
|
26
26
|
bin.data = @data
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/company'
|
3
|
+
require 'fixtures/topic'
|
4
|
+
|
5
|
+
Company.has_many :accounts
|
6
|
+
|
7
|
+
class CalculationsTest < Test::Unit::TestCase
|
8
|
+
fixtures :companies, :accounts, :topics
|
9
|
+
|
10
|
+
def test_should_sum_field
|
11
|
+
assert_equal 265, Account.sum(:credit_limit)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_average_field
|
15
|
+
value = Account.average(:credit_limit)
|
16
|
+
assert_equal 53, value
|
17
|
+
assert_kind_of Float, value
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_get_maximum_of_field
|
21
|
+
assert_equal 60, Account.maximum(:credit_limit)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_get_minimum_of_field
|
25
|
+
assert_equal 50, Account.minimum(:credit_limit)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_should_group_by_field
|
29
|
+
c = Account.sum(:credit_limit, :group => :firm_id)
|
30
|
+
[1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_should_group_by_summed_field
|
34
|
+
c = Account.sum(:credit_limit, :group => :firm_id)
|
35
|
+
assert_equal 50, c[1]
|
36
|
+
assert_equal 105, c[6]
|
37
|
+
assert_equal 60, c[2]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_should_order_by_grouped_field
|
41
|
+
c = Account.sum(:credit_limit, :group => :firm_id, :order => "firm_id")
|
42
|
+
assert_equal [1, 2, 6], c.keys.compact
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_order_by_calculation
|
46
|
+
c = Account.sum(:credit_limit, :group => :firm_id, :order => "sum_credit_limit desc, firm_id")
|
47
|
+
assert_equal [105, 60, 50, 50], c.keys.collect { |k| c[k] }
|
48
|
+
assert_equal [6, 2, 1], c.keys.compact
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_should_group_by_summed_field_having_condition
|
52
|
+
c = Account.sum(:credit_limit, :group => :firm_id,
|
53
|
+
:having => 'sum(credit_limit) > 50')
|
54
|
+
assert_nil c[1]
|
55
|
+
assert_equal 105, c[6]
|
56
|
+
assert_equal 60, c[2]
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_should_group_by_summed_association
|
60
|
+
c = Account.sum(:credit_limit, :group => :firm)
|
61
|
+
assert_equal 50, c[companies(:first_firm)]
|
62
|
+
assert_equal 105, c[companies(:rails_core)]
|
63
|
+
assert_equal 60, c[companies(:first_client)]
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_should_sum_field_with_conditions
|
67
|
+
assert_equal 105, Account.sum(:credit_limit, :conditions => 'firm_id = 6')
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_should_group_by_summed_field_with_conditions
|
71
|
+
c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
|
72
|
+
:group => :firm_id)
|
73
|
+
assert_nil c[1]
|
74
|
+
assert_equal 105, c[6]
|
75
|
+
assert_equal 60, c[2]
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_should_group_by_summed_field_with_conditions_and_having
|
79
|
+
c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
|
80
|
+
:group => :firm_id,
|
81
|
+
:having => 'sum(credit_limit) > 60')
|
82
|
+
assert_nil c[1]
|
83
|
+
assert_equal 105, c[6]
|
84
|
+
assert_nil c[2]
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_should_group_by_fields_with_table_alias
|
88
|
+
c = Account.sum(:credit_limit, :group => 'accounts.firm_id')
|
89
|
+
assert_equal 50, c[1]
|
90
|
+
assert_equal 105, c[6]
|
91
|
+
assert_equal 60, c[2]
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_should_calculate_with_invalid_field
|
95
|
+
assert_equal 5, Account.calculate(:count, '*')
|
96
|
+
assert_equal 5, Account.calculate(:count, :all)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_should_calculate_grouped_with_invalid_field
|
100
|
+
c = Account.count(:all, :group => 'accounts.firm_id')
|
101
|
+
assert_equal 1, c[1]
|
102
|
+
assert_equal 2, c[6]
|
103
|
+
assert_equal 1, c[2]
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_should_calculate_grouped_association_with_invalid_field
|
107
|
+
c = Account.count(:all, :group => :firm)
|
108
|
+
assert_equal 1, c[companies(:first_firm)]
|
109
|
+
assert_equal 2, c[companies(:rails_core)]
|
110
|
+
assert_equal 1, c[companies(:first_client)]
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_should_calculate_grouped_by_function
|
114
|
+
c = Company.count(:all, :group => 'UPPER(type)')
|
115
|
+
assert_equal 2, c[nil]
|
116
|
+
assert_equal 1, c['DEPENDENTFIRM']
|
117
|
+
assert_equal 3, c['CLIENT']
|
118
|
+
assert_equal 2, c['FIRM']
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_should_calculate_grouped_by_function_with_table_alias
|
122
|
+
c = Company.count(:all, :group => 'UPPER(companies.type)')
|
123
|
+
assert_equal 2, c[nil]
|
124
|
+
assert_equal 1, c['DEPENDENTFIRM']
|
125
|
+
assert_equal 3, c['CLIENT']
|
126
|
+
assert_equal 2, c['FIRM']
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_should_sum_scoped_field
|
130
|
+
assert_equal 15, companies(:rails_core).companies.sum(:id)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_should_sum_scoped_field_with_conditions
|
134
|
+
assert_equal 8, companies(:rails_core).companies.sum(:id, :conditions => 'id > 7')
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_should_group_by_scoped_field
|
138
|
+
c = companies(:rails_core).companies.sum(:id, :group => :name)
|
139
|
+
assert_equal 7, c['Leetsoft']
|
140
|
+
assert_equal 8, c['Jadedpixel']
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_should_group_by_summed_field_with_conditions_and_having
|
144
|
+
c = companies(:rails_core).companies.sum(:id, :group => :name,
|
145
|
+
:having => 'sum(id) > 7')
|
146
|
+
assert_nil c['Leetsoft']
|
147
|
+
assert_equal 8, c['Jadedpixel']
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_should_reject_invalid_options
|
151
|
+
assert_nothing_raised do
|
152
|
+
[:count, :sum].each do |func|
|
153
|
+
# empty options are valid
|
154
|
+
Company.send(:validate_calculation_options, func)
|
155
|
+
# these options are valid for all calculations
|
156
|
+
[:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
|
157
|
+
Company.send(:validate_calculation_options, func, opt => true)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# :include is only valid on :count
|
162
|
+
Company.send(:validate_calculation_options, :count, :include => true)
|
163
|
+
end
|
164
|
+
|
165
|
+
assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :sum, :include => :posts) }
|
166
|
+
assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) }
|
167
|
+
assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
|
168
|
+
end
|
169
|
+
end
|