activerecord 1.15.6 → 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 +2454 -34
- data/README +1 -1
- data/RUNNING_UNIT_TESTS +3 -34
- data/Rakefile +98 -77
- data/install.rb +1 -1
- data/lib/active_record.rb +13 -22
- data/lib/active_record/aggregations.rb +38 -49
- data/lib/active_record/associations.rb +452 -333
- data/lib/active_record/associations/association_collection.rb +66 -20
- data/lib/active_record/associations/association_proxy.rb +9 -8
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -51
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +38 -18
- data/lib/active_record/associations/has_one_association.rb +30 -14
- data/lib/active_record/attribute_methods.rb +253 -0
- data/lib/active_record/base.rb +719 -494
- data/lib/active_record/calculations.rb +62 -63
- data/lib/active_record/callbacks.rb +57 -83
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +38 -9
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -15
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +191 -62
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -17
- data/lib/active_record/connection_adapters/mysql_adapter.rb +119 -37
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +473 -210
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +91 -107
- data/lib/active_record/fixtures.rb +503 -113
- data/lib/active_record/locking/optimistic.rb +72 -34
- data/lib/active_record/migration.rb +80 -57
- data/lib/active_record/observer.rb +13 -10
- data/lib/active_record/query_cache.rb +16 -57
- data/lib/active_record/reflection.rb +35 -38
- data/lib/active_record/schema.rb +5 -5
- data/lib/active_record/schema_dumper.rb +35 -13
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/{xml_serialization.rb → serializers/xml_serializer.rb} +90 -83
- data/lib/active_record/timestamp.rb +20 -21
- data/lib/active_record/transactions.rb +39 -43
- data/lib/active_record/validations.rb +256 -107
- data/lib/active_record/version.rb +3 -3
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +15 -2
- data/test/abstract_unit.rb +24 -17
- data/test/active_schema_test_mysql.rb +20 -8
- data/test/adapter_test.rb +23 -5
- data/test/adapter_test_sqlserver.rb +15 -1
- data/test/aggregations_test.rb +16 -1
- data/test/all.sh +2 -2
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +51 -30
- data/test/associations/cascaded_eager_loading_test.rb +1 -29
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +42 -6
- data/test/associations/extension_test.rb +6 -1
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +47 -16
- data/test/associations_test.rb +449 -226
- data/test/attribute_methods_test.rb +97 -0
- data/test/base_test.rb +251 -105
- data/test/binary_test.rb +22 -27
- data/test/calculations_test.rb +37 -5
- data/test/callbacks_test.rb +23 -0
- data/test/connection_test_firebird.rb +2 -2
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_mysql/connection.rb +3 -0
- data/test/connections/native_sqlite/connection.rb +5 -14
- data/test/connections/native_sqlite3/connection.rb +5 -14
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -1
- data/test/{copy_table_sqlite.rb → copy_table_test_sqlite.rb} +8 -3
- data/test/datatype_test_postgresql.rb +178 -27
- data/test/{empty_date_time_test.rb → date_time_test.rb} +13 -1
- data/test/defaults_test.rb +8 -1
- data/test/deprecated_finder_test.rb +7 -128
- data/test/finder_test.rb +192 -54
- 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 +12 -5
- data/test/fixtures/binaries.yml +130 -435
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +8 -1
- data/test/fixtures/computer.rb +1 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/customer.rb +2 -2
- data/test/fixtures/db_definitions/db2.drop.sql +1 -0
- data/test/fixtures/db_definitions/db2.sql +4 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +3 -1
- data/test/fixtures/db_definitions/firebird.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase.sql +5 -0
- data/test/fixtures/db_definitions/openbase.sql +41 -25
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +5 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +7 -0
- data/test/fixtures/db_definitions/postgresql.sql +87 -58
- data/test/fixtures/db_definitions/postgresql2.sql +1 -2
- data/test/fixtures/db_definitions/schema.rb +280 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +4 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +1 -0
- data/test/fixtures/db_definitions/sybase.sql +4 -0
- data/test/fixtures/developer.rb +10 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +0 -3
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixins.yml +2 -100
- 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/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +1 -0
- data/test/fixtures/project.rb +3 -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/tagging.rb +4 -0
- data/test/fixtures/taggings.yml +8 -1
- data/test/fixtures/topic.rb +13 -1
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures_test.rb +205 -24
- data/test/inheritance_test.rb +7 -1
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +1 -1
- data/test/locking_test.rb +85 -2
- data/test/migration_test.rb +206 -40
- data/test/mixin_test.rb +13 -515
- data/test/pk_test.rb +3 -6
- data/test/query_cache_test.rb +104 -0
- data/test/reflection_test.rb +16 -0
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_dumper_test.rb +38 -3
- data/test/serialization_test.rb +47 -0
- data/test/transactions_test.rb +74 -23
- data/test/unconnected_test.rb +1 -1
- data/test/validations_test.rb +322 -32
- data/test/xml_serialization_test.rb +121 -44
- metadata +48 -41
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -85
- data/lib/active_record/acts/list.rb +0 -256
- data/lib/active_record/acts/nested_set.rb +0 -211
- data/lib/active_record/acts/tree.rb +0 -96
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -228
- data/lib/active_record/connection_adapters/firebird_adapter.rb +0 -728
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +0 -861
- data/lib/active_record/connection_adapters/openbase_adapter.rb +0 -350
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -690
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +0 -591
- data/lib/active_record/connection_adapters/sybase_adapter.rb +0 -662
- data/lib/active_record/deprecated_associations.rb +0 -104
- data/lib/active_record/deprecated_finders.rb +0 -44
- data/lib/active_record/vendor/simple.rb +0 -693
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -58
- data/test/connections/native_sqlserver/connection.rb +0 -23
- data/test/connections/native_sqlserver_odbc/connection.rb +0 -25
- data/test/deprecated_associations_test.rb +0 -396
- data/test/fixtures/db_definitions/mysql.drop.sql +0 -32
- data/test/fixtures/db_definitions/mysql.sql +0 -234
- data/test/fixtures/db_definitions/mysql2.drop.sql +0 -2
- data/test/fixtures/db_definitions/mysql2.sql +0 -5
- data/test/fixtures/db_definitions/sqlserver.drop.sql +0 -34
- data/test/fixtures/db_definitions/sqlserver.sql +0 -243
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +0 -2
- data/test/fixtures/db_definitions/sqlserver2.sql +0 -5
- data/test/fixtures/mixin.rb +0 -63
- data/test/mixin_nested_set_test.rb +0 -196
data/test/pk_test.rb
CHANGED
@@ -83,11 +83,8 @@ class PrimaryKeysTest < Test::Unit::TestCase
|
|
83
83
|
def test_delete_should_quote_pkey
|
84
84
|
assert_nothing_raised { MixedCaseMonkey.delete(1) }
|
85
85
|
end
|
86
|
-
def
|
87
|
-
assert_nothing_raised { MixedCaseMonkey.
|
88
|
-
end
|
89
|
-
def test_decrement_counter_should_quote_pkey_and_quote_counter_columns
|
90
|
-
assert_nothing_raised { MixedCaseMonkey.decrement_counter(:fleaCount, 1) }
|
86
|
+
def test_update_counters_should_quote_pkey_and_quote_counter_columns
|
87
|
+
assert_nothing_raised { MixedCaseMonkey.update_counters(1, :fleaCount => 99) }
|
91
88
|
end
|
92
89
|
def test_find_with_one_id_should_quote_pkey
|
93
90
|
assert_nothing_raised { MixedCaseMonkey.find(1) }
|
@@ -98,7 +95,7 @@ class PrimaryKeysTest < Test::Unit::TestCase
|
|
98
95
|
def test_instance_update_should_quote_pkey
|
99
96
|
assert_nothing_raised { MixedCaseMonkey.find(1).save }
|
100
97
|
end
|
101
|
-
def
|
98
|
+
def test_instance_destroy_should_quote_pkey
|
102
99
|
assert_nothing_raised { MixedCaseMonkey.find(1).destroy }
|
103
100
|
end
|
104
101
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/topic'
|
3
|
+
require 'fixtures/reply'
|
4
|
+
require 'fixtures/task'
|
5
|
+
require 'fixtures/course'
|
6
|
+
|
7
|
+
|
8
|
+
class QueryCacheTest < Test::Unit::TestCase
|
9
|
+
fixtures :tasks, :topics
|
10
|
+
|
11
|
+
def test_find_queries
|
12
|
+
assert_queries(2) { Task.find(1); Task.find(1) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_find_queries_with_cache
|
16
|
+
Task.cache do
|
17
|
+
assert_queries(1) { Task.find(1); Task.find(1) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_count_queries_with_cache
|
22
|
+
Task.cache do
|
23
|
+
assert_queries(1) { Task.count; Task.count }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_query_cache_dups_results_correctly
|
28
|
+
Task.cache do
|
29
|
+
now = Time.now.utc
|
30
|
+
task = Task.find 1
|
31
|
+
assert_not_equal now, task.starting
|
32
|
+
task.starting = now
|
33
|
+
task.reload
|
34
|
+
assert_not_equal now, task.starting
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_cache_is_flat
|
39
|
+
Task.cache do
|
40
|
+
Topic.columns # don't count this query
|
41
|
+
assert_queries(1) { Topic.find(1); Topic.find(1); }
|
42
|
+
end
|
43
|
+
|
44
|
+
ActiveRecord::Base.cache do
|
45
|
+
assert_queries(1) { Task.find(1); Task.find(1) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_cache_does_not_wrap_string_results_in_arrays
|
50
|
+
Task.cache do
|
51
|
+
assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
uses_mocha 'QueryCacheExpiryTest' do
|
57
|
+
|
58
|
+
class QueryCacheExpiryTest < Test::Unit::TestCase
|
59
|
+
fixtures :tasks
|
60
|
+
|
61
|
+
def test_find
|
62
|
+
Task.connection.expects(:clear_query_cache).times(1)
|
63
|
+
|
64
|
+
assert !Task.connection.query_cache_enabled
|
65
|
+
Task.cache do
|
66
|
+
assert Task.connection.query_cache_enabled
|
67
|
+
Task.find(1)
|
68
|
+
|
69
|
+
Task.uncached do
|
70
|
+
assert !Task.connection.query_cache_enabled
|
71
|
+
Task.find(1)
|
72
|
+
end
|
73
|
+
|
74
|
+
assert Task.connection.query_cache_enabled
|
75
|
+
end
|
76
|
+
assert !Task.connection.query_cache_enabled
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_update
|
80
|
+
Task.connection.expects(:clear_query_cache).times(2)
|
81
|
+
|
82
|
+
Task.cache do
|
83
|
+
Task.find(1).save!
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_destroy
|
88
|
+
Task.connection.expects(:clear_query_cache).times(2)
|
89
|
+
|
90
|
+
Task.cache do
|
91
|
+
Task.find(1).destroy
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_insert
|
96
|
+
ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
|
97
|
+
|
98
|
+
Task.cache do
|
99
|
+
Task.create!
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/test/reflection_test.rb
CHANGED
@@ -60,6 +60,13 @@ class ReflectionTest < Test::Unit::TestCase
|
|
60
60
|
assert_equal :integer, @first.column_for_attribute("id").type
|
61
61
|
end
|
62
62
|
|
63
|
+
def test_reflection_klass_for_nested_class_name
|
64
|
+
reflection = ActiveRecord::Reflection::MacroReflection.new(nil, nil, { :class_name => 'MyApplication::Business::Company' }, nil)
|
65
|
+
assert_nothing_raised do
|
66
|
+
assert_equal MyApplication::Business::Company, reflection.klass
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
63
70
|
def test_aggregation_reflection
|
64
71
|
reflection_for_address = ActiveRecord::Reflection::AggregateReflection.new(
|
65
72
|
:composed_of, :address, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer
|
@@ -104,6 +111,15 @@ class ReflectionTest < Test::Unit::TestCase
|
|
104
111
|
assert_equal 'accounts', Firm.reflect_on_association(:account).table_name
|
105
112
|
end
|
106
113
|
|
114
|
+
def test_belongs_to_inferred_foreign_key_from_assoc_name
|
115
|
+
Company.belongs_to :foo
|
116
|
+
assert_equal "foo_id", Company.reflect_on_association(:foo).primary_key_name
|
117
|
+
Company.belongs_to :bar, :class_name => "Xyzzy"
|
118
|
+
assert_equal "bar_id", Company.reflect_on_association(:bar).primary_key_name
|
119
|
+
Company.belongs_to :baz, :class_name => "Xyzzy", :foreign_key => "xyzzy_id"
|
120
|
+
assert_equal "xyzzy_id", Company.reflect_on_association(:baz).primary_key_name
|
121
|
+
end
|
122
|
+
|
107
123
|
def test_association_reflection_in_modules
|
108
124
|
assert_reflection MyApplication::Business::Firm,
|
109
125
|
:clients_of_firm,
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_unit"
|
2
|
+
|
3
|
+
class Group < ActiveRecord::Base
|
4
|
+
Group.table_name = 'group'
|
5
|
+
belongs_to :select, :class_name => 'Select'
|
6
|
+
has_one :values
|
7
|
+
end
|
8
|
+
|
9
|
+
class Select < ActiveRecord::Base
|
10
|
+
Select.table_name = 'select'
|
11
|
+
has_many :groups
|
12
|
+
end
|
13
|
+
|
14
|
+
class Values < ActiveRecord::Base
|
15
|
+
Values.table_name = 'values'
|
16
|
+
end
|
17
|
+
|
18
|
+
class Distinct < ActiveRecord::Base
|
19
|
+
Distinct.table_name = 'distinct'
|
20
|
+
has_and_belongs_to_many :selects
|
21
|
+
has_many :values, :through => :groups
|
22
|
+
end
|
23
|
+
|
24
|
+
# a suite of tests to ensure the ConnectionAdapters#MysqlAdapter can handle tables with
|
25
|
+
# reserved word names (ie: group, order, values, etc...)
|
26
|
+
class MysqlReservedWordTest < Test::Unit::TestCase
|
27
|
+
def setup
|
28
|
+
@connection = ActiveRecord::Base.connection
|
29
|
+
|
30
|
+
# we call execute directly here (and do similar below) because ActiveRecord::Base#create_table()
|
31
|
+
# will fail with these table names if these test cases fail
|
32
|
+
|
33
|
+
create_tables_directly 'group'=>'id int auto_increment primary key, `order` varchar(255), select_id int',
|
34
|
+
'select'=>'id int auto_increment primary key',
|
35
|
+
'values'=>'id int auto_increment primary key, group_id int',
|
36
|
+
'distinct'=>'id int auto_increment primary key',
|
37
|
+
'distincts_selects'=>'distinct_id int, select_id int'
|
38
|
+
end
|
39
|
+
|
40
|
+
def teardown
|
41
|
+
drop_tables_directly ['group', 'select', 'values', 'distinct', 'distincts_selects', 'order']
|
42
|
+
end
|
43
|
+
|
44
|
+
# create tables with reserved-word names and columns
|
45
|
+
def test_create_tables
|
46
|
+
assert_nothing_raised {
|
47
|
+
@connection.create_table :order do |t|
|
48
|
+
t.column :group, :string
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
# rename tables with reserved-word names
|
54
|
+
def test_rename_tables
|
55
|
+
assert_nothing_raised { @connection.rename_table(:group, :order) }
|
56
|
+
end
|
57
|
+
|
58
|
+
# alter column with a reserved-word name in a table with a reserved-word name
|
59
|
+
def test_change_columns
|
60
|
+
assert_nothing_raised { @connection.change_column_default(:group, :order, 'whatever') }
|
61
|
+
#the quoting here will reveal any double quoting issues in change_column's interaction with the column method in the adapter
|
62
|
+
assert_nothing_raised { @connection.change_column('group', 'order', :Int, :default => 0) }
|
63
|
+
assert_nothing_raised { @connection.rename_column(:group, :order, :values) }
|
64
|
+
end
|
65
|
+
|
66
|
+
# dump structure of table with reserved word name
|
67
|
+
def test_structure_dump
|
68
|
+
assert_nothing_raised { @connection.structure_dump }
|
69
|
+
end
|
70
|
+
|
71
|
+
# introspect table with reserved word name
|
72
|
+
def test_introspect
|
73
|
+
assert_nothing_raised { @connection.columns(:group) }
|
74
|
+
assert_nothing_raised { @connection.indexes(:group) }
|
75
|
+
end
|
76
|
+
|
77
|
+
#fixtures
|
78
|
+
self.use_instantiated_fixtures = true
|
79
|
+
self.use_transactional_fixtures = false
|
80
|
+
|
81
|
+
#fixtures :group
|
82
|
+
|
83
|
+
def test_fixtures
|
84
|
+
f = create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
85
|
+
|
86
|
+
assert_nothing_raised {
|
87
|
+
f.each do |x|
|
88
|
+
x.delete_existing_fixtures
|
89
|
+
end
|
90
|
+
}
|
91
|
+
|
92
|
+
assert_nothing_raised {
|
93
|
+
f.each do |x|
|
94
|
+
x.insert_fixtures
|
95
|
+
end
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
#activerecord model class with reserved-word table name
|
100
|
+
def test_activerecord_model
|
101
|
+
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
102
|
+
x = nil
|
103
|
+
assert_nothing_raised { x = Group.new }
|
104
|
+
x.order = 'x'
|
105
|
+
assert_nothing_raised { x.save }
|
106
|
+
x.order = 'y'
|
107
|
+
assert_nothing_raised { x.save }
|
108
|
+
assert_nothing_raised { y = Group.find_by_order('y') }
|
109
|
+
assert_nothing_raised { y = Group.find(1) }
|
110
|
+
x = Group.find(1)
|
111
|
+
end
|
112
|
+
|
113
|
+
# has_one association with reserved-word table name
|
114
|
+
def test_has_one_associations
|
115
|
+
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
116
|
+
v = nil
|
117
|
+
assert_nothing_raised { v = Group.find(1).values }
|
118
|
+
assert_equal v.id, 2
|
119
|
+
end
|
120
|
+
|
121
|
+
# belongs_to association with reserved-word table name
|
122
|
+
def test_belongs_to_associations
|
123
|
+
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
124
|
+
gs = nil
|
125
|
+
assert_nothing_raised { gs = Select.find(2).groups }
|
126
|
+
assert_equal gs.length, 2
|
127
|
+
assert(gs.collect{|x| x.id}.sort == [2, 3])
|
128
|
+
end
|
129
|
+
|
130
|
+
# has_and_belongs_to_many with reserved-word table name
|
131
|
+
def test_has_and_belongs_to_many
|
132
|
+
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
|
133
|
+
s = nil
|
134
|
+
assert_nothing_raised { s = Distinct.find(1).selects }
|
135
|
+
assert_equal s.length, 2
|
136
|
+
assert(s.collect{|x|x.id}.sort == [1, 2])
|
137
|
+
end
|
138
|
+
|
139
|
+
# activerecord model introspection with reserved-word table and column names
|
140
|
+
def test_activerecord_introspection
|
141
|
+
assert_nothing_raised { Group.table_exists? }
|
142
|
+
assert_nothing_raised { Group.columns }
|
143
|
+
end
|
144
|
+
|
145
|
+
# Calculations
|
146
|
+
def test_calculations_work_with_reserved_words
|
147
|
+
assert_nothing_raised { Group.count }
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_associations_work_with_reserved_words
|
151
|
+
assert_nothing_raised { Select.find(:all, :include => [:groups]) }
|
152
|
+
end
|
153
|
+
|
154
|
+
#the following functions were added to DRY test cases
|
155
|
+
|
156
|
+
private
|
157
|
+
# custom fixture loader, uses Fixtures#create_fixtures and appends base_path to the current file's path
|
158
|
+
def create_test_fixtures(*fixture_names)
|
159
|
+
fixture_path = "./test/fixtures/reserved_words"
|
160
|
+
Fixtures.create_fixtures(fixture_path, fixture_names)
|
161
|
+
end
|
162
|
+
|
163
|
+
# custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name
|
164
|
+
def drop_tables_directly(table_names, connection = @connection)
|
165
|
+
table_names.each do |name|
|
166
|
+
connection.execute("DROP TABLE IF EXISTS `#{name}`")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns
|
171
|
+
def create_tables_directly (tables, connection = @connection)
|
172
|
+
tables.each do |table_name, column_properties|
|
173
|
+
connection.execute("CREATE TABLE `#{table_name}` ( #{column_properties} )")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
data/test/schema_dumper_test.rb
CHANGED
@@ -19,6 +19,11 @@ if ActiveRecord::Base.connection.respond_to?(:tables)
|
|
19
19
|
assert_no_match %r{create_table "schema_info"}, output
|
20
20
|
end
|
21
21
|
|
22
|
+
def test_schema_dump_excludes_sqlite_sequence
|
23
|
+
output = standard_dump
|
24
|
+
assert_no_match %r{create_table "sqlite_sequence"}, output
|
25
|
+
end
|
26
|
+
|
22
27
|
def assert_line_up(lines, pattern, required = false)
|
23
28
|
return assert(true) if lines.empty?
|
24
29
|
matches = lines.map { |line| line.match(pattern) }
|
@@ -27,11 +32,27 @@ if ActiveRecord::Base.connection.respond_to?(:tables)
|
|
27
32
|
return assert(true) if matches.empty?
|
28
33
|
assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
|
29
34
|
end
|
35
|
+
|
36
|
+
def column_definition_lines(output = standard_dump)
|
37
|
+
output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_types_line_up
|
41
|
+
column_definition_lines.each do |column_set|
|
42
|
+
next if column_set.empty?
|
43
|
+
|
44
|
+
lengths = column_set.map do |column|
|
45
|
+
if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
|
46
|
+
match[0].length
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
assert_equal 1, lengths.uniq.length
|
51
|
+
end
|
52
|
+
end
|
30
53
|
|
31
54
|
def test_arguments_line_up
|
32
|
-
|
33
|
-
output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }.each do |column_set|
|
34
|
-
assert_line_up(column_set, /:(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)/, true)
|
55
|
+
column_definition_lines.each do |column_set|
|
35
56
|
assert_line_up(column_set, /:default => /)
|
36
57
|
assert_line_up(column_set, /:limit => /)
|
37
58
|
assert_line_up(column_set, /:null => /)
|
@@ -84,6 +105,20 @@ if ActiveRecord::Base.connection.respond_to?(:tables)
|
|
84
105
|
end
|
85
106
|
end
|
86
107
|
|
108
|
+
if current_adapter?(:MysqlAdapter)
|
109
|
+
def test_schema_dump_should_not_add_default_value_for_mysql_text_field
|
110
|
+
output = standard_dump
|
111
|
+
assert_match %r{t.text\s+"body",\s+:default => "",\s+:null => false$}, output
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_mysql_schema_dump_should_honor_nonstandard_primary_keys
|
115
|
+
output = standard_dump
|
116
|
+
match = output.match(%r{create_table "movies"(.*)do})
|
117
|
+
assert_not_nil(match, "nonstandardpk table not found")
|
118
|
+
assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
87
122
|
def test_schema_dump_includes_decimal_options
|
88
123
|
stream = StringIO.new
|
89
124
|
ActiveRecord::SchemaDumper.ignore_tables = [/^[^n]/]
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/contact'
|
3
|
+
|
4
|
+
class SerializationTest < Test::Unit::TestCase
|
5
|
+
FORMATS = [ :xml, :json ]
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@contact_attributes = {
|
9
|
+
:name => 'aaron stack',
|
10
|
+
:age => 25,
|
11
|
+
:avatar => 'binarydata',
|
12
|
+
:created_at => Time.utc(2006, 8, 1),
|
13
|
+
:awesome => false,
|
14
|
+
:preferences => { :gem => '<strong>ruby</strong>' }
|
15
|
+
}
|
16
|
+
|
17
|
+
@contact = Contact.new(@contact_attributes)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_serialize_should_be_reversible
|
21
|
+
for format in FORMATS
|
22
|
+
@serialized = Contact.new.send("to_#{format}")
|
23
|
+
contact = Contact.new.send("from_#{format}", @serialized)
|
24
|
+
|
25
|
+
assert_equal @contact_attributes.keys.collect(&:to_s).sort, contact.attributes.keys.collect(&:to_s).sort, "For #{format}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_serialize_should_allow_attribute_only_filtering
|
30
|
+
for format in FORMATS
|
31
|
+
@serialized = Contact.new(@contact_attributes).send("to_#{format}", :only => [ :age, :name ])
|
32
|
+
contact = Contact.new.send("from_#{format}", @serialized)
|
33
|
+
assert_equal @contact_attributes[:name], contact.name, "For #{format}"
|
34
|
+
assert_nil contact.avatar, "For #{format}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_serialize_should_allow_attribute_except_filtering
|
39
|
+
for format in FORMATS
|
40
|
+
@serialized = Contact.new(@contact_attributes).send("to_#{format}", :except => [ :age, :name ])
|
41
|
+
contact = Contact.new.send("from_#{format}", @serialized)
|
42
|
+
assert_nil contact.name, "For #{format}"
|
43
|
+
assert_nil contact.age, "For #{format}"
|
44
|
+
assert_equal @contact_attributes[:awesome], contact.awesome, "For #{format}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/test/transactions_test.rb
CHANGED
@@ -81,32 +81,12 @@ class TransactionTest < Test::Unit::TestCase
|
|
81
81
|
|
82
82
|
assert @first.approved?, "First should still be changed in the objects"
|
83
83
|
assert !@second.approved?, "Second should still be changed in the objects"
|
84
|
-
|
84
|
+
|
85
85
|
assert !Topic.find(1).approved?, "First shouldn't have been approved"
|
86
86
|
assert Topic.find(2).approved?, "Second should still be approved"
|
87
87
|
end
|
88
|
-
|
89
|
-
def test_failing_with_object_rollback
|
90
|
-
assert !@first.approved?, "First should be unapproved initially"
|
91
88
|
|
92
|
-
|
93
|
-
assert_deprecated /Object transactions/ do
|
94
|
-
Topic.transaction(@first, @second) do
|
95
|
-
@first.approved = true
|
96
|
-
@second.approved = false
|
97
|
-
@first.save
|
98
|
-
@second.save
|
99
|
-
raise "Bad things!"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
rescue
|
103
|
-
# caught it
|
104
|
-
end
|
105
|
-
|
106
|
-
assert !@first.approved?, "First shouldn't have been approved"
|
107
|
-
assert @second.approved?, "Second should still be approved"
|
108
|
-
end
|
109
|
-
|
89
|
+
|
110
90
|
def test_callback_rollback_in_save
|
111
91
|
add_exception_raising_after_save_callback_to_topic
|
112
92
|
|
@@ -122,6 +102,38 @@ class TransactionTest < Test::Unit::TestCase
|
|
122
102
|
end
|
123
103
|
end
|
124
104
|
|
105
|
+
def test_callback_rollback_in_create
|
106
|
+
new_topic = Topic.new(
|
107
|
+
:title => "A new topic",
|
108
|
+
:author_name => "Ben",
|
109
|
+
:author_email_address => "ben@example.com",
|
110
|
+
:written_on => "2003-07-16t15:28:11.2233+01:00",
|
111
|
+
:last_read => "2004-04-15",
|
112
|
+
:bonus_time => "2005-01-30t15:28:00.00+01:00",
|
113
|
+
:content => "Have a nice day",
|
114
|
+
:approved => false)
|
115
|
+
new_record_snapshot = new_topic.new_record?
|
116
|
+
id_present = new_topic.has_attribute?(Topic.primary_key)
|
117
|
+
id_snapshot = new_topic.id
|
118
|
+
|
119
|
+
# Make sure the second save gets the after_create callback called.
|
120
|
+
2.times do
|
121
|
+
begin
|
122
|
+
add_exception_raising_after_create_callback_to_topic
|
123
|
+
new_topic.approved = true
|
124
|
+
new_topic.save
|
125
|
+
flunk
|
126
|
+
rescue => e
|
127
|
+
assert_equal "Make the transaction rollback", e.message
|
128
|
+
assert_equal new_record_snapshot, new_topic.new_record?, "The topic should have its old new_record value"
|
129
|
+
assert_equal id_snapshot, new_topic.id, "The topic should have its old id"
|
130
|
+
assert_equal id_present, new_topic.has_attribute?(Topic.primary_key)
|
131
|
+
ensure
|
132
|
+
remove_exception_raising_after_create_callback_to_topic
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
125
137
|
def test_nested_explicit_transactions
|
126
138
|
Topic.transaction do
|
127
139
|
Topic.transaction do
|
@@ -136,14 +148,53 @@ class TransactionTest < Test::Unit::TestCase
|
|
136
148
|
assert !Topic.find(2).approved?, "Second should have been unapproved"
|
137
149
|
end
|
138
150
|
|
151
|
+
def test_manually_rolling_back_a_transaction
|
152
|
+
Topic.transaction do
|
153
|
+
@first.approved = true
|
154
|
+
@second.approved = false
|
155
|
+
@first.save
|
156
|
+
@second.save
|
157
|
+
|
158
|
+
raise ActiveRecord::Rollback
|
159
|
+
end
|
160
|
+
|
161
|
+
assert @first.approved?, "First should still be changed in the objects"
|
162
|
+
assert !@second.approved?, "Second should still be changed in the objects"
|
163
|
+
|
164
|
+
assert !Topic.find(1).approved?, "First shouldn't have been approved"
|
165
|
+
assert Topic.find(2).approved?, "Second should still be approved"
|
166
|
+
end
|
167
|
+
|
168
|
+
uses_mocha 'mocking connection.commit_db_transaction' do
|
169
|
+
def test_rollback_when_commit_raises
|
170
|
+
Topic.connection.expects(:begin_db_transaction)
|
171
|
+
Topic.connection.expects(:commit_db_transaction).raises('OH NOES')
|
172
|
+
Topic.connection.expects(:rollback_db_transaction)
|
173
|
+
|
174
|
+
assert_raise RuntimeError do
|
175
|
+
Topic.transaction do
|
176
|
+
# do nothing
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
139
182
|
private
|
140
183
|
def add_exception_raising_after_save_callback_to_topic
|
141
184
|
Topic.class_eval { def after_save() raise "Make the transaction rollback" end }
|
142
185
|
end
|
143
|
-
|
186
|
+
|
144
187
|
def remove_exception_raising_after_save_callback_to_topic
|
145
188
|
Topic.class_eval { remove_method :after_save }
|
146
189
|
end
|
190
|
+
|
191
|
+
def add_exception_raising_after_create_callback_to_topic
|
192
|
+
Topic.class_eval { def after_create() raise "Make the transaction rollback" end }
|
193
|
+
end
|
194
|
+
|
195
|
+
def remove_exception_raising_after_create_callback_to_topic
|
196
|
+
Topic.class_eval { remove_method :after_create }
|
197
|
+
end
|
147
198
|
end
|
148
199
|
|
149
200
|
if current_adapter?(:PostgreSQLAdapter)
|