activerecord 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +4928 -3
- data/README +45 -46
- data/RUNNING_UNIT_TESTS +8 -11
- data/Rakefile +247 -0
- data/install.rb +8 -38
- data/lib/active_record/aggregations.rb +64 -49
- data/lib/active_record/associations/association_collection.rb +217 -47
- data/lib/active_record/associations/association_proxy.rb +159 -0
- data/lib/active_record/associations/belongs_to_association.rb +56 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
- data/lib/active_record/associations/has_many_association.rb +145 -75
- data/lib/active_record/associations/has_many_through_association.rb +283 -0
- data/lib/active_record/associations/has_one_association.rb +96 -0
- data/lib/active_record/associations.rb +1537 -304
- data/lib/active_record/attribute_methods.rb +328 -0
- data/lib/active_record/base.rb +2001 -588
- data/lib/active_record/calculations.rb +269 -0
- data/lib/active_record/callbacks.rb +169 -165
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
- data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
- data/lib/active_record/fixtures.rb +946 -100
- data/lib/active_record/locking/optimistic.rb +144 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +417 -0
- data/lib/active_record/observer.rb +142 -32
- data/lib/active_record/query_cache.rb +23 -0
- data/lib/active_record/reflection.rb +163 -70
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +171 -0
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/serializers/xml_serializer.rb +315 -0
- data/lib/active_record/timestamp.rb +41 -0
- data/lib/active_record/transactions.rb +87 -57
- data/lib/active_record/validations.rb +909 -122
- data/lib/active_record/vendor/db2.rb +362 -0
- data/lib/active_record/vendor/mysql.rb +126 -29
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record.rb +35 -7
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +72 -0
- data/test/abstract_unit.rb +73 -5
- data/test/active_schema_test_mysql.rb +43 -0
- data/test/adapter_test.rb +105 -0
- data/test/adapter_test_sqlserver.rb +95 -0
- data/test/aggregations_test.rb +110 -16
- data/test/all.sh +2 -2
- data/test/ar_schema_test.rb +33 -0
- data/test/association_inheritance_reload.rb +14 -0
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +147 -0
- data/test/associations/cascaded_eager_loading_test.rb +110 -0
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +442 -0
- data/test/associations/extension_test.rb +47 -0
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +553 -0
- data/test/associations_test.rb +1930 -267
- data/test/attribute_methods_test.rb +146 -0
- data/test/base_test.rb +1316 -84
- data/test/binary_test.rb +32 -0
- data/test/calculations_test.rb +251 -0
- data/test/callbacks_test.rb +400 -0
- data/test/class_inheritable_attributes_test.rb +3 -4
- data/test/column_alias_test.rb +17 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +21 -18
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +17 -18
- data/test/connections/native_sqlite/connection.rb +17 -16
- data/test/connections/native_sqlite3/connection.rb +25 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/copy_table_test_sqlite.rb +69 -0
- data/test/datatype_test_postgresql.rb +203 -0
- data/test/date_time_test.rb +37 -0
- data/test/default_test_firebird.rb +16 -0
- data/test/defaults_test.rb +67 -0
- data/test/deprecated_finder_test.rb +30 -0
- data/test/finder_test.rb +607 -32
- data/test/fixtures/accounts.yml +28 -0
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author.rb +107 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +7 -0
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
- data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
- data/test/fixtures/bad_fixtures/blank_line +3 -0
- data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
- data/test/fixtures/bad_fixtures/missing_value +1 -0
- data/test/fixtures/binaries.yml +132 -0
- data/test/fixtures/binary.rb +2 -0
- data/test/fixtures/book.rb +4 -0
- data/test/fixtures/books.yml +7 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/category.rb +26 -0
- data/test/fixtures/citation.rb +6 -0
- data/test/fixtures/comment.rb +23 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +55 -0
- data/test/fixtures/company.rb +81 -4
- data/test/fixtures/company_in_module.rb +32 -6
- data/test/fixtures/computer.rb +4 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customer.rb +28 -3
- data/test/fixtures/customers.yml +17 -0
- data/test/fixtures/db_definitions/db2.drop.sql +33 -0
- data/test/fixtures/db_definitions/db2.sql +235 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
- data/test/fixtures/db_definitions/firebird.sql +310 -0
- data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
- data/test/fixtures/db_definitions/firebird2.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
- data/test/fixtures/db_definitions/frontbase.sql +273 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +318 -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/oracle.drop.sql +67 -0
- data/test/fixtures/db_definitions/oracle.sql +330 -0
- data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
- data/test/fixtures/db_definitions/postgresql.sql +217 -38
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +2 -2
- data/test/fixtures/db_definitions/schema.rb +354 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
- data/test/fixtures/db_definitions/sqlite.sql +139 -5
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +1 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
- data/test/fixtures/db_definitions/sybase.sql +222 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developer.rb +70 -6
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects/david_action_controller +2 -1
- data/test/fixtures/developers_projects/david_active_record +2 -1
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +3 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
- data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixed_case_monkey.rb +3 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixins.yml +29 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/parrot.rb +13 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/people.yml +3 -0
- data/test/fixtures/person.rb +4 -0
- data/test/fixtures/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +59 -0
- data/test/fixtures/posts.yml +48 -0
- data/test/fixtures/project.rb +27 -2
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +18 -2
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ship.rb +3 -0
- data/test/fixtures/ships.yml +5 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +4 -3
- data/test/fixtures/tag.rb +7 -0
- data/test/fixtures/tagging.rb +10 -0
- data/test/fixtures/taggings.yml +25 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/task.rb +3 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topic.rb +20 -3
- data/test/fixtures/topics.yml +22 -0
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +574 -8
- data/test/inheritance_test.rb +113 -27
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +56 -29
- data/test/locking_test.rb +273 -0
- data/test/method_scoping_test.rb +416 -0
- data/test/migration_test.rb +933 -0
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_test.rb +95 -0
- data/test/modules_test.rb +23 -10
- data/test/multiple_db_test.rb +17 -3
- data/test/pk_test.rb +59 -15
- data/test/query_cache_test.rb +104 -0
- data/test/readonly_test.rb +107 -0
- data/test/reflection_test.rb +124 -27
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +131 -0
- data/test/schema_test_postgresql.rb +64 -0
- data/test/serialization_test.rb +47 -0
- data/test/synonym_test_oracle.rb +17 -0
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +48 -0
- data/test/transactions_test.rb +227 -29
- data/test/unconnected_test.rb +14 -6
- data/test/validations_test.rb +1293 -32
- data/test/xml_serialization_test.rb +202 -0
- metadata +347 -143
- data/dev-utils/eval_debugger.rb +0 -9
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -88
- data/lib/active_record/deprecated_associations.rb +0 -70
- data/lib/active_record/support/class_attribute_accessors.rb +0 -43
- data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
- data/lib/active_record/support/clean_logger.rb +0 -10
- data/lib/active_record/support/inflector.rb +0 -70
- data/lib/active_record/vendor/simple.rb +0 -702
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -59
- data/rakefile +0 -122
- data/test/deprecated_associations_test.rb +0 -336
- data/test/fixtures/accounts/signals37 +0 -3
- data/test/fixtures/accounts/unknown +0 -2
- data/test/fixtures/companies/first_client +0 -6
- data/test/fixtures/companies/first_firm +0 -4
- data/test/fixtures/companies/second_client +0 -6
- data/test/fixtures/courses/java +0 -2
- data/test/fixtures/courses/ruby +0 -2
- data/test/fixtures/customers/david +0 -6
- data/test/fixtures/db_definitions/mysql.sql +0 -96
- data/test/fixtures/db_definitions/mysql2.sql +0 -4
- data/test/fixtures/developers/david +0 -2
- data/test/fixtures/developers/jamis +0 -2
- data/test/fixtures/entrants/first +0 -3
- data/test/fixtures/entrants/second +0 -3
- data/test/fixtures/entrants/third +0 -3
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/movies/first +0 -2
- data/test/fixtures/movies/second +0 -2
- data/test/fixtures/projects/action_controller +0 -2
- data/test/fixtures/projects/active_record +0 -2
- data/test/fixtures/topics/first +0 -9
- data/test/fixtures/topics/second +0 -8
- data/test/inflector_test.rb +0 -104
- data/test/thread_safety_test.rb +0 -33
data/test/base_test.rb
CHANGED
@@ -2,46 +2,94 @@ require 'abstract_unit'
|
|
2
2
|
require 'fixtures/topic'
|
3
3
|
require 'fixtures/reply'
|
4
4
|
require 'fixtures/company'
|
5
|
+
require 'fixtures/customer'
|
6
|
+
require 'fixtures/developer'
|
7
|
+
require 'fixtures/project'
|
5
8
|
require 'fixtures/default'
|
6
9
|
require 'fixtures/auto_id'
|
7
10
|
require 'fixtures/column_name'
|
11
|
+
require 'fixtures/subscriber'
|
12
|
+
require 'fixtures/keyboard'
|
13
|
+
require 'fixtures/post'
|
14
|
+
require 'fixtures/minimalistic'
|
15
|
+
require 'rexml/document'
|
8
16
|
|
9
17
|
class Category < ActiveRecord::Base; end
|
10
18
|
class Smarts < ActiveRecord::Base; end
|
11
|
-
class CreditCard < ActiveRecord::Base
|
19
|
+
class CreditCard < ActiveRecord::Base
|
20
|
+
class PinNumber < ActiveRecord::Base
|
21
|
+
class CvvCode < ActiveRecord::Base; end
|
22
|
+
class SubCvvCode < CvvCode; end
|
23
|
+
end
|
24
|
+
class SubPinNumber < PinNumber; end
|
25
|
+
class Brand < Category; end
|
26
|
+
end
|
12
27
|
class MasterCreditCard < ActiveRecord::Base; end
|
28
|
+
class Post < ActiveRecord::Base; end
|
29
|
+
class Computer < ActiveRecord::Base; end
|
30
|
+
class NonExistentTable < ActiveRecord::Base; end
|
31
|
+
class TestOracleDefault < ActiveRecord::Base; end
|
13
32
|
|
14
33
|
class LoosePerson < ActiveRecord::Base
|
34
|
+
self.table_name = 'people'
|
35
|
+
self.abstract_class = true
|
15
36
|
attr_protected :credit_rating, :administrator
|
16
37
|
end
|
17
38
|
|
39
|
+
class LooseDescendant < LoosePerson
|
40
|
+
attr_protected :phone_number
|
41
|
+
end
|
42
|
+
|
43
|
+
class LooseDescendantSecond< LoosePerson
|
44
|
+
attr_protected :phone_number
|
45
|
+
attr_protected :name
|
46
|
+
end
|
47
|
+
|
18
48
|
class TightPerson < ActiveRecord::Base
|
49
|
+
self.table_name = 'people'
|
19
50
|
attr_accessible :name, :address
|
20
51
|
end
|
21
52
|
|
22
|
-
class
|
53
|
+
class TightDescendant < TightPerson
|
23
54
|
attr_accessible :phone_number
|
24
55
|
end
|
25
56
|
|
57
|
+
class ReadonlyTitlePost < Post
|
58
|
+
attr_readonly :title
|
59
|
+
end
|
60
|
+
|
26
61
|
class Booleantest < ActiveRecord::Base; end
|
27
62
|
|
63
|
+
class Task < ActiveRecord::Base
|
64
|
+
attr_protected :starting
|
65
|
+
end
|
66
|
+
|
67
|
+
class TopicWithProtectedContentAndAccessibleAuthorName < ActiveRecord::Base
|
68
|
+
self.table_name = 'topics'
|
69
|
+
attr_accessible :author_name
|
70
|
+
attr_protected :content
|
71
|
+
end
|
72
|
+
|
28
73
|
class BasicsTest < Test::Unit::TestCase
|
29
|
-
|
30
|
-
@topic_fixtures, @companies = create_fixtures "topics", "companies"
|
31
|
-
end
|
74
|
+
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics
|
32
75
|
|
76
|
+
def test_table_exists
|
77
|
+
assert !NonExistentTable.table_exists?
|
78
|
+
assert Topic.table_exists?
|
79
|
+
end
|
80
|
+
|
33
81
|
def test_set_attributes
|
34
82
|
topic = Topic.find(1)
|
35
83
|
topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
|
36
84
|
topic.save
|
37
85
|
assert_equal("Budget", topic.title)
|
38
86
|
assert_equal("Jason", topic.author_name)
|
39
|
-
assert_equal(
|
87
|
+
assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
|
40
88
|
end
|
41
|
-
|
89
|
+
|
42
90
|
def test_integers_as_nil
|
43
|
-
|
44
|
-
assert_nil
|
91
|
+
test = AutoId.create('value' => '')
|
92
|
+
assert_nil AutoId.find(test.id).value
|
45
93
|
end
|
46
94
|
|
47
95
|
def test_set_attributes_with_block
|
@@ -59,9 +107,13 @@ class BasicsTest < Test::Unit::TestCase
|
|
59
107
|
assert topic.respond_to?("title")
|
60
108
|
assert topic.respond_to?("title?")
|
61
109
|
assert topic.respond_to?("title=")
|
110
|
+
assert topic.respond_to?(:title)
|
111
|
+
assert topic.respond_to?(:title?)
|
112
|
+
assert topic.respond_to?(:title=)
|
62
113
|
assert topic.respond_to?("author_name")
|
63
114
|
assert topic.respond_to?("attribute_names")
|
64
115
|
assert !topic.respond_to?("nothingness")
|
116
|
+
assert !topic.respond_to?(:nothingness)
|
65
117
|
end
|
66
118
|
|
67
119
|
def test_array_content
|
@@ -98,16 +150,80 @@ class BasicsTest < Test::Unit::TestCase
|
|
98
150
|
topic.content << "five"
|
99
151
|
assert_equal(%w( one two three four five ), topic.content)
|
100
152
|
end
|
101
|
-
|
153
|
+
|
154
|
+
def test_case_sensitive_attributes_hash
|
155
|
+
# DB2 is not case-sensitive
|
156
|
+
return true if current_adapter?(:DB2Adapter)
|
157
|
+
|
158
|
+
assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
|
159
|
+
end
|
160
|
+
|
102
161
|
def test_create
|
103
162
|
topic = Topic.new
|
104
163
|
topic.title = "New Topic"
|
105
164
|
topic.save
|
106
|
-
|
107
|
-
|
108
|
-
assert_equal("New Topic", topicReloaded.title)
|
165
|
+
topic_reloaded = Topic.find(topic.id)
|
166
|
+
assert_equal("New Topic", topic_reloaded.title)
|
109
167
|
end
|
110
168
|
|
169
|
+
def test_save!
|
170
|
+
topic = Topic.new(:title => "New Topic")
|
171
|
+
assert topic.save!
|
172
|
+
|
173
|
+
reply = Reply.new
|
174
|
+
assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_save_null_string_attributes
|
178
|
+
topic = Topic.find(1)
|
179
|
+
topic.attributes = { "title" => "null", "author_name" => "null" }
|
180
|
+
topic.save!
|
181
|
+
topic.reload
|
182
|
+
assert_equal("null", topic.title)
|
183
|
+
assert_equal("null", topic.author_name)
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_save_nil_string_attributes
|
187
|
+
topic = Topic.find(1)
|
188
|
+
topic.title = nil
|
189
|
+
topic.save!
|
190
|
+
topic.reload
|
191
|
+
assert_nil topic.title
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_save_for_record_with_only_primary_key
|
195
|
+
minimalistic = Minimalistic.new
|
196
|
+
assert_nothing_raised { minimalistic.save }
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_save_for_record_with_only_primary_key_that_is_provided
|
200
|
+
assert_nothing_raised { Minimalistic.create!(:id => 2) }
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_hashes_not_mangled
|
204
|
+
new_topic = { :title => "New Topic" }
|
205
|
+
new_topic_values = { :title => "AnotherTopic" }
|
206
|
+
|
207
|
+
topic = Topic.new(new_topic)
|
208
|
+
assert_equal new_topic[:title], topic.title
|
209
|
+
|
210
|
+
topic.attributes= new_topic_values
|
211
|
+
assert_equal new_topic_values[:title], topic.title
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_create_many
|
215
|
+
topics = Topic.create([ { "title" => "first" }, { "title" => "second" }])
|
216
|
+
assert_equal 2, topics.size
|
217
|
+
assert_equal "first", topics.first.title
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_create_columns_not_equal_attributes
|
221
|
+
topic = Topic.new
|
222
|
+
topic.title = 'Another New Topic'
|
223
|
+
topic.send :write_attribute, 'does_not_exist', 'test'
|
224
|
+
assert_nothing_raised { topic.save }
|
225
|
+
end
|
226
|
+
|
111
227
|
def test_create_through_factory
|
112
228
|
topic = Topic.create("title" => "New Topic")
|
113
229
|
topicReloaded = Topic.find(topic.id)
|
@@ -117,47 +233,209 @@ class BasicsTest < Test::Unit::TestCase
|
|
117
233
|
def test_update
|
118
234
|
topic = Topic.new
|
119
235
|
topic.title = "Another New Topic"
|
120
|
-
topic.written_on = "2003-12-12 23:23"
|
236
|
+
topic.written_on = "2003-12-12 23:23:00"
|
121
237
|
topic.save
|
122
|
-
|
123
|
-
assert_equal(id, topic.id)
|
124
|
-
|
125
|
-
topicReloaded = Topic.find(id)
|
238
|
+
topicReloaded = Topic.find(topic.id)
|
126
239
|
assert_equal("Another New Topic", topicReloaded.title)
|
127
240
|
|
128
241
|
topicReloaded.title = "Updated topic"
|
129
242
|
topicReloaded.save
|
130
243
|
|
131
|
-
topicReloadedAgain = Topic.find(id)
|
244
|
+
topicReloadedAgain = Topic.find(topic.id)
|
132
245
|
|
133
246
|
assert_equal("Updated topic", topicReloadedAgain.title)
|
134
247
|
end
|
135
248
|
|
136
|
-
def
|
249
|
+
def test_update_columns_not_equal_attributes
|
250
|
+
topic = Topic.new
|
251
|
+
topic.title = "Still another topic"
|
252
|
+
topic.save
|
253
|
+
|
254
|
+
topicReloaded = Topic.find(topic.id)
|
255
|
+
topicReloaded.title = "A New Topic"
|
256
|
+
topicReloaded.send :write_attribute, 'does_not_exist', 'test'
|
257
|
+
assert_nothing_raised { topicReloaded.save }
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_update_for_record_with_only_primary_key
|
261
|
+
minimalistic = minimalistics(:first)
|
262
|
+
assert_nothing_raised { minimalistic.save }
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_write_attribute
|
266
|
+
topic = Topic.new
|
267
|
+
topic.send(:write_attribute, :title, "Still another topic")
|
268
|
+
assert_equal "Still another topic", topic.title
|
269
|
+
|
270
|
+
topic.send(:write_attribute, "title", "Still another topic: part 2")
|
271
|
+
assert_equal "Still another topic: part 2", topic.title
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_read_attribute
|
275
|
+
topic = Topic.new
|
276
|
+
topic.title = "Don't change the topic"
|
277
|
+
assert_equal "Don't change the topic", topic.send(:read_attribute, "title")
|
278
|
+
assert_equal "Don't change the topic", topic["title"]
|
279
|
+
|
280
|
+
assert_equal "Don't change the topic", topic.send(:read_attribute, :title)
|
281
|
+
assert_equal "Don't change the topic", topic[:title]
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_read_attribute_when_false
|
285
|
+
topic = topics(:first)
|
286
|
+
topic.approved = false
|
287
|
+
assert !topic.approved?, "approved should be false"
|
288
|
+
topic.approved = "false"
|
289
|
+
assert !topic.approved?, "approved should be false"
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_read_attribute_when_true
|
293
|
+
topic = topics(:first)
|
294
|
+
topic.approved = true
|
295
|
+
assert topic.approved?, "approved should be true"
|
296
|
+
topic.approved = "true"
|
297
|
+
assert topic.approved?, "approved should be true"
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_read_write_boolean_attribute
|
301
|
+
topic = Topic.new
|
302
|
+
# puts ""
|
303
|
+
# puts "New Topic"
|
304
|
+
# puts topic.inspect
|
305
|
+
topic.approved = "false"
|
306
|
+
# puts "Expecting false"
|
307
|
+
# puts topic.inspect
|
308
|
+
assert !topic.approved?, "approved should be false"
|
309
|
+
topic.approved = "false"
|
310
|
+
# puts "Expecting false"
|
311
|
+
# puts topic.inspect
|
312
|
+
assert !topic.approved?, "approved should be false"
|
313
|
+
topic.approved = "true"
|
314
|
+
# puts "Expecting true"
|
315
|
+
# puts topic.inspect
|
316
|
+
assert topic.approved?, "approved should be true"
|
317
|
+
topic.approved = "true"
|
318
|
+
# puts "Expecting true"
|
319
|
+
# puts topic.inspect
|
320
|
+
assert topic.approved?, "approved should be true"
|
321
|
+
# puts ""
|
322
|
+
end
|
323
|
+
|
324
|
+
def test_query_attribute_string
|
325
|
+
[nil, "", " "].each do |value|
|
326
|
+
assert_equal false, Topic.new(:author_name => value).author_name?
|
327
|
+
end
|
328
|
+
|
329
|
+
assert_equal true, Topic.new(:author_name => "Name").author_name?
|
330
|
+
end
|
331
|
+
|
332
|
+
def test_query_attribute_number
|
333
|
+
[nil, 0, "0"].each do |value|
|
334
|
+
assert_equal false, Developer.new(:salary => value).salary?
|
335
|
+
end
|
336
|
+
|
337
|
+
assert_equal true, Developer.new(:salary => 1).salary?
|
338
|
+
assert_equal true, Developer.new(:salary => "1").salary?
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_query_attribute_boolean
|
342
|
+
[nil, "", false, "false", "f", 0].each do |value|
|
343
|
+
assert_equal false, Topic.new(:approved => value).approved?
|
344
|
+
end
|
345
|
+
|
346
|
+
[true, "true", "1", 1].each do |value|
|
347
|
+
assert_equal true, Topic.new(:approved => value).approved?
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def test_query_attribute_with_custom_fields
|
352
|
+
object = Company.find_by_sql(<<-SQL).first
|
353
|
+
SELECT c1.*, c2.ruby_type as string_value, c2.rating as int_value
|
354
|
+
FROM companies c1, companies c2
|
355
|
+
WHERE c1.firm_id = c2.id
|
356
|
+
AND c1.id = 2
|
357
|
+
SQL
|
358
|
+
|
359
|
+
assert_equal "Firm", object.string_value
|
360
|
+
assert object.string_value?
|
361
|
+
|
362
|
+
object.string_value = " "
|
363
|
+
assert !object.string_value?
|
364
|
+
|
365
|
+
assert_equal 1, object.int_value.to_i
|
366
|
+
assert object.int_value?
|
367
|
+
|
368
|
+
object.int_value = "0"
|
369
|
+
assert !object.int_value?
|
370
|
+
end
|
371
|
+
|
372
|
+
|
373
|
+
def test_reader_for_invalid_column_names
|
374
|
+
Topic.send(:define_read_method, "mumub-jumbo".to_sym, "mumub-jumbo", nil)
|
375
|
+
assert !Topic.generated_methods.include?("mumub-jumbo")
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_non_attribute_access_and_assignment
|
379
|
+
topic = Topic.new
|
380
|
+
assert !topic.respond_to?("mumbo")
|
381
|
+
assert_raises(NoMethodError) { topic.mumbo }
|
382
|
+
assert_raises(NoMethodError) { topic.mumbo = 5 }
|
383
|
+
end
|
384
|
+
|
385
|
+
def test_preserving_date_objects
|
386
|
+
# SQL Server doesn't have a separate column type just for dates, so all are returned as time
|
387
|
+
return true if current_adapter?(:SQLServerAdapter)
|
388
|
+
|
389
|
+
if current_adapter?(:SybaseAdapter, :OracleAdapter)
|
390
|
+
# Sybase ctlib does not (yet?) support the date type; use datetime instead.
|
391
|
+
# Oracle treats all dates/times as Time.
|
392
|
+
assert_kind_of(
|
393
|
+
Time, Topic.find(1).last_read,
|
394
|
+
"The last_read attribute should be of the Time class"
|
395
|
+
)
|
396
|
+
else
|
397
|
+
assert_kind_of(
|
398
|
+
Date, Topic.find(1).last_read,
|
399
|
+
"The last_read attribute should be of the Date class"
|
400
|
+
)
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
def test_preserving_time_objects
|
137
405
|
assert_kind_of(
|
138
|
-
Time, Topic.find(1).
|
139
|
-
"The
|
406
|
+
Time, Topic.find(1).bonus_time,
|
407
|
+
"The bonus_time attribute should be of the Time class"
|
140
408
|
)
|
141
409
|
|
142
410
|
assert_kind_of(
|
143
|
-
|
144
|
-
"The
|
411
|
+
Time, Topic.find(1).written_on,
|
412
|
+
"The written_on attribute should be of the Time class"
|
145
413
|
)
|
414
|
+
|
415
|
+
# For adapters which support microsecond resolution.
|
416
|
+
if current_adapter?(:PostgreSQLAdapter)
|
417
|
+
assert_equal 11, Topic.find(1).written_on.sec
|
418
|
+
assert_equal 223300, Topic.find(1).written_on.usec
|
419
|
+
assert_equal 9900, Topic.find(2).written_on.usec
|
420
|
+
end
|
146
421
|
end
|
147
422
|
|
423
|
+
def test_custom_mutator
|
424
|
+
topic = Topic.find(1)
|
425
|
+
# This mutator is protected in the class definition
|
426
|
+
topic.send(:approved=, true)
|
427
|
+
assert topic.instance_variable_get("@custom_approved")
|
428
|
+
end
|
429
|
+
|
148
430
|
def test_destroy
|
149
|
-
topic = Topic.
|
150
|
-
topic.
|
151
|
-
topic.
|
152
|
-
topic.
|
153
|
-
id = topic.id
|
154
|
-
topic.destroy
|
155
|
-
|
156
|
-
assert_raises(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(id) }
|
431
|
+
topic = Topic.find(1)
|
432
|
+
assert_equal topic, topic.destroy, 'topic.destroy did not return self'
|
433
|
+
assert topic.frozen?, 'topic not frozen after destroy'
|
434
|
+
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
|
157
435
|
end
|
158
|
-
|
436
|
+
|
159
437
|
def test_record_not_found_exception
|
160
|
-
assert_raises(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(
|
438
|
+
assert_raises(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(99999) }
|
161
439
|
end
|
162
440
|
|
163
441
|
def test_initialize_with_attributes
|
@@ -168,62 +446,107 @@ class BasicsTest < Test::Unit::TestCase
|
|
168
446
|
assert_equal("initialized from attributes", topic.title)
|
169
447
|
end
|
170
448
|
|
449
|
+
def test_initialize_with_invalid_attribute
|
450
|
+
begin
|
451
|
+
topic = Topic.new({ "title" => "test",
|
452
|
+
"last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
|
453
|
+
rescue ActiveRecord::MultiparameterAssignmentErrors => ex
|
454
|
+
assert_equal(1, ex.errors.size)
|
455
|
+
assert_equal("last_read", ex.errors[0].attribute)
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
171
459
|
def test_load
|
172
|
-
topics = Topic.
|
460
|
+
topics = Topic.find(:all, :order => 'id')
|
173
461
|
assert_equal(2, topics.size)
|
174
|
-
assert_equal(
|
462
|
+
assert_equal(topics(:first).title, topics.first.title)
|
175
463
|
end
|
176
464
|
|
177
465
|
def test_load_with_condition
|
178
|
-
topics = Topic.
|
466
|
+
topics = Topic.find(:all, :conditions => "author_name = 'Mary'")
|
179
467
|
|
180
468
|
assert_equal(1, topics.size)
|
181
|
-
assert_equal(
|
469
|
+
assert_equal(topics(:second).title, topics.first.title)
|
182
470
|
end
|
183
471
|
|
184
472
|
def test_table_name_guesses
|
473
|
+
classes = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]
|
474
|
+
|
185
475
|
assert_equal "topics", Topic.table_name
|
186
|
-
|
476
|
+
|
187
477
|
assert_equal "categories", Category.table_name
|
188
478
|
assert_equal "smarts", Smarts.table_name
|
189
479
|
assert_equal "credit_cards", CreditCard.table_name
|
480
|
+
assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
|
481
|
+
assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
|
482
|
+
assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
|
483
|
+
assert_equal "categories", CreditCard::Brand.table_name
|
190
484
|
assert_equal "master_credit_cards", MasterCreditCard.table_name
|
191
485
|
|
192
486
|
ActiveRecord::Base.pluralize_table_names = false
|
487
|
+
classes.each(&:reset_table_name)
|
488
|
+
|
193
489
|
assert_equal "category", Category.table_name
|
194
490
|
assert_equal "smarts", Smarts.table_name
|
195
491
|
assert_equal "credit_card", CreditCard.table_name
|
492
|
+
assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
|
493
|
+
assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
|
494
|
+
assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
|
495
|
+
assert_equal "category", CreditCard::Brand.table_name
|
196
496
|
assert_equal "master_credit_card", MasterCreditCard.table_name
|
497
|
+
|
197
498
|
ActiveRecord::Base.pluralize_table_names = true
|
499
|
+
classes.each(&:reset_table_name)
|
198
500
|
|
199
501
|
ActiveRecord::Base.table_name_prefix = "test_"
|
502
|
+
Category.reset_table_name
|
200
503
|
assert_equal "test_categories", Category.table_name
|
201
504
|
ActiveRecord::Base.table_name_suffix = "_test"
|
505
|
+
Category.reset_table_name
|
202
506
|
assert_equal "test_categories_test", Category.table_name
|
203
507
|
ActiveRecord::Base.table_name_prefix = ""
|
508
|
+
Category.reset_table_name
|
204
509
|
assert_equal "categories_test", Category.table_name
|
205
510
|
ActiveRecord::Base.table_name_suffix = ""
|
511
|
+
Category.reset_table_name
|
206
512
|
assert_equal "categories", Category.table_name
|
207
513
|
|
208
514
|
ActiveRecord::Base.pluralize_table_names = false
|
209
515
|
ActiveRecord::Base.table_name_prefix = "test_"
|
516
|
+
Category.reset_table_name
|
210
517
|
assert_equal "test_category", Category.table_name
|
211
518
|
ActiveRecord::Base.table_name_suffix = "_test"
|
519
|
+
Category.reset_table_name
|
212
520
|
assert_equal "test_category_test", Category.table_name
|
213
521
|
ActiveRecord::Base.table_name_prefix = ""
|
522
|
+
Category.reset_table_name
|
214
523
|
assert_equal "category_test", Category.table_name
|
215
524
|
ActiveRecord::Base.table_name_suffix = ""
|
525
|
+
Category.reset_table_name
|
216
526
|
assert_equal "category", Category.table_name
|
527
|
+
|
217
528
|
ActiveRecord::Base.pluralize_table_names = true
|
529
|
+
classes.each(&:reset_table_name)
|
218
530
|
end
|
219
531
|
|
220
532
|
def test_destroy_all
|
221
|
-
assert_equal
|
533
|
+
assert_equal 2, Topic.count
|
222
534
|
|
223
535
|
Topic.destroy_all "author_name = 'Mary'"
|
224
|
-
assert_equal
|
536
|
+
assert_equal 1, Topic.count
|
225
537
|
end
|
226
|
-
|
538
|
+
|
539
|
+
def test_destroy_many
|
540
|
+
assert_equal 3, Client.count
|
541
|
+
Client.destroy([2, 3])
|
542
|
+
assert_equal 1, Client.count
|
543
|
+
end
|
544
|
+
|
545
|
+
def test_delete_many
|
546
|
+
Topic.delete([1, 2])
|
547
|
+
assert_equal 0, Topic.count
|
548
|
+
end
|
549
|
+
|
227
550
|
def test_boolean_attributes
|
228
551
|
assert ! Topic.find(1).approved?
|
229
552
|
assert Topic.find(2).approved?
|
@@ -231,28 +554,63 @@ class BasicsTest < Test::Unit::TestCase
|
|
231
554
|
|
232
555
|
def test_increment_counter
|
233
556
|
Topic.increment_counter("replies_count", 1)
|
234
|
-
assert_equal
|
557
|
+
assert_equal 2, Topic.find(1).replies_count
|
235
558
|
|
236
559
|
Topic.increment_counter("replies_count", 1)
|
237
|
-
assert_equal
|
560
|
+
assert_equal 3, Topic.find(1).replies_count
|
238
561
|
end
|
239
562
|
|
240
563
|
def test_decrement_counter
|
241
564
|
Topic.decrement_counter("replies_count", 2)
|
242
|
-
assert_equal 1, Topic.find(2).replies_count
|
565
|
+
assert_equal -1, Topic.find(2).replies_count
|
243
566
|
|
244
567
|
Topic.decrement_counter("replies_count", 2)
|
245
|
-
assert_equal
|
568
|
+
assert_equal -2, Topic.find(2).replies_count
|
246
569
|
end
|
247
|
-
|
570
|
+
|
248
571
|
def test_update_all
|
249
|
-
Topic.update_all
|
572
|
+
assert_equal 2, Topic.update_all("content = 'bulk updated!'")
|
250
573
|
assert_equal "bulk updated!", Topic.find(1).content
|
251
574
|
assert_equal "bulk updated!", Topic.find(2).content
|
575
|
+
|
576
|
+
assert_equal 2, Topic.update_all(['content = ?', 'bulk updated again!'])
|
577
|
+
assert_equal "bulk updated again!", Topic.find(1).content
|
578
|
+
assert_equal "bulk updated again!", Topic.find(2).content
|
579
|
+
|
580
|
+
assert_equal 2, Topic.update_all(['content = ?', nil])
|
581
|
+
assert_nil Topic.find(1).content
|
252
582
|
end
|
253
|
-
|
583
|
+
|
584
|
+
def test_update_all_with_hash
|
585
|
+
assert_not_nil Topic.find(1).last_read
|
586
|
+
assert_equal 2, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil)
|
587
|
+
assert_equal "bulk updated with hash!", Topic.find(1).content
|
588
|
+
assert_equal "bulk updated with hash!", Topic.find(2).content
|
589
|
+
assert_nil Topic.find(1).last_read
|
590
|
+
assert_nil Topic.find(2).last_read
|
591
|
+
end
|
592
|
+
|
593
|
+
if current_adapter?(:MysqlAdapter)
|
594
|
+
def test_update_all_with_order_and_limit
|
595
|
+
assert_equal 1, Topic.update_all("content = 'bulk updated!'", nil, :limit => 1, :order => 'id DESC')
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
def test_update_many
|
600
|
+
topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
|
601
|
+
updated = Topic.update(topic_data.keys, topic_data.values)
|
602
|
+
|
603
|
+
assert_equal 2, updated.size
|
604
|
+
assert_equal "1 updated", Topic.find(1).content
|
605
|
+
assert_equal "2 updated", Topic.find(2).content
|
606
|
+
end
|
607
|
+
|
608
|
+
def test_delete_all
|
609
|
+
assert_equal 2, Topic.delete_all
|
610
|
+
end
|
611
|
+
|
254
612
|
def test_update_by_condition
|
255
|
-
Topic.update_all "content = 'bulk updated!'", "approved =
|
613
|
+
Topic.update_all "content = 'bulk updated!'", ["approved = ?", true]
|
256
614
|
assert_equal "Have a nice day", Topic.find(1).content
|
257
615
|
assert_equal "bulk updated!", Topic.find(2).content
|
258
616
|
end
|
@@ -269,7 +627,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
269
627
|
def test_attribute_keys_on_new_instance
|
270
628
|
t = Topic.new
|
271
629
|
assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
|
272
|
-
|
630
|
+
assert_raise(NoMethodError) { t.title2 }
|
273
631
|
end
|
274
632
|
|
275
633
|
def test_class_name
|
@@ -298,17 +656,52 @@ class BasicsTest < Test::Unit::TestCase
|
|
298
656
|
|
299
657
|
def test_default_values
|
300
658
|
topic = Topic.new
|
301
|
-
|
659
|
+
assert topic.approved?
|
302
660
|
assert_nil topic.written_on
|
661
|
+
assert_nil topic.bonus_time
|
303
662
|
assert_nil topic.last_read
|
304
663
|
|
305
664
|
topic.save
|
306
665
|
|
307
666
|
topic = Topic.find(topic.id)
|
308
|
-
|
667
|
+
assert topic.approved?
|
309
668
|
assert_nil topic.last_read
|
669
|
+
|
670
|
+
# Oracle has some funky default handling, so it requires a bit of
|
671
|
+
# extra testing. See ticket #2788.
|
672
|
+
if current_adapter?(:OracleAdapter)
|
673
|
+
test = TestOracleDefault.new
|
674
|
+
assert_equal "X", test.test_char
|
675
|
+
assert_equal "hello", test.test_string
|
676
|
+
assert_equal 3, test.test_int
|
677
|
+
end
|
310
678
|
end
|
311
|
-
|
679
|
+
|
680
|
+
# Oracle, SQLServer, and Sybase do not have a TIME datatype.
|
681
|
+
unless current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
|
682
|
+
def test_utc_as_time_zone
|
683
|
+
Topic.default_timezone = :utc
|
684
|
+
attributes = { "bonus_time" => "5:42:00AM" }
|
685
|
+
topic = Topic.find(1)
|
686
|
+
topic.attributes = attributes
|
687
|
+
assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
|
688
|
+
Topic.default_timezone = :local
|
689
|
+
end
|
690
|
+
|
691
|
+
def test_utc_as_time_zone_and_new
|
692
|
+
Topic.default_timezone = :utc
|
693
|
+
attributes = { "bonus_time(1i)"=>"2000",
|
694
|
+
"bonus_time(2i)"=>"1",
|
695
|
+
"bonus_time(3i)"=>"1",
|
696
|
+
"bonus_time(4i)"=>"10",
|
697
|
+
"bonus_time(5i)"=>"35",
|
698
|
+
"bonus_time(6i)"=>"50" }
|
699
|
+
topic = Topic.new(attributes)
|
700
|
+
assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
|
701
|
+
Topic.default_timezone = :local
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
312
705
|
def test_default_values_on_empty_strings
|
313
706
|
topic = Topic.new
|
314
707
|
topic.approved = nil
|
@@ -318,11 +711,25 @@ class BasicsTest < Test::Unit::TestCase
|
|
318
711
|
|
319
712
|
topic = Topic.find(topic.id)
|
320
713
|
assert_nil topic.last_read
|
321
|
-
|
714
|
+
|
715
|
+
# Sybase adapter does not allow nulls in boolean columns
|
716
|
+
if current_adapter?(:SybaseAdapter)
|
717
|
+
assert topic.approved == false
|
718
|
+
else
|
719
|
+
assert_nil topic.approved
|
720
|
+
end
|
322
721
|
end
|
323
|
-
|
722
|
+
|
324
723
|
def test_equality
|
325
|
-
assert_equal Topic.find(1), Topic.find(2).
|
724
|
+
assert_equal Topic.find(1), Topic.find(2).topic
|
725
|
+
end
|
726
|
+
|
727
|
+
def test_equality_of_new_records
|
728
|
+
assert_not_equal Topic.new, Topic.new
|
729
|
+
end
|
730
|
+
|
731
|
+
def test_hashing
|
732
|
+
assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
|
326
733
|
end
|
327
734
|
|
328
735
|
def test_destroy_new_record
|
@@ -331,10 +738,61 @@ class BasicsTest < Test::Unit::TestCase
|
|
331
738
|
assert client.frozen?
|
332
739
|
end
|
333
740
|
|
741
|
+
def test_destroy_record_with_associations
|
742
|
+
client = Client.find(3)
|
743
|
+
client.destroy
|
744
|
+
assert client.frozen?
|
745
|
+
assert_kind_of Firm, client.firm
|
746
|
+
assert_raises(TypeError) { client.name = "something else" }
|
747
|
+
end
|
748
|
+
|
334
749
|
def test_update_attribute
|
335
750
|
assert !Topic.find(1).approved?
|
336
751
|
Topic.find(1).update_attribute("approved", true)
|
337
752
|
assert Topic.find(1).approved?
|
753
|
+
|
754
|
+
Topic.find(1).update_attribute(:approved, false)
|
755
|
+
assert !Topic.find(1).approved?
|
756
|
+
end
|
757
|
+
|
758
|
+
def test_update_attributes
|
759
|
+
topic = Topic.find(1)
|
760
|
+
assert !topic.approved?
|
761
|
+
assert_equal "The First Topic", topic.title
|
762
|
+
|
763
|
+
topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
|
764
|
+
topic.reload
|
765
|
+
assert topic.approved?
|
766
|
+
assert_equal "The First Topic Updated", topic.title
|
767
|
+
|
768
|
+
topic.update_attributes(:approved => false, :title => "The First Topic")
|
769
|
+
topic.reload
|
770
|
+
assert !topic.approved?
|
771
|
+
assert_equal "The First Topic", topic.title
|
772
|
+
end
|
773
|
+
|
774
|
+
def test_update_attributes!
|
775
|
+
reply = Reply.find(2)
|
776
|
+
assert_equal "The Second Topic's of the day", reply.title
|
777
|
+
assert_equal "Have a nice day", reply.content
|
778
|
+
|
779
|
+
reply.update_attributes!("title" => "The Second Topic's of the day updated", "content" => "Have a nice evening")
|
780
|
+
reply.reload
|
781
|
+
assert_equal "The Second Topic's of the day updated", reply.title
|
782
|
+
assert_equal "Have a nice evening", reply.content
|
783
|
+
|
784
|
+
reply.update_attributes!(:title => "The Second Topic's of the day", :content => "Have a nice day")
|
785
|
+
reply.reload
|
786
|
+
assert_equal "The Second Topic's of the day", reply.title
|
787
|
+
assert_equal "Have a nice day", reply.content
|
788
|
+
|
789
|
+
assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(:title => nil, :content => "Have a nice evening") }
|
790
|
+
end
|
791
|
+
|
792
|
+
def test_mass_assignment_should_raise_exception_if_accessible_and_protected_attribute_writers_are_both_used
|
793
|
+
topic = TopicWithProtectedContentAndAccessibleAuthorName.new
|
794
|
+
assert_raises(RuntimeError) { topic.attributes = { "author_name" => "me" } }
|
795
|
+
assert_raises(RuntimeError) { topic.attributes = { "content" => "stuff" } }
|
338
796
|
end
|
339
797
|
|
340
798
|
def test_mass_assignment_protection
|
@@ -343,35 +801,97 @@ class BasicsTest < Test::Unit::TestCase
|
|
343
801
|
assert_equal 1, firm.rating
|
344
802
|
end
|
345
803
|
|
804
|
+
def test_mass_assignment_protection_against_class_attribute_writers
|
805
|
+
[:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names, :colorize_logging,
|
806
|
+
:default_timezone, :allow_concurrency, :schema_format, :verification_timeout, :lock_optimistically, :record_timestamps].each do |method|
|
807
|
+
assert Task.respond_to?(method)
|
808
|
+
assert Task.respond_to?("#{method}=")
|
809
|
+
assert Task.new.respond_to?(method)
|
810
|
+
assert !Task.new.respond_to?("#{method}=")
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
814
|
+
def test_customized_primary_key_remains_protected
|
815
|
+
subscriber = Subscriber.new(:nick => 'webster123', :name => 'nice try')
|
816
|
+
assert_nil subscriber.id
|
817
|
+
|
818
|
+
keyboard = Keyboard.new(:key_number => 9, :name => 'nice try')
|
819
|
+
assert_nil keyboard.id
|
820
|
+
end
|
821
|
+
|
822
|
+
def test_customized_primary_key_remains_protected_when_referred_to_as_id
|
823
|
+
subscriber = Subscriber.new(:id => 'webster123', :name => 'nice try')
|
824
|
+
assert_nil subscriber.id
|
825
|
+
|
826
|
+
keyboard = Keyboard.new(:id => 9, :name => 'nice try')
|
827
|
+
assert_nil keyboard.id
|
828
|
+
end
|
829
|
+
|
830
|
+
def test_mass_assignment_protection_on_defaults
|
831
|
+
firm = Firm.new
|
832
|
+
firm.attributes = { "id" => 5, "type" => "Client" }
|
833
|
+
assert_nil firm.id
|
834
|
+
assert_equal "Firm", firm[:type]
|
835
|
+
end
|
836
|
+
|
346
837
|
def test_mass_assignment_accessible
|
347
|
-
reply = Reply.new("title" => "hello", "content" => "world", "approved" =>
|
838
|
+
reply = Reply.new("title" => "hello", "content" => "world", "approved" => true)
|
348
839
|
reply.save
|
840
|
+
|
841
|
+
assert reply.approved?
|
349
842
|
|
350
|
-
|
351
|
-
|
352
|
-
reply.approved = 0
|
843
|
+
reply.approved = false
|
353
844
|
reply.save
|
354
845
|
|
355
|
-
|
846
|
+
assert !reply.approved?
|
356
847
|
end
|
357
848
|
|
358
849
|
def test_mass_assignment_protection_inheritance
|
359
|
-
|
850
|
+
assert_nil LoosePerson.accessible_attributes
|
851
|
+
assert_equal Set.new([ 'credit_rating', 'administrator' ]), LoosePerson.protected_attributes
|
852
|
+
|
853
|
+
assert_nil LooseDescendant.accessible_attributes
|
854
|
+
assert_equal Set.new([ 'credit_rating', 'administrator', 'phone_number' ]), LooseDescendant.protected_attributes
|
855
|
+
|
856
|
+
assert_nil LooseDescendantSecond.accessible_attributes
|
857
|
+
assert_equal Set.new([ 'credit_rating', 'administrator', 'phone_number', 'name' ]), LooseDescendantSecond.protected_attributes, 'Running attr_protected twice in one class should merge the protections'
|
858
|
+
|
360
859
|
assert_nil TightPerson.protected_attributes
|
860
|
+
assert_equal Set.new([ 'name', 'address' ]), TightPerson.accessible_attributes
|
861
|
+
|
862
|
+
assert_nil TightDescendant.protected_attributes
|
863
|
+
assert_equal Set.new([ 'name', 'address', 'phone_number' ]), TightDescendant.accessible_attributes
|
864
|
+
end
|
865
|
+
|
866
|
+
def test_readonly_attributes
|
867
|
+
assert_equal Set.new([ 'title' ]), ReadonlyTitlePost.readonly_attributes
|
868
|
+
|
869
|
+
post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable")
|
870
|
+
post.reload
|
871
|
+
assert_equal "cannot change this", post.title
|
872
|
+
|
873
|
+
post.update_attributes(:title => "try to change", :body => "changed")
|
874
|
+
post.reload
|
875
|
+
assert_equal "cannot change this", post.title
|
876
|
+
assert_equal "changed", post.body
|
361
877
|
end
|
362
878
|
|
363
879
|
def test_multiparameter_attributes_on_date
|
364
880
|
attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" }
|
365
881
|
topic = Topic.find(1)
|
366
882
|
topic.attributes = attributes
|
367
|
-
|
883
|
+
# note that extra #to_date call allows test to pass for Oracle, which
|
884
|
+
# treats dates/times the same
|
885
|
+
assert_date_from_db Date.new(2004, 6, 24), topic.last_read.to_date
|
368
886
|
end
|
369
887
|
|
370
888
|
def test_multiparameter_attributes_on_date_with_empty_date
|
371
889
|
attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "" }
|
372
890
|
topic = Topic.find(1)
|
373
891
|
topic.attributes = attributes
|
374
|
-
|
892
|
+
# note that extra #to_date call allows test to pass for Oracle, which
|
893
|
+
# treats dates/times the same
|
894
|
+
assert_date_from_db Date.new(2004, 6, 1), topic.last_read.to_date
|
375
895
|
end
|
376
896
|
|
377
897
|
def test_multiparameter_attributes_on_date_with_all_empty
|
@@ -401,6 +921,35 @@ class BasicsTest < Test::Unit::TestCase
|
|
401
921
|
assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
|
402
922
|
end
|
403
923
|
|
924
|
+
def test_multiparameter_mass_assignment_protector
|
925
|
+
task = Task.new
|
926
|
+
time = Time.mktime(2000, 1, 1, 1)
|
927
|
+
task.starting = time
|
928
|
+
attributes = { "starting(1i)" => "2004", "starting(2i)" => "6", "starting(3i)" => "24" }
|
929
|
+
task.attributes = attributes
|
930
|
+
assert_equal time, task.starting
|
931
|
+
end
|
932
|
+
|
933
|
+
def test_multiparameter_assignment_of_aggregation
|
934
|
+
customer = Customer.new
|
935
|
+
address = Address.new("The Street", "The City", "The Country")
|
936
|
+
attributes = { "address(1)" => address.street, "address(2)" => address.city, "address(3)" => address.country }
|
937
|
+
customer.attributes = attributes
|
938
|
+
assert_equal address, customer.address
|
939
|
+
end
|
940
|
+
|
941
|
+
def test_attributes_on_dummy_time
|
942
|
+
# Oracle, SQL Server, and Sybase do not have a TIME datatype.
|
943
|
+
return true if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
|
944
|
+
|
945
|
+
attributes = {
|
946
|
+
"bonus_time" => "5:42:00AM"
|
947
|
+
}
|
948
|
+
topic = Topic.find(1)
|
949
|
+
topic.attributes = attributes
|
950
|
+
assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
|
951
|
+
end
|
952
|
+
|
404
953
|
def test_boolean
|
405
954
|
b_false = Booleantest.create({ "value" => false })
|
406
955
|
false_id = b_false.id
|
@@ -412,10 +961,23 @@ class BasicsTest < Test::Unit::TestCase
|
|
412
961
|
b_true = Booleantest.find(true_id)
|
413
962
|
assert b_true.value?
|
414
963
|
end
|
964
|
+
|
965
|
+
def test_boolean_cast_from_string
|
966
|
+
b_false = Booleantest.create({ "value" => "0" })
|
967
|
+
false_id = b_false.id
|
968
|
+
b_true = Booleantest.create({ "value" => "1" })
|
969
|
+
true_id = b_true.id
|
970
|
+
|
971
|
+
b_false = Booleantest.find(false_id)
|
972
|
+
assert !b_false.value?
|
973
|
+
b_true = Booleantest.find(true_id)
|
974
|
+
assert b_true.value?
|
975
|
+
end
|
415
976
|
|
416
977
|
def test_clone
|
417
978
|
topic = Topic.find(1)
|
418
|
-
cloned_topic =
|
979
|
+
cloned_topic = nil
|
980
|
+
assert_nothing_raised { cloned_topic = topic.clone }
|
419
981
|
assert_equal topic.title, cloned_topic.title
|
420
982
|
assert cloned_topic.new_record?
|
421
983
|
|
@@ -430,8 +992,42 @@ class BasicsTest < Test::Unit::TestCase
|
|
430
992
|
cloned_topic = topic.clone
|
431
993
|
cloned_topic.title["a"] = "c"
|
432
994
|
assert_equal "b", topic.title["a"]
|
995
|
+
|
996
|
+
#test if attributes set as part of after_initialize are cloned correctly
|
997
|
+
assert_equal topic.author_email_address, cloned_topic.author_email_address
|
998
|
+
|
999
|
+
# test if saved clone object differs from original
|
1000
|
+
cloned_topic.save
|
1001
|
+
assert !cloned_topic.new_record?
|
1002
|
+
assert cloned_topic.id != topic.id
|
433
1003
|
end
|
434
|
-
|
1004
|
+
|
1005
|
+
def test_clone_with_aggregate_of_same_name_as_attribute
|
1006
|
+
dev = DeveloperWithAggregate.find(1)
|
1007
|
+
assert_kind_of DeveloperSalary, dev.salary
|
1008
|
+
|
1009
|
+
clone = nil
|
1010
|
+
assert_nothing_raised { clone = dev.clone }
|
1011
|
+
assert_kind_of DeveloperSalary, clone.salary
|
1012
|
+
assert_equal dev.salary.amount, clone.salary.amount
|
1013
|
+
assert clone.new_record?
|
1014
|
+
|
1015
|
+
# test if the attributes have been cloned
|
1016
|
+
original_amount = clone.salary.amount
|
1017
|
+
dev.salary.amount = 1
|
1018
|
+
assert_equal original_amount, clone.salary.amount
|
1019
|
+
|
1020
|
+
assert clone.save
|
1021
|
+
assert !clone.new_record?
|
1022
|
+
assert clone.id != dev.id
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
def test_clone_preserves_subtype
|
1026
|
+
clone = nil
|
1027
|
+
assert_nothing_raised { clone = Company.find(3).clone }
|
1028
|
+
assert_kind_of Client, clone
|
1029
|
+
end
|
1030
|
+
|
435
1031
|
def test_bignum
|
436
1032
|
company = Company.find(1)
|
437
1033
|
company.rating = 2147483647
|
@@ -440,15 +1036,11 @@ class BasicsTest < Test::Unit::TestCase
|
|
440
1036
|
assert_equal 2147483647, company.rating
|
441
1037
|
end
|
442
1038
|
|
443
|
-
|
444
|
-
|
1039
|
+
# TODO: extend defaults tests to other databases!
|
1040
|
+
if current_adapter?(:PostgreSQLAdapter)
|
1041
|
+
def test_default
|
445
1042
|
default = Default.new
|
446
1043
|
|
447
|
-
# dates / timestampts
|
448
|
-
time_format = "%m/%d/%Y %H:%M"
|
449
|
-
assert_equal Time.now.strftime(time_format), default.modified_time.strftime(time_format)
|
450
|
-
assert_equal Date.today, default.modified_date
|
451
|
-
|
452
1044
|
# fixed dates / times
|
453
1045
|
assert_equal Date.new(2004, 1, 1), default.fixed_date
|
454
1046
|
assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
|
@@ -458,6 +1050,100 @@ class BasicsTest < Test::Unit::TestCase
|
|
458
1050
|
assert_equal 'a varchar field', default.char2
|
459
1051
|
assert_equal 'a text field', default.char3
|
460
1052
|
end
|
1053
|
+
|
1054
|
+
class Geometric < ActiveRecord::Base; end
|
1055
|
+
def test_geometric_content
|
1056
|
+
|
1057
|
+
# accepted format notes:
|
1058
|
+
# ()'s aren't required
|
1059
|
+
# values can be a mix of float or integer
|
1060
|
+
|
1061
|
+
g = Geometric.new(
|
1062
|
+
:a_point => '(5.0, 6.1)',
|
1063
|
+
#:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
|
1064
|
+
:a_line_segment => '(2.0, 3), (5.5, 7.0)',
|
1065
|
+
:a_box => '2.0, 3, 5.5, 7.0',
|
1066
|
+
:a_path => '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]', # [ ] is an open path
|
1067
|
+
:a_polygon => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))',
|
1068
|
+
:a_circle => '<(5.3, 10.4), 2>'
|
1069
|
+
)
|
1070
|
+
|
1071
|
+
assert g.save
|
1072
|
+
|
1073
|
+
# Reload and check that we have all the geometric attributes.
|
1074
|
+
h = Geometric.find(g.id)
|
1075
|
+
|
1076
|
+
assert_equal '(5,6.1)', h.a_point
|
1077
|
+
assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
|
1078
|
+
assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
|
1079
|
+
assert_equal '[(2,3),(5.5,7),(8.5,11)]', h.a_path
|
1080
|
+
assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
|
1081
|
+
assert_equal '<(5.3,10.4),2>', h.a_circle
|
1082
|
+
|
1083
|
+
# use a geometric function to test for an open path
|
1084
|
+
objs = Geometric.find_by_sql ["select isopen(a_path) from geometrics where id = ?", g.id]
|
1085
|
+
assert_equal objs[0].isopen, 't'
|
1086
|
+
|
1087
|
+
# test alternate formats when defining the geometric types
|
1088
|
+
|
1089
|
+
g = Geometric.new(
|
1090
|
+
:a_point => '5.0, 6.1',
|
1091
|
+
#:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
|
1092
|
+
:a_line_segment => '((2.0, 3), (5.5, 7.0))',
|
1093
|
+
:a_box => '(2.0, 3), (5.5, 7.0)',
|
1094
|
+
:a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', # ( ) is a closed path
|
1095
|
+
:a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
|
1096
|
+
:a_circle => '((5.3, 10.4), 2)'
|
1097
|
+
)
|
1098
|
+
|
1099
|
+
assert g.save
|
1100
|
+
|
1101
|
+
# Reload and check that we have all the geometric attributes.
|
1102
|
+
h = Geometric.find(g.id)
|
1103
|
+
|
1104
|
+
assert_equal '(5,6.1)', h.a_point
|
1105
|
+
assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
|
1106
|
+
assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
|
1107
|
+
assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
|
1108
|
+
assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
|
1109
|
+
assert_equal '<(5.3,10.4),2>', h.a_circle
|
1110
|
+
|
1111
|
+
# use a geometric function to test for an closed path
|
1112
|
+
objs = Geometric.find_by_sql ["select isclosed(a_path) from geometrics where id = ?", g.id]
|
1113
|
+
assert_equal objs[0].isclosed, 't'
|
1114
|
+
end
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
class NumericData < ActiveRecord::Base
|
1118
|
+
self.table_name = 'numeric_data'
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
def test_numeric_fields
|
1122
|
+
m = NumericData.new(
|
1123
|
+
:bank_balance => 1586.43,
|
1124
|
+
:big_bank_balance => BigDecimal("1000234000567.95"),
|
1125
|
+
:world_population => 6000000000,
|
1126
|
+
:my_house_population => 3
|
1127
|
+
)
|
1128
|
+
assert m.save
|
1129
|
+
|
1130
|
+
m1 = NumericData.find(m.id)
|
1131
|
+
assert_not_nil m1
|
1132
|
+
|
1133
|
+
# As with migration_test.rb, we should make world_population >= 2**62
|
1134
|
+
# to cover 64-bit platforms and test it is a Bignum, but the main thing
|
1135
|
+
# is that it's an Integer.
|
1136
|
+
assert_kind_of Integer, m1.world_population
|
1137
|
+
assert_equal 6000000000, m1.world_population
|
1138
|
+
|
1139
|
+
assert_kind_of Fixnum, m1.my_house_population
|
1140
|
+
assert_equal 3, m1.my_house_population
|
1141
|
+
|
1142
|
+
assert_kind_of BigDecimal, m1.bank_balance
|
1143
|
+
assert_equal BigDecimal("1586.43"), m1.bank_balance
|
1144
|
+
|
1145
|
+
assert_kind_of BigDecimal, m1.big_bank_balance
|
1146
|
+
assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
|
461
1147
|
end
|
462
1148
|
|
463
1149
|
def test_auto_id
|
@@ -465,7 +1151,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
465
1151
|
auto.save
|
466
1152
|
assert (auto.id > 0)
|
467
1153
|
end
|
468
|
-
|
1154
|
+
|
469
1155
|
def quote_column_name(name)
|
470
1156
|
"<#{name}>"
|
471
1157
|
end
|
@@ -479,16 +1165,30 @@ class BasicsTest < Test::Unit::TestCase
|
|
479
1165
|
assert_equal("<baz>", inverted["quux"])
|
480
1166
|
end
|
481
1167
|
|
1168
|
+
def test_sql_injection_via_find
|
1169
|
+
assert_raises(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
|
1170
|
+
Topic.find("123456 OR id > 0")
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
|
482
1174
|
def test_column_name_properly_quoted
|
483
1175
|
col_record = ColumnName.new
|
484
1176
|
col_record.references = 40
|
485
|
-
col_record.save
|
1177
|
+
assert col_record.save
|
486
1178
|
col_record.references = 41
|
487
|
-
col_record.save
|
488
|
-
c2 = ColumnName.find(col_record.id)
|
1179
|
+
assert col_record.save
|
1180
|
+
assert_not_nil c2 = ColumnName.find(col_record.id)
|
489
1181
|
assert_equal(41, c2.references)
|
490
1182
|
end
|
491
1183
|
|
1184
|
+
def test_quoting_arrays
|
1185
|
+
replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
|
1186
|
+
assert_equal topics(:first).replies.size, replies.size
|
1187
|
+
|
1188
|
+
replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
|
1189
|
+
assert_equal 0, replies.size
|
1190
|
+
end
|
1191
|
+
|
492
1192
|
MyObject = Struct.new :attribute1, :attribute2
|
493
1193
|
|
494
1194
|
def test_serialized_attribute
|
@@ -498,16 +1198,548 @@ class BasicsTest < Test::Unit::TestCase
|
|
498
1198
|
assert_equal(myobj, topic.content)
|
499
1199
|
end
|
500
1200
|
|
501
|
-
def
|
1201
|
+
def test_nil_serialized_attribute_with_class_constraint
|
502
1202
|
myobj = MyObject.new('value1', 'value2')
|
503
|
-
topic = Topic.
|
504
|
-
|
1203
|
+
topic = Topic.new
|
1204
|
+
assert_nil topic.content
|
1205
|
+
end
|
505
1206
|
|
506
|
-
|
1207
|
+
def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
|
1208
|
+
myobj = MyObject.new('value1', 'value2')
|
1209
|
+
topic = Topic.new(:content => myobj)
|
1210
|
+
assert topic.save
|
1211
|
+
Topic.serialize(:content, Hash)
|
1212
|
+
assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content }
|
1213
|
+
ensure
|
1214
|
+
Topic.serialize(:content)
|
1215
|
+
end
|
507
1216
|
|
1217
|
+
def test_serialized_attribute_with_class_constraint
|
508
1218
|
settings = { "color" => "blue" }
|
509
|
-
Topic.
|
1219
|
+
Topic.serialize(:content, Hash)
|
1220
|
+
topic = Topic.new(:content => settings)
|
1221
|
+
assert topic.save
|
510
1222
|
assert_equal(settings, Topic.find(topic.id).content)
|
1223
|
+
ensure
|
511
1224
|
Topic.serialize(:content)
|
512
1225
|
end
|
513
|
-
|
1226
|
+
|
1227
|
+
def test_quote
|
1228
|
+
author_name = "\\ \001 ' \n \\n \""
|
1229
|
+
topic = Topic.create('author_name' => author_name)
|
1230
|
+
assert_equal author_name, Topic.find(topic.id).author_name
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
def test_quote_chars
|
1234
|
+
str = 'The Narrator'
|
1235
|
+
topic = Topic.create(:author_name => str)
|
1236
|
+
assert_equal str, topic.author_name
|
1237
|
+
|
1238
|
+
assert_kind_of ActiveSupport::Multibyte::Chars, str.chars
|
1239
|
+
topic = Topic.find_by_author_name(str.chars)
|
1240
|
+
|
1241
|
+
assert_kind_of Topic, topic
|
1242
|
+
assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
def test_class_level_destroy
|
1246
|
+
should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
|
1247
|
+
Topic.find(1).replies << should_be_destroyed_reply
|
1248
|
+
|
1249
|
+
Topic.destroy(1)
|
1250
|
+
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
|
1251
|
+
assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
def test_class_level_delete
|
1255
|
+
should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
|
1256
|
+
Topic.find(1).replies << should_be_destroyed_reply
|
1257
|
+
|
1258
|
+
Topic.delete(1)
|
1259
|
+
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
|
1260
|
+
assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
def test_increment_attribute
|
1264
|
+
assert_equal 50, accounts(:signals37).credit_limit
|
1265
|
+
accounts(:signals37).increment! :credit_limit
|
1266
|
+
assert_equal 51, accounts(:signals37, :reload).credit_limit
|
1267
|
+
|
1268
|
+
accounts(:signals37).increment(:credit_limit).increment!(:credit_limit)
|
1269
|
+
assert_equal 53, accounts(:signals37, :reload).credit_limit
|
1270
|
+
end
|
1271
|
+
|
1272
|
+
def test_increment_nil_attribute
|
1273
|
+
assert_nil topics(:first).parent_id
|
1274
|
+
topics(:first).increment! :parent_id
|
1275
|
+
assert_equal 1, topics(:first).parent_id
|
1276
|
+
end
|
1277
|
+
|
1278
|
+
def test_decrement_attribute
|
1279
|
+
assert_equal 50, accounts(:signals37).credit_limit
|
1280
|
+
|
1281
|
+
accounts(:signals37).decrement!(:credit_limit)
|
1282
|
+
assert_equal 49, accounts(:signals37, :reload).credit_limit
|
1283
|
+
|
1284
|
+
accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit)
|
1285
|
+
assert_equal 47, accounts(:signals37, :reload).credit_limit
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
def test_toggle_attribute
|
1289
|
+
assert !topics(:first).approved?
|
1290
|
+
topics(:first).toggle!(:approved)
|
1291
|
+
assert topics(:first).approved?
|
1292
|
+
topic = topics(:first)
|
1293
|
+
topic.toggle(:approved)
|
1294
|
+
assert !topic.approved?
|
1295
|
+
topic.reload
|
1296
|
+
assert topic.approved?
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
def test_reload
|
1300
|
+
t1 = Topic.find(1)
|
1301
|
+
t2 = Topic.find(1)
|
1302
|
+
t1.title = "something else"
|
1303
|
+
t1.save
|
1304
|
+
t2.reload
|
1305
|
+
assert_equal t1.title, t2.title
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
def test_define_attr_method_with_value
|
1309
|
+
k = Class.new( ActiveRecord::Base )
|
1310
|
+
k.send(:define_attr_method, :table_name, "foo")
|
1311
|
+
assert_equal "foo", k.table_name
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
def test_define_attr_method_with_block
|
1315
|
+
k = Class.new( ActiveRecord::Base )
|
1316
|
+
k.send(:define_attr_method, :primary_key) { "sys_" + original_primary_key }
|
1317
|
+
assert_equal "sys_id", k.primary_key
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
def test_set_table_name_with_value
|
1321
|
+
k = Class.new( ActiveRecord::Base )
|
1322
|
+
k.table_name = "foo"
|
1323
|
+
assert_equal "foo", k.table_name
|
1324
|
+
k.set_table_name "bar"
|
1325
|
+
assert_equal "bar", k.table_name
|
1326
|
+
end
|
1327
|
+
|
1328
|
+
def test_set_table_name_with_block
|
1329
|
+
k = Class.new( ActiveRecord::Base )
|
1330
|
+
k.set_table_name { "ks" }
|
1331
|
+
assert_equal "ks", k.table_name
|
1332
|
+
end
|
1333
|
+
|
1334
|
+
def test_set_primary_key_with_value
|
1335
|
+
k = Class.new( ActiveRecord::Base )
|
1336
|
+
k.primary_key = "foo"
|
1337
|
+
assert_equal "foo", k.primary_key
|
1338
|
+
k.set_primary_key "bar"
|
1339
|
+
assert_equal "bar", k.primary_key
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
def test_set_primary_key_with_block
|
1343
|
+
k = Class.new( ActiveRecord::Base )
|
1344
|
+
k.set_primary_key { "sys_" + original_primary_key }
|
1345
|
+
assert_equal "sys_id", k.primary_key
|
1346
|
+
end
|
1347
|
+
|
1348
|
+
def test_set_inheritance_column_with_value
|
1349
|
+
k = Class.new( ActiveRecord::Base )
|
1350
|
+
k.inheritance_column = "foo"
|
1351
|
+
assert_equal "foo", k.inheritance_column
|
1352
|
+
k.set_inheritance_column "bar"
|
1353
|
+
assert_equal "bar", k.inheritance_column
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
def test_set_inheritance_column_with_block
|
1357
|
+
k = Class.new( ActiveRecord::Base )
|
1358
|
+
k.set_inheritance_column { original_inheritance_column + "_id" }
|
1359
|
+
assert_equal "type_id", k.inheritance_column
|
1360
|
+
end
|
1361
|
+
|
1362
|
+
def test_count_with_join
|
1363
|
+
res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
|
1364
|
+
|
1365
|
+
res2 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'", :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
|
1366
|
+
assert_equal res, res2
|
1367
|
+
|
1368
|
+
res3 = nil
|
1369
|
+
assert_nothing_raised do
|
1370
|
+
res3 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'",
|
1371
|
+
:joins => "LEFT JOIN comments ON posts.id=comments.post_id")
|
1372
|
+
end
|
1373
|
+
assert_equal res, res3
|
1374
|
+
|
1375
|
+
res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
|
1376
|
+
res5 = nil
|
1377
|
+
assert_nothing_raised do
|
1378
|
+
res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
|
1379
|
+
:joins => "p, comments co",
|
1380
|
+
:select => "p.id")
|
1381
|
+
end
|
1382
|
+
|
1383
|
+
assert_equal res4, res5
|
1384
|
+
|
1385
|
+
unless current_adapter?(:SQLite2Adapter, :DeprecatedSQLiteAdapter)
|
1386
|
+
res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
|
1387
|
+
res7 = nil
|
1388
|
+
assert_nothing_raised do
|
1389
|
+
res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
|
1390
|
+
:joins => "p, comments co",
|
1391
|
+
:select => "p.id",
|
1392
|
+
:distinct => true)
|
1393
|
+
end
|
1394
|
+
assert_equal res6, res7
|
1395
|
+
end
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
def test_clear_association_cache_stored
|
1399
|
+
firm = Firm.find(1)
|
1400
|
+
assert_kind_of Firm, firm
|
1401
|
+
|
1402
|
+
firm.clear_association_cache
|
1403
|
+
assert_equal Firm.find(1).clients.collect{ |x| x.name }.sort, firm.clients.collect{ |x| x.name }.sort
|
1404
|
+
end
|
1405
|
+
|
1406
|
+
def test_clear_association_cache_new_record
|
1407
|
+
firm = Firm.new
|
1408
|
+
client_stored = Client.find(3)
|
1409
|
+
client_new = Client.new
|
1410
|
+
client_new.name = "The Joneses"
|
1411
|
+
clients = [ client_stored, client_new ]
|
1412
|
+
|
1413
|
+
firm.clients << clients
|
1414
|
+
assert_equal clients.map(&:name).to_set, firm.clients.map(&:name).to_set
|
1415
|
+
|
1416
|
+
firm.clear_association_cache
|
1417
|
+
assert_equal clients.map(&:name).to_set, firm.clients.map(&:name).to_set
|
1418
|
+
end
|
1419
|
+
|
1420
|
+
def test_interpolate_sql
|
1421
|
+
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo@bar') }
|
1422
|
+
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar) baz') }
|
1423
|
+
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar} baz') }
|
1424
|
+
end
|
1425
|
+
|
1426
|
+
def test_scoped_find_conditions
|
1427
|
+
scoped_developers = Developer.with_scope(:find => { :conditions => 'salary > 90000' }) do
|
1428
|
+
Developer.find(:all, :conditions => 'id < 5')
|
1429
|
+
end
|
1430
|
+
assert !scoped_developers.include?(developers(:david)) # David's salary is less than 90,000
|
1431
|
+
assert_equal 3, scoped_developers.size
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
def test_scoped_find_limit_offset
|
1435
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 3, :offset => 2 }) do
|
1436
|
+
Developer.find(:all, :order => 'id')
|
1437
|
+
end
|
1438
|
+
assert !scoped_developers.include?(developers(:david))
|
1439
|
+
assert !scoped_developers.include?(developers(:jamis))
|
1440
|
+
assert_equal 3, scoped_developers.size
|
1441
|
+
|
1442
|
+
# Test without scoped find conditions to ensure we get the whole thing
|
1443
|
+
developers = Developer.find(:all, :order => 'id')
|
1444
|
+
assert_equal Developer.count, developers.size
|
1445
|
+
end
|
1446
|
+
|
1447
|
+
def test_scoped_find_order
|
1448
|
+
# Test order in scope
|
1449
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 1, :order => 'salary DESC' }) do
|
1450
|
+
Developer.find(:all)
|
1451
|
+
end
|
1452
|
+
assert_equal 'Jamis', scoped_developers.first.name
|
1453
|
+
assert scoped_developers.include?(developers(:jamis))
|
1454
|
+
# Test scope without order and order in find
|
1455
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 1 }) do
|
1456
|
+
Developer.find(:all, :order => 'salary DESC')
|
1457
|
+
end
|
1458
|
+
# Test scope order + find order, find has priority
|
1459
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 3, :order => 'id DESC' }) do
|
1460
|
+
Developer.find(:all, :order => 'salary ASC')
|
1461
|
+
end
|
1462
|
+
assert scoped_developers.include?(developers(:poor_jamis))
|
1463
|
+
assert scoped_developers.include?(developers(:david))
|
1464
|
+
assert scoped_developers.include?(developers(:dev_10))
|
1465
|
+
# Test without scoped find conditions to ensure we get the right thing
|
1466
|
+
developers = Developer.find(:all, :order => 'id', :limit => 1)
|
1467
|
+
assert scoped_developers.include?(developers(:david))
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
def test_scoped_find_limit_offset_including_has_many_association
|
1471
|
+
topics = Topic.with_scope(:find => {:limit => 1, :offset => 1, :include => :replies}) do
|
1472
|
+
Topic.find(:all, :order => "topics.id")
|
1473
|
+
end
|
1474
|
+
assert_equal 1, topics.size
|
1475
|
+
assert_equal 2, topics.first.id
|
1476
|
+
end
|
1477
|
+
|
1478
|
+
def test_scoped_find_order_including_has_many_association
|
1479
|
+
developers = Developer.with_scope(:find => { :order => 'developers.salary DESC', :include => :projects }) do
|
1480
|
+
Developer.find(:all)
|
1481
|
+
end
|
1482
|
+
assert developers.size >= 2
|
1483
|
+
for i in 1...developers.size
|
1484
|
+
assert developers[i-1].salary >= developers[i].salary
|
1485
|
+
end
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
def test_abstract_class
|
1489
|
+
assert !ActiveRecord::Base.abstract_class?
|
1490
|
+
assert LoosePerson.abstract_class?
|
1491
|
+
assert !LooseDescendant.abstract_class?
|
1492
|
+
end
|
1493
|
+
|
1494
|
+
def test_base_class
|
1495
|
+
assert_equal LoosePerson, LoosePerson.base_class
|
1496
|
+
assert_equal LooseDescendant, LooseDescendant.base_class
|
1497
|
+
assert_equal TightPerson, TightPerson.base_class
|
1498
|
+
assert_equal TightPerson, TightDescendant.base_class
|
1499
|
+
|
1500
|
+
assert_equal Post, Post.base_class
|
1501
|
+
assert_equal Post, SpecialPost.base_class
|
1502
|
+
assert_equal Post, StiPost.base_class
|
1503
|
+
assert_equal SubStiPost, SubStiPost.base_class
|
1504
|
+
end
|
1505
|
+
|
1506
|
+
def test_descends_from_active_record
|
1507
|
+
# Tries to call Object.abstract_class?
|
1508
|
+
assert_raise(NoMethodError) do
|
1509
|
+
ActiveRecord::Base.descends_from_active_record?
|
1510
|
+
end
|
1511
|
+
|
1512
|
+
# Abstract subclass of AR::Base.
|
1513
|
+
assert LoosePerson.descends_from_active_record?
|
1514
|
+
|
1515
|
+
# Concrete subclass of an abstract class.
|
1516
|
+
assert LooseDescendant.descends_from_active_record?
|
1517
|
+
|
1518
|
+
# Concrete subclass of AR::Base.
|
1519
|
+
assert TightPerson.descends_from_active_record?
|
1520
|
+
|
1521
|
+
# Concrete subclass of a concrete class but has no type column.
|
1522
|
+
assert TightDescendant.descends_from_active_record?
|
1523
|
+
|
1524
|
+
# Concrete subclass of AR::Base.
|
1525
|
+
assert Post.descends_from_active_record?
|
1526
|
+
|
1527
|
+
# Abstract subclass of a concrete class which has a type column.
|
1528
|
+
# This is pathological, as you'll never have Sub < Abstract < Concrete.
|
1529
|
+
assert !StiPost.descends_from_active_record?
|
1530
|
+
|
1531
|
+
# Concrete subclasses an abstract class which has a type column.
|
1532
|
+
assert !SubStiPost.descends_from_active_record?
|
1533
|
+
end
|
1534
|
+
|
1535
|
+
def test_find_on_abstract_base_class_doesnt_use_type_condition
|
1536
|
+
old_class = LooseDescendant
|
1537
|
+
Object.send :remove_const, :LooseDescendant
|
1538
|
+
|
1539
|
+
descendant = old_class.create!
|
1540
|
+
assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
|
1541
|
+
ensure
|
1542
|
+
unless Object.const_defined?(:LooseDescendant)
|
1543
|
+
Object.const_set :LooseDescendant, old_class
|
1544
|
+
end
|
1545
|
+
end
|
1546
|
+
|
1547
|
+
def test_assert_queries
|
1548
|
+
query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
|
1549
|
+
assert_queries(2) { 2.times { query.call } }
|
1550
|
+
assert_queries 1, &query
|
1551
|
+
assert_no_queries { assert true }
|
1552
|
+
end
|
1553
|
+
|
1554
|
+
def test_to_xml
|
1555
|
+
xml = REXML::Document.new(topics(:first).to_xml(:indent => 0))
|
1556
|
+
bonus_time_in_current_timezone = topics(:first).bonus_time.xmlschema
|
1557
|
+
written_on_in_current_timezone = topics(:first).written_on.xmlschema
|
1558
|
+
last_read_in_current_timezone = topics(:first).last_read.xmlschema
|
1559
|
+
|
1560
|
+
assert_equal "topic", xml.root.name
|
1561
|
+
assert_equal "The First Topic" , xml.elements["//title"].text
|
1562
|
+
assert_equal "David" , xml.elements["//author-name"].text
|
1563
|
+
|
1564
|
+
assert_equal "1", xml.elements["//id"].text
|
1565
|
+
assert_equal "integer" , xml.elements["//id"].attributes['type']
|
1566
|
+
|
1567
|
+
assert_equal "1", xml.elements["//replies-count"].text
|
1568
|
+
assert_equal "integer" , xml.elements["//replies-count"].attributes['type']
|
1569
|
+
|
1570
|
+
assert_equal written_on_in_current_timezone, xml.elements["//written-on"].text
|
1571
|
+
assert_equal "datetime" , xml.elements["//written-on"].attributes['type']
|
1572
|
+
|
1573
|
+
assert_equal "--- Have a nice day\n" , xml.elements["//content"].text
|
1574
|
+
assert_equal "yaml" , xml.elements["//content"].attributes['type']
|
1575
|
+
|
1576
|
+
assert_equal "david@loudthinking.com", xml.elements["//author-email-address"].text
|
1577
|
+
|
1578
|
+
assert_equal nil, xml.elements["//parent-id"].text
|
1579
|
+
assert_equal "integer", xml.elements["//parent-id"].attributes['type']
|
1580
|
+
assert_equal "true", xml.elements["//parent-id"].attributes['nil']
|
1581
|
+
|
1582
|
+
if current_adapter?(:SybaseAdapter, :SQLServerAdapter, :OracleAdapter)
|
1583
|
+
assert_equal last_read_in_current_timezone, xml.elements["//last-read"].text
|
1584
|
+
assert_equal "datetime" , xml.elements["//last-read"].attributes['type']
|
1585
|
+
else
|
1586
|
+
assert_equal "2004-04-15", xml.elements["//last-read"].text
|
1587
|
+
assert_equal "date" , xml.elements["//last-read"].attributes['type']
|
1588
|
+
end
|
1589
|
+
|
1590
|
+
# Oracle and DB2 don't have true boolean or time-only fields
|
1591
|
+
unless current_adapter?(:OracleAdapter, :DB2Adapter)
|
1592
|
+
assert_equal "false", xml.elements["//approved"].text
|
1593
|
+
assert_equal "boolean" , xml.elements["//approved"].attributes['type']
|
1594
|
+
|
1595
|
+
assert_equal bonus_time_in_current_timezone, xml.elements["//bonus-time"].text
|
1596
|
+
assert_equal "datetime" , xml.elements["//bonus-time"].attributes['type']
|
1597
|
+
end
|
1598
|
+
end
|
1599
|
+
|
1600
|
+
def test_to_xml_skipping_attributes
|
1601
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :replies_count])
|
1602
|
+
assert_equal "<topic>", xml.first(7)
|
1603
|
+
assert !xml.include?(%(<title>The First Topic</title>))
|
1604
|
+
assert xml.include?(%(<author-name>David</author-name>))
|
1605
|
+
|
1606
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :author_name, :replies_count])
|
1607
|
+
assert !xml.include?(%(<title>The First Topic</title>))
|
1608
|
+
assert !xml.include?(%(<author-name>David</author-name>))
|
1609
|
+
end
|
1610
|
+
|
1611
|
+
def test_to_xml_including_has_many_association
|
1612
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies, :except => :replies_count)
|
1613
|
+
assert_equal "<topic>", xml.first(7)
|
1614
|
+
assert xml.include?(%(<replies type="array"><reply>))
|
1615
|
+
assert xml.include?(%(<title>The Second Topic's of the day</title>))
|
1616
|
+
end
|
1617
|
+
|
1618
|
+
def test_array_to_xml_including_has_many_association
|
1619
|
+
xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :include => :replies)
|
1620
|
+
assert xml.include?(%(<replies type="array"><reply>))
|
1621
|
+
end
|
1622
|
+
|
1623
|
+
def test_array_to_xml_including_methods
|
1624
|
+
xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :methods => [ :topic_id ])
|
1625
|
+
assert xml.include?(%(<topic-id type="integer">#{topics(:first).topic_id}</topic-id>)), xml
|
1626
|
+
assert xml.include?(%(<topic-id type="integer">#{topics(:second).topic_id}</topic-id>)), xml
|
1627
|
+
end
|
1628
|
+
|
1629
|
+
def test_array_to_xml_including_has_one_association
|
1630
|
+
xml = [ companies(:first_firm), companies(:rails_core) ].to_xml(:indent => 0, :skip_instruct => true, :include => :account)
|
1631
|
+
assert xml.include?(companies(:first_firm).account.to_xml(:indent => 0, :skip_instruct => true))
|
1632
|
+
assert xml.include?(companies(:rails_core).account.to_xml(:indent => 0, :skip_instruct => true))
|
1633
|
+
end
|
1634
|
+
|
1635
|
+
def test_array_to_xml_including_belongs_to_association
|
1636
|
+
xml = [ companies(:first_client), companies(:second_client), companies(:another_client) ].to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1637
|
+
assert xml.include?(companies(:first_client).to_xml(:indent => 0, :skip_instruct => true))
|
1638
|
+
assert xml.include?(companies(:second_client).firm.to_xml(:indent => 0, :skip_instruct => true))
|
1639
|
+
assert xml.include?(companies(:another_client).firm.to_xml(:indent => 0, :skip_instruct => true))
|
1640
|
+
end
|
1641
|
+
|
1642
|
+
def test_to_xml_including_belongs_to_association
|
1643
|
+
xml = companies(:first_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1644
|
+
assert !xml.include?("<firm>")
|
1645
|
+
|
1646
|
+
xml = companies(:second_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1647
|
+
assert xml.include?("<firm>")
|
1648
|
+
end
|
1649
|
+
|
1650
|
+
def test_to_xml_including_multiple_associations
|
1651
|
+
xml = companies(:first_firm).to_xml(:indent => 0, :skip_instruct => true, :include => [ :clients, :account ])
|
1652
|
+
assert_equal "<firm>", xml.first(6)
|
1653
|
+
assert xml.include?(%(<account>))
|
1654
|
+
assert xml.include?(%(<clients type="array"><client>))
|
1655
|
+
end
|
1656
|
+
|
1657
|
+
def test_to_xml_including_multiple_associations_with_options
|
1658
|
+
xml = companies(:first_firm).to_xml(
|
1659
|
+
:indent => 0, :skip_instruct => true,
|
1660
|
+
:include => { :clients => { :only => :name } }
|
1661
|
+
)
|
1662
|
+
|
1663
|
+
assert_equal "<firm>", xml.first(6)
|
1664
|
+
assert xml.include?(%(<client><name>Summit</name></client>))
|
1665
|
+
assert xml.include?(%(<clients type="array"><client>))
|
1666
|
+
end
|
1667
|
+
|
1668
|
+
def test_to_xml_including_methods
|
1669
|
+
xml = Company.new.to_xml(:methods => :arbitrary_method, :skip_instruct => true)
|
1670
|
+
assert_equal "<company>", xml.first(9)
|
1671
|
+
assert xml.include?(%(<arbitrary-method>I am Jack's profound disappointment</arbitrary-method>))
|
1672
|
+
end
|
1673
|
+
|
1674
|
+
def test_to_xml_with_block
|
1675
|
+
value = "Rockin' the block"
|
1676
|
+
xml = Company.new.to_xml(:skip_instruct => true) do |xml|
|
1677
|
+
xml.tag! "arbitrary-element", value
|
1678
|
+
end
|
1679
|
+
assert_equal "<company>", xml.first(9)
|
1680
|
+
assert xml.include?(%(<arbitrary-element>#{value}</arbitrary-element>))
|
1681
|
+
end
|
1682
|
+
|
1683
|
+
def test_except_attributes
|
1684
|
+
assert_equal(
|
1685
|
+
%w( author_name type id approved replies_count bonus_time written_on content author_email_address parent_id last_read),
|
1686
|
+
topics(:first).attributes(:except => :title).keys
|
1687
|
+
)
|
1688
|
+
|
1689
|
+
assert_equal(
|
1690
|
+
%w( replies_count bonus_time written_on content author_email_address parent_id last_read),
|
1691
|
+
topics(:first).attributes(:except => [ :title, :id, :type, :approved, :author_name ]).keys
|
1692
|
+
)
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
def test_include_attributes
|
1696
|
+
assert_equal(%w( title ), topics(:first).attributes(:only => :title).keys)
|
1697
|
+
assert_equal(%w( title author_name type id approved ), topics(:first).attributes(:only => [ :title, :id, :type, :approved, :author_name ]).keys)
|
1698
|
+
end
|
1699
|
+
|
1700
|
+
def test_type_name_with_module_should_handle_beginning
|
1701
|
+
assert_equal 'ActiveRecord::Person', ActiveRecord::Base.send(:type_name_with_module, 'Person')
|
1702
|
+
assert_equal '::Person', ActiveRecord::Base.send(:type_name_with_module, '::Person')
|
1703
|
+
end
|
1704
|
+
|
1705
|
+
def test_to_param_should_return_string
|
1706
|
+
assert_kind_of String, Client.find(:first).to_param
|
1707
|
+
end
|
1708
|
+
|
1709
|
+
def test_inspect_class
|
1710
|
+
assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect
|
1711
|
+
assert_equal 'LoosePerson(abstract)', LoosePerson.inspect
|
1712
|
+
assert_match(/^Topic\(id: integer, title: string/, Topic.inspect)
|
1713
|
+
end
|
1714
|
+
|
1715
|
+
def test_inspect_instance
|
1716
|
+
topic = topics(:first)
|
1717
|
+
assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, type: nil>), topic.inspect
|
1718
|
+
end
|
1719
|
+
|
1720
|
+
def test_inspect_new_instance
|
1721
|
+
assert_match /Topic id: nil/, Topic.new.inspect
|
1722
|
+
end
|
1723
|
+
|
1724
|
+
def test_inspect_limited_select_instance
|
1725
|
+
assert_equal %(#<Topic id: 1>), Topic.find(:first, :select => 'id', :conditions => 'id = 1').inspect
|
1726
|
+
assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.find(:first, :select => 'id, title', :conditions => 'id = 1').inspect
|
1727
|
+
end
|
1728
|
+
|
1729
|
+
def test_inspect_class_without_table
|
1730
|
+
assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect
|
1731
|
+
end
|
1732
|
+
|
1733
|
+
def test_attribute_for_inspect
|
1734
|
+
t = topics(:first)
|
1735
|
+
t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
|
1736
|
+
|
1737
|
+
assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
|
1738
|
+
assert_equal '"The First Topic Now Has A Title With\nNewlines And M..."', t.attribute_for_inspect(:title)
|
1739
|
+
end
|
1740
|
+
|
1741
|
+
def test_becomes
|
1742
|
+
assert_kind_of Reply, topics(:first).becomes(Reply)
|
1743
|
+
assert_equal "The First Topic", topics(:first).becomes(Reply).title
|
1744
|
+
end
|
1745
|
+
end
|