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/validations_test.rb
CHANGED
@@ -1,28 +1,80 @@
|
|
1
1
|
require 'abstract_unit'
|
2
2
|
require 'fixtures/topic'
|
3
3
|
require 'fixtures/reply'
|
4
|
+
require 'fixtures/person'
|
4
5
|
require 'fixtures/developer'
|
5
6
|
|
7
|
+
# The following methods in Topic are used in test_conditional_validation_*
|
8
|
+
class Topic
|
9
|
+
def condition_is_true
|
10
|
+
return true
|
11
|
+
end
|
12
|
+
|
13
|
+
def condition_is_true_but_its_not
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ProtectedPerson < ActiveRecord::Base
|
19
|
+
set_table_name 'people'
|
20
|
+
attr_accessor :addon
|
21
|
+
attr_protected :first_name
|
22
|
+
end
|
23
|
+
|
24
|
+
class UniqueReply < Reply
|
25
|
+
validates_uniqueness_of :content, :scope => 'parent_id'
|
26
|
+
end
|
27
|
+
|
28
|
+
class PlagiarizedReply < Reply
|
29
|
+
validates_acceptance_of :author_name
|
30
|
+
end
|
31
|
+
|
32
|
+
class SillyUniqueReply < UniqueReply
|
33
|
+
end
|
34
|
+
|
35
|
+
class Topic < ActiveRecord::Base
|
36
|
+
has_many :unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
|
37
|
+
has_many :silly_unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
|
38
|
+
end
|
39
|
+
|
40
|
+
class Wizard < ActiveRecord::Base
|
41
|
+
self.abstract_class = true
|
42
|
+
|
43
|
+
validates_uniqueness_of :name
|
44
|
+
end
|
45
|
+
|
46
|
+
class IneptWizard < Wizard
|
47
|
+
validates_uniqueness_of :city
|
48
|
+
end
|
49
|
+
|
50
|
+
class Conjurer < IneptWizard
|
51
|
+
end
|
52
|
+
|
53
|
+
class Thaumaturgist < IneptWizard
|
54
|
+
end
|
6
55
|
|
7
56
|
class ValidationsTest < Test::Unit::TestCase
|
57
|
+
fixtures :topics, :developers
|
58
|
+
|
8
59
|
def setup
|
9
|
-
|
10
|
-
|
60
|
+
Topic.write_inheritable_attribute(:validate, nil)
|
61
|
+
Topic.write_inheritable_attribute(:validate_on_create, nil)
|
62
|
+
Topic.write_inheritable_attribute(:validate_on_update, nil)
|
11
63
|
end
|
12
64
|
|
13
65
|
def test_single_field_validation
|
14
66
|
r = Reply.new
|
15
67
|
r.title = "There's no content!"
|
16
|
-
assert !r.
|
68
|
+
assert !r.valid?, "A reply without content shouldn't be saveable"
|
17
69
|
|
18
70
|
r.content = "Messa content!"
|
19
|
-
assert r.
|
71
|
+
assert r.valid?, "A reply with content should be saveable"
|
20
72
|
end
|
21
|
-
|
73
|
+
|
22
74
|
def test_single_attr_validation_and_error_msg
|
23
75
|
r = Reply.new
|
24
76
|
r.title = "There's no content!"
|
25
|
-
r.
|
77
|
+
assert !r.valid?
|
26
78
|
assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
|
27
79
|
assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
|
28
80
|
assert_equal 1, r.errors.count
|
@@ -30,7 +82,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
30
82
|
|
31
83
|
def test_double_attr_validation_and_error_msg
|
32
84
|
r = Reply.new
|
33
|
-
assert !r.
|
85
|
+
assert !r.valid?
|
34
86
|
|
35
87
|
assert r.errors.invalid?("title"), "A reply without title should mark that attribute as invalid"
|
36
88
|
assert_equal "Empty", r.errors.on("title"), "A reply without title should contain an error"
|
@@ -40,66 +92,107 @@ class ValidationsTest < Test::Unit::TestCase
|
|
40
92
|
|
41
93
|
assert_equal 2, r.errors.count
|
42
94
|
end
|
43
|
-
|
95
|
+
|
44
96
|
def test_error_on_create
|
45
97
|
r = Reply.new
|
46
98
|
r.title = "Wrong Create"
|
47
|
-
assert !r.
|
99
|
+
assert !r.valid?
|
48
100
|
assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
|
49
101
|
assert_equal "is Wrong Create", r.errors.on("title"), "A reply with a bad content should contain an error"
|
50
102
|
end
|
51
103
|
|
52
|
-
|
53
104
|
def test_error_on_update
|
54
105
|
r = Reply.new
|
55
106
|
r.title = "Bad"
|
56
107
|
r.content = "Good"
|
57
|
-
|
58
108
|
assert r.save, "First save should be successful"
|
59
|
-
|
109
|
+
|
60
110
|
r.title = "Wrong Update"
|
61
111
|
assert !r.save, "Second save should fail"
|
62
|
-
|
112
|
+
|
63
113
|
assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
|
64
114
|
assert_equal "is Wrong Update", r.errors.on("title"), "A reply with a bad content should contain an error"
|
65
115
|
end
|
66
|
-
|
116
|
+
|
117
|
+
def test_invalid_record_exception
|
118
|
+
assert_raises(ActiveRecord::RecordInvalid) { Reply.create! }
|
119
|
+
assert_raises(ActiveRecord::RecordInvalid) { Reply.new.save! }
|
120
|
+
|
121
|
+
begin
|
122
|
+
r = Reply.new
|
123
|
+
r.save!
|
124
|
+
flunk
|
125
|
+
rescue ActiveRecord::RecordInvalid => invalid
|
126
|
+
assert_equal r, invalid.record
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_exception_on_create_bang_many
|
131
|
+
assert_raises(ActiveRecord::RecordInvalid) do
|
132
|
+
Reply.create!([ { "title" => "OK" }, { "title" => "Wrong Create" }])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_scoped_create_without_attributes
|
137
|
+
Reply.with_scope(:create => {}) do
|
138
|
+
assert_raises(ActiveRecord::RecordInvalid) { Reply.create! }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_create_with_exceptions_using_scope_for_protected_attributes
|
143
|
+
assert_nothing_raised do
|
144
|
+
ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
|
145
|
+
person = ProtectedPerson.create! :addon => "Addon"
|
146
|
+
assert_equal person.first_name, "Mary", "scope should ignore attr_protected"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_create_with_exceptions_using_scope_and_empty_attributes
|
152
|
+
assert_nothing_raised do
|
153
|
+
ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
|
154
|
+
person = ProtectedPerson.create!
|
155
|
+
assert_equal person.first_name, "Mary", "should be ok when no attributes are passed to create!"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
67
160
|
def test_single_error_per_attr_iteration
|
68
161
|
r = Reply.new
|
69
162
|
r.save
|
70
|
-
|
163
|
+
|
71
164
|
errors = []
|
72
165
|
r.errors.each { |attr, msg| errors << [attr, msg] }
|
73
|
-
|
166
|
+
|
74
167
|
assert errors.include?(["title", "Empty"])
|
75
168
|
assert errors.include?(["content", "Empty"])
|
76
169
|
end
|
77
|
-
|
170
|
+
|
78
171
|
def test_multiple_errors_per_attr_iteration_with_full_error_composition
|
79
172
|
r = Reply.new
|
80
173
|
r.title = "Wrong Create"
|
81
174
|
r.content = "Mismatch"
|
82
175
|
r.save
|
83
|
-
|
176
|
+
|
84
177
|
errors = []
|
85
178
|
r.errors.each_full { |error| errors << error }
|
86
|
-
|
179
|
+
|
87
180
|
assert_equal "Title is Wrong Create", errors[0]
|
88
181
|
assert_equal "Title is Content Mismatch", errors[1]
|
89
182
|
assert_equal 2, r.errors.count
|
90
183
|
end
|
91
|
-
|
184
|
+
|
92
185
|
def test_errors_on_base
|
93
186
|
r = Reply.new
|
94
187
|
r.content = "Mismatch"
|
95
188
|
r.save
|
96
189
|
r.errors.add_to_base "Reply is not dignifying"
|
97
|
-
|
190
|
+
|
98
191
|
errors = []
|
99
192
|
r.errors.each_full { |error| errors << error }
|
100
|
-
|
193
|
+
|
101
194
|
assert_equal "Reply is not dignifying", r.errors.on_base
|
102
|
-
|
195
|
+
|
103
196
|
assert errors.include?("Title Empty")
|
104
197
|
assert errors.include?("Reply is not dignifying")
|
105
198
|
assert_equal 2, r.errors.count
|
@@ -110,17 +203,1185 @@ class ValidationsTest < Test::Unit::TestCase
|
|
110
203
|
assert !reply.save
|
111
204
|
assert reply.save(false)
|
112
205
|
end
|
206
|
+
|
207
|
+
def test_create_without_validation_bang
|
208
|
+
count = Reply.count
|
209
|
+
assert_nothing_raised { Reply.new.save_without_validation! }
|
210
|
+
assert count+1, Reply.count
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_validates_each
|
214
|
+
perform = true
|
215
|
+
hits = 0
|
216
|
+
Topic.validates_each(:title, :content, [:title, :content]) do |record, attr|
|
217
|
+
if perform
|
218
|
+
record.errors.add attr, 'gotcha'
|
219
|
+
hits += 1
|
220
|
+
end
|
221
|
+
end
|
222
|
+
t = Topic.new("title" => "valid", "content" => "whatever")
|
223
|
+
assert !t.save
|
224
|
+
assert_equal 4, hits
|
225
|
+
assert_equal %w(gotcha gotcha), t.errors.on(:title)
|
226
|
+
assert_equal %w(gotcha gotcha), t.errors.on(:content)
|
227
|
+
ensure
|
228
|
+
perform = false
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_no_title_confirmation
|
232
|
+
Topic.validates_confirmation_of(:title)
|
233
|
+
|
234
|
+
t = Topic.new(:author_name => "Plutarch")
|
235
|
+
assert t.valid?
|
236
|
+
|
237
|
+
t.title_confirmation = "Parallel Lives"
|
238
|
+
assert !t.valid?
|
239
|
+
|
240
|
+
t.title_confirmation = nil
|
241
|
+
t.title = "Parallel Lives"
|
242
|
+
assert t.valid?
|
243
|
+
|
244
|
+
t.title_confirmation = "Parallel Lives"
|
245
|
+
assert t.valid?
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_title_confirmation
|
249
|
+
Topic.validates_confirmation_of(:title)
|
250
|
+
|
251
|
+
t = Topic.create("title" => "We should be confirmed","title_confirmation" => "")
|
252
|
+
assert !t.save
|
253
|
+
|
254
|
+
t.title_confirmation = "We should be confirmed"
|
255
|
+
assert t.save
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_terms_of_service_agreement_no_acceptance
|
259
|
+
Topic.validates_acceptance_of(:terms_of_service, :on => :create)
|
260
|
+
|
261
|
+
t = Topic.create("title" => "We should not be confirmed")
|
262
|
+
assert t.save
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_terms_of_service_agreement
|
266
|
+
Topic.validates_acceptance_of(:terms_of_service, :on => :create)
|
267
|
+
|
268
|
+
t = Topic.create("title" => "We should be confirmed","terms_of_service" => "")
|
269
|
+
assert !t.save
|
270
|
+
assert_equal "must be accepted", t.errors.on(:terms_of_service)
|
271
|
+
|
272
|
+
t.terms_of_service = "1"
|
273
|
+
assert t.save
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
def test_eula
|
278
|
+
Topic.validates_acceptance_of(:eula, :message => "must be abided", :on => :create)
|
279
|
+
|
280
|
+
t = Topic.create("title" => "We should be confirmed","eula" => "")
|
281
|
+
assert !t.save
|
282
|
+
assert_equal "must be abided", t.errors.on(:eula)
|
283
|
+
|
284
|
+
t.eula = "1"
|
285
|
+
assert t.save
|
286
|
+
end
|
287
|
+
|
288
|
+
def test_terms_of_service_agreement_with_accept_value
|
289
|
+
Topic.validates_acceptance_of(:terms_of_service, :on => :create, :accept => "I agree.")
|
290
|
+
|
291
|
+
t = Topic.create("title" => "We should be confirmed", "terms_of_service" => "")
|
292
|
+
assert !t.save
|
293
|
+
assert_equal "must be accepted", t.errors.on(:terms_of_service)
|
294
|
+
|
295
|
+
t.terms_of_service = "I agree."
|
296
|
+
assert t.save
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_validates_acceptance_of_as_database_column
|
300
|
+
reply = PlagiarizedReply.create("author_name" => "Dan Brown")
|
301
|
+
assert_equal "Dan Brown", reply["author_name"]
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_validate_presences
|
305
|
+
Topic.validates_presence_of(:title, :content)
|
306
|
+
|
307
|
+
t = Topic.create
|
308
|
+
assert !t.save
|
309
|
+
assert_equal "can't be blank", t.errors.on(:title)
|
310
|
+
assert_equal "can't be blank", t.errors.on(:content)
|
311
|
+
|
312
|
+
t.title = "something"
|
313
|
+
t.content = " "
|
314
|
+
|
315
|
+
assert !t.save
|
316
|
+
assert_equal "can't be blank", t.errors.on(:content)
|
317
|
+
|
318
|
+
t.content = "like stuff"
|
319
|
+
|
320
|
+
assert t.save
|
321
|
+
end
|
322
|
+
|
323
|
+
def test_validate_uniqueness
|
324
|
+
Topic.validates_uniqueness_of(:title)
|
325
|
+
|
326
|
+
t = Topic.new("title" => "I'm unique!")
|
327
|
+
assert t.save, "Should save t as unique"
|
328
|
+
|
329
|
+
t.content = "Remaining unique"
|
330
|
+
assert t.save, "Should still save t as unique"
|
331
|
+
|
332
|
+
t2 = Topic.new("title" => "I'm unique!")
|
333
|
+
assert !t2.valid?, "Shouldn't be valid"
|
334
|
+
assert !t2.save, "Shouldn't save t2 as unique"
|
335
|
+
assert_equal "has already been taken", t2.errors.on(:title)
|
336
|
+
|
337
|
+
t2.title = "Now Im really also unique"
|
338
|
+
assert t2.save, "Should now save t2 as unique"
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_validate_uniqueness_with_scope
|
342
|
+
Reply.validates_uniqueness_of(:content, :scope => "parent_id")
|
343
|
+
|
344
|
+
t = Topic.create("title" => "I'm unique!")
|
345
|
+
|
346
|
+
r1 = t.replies.create "title" => "r1", "content" => "hello world"
|
347
|
+
assert r1.valid?, "Saving r1"
|
348
|
+
|
349
|
+
r2 = t.replies.create "title" => "r2", "content" => "hello world"
|
350
|
+
assert !r2.valid?, "Saving r2 first time"
|
351
|
+
|
352
|
+
r2.content = "something else"
|
353
|
+
assert r2.save, "Saving r2 second time"
|
354
|
+
|
355
|
+
t2 = Topic.create("title" => "I'm unique too!")
|
356
|
+
r3 = t2.replies.create "title" => "r3", "content" => "hello world"
|
357
|
+
assert r3.valid?, "Saving r3"
|
358
|
+
end
|
359
|
+
|
360
|
+
def test_validate_uniqueness_scoped_to_defining_class
|
361
|
+
t = Topic.create("title" => "What, me worry?")
|
362
|
+
|
363
|
+
r1 = t.unique_replies.create "title" => "r1", "content" => "a barrel of fun"
|
364
|
+
assert r1.valid?, "Saving r1"
|
365
|
+
|
366
|
+
r2 = t.silly_unique_replies.create "title" => "r2", "content" => "a barrel of fun"
|
367
|
+
assert !r2.valid?, "Saving r2"
|
368
|
+
|
369
|
+
# Should succeed as validates_uniqueness_of only applies to
|
370
|
+
# UniqueReply and its subclasses
|
371
|
+
r3 = t.replies.create "title" => "r2", "content" => "a barrel of fun"
|
372
|
+
assert r3.valid?, "Saving r3"
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_validate_uniqueness_with_scope_array
|
376
|
+
Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
|
377
|
+
|
378
|
+
t = Topic.create("title" => "The earth is actually flat!")
|
379
|
+
|
380
|
+
r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
|
381
|
+
assert r1.valid?, "Saving r1"
|
382
|
+
|
383
|
+
r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
|
384
|
+
assert !r2.valid?, "Saving r2. Double reply by same author."
|
385
|
+
|
386
|
+
r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
|
387
|
+
assert r2.save, "Saving r2 the second time."
|
388
|
+
|
389
|
+
r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
|
390
|
+
assert !r3.valid?, "Saving r3"
|
391
|
+
|
392
|
+
r3.author_name = "jj"
|
393
|
+
assert r3.save, "Saving r3 the second time."
|
394
|
+
|
395
|
+
r3.author_name = "jeremy"
|
396
|
+
assert !r3.save, "Saving r3 the third time."
|
397
|
+
end
|
398
|
+
|
399
|
+
def test_validate_case_insensitive_uniqueness
|
400
|
+
Topic.validates_uniqueness_of(:title, :parent_id, :case_sensitive => false, :allow_nil => true)
|
401
|
+
|
402
|
+
t = Topic.new("title" => "I'm unique!", :parent_id => 2)
|
403
|
+
assert t.save, "Should save t as unique"
|
404
|
+
|
405
|
+
t.content = "Remaining unique"
|
406
|
+
assert t.save, "Should still save t as unique"
|
407
|
+
|
408
|
+
t2 = Topic.new("title" => "I'm UNIQUE!", :parent_id => 1)
|
409
|
+
assert !t2.valid?, "Shouldn't be valid"
|
410
|
+
assert !t2.save, "Shouldn't save t2 as unique"
|
411
|
+
assert t2.errors.on(:title)
|
412
|
+
assert t2.errors.on(:parent_id)
|
413
|
+
assert_equal "has already been taken", t2.errors.on(:title)
|
414
|
+
|
415
|
+
t2.title = "I'm truly UNIQUE!"
|
416
|
+
assert !t2.valid?, "Shouldn't be valid"
|
417
|
+
assert !t2.save, "Shouldn't save t2 as unique"
|
418
|
+
assert_nil t2.errors.on(:title)
|
419
|
+
assert t2.errors.on(:parent_id)
|
420
|
+
|
421
|
+
t2.parent_id = 3
|
422
|
+
assert t2.save, "Should now save t2 as unique"
|
423
|
+
|
424
|
+
t2.parent_id = nil
|
425
|
+
t2.title = nil
|
426
|
+
assert t2.valid?, "should validate with nil"
|
427
|
+
assert t2.save, "should save with nil"
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_validate_straight_inheritance_uniqueness
|
431
|
+
w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork")
|
432
|
+
assert w1.valid?, "Saving w1"
|
433
|
+
|
434
|
+
# Should use validation from base class (which is abstract)
|
435
|
+
w2 = IneptWizard.new(:name => "Rincewind", :city => "Quirm")
|
436
|
+
assert !w2.valid?, "w2 shouldn't be valid"
|
437
|
+
assert w2.errors.on(:name), "Should have errors for name"
|
438
|
+
assert_equal "has already been taken", w2.errors.on(:name), "Should have uniqueness message for name"
|
439
|
+
|
440
|
+
w3 = Conjurer.new(:name => "Rincewind", :city => "Quirm")
|
441
|
+
assert !w3.valid?, "w3 shouldn't be valid"
|
442
|
+
assert w3.errors.on(:name), "Should have errors for name"
|
443
|
+
assert_equal "has already been taken", w3.errors.on(:name), "Should have uniqueness message for name"
|
444
|
+
|
445
|
+
w4 = Conjurer.create(:name => "The Amazing Bonko", :city => "Quirm")
|
446
|
+
assert w4.valid?, "Saving w4"
|
447
|
+
|
448
|
+
w5 = Thaumaturgist.new(:name => "The Amazing Bonko", :city => "Lancre")
|
449
|
+
assert !w5.valid?, "w5 shouldn't be valid"
|
450
|
+
assert w5.errors.on(:name), "Should have errors for name"
|
451
|
+
assert_equal "has already been taken", w5.errors.on(:name), "Should have uniqueness message for name"
|
452
|
+
|
453
|
+
w6 = Thaumaturgist.new(:name => "Mustrum Ridcully", :city => "Quirm")
|
454
|
+
assert !w6.valid?, "w6 shouldn't be valid"
|
455
|
+
assert w6.errors.on(:city), "Should have errors for city"
|
456
|
+
assert_equal "has already been taken", w6.errors.on(:city), "Should have uniqueness message for city"
|
457
|
+
end
|
458
|
+
|
459
|
+
def test_validate_format
|
460
|
+
Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data")
|
461
|
+
|
462
|
+
t = Topic.create("title" => "i'm incorrect", "content" => "Validation macros rule!")
|
463
|
+
assert !t.valid?, "Shouldn't be valid"
|
464
|
+
assert !t.save, "Shouldn't save because it's invalid"
|
465
|
+
assert_equal "is bad data", t.errors.on(:title)
|
466
|
+
assert_nil t.errors.on(:content)
|
467
|
+
|
468
|
+
t.title = "Validation macros rule!"
|
469
|
+
|
470
|
+
assert t.save
|
471
|
+
assert_nil t.errors.on(:title)
|
472
|
+
|
473
|
+
assert_raise(ArgumentError) { Topic.validates_format_of(:title, :content) }
|
474
|
+
end
|
113
475
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
476
|
+
# testing ticket #3142
|
477
|
+
def test_validate_format_numeric
|
478
|
+
Topic.validates_format_of(:title, :content, :with => /^[1-9][0-9]*$/, :message => "is bad data")
|
479
|
+
|
480
|
+
t = Topic.create("title" => "72x", "content" => "6789")
|
481
|
+
assert !t.valid?, "Shouldn't be valid"
|
482
|
+
assert !t.save, "Shouldn't save because it's invalid"
|
483
|
+
assert_equal "is bad data", t.errors.on(:title)
|
484
|
+
assert_nil t.errors.on(:content)
|
485
|
+
|
486
|
+
t.title = "-11"
|
487
|
+
assert !t.valid?, "Shouldn't be valid"
|
488
|
+
|
489
|
+
t.title = "03"
|
490
|
+
assert !t.valid?, "Shouldn't be valid"
|
491
|
+
|
492
|
+
t.title = "z44"
|
493
|
+
assert !t.valid?, "Shouldn't be valid"
|
494
|
+
|
495
|
+
t.title = "5v7"
|
496
|
+
assert !t.valid?, "Shouldn't be valid"
|
497
|
+
|
498
|
+
t.title = "1"
|
499
|
+
|
500
|
+
assert t.save
|
501
|
+
assert_nil t.errors.on(:title)
|
502
|
+
end
|
503
|
+
|
504
|
+
def test_validates_inclusion_of
|
505
|
+
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) )
|
506
|
+
|
507
|
+
assert !Topic.create("title" => "a!", "content" => "abc").valid?
|
508
|
+
assert !Topic.create("title" => "a b", "content" => "abc").valid?
|
509
|
+
assert !Topic.create("title" => nil, "content" => "def").valid?
|
510
|
+
|
511
|
+
t = Topic.create("title" => "a", "content" => "I know you are but what am I?")
|
512
|
+
assert t.valid?
|
513
|
+
t.title = "uhoh"
|
514
|
+
assert !t.valid?
|
515
|
+
assert t.errors.on(:title)
|
516
|
+
assert_equal "is not included in the list", t.errors["title"]
|
517
|
+
|
518
|
+
assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => nil ) }
|
519
|
+
assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => 0) }
|
520
|
+
|
521
|
+
assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => "hi!" ) }
|
522
|
+
assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => {} ) }
|
523
|
+
assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => [] ) }
|
524
|
+
end
|
525
|
+
|
526
|
+
def test_validates_inclusion_of_with_allow_nil
|
527
|
+
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :allow_nil=>true )
|
528
|
+
|
529
|
+
assert !Topic.create("title" => "a!", "content" => "abc").valid?
|
530
|
+
assert !Topic.create("title" => "", "content" => "abc").valid?
|
531
|
+
assert Topic.create("title" => nil, "content" => "abc").valid?
|
532
|
+
end
|
533
|
+
|
534
|
+
def test_numericality_with_getter_method
|
535
|
+
Developer.validates_numericality_of( :salary )
|
536
|
+
developer = Developer.new("name" => "michael", "salary" => nil)
|
537
|
+
developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end")
|
538
|
+
assert developer.valid?
|
539
|
+
end
|
540
|
+
|
541
|
+
def test_validates_length_of_with_allow_nil
|
542
|
+
Topic.validates_length_of( :title, :is => 5, :allow_nil=>true )
|
543
|
+
|
544
|
+
assert !Topic.create("title" => "ab").valid?
|
545
|
+
assert !Topic.create("title" => "").valid?
|
546
|
+
assert Topic.create("title" => nil).valid?
|
547
|
+
assert Topic.create("title" => "abcde").valid?
|
548
|
+
end
|
549
|
+
|
550
|
+
def test_validates_length_of_with_allow_blank
|
551
|
+
Topic.validates_length_of( :title, :is => 5, :allow_blank=>true )
|
552
|
+
|
553
|
+
assert !Topic.create("title" => "ab").valid?
|
554
|
+
assert Topic.create("title" => "").valid?
|
555
|
+
assert Topic.create("title" => nil).valid?
|
556
|
+
assert Topic.create("title" => "abcde").valid?
|
557
|
+
end
|
558
|
+
|
559
|
+
def test_validates_inclusion_of_with_formatted_message
|
560
|
+
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %s is not in the list" )
|
561
|
+
|
562
|
+
assert Topic.create("title" => "a", "content" => "abc").valid?
|
563
|
+
|
564
|
+
t = Topic.create("title" => "uhoh", "content" => "abc")
|
565
|
+
assert !t.valid?
|
566
|
+
assert t.errors.on(:title)
|
567
|
+
assert_equal "option uhoh is not in the list", t.errors["title"]
|
568
|
+
end
|
569
|
+
|
570
|
+
def test_numericality_with_allow_nil_and_getter_method
|
571
|
+
Developer.validates_numericality_of( :salary, :allow_nil => true)
|
572
|
+
developer = Developer.new("name" => "michael", "salary" => nil)
|
573
|
+
developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end")
|
574
|
+
assert developer.valid?
|
575
|
+
end
|
576
|
+
|
577
|
+
def test_validates_exclusion_of
|
578
|
+
Topic.validates_exclusion_of( :title, :in => %w( abe monkey ) )
|
579
|
+
|
580
|
+
assert Topic.create("title" => "something", "content" => "abc").valid?
|
581
|
+
assert !Topic.create("title" => "monkey", "content" => "abc").valid?
|
582
|
+
end
|
583
|
+
|
584
|
+
def test_validates_exclusion_of_with_formatted_message
|
585
|
+
Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %s is restricted" )
|
586
|
+
|
587
|
+
assert Topic.create("title" => "something", "content" => "abc")
|
588
|
+
|
589
|
+
t = Topic.create("title" => "monkey")
|
590
|
+
assert !t.valid?
|
591
|
+
assert t.errors.on(:title)
|
592
|
+
assert_equal "option monkey is restricted", t.errors["title"]
|
593
|
+
end
|
594
|
+
|
595
|
+
def test_validates_length_of_using_minimum
|
596
|
+
Topic.validates_length_of :title, :minimum => 5
|
597
|
+
|
598
|
+
t = Topic.create("title" => "valid", "content" => "whatever")
|
599
|
+
assert t.valid?
|
600
|
+
|
601
|
+
t.title = "not"
|
602
|
+
assert !t.valid?
|
603
|
+
assert t.errors.on(:title)
|
604
|
+
assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
|
605
|
+
|
606
|
+
t.title = ""
|
607
|
+
assert !t.valid?
|
608
|
+
assert t.errors.on(:title)
|
609
|
+
assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
|
610
|
+
|
611
|
+
t.title = nil
|
612
|
+
assert !t.valid?
|
613
|
+
assert t.errors.on(:title)
|
614
|
+
assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
|
615
|
+
end
|
616
|
+
|
617
|
+
def test_optionally_validates_length_of_using_minimum
|
618
|
+
Topic.validates_length_of :title, :minimum => 5, :allow_nil => true
|
619
|
+
|
620
|
+
t = Topic.create("title" => "valid", "content" => "whatever")
|
621
|
+
assert t.valid?
|
622
|
+
|
623
|
+
t.title = nil
|
624
|
+
assert t.valid?
|
625
|
+
end
|
626
|
+
|
627
|
+
def test_validates_length_of_using_maximum
|
628
|
+
Topic.validates_length_of :title, :maximum => 5
|
629
|
+
|
630
|
+
t = Topic.create("title" => "valid", "content" => "whatever")
|
631
|
+
assert t.valid?
|
632
|
+
|
633
|
+
t.title = "notvalid"
|
634
|
+
assert !t.valid?
|
635
|
+
assert t.errors.on(:title)
|
636
|
+
assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
|
637
|
+
|
638
|
+
t.title = ""
|
639
|
+
assert t.valid?
|
640
|
+
|
641
|
+
t.title = nil
|
642
|
+
assert !t.valid?
|
643
|
+
end
|
644
|
+
|
645
|
+
def test_optionally_validates_length_of_using_maximum
|
646
|
+
Topic.validates_length_of :title, :maximum => 5, :allow_nil => true
|
647
|
+
|
648
|
+
t = Topic.create("title" => "valid", "content" => "whatever")
|
649
|
+
assert t.valid?
|
650
|
+
|
651
|
+
t.title = nil
|
652
|
+
assert t.valid?
|
653
|
+
end
|
654
|
+
|
655
|
+
def test_validates_length_of_using_within
|
656
|
+
Topic.validates_length_of(:title, :content, :within => 3..5)
|
657
|
+
|
658
|
+
t = Topic.new("title" => "a!", "content" => "I'm ooooooooh so very long")
|
659
|
+
assert !t.valid?
|
660
|
+
assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
|
661
|
+
assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
|
662
|
+
|
663
|
+
t.title = nil
|
664
|
+
t.content = nil
|
665
|
+
assert !t.valid?
|
666
|
+
assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
|
667
|
+
assert_equal "is too short (minimum is 3 characters)", t.errors.on(:content)
|
668
|
+
|
669
|
+
t.title = "abe"
|
670
|
+
t.content = "mad"
|
671
|
+
assert t.valid?
|
672
|
+
end
|
673
|
+
|
674
|
+
def test_optionally_validates_length_of_using_within
|
675
|
+
Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true
|
676
|
+
|
677
|
+
t = Topic.create('title' => 'abc', 'content' => 'abcd')
|
678
|
+
assert t.valid?
|
679
|
+
|
680
|
+
t.title = nil
|
681
|
+
assert t.valid?
|
682
|
+
end
|
683
|
+
|
684
|
+
def test_optionally_validates_length_of_using_within_on_create
|
685
|
+
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %d"
|
686
|
+
|
687
|
+
t = Topic.create("title" => "thisisnotvalid", "content" => "whatever")
|
688
|
+
assert !t.save
|
689
|
+
assert t.errors.on(:title)
|
690
|
+
assert_equal "my string is too long: 10", t.errors[:title]
|
691
|
+
|
692
|
+
t.title = "butthisis"
|
693
|
+
assert t.save
|
694
|
+
|
695
|
+
t.title = "few"
|
696
|
+
assert t.save
|
697
|
+
|
698
|
+
t.content = "andthisislong"
|
699
|
+
assert t.save
|
700
|
+
|
701
|
+
t.content = t.title = "iamfine"
|
702
|
+
assert t.save
|
703
|
+
end
|
704
|
+
|
705
|
+
def test_optionally_validates_length_of_using_within_on_update
|
706
|
+
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %d"
|
707
|
+
|
708
|
+
t = Topic.create("title" => "vali", "content" => "whatever")
|
709
|
+
assert !t.save
|
710
|
+
assert t.errors.on(:title)
|
711
|
+
|
712
|
+
t.title = "not"
|
713
|
+
assert !t.save
|
714
|
+
assert t.errors.on(:title)
|
715
|
+
assert_equal "my string is too short: 5", t.errors[:title]
|
716
|
+
|
717
|
+
t.title = "valid"
|
718
|
+
t.content = "andthisistoolong"
|
719
|
+
assert !t.save
|
720
|
+
assert t.errors.on(:content)
|
721
|
+
|
722
|
+
t.content = "iamfine"
|
723
|
+
assert t.save
|
724
|
+
end
|
725
|
+
|
726
|
+
def test_validates_length_of_using_is
|
727
|
+
Topic.validates_length_of :title, :is => 5
|
728
|
+
|
729
|
+
t = Topic.create("title" => "valid", "content" => "whatever")
|
730
|
+
assert t.valid?
|
731
|
+
|
732
|
+
t.title = "notvalid"
|
733
|
+
assert !t.valid?
|
734
|
+
assert t.errors.on(:title)
|
735
|
+
assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
|
736
|
+
|
737
|
+
t.title = ""
|
738
|
+
assert !t.valid?
|
739
|
+
|
740
|
+
t.title = nil
|
741
|
+
assert !t.valid?
|
742
|
+
end
|
743
|
+
|
744
|
+
def test_optionally_validates_length_of_using_is
|
745
|
+
Topic.validates_length_of :title, :is => 5, :allow_nil => true
|
746
|
+
|
747
|
+
t = Topic.create("title" => "valid", "content" => "whatever")
|
748
|
+
assert t.valid?
|
749
|
+
|
750
|
+
t.title = nil
|
751
|
+
assert t.valid?
|
752
|
+
end
|
753
|
+
|
754
|
+
def test_validates_length_of_using_bignum
|
755
|
+
bigmin = 2 ** 30
|
756
|
+
bigmax = 2 ** 32
|
757
|
+
bigrange = bigmin...bigmax
|
758
|
+
assert_nothing_raised do
|
759
|
+
Topic.validates_length_of :title, :is => bigmin + 5
|
760
|
+
Topic.validates_length_of :title, :within => bigrange
|
761
|
+
Topic.validates_length_of :title, :in => bigrange
|
762
|
+
Topic.validates_length_of :title, :minimum => bigmin
|
763
|
+
Topic.validates_length_of :title, :maximum => bigmax
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
def test_validates_length_with_globally_modified_error_message
|
768
|
+
ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre %d'
|
769
|
+
Topic.validates_length_of :title, :minimum => 10
|
770
|
+
t = Topic.create(:title => 'too short')
|
771
|
+
assert !t.valid?
|
772
|
+
|
773
|
+
assert_equal 'tu est trops petit hombre 10', t.errors['title']
|
774
|
+
end
|
775
|
+
|
776
|
+
def test_validates_size_of_association
|
777
|
+
assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 }
|
778
|
+
t = Topic.new('title' => 'noreplies', 'content' => 'whatever')
|
779
|
+
assert !t.save
|
780
|
+
assert t.errors.on(:replies)
|
781
|
+
reply = t.replies.build('title' => 'areply', 'content' => 'whateveragain')
|
782
|
+
assert t.valid?
|
783
|
+
end
|
784
|
+
|
785
|
+
def test_validates_length_of_nasty_params
|
786
|
+
assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>6, :maximum=>9) }
|
787
|
+
assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :maximum=>9) }
|
788
|
+
assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :minimum=>9) }
|
789
|
+
assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :is=>9) }
|
790
|
+
assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>"a") }
|
791
|
+
assert_raise(ArgumentError) { Topic.validates_length_of(:title, :maximum=>"a") }
|
792
|
+
assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>"a") }
|
793
|
+
assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is=>"a") }
|
794
|
+
end
|
795
|
+
|
796
|
+
def test_validates_length_of_custom_errors_for_minimum_with_message
|
797
|
+
Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %d" )
|
798
|
+
t = Topic.create("title" => "uhoh", "content" => "whatever")
|
799
|
+
assert !t.valid?
|
800
|
+
assert t.errors.on(:title)
|
801
|
+
assert_equal "boo 5", t.errors["title"]
|
802
|
+
end
|
803
|
+
|
804
|
+
def test_validates_length_of_custom_errors_for_minimum_with_too_short
|
805
|
+
Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %d" )
|
806
|
+
t = Topic.create("title" => "uhoh", "content" => "whatever")
|
807
|
+
assert !t.valid?
|
808
|
+
assert t.errors.on(:title)
|
809
|
+
assert_equal "hoo 5", t.errors["title"]
|
810
|
+
end
|
811
|
+
|
812
|
+
def test_validates_length_of_custom_errors_for_maximum_with_message
|
813
|
+
Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %d" )
|
814
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
815
|
+
assert !t.valid?
|
816
|
+
assert t.errors.on(:title)
|
817
|
+
assert_equal "boo 5", t.errors["title"]
|
818
|
+
end
|
819
|
+
|
820
|
+
def test_validates_length_of_custom_errors_for_maximum_with_too_long
|
821
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d" )
|
822
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
823
|
+
assert !t.valid?
|
824
|
+
assert t.errors.on(:title)
|
825
|
+
assert_equal "hoo 5", t.errors["title"]
|
826
|
+
end
|
827
|
+
|
828
|
+
def test_validates_length_of_custom_errors_for_is_with_message
|
829
|
+
Topic.validates_length_of( :title, :is=>5, :message=>"boo %d" )
|
830
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
831
|
+
assert !t.valid?
|
832
|
+
assert t.errors.on(:title)
|
833
|
+
assert_equal "boo 5", t.errors["title"]
|
834
|
+
end
|
835
|
+
|
836
|
+
def test_validates_length_of_custom_errors_for_is_with_wrong_length
|
837
|
+
Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %d" )
|
838
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
839
|
+
assert !t.valid?
|
840
|
+
assert t.errors.on(:title)
|
841
|
+
assert_equal "hoo 5", t.errors["title"]
|
842
|
+
end
|
843
|
+
|
844
|
+
def kcode_scope(kcode)
|
845
|
+
orig_kcode = $KCODE
|
846
|
+
$KCODE = kcode
|
847
|
+
begin
|
848
|
+
yield
|
849
|
+
ensure
|
850
|
+
$KCODE = orig_kcode
|
851
|
+
end
|
852
|
+
end
|
853
|
+
|
854
|
+
def test_validates_length_of_using_minimum_utf8
|
855
|
+
kcode_scope('UTF8') do
|
856
|
+
Topic.validates_length_of :title, :minimum => 5
|
857
|
+
|
858
|
+
t = Topic.create("title" => "一二三四五", "content" => "whatever")
|
859
|
+
assert t.valid?
|
860
|
+
|
861
|
+
t.title = "一二三四"
|
862
|
+
assert !t.valid?
|
863
|
+
assert t.errors.on(:title)
|
864
|
+
assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
|
865
|
+
end
|
866
|
+
end
|
867
|
+
|
868
|
+
def test_validates_length_of_using_maximum_utf8
|
869
|
+
kcode_scope('UTF8') do
|
870
|
+
Topic.validates_length_of :title, :maximum => 5
|
871
|
+
|
872
|
+
t = Topic.create("title" => "一二三四五", "content" => "whatever")
|
873
|
+
assert t.valid?
|
874
|
+
|
875
|
+
t.title = "一二34五六"
|
876
|
+
assert !t.valid?
|
877
|
+
assert t.errors.on(:title)
|
878
|
+
assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
882
|
+
def test_validates_length_of_using_within_utf8
|
883
|
+
kcode_scope('UTF8') do
|
884
|
+
Topic.validates_length_of(:title, :content, :within => 3..5)
|
885
|
+
|
886
|
+
t = Topic.new("title" => "一二", "content" => "12三四五六七")
|
887
|
+
assert !t.valid?
|
888
|
+
assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
|
889
|
+
assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
|
890
|
+
t.title = "一二三"
|
891
|
+
t.content = "12三"
|
892
|
+
assert t.valid?
|
893
|
+
end
|
894
|
+
end
|
895
|
+
|
896
|
+
def test_optionally_validates_length_of_using_within_utf8
|
897
|
+
kcode_scope('UTF8') do
|
898
|
+
Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true
|
899
|
+
|
900
|
+
t = Topic.create('title' => '一二三', 'content' => '一二三四五')
|
901
|
+
assert t.valid?
|
902
|
+
|
903
|
+
t.title = nil
|
904
|
+
assert t.valid?
|
905
|
+
end
|
906
|
+
end
|
907
|
+
|
908
|
+
def test_optionally_validates_length_of_using_within_on_create_utf8
|
909
|
+
kcode_scope('UTF8') do
|
910
|
+
Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "長すぎます: %d"
|
911
|
+
|
912
|
+
t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
|
913
|
+
assert !t.save
|
914
|
+
assert t.errors.on(:title)
|
915
|
+
assert_equal "長すぎます: 10", t.errors[:title]
|
916
|
+
|
917
|
+
t.title = "一二三四五六七八九"
|
918
|
+
assert t.save
|
919
|
+
|
920
|
+
t.title = "一二3"
|
921
|
+
assert t.save
|
922
|
+
|
923
|
+
t.content = "一二三四五六七八九十"
|
924
|
+
assert t.save
|
925
|
+
|
926
|
+
t.content = t.title = "一二三四五六"
|
927
|
+
assert t.save
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
931
|
+
def test_optionally_validates_length_of_using_within_on_update_utf8
|
932
|
+
kcode_scope('UTF8') do
|
933
|
+
Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "短すぎます: %d"
|
934
|
+
|
935
|
+
t = Topic.create("title" => "一二三4", "content" => "whatever")
|
936
|
+
assert !t.save
|
937
|
+
assert t.errors.on(:title)
|
938
|
+
|
939
|
+
t.title = "1二三4"
|
940
|
+
assert !t.save
|
941
|
+
assert t.errors.on(:title)
|
942
|
+
assert_equal "短すぎます: 5", t.errors[:title]
|
943
|
+
|
944
|
+
t.title = "valid"
|
945
|
+
t.content = "一二三四五六七八九十A"
|
946
|
+
assert !t.save
|
947
|
+
assert t.errors.on(:content)
|
948
|
+
|
949
|
+
t.content = "一二345"
|
950
|
+
assert t.save
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
def test_validates_length_of_using_is_utf8
|
955
|
+
kcode_scope('UTF8') do
|
956
|
+
Topic.validates_length_of :title, :is => 5
|
957
|
+
|
958
|
+
t = Topic.create("title" => "一二345", "content" => "whatever")
|
959
|
+
assert t.valid?
|
960
|
+
|
961
|
+
t.title = "一二345六"
|
962
|
+
assert !t.valid?
|
963
|
+
assert t.errors.on(:title)
|
964
|
+
assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
|
965
|
+
end
|
966
|
+
end
|
967
|
+
|
968
|
+
def test_validates_size_of_association_utf8
|
969
|
+
kcode_scope('UTF8') do
|
970
|
+
assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 }
|
971
|
+
t = Topic.new('title' => 'あいうえお', 'content' => 'かきくけこ')
|
972
|
+
assert !t.save
|
973
|
+
assert t.errors.on(:replies)
|
974
|
+
t.replies.build('title' => 'あいうえお', 'content' => 'かきくけこ')
|
975
|
+
assert t.valid?
|
976
|
+
end
|
977
|
+
end
|
978
|
+
|
979
|
+
def test_validates_associated_many
|
980
|
+
Topic.validates_associated( :replies )
|
981
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
982
|
+
t.replies << [r = Reply.new("title" => "A reply"), r2 = Reply.new("title" => "Another reply", "content" => "non-empty"), r3 = Reply.new("title" => "Yet another reply"), r4 = Reply.new("title" => "The last reply", "content" => "non-empty")]
|
983
|
+
assert !t.valid?
|
984
|
+
assert t.errors.on(:replies)
|
985
|
+
assert_equal 1, r.errors.count # make sure all associated objects have been validated
|
986
|
+
assert_equal 0, r2.errors.count
|
987
|
+
assert_equal 1, r3.errors.count
|
988
|
+
assert_equal 0, r4.errors.count
|
989
|
+
r.content = r3.content = "non-empty"
|
990
|
+
assert t.valid?
|
991
|
+
end
|
992
|
+
|
993
|
+
def test_validates_associated_one
|
994
|
+
Reply.validates_associated( :topic )
|
995
|
+
Topic.validates_presence_of( :content )
|
996
|
+
r = Reply.new("title" => "A reply", "content" => "with content!")
|
997
|
+
r.topic = Topic.create("title" => "uhohuhoh")
|
998
|
+
assert !r.valid?
|
999
|
+
assert r.errors.on(:topic)
|
1000
|
+
r.topic.content = "non-empty"
|
1001
|
+
assert r.valid?
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
def test_validate_block
|
1005
|
+
Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
|
1006
|
+
t = Topic.create("title" => "Title", "content" => "whatever")
|
1007
|
+
assert !t.valid?
|
1008
|
+
assert t.errors.on(:title)
|
1009
|
+
assert_equal "will never be valid", t.errors["title"]
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
def test_invalid_validator
|
1013
|
+
Topic.validate 3
|
1014
|
+
assert_raise(ActiveRecord::ActiveRecordError) { t = Topic.create }
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def test_throw_away_typing
|
1018
|
+
d = Developer.new("name" => "David", "salary" => "100,000")
|
1019
|
+
assert !d.valid?
|
1020
|
+
assert_equal 100, d.salary
|
1021
|
+
assert_equal "100,000", d.salary_before_type_cast
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
def test_validates_acceptance_of_with_custom_error_using_quotes
|
1025
|
+
Developer.validates_acceptance_of :salary, :message=> "This string contains 'single' and \"double\" quotes"
|
1026
|
+
d = Developer.new
|
1027
|
+
d.salary = "0"
|
1028
|
+
assert !d.valid?
|
1029
|
+
assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:salary).last
|
1030
|
+
end
|
1031
|
+
|
1032
|
+
def test_validates_confirmation_of_with_custom_error_using_quotes
|
1033
|
+
Developer.validates_confirmation_of :name, :message=> "confirm 'single' and \"double\" quotes"
|
1034
|
+
d = Developer.new
|
1035
|
+
d.name = "John"
|
1036
|
+
d.name_confirmation = "Johnny"
|
1037
|
+
assert !d.valid?
|
1038
|
+
assert_equal "confirm 'single' and \"double\" quotes", d.errors.on(:name)
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def test_validates_format_of_with_custom_error_using_quotes
|
1042
|
+
Developer.validates_format_of :name, :with => /^(A-Z*)$/, :message=> "format 'single' and \"double\" quotes"
|
1043
|
+
d = Developer.new
|
1044
|
+
d.name = d.name_confirmation = "John 32"
|
1045
|
+
assert !d.valid?
|
1046
|
+
assert_equal "format 'single' and \"double\" quotes", d.errors.on(:name)
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
def test_validates_inclusion_of_with_custom_error_using_quotes
|
1050
|
+
Developer.validates_inclusion_of :salary, :in => 1000..80000, :message=> "This string contains 'single' and \"double\" quotes"
|
1051
|
+
d = Developer.new
|
1052
|
+
d.salary = "90,000"
|
1053
|
+
assert !d.valid?
|
1054
|
+
assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:salary).last
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def test_validates_length_of_with_custom_too_long_using_quotes
|
1058
|
+
Developer.validates_length_of :name, :maximum => 4, :too_long=> "This string contains 'single' and \"double\" quotes"
|
1059
|
+
d = Developer.new
|
1060
|
+
d.name = "Jeffrey"
|
1061
|
+
assert !d.valid?
|
1062
|
+
assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name).last
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
def test_validates_length_of_with_custom_too_short_using_quotes
|
1066
|
+
Developer.validates_length_of :name, :minimum => 4, :too_short=> "This string contains 'single' and \"double\" quotes"
|
1067
|
+
d = Developer.new
|
1068
|
+
d.name = "Joe"
|
1069
|
+
assert !d.valid?
|
1070
|
+
assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name).last
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
def test_validates_length_of_with_custom_message_using_quotes
|
1074
|
+
Developer.validates_length_of :name, :minimum => 4, :message=> "This string contains 'single' and \"double\" quotes"
|
1075
|
+
d = Developer.new
|
1076
|
+
d.name = "Joe"
|
1077
|
+
assert !d.valid?
|
1078
|
+
assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name).last
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
def test_validates_presence_of_with_custom_message_using_quotes
|
1082
|
+
Developer.validates_presence_of :non_existent, :message=> "This string contains 'single' and \"double\" quotes"
|
1083
|
+
d = Developer.new
|
1084
|
+
d.name = "Joe"
|
1085
|
+
assert !d.valid?
|
1086
|
+
assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:non_existent)
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
def test_validates_uniqueness_of_with_custom_message_using_quotes
|
1090
|
+
Developer.validates_uniqueness_of :name, :message=> "This string contains 'single' and \"double\" quotes"
|
1091
|
+
d = Developer.new
|
1092
|
+
d.name = "David"
|
1093
|
+
assert !d.valid?
|
1094
|
+
assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name).last
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
def test_validates_associated_with_custom_message_using_quotes
|
1098
|
+
Reply.validates_associated :topic, :message=> "This string contains 'single' and \"double\" quotes"
|
1099
|
+
Topic.validates_presence_of :content
|
1100
|
+
r = Reply.create("title" => "A reply", "content" => "with content!")
|
1101
|
+
r.topic = Topic.create("title" => "uhohuhoh")
|
1102
|
+
assert !r.valid?
|
1103
|
+
assert_equal "This string contains 'single' and \"double\" quotes", r.errors.on(:topic).last
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
def test_if_validation_using_method_true
|
1107
|
+
# When the method returns true
|
1108
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => :condition_is_true )
|
1109
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1110
|
+
assert !t.valid?
|
1111
|
+
assert t.errors.on(:title)
|
1112
|
+
assert_equal "hoo 5", t.errors["title"]
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
def test_unless_validation_using_method_true
|
1116
|
+
# When the method returns true
|
1117
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => :condition_is_true )
|
1118
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1119
|
+
assert t.valid?
|
1120
|
+
assert !t.errors.on(:title)
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
def test_if_validation_using_method_false
|
1124
|
+
# When the method returns false
|
1125
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => :condition_is_true_but_its_not )
|
1126
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1127
|
+
assert t.valid?
|
1128
|
+
assert !t.errors.on(:title)
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
def test_unless_validation_using_method_false
|
1132
|
+
# When the method returns false
|
1133
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => :condition_is_true_but_its_not )
|
1134
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1135
|
+
assert !t.valid?
|
1136
|
+
assert t.errors.on(:title)
|
1137
|
+
assert_equal "hoo 5", t.errors["title"]
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
def test_if_validation_using_string_true
|
1141
|
+
# When the evaluated string returns true
|
1142
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => "a = 1; a == 1" )
|
1143
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1144
|
+
assert !t.valid?
|
1145
|
+
assert t.errors.on(:title)
|
1146
|
+
assert_equal "hoo 5", t.errors["title"]
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
def test_unless_validation_using_string_true
|
1150
|
+
# When the evaluated string returns true
|
1151
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => "a = 1; a == 1" )
|
1152
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1153
|
+
assert t.valid?
|
1154
|
+
assert !t.errors.on(:title)
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
def test_if_validation_using_string_false
|
1158
|
+
# When the evaluated string returns false
|
1159
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => "false")
|
1160
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1161
|
+
assert t.valid?
|
1162
|
+
assert !t.errors.on(:title)
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
def test_unless_validation_using_string_false
|
1166
|
+
# When the evaluated string returns false
|
1167
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => "false")
|
1168
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1169
|
+
assert !t.valid?
|
1170
|
+
assert t.errors.on(:title)
|
1171
|
+
assert_equal "hoo 5", t.errors["title"]
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
def test_if_validation_using_block_true
|
1175
|
+
# When the block returns true
|
1176
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d",
|
1177
|
+
:if => Proc.new { |r| r.content.size > 4 } )
|
1178
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1179
|
+
assert !t.valid?
|
1180
|
+
assert t.errors.on(:title)
|
1181
|
+
assert_equal "hoo 5", t.errors["title"]
|
1182
|
+
end
|
1183
|
+
|
1184
|
+
def test_unless_validation_using_block_true
|
1185
|
+
# When the block returns true
|
1186
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d",
|
1187
|
+
:unless => Proc.new { |r| r.content.size > 4 } )
|
1188
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1189
|
+
assert t.valid?
|
1190
|
+
assert !t.errors.on(:title)
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
def test_if_validation_using_block_false
|
1194
|
+
# When the block returns false
|
1195
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d",
|
1196
|
+
:if => Proc.new { |r| r.title != "uhohuhoh"} )
|
1197
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1198
|
+
assert t.valid?
|
1199
|
+
assert !t.errors.on(:title)
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
def test_unless_validation_using_block_false
|
1203
|
+
# When the block returns false
|
1204
|
+
Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d",
|
1205
|
+
:unless => Proc.new { |r| r.title != "uhohuhoh"} )
|
1206
|
+
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
|
1207
|
+
assert !t.valid?
|
1208
|
+
assert t.errors.on(:title)
|
1209
|
+
assert_equal "hoo 5", t.errors["title"]
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
def test_validates_associated_missing
|
1213
|
+
Reply.validates_presence_of(:topic)
|
1214
|
+
r = Reply.create("title" => "A reply", "content" => "with content!")
|
1215
|
+
assert !r.valid?
|
1216
|
+
assert r.errors.on(:topic)
|
118
1217
|
|
119
|
-
|
120
|
-
assert
|
121
|
-
|
1218
|
+
r.topic = Topic.find :first
|
1219
|
+
assert r.valid?
|
1220
|
+
end
|
122
1221
|
|
123
|
-
|
124
|
-
|
1222
|
+
def test_errors_to_xml
|
1223
|
+
r = Reply.new :title => "Wrong Create"
|
1224
|
+
assert !r.valid?
|
1225
|
+
xml = r.errors.to_xml(:skip_instruct => true)
|
1226
|
+
assert_equal "<errors>", xml.first(8)
|
1227
|
+
assert xml.include?("<error>Title is Wrong Create</error>")
|
1228
|
+
assert xml.include?("<error>Content Empty</error>")
|
125
1229
|
end
|
1230
|
+
|
1231
|
+
def test_validation_order
|
1232
|
+
Topic.validates_presence_of :title
|
1233
|
+
Topic.validates_length_of :title, :minimum => 2
|
1234
|
+
|
1235
|
+
t = Topic.new("title" => "")
|
1236
|
+
assert !t.valid?
|
1237
|
+
assert_equal "can't be blank", t.errors.on("title").first
|
1238
|
+
end
|
1239
|
+
|
1240
|
+
# previous implementation of validates_presence_of eval'd the
|
1241
|
+
# string with the wrong binding, this regression test is to
|
1242
|
+
# ensure that it works correctly
|
1243
|
+
def test_validation_with_if_as_string
|
1244
|
+
Topic.validates_presence_of(:title)
|
1245
|
+
Topic.validates_presence_of(:author_name, :if => "title.to_s.match('important')")
|
1246
|
+
|
1247
|
+
t = Topic.new
|
1248
|
+
assert !t.valid?, "A topic without a title should not be valid"
|
1249
|
+
assert !t.errors.invalid?("author_name"), "A topic without an 'important' title should not require an author"
|
1250
|
+
|
1251
|
+
t.title = "Just a title"
|
1252
|
+
assert t.valid?, "A topic with a basic title should be valid"
|
1253
|
+
|
1254
|
+
t.title = "A very important title"
|
1255
|
+
assert !t.valid?, "A topic with an important title, but without an author, should not be valid"
|
1256
|
+
assert t.errors.invalid?("author_name"), "A topic with an 'important' title should require an author"
|
1257
|
+
|
1258
|
+
t.author_name = "Hubert J. Farnsworth"
|
1259
|
+
assert t.valid?, "A topic with an important title and author should be valid"
|
1260
|
+
end
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
|
1264
|
+
class ValidatesNumericalityTest < Test::Unit::TestCase
|
1265
|
+
NIL = [nil]
|
1266
|
+
BLANK = ["", " ", " \t \r \n"]
|
1267
|
+
BIGDECIMAL_STRINGS = %w(12345678901234567890.1234567890) # 30 significent digits
|
1268
|
+
FLOAT_STRINGS = %w(0.0 +0.0 -0.0 10.0 10.5 -10.5 -0.0001 -090.1 90.1e1 -90.1e5 -90.1e-5 90e-5)
|
1269
|
+
INTEGER_STRINGS = %w(0 +0 -0 10 +10 -10 0090 -090)
|
1270
|
+
FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS
|
1271
|
+
INTEGERS = [0, 10, -10] + INTEGER_STRINGS
|
1272
|
+
BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal.new(bd) }
|
1273
|
+
JUNK = ["not a number", "42 not a number", "0xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"]
|
1274
|
+
|
1275
|
+
def setup
|
1276
|
+
Topic.write_inheritable_attribute(:validate, nil)
|
1277
|
+
Topic.write_inheritable_attribute(:validate_on_create, nil)
|
1278
|
+
Topic.write_inheritable_attribute(:validate_on_update, nil)
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
def test_default_validates_numericality_of
|
1282
|
+
Topic.validates_numericality_of :approved
|
1283
|
+
|
1284
|
+
invalid!(NIL + BLANK + JUNK)
|
1285
|
+
valid!(FLOATS + INTEGERS + BIGDECIMAL)
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
def test_validates_numericality_of_with_nil_allowed
|
1289
|
+
Topic.validates_numericality_of :approved, :allow_nil => true
|
1290
|
+
|
1291
|
+
invalid!(BLANK + JUNK)
|
1292
|
+
valid!(NIL + FLOATS + INTEGERS + BIGDECIMAL)
|
1293
|
+
end
|
1294
|
+
|
1295
|
+
def test_validates_numericality_of_with_integer_only
|
1296
|
+
Topic.validates_numericality_of :approved, :only_integer => true
|
1297
|
+
|
1298
|
+
invalid!(NIL + BLANK + JUNK + FLOATS + BIGDECIMAL)
|
1299
|
+
valid!(INTEGERS)
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
def test_validates_numericality_of_with_integer_only_and_nil_allowed
|
1303
|
+
Topic.validates_numericality_of :approved, :only_integer => true, :allow_nil => true
|
1304
|
+
|
1305
|
+
invalid!(BLANK + JUNK + FLOATS + BIGDECIMAL)
|
1306
|
+
valid!(NIL + INTEGERS)
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
def test_validates_numericality_with_greater_than
|
1310
|
+
Topic.validates_numericality_of :approved, :greater_than => 10
|
1311
|
+
|
1312
|
+
invalid!([-10, 10], 'must be greater than 10')
|
1313
|
+
valid!([11])
|
1314
|
+
end
|
1315
|
+
|
1316
|
+
def test_validates_numericality_with_greater_than_or_equal
|
1317
|
+
Topic.validates_numericality_of :approved, :greater_than_or_equal_to => 10
|
1318
|
+
|
1319
|
+
invalid!([-9, 9], 'must be greater than or equal to 10')
|
1320
|
+
valid!([10])
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
def test_validates_numericality_with_equal_to
|
1324
|
+
Topic.validates_numericality_of :approved, :equal_to => 10
|
1325
|
+
|
1326
|
+
invalid!([-10, 11], 'must be equal to 10')
|
1327
|
+
valid!([10])
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
def test_validates_numericality_with_less_than
|
1331
|
+
Topic.validates_numericality_of :approved, :less_than => 10
|
1332
|
+
|
1333
|
+
invalid!([10], 'must be less than 10')
|
1334
|
+
valid!([-9, 9])
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
def test_validates_numericality_with_less_than_or_equal_to
|
1338
|
+
Topic.validates_numericality_of :approved, :less_than_or_equal_to => 10
|
1339
|
+
|
1340
|
+
invalid!([11], 'must be less than or equal to 10')
|
1341
|
+
valid!([-10, 10])
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
def test_validates_numericality_with_odd
|
1345
|
+
Topic.validates_numericality_of :approved, :odd => true
|
1346
|
+
|
1347
|
+
invalid!([-2, 2], 'must be odd')
|
1348
|
+
valid!([-1, 1])
|
1349
|
+
end
|
1350
|
+
|
1351
|
+
def test_validates_numericality_with_even
|
1352
|
+
Topic.validates_numericality_of :approved, :even => true
|
1353
|
+
|
1354
|
+
invalid!([-1, 1], 'must be even')
|
1355
|
+
valid!([-2, 2])
|
1356
|
+
end
|
1357
|
+
|
1358
|
+
def test_validates_numericality_with_greater_than_less_than_and_even
|
1359
|
+
Topic.validates_numericality_of :approved, :greater_than => 1, :less_than => 4, :even => true
|
1360
|
+
|
1361
|
+
invalid!([1, 3, 4])
|
1362
|
+
valid!([2])
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
private
|
1366
|
+
def invalid!(values, error=nil)
|
1367
|
+
with_each_topic_approved_value(values) do |topic, value|
|
1368
|
+
assert !topic.valid?, "#{value.inspect} not rejected as a number"
|
1369
|
+
assert topic.errors.on(:approved)
|
1370
|
+
assert_equal error, topic.errors.on(:approved) if error
|
1371
|
+
end
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
def valid!(values)
|
1375
|
+
with_each_topic_approved_value(values) do |topic, value|
|
1376
|
+
assert topic.valid?, "#{value.inspect} not accepted as a number"
|
1377
|
+
end
|
1378
|
+
end
|
1379
|
+
|
1380
|
+
def with_each_topic_approved_value(values)
|
1381
|
+
topic = Topic.new("title" => "numeric test", "content" => "whatever")
|
1382
|
+
values.each do |value|
|
1383
|
+
topic.approved = value
|
1384
|
+
yield topic, value
|
1385
|
+
end
|
1386
|
+
end
|
126
1387
|
end
|