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
@@ -0,0 +1,273 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/person'
|
3
|
+
require 'fixtures/reader'
|
4
|
+
require 'fixtures/legacy_thing'
|
5
|
+
|
6
|
+
class LockWithoutDefault < ActiveRecord::Base; end
|
7
|
+
|
8
|
+
class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
|
9
|
+
set_table_name :lock_without_defaults_cust
|
10
|
+
set_locking_column :custom_lock_version
|
11
|
+
end
|
12
|
+
|
13
|
+
class ReadonlyFirstNamePerson < Person
|
14
|
+
attr_readonly :first_name
|
15
|
+
end
|
16
|
+
|
17
|
+
class OptimisticLockingTest < Test::Unit::TestCase
|
18
|
+
fixtures :people, :legacy_things
|
19
|
+
|
20
|
+
# need to disable transactional fixtures, because otherwise the sqlite3
|
21
|
+
# adapter (at least) chokes when we try and change the schema in the middle
|
22
|
+
# of a test (see test_increment_counter_*).
|
23
|
+
self.use_transactional_fixtures = false
|
24
|
+
|
25
|
+
def test_lock_existing
|
26
|
+
p1 = Person.find(1)
|
27
|
+
p2 = Person.find(1)
|
28
|
+
assert_equal 0, p1.lock_version
|
29
|
+
assert_equal 0, p2.lock_version
|
30
|
+
|
31
|
+
p1.save!
|
32
|
+
assert_equal 1, p1.lock_version
|
33
|
+
assert_equal 0, p2.lock_version
|
34
|
+
|
35
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_lock_repeating
|
39
|
+
p1 = Person.find(1)
|
40
|
+
p2 = Person.find(1)
|
41
|
+
assert_equal 0, p1.lock_version
|
42
|
+
assert_equal 0, p2.lock_version
|
43
|
+
|
44
|
+
p1.save!
|
45
|
+
assert_equal 1, p1.lock_version
|
46
|
+
assert_equal 0, p2.lock_version
|
47
|
+
|
48
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
49
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_lock_new
|
53
|
+
p1 = Person.new(:first_name => 'anika')
|
54
|
+
assert_equal 0, p1.lock_version
|
55
|
+
|
56
|
+
p1.save!
|
57
|
+
p2 = Person.find(p1.id)
|
58
|
+
assert_equal 0, p1.lock_version
|
59
|
+
assert_equal 0, p2.lock_version
|
60
|
+
|
61
|
+
p1.save!
|
62
|
+
assert_equal 1, p1.lock_version
|
63
|
+
assert_equal 0, p2.lock_version
|
64
|
+
|
65
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_lock_column_name_existing
|
69
|
+
t1 = LegacyThing.find(1)
|
70
|
+
t2 = LegacyThing.find(1)
|
71
|
+
assert_equal 0, t1.version
|
72
|
+
assert_equal 0, t2.version
|
73
|
+
|
74
|
+
t1.save!
|
75
|
+
assert_equal 1, t1.version
|
76
|
+
assert_equal 0, t2.version
|
77
|
+
|
78
|
+
assert_raises(ActiveRecord::StaleObjectError) { t2.save! }
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_lock_column_is_mass_assignable
|
82
|
+
p1 = Person.create(:first_name => 'bianca')
|
83
|
+
assert_equal 0, p1.lock_version
|
84
|
+
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
85
|
+
|
86
|
+
p1.save!
|
87
|
+
assert_equal 1, p1.lock_version
|
88
|
+
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_lock_without_default_sets_version_to_zero
|
92
|
+
t1 = LockWithoutDefault.new
|
93
|
+
assert_equal 0, t1.lock_version
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_lock_with_custom_column_without_default_sets_version_to_zero
|
97
|
+
t1 = LockWithCustomColumnWithoutDefault.new
|
98
|
+
assert_equal 0, t1.custom_lock_version
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_readonly_attributes
|
102
|
+
assert_equal Set.new([ 'first_name' ]), ReadonlyFirstNamePerson.readonly_attributes
|
103
|
+
|
104
|
+
p = ReadonlyFirstNamePerson.create(:first_name => "unchangeable name")
|
105
|
+
p.reload
|
106
|
+
assert_equal "unchangeable name", p.first_name
|
107
|
+
|
108
|
+
p.update_attributes(:first_name => "changed name")
|
109
|
+
p.reload
|
110
|
+
assert_equal "unchangeable name", p.first_name
|
111
|
+
end
|
112
|
+
|
113
|
+
{ :lock_version => Person, :custom_lock_version => LegacyThing }.each do |name, model|
|
114
|
+
define_method("test_increment_counter_updates_#{name}") do
|
115
|
+
counter_test model, 1 do |id|
|
116
|
+
model.increment_counter :test_count, id
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
define_method("test_decrement_counter_updates_#{name}") do
|
121
|
+
counter_test model, -1 do |id|
|
122
|
+
model.decrement_counter :test_count, id
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
define_method("test_update_counters_updates_#{name}") do
|
127
|
+
counter_test model, 1 do |id|
|
128
|
+
model.update_counters id, :test_count => 1
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def add_counter_column_to(model)
|
136
|
+
model.connection.add_column model.table_name, :test_count, :integer, :null => false, :default => 0
|
137
|
+
model.reset_column_information
|
138
|
+
# OpenBase does not set a value to existing rows when adding a not null default column
|
139
|
+
model.update_all(:test_count => 0) if current_adapter?(:OpenBaseAdapter)
|
140
|
+
end
|
141
|
+
|
142
|
+
def remove_counter_column_from(model)
|
143
|
+
model.connection.remove_column model.table_name, :test_count
|
144
|
+
model.reset_column_information
|
145
|
+
end
|
146
|
+
|
147
|
+
def counter_test(model, expected_count)
|
148
|
+
add_counter_column_to(model)
|
149
|
+
object = model.find(:first)
|
150
|
+
assert_equal 0, object.test_count
|
151
|
+
assert_equal 0, object.send(model.locking_column)
|
152
|
+
yield object.id
|
153
|
+
object.reload
|
154
|
+
assert_equal expected_count, object.test_count
|
155
|
+
assert_equal 1, object.send(model.locking_column)
|
156
|
+
ensure
|
157
|
+
remove_counter_column_from(model)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
# TODO: test against the generated SQL since testing locking behavior itself
|
163
|
+
# is so cumbersome. Will deadlock Ruby threads if the underlying db.execute
|
164
|
+
# blocks, so separate script called by Kernel#system is needed.
|
165
|
+
# (See exec vs. async_exec in the PostgreSQL adapter.)
|
166
|
+
|
167
|
+
# TODO: The SQL Server, Sybase, and OpenBase adapters currently have no support for pessimistic locking
|
168
|
+
|
169
|
+
unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :OpenBaseAdapter)
|
170
|
+
class PessimisticLockingTest < Test::Unit::TestCase
|
171
|
+
self.use_transactional_fixtures = false
|
172
|
+
fixtures :people, :readers
|
173
|
+
|
174
|
+
def setup
|
175
|
+
# Avoid introspection queries during tests.
|
176
|
+
Person.columns; Reader.columns
|
177
|
+
|
178
|
+
@allow_concurrency = ActiveRecord::Base.allow_concurrency
|
179
|
+
ActiveRecord::Base.allow_concurrency = true
|
180
|
+
end
|
181
|
+
|
182
|
+
def teardown
|
183
|
+
ActiveRecord::Base.allow_concurrency = @allow_concurrency
|
184
|
+
end
|
185
|
+
|
186
|
+
# Test typical find.
|
187
|
+
def test_sane_find_with_lock
|
188
|
+
assert_nothing_raised do
|
189
|
+
Person.transaction do
|
190
|
+
Person.find 1, :lock => true
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Test scoped lock.
|
196
|
+
def test_sane_find_with_scoped_lock
|
197
|
+
assert_nothing_raised do
|
198
|
+
Person.transaction do
|
199
|
+
Person.with_scope(:find => { :lock => true }) do
|
200
|
+
Person.find 1
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
|
207
|
+
unless current_adapter?(:PostgreSQLAdapter)
|
208
|
+
# Test locked eager find.
|
209
|
+
def test_eager_find_with_lock
|
210
|
+
assert_nothing_raised do
|
211
|
+
Person.transaction do
|
212
|
+
Person.find 1, :include => :readers, :lock => true
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Locking a record reloads it.
|
219
|
+
def test_sane_lock_method
|
220
|
+
assert_nothing_raised do
|
221
|
+
Person.transaction do
|
222
|
+
person = Person.find 1
|
223
|
+
old, person.first_name = person.first_name, 'fooman'
|
224
|
+
person.lock!
|
225
|
+
assert_equal old, person.first_name
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
|
231
|
+
def test_no_locks_no_wait
|
232
|
+
first, second = duel { Person.find 1 }
|
233
|
+
assert first.end > second.end
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_second_lock_waits
|
237
|
+
assert [0.2, 1, 5].any? { |zzz|
|
238
|
+
first, second = duel(zzz) { Person.find 1, :lock => true }
|
239
|
+
second.end > first.end
|
240
|
+
}
|
241
|
+
end
|
242
|
+
|
243
|
+
protected
|
244
|
+
def duel(zzz = 5)
|
245
|
+
t0, t1, t2, t3 = nil, nil, nil, nil
|
246
|
+
|
247
|
+
a = Thread.new do
|
248
|
+
t0 = Time.now
|
249
|
+
Person.transaction do
|
250
|
+
yield
|
251
|
+
sleep zzz # block thread 2 for zzz seconds
|
252
|
+
end
|
253
|
+
t1 = Time.now
|
254
|
+
end
|
255
|
+
|
256
|
+
b = Thread.new do
|
257
|
+
sleep zzz / 2.0 # ensure thread 1 tx starts first
|
258
|
+
t2 = Time.now
|
259
|
+
Person.transaction { yield }
|
260
|
+
t3 = Time.now
|
261
|
+
end
|
262
|
+
|
263
|
+
a.join
|
264
|
+
b.join
|
265
|
+
|
266
|
+
assert t1 > t0 + zzz
|
267
|
+
assert t2 > t0
|
268
|
+
assert t3 > t2
|
269
|
+
[t0.to_f..t1.to_f, t2.to_f..t3.to_f]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
@@ -0,0 +1,416 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/developer'
|
3
|
+
require 'fixtures/project'
|
4
|
+
require 'fixtures/comment'
|
5
|
+
require 'fixtures/post'
|
6
|
+
require 'fixtures/category'
|
7
|
+
|
8
|
+
class MethodScopingTest < Test::Unit::TestCase
|
9
|
+
fixtures :developers, :projects, :comments, :posts
|
10
|
+
|
11
|
+
def test_set_conditions
|
12
|
+
Developer.with_scope(:find => { :conditions => 'just a test...' }) do
|
13
|
+
assert_equal 'just a test...', Developer.send(:current_scoped_methods)[:find][:conditions]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_scoped_find
|
18
|
+
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
19
|
+
assert_nothing_raised { Developer.find(1) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_scoped_find_first
|
24
|
+
Developer.with_scope(:find => { :conditions => "salary = 100000" }) do
|
25
|
+
assert_equal Developer.find(10), Developer.find(:first, :order => 'name')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_scoped_find_combines_conditions
|
30
|
+
Developer.with_scope(:find => { :conditions => "salary = 9000" }) do
|
31
|
+
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => "name = 'Jamis'")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_scoped_find_sanitizes_conditions
|
36
|
+
Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
|
37
|
+
assert_equal developers(:poor_jamis), Developer.find(:first)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_scoped_find_combines_and_sanitizes_conditions
|
42
|
+
Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
|
43
|
+
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_scoped_find_all
|
48
|
+
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
49
|
+
assert_equal [developers(:david)], Developer.find(:all)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_scoped_count
|
54
|
+
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
55
|
+
assert_equal 1, Developer.count
|
56
|
+
end
|
57
|
+
|
58
|
+
Developer.with_scope(:find => { :conditions => 'salary = 100000' }) do
|
59
|
+
assert_equal 8, Developer.count
|
60
|
+
assert_equal 1, Developer.count(:conditions => "name LIKE 'fixture_1%'")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_scoped_find_include
|
65
|
+
# with the include, will retrieve only developers for the given project
|
66
|
+
scoped_developers = Developer.with_scope(:find => { :include => :projects }) do
|
67
|
+
Developer.find(:all, :conditions => 'projects.id = 2')
|
68
|
+
end
|
69
|
+
assert scoped_developers.include?(developers(:david))
|
70
|
+
assert !scoped_developers.include?(developers(:jamis))
|
71
|
+
assert_equal 1, scoped_developers.size
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_scoped_count_include
|
75
|
+
# with the include, will retrieve only developers for the given project
|
76
|
+
Developer.with_scope(:find => { :include => :projects }) do
|
77
|
+
assert_equal 1, Developer.count(:conditions => 'projects.id = 2')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_scoped_create
|
82
|
+
new_comment = nil
|
83
|
+
|
84
|
+
VerySpecialComment.with_scope(:create => { :post_id => 1 }) do
|
85
|
+
assert_equal({ :post_id => 1 }, VerySpecialComment.send(:current_scoped_methods)[:create])
|
86
|
+
new_comment = VerySpecialComment.create :body => "Wonderful world"
|
87
|
+
end
|
88
|
+
|
89
|
+
assert Post.find(1).comments.include?(new_comment)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_immutable_scope
|
93
|
+
options = { :conditions => "name = 'David'" }
|
94
|
+
Developer.with_scope(:find => options) do
|
95
|
+
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
96
|
+
options[:conditions] = "name != 'David'"
|
97
|
+
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
98
|
+
end
|
99
|
+
|
100
|
+
scope = { :find => { :conditions => "name = 'David'" }}
|
101
|
+
Developer.with_scope(scope) do
|
102
|
+
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
103
|
+
scope[:find][:conditions] = "name != 'David'"
|
104
|
+
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_scoped_with_duck_typing
|
109
|
+
scoping = Struct.new(:method_scoping).new(:find => { :conditions => ["name = ?", 'David'] })
|
110
|
+
Developer.with_scope(scoping) do
|
111
|
+
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_ensure_that_method_scoping_is_correctly_restored
|
116
|
+
scoped_methods = Developer.instance_eval('current_scoped_methods')
|
117
|
+
|
118
|
+
begin
|
119
|
+
Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
120
|
+
raise "an exception"
|
121
|
+
end
|
122
|
+
rescue
|
123
|
+
end
|
124
|
+
assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class NestedScopingTest < Test::Unit::TestCase
|
129
|
+
fixtures :developers, :projects, :comments, :posts
|
130
|
+
|
131
|
+
def test_merge_options
|
132
|
+
Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do
|
133
|
+
Developer.with_scope(:find => { :limit => 10 }) do
|
134
|
+
merged_option = Developer.instance_eval('current_scoped_methods')[:find]
|
135
|
+
assert_equal({ :conditions => 'salary = 80000', :limit => 10 }, merged_option)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_replace_options
|
141
|
+
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
142
|
+
Developer.with_exclusive_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
143
|
+
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.instance_eval('current_scoped_methods'))
|
144
|
+
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.send(:scoped_methods)[-1])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_append_conditions
|
150
|
+
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
151
|
+
Developer.with_scope(:find => { :conditions => 'salary = 80000' }) do
|
152
|
+
appended_condition = Developer.instance_eval('current_scoped_methods')[:find][:conditions]
|
153
|
+
assert_equal("( name = 'David' ) AND ( salary = 80000 )", appended_condition)
|
154
|
+
assert_equal(1, Developer.count)
|
155
|
+
end
|
156
|
+
Developer.with_scope(:find => { :conditions => "name = 'Maiha'" }) do
|
157
|
+
assert_equal(0, Developer.count)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_merge_and_append_options
|
163
|
+
Developer.with_scope(:find => { :conditions => 'salary = 80000', :limit => 10 }) do
|
164
|
+
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
165
|
+
merged_option = Developer.instance_eval('current_scoped_methods')[:find]
|
166
|
+
assert_equal({ :conditions => "( salary = 80000 ) AND ( name = 'David' )", :limit => 10 }, merged_option)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_nested_scoped_find
|
172
|
+
Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
173
|
+
Developer.with_exclusive_scope(:find => { :conditions => "name = 'David'" }) do
|
174
|
+
assert_nothing_raised { Developer.find(1) }
|
175
|
+
assert_equal('David', Developer.find(:first).name)
|
176
|
+
end
|
177
|
+
assert_equal('Jamis', Developer.find(:first).name)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_nested_scoped_find_include
|
182
|
+
Developer.with_scope(:find => { :include => :projects }) do
|
183
|
+
Developer.with_scope(:find => { :conditions => "projects.id = 2" }) do
|
184
|
+
assert_nothing_raised { Developer.find(1) }
|
185
|
+
assert_equal('David', Developer.find(:first).name)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_nested_scoped_find_merged_include
|
191
|
+
# :include's remain unique and don't "double up" when merging
|
192
|
+
Developer.with_scope(:find => { :include => :projects, :conditions => "projects.id = 2" }) do
|
193
|
+
Developer.with_scope(:find => { :include => :projects }) do
|
194
|
+
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
|
195
|
+
assert_equal('David', Developer.find(:first).name)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# the nested scope doesn't remove the first :include
|
200
|
+
Developer.with_scope(:find => { :include => :projects, :conditions => "projects.id = 2" }) do
|
201
|
+
Developer.with_scope(:find => { :include => [] }) do
|
202
|
+
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
|
203
|
+
assert_equal('David', Developer.find(:first).name)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# mixing array and symbol include's will merge correctly
|
208
|
+
Developer.with_scope(:find => { :include => [:projects], :conditions => "projects.id = 2" }) do
|
209
|
+
Developer.with_scope(:find => { :include => :projects }) do
|
210
|
+
assert_equal 1, Developer.instance_eval('current_scoped_methods')[:find][:include].length
|
211
|
+
assert_equal('David', Developer.find(:first).name)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_nested_scoped_find_replace_include
|
217
|
+
Developer.with_scope(:find => { :include => :projects }) do
|
218
|
+
Developer.with_exclusive_scope(:find => { :include => [] }) do
|
219
|
+
assert_equal 0, Developer.instance_eval('current_scoped_methods')[:find][:include].length
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_three_level_nested_exclusive_scoped_find
|
225
|
+
Developer.with_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
226
|
+
assert_equal('Jamis', Developer.find(:first).name)
|
227
|
+
|
228
|
+
Developer.with_exclusive_scope(:find => { :conditions => "name = 'David'" }) do
|
229
|
+
assert_equal('David', Developer.find(:first).name)
|
230
|
+
|
231
|
+
Developer.with_exclusive_scope(:find => { :conditions => "name = 'Maiha'" }) do
|
232
|
+
assert_equal(nil, Developer.find(:first))
|
233
|
+
end
|
234
|
+
|
235
|
+
# ensure that scoping is restored
|
236
|
+
assert_equal('David', Developer.find(:first).name)
|
237
|
+
end
|
238
|
+
|
239
|
+
# ensure that scoping is restored
|
240
|
+
assert_equal('Jamis', Developer.find(:first).name)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_merged_scoped_find
|
245
|
+
poor_jamis = developers(:poor_jamis)
|
246
|
+
Developer.with_scope(:find => { :conditions => "salary < 100000" }) do
|
247
|
+
Developer.with_scope(:find => { :offset => 1 }) do
|
248
|
+
assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_merged_scoped_find_sanitizes_conditions
|
254
|
+
Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
|
255
|
+
Developer.with_scope(:find => { :conditions => ['salary = ?', 9000] }) do
|
256
|
+
assert_raise(ActiveRecord::RecordNotFound) { developers(:poor_jamis) }
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_nested_scoped_find_combines_and_sanitizes_conditions
|
262
|
+
Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
|
263
|
+
Developer.with_exclusive_scope(:find => { :conditions => ['salary = ?', 9000] }) do
|
264
|
+
assert_equal developers(:poor_jamis), Developer.find(:first)
|
265
|
+
assert_equal developers(:poor_jamis), Developer.find(:first, :conditions => ['name = ?', 'Jamis'])
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_merged_scoped_find_combines_and_sanitizes_conditions
|
271
|
+
Developer.with_scope(:find => { :conditions => ["name = ?", 'David'] }) do
|
272
|
+
Developer.with_scope(:find => { :conditions => ['salary > ?', 9000] }) do
|
273
|
+
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_immutable_nested_scope
|
279
|
+
options1 = { :conditions => "name = 'Jamis'" }
|
280
|
+
options2 = { :conditions => "name = 'David'" }
|
281
|
+
Developer.with_scope(:find => options1) do
|
282
|
+
Developer.with_exclusive_scope(:find => options2) do
|
283
|
+
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
284
|
+
options1[:conditions] = options2[:conditions] = nil
|
285
|
+
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_immutable_merged_scope
|
291
|
+
options1 = { :conditions => "name = 'Jamis'" }
|
292
|
+
options2 = { :conditions => "salary > 10000" }
|
293
|
+
Developer.with_scope(:find => options1) do
|
294
|
+
Developer.with_scope(:find => options2) do
|
295
|
+
assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
|
296
|
+
options1[:conditions] = options2[:conditions] = nil
|
297
|
+
assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def test_ensure_that_method_scoping_is_correctly_restored
|
303
|
+
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
304
|
+
scoped_methods = Developer.instance_eval('current_scoped_methods')
|
305
|
+
begin
|
306
|
+
Developer.with_scope(:find => { :conditions => "name = 'Maiha'" }) do
|
307
|
+
raise "an exception"
|
308
|
+
end
|
309
|
+
rescue
|
310
|
+
end
|
311
|
+
assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods')
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
class HasManyScopingTest< Test::Unit::TestCase
|
317
|
+
fixtures :comments, :posts
|
318
|
+
|
319
|
+
def setup
|
320
|
+
@welcome = Post.find(1)
|
321
|
+
end
|
322
|
+
|
323
|
+
def test_forwarding_of_static_methods
|
324
|
+
assert_equal 'a comment...', Comment.what_are_you
|
325
|
+
assert_equal 'a comment...', @welcome.comments.what_are_you
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_forwarding_to_scoped
|
329
|
+
assert_equal 4, Comment.search_by_type('Comment').size
|
330
|
+
assert_equal 2, @welcome.comments.search_by_type('Comment').size
|
331
|
+
end
|
332
|
+
|
333
|
+
def test_forwarding_to_dynamic_finders
|
334
|
+
assert_equal 4, Comment.find_all_by_type('Comment').size
|
335
|
+
assert_equal 2, @welcome.comments.find_all_by_type('Comment').size
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_nested_scope
|
339
|
+
Comment.with_scope(:find => { :conditions => '1=1' }) do
|
340
|
+
assert_equal 'a comment...', @welcome.comments.what_are_you
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
|
346
|
+
class HasAndBelongsToManyScopingTest< Test::Unit::TestCase
|
347
|
+
fixtures :posts, :categories, :categories_posts
|
348
|
+
|
349
|
+
def setup
|
350
|
+
@welcome = Post.find(1)
|
351
|
+
end
|
352
|
+
|
353
|
+
def test_forwarding_of_static_methods
|
354
|
+
assert_equal 'a category...', Category.what_are_you
|
355
|
+
assert_equal 'a category...', @welcome.categories.what_are_you
|
356
|
+
end
|
357
|
+
|
358
|
+
def test_forwarding_to_dynamic_finders
|
359
|
+
assert_equal 4, Category.find_all_by_type('SpecialCategory').size
|
360
|
+
assert_equal 0, @welcome.categories.find_all_by_type('SpecialCategory').size
|
361
|
+
assert_equal 2, @welcome.categories.find_all_by_type('Category').size
|
362
|
+
end
|
363
|
+
|
364
|
+
def test_nested_scope
|
365
|
+
Category.with_scope(:find => { :conditions => '1=1' }) do
|
366
|
+
assert_equal 'a comment...', @welcome.comments.what_are_you
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
|
372
|
+
=begin
|
373
|
+
# We disabled the scoping for has_one and belongs_to as we can't think of a proper use case
|
374
|
+
|
375
|
+
|
376
|
+
class BelongsToScopingTest< Test::Unit::TestCase
|
377
|
+
fixtures :comments, :posts
|
378
|
+
|
379
|
+
def setup
|
380
|
+
@greetings = Comment.find(1)
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_forwarding_of_static_method
|
384
|
+
assert_equal 'a post...', Post.what_are_you
|
385
|
+
assert_equal 'a post...', @greetings.post.what_are_you
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_forwarding_to_dynamic_finders
|
389
|
+
assert_equal 4, Post.find_all_by_type('Post').size
|
390
|
+
assert_equal 1, @greetings.post.find_all_by_type('Post').size
|
391
|
+
end
|
392
|
+
|
393
|
+
end
|
394
|
+
|
395
|
+
|
396
|
+
class HasOneScopingTest< Test::Unit::TestCase
|
397
|
+
fixtures :comments, :posts
|
398
|
+
|
399
|
+
def setup
|
400
|
+
@sti_comments = Post.find(4)
|
401
|
+
end
|
402
|
+
|
403
|
+
def test_forwarding_of_static_methods
|
404
|
+
assert_equal 'a comment...', Comment.what_are_you
|
405
|
+
assert_equal 'a very special comment...', @sti_comments.very_special_comment.what_are_you
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_forwarding_to_dynamic_finders
|
409
|
+
assert_equal 1, Comment.find_all_by_type('VerySpecialComment').size
|
410
|
+
assert_equal 1, @sti_comments.very_special_comment.find_all_by_type('VerySpecialComment').size
|
411
|
+
assert_equal 0, @sti_comments.very_special_comment.find_all_by_type('Comment').size
|
412
|
+
end
|
413
|
+
|
414
|
+
end
|
415
|
+
|
416
|
+
=end
|