db2 2.6.2 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +17 -0
- data/README +79 -141
- data/ext/Makefile.nt32 +3 -3
- data/ext/Makefile.nt32.191 +212 -0
- data/ext/extconf.rb +75 -14
- data/ext/ibm_db.c +504 -47
- data/ext/ruby_ibm_db.h +4 -1
- data/ext/ruby_ibm_db_cli.c +108 -1
- data/ext/ruby_ibm_db_cli.h +54 -1
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +423 -124
- data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1 -1
- data/test/cases/adapter_test.rb +169 -164
- data/test/cases/associations/belongs_to_associations_test.rb +268 -43
- data/test/cases/associations/cascaded_eager_loading_test.rb +31 -33
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +90 -156
- data/test/cases/associations/join_model_test.rb +100 -150
- data/test/cases/attribute_methods_test.rb +259 -58
- data/test/cases/base_test.rb +785 -138
- data/test/cases/calculations_test.rb +128 -8
- data/test/cases/migration_test.rb +680 -286
- data/test/cases/persistence_test.rb +642 -0
- data/test/cases/query_cache_test.rb +257 -0
- data/test/cases/relations_test.rb +1182 -0
- data/test/cases/schema_dumper_test.rb +41 -17
- data/test/cases/transaction_callbacks_test.rb +300 -0
- data/test/cases/validations/uniqueness_validation_test.rb +38 -22
- data/test/cases/xml_serialization_test.rb +408 -0
- data/test/config.yml +154 -0
- data/test/connections/native_ibm_db/connection.rb +2 -0
- data/test/models/warehouse_thing.rb +4 -4
- data/test/schema/i5/ibm_db_specific_schema.rb +3 -1
- data/test/schema/ids/ibm_db_specific_schema.rb +3 -1
- data/test/schema/luw/ibm_db_specific_schema.rb +2 -0
- data/test/schema/schema.rb +196 -92
- data/test/schema/zOS/ibm_db_specific_schema.rb +3 -1
- metadata +73 -68
- data/.gitignore +0 -1
- data/test/cases/associations/eager_test.rb +0 -862
- data/test/cases/associations/has_many_through_associations_test.rb +0 -461
- data/test/cases/finder_test.rb +0 -1088
- data/test/cases/fixtures_test.rb +0 -684
data/test/cases/base_test.rb
CHANGED
@@ -18,10 +18,22 @@ require 'models/comment'
|
|
18
18
|
require 'models/minimalistic'
|
19
19
|
require 'models/warehouse_thing'
|
20
20
|
require 'models/parrot'
|
21
|
-
require 'models/
|
21
|
+
require 'models/person'
|
22
|
+
require 'models/edge'
|
23
|
+
require 'models/joke'
|
24
|
+
require 'models/bulb'
|
25
|
+
require 'models/bird'
|
22
26
|
require 'rexml/document'
|
23
27
|
require 'active_support/core_ext/exception'
|
28
|
+
require 'bcrypt'
|
24
29
|
|
30
|
+
class FirstAbstractClass < ActiveRecord::Base
|
31
|
+
self.abstract_class = true
|
32
|
+
end
|
33
|
+
class SecondAbstractClass < FirstAbstractClass
|
34
|
+
self.abstract_class = true
|
35
|
+
end
|
36
|
+
class Photo < SecondAbstractClass; end
|
25
37
|
class Category < ActiveRecord::Base; end
|
26
38
|
class Categorization < ActiveRecord::Base; end
|
27
39
|
class Smarts < ActiveRecord::Base; end
|
@@ -43,10 +55,117 @@ class ReadonlyTitlePost < Post
|
|
43
55
|
attr_readonly :title
|
44
56
|
end
|
45
57
|
|
58
|
+
class ProtectedTitlePost < Post
|
59
|
+
attr_protected :title
|
60
|
+
end
|
61
|
+
|
62
|
+
class Weird < ActiveRecord::Base; end
|
63
|
+
|
46
64
|
class Boolean < ActiveRecord::Base; end
|
47
65
|
|
66
|
+
class LintTest < ActiveRecord::TestCase
|
67
|
+
include ActiveModel::Lint::Tests
|
68
|
+
|
69
|
+
class LintModel < ActiveRecord::Base; end
|
70
|
+
|
71
|
+
def setup
|
72
|
+
@model = LintModel.new
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
48
76
|
class BasicsTest < ActiveRecord::TestCase
|
49
|
-
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics,
|
77
|
+
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse_things', :authors, :categorizations, :categories, :posts
|
78
|
+
|
79
|
+
def test_generated_methods_modules
|
80
|
+
modules = Computer.ancestors
|
81
|
+
assert modules.include?(Computer::GeneratedFeatureMethods)
|
82
|
+
assert_equal(Computer::GeneratedFeatureMethods, Computer.generated_feature_methods)
|
83
|
+
assert(modules.index(Computer.generated_attribute_methods) > modules.index(Computer.generated_feature_methods),
|
84
|
+
"generated_attribute_methods must be higher in inheritance hierarchy than generated_feature_methods")
|
85
|
+
assert_not_equal Computer.generated_feature_methods, Post.generated_feature_methods
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_column_names_are_escaped
|
89
|
+
conn = ActiveRecord::Base.connection
|
90
|
+
classname = conn.class.name[/[^:]*$/]
|
91
|
+
badchar = {
|
92
|
+
'SQLite3Adapter' => '"',
|
93
|
+
'MysqlAdapter' => '`',
|
94
|
+
'Mysql2Adapter' => '`',
|
95
|
+
'PostgreSQLAdapter' => '"',
|
96
|
+
'OracleAdapter' => '"',
|
97
|
+
'IBM_DBAdapter' => '"'
|
98
|
+
}.fetch(classname) {
|
99
|
+
raise "need a bad char for #{classname}"
|
100
|
+
}
|
101
|
+
|
102
|
+
quoted = conn.quote_column_name "foo#{badchar}bar"
|
103
|
+
if current_adapter?(:OracleAdapter)
|
104
|
+
# Oracle does not allow double quotes in table and column names at all
|
105
|
+
# therefore quoting removes them
|
106
|
+
assert_equal("#{badchar}foobar#{badchar}", quoted)
|
107
|
+
elsif current_adapter?(:IBM_DBAdapter)
|
108
|
+
assert_equal("foo#{badchar}bar", quoted)
|
109
|
+
else
|
110
|
+
assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_columns_should_obey_set_primary_key
|
115
|
+
pk = Subscriber.columns.find { |x| x.name == 'nick' }
|
116
|
+
assert pk.primary, 'nick should be primary key'
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_primary_key_with_no_id
|
120
|
+
assert_nil Edge.primary_key
|
121
|
+
end
|
122
|
+
|
123
|
+
unless current_adapter?(:PostgreSQLAdapter,:OracleAdapter,:SQLServerAdapter, :IBM_DBAdapter)
|
124
|
+
def test_limit_with_comma
|
125
|
+
assert_nothing_raised do
|
126
|
+
Topic.limit("1,2").all
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_limit_without_comma
|
132
|
+
assert_nothing_raised do
|
133
|
+
assert_equal 1, Topic.limit("1").all.length
|
134
|
+
end
|
135
|
+
|
136
|
+
assert_nothing_raised do
|
137
|
+
assert_equal 1, Topic.limit(1).all.length
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_invalid_limit
|
142
|
+
assert_raises(ArgumentError) do
|
143
|
+
Topic.limit("asdfadf").all
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_limit_should_sanitize_sql_injection_for_limit_without_comas
|
148
|
+
assert_raises(ArgumentError) do
|
149
|
+
Topic.limit("1 select * from schema").all
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_limit_should_sanitize_sql_injection_for_limit_with_comas
|
154
|
+
assert_raises(ArgumentError) do
|
155
|
+
Topic.limit("1, 7 procedure help()").all
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
unless current_adapter?(:MysqlAdapter) || current_adapter?(:Mysql2Adapter) || current_adapter?(:IBM_DBAdapter)
|
160
|
+
def test_limit_should_allow_sql_literal
|
161
|
+
assert_equal 1, Topic.limit(Arel.sql('2-1')).all.length
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_select_symbol
|
166
|
+
topic_ids = Topic.select(:id).map(&:id).sort
|
167
|
+
assert_equal Topic.all.map(&:id).sort, topic_ids
|
168
|
+
end
|
50
169
|
|
51
170
|
def test_table_exists
|
52
171
|
assert !NonExistentTable.table_exists?
|
@@ -69,24 +188,6 @@ class BasicsTest < ActiveRecord::TestCase
|
|
69
188
|
end
|
70
189
|
end
|
71
190
|
|
72
|
-
def test_use_table_engine_for_quoting_where
|
73
|
-
relation = Topic.where(Topic.arel_table[:id].eq(1))
|
74
|
-
engine = relation.table.engine
|
75
|
-
|
76
|
-
fakepool = Class.new(Struct.new(:spec)) {
|
77
|
-
def with_connection; yield self; end
|
78
|
-
def connection_pool; self; end
|
79
|
-
def quote_table_name(*args); raise "lol quote_table_name"; end
|
80
|
-
}
|
81
|
-
|
82
|
-
relation.table.engine = fakepool.new(engine.connection_pool.spec)
|
83
|
-
|
84
|
-
error = assert_raises(RuntimeError) { relation.to_a }
|
85
|
-
assert_match('lol', error.message)
|
86
|
-
ensure
|
87
|
-
relation.table.engine = engine
|
88
|
-
end
|
89
|
-
|
90
191
|
def test_preserving_time_objects
|
91
192
|
assert_kind_of(
|
92
193
|
Time, Topic.find(1).bonus_time,
|
@@ -111,7 +212,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
111
212
|
with_active_record_default_timezone :utc do
|
112
213
|
time = Time.local(2000)
|
113
214
|
topic = Topic.create('written_on' => time)
|
114
|
-
saved_time = Topic.find(topic.id).written_on
|
215
|
+
saved_time = Topic.find(topic.id).reload.written_on
|
115
216
|
assert_equal time, saved_time
|
116
217
|
assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "EST"], time.to_a
|
117
218
|
assert_equal [0, 0, 5, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
|
@@ -125,7 +226,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
125
226
|
Time.use_zone 'Central Time (US & Canada)' do
|
126
227
|
time = Time.zone.local(2000)
|
127
228
|
topic = Topic.create('written_on' => time)
|
128
|
-
saved_time = Topic.find(topic.id).written_on
|
229
|
+
saved_time = Topic.find(topic.id).reload.written_on
|
129
230
|
assert_equal time, saved_time
|
130
231
|
assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
|
131
232
|
assert_equal [0, 0, 6, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
|
@@ -138,7 +239,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
138
239
|
with_env_tz 'America/New_York' do
|
139
240
|
time = Time.utc(2000)
|
140
241
|
topic = Topic.create('written_on' => time)
|
141
|
-
saved_time = Topic.find(topic.id).written_on
|
242
|
+
saved_time = Topic.find(topic.id).reload.written_on
|
142
243
|
assert_equal time, saved_time
|
143
244
|
assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], time.to_a
|
144
245
|
assert_equal [0, 0, 19, 31, 12, 1999, 5, 365, false, "EST"], saved_time.to_a
|
@@ -151,7 +252,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
151
252
|
Time.use_zone 'Central Time (US & Canada)' do
|
152
253
|
time = Time.zone.local(2000)
|
153
254
|
topic = Topic.create('written_on' => time)
|
154
|
-
saved_time = Topic.find(topic.id).written_on
|
255
|
+
saved_time = Topic.find(topic.id).reload.written_on
|
155
256
|
assert_equal time, saved_time
|
156
257
|
assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
|
157
258
|
assert_equal [0, 0, 1, 1, 1, 2000, 6, 1, false, "EST"], saved_time.to_a
|
@@ -177,7 +278,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
177
278
|
|
178
279
|
def test_initialize_with_invalid_attribute
|
179
280
|
begin
|
180
|
-
|
281
|
+
Topic.new({ "title" => "test",
|
181
282
|
"last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
|
182
283
|
rescue ActiveRecord::MultiparameterAssignmentErrors => ex
|
183
284
|
assert_equal(1, ex.errors.size)
|
@@ -185,6 +286,41 @@ class BasicsTest < ActiveRecord::TestCase
|
|
185
286
|
end
|
186
287
|
end
|
187
288
|
|
289
|
+
def test_create_after_initialize_without_block
|
290
|
+
cb = CustomBulb.create(:name => 'Dude')
|
291
|
+
assert_equal('Dude', cb.name)
|
292
|
+
assert_equal(true, cb.frickinawesome)
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_create_after_initialize_with_block
|
296
|
+
cb = CustomBulb.create {|c| c.name = 'Dude' }
|
297
|
+
assert_equal('Dude', cb.name)
|
298
|
+
assert_equal(true, cb.frickinawesome)
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_first_or_create
|
302
|
+
parrot = Bird.first_or_create(:color => 'green', :name => 'parrot')
|
303
|
+
assert parrot.persisted?
|
304
|
+
the_same_parrot = Bird.first_or_create(:color => 'yellow', :name => 'macaw')
|
305
|
+
assert_equal parrot, the_same_parrot
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_first_or_create_bang
|
309
|
+
assert_raises(ActiveRecord::RecordInvalid) { Bird.first_or_create! }
|
310
|
+
parrot = Bird.first_or_create!(:color => 'green', :name => 'parrot')
|
311
|
+
assert parrot.persisted?
|
312
|
+
the_same_parrot = Bird.first_or_create!(:color => 'yellow', :name => 'macaw')
|
313
|
+
assert_equal parrot, the_same_parrot
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_first_or_initialize
|
317
|
+
parrot = Bird.first_or_initialize(:color => 'green', :name => 'parrot')
|
318
|
+
assert_kind_of Bird, parrot
|
319
|
+
assert !parrot.persisted?
|
320
|
+
assert parrot.new_record?
|
321
|
+
assert parrot.valid?
|
322
|
+
end
|
323
|
+
|
188
324
|
def test_load
|
189
325
|
topics = Topic.find(:all, :order => 'id')
|
190
326
|
assert_equal(4, topics.size)
|
@@ -302,6 +438,15 @@ class BasicsTest < ActiveRecord::TestCase
|
|
302
438
|
GUESSED_CLASSES.each(&:reset_table_name)
|
303
439
|
end
|
304
440
|
|
441
|
+
def test_singular_table_name_guesses_for_individual_table
|
442
|
+
CreditCard.pluralize_table_names = false
|
443
|
+
CreditCard.reset_table_name
|
444
|
+
assert_equal "credit_card", CreditCard.table_name
|
445
|
+
assert_equal "categories", Category.table_name
|
446
|
+
ensure
|
447
|
+
CreditCard.pluralize_table_names = true
|
448
|
+
CreditCard.reset_table_name
|
449
|
+
end
|
305
450
|
|
306
451
|
if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
|
307
452
|
def test_update_all_with_order_and_limit
|
@@ -384,6 +529,10 @@ class BasicsTest < ActiveRecord::TestCase
|
|
384
529
|
assert_equal Topic.find(1), Topic.find(2).topic
|
385
530
|
end
|
386
531
|
|
532
|
+
def test_find_by_slug
|
533
|
+
assert_equal Topic.find('1-meowmeow'), Topic.find(1)
|
534
|
+
end
|
535
|
+
|
387
536
|
def test_equality_of_new_records
|
388
537
|
assert_not_equal Topic.new, Topic.new
|
389
538
|
end
|
@@ -401,6 +550,19 @@ class BasicsTest < ActiveRecord::TestCase
|
|
401
550
|
assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
|
402
551
|
end
|
403
552
|
|
553
|
+
def test_comparison
|
554
|
+
topic_1 = Topic.create!
|
555
|
+
topic_2 = Topic.create!
|
556
|
+
|
557
|
+
assert_equal [topic_2, topic_1].sort, [topic_1, topic_2]
|
558
|
+
end
|
559
|
+
|
560
|
+
def test_comparison_with_different_objects
|
561
|
+
topic = Topic.create
|
562
|
+
category = Category.create(:name => "comparison")
|
563
|
+
assert_nil topic <=> category
|
564
|
+
end
|
565
|
+
|
404
566
|
def test_readonly_attributes
|
405
567
|
assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes
|
406
568
|
|
@@ -414,6 +576,18 @@ class BasicsTest < ActiveRecord::TestCase
|
|
414
576
|
assert_equal "changed", post.body
|
415
577
|
end
|
416
578
|
|
579
|
+
def test_non_valid_identifier_column_name
|
580
|
+
weird = Weird.create('a$b' => 'value')
|
581
|
+
weird.reload
|
582
|
+
assert_equal 'value', weird.send('a$b')
|
583
|
+
assert_equal 'value', weird.read_attribute('a$b')
|
584
|
+
|
585
|
+
weird.update_column('a$b', 'value2')
|
586
|
+
weird.reload
|
587
|
+
assert_equal 'value2', weird.send('a$b')
|
588
|
+
assert_equal 'value2', weird.read_attribute('a$b')
|
589
|
+
end
|
590
|
+
|
417
591
|
def test_multiparameter_attributes_on_date
|
418
592
|
attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" }
|
419
593
|
topic = Topic.find(1)
|
@@ -429,7 +603,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
429
603
|
topic.attributes = attributes
|
430
604
|
# note that extra #to_date call allows test to pass for Oracle, which
|
431
605
|
# treats dates/times the same
|
432
|
-
|
606
|
+
assert_nil topic.last_read
|
433
607
|
end
|
434
608
|
|
435
609
|
def test_multiparameter_attributes_on_date_with_empty_month
|
@@ -438,7 +612,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
438
612
|
topic.attributes = attributes
|
439
613
|
# note that extra #to_date call allows test to pass for Oracle, which
|
440
614
|
# treats dates/times the same
|
441
|
-
|
615
|
+
assert_nil topic.last_read
|
442
616
|
end
|
443
617
|
|
444
618
|
def test_multiparameter_attributes_on_date_with_empty_day
|
@@ -447,7 +621,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
447
621
|
topic.attributes = attributes
|
448
622
|
# note that extra #to_date call allows test to pass for Oracle, which
|
449
623
|
# treats dates/times the same
|
450
|
-
|
624
|
+
assert_nil topic.last_read
|
451
625
|
end
|
452
626
|
|
453
627
|
def test_multiparameter_attributes_on_date_with_empty_day_and_year
|
@@ -456,7 +630,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
456
630
|
topic.attributes = attributes
|
457
631
|
# note that extra #to_date call allows test to pass for Oracle, which
|
458
632
|
# treats dates/times the same
|
459
|
-
|
633
|
+
assert_nil topic.last_read
|
460
634
|
end
|
461
635
|
|
462
636
|
def test_multiparameter_attributes_on_date_with_empty_day_and_month
|
@@ -465,7 +639,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
465
639
|
topic.attributes = attributes
|
466
640
|
# note that extra #to_date call allows test to pass for Oracle, which
|
467
641
|
# treats dates/times the same
|
468
|
-
|
642
|
+
assert_nil topic.last_read
|
469
643
|
end
|
470
644
|
|
471
645
|
def test_multiparameter_attributes_on_date_with_empty_year_and_month
|
@@ -474,7 +648,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
474
648
|
topic.attributes = attributes
|
475
649
|
# note that extra #to_date call allows test to pass for Oracle, which
|
476
650
|
# treats dates/times the same
|
477
|
-
|
651
|
+
assert_nil topic.last_read
|
478
652
|
end
|
479
653
|
|
480
654
|
def test_multiparameter_attributes_on_date_with_all_empty
|
@@ -494,6 +668,29 @@ class BasicsTest < ActiveRecord::TestCase
|
|
494
668
|
assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
|
495
669
|
end
|
496
670
|
|
671
|
+
def test_multiparameter_attributes_on_time_with_no_date
|
672
|
+
ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
|
673
|
+
attributes = {
|
674
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
|
675
|
+
}
|
676
|
+
topic = Topic.find(1)
|
677
|
+
topic.attributes = attributes
|
678
|
+
end
|
679
|
+
assert_equal("written_on", ex.errors[0].attribute)
|
680
|
+
end
|
681
|
+
|
682
|
+
def test_multiparameter_attributes_on_time_with_invalid_time_params
|
683
|
+
ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
|
684
|
+
attributes = {
|
685
|
+
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
686
|
+
"written_on(4i)" => "2004", "written_on(5i)" => "36", "written_on(6i)" => "64",
|
687
|
+
}
|
688
|
+
topic = Topic.find(1)
|
689
|
+
topic.attributes = attributes
|
690
|
+
end
|
691
|
+
assert_equal("written_on", ex.errors[0].attribute)
|
692
|
+
end
|
693
|
+
|
497
694
|
def test_multiparameter_attributes_on_time_with_old_date
|
498
695
|
attributes = {
|
499
696
|
"written_on(1i)" => "1850", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
@@ -505,6 +702,67 @@ class BasicsTest < ActiveRecord::TestCase
|
|
505
702
|
assert_equal "1850-06-24 16:24:00", topic.written_on.to_s(:db)
|
506
703
|
end
|
507
704
|
|
705
|
+
def test_multiparameter_attributes_on_time_will_raise_on_big_time_if_missing_date_parts
|
706
|
+
ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
|
707
|
+
attributes = {
|
708
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24"
|
709
|
+
}
|
710
|
+
topic = Topic.find(1)
|
711
|
+
topic.attributes = attributes
|
712
|
+
end
|
713
|
+
assert_equal("written_on", ex.errors[0].attribute)
|
714
|
+
end
|
715
|
+
|
716
|
+
def test_multiparameter_attributes_on_time_with_raise_on_small_time_if_missing_date_parts
|
717
|
+
ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
|
718
|
+
attributes = {
|
719
|
+
"written_on(4i)" => "16", "written_on(5i)" => "12", "written_on(6i)" => "02"
|
720
|
+
}
|
721
|
+
topic = Topic.find(1)
|
722
|
+
topic.attributes = attributes
|
723
|
+
end
|
724
|
+
assert_equal("written_on", ex.errors[0].attribute)
|
725
|
+
end
|
726
|
+
|
727
|
+
def test_multiparameter_attributes_on_time_will_ignore_hour_if_missing
|
728
|
+
attributes = {
|
729
|
+
"written_on(1i)" => "2004", "written_on(2i)" => "12", "written_on(3i)" => "12",
|
730
|
+
"written_on(5i)" => "12", "written_on(6i)" => "02"
|
731
|
+
}
|
732
|
+
topic = Topic.find(1)
|
733
|
+
topic.attributes = attributes
|
734
|
+
assert_equal Time.local(2004, 12, 12, 0, 12, 2), topic.written_on
|
735
|
+
end
|
736
|
+
|
737
|
+
def test_multiparameter_attributes_on_time_will_ignore_hour_if_blank
|
738
|
+
attributes = {
|
739
|
+
"written_on(1i)" => "", "written_on(2i)" => "", "written_on(3i)" => "",
|
740
|
+
"written_on(4i)" => "", "written_on(5i)" => "12", "written_on(6i)" => "02"
|
741
|
+
}
|
742
|
+
topic = Topic.find(1)
|
743
|
+
topic.attributes = attributes
|
744
|
+
assert_nil topic.written_on
|
745
|
+
end
|
746
|
+
|
747
|
+
def test_multiparameter_attributes_on_time_will_ignore_date_if_empty
|
748
|
+
attributes = {
|
749
|
+
"written_on(1i)" => "", "written_on(2i)" => "", "written_on(3i)" => "",
|
750
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24"
|
751
|
+
}
|
752
|
+
topic = Topic.find(1)
|
753
|
+
topic.attributes = attributes
|
754
|
+
assert_nil topic.written_on
|
755
|
+
end
|
756
|
+
def test_multiparameter_attributes_on_time_with_seconds_will_ignore_date_if_empty
|
757
|
+
attributes = {
|
758
|
+
"written_on(1i)" => "", "written_on(2i)" => "", "written_on(3i)" => "",
|
759
|
+
"written_on(4i)" => "16", "written_on(5i)" => "12", "written_on(6i)" => "02"
|
760
|
+
}
|
761
|
+
topic = Topic.find(1)
|
762
|
+
topic.attributes = attributes
|
763
|
+
assert_nil topic.written_on
|
764
|
+
end
|
765
|
+
|
508
766
|
def test_multiparameter_attributes_on_time_with_utc
|
509
767
|
ActiveRecord::Base.default_timezone = :utc
|
510
768
|
attributes = {
|
@@ -611,6 +869,42 @@ class BasicsTest < ActiveRecord::TestCase
|
|
611
869
|
assert_equal address, customer.address
|
612
870
|
end
|
613
871
|
|
872
|
+
def test_multiparameter_assignment_of_aggregation_out_of_order
|
873
|
+
customer = Customer.new
|
874
|
+
address = Address.new("The Street", "The City", "The Country")
|
875
|
+
attributes = { "address(3)" => address.country, "address(2)" => address.city, "address(1)" => address.street }
|
876
|
+
customer.attributes = attributes
|
877
|
+
assert_equal address, customer.address
|
878
|
+
end
|
879
|
+
|
880
|
+
def test_multiparameter_assignment_of_aggregation_with_missing_values
|
881
|
+
ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
|
882
|
+
customer = Customer.new
|
883
|
+
address = Address.new("The Street", "The City", "The Country")
|
884
|
+
attributes = { "address(2)" => address.city, "address(3)" => address.country }
|
885
|
+
customer.attributes = attributes
|
886
|
+
end
|
887
|
+
assert_equal("address", ex.errors[0].attribute)
|
888
|
+
end
|
889
|
+
|
890
|
+
def test_multiparameter_assignment_of_aggregation_with_blank_values
|
891
|
+
customer = Customer.new
|
892
|
+
address = Address.new("The Street", "The City", "The Country")
|
893
|
+
attributes = { "address(1)" => "", "address(2)" => address.city, "address(3)" => address.country }
|
894
|
+
customer.attributes = attributes
|
895
|
+
assert_equal Address.new(nil, "The City", "The Country"), customer.address
|
896
|
+
end
|
897
|
+
|
898
|
+
def test_multiparameter_assignment_of_aggregation_with_large_index
|
899
|
+
ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
|
900
|
+
customer = Customer.new
|
901
|
+
address = Address.new("The Street", "The City", "The Country")
|
902
|
+
attributes = { "address(1)" => "The Street", "address(2)" => address.city, "address(3000)" => address.country }
|
903
|
+
customer.attributes = attributes
|
904
|
+
end
|
905
|
+
assert_equal("address", ex.errors[0].attribute)
|
906
|
+
end
|
907
|
+
|
614
908
|
def test_attributes_on_dummy_time
|
615
909
|
# Oracle, and Sybase do not have a TIME datatype.
|
616
910
|
return true if current_adapter?(:OracleAdapter, :SybaseAdapter)
|
@@ -660,60 +954,65 @@ class BasicsTest < ActiveRecord::TestCase
|
|
660
954
|
assert_equal true, Topic.find(1).persisted?
|
661
955
|
end
|
662
956
|
|
663
|
-
def
|
957
|
+
def test_dup
|
664
958
|
topic = Topic.find(1)
|
665
|
-
|
666
|
-
assert_nothing_raised {
|
667
|
-
assert_equal topic.title,
|
668
|
-
assert !
|
959
|
+
duped_topic = nil
|
960
|
+
assert_nothing_raised { duped_topic = topic.dup }
|
961
|
+
assert_equal topic.title, duped_topic.title
|
962
|
+
assert !duped_topic.persisted?
|
669
963
|
|
670
|
-
# test if the attributes have been
|
964
|
+
# test if the attributes have been duped
|
671
965
|
topic.title = "a"
|
672
|
-
|
966
|
+
duped_topic.title = "b"
|
673
967
|
assert_equal "a", topic.title
|
674
|
-
assert_equal "b",
|
968
|
+
assert_equal "b", duped_topic.title
|
675
969
|
|
676
|
-
# test if the attribute values have been
|
970
|
+
# test if the attribute values have been duped
|
677
971
|
topic.title = {"a" => "b"}
|
678
|
-
|
679
|
-
|
972
|
+
duped_topic = topic.dup
|
973
|
+
duped_topic.title["a"] = "c"
|
680
974
|
assert_equal "b", topic.title["a"]
|
681
975
|
|
682
|
-
# test if attributes set as part of after_initialize are
|
683
|
-
assert_equal topic.author_email_address,
|
976
|
+
# test if attributes set as part of after_initialize are duped correctly
|
977
|
+
assert_equal topic.author_email_address, duped_topic.author_email_address
|
684
978
|
|
685
979
|
# test if saved clone object differs from original
|
686
|
-
|
687
|
-
assert
|
688
|
-
assert_not_equal
|
980
|
+
duped_topic.save
|
981
|
+
assert duped_topic.persisted?
|
982
|
+
assert_not_equal duped_topic.id, topic.id
|
983
|
+
|
984
|
+
duped_topic.reload
|
985
|
+
# FIXME: I think this is poor behavior, and will fix it with #5686
|
986
|
+
assert_equal({'a' => 'c'}.to_yaml, duped_topic.title)
|
689
987
|
end
|
690
988
|
|
691
|
-
def
|
989
|
+
def test_dup_with_aggregate_of_same_name_as_attribute
|
692
990
|
dev = DeveloperWithAggregate.find(1)
|
693
991
|
assert_kind_of DeveloperSalary, dev.salary
|
694
992
|
|
695
|
-
|
696
|
-
assert_nothing_raised {
|
697
|
-
assert_kind_of DeveloperSalary,
|
698
|
-
assert_equal dev.salary.amount,
|
699
|
-
assert !
|
993
|
+
dup = nil
|
994
|
+
assert_nothing_raised { dup = dev.dup }
|
995
|
+
assert_kind_of DeveloperSalary, dup.salary
|
996
|
+
assert_equal dev.salary.amount, dup.salary.amount
|
997
|
+
assert !dup.persisted?
|
700
998
|
|
701
|
-
# test if the attributes have been
|
702
|
-
original_amount =
|
999
|
+
# test if the attributes have been dupd
|
1000
|
+
original_amount = dup.salary.amount
|
703
1001
|
dev.salary.amount = 1
|
704
|
-
assert_equal original_amount,
|
1002
|
+
assert_equal original_amount, dup.salary.amount
|
705
1003
|
|
706
|
-
assert
|
707
|
-
assert
|
708
|
-
assert_not_equal
|
1004
|
+
assert dup.save
|
1005
|
+
assert dup.persisted?
|
1006
|
+
assert_not_equal dup.id, dev.id
|
709
1007
|
end
|
710
1008
|
|
711
|
-
def
|
1009
|
+
def test_dup_does_not_copy_associations
|
712
1010
|
author = authors(:david)
|
713
1011
|
assert_not_equal [], author.posts
|
1012
|
+
author.send(:clear_association_cache)
|
714
1013
|
|
715
|
-
|
716
|
-
assert_equal [],
|
1014
|
+
author_dup = author.dup
|
1015
|
+
assert_equal [], author_dup.posts
|
717
1016
|
end
|
718
1017
|
|
719
1018
|
def test_clone_preserves_subtype
|
@@ -752,24 +1051,24 @@ class BasicsTest < ActiveRecord::TestCase
|
|
752
1051
|
assert !cloned_developer.salary_changed? # ... and cloned instance should behave same
|
753
1052
|
end
|
754
1053
|
|
755
|
-
def
|
1054
|
+
def test_dup_of_saved_object_marks_attributes_as_dirty
|
756
1055
|
developer = Developer.create! :name => 'Bjorn', :salary => 100000
|
757
1056
|
assert !developer.name_changed?
|
758
1057
|
assert !developer.salary_changed?
|
759
1058
|
|
760
|
-
cloned_developer = developer.
|
1059
|
+
cloned_developer = developer.dup
|
761
1060
|
assert cloned_developer.name_changed? # both attributes differ from defaults
|
762
1061
|
assert cloned_developer.salary_changed?
|
763
1062
|
end
|
764
1063
|
|
765
|
-
def
|
1064
|
+
def test_dup_of_saved_object_marks_as_dirty_only_changed_attributes
|
766
1065
|
developer = Developer.create! :name => 'Bjorn'
|
767
|
-
assert !developer.name_changed? # both attributes of saved object should be
|
1066
|
+
assert !developer.name_changed? # both attributes of saved object should be treated as not changed
|
768
1067
|
assert !developer.salary_changed?
|
769
1068
|
|
770
|
-
cloned_developer = developer.
|
1069
|
+
cloned_developer = developer.dup
|
771
1070
|
assert cloned_developer.name_changed? # ... but on cloned object should be
|
772
|
-
assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be
|
1071
|
+
assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be treated as not changed on cloned instance
|
773
1072
|
end
|
774
1073
|
|
775
1074
|
def test_bignum
|
@@ -815,7 +1114,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
815
1114
|
assert g.save
|
816
1115
|
|
817
1116
|
# Reload and check that we have all the geometric attributes.
|
818
|
-
h = Geometric.find(g.id)
|
1117
|
+
h = ActiveRecord::IdentityMap.without { Geometric.find(g.id) }
|
819
1118
|
|
820
1119
|
assert_equal '(5,6.1)', h.a_point
|
821
1120
|
assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
|
@@ -843,7 +1142,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
843
1142
|
assert g.save
|
844
1143
|
|
845
1144
|
# Reload and check that we have all the geometric attributes.
|
846
|
-
h = Geometric.find(g.id)
|
1145
|
+
h = ActiveRecord::IdentityMap.without { Geometric.find(g.id) }
|
847
1146
|
|
848
1147
|
assert_equal '(5,6.1)', h.a_point
|
849
1148
|
assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
|
@@ -862,6 +1161,17 @@ class BasicsTest < ActiveRecord::TestCase
|
|
862
1161
|
self.table_name = 'numeric_data'
|
863
1162
|
end
|
864
1163
|
|
1164
|
+
def test_big_decimal_conditions
|
1165
|
+
m = NumericData.new(
|
1166
|
+
:bank_balance => 1586.43,
|
1167
|
+
:big_bank_balance => BigDecimal("1000234000567.95"),
|
1168
|
+
:world_population => 6000000000,
|
1169
|
+
:my_house_population => 3
|
1170
|
+
)
|
1171
|
+
assert m.save
|
1172
|
+
assert_equal 0, NumericData.where("bank_balance > ?", 2000.0).count
|
1173
|
+
end
|
1174
|
+
|
865
1175
|
def test_numeric_fields
|
866
1176
|
m = NumericData.new(
|
867
1177
|
:bank_balance => 1586.43,
|
@@ -881,13 +1191,14 @@ class BasicsTest < ActiveRecord::TestCase
|
|
881
1191
|
assert_kind_of Integer, m1.world_population
|
882
1192
|
else
|
883
1193
|
assert_kind_of BigDecimal, m1.world_population
|
884
|
-
end
|
1194
|
+
end
|
885
1195
|
assert_equal 6000000000, m1.world_population
|
1196
|
+
|
886
1197
|
unless current_adapter?(:IBM_DBAdapter)
|
887
1198
|
assert_kind_of Fixnum, m1.my_house_population
|
888
1199
|
else
|
889
1200
|
assert_kind_of BigDecimal, m1.my_house_population
|
890
|
-
end
|
1201
|
+
end
|
891
1202
|
assert_equal 3, m1.my_house_population
|
892
1203
|
|
893
1204
|
assert_kind_of BigDecimal, m1.bank_balance
|
@@ -903,19 +1214,6 @@ class BasicsTest < ActiveRecord::TestCase
|
|
903
1214
|
assert(auto.id > 0)
|
904
1215
|
end
|
905
1216
|
|
906
|
-
def quote_column_name(name)
|
907
|
-
"<#{name}>"
|
908
|
-
end
|
909
|
-
|
910
|
-
def test_quote_keys
|
911
|
-
ar = AutoId.new
|
912
|
-
source = {"foo" => "bar", "baz" => "quux"}
|
913
|
-
actual = ar.send(:quote_columns, self, source)
|
914
|
-
inverted = actual.invert
|
915
|
-
assert_equal("<foo>", inverted["bar"])
|
916
|
-
assert_equal("<baz>", inverted["quux"])
|
917
|
-
end
|
918
|
-
|
919
1217
|
def test_sql_injection_via_find
|
920
1218
|
assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
|
921
1219
|
Topic.find("123456 OR id > 0")
|
@@ -953,6 +1251,42 @@ class BasicsTest < ActiveRecord::TestCase
|
|
953
1251
|
assert_equal(myobj, topic.content)
|
954
1252
|
end
|
955
1253
|
|
1254
|
+
def test_serialized_attribute_in_base_class
|
1255
|
+
Topic.serialize("content", Hash)
|
1256
|
+
|
1257
|
+
hash = { 'content1' => 'value1', 'content2' => 'value2' }
|
1258
|
+
important_topic = ImportantTopic.create("content" => hash)
|
1259
|
+
assert_equal(hash, important_topic.content)
|
1260
|
+
|
1261
|
+
important_topic.reload
|
1262
|
+
assert_equal(hash, important_topic.content)
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
# This test was added to fix GH #4004. Obviously the value returned
|
1266
|
+
# is not really the value 'before type cast' so we should maybe think
|
1267
|
+
# about changing that in the future.
|
1268
|
+
def test_serialized_attribute_before_type_cast_returns_unserialized_value
|
1269
|
+
klass = Class.new(ActiveRecord::Base)
|
1270
|
+
klass.table_name = "topics"
|
1271
|
+
klass.serialize :content, Hash
|
1272
|
+
|
1273
|
+
t = klass.new(:content => { :foo => :bar })
|
1274
|
+
assert_equal({ :foo => :bar }, t.content_before_type_cast)
|
1275
|
+
t.save!
|
1276
|
+
t.reload
|
1277
|
+
assert_equal({ :foo => :bar }, t.content_before_type_cast)
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
def test_serialized_attribute_declared_in_subclass
|
1281
|
+
hash = { 'important1' => 'value1', 'important2' => 'value2' }
|
1282
|
+
important_topic = ImportantTopic.create("important" => hash)
|
1283
|
+
assert_equal(hash, important_topic.important)
|
1284
|
+
|
1285
|
+
important_topic.reload
|
1286
|
+
assert_equal(hash, important_topic.important)
|
1287
|
+
assert_equal(hash, important_topic.read_attribute(:important))
|
1288
|
+
end
|
1289
|
+
|
956
1290
|
def test_serialized_time_attribute
|
957
1291
|
myobj = Time.local(2008,1,1,1,0)
|
958
1292
|
topic = Topic.create("content" => myobj).reload
|
@@ -966,7 +1300,6 @@ class BasicsTest < ActiveRecord::TestCase
|
|
966
1300
|
end
|
967
1301
|
|
968
1302
|
def test_nil_serialized_attribute_with_class_constraint
|
969
|
-
myobj = MyObject.new('value1', 'value2')
|
970
1303
|
topic = Topic.new
|
971
1304
|
assert_nil topic.content
|
972
1305
|
end
|
@@ -976,7 +1309,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
976
1309
|
topic = Topic.new(:content => myobj)
|
977
1310
|
assert topic.save
|
978
1311
|
Topic.serialize(:content, Hash)
|
979
|
-
assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content }
|
1312
|
+
assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).reload.content }
|
980
1313
|
ensure
|
981
1314
|
Topic.serialize(:content)
|
982
1315
|
end
|
@@ -991,6 +1324,87 @@ class BasicsTest < ActiveRecord::TestCase
|
|
991
1324
|
Topic.serialize(:content)
|
992
1325
|
end
|
993
1326
|
|
1327
|
+
def test_serialized_default_class
|
1328
|
+
Topic.serialize(:content, Hash)
|
1329
|
+
topic = Topic.new
|
1330
|
+
assert_equal Hash, topic.content.class
|
1331
|
+
assert_equal Hash, topic.read_attribute(:content).class
|
1332
|
+
topic.content["beer"] = "MadridRb"
|
1333
|
+
assert topic.save
|
1334
|
+
topic.reload
|
1335
|
+
assert_equal Hash, topic.content.class
|
1336
|
+
assert_equal "MadridRb", topic.content["beer"]
|
1337
|
+
ensure
|
1338
|
+
Topic.serialize(:content)
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
def test_serialized_no_default_class_for_object
|
1342
|
+
topic = Topic.new
|
1343
|
+
assert_nil topic.content
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
def test_serialized_boolean_value_true
|
1347
|
+
Topic.serialize(:content)
|
1348
|
+
topic = Topic.new(:content => true)
|
1349
|
+
assert topic.save
|
1350
|
+
topic = topic.reload
|
1351
|
+
assert_equal topic.content, true
|
1352
|
+
end
|
1353
|
+
|
1354
|
+
def test_serialized_boolean_value_false
|
1355
|
+
Topic.serialize(:content)
|
1356
|
+
topic = Topic.new(:content => false)
|
1357
|
+
assert topic.save
|
1358
|
+
topic = topic.reload
|
1359
|
+
assert_equal topic.content, false
|
1360
|
+
end
|
1361
|
+
|
1362
|
+
def test_serialize_with_coder
|
1363
|
+
coder = Class.new {
|
1364
|
+
# Identity
|
1365
|
+
def load(thing)
|
1366
|
+
thing
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
# base 64
|
1370
|
+
def dump(thing)
|
1371
|
+
[thing].pack('m')
|
1372
|
+
end
|
1373
|
+
}.new
|
1374
|
+
|
1375
|
+
Topic.serialize(:content, coder)
|
1376
|
+
s = 'hello world'
|
1377
|
+
topic = Topic.new(:content => s)
|
1378
|
+
assert topic.save
|
1379
|
+
topic = topic.reload
|
1380
|
+
assert_equal [s].pack('m'), topic.content
|
1381
|
+
ensure
|
1382
|
+
Topic.serialize(:content)
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
def test_serialize_with_bcrypt_coder
|
1386
|
+
crypt_coder = Class.new {
|
1387
|
+
def load(thing)
|
1388
|
+
return unless thing
|
1389
|
+
BCrypt::Password.new thing
|
1390
|
+
end
|
1391
|
+
|
1392
|
+
def dump(thing)
|
1393
|
+
BCrypt::Password.create(thing).to_s
|
1394
|
+
end
|
1395
|
+
}.new
|
1396
|
+
|
1397
|
+
Topic.serialize(:content, crypt_coder)
|
1398
|
+
password = 'password'
|
1399
|
+
topic = Topic.new(:content => password)
|
1400
|
+
assert topic.save
|
1401
|
+
topic = topic.reload
|
1402
|
+
assert_kind_of BCrypt::Password, topic.content
|
1403
|
+
assert_equal(true, topic.content == password, 'password should equal')
|
1404
|
+
ensure
|
1405
|
+
Topic.serialize(:content)
|
1406
|
+
end
|
1407
|
+
|
994
1408
|
def test_quote
|
995
1409
|
author_name = "\\ \001 ' \n \\n \""
|
996
1410
|
topic = Topic.create('author_name' => author_name)
|
@@ -1039,72 +1453,211 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1039
1453
|
assert_equal dev, dev.reload
|
1040
1454
|
end
|
1041
1455
|
|
1042
|
-
def
|
1456
|
+
def test_set_table_name_with_value
|
1043
1457
|
k = Class.new( ActiveRecord::Base )
|
1044
|
-
k.
|
1458
|
+
k.table_name = "foo"
|
1045
1459
|
assert_equal "foo", k.table_name
|
1460
|
+
|
1461
|
+
assert_deprecated do
|
1462
|
+
k.set_table_name "bar"
|
1463
|
+
end
|
1464
|
+
assert_equal "bar", k.table_name
|
1046
1465
|
end
|
1047
1466
|
|
1048
|
-
def
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1467
|
+
def test_switching_between_table_name
|
1468
|
+
assert_difference("GoodJoke.count") do
|
1469
|
+
Joke.table_name = "cold_jokes"
|
1470
|
+
Joke.create
|
1471
|
+
|
1472
|
+
Joke.table_name = "funny_jokes"
|
1473
|
+
Joke.create
|
1474
|
+
end
|
1052
1475
|
end
|
1053
1476
|
|
1054
|
-
def
|
1055
|
-
|
1056
|
-
|
1057
|
-
assert_equal "foo", k.table_name
|
1058
|
-
k.set_table_name "bar"
|
1059
|
-
assert_equal "bar", k.table_name
|
1477
|
+
def test_set_table_name_symbol_converted_to_string
|
1478
|
+
Joke.table_name = :cold_jokes
|
1479
|
+
assert_equal 'cold_jokes', Joke.table_name
|
1060
1480
|
end
|
1061
1481
|
|
1062
1482
|
def test_quoted_table_name_after_set_table_name
|
1063
1483
|
klass = Class.new(ActiveRecord::Base)
|
1064
1484
|
|
1065
|
-
klass.
|
1485
|
+
klass.table_name = "foo"
|
1066
1486
|
assert_equal "foo", klass.table_name
|
1067
1487
|
assert_equal klass.connection.quote_table_name("foo"), klass.quoted_table_name
|
1068
1488
|
|
1069
|
-
klass.
|
1489
|
+
klass.table_name = "bar"
|
1070
1490
|
assert_equal "bar", klass.table_name
|
1071
1491
|
assert_equal klass.connection.quote_table_name("bar"), klass.quoted_table_name
|
1072
1492
|
end
|
1073
1493
|
|
1074
1494
|
def test_set_table_name_with_block
|
1075
1495
|
k = Class.new( ActiveRecord::Base )
|
1076
|
-
|
1077
|
-
|
1496
|
+
assert_deprecated do
|
1497
|
+
k.set_table_name "foo"
|
1498
|
+
k.set_table_name do
|
1499
|
+
ActiveSupport::Deprecation.silence { original_table_name } + "ks"
|
1500
|
+
end
|
1501
|
+
end
|
1502
|
+
assert_equal "fooks", k.table_name
|
1503
|
+
end
|
1504
|
+
|
1505
|
+
def test_set_table_name_with_inheritance
|
1506
|
+
k = Class.new( ActiveRecord::Base )
|
1507
|
+
def k.name; "Foo"; end
|
1508
|
+
def k.table_name; super + "ks"; end
|
1509
|
+
assert_equal "foosks", k.table_name
|
1510
|
+
end
|
1511
|
+
|
1512
|
+
def test_original_table_name
|
1513
|
+
k = Class.new(ActiveRecord::Base)
|
1514
|
+
def k.name; "Foo"; end
|
1515
|
+
k.table_name = "bar"
|
1516
|
+
|
1517
|
+
assert_deprecated do
|
1518
|
+
assert_equal "foos", k.original_table_name
|
1519
|
+
end
|
1520
|
+
|
1521
|
+
k = Class.new(ActiveRecord::Base)
|
1522
|
+
k.table_name = "omg"
|
1523
|
+
k.table_name = "wtf"
|
1524
|
+
|
1525
|
+
assert_deprecated do
|
1526
|
+
assert_equal "omg", k.original_table_name
|
1527
|
+
end
|
1078
1528
|
end
|
1079
1529
|
|
1080
1530
|
def test_set_primary_key_with_value
|
1081
1531
|
k = Class.new( ActiveRecord::Base )
|
1082
1532
|
k.primary_key = "foo"
|
1083
1533
|
assert_equal "foo", k.primary_key
|
1084
|
-
|
1534
|
+
|
1535
|
+
assert_deprecated do
|
1536
|
+
k.set_primary_key "bar"
|
1537
|
+
end
|
1085
1538
|
assert_equal "bar", k.primary_key
|
1086
1539
|
end
|
1087
1540
|
|
1088
1541
|
def test_set_primary_key_with_block
|
1089
1542
|
k = Class.new( ActiveRecord::Base )
|
1090
|
-
k.
|
1543
|
+
k.primary_key = 'id'
|
1544
|
+
|
1545
|
+
assert_deprecated do
|
1546
|
+
k.set_primary_key do
|
1547
|
+
"sys_" + ActiveSupport::Deprecation.silence { original_primary_key }
|
1548
|
+
end
|
1549
|
+
end
|
1091
1550
|
assert_equal "sys_id", k.primary_key
|
1092
1551
|
end
|
1093
1552
|
|
1553
|
+
def test_original_primary_key
|
1554
|
+
k = Class.new(ActiveRecord::Base)
|
1555
|
+
def k.name; "Foo"; end
|
1556
|
+
k.table_name = "posts"
|
1557
|
+
k.primary_key = "bar"
|
1558
|
+
|
1559
|
+
assert_deprecated do
|
1560
|
+
assert_equal "id", k.original_primary_key
|
1561
|
+
end
|
1562
|
+
|
1563
|
+
k = Class.new(ActiveRecord::Base)
|
1564
|
+
k.primary_key = "omg"
|
1565
|
+
k.primary_key = "wtf"
|
1566
|
+
|
1567
|
+
assert_deprecated do
|
1568
|
+
assert_equal "omg", k.original_primary_key
|
1569
|
+
end
|
1570
|
+
end
|
1571
|
+
|
1094
1572
|
def test_set_inheritance_column_with_value
|
1095
1573
|
k = Class.new( ActiveRecord::Base )
|
1096
1574
|
k.inheritance_column = "foo"
|
1097
1575
|
assert_equal "foo", k.inheritance_column
|
1098
|
-
|
1576
|
+
|
1577
|
+
assert_deprecated do
|
1578
|
+
k.set_inheritance_column "bar"
|
1579
|
+
end
|
1099
1580
|
assert_equal "bar", k.inheritance_column
|
1100
1581
|
end
|
1101
1582
|
|
1102
1583
|
def test_set_inheritance_column_with_block
|
1103
1584
|
k = Class.new( ActiveRecord::Base )
|
1104
|
-
|
1585
|
+
assert_deprecated do
|
1586
|
+
k.set_inheritance_column do
|
1587
|
+
ActiveSupport::Deprecation.silence { original_inheritance_column } + "_id"
|
1588
|
+
end
|
1589
|
+
end
|
1105
1590
|
assert_equal "type_id", k.inheritance_column
|
1106
1591
|
end
|
1107
1592
|
|
1593
|
+
def test_original_inheritance_column
|
1594
|
+
k = Class.new(ActiveRecord::Base)
|
1595
|
+
def k.name; "Foo"; end
|
1596
|
+
k.inheritance_column = "omg"
|
1597
|
+
|
1598
|
+
assert_deprecated do
|
1599
|
+
assert_equal "type", k.original_inheritance_column
|
1600
|
+
end
|
1601
|
+
end
|
1602
|
+
|
1603
|
+
def test_set_sequence_name_with_value
|
1604
|
+
k = Class.new( ActiveRecord::Base )
|
1605
|
+
k.sequence_name = "foo"
|
1606
|
+
assert_equal "foo", k.sequence_name
|
1607
|
+
|
1608
|
+
assert_deprecated do
|
1609
|
+
k.set_sequence_name "bar"
|
1610
|
+
end
|
1611
|
+
assert_equal "bar", k.sequence_name
|
1612
|
+
end
|
1613
|
+
|
1614
|
+
def test_set_sequence_name_with_block
|
1615
|
+
k = Class.new( ActiveRecord::Base )
|
1616
|
+
k.table_name = "projects"
|
1617
|
+
orig_name = k.sequence_name
|
1618
|
+
return skip "sequences not supported by db" unless orig_name
|
1619
|
+
|
1620
|
+
assert_deprecated do
|
1621
|
+
k.set_sequence_name do
|
1622
|
+
ActiveSupport::Deprecation.silence { original_sequence_name } + "_lol"
|
1623
|
+
end
|
1624
|
+
end
|
1625
|
+
assert_equal orig_name + "_lol", k.sequence_name
|
1626
|
+
end
|
1627
|
+
|
1628
|
+
def test_original_sequence_name
|
1629
|
+
k = Class.new(ActiveRecord::Base)
|
1630
|
+
k.table_name = "projects"
|
1631
|
+
orig_name = k.sequence_name
|
1632
|
+
return skip "sequences not supported by db" unless orig_name
|
1633
|
+
|
1634
|
+
k = Class.new(ActiveRecord::Base)
|
1635
|
+
k.table_name = "projects"
|
1636
|
+
k.sequence_name = "omg"
|
1637
|
+
|
1638
|
+
assert_deprecated do
|
1639
|
+
assert_equal orig_name, k.original_sequence_name
|
1640
|
+
end
|
1641
|
+
|
1642
|
+
k = Class.new(ActiveRecord::Base)
|
1643
|
+
k.table_name = "projects"
|
1644
|
+
k.sequence_name = "omg"
|
1645
|
+
k.sequence_name = "wtf"
|
1646
|
+
assert_deprecated do
|
1647
|
+
assert_equal "omg", k.original_sequence_name
|
1648
|
+
end
|
1649
|
+
end
|
1650
|
+
|
1651
|
+
def test_sequence_name_with_abstract_class
|
1652
|
+
ak = Class.new(ActiveRecord::Base)
|
1653
|
+
ak.abstract_class = true
|
1654
|
+
k = Class.new(ak)
|
1655
|
+
k.table_name = "projects"
|
1656
|
+
orig_name = k.sequence_name
|
1657
|
+
return skip "sequences not supported by db" unless orig_name
|
1658
|
+
assert_equal k.reset_sequence_name, orig_name
|
1659
|
+
end
|
1660
|
+
|
1108
1661
|
def test_count_with_join
|
1109
1662
|
res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
|
1110
1663
|
|
@@ -1139,12 +1692,6 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1139
1692
|
assert_equal res6, res7
|
1140
1693
|
end
|
1141
1694
|
|
1142
|
-
def test_interpolate_sql
|
1143
|
-
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo@bar') }
|
1144
|
-
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar) baz') }
|
1145
|
-
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar} baz') }
|
1146
|
-
end
|
1147
|
-
|
1148
1695
|
def test_scoped_find_conditions
|
1149
1696
|
scoped_developers = Developer.send(:with_scope, :find => { :conditions => 'salary > 90000' }) do
|
1150
1697
|
Developer.find(:all, :conditions => 'id < 5')
|
@@ -1153,6 +1700,12 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1153
1700
|
assert_equal 3, scoped_developers.size
|
1154
1701
|
end
|
1155
1702
|
|
1703
|
+
def test_no_limit_offset
|
1704
|
+
assert_nothing_raised do
|
1705
|
+
Developer.find(:all, :offset => 2)
|
1706
|
+
end
|
1707
|
+
end
|
1708
|
+
|
1156
1709
|
def test_scoped_find_limit_offset
|
1157
1710
|
scoped_developers = Developer.send(:with_scope, :find => { :limit => 3, :offset => 2 }) do
|
1158
1711
|
Developer.find(:all, :order => 'id')
|
@@ -1278,6 +1831,10 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1278
1831
|
assert !LooseDescendant.abstract_class?
|
1279
1832
|
end
|
1280
1833
|
|
1834
|
+
def test_abstract_class_table_name
|
1835
|
+
assert_nil AbstractCompany.table_name
|
1836
|
+
end
|
1837
|
+
|
1281
1838
|
def test_base_class
|
1282
1839
|
assert_equal LoosePerson, LoosePerson.base_class
|
1283
1840
|
assert_equal LooseDescendant, LooseDescendant.base_class
|
@@ -1350,7 +1907,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1350
1907
|
|
1351
1908
|
def test_inspect_instance
|
1352
1909
|
topic = topics(:first)
|
1353
|
-
assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil>), topic.inspect
|
1910
|
+
assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", important: nil, approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect
|
1354
1911
|
end
|
1355
1912
|
|
1356
1913
|
def test_inspect_new_instance
|
@@ -1379,6 +1936,14 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1379
1936
|
assert_equal "The First Topic", topics(:first).becomes(Reply).title
|
1380
1937
|
end
|
1381
1938
|
|
1939
|
+
def test_becomes_includes_errors
|
1940
|
+
company = Company.new(:name => nil)
|
1941
|
+
assert !company.valid?
|
1942
|
+
original_errors = company.errors
|
1943
|
+
client = company.becomes(Client)
|
1944
|
+
assert_equal original_errors, client.errors
|
1945
|
+
end
|
1946
|
+
|
1382
1947
|
def test_silence_sets_log_level_to_error_in_block
|
1383
1948
|
original_logger = ActiveRecord::Base.logger
|
1384
1949
|
log = StringIO.new
|
@@ -1424,7 +1989,9 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1424
1989
|
original_logger = ActiveRecord::Base.logger
|
1425
1990
|
log = StringIO.new
|
1426
1991
|
ActiveRecord::Base.logger = Logger.new(log)
|
1427
|
-
|
1992
|
+
assert_deprecated do
|
1993
|
+
ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => true) { ActiveRecord::Base.logger.debug "Loud" }
|
1994
|
+
end
|
1428
1995
|
ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" }
|
1429
1996
|
assert_no_match(/Loud/, log.string)
|
1430
1997
|
assert_match(/Quiet/, log.string)
|
@@ -1432,10 +1999,6 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1432
1999
|
ActiveRecord::Base.logger = original_logger
|
1433
2000
|
end
|
1434
2001
|
|
1435
|
-
def test_dup
|
1436
|
-
assert !Minimalistic.new.freeze.dup.frozen?
|
1437
|
-
end
|
1438
|
-
|
1439
2002
|
def test_compute_type_success
|
1440
2003
|
assert_equal Author, ActiveRecord::Base.send(:compute_type, 'Author')
|
1441
2004
|
end
|
@@ -1453,34 +2016,118 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1453
2016
|
end
|
1454
2017
|
end
|
1455
2018
|
|
1456
|
-
def
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
default_scope order('posts.comments_count ASC')
|
2019
|
+
def test_compute_type_argument_error
|
2020
|
+
ActiveSupport::Dependencies.stubs(:constantize).raises(ArgumentError)
|
2021
|
+
assert_raises ArgumentError do
|
2022
|
+
ActiveRecord::Base.send :compute_type, 'InvalidModel'
|
1461
2023
|
end
|
1462
|
-
|
2024
|
+
end
|
2025
|
+
|
2026
|
+
def test_clear_cache!
|
2027
|
+
# preheat cache
|
2028
|
+
c1 = Post.connection.schema_cache.columns['posts']
|
2029
|
+
ActiveRecord::Base.clear_cache!
|
2030
|
+
c2 = Post.connection.schema_cache.columns['posts']
|
2031
|
+
assert_not_equal c1, c2
|
2032
|
+
end
|
2033
|
+
|
2034
|
+
def test_current_scope_is_reset
|
2035
|
+
Object.const_set :UnloadablePost, Class.new(ActiveRecord::Base)
|
2036
|
+
UnloadablePost.send(:current_scope=, UnloadablePost.scoped)
|
1463
2037
|
|
1464
2038
|
UnloadablePost.unloadable
|
1465
|
-
assert_not_nil Thread.current[:
|
2039
|
+
assert_not_nil Thread.current[:UnloadablePost_current_scope]
|
1466
2040
|
ActiveSupport::Dependencies.remove_unloadable_constants!
|
1467
|
-
assert_nil Thread.current[:
|
2041
|
+
assert_nil Thread.current[:UnloadablePost_current_scope]
|
1468
2042
|
ensure
|
1469
2043
|
Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
|
1470
2044
|
end
|
1471
2045
|
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
ensure
|
1477
|
-
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
|
2046
|
+
def test_marshal_round_trip
|
2047
|
+
if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
|
2048
|
+
return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
|
2049
|
+
"to be a Ruby bug.")
|
1478
2050
|
end
|
1479
2051
|
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
2052
|
+
expected = posts(:welcome)
|
2053
|
+
marshalled = Marshal.dump(expected)
|
2054
|
+
actual = Marshal.load(marshalled)
|
2055
|
+
|
2056
|
+
assert_equal expected.attributes, actual.attributes
|
2057
|
+
end
|
2058
|
+
|
2059
|
+
def test_marshal_new_record_round_trip
|
2060
|
+
if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
|
2061
|
+
return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
|
2062
|
+
"to be a Ruby bug.")
|
2063
|
+
end
|
2064
|
+
|
2065
|
+
marshalled = Marshal.dump(Post.new)
|
2066
|
+
post = Marshal.load(marshalled)
|
2067
|
+
|
2068
|
+
assert post.new_record?, "should be a new record"
|
2069
|
+
end
|
2070
|
+
|
2071
|
+
def test_marshalling_with_associations
|
2072
|
+
if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
|
2073
|
+
return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
|
2074
|
+
"to be a Ruby bug.")
|
1485
2075
|
end
|
2076
|
+
|
2077
|
+
post = Post.new
|
2078
|
+
post.comments.build
|
2079
|
+
|
2080
|
+
marshalled = Marshal.dump(post)
|
2081
|
+
post = Marshal.load(marshalled)
|
2082
|
+
|
2083
|
+
assert_equal 1, post.comments.length
|
2084
|
+
end
|
2085
|
+
|
2086
|
+
def test_attribute_names
|
2087
|
+
assert_equal ["id", "type", "ruby_type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id"],
|
2088
|
+
Company.attribute_names
|
2089
|
+
end
|
2090
|
+
|
2091
|
+
def test_attribute_names_on_table_not_exists
|
2092
|
+
assert_equal [], NonExistentTable.attribute_names
|
2093
|
+
end
|
2094
|
+
|
2095
|
+
def test_attribtue_names_on_abstract_class
|
2096
|
+
assert_equal [], AbstractCompany.attribute_names
|
2097
|
+
end
|
2098
|
+
|
2099
|
+
def test_cache_key_for_existing_record_is_not_timezone_dependent
|
2100
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
2101
|
+
|
2102
|
+
Time.zone = "UTC"
|
2103
|
+
utc_key = Developer.first.cache_key
|
2104
|
+
|
2105
|
+
Time.zone = "EST"
|
2106
|
+
est_key = Developer.first.cache_key
|
2107
|
+
|
2108
|
+
assert_equal utc_key, est_key
|
2109
|
+
ensure
|
2110
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
2111
|
+
end
|
2112
|
+
|
2113
|
+
def test_cache_key_format_for_existing_record_with_updated_at
|
2114
|
+
dev = Developer.first
|
2115
|
+
assert_equal "developers/#{dev.id}-#{dev.updated_at.utc.to_s(:number)}", dev.cache_key
|
2116
|
+
end
|
2117
|
+
|
2118
|
+
def test_cache_key_format_for_existing_record_with_nil_updated_at
|
2119
|
+
dev = Developer.first
|
2120
|
+
dev.update_attribute(:updated_at, nil)
|
2121
|
+
assert_match(/\/#{dev.id}$/, dev.cache_key)
|
2122
|
+
end
|
2123
|
+
|
2124
|
+
def test_uniq_delegates_to_scoped
|
2125
|
+
scope = stub
|
2126
|
+
Bird.stubs(:scoped).returns(mock(:uniq => scope))
|
2127
|
+
assert_equal scope, Bird.uniq
|
2128
|
+
end
|
2129
|
+
|
2130
|
+
def test_table_name_with_2_abstract_subclasses
|
2131
|
+
assert_equal "photos", Photo.table_name
|
2132
|
+
end
|
1486
2133
|
end
|