activerecord 1.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 +581 -0
- data/README +361 -0
- data/RUNNING_UNIT_TESTS +36 -0
- data/dev-utils/eval_debugger.rb +9 -0
- data/examples/associations.png +0 -0
- data/examples/associations.rb +87 -0
- data/examples/shared_setup.rb +15 -0
- data/examples/validation.rb +88 -0
- data/install.rb +60 -0
- data/lib/active_record.rb +48 -0
- data/lib/active_record/aggregations.rb +165 -0
- data/lib/active_record/associations.rb +536 -0
- data/lib/active_record/associations/association_collection.rb +70 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -0
- data/lib/active_record/associations/has_many_association.rb +104 -0
- data/lib/active_record/base.rb +985 -0
- data/lib/active_record/callbacks.rb +337 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +326 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +131 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +177 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +107 -0
- data/lib/active_record/deprecated_associations.rb +70 -0
- data/lib/active_record/fixtures.rb +172 -0
- data/lib/active_record/observer.rb +71 -0
- data/lib/active_record/reflection.rb +126 -0
- data/lib/active_record/support/class_attribute_accessors.rb +43 -0
- data/lib/active_record/support/class_inheritable_attributes.rb +37 -0
- data/lib/active_record/support/clean_logger.rb +10 -0
- data/lib/active_record/support/inflector.rb +70 -0
- data/lib/active_record/transactions.rb +102 -0
- data/lib/active_record/validations.rb +205 -0
- data/lib/active_record/vendor/mysql.rb +1117 -0
- data/lib/active_record/vendor/simple.rb +702 -0
- data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
- data/lib/active_record/wrappings.rb +59 -0
- data/rakefile +122 -0
- data/test/abstract_unit.rb +16 -0
- data/test/aggregations_test.rb +34 -0
- data/test/all.sh +8 -0
- data/test/associations_test.rb +477 -0
- data/test/base_test.rb +513 -0
- data/test/class_inheritable_attributes_test.rb +33 -0
- data/test/connections/native_mysql/connection.rb +24 -0
- data/test/connections/native_postgresql/connection.rb +24 -0
- data/test/connections/native_sqlite/connection.rb +24 -0
- data/test/deprecated_associations_test.rb +336 -0
- data/test/finder_test.rb +67 -0
- data/test/fixtures/accounts/signals37 +3 -0
- data/test/fixtures/accounts/unknown +2 -0
- data/test/fixtures/auto_id.rb +4 -0
- data/test/fixtures/column_name.rb +3 -0
- data/test/fixtures/companies/first_client +6 -0
- data/test/fixtures/companies/first_firm +4 -0
- data/test/fixtures/companies/second_client +6 -0
- data/test/fixtures/company.rb +37 -0
- data/test/fixtures/company_in_module.rb +33 -0
- data/test/fixtures/course.rb +3 -0
- data/test/fixtures/courses/java +2 -0
- data/test/fixtures/courses/ruby +2 -0
- data/test/fixtures/customer.rb +30 -0
- data/test/fixtures/customers/david +6 -0
- data/test/fixtures/db_definitions/mysql.sql +96 -0
- data/test/fixtures/db_definitions/mysql2.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +113 -0
- data/test/fixtures/db_definitions/postgresql2.sql +4 -0
- data/test/fixtures/db_definitions/sqlite.sql +85 -0
- data/test/fixtures/db_definitions/sqlite2.sql +4 -0
- data/test/fixtures/default.rb +2 -0
- data/test/fixtures/developer.rb +8 -0
- data/test/fixtures/developers/david +2 -0
- data/test/fixtures/developers/jamis +2 -0
- data/test/fixtures/developers_projects/david_action_controller +2 -0
- data/test/fixtures/developers_projects/david_active_record +2 -0
- data/test/fixtures/developers_projects/jamis_active_record +2 -0
- data/test/fixtures/entrant.rb +3 -0
- data/test/fixtures/entrants/first +3 -0
- data/test/fixtures/entrants/second +3 -0
- data/test/fixtures/entrants/third +3 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/movie.rb +5 -0
- data/test/fixtures/movies/first +2 -0
- data/test/fixtures/movies/second +2 -0
- data/test/fixtures/project.rb +3 -0
- data/test/fixtures/projects/action_controller +2 -0
- data/test/fixtures/projects/active_record +2 -0
- data/test/fixtures/reply.rb +21 -0
- data/test/fixtures/subscriber.rb +5 -0
- data/test/fixtures/subscribers/first +2 -0
- data/test/fixtures/subscribers/second +2 -0
- data/test/fixtures/topic.rb +20 -0
- data/test/fixtures/topics/first +9 -0
- data/test/fixtures/topics/second +8 -0
- data/test/fixtures_test.rb +20 -0
- data/test/inflector_test.rb +104 -0
- data/test/inheritance_test.rb +125 -0
- data/test/lifecycle_test.rb +110 -0
- data/test/modules_test.rb +21 -0
- data/test/multiple_db_test.rb +46 -0
- data/test/pk_test.rb +57 -0
- data/test/reflection_test.rb +78 -0
- data/test/thread_safety_test.rb +33 -0
- data/test/transactions_test.rb +83 -0
- data/test/unconnected_test.rb +24 -0
- data/test/validations_test.rb +126 -0
- metadata +166 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
# require File.dirname(__FILE__) + '/../dev-utils/eval_debugger'
|
3
|
+
require 'fixtures/company_in_module'
|
4
|
+
|
5
|
+
class ModulesTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
create_fixtures "accounts"
|
8
|
+
create_fixtures "companies"
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_module_spanning_associations
|
12
|
+
assert MyApplication::Business::Firm.find_first.has_clients?, "Firm should have clients"
|
13
|
+
firm = MyApplication::Business::Firm.find_first
|
14
|
+
assert_nil firm.class.table_name.match('::'), "Firm shouldn't have the module appear in its table name"
|
15
|
+
assert_equal 2, firm.clients_count, "Firm should have two clients"
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_associations_spanning_cross_modules
|
19
|
+
assert MyApplication::Billing::Account.find(1).has_firm?, "37signals account should be able to backtrack"
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/course'
|
3
|
+
require 'fixtures/entrant'
|
4
|
+
|
5
|
+
class MultipleDbTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@courses = create_fixtures("courses") { Course.retrieve_connection }
|
8
|
+
@entrants = create_fixtures("entrants")
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_connected
|
12
|
+
assert_not_nil Entrant.connection
|
13
|
+
assert_not_nil Course.connection
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_proper_connection
|
17
|
+
assert_not_equal(Entrant.connection, Course.connection)
|
18
|
+
assert_equal(Entrant.connection, Entrant.retrieve_connection)
|
19
|
+
assert_equal(Course.connection, Course.retrieve_connection)
|
20
|
+
assert_equal(ActiveRecord::Base.connection, Entrant.connection)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_find
|
24
|
+
c1 = Course.find(1)
|
25
|
+
assert_equal "Ruby Development", c1.name
|
26
|
+
c2 = Course.find(2)
|
27
|
+
assert_equal "Java Development", c2.name
|
28
|
+
e1 = Entrant.find(1)
|
29
|
+
assert_equal "Ruby Developer", e1.name
|
30
|
+
e2 = Entrant.find(2)
|
31
|
+
assert_equal "Ruby Guru", e2.name
|
32
|
+
e3 = Entrant.find(3)
|
33
|
+
assert_equal "Java Lover", e3.name
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_associations
|
37
|
+
c1 = Course.find(1)
|
38
|
+
assert_equal 2, c1.entrants_count
|
39
|
+
e1 = Entrant.find(1)
|
40
|
+
assert_equal e1.course.id, c1.id
|
41
|
+
c2 = Course.find(2)
|
42
|
+
assert_equal 1, c2.entrants_count
|
43
|
+
e3 = Entrant.find(3)
|
44
|
+
assert_equal e3.course.id, c2.id
|
45
|
+
end
|
46
|
+
end
|
data/test/pk_test.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/topic'
|
3
|
+
require 'fixtures/subscriber'
|
4
|
+
require 'fixtures/movie'
|
5
|
+
|
6
|
+
class PrimaryKeysTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@topics = create_fixtures "topics"
|
9
|
+
@subscribers = create_fixtures "subscribers"
|
10
|
+
@movies = create_fixtures "movies"
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_integer_key
|
14
|
+
topic = Topic.find(1)
|
15
|
+
assert_equal(@topics["first"]["author_name"], topic.author_name)
|
16
|
+
topic = Topic.find(2)
|
17
|
+
assert_equal(@topics["second"]["author_name"], topic.author_name)
|
18
|
+
|
19
|
+
topic = Topic.new
|
20
|
+
topic.title = "New Topic"
|
21
|
+
topic.save
|
22
|
+
id = topic.id
|
23
|
+
|
24
|
+
topicReloaded = Topic.find(id)
|
25
|
+
assert_equal("New Topic", topicReloaded.title)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_string_key
|
29
|
+
subscriber = Subscriber.find(@subscribers["first"]["nick"])
|
30
|
+
assert_equal(@subscribers["first"]["name"], subscriber.name)
|
31
|
+
subscriber = Subscriber.find(@subscribers["second"]["nick"])
|
32
|
+
assert_equal(@subscribers["second"]["name"], subscriber.name)
|
33
|
+
|
34
|
+
subscriber = Subscriber.new
|
35
|
+
subscriber.id = "jdoe"
|
36
|
+
subscriber.name = "John Doe"
|
37
|
+
subscriber.save
|
38
|
+
|
39
|
+
subscriberReloaded = Subscriber.find("jdoe")
|
40
|
+
assert_equal("John Doe", subscriberReloaded.name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_find_with_more_than_one_string_key
|
44
|
+
assert_equal 2, Subscriber.find(@subscribers["first"]["nick"], @subscribers["second"]["nick"]).length
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_primary_key_prefix
|
48
|
+
ActiveRecord::Base.primary_key_prefix_type = :table_name
|
49
|
+
assert_equal "topicid", Topic.primary_key
|
50
|
+
|
51
|
+
ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
|
52
|
+
assert_equal "topic_id", Topic.primary_key
|
53
|
+
|
54
|
+
ActiveRecord::Base.primary_key_prefix_type = nil
|
55
|
+
assert_equal "id", Topic.primary_key
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#require File.dirname(__FILE__) + '/../dev-utils/eval_debugger'
|
2
|
+
require 'abstract_unit'
|
3
|
+
require 'fixtures/topic'
|
4
|
+
require 'fixtures/customer'
|
5
|
+
require 'fixtures/company'
|
6
|
+
require 'fixtures/company_in_module'
|
7
|
+
|
8
|
+
class ReflectionTest < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@topics = create_fixtures "topics"
|
11
|
+
@customers = create_fixtures "customers"
|
12
|
+
@companies = create_fixtures "companies"
|
13
|
+
@first = Topic.find(1)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_read_attribute_names
|
17
|
+
assert_equal(
|
18
|
+
%w( id title author_name author_email_address written_on last_read content approved replies_count parent_id type ).sort,
|
19
|
+
@first.attribute_names
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_columns
|
24
|
+
assert_equal 11, Topic.columns.length
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_content_columns
|
28
|
+
assert_equal 7, Topic.content_columns.length
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_column_string_type_and_limit
|
32
|
+
assert_equal :string, @first.column_for_attribute("title").type
|
33
|
+
assert_equal 255, @first.column_for_attribute("title").limit
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_human_name_for_column
|
37
|
+
assert_equal "Author name", @first.column_for_attribute("author_name").human_name
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_integer_columns
|
41
|
+
assert_equal :integer, @first.column_for_attribute("id").type
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_aggregation_reflection
|
45
|
+
reflection_for_address = ActiveRecord::Reflection::AggregateReflection.new(
|
46
|
+
:address, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer
|
47
|
+
)
|
48
|
+
|
49
|
+
reflection_for_balance = ActiveRecord::Reflection::AggregateReflection.new(
|
50
|
+
:balance, { :class_name => "Money", :mapping => %w(balance amount) }, Customer
|
51
|
+
)
|
52
|
+
|
53
|
+
assert_equal(
|
54
|
+
[ reflection_for_address, reflection_for_balance ],
|
55
|
+
Customer.reflect_on_all_aggregations
|
56
|
+
)
|
57
|
+
|
58
|
+
assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address)
|
59
|
+
|
60
|
+
assert_equal Address, Customer.reflect_on_aggregation(:address).klass
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_association_reflection
|
64
|
+
reflection_for_clients = ActiveRecord::Reflection::AssociationReflection.new(
|
65
|
+
:clients, { :order => "id", :dependent => true }, Firm
|
66
|
+
)
|
67
|
+
|
68
|
+
assert_equal reflection_for_clients, Firm.reflect_on_association(:clients)
|
69
|
+
|
70
|
+
assert_equal Client, Firm.reflect_on_association(:clients).klass
|
71
|
+
assert_equal Client, Firm.reflect_on_association(:clients_of_firm).klass
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_association_reflection_in_modules
|
75
|
+
assert_equal MyApplication::Business::Client, MyApplication::Business::Firm.reflect_on_association(:clients_of_firm).klass
|
76
|
+
assert_equal MyApplication::Business::Firm, MyApplication::Billing::Account.reflect_on_association(:firm).klass
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/topic'
|
3
|
+
|
4
|
+
class ThreadSafetyTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@topics = create_fixtures "topics"
|
7
|
+
@threads = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_threading_on_transactions
|
11
|
+
# SQLite breaks down under thread banging
|
12
|
+
# Jamis Buck (author of SQLite-ruby): "I know that sqlite itself is not designed for concurrent access"
|
13
|
+
if ActiveRecord::ConnectionAdapters.const_defined? :SQLiteAdapter
|
14
|
+
return true if ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::SQLiteAdapter)
|
15
|
+
end
|
16
|
+
|
17
|
+
5.times do |thread_number|
|
18
|
+
@threads << Thread.new(thread_number) do |thread_number|
|
19
|
+
first, second = Topic.find(1, 2)
|
20
|
+
Topic.transaction(first, second) do
|
21
|
+
Topic.logger.info "started #{thread_number}"
|
22
|
+
first.approved = 1
|
23
|
+
second.approved = 0
|
24
|
+
first.save
|
25
|
+
second.save
|
26
|
+
Topic.logger.info "ended #{thread_number}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@threads.each { |t| t.join }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/topic'
|
3
|
+
|
4
|
+
|
5
|
+
class TransactionTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@topics = create_fixtures "topics"
|
8
|
+
@first, @second = Topic.find(1, 2)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_succesful
|
12
|
+
Topic.transaction do
|
13
|
+
@first.approved = 1
|
14
|
+
@second.approved = 0
|
15
|
+
@first.save
|
16
|
+
@second.save
|
17
|
+
end
|
18
|
+
|
19
|
+
assert Topic.find(1).approved?, "First should have been approved"
|
20
|
+
assert !Topic.find(2).approved?, "Second should have been unapproved"
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_failing_on_exception
|
24
|
+
begin
|
25
|
+
Topic.transaction do
|
26
|
+
@first.approved = true
|
27
|
+
@second.approved = false
|
28
|
+
@first.save
|
29
|
+
@second.save
|
30
|
+
raise "Bad things!"
|
31
|
+
end
|
32
|
+
rescue
|
33
|
+
# caught it
|
34
|
+
end
|
35
|
+
|
36
|
+
assert @first.approved?, "First should still be changed in the objects"
|
37
|
+
assert !@second.approved?, "Second should still be changed in the objects"
|
38
|
+
|
39
|
+
assert !Topic.find(1).approved?, "First shouldn't have been approved"
|
40
|
+
assert Topic.find(2).approved?, "Second should still be approved"
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_failing_with_object_rollback
|
44
|
+
begin
|
45
|
+
Topic.transaction(@first, @second) do
|
46
|
+
@first.approved = true
|
47
|
+
@second.approved = false
|
48
|
+
@first.save
|
49
|
+
@second.save
|
50
|
+
raise "Bad things!"
|
51
|
+
end
|
52
|
+
rescue
|
53
|
+
# caught it
|
54
|
+
end
|
55
|
+
|
56
|
+
assert !@first.approved?, "First shouldn't have been approved"
|
57
|
+
assert @second.approved?, "Second should still be approved"
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_callback_rollback_in_save
|
61
|
+
add_exception_raising_after_save_callback_to_topic
|
62
|
+
|
63
|
+
begin
|
64
|
+
@first.approved = true
|
65
|
+
@first.save
|
66
|
+
flunk
|
67
|
+
rescue => e
|
68
|
+
assert_equal "Make the transaction rollback", e.message
|
69
|
+
assert !Topic.find(1).approved?
|
70
|
+
ensure
|
71
|
+
remove_exception_raising_after_save_callback_to_topic
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def add_exception_raising_after_save_callback_to_topic
|
77
|
+
Topic.class_eval { def after_save() raise "Make the transaction rollback" end }
|
78
|
+
end
|
79
|
+
|
80
|
+
def remove_exception_raising_after_save_callback_to_topic
|
81
|
+
Topic.class_eval { remove_method :after_save }
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
|
3
|
+
class TestRecord < ActiveRecord::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class TestUnconnectedAdaptor < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@connection = ActiveRecord::Base.remove_connection
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
ActiveRecord::Base.establish_connection(@connection)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_unconnected
|
17
|
+
assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
18
|
+
TestRecord.find(1)
|
19
|
+
end
|
20
|
+
assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
21
|
+
TestRecord.new.save
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/topic'
|
3
|
+
require 'fixtures/reply'
|
4
|
+
require 'fixtures/developer'
|
5
|
+
|
6
|
+
|
7
|
+
class ValidationsTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@topic_fixtures = create_fixtures("topics")
|
10
|
+
@developers = create_fixtures("developers")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_single_field_validation
|
14
|
+
r = Reply.new
|
15
|
+
r.title = "There's no content!"
|
16
|
+
assert !r.save, "A reply without content shouldn't be saveable"
|
17
|
+
|
18
|
+
r.content = "Messa content!"
|
19
|
+
assert r.save, "A reply with content should be saveable"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_single_attr_validation_and_error_msg
|
23
|
+
r = Reply.new
|
24
|
+
r.title = "There's no content!"
|
25
|
+
r.save
|
26
|
+
assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
|
27
|
+
assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
|
28
|
+
assert_equal 1, r.errors.count
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_double_attr_validation_and_error_msg
|
32
|
+
r = Reply.new
|
33
|
+
assert !r.save
|
34
|
+
|
35
|
+
assert r.errors.invalid?("title"), "A reply without title should mark that attribute as invalid"
|
36
|
+
assert_equal "Empty", r.errors.on("title"), "A reply without title should contain an error"
|
37
|
+
|
38
|
+
assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
|
39
|
+
assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
|
40
|
+
|
41
|
+
assert_equal 2, r.errors.count
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_error_on_create
|
45
|
+
r = Reply.new
|
46
|
+
r.title = "Wrong Create"
|
47
|
+
assert !r.save
|
48
|
+
assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
|
49
|
+
assert_equal "is Wrong Create", r.errors.on("title"), "A reply with a bad content should contain an error"
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def test_error_on_update
|
54
|
+
r = Reply.new
|
55
|
+
r.title = "Bad"
|
56
|
+
r.content = "Good"
|
57
|
+
|
58
|
+
assert r.save, "First save should be successful"
|
59
|
+
|
60
|
+
r.title = "Wrong Update"
|
61
|
+
assert !r.save, "Second save should fail"
|
62
|
+
|
63
|
+
assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
|
64
|
+
assert_equal "is Wrong Update", r.errors.on("title"), "A reply with a bad content should contain an error"
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_single_error_per_attr_iteration
|
68
|
+
r = Reply.new
|
69
|
+
r.save
|
70
|
+
|
71
|
+
errors = []
|
72
|
+
r.errors.each { |attr, msg| errors << [attr, msg] }
|
73
|
+
|
74
|
+
assert errors.include?(["title", "Empty"])
|
75
|
+
assert errors.include?(["content", "Empty"])
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_multiple_errors_per_attr_iteration_with_full_error_composition
|
79
|
+
r = Reply.new
|
80
|
+
r.title = "Wrong Create"
|
81
|
+
r.content = "Mismatch"
|
82
|
+
r.save
|
83
|
+
|
84
|
+
errors = []
|
85
|
+
r.errors.each_full { |error| errors << error }
|
86
|
+
|
87
|
+
assert_equal "Title is Wrong Create", errors[0]
|
88
|
+
assert_equal "Title is Content Mismatch", errors[1]
|
89
|
+
assert_equal 2, r.errors.count
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_errors_on_base
|
93
|
+
r = Reply.new
|
94
|
+
r.content = "Mismatch"
|
95
|
+
r.save
|
96
|
+
r.errors.add_to_base "Reply is not dignifying"
|
97
|
+
|
98
|
+
errors = []
|
99
|
+
r.errors.each_full { |error| errors << error }
|
100
|
+
|
101
|
+
assert_equal "Reply is not dignifying", r.errors.on_base
|
102
|
+
|
103
|
+
assert errors.include?("Title Empty")
|
104
|
+
assert errors.include?("Reply is not dignifying")
|
105
|
+
assert_equal 2, r.errors.count
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_create_without_validation
|
109
|
+
reply = Reply.new
|
110
|
+
assert !reply.save
|
111
|
+
assert reply.save(false)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_errors_on_boundary_breaking
|
115
|
+
developer = Developer.new("name" => "xs")
|
116
|
+
assert !developer.save
|
117
|
+
assert_equal "is too short (min is 3 characters)", developer.errors.on("name")
|
118
|
+
|
119
|
+
developer.name = "All too very long for this boundary, it really is"
|
120
|
+
assert !developer.save
|
121
|
+
assert_equal "is too long (max is 20 characters)", developer.errors.on("name")
|
122
|
+
|
123
|
+
developer.name = "Just right"
|
124
|
+
assert developer.save
|
125
|
+
end
|
126
|
+
end
|