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.
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