db2 2.6.2 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGES +17 -0
  2. data/README +79 -141
  3. data/ext/Makefile.nt32 +3 -3
  4. data/ext/Makefile.nt32.191 +212 -0
  5. data/ext/extconf.rb +75 -14
  6. data/ext/ibm_db.c +504 -47
  7. data/ext/ruby_ibm_db.h +4 -1
  8. data/ext/ruby_ibm_db_cli.c +108 -1
  9. data/ext/ruby_ibm_db_cli.h +54 -1
  10. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +423 -124
  11. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1 -1
  12. data/test/cases/adapter_test.rb +169 -164
  13. data/test/cases/associations/belongs_to_associations_test.rb +268 -43
  14. data/test/cases/associations/cascaded_eager_loading_test.rb +31 -33
  15. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +90 -156
  16. data/test/cases/associations/join_model_test.rb +100 -150
  17. data/test/cases/attribute_methods_test.rb +259 -58
  18. data/test/cases/base_test.rb +785 -138
  19. data/test/cases/calculations_test.rb +128 -8
  20. data/test/cases/migration_test.rb +680 -286
  21. data/test/cases/persistence_test.rb +642 -0
  22. data/test/cases/query_cache_test.rb +257 -0
  23. data/test/cases/relations_test.rb +1182 -0
  24. data/test/cases/schema_dumper_test.rb +41 -17
  25. data/test/cases/transaction_callbacks_test.rb +300 -0
  26. data/test/cases/validations/uniqueness_validation_test.rb +38 -22
  27. data/test/cases/xml_serialization_test.rb +408 -0
  28. data/test/config.yml +154 -0
  29. data/test/connections/native_ibm_db/connection.rb +2 -0
  30. data/test/models/warehouse_thing.rb +4 -4
  31. data/test/schema/i5/ibm_db_specific_schema.rb +3 -1
  32. data/test/schema/ids/ibm_db_specific_schema.rb +3 -1
  33. data/test/schema/luw/ibm_db_specific_schema.rb +2 -0
  34. data/test/schema/schema.rb +196 -92
  35. data/test/schema/zOS/ibm_db_specific_schema.rb +3 -1
  36. metadata +73 -68
  37. data/.gitignore +0 -1
  38. data/test/cases/associations/eager_test.rb +0 -862
  39. data/test/cases/associations/has_many_through_associations_test.rb +0 -461
  40. data/test/cases/finder_test.rb +0 -1088
  41. data/test/cases/fixtures_test.rb +0 -684
@@ -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/loose_person'
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, :warehouse_things, :authors, :categorizations, :categories, :posts
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
- topic = Topic.new({ "title" => "test",
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
- assert_date_from_db Date.new(1, 6, 24), topic.last_read.to_date
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
- assert_date_from_db Date.new(2004, 1, 24), topic.last_read.to_date
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
- assert_date_from_db Date.new(2004, 6, 1), topic.last_read.to_date
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
- assert_date_from_db Date.new(1, 6, 1), topic.last_read.to_date
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
- assert_date_from_db Date.new(2004, 1, 1), topic.last_read.to_date
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
- assert_date_from_db Date.new(1, 1, 24), topic.last_read.to_date
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 test_clone
957
+ def test_dup
664
958
  topic = Topic.find(1)
665
- cloned_topic = nil
666
- assert_nothing_raised { cloned_topic = topic.clone }
667
- assert_equal topic.title, cloned_topic.title
668
- assert !cloned_topic.persisted?
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 cloned
964
+ # test if the attributes have been duped
671
965
  topic.title = "a"
672
- cloned_topic.title = "b"
966
+ duped_topic.title = "b"
673
967
  assert_equal "a", topic.title
674
- assert_equal "b", cloned_topic.title
968
+ assert_equal "b", duped_topic.title
675
969
 
676
- # test if the attribute values have been cloned
970
+ # test if the attribute values have been duped
677
971
  topic.title = {"a" => "b"}
678
- cloned_topic = topic.clone
679
- cloned_topic.title["a"] = "c"
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 cloned correctly
683
- assert_equal topic.author_email_address, cloned_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
- cloned_topic.save
687
- assert cloned_topic.persisted?
688
- assert_not_equal cloned_topic.id, topic.id
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 test_clone_with_aggregate_of_same_name_as_attribute
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
- clone = nil
696
- assert_nothing_raised { clone = dev.clone }
697
- assert_kind_of DeveloperSalary, clone.salary
698
- assert_equal dev.salary.amount, clone.salary.amount
699
- assert !clone.persisted?
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 cloned
702
- original_amount = clone.salary.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, clone.salary.amount
1002
+ assert_equal original_amount, dup.salary.amount
705
1003
 
706
- assert clone.save
707
- assert clone.persisted?
708
- assert_not_equal clone.id, dev.id
1004
+ assert dup.save
1005
+ assert dup.persisted?
1006
+ assert_not_equal dup.id, dev.id
709
1007
  end
710
1008
 
711
- def test_clone_does_not_clone_associations
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
- author_clone = author.clone
716
- assert_equal [], author_clone.posts
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 test_clone_of_saved_object_marks_attributes_as_dirty
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.clone
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 test_clone_of_saved_object_marks_as_dirty_only_changed_attributes
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 threated as not changed
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.clone
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 threated as not changed on cloned instance
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 test_define_attr_method_with_value
1456
+ def test_set_table_name_with_value
1043
1457
  k = Class.new( ActiveRecord::Base )
1044
- k.send(:define_attr_method, :table_name, "foo")
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 test_define_attr_method_with_block
1049
- k = Class.new( ActiveRecord::Base )
1050
- k.send(:define_attr_method, :primary_key) { "sys_" + original_primary_key }
1051
- assert_equal "sys_id", k.primary_key
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 test_set_table_name_with_value
1055
- k = Class.new( ActiveRecord::Base )
1056
- k.table_name = "foo"
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.set_table_name "foo"
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.set_table_name "bar"
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
- k.set_table_name { "ks" }
1077
- assert_equal "ks", k.table_name
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
- k.set_primary_key "bar"
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.set_primary_key { "sys_" + original_primary_key }
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
- k.set_inheritance_column "bar"
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
- k.set_inheritance_column { original_inheritance_column + "_id" }
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
- ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => true) { ActiveRecord::Base.logger.debug "Loud" }
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 test_default_scope_is_reset
1457
- Object.const_set :UnloadablePost, Class.new(ActiveRecord::Base)
1458
- UnloadablePost.table_name = 'posts'
1459
- UnloadablePost.class_eval do
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
- UnloadablePost.scoped_methods # make Thread.current[:UnloadablePost_scoped_methods] not nil
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[:UnloadablePost_scoped_methods]
2039
+ assert_not_nil Thread.current[:UnloadablePost_current_scope]
1466
2040
  ActiveSupport::Dependencies.remove_unloadable_constants!
1467
- assert_nil Thread.current[:UnloadablePost_scoped_methods]
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
- protected
1473
- def with_env_tz(new_tz = 'US/Eastern')
1474
- old_tz, ENV['TZ'] = ENV['TZ'], new_tz
1475
- yield
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
- def with_active_record_default_timezone(zone)
1481
- old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone
1482
- yield
1483
- ensure
1484
- ActiveRecord::Base.default_timezone = old_zone
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