ibm_db 2.5.26-universal-darwin-14 → 2.6.1-universal-darwin-14

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +11 -0
  3. data/MANIFEST +14 -14
  4. data/README +225 -225
  5. data/ext/Makefile.nt32 +181 -181
  6. data/ext/Makefile.nt32.191 +212 -212
  7. data/ext/extconf.rb +264 -261
  8. data/ext/extconf_MacOS.rb +269 -0
  9. data/ext/ibm_db.c +11879 -11793
  10. data/ext/ruby_ibm_db.h +241 -240
  11. data/ext/ruby_ibm_db_cli.c +851 -845
  12. data/ext/ruby_ibm_db_cli.h +500 -489
  13. data/init.rb +41 -41
  14. data/lib/IBM_DB.rb +27 -19
  15. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3339 -3289
  16. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +1 -1
  17. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  18. data/test/cases/adapter_test.rb +207 -207
  19. data/test/cases/associations/belongs_to_associations_test.rb +711 -711
  20. data/test/cases/associations/cascaded_eager_loading_test.rb +181 -181
  21. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +851 -851
  22. data/test/cases/associations/join_model_test.rb +743 -743
  23. data/test/cases/attribute_methods_test.rb +822 -822
  24. data/test/cases/base_test.rb +2133 -2133
  25. data/test/cases/calculations_test.rb +482 -482
  26. data/test/cases/migration_test.rb +2408 -2408
  27. data/test/cases/persistence_test.rb +642 -642
  28. data/test/cases/query_cache_test.rb +257 -257
  29. data/test/cases/relations_test.rb +1182 -1182
  30. data/test/cases/schema_dumper_test.rb +256 -256
  31. data/test/cases/transaction_callbacks_test.rb +300 -300
  32. data/test/cases/validations/uniqueness_validation_test.rb +299 -299
  33. data/test/cases/xml_serialization_test.rb +408 -408
  34. data/test/config.yml +154 -154
  35. data/test/connections/native_ibm_db/connection.rb +43 -43
  36. data/test/ibm_db_test.rb +24 -24
  37. data/test/models/warehouse_thing.rb +4 -4
  38. data/test/schema/schema.rb +751 -751
  39. metadata +6 -8
  40. data/lib/linux/rb18x/ibm_db.bundle +0 -0
  41. data/lib/linux/rb19x/ibm_db.bundle +0 -0
  42. data/lib/linux/rb20x/ibm_db.bundle +0 -0
  43. data/lib/linux/rb21x/ibm_db.bundle +0 -0
@@ -1,822 +1,822 @@
1
- require "cases/helper"
2
- require 'active_support/core_ext/object/inclusion'
3
- require 'models/minimalistic'
4
- require 'models/developer'
5
- require 'models/auto_id'
6
- require 'models/boolean'
7
- require 'models/computer'
8
- require 'models/topic'
9
- require 'models/company'
10
- require 'models/category'
11
- require 'models/reply'
12
- require 'models/contact'
13
- require 'models/keyboard'
14
-
15
- class AttributeMethodsTest < ActiveRecord::TestCase
16
- fixtures :topics, :developers, :companies, :computers
17
-
18
- def setup
19
- @old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
20
- @target = Class.new(ActiveRecord::Base)
21
- @target.table_name = 'topics'
22
- end
23
-
24
- def teardown
25
- ActiveRecord::Base.send(:attribute_method_matchers).clear
26
- ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
27
- end
28
-
29
- def test_attribute_present
30
- t = Topic.new
31
- t.title = "hello there!"
32
- t.written_on = Time.now
33
- t.author_name = ""
34
- assert t.attribute_present?("title")
35
- assert t.attribute_present?("written_on")
36
- assert !t.attribute_present?("content")
37
- assert !t.attribute_present?("author_name")
38
-
39
- end
40
-
41
- def test_attribute_present_with_booleans
42
- b1 = Boolean.new
43
- b1.value = false
44
- assert b1.attribute_present?(:value)
45
-
46
- b2 = Boolean.new
47
- b2.value = true
48
- assert b2.attribute_present?(:value)
49
-
50
- b3 = Boolean.new
51
- assert !b3.attribute_present?(:value)
52
-
53
- b4 = Boolean.new
54
- b4.value = false
55
- b4.save!
56
- assert Boolean.find(b4.id).attribute_present?(:value)
57
- end
58
-
59
- def test_caching_nil_primary_key
60
- klass = Class.new(Minimalistic)
61
- klass.expects(:reset_primary_key).returns(nil).once
62
- 2.times { klass.primary_key }
63
- end
64
-
65
- def test_attribute_keys_on_new_instance
66
- t = Topic.new
67
- assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
68
- assert_raise(NoMethodError) { t.title2 }
69
- end
70
-
71
- def test_boolean_attributes
72
- assert ! Topic.find(1).approved?
73
- assert Topic.find(2).approved?
74
- end
75
-
76
- def test_set_attributes
77
- topic = Topic.find(1)
78
- topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
79
- topic.save
80
- assert_equal("Budget", topic.title)
81
- assert_equal("Jason", topic.author_name)
82
- assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
83
- end
84
-
85
- def test_set_attributes_without_hash
86
- topic = Topic.new
87
- assert_nothing_raised { topic.attributes = '' }
88
- end
89
-
90
- def test_integers_as_nil
91
- test = AutoId.create('value' => '')
92
- assert_nil AutoId.find(test.id).value
93
- end
94
-
95
- def test_set_attributes_with_block
96
- topic = Topic.new do |t|
97
- t.title = "Budget"
98
- t.author_name = "Jason"
99
- end
100
-
101
- assert_equal("Budget", topic.title)
102
- assert_equal("Jason", topic.author_name)
103
- end
104
-
105
- def test_respond_to?
106
- topic = Topic.find(1)
107
- assert_respond_to topic, "title"
108
- assert_respond_to topic, "_title"
109
- assert_respond_to topic, "title?"
110
- assert_respond_to topic, "title="
111
- assert_respond_to topic, :title
112
- assert_respond_to topic, :title?
113
- assert_respond_to topic, :title=
114
- assert_respond_to topic, "author_name"
115
- assert_respond_to topic, "attribute_names"
116
- assert !topic.respond_to?("nothingness")
117
- assert !topic.respond_to?(:nothingness)
118
- end
119
-
120
- def test_deprecated_underscore_method
121
- topic = Topic.find(1)
122
- assert_equal topic.title, assert_deprecated { topic._title }
123
- end
124
-
125
- def test_respond_to_with_custom_primary_key
126
- keyboard = Keyboard.create
127
- assert_not_nil keyboard.key_number
128
- assert_equal keyboard.key_number, keyboard.id
129
- assert keyboard.respond_to?('key_number')
130
- assert keyboard.respond_to?('_key_number')
131
- assert keyboard.respond_to?('id')
132
- assert keyboard.respond_to?('_id')
133
- end
134
-
135
- # Syck calls respond_to? before actually calling initialize
136
- def test_respond_to_with_allocated_object
137
- topic = Topic.allocate
138
- assert !topic.respond_to?("nothingness")
139
- assert !topic.respond_to?(:nothingness)
140
- assert_respond_to topic, "title"
141
- assert_respond_to topic, :title
142
- end
143
-
144
- # IRB inspects the return value of "MyModel.allocate"
145
- # by inspecting it.
146
- def test_allocated_object_can_be_inspected
147
- topic = Topic.allocate
148
- topic.instance_eval { @attributes = nil }
149
- assert_nothing_raised { topic.inspect }
150
- assert topic.inspect, "#<Topic not initialized>"
151
- end
152
-
153
- def test_array_content
154
- topic = Topic.new
155
- topic.content = %w( one two three )
156
- topic.save
157
-
158
- assert_equal(%w( one two three ), Topic.find(topic.id).content)
159
- end
160
-
161
- def test_read_attributes_before_type_cast
162
- category = Category.new({:name=>"Test categoty", :type => nil})
163
- category_attrs = {"name"=>"Test categoty", "id" => nil, "type" => nil, "categorizations_count" => nil}
164
- assert_equal category_attrs , category.attributes_before_type_cast
165
- end
166
-
167
- if current_adapter?(:MysqlAdapter)
168
- def test_read_attributes_before_type_cast_on_boolean
169
- bool = Boolean.create({ "value" => false })
170
- if RUBY_PLATFORM =~ /java/
171
- # JRuby will return the value before typecast as string
172
- assert_equal "0", bool.reload.attributes_before_type_cast["value"]
173
- else
174
- assert_equal 0, bool.reload.attributes_before_type_cast["value"]
175
- end
176
- end
177
- end
178
-
179
- def test_read_attributes_before_type_cast_on_datetime
180
- in_time_zone "Pacific Time (US & Canada)" do
181
- record = @target.new
182
-
183
- record.written_on = "345643456"
184
- assert_equal "345643456", record.written_on_before_type_cast
185
- assert_equal nil, record.written_on
186
-
187
- record.written_on = "2009-10-11 12:13:14"
188
- assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast
189
- assert_equal Time.zone.parse("2009-10-11 12:13:14"), record.written_on
190
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
191
- end
192
- end
193
-
194
- def test_read_attributes_after_type_cast_on_datetime
195
- tz = "Pacific Time (US & Canada)"
196
-
197
- in_time_zone tz do
198
- record = @target.new
199
-
200
- date_string = "2011-03-24"
201
- time = Time.zone.parse date_string
202
-
203
- record.written_on = date_string
204
- assert_equal date_string, record.written_on_before_type_cast
205
- assert_equal time, record.written_on
206
- assert_equal ActiveSupport::TimeZone[tz], record.written_on.time_zone
207
-
208
- record.save
209
- record.reload
210
-
211
- assert_equal time, record.written_on
212
- end
213
- end
214
-
215
- def test_hash_content
216
- topic = Topic.new
217
- topic.content = { "one" => 1, "two" => 2 }
218
- topic.save
219
-
220
- assert_equal 2, Topic.find(topic.id).content["two"]
221
-
222
- topic.content_will_change!
223
- topic.content["three"] = 3
224
- topic.save
225
-
226
- assert_equal 3, Topic.find(topic.id).content["three"]
227
- end
228
-
229
- def test_update_array_content
230
- topic = Topic.new
231
- topic.content = %w( one two three )
232
-
233
- topic.content.push "four"
234
- assert_equal(%w( one two three four ), topic.content)
235
-
236
- topic.save
237
-
238
- topic = Topic.find(topic.id)
239
- topic.content << "five"
240
- assert_equal(%w( one two three four five ), topic.content)
241
- end
242
-
243
- def test_case_sensitive_attributes_hash
244
- # DB2 is not case-sensitive
245
- return true if current_adapter?(:DB2Adapter,:IBM_DBAdapter)
246
-
247
- assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
248
- end
249
-
250
- def test_hashes_not_mangled
251
- new_topic = { :title => "New Topic" }
252
- new_topic_values = { :title => "AnotherTopic" }
253
-
254
- topic = Topic.new(new_topic)
255
- assert_equal new_topic[:title], topic.title
256
-
257
- topic.attributes= new_topic_values
258
- assert_equal new_topic_values[:title], topic.title
259
- end
260
-
261
- def test_create_through_factory
262
- topic = Topic.create("title" => "New Topic")
263
- topicReloaded = Topic.find(topic.id)
264
- assert_equal(topic, topicReloaded)
265
- end
266
-
267
- def test_write_attribute
268
- topic = Topic.new
269
- topic.send(:write_attribute, :title, "Still another topic")
270
- assert_equal "Still another topic", topic.title
271
-
272
- topic[:title] = "Still another topic: part 2"
273
- assert_equal "Still another topic: part 2", topic.title
274
-
275
- topic.send(:write_attribute, "title", "Still another topic: part 3")
276
- assert_equal "Still another topic: part 3", topic.title
277
-
278
- topic["title"] = "Still another topic: part 4"
279
- assert_equal "Still another topic: part 4", topic.title
280
- end
281
-
282
- def test_read_attribute
283
- topic = Topic.new
284
- topic.title = "Don't change the topic"
285
- assert_equal "Don't change the topic", topic.send(:read_attribute, "title")
286
- assert_equal "Don't change the topic", topic["title"]
287
-
288
- assert_equal "Don't change the topic", topic.send(:read_attribute, :title)
289
- assert_equal "Don't change the topic", topic[:title]
290
- end
291
-
292
- def test_read_attribute_when_false
293
- topic = topics(:first)
294
- topic.approved = false
295
- assert !topic.approved?, "approved should be false"
296
- topic.approved = "false"
297
- assert !topic.approved?, "approved should be false"
298
- end
299
-
300
- def test_read_attribute_when_true
301
- topic = topics(:first)
302
- topic.approved = true
303
- assert topic.approved?, "approved should be true"
304
- topic.approved = "true"
305
- assert topic.approved?, "approved should be true"
306
- end
307
-
308
- def test_read_write_boolean_attribute
309
- topic = Topic.new
310
- # puts ""
311
- # puts "New Topic"
312
- # puts topic.inspect
313
- topic.approved = "false"
314
- # puts "Expecting false"
315
- # puts topic.inspect
316
- assert !topic.approved?, "approved should be false"
317
- topic.approved = "false"
318
- # puts "Expecting false"
319
- # puts topic.inspect
320
- assert !topic.approved?, "approved should be false"
321
- topic.approved = "true"
322
- # puts "Expecting true"
323
- # puts topic.inspect
324
- assert topic.approved?, "approved should be true"
325
- topic.approved = "true"
326
- # puts "Expecting true"
327
- # puts topic.inspect
328
- assert topic.approved?, "approved should be true"
329
- # puts ""
330
- end
331
-
332
- def test_overridden_write_attribute
333
- topic = Topic.new
334
- def topic.write_attribute(attr_name, value)
335
- super(attr_name, value.downcase)
336
- end
337
-
338
- topic.send(:write_attribute, :title, "Yet another topic")
339
- assert_equal "yet another topic", topic.title
340
-
341
- topic[:title] = "Yet another topic: part 2"
342
- assert_equal "yet another topic: part 2", topic.title
343
-
344
- topic.send(:write_attribute, "title", "Yet another topic: part 3")
345
- assert_equal "yet another topic: part 3", topic.title
346
-
347
- topic["title"] = "Yet another topic: part 4"
348
- assert_equal "yet another topic: part 4", topic.title
349
- end
350
-
351
- def test_overridden_read_attribute
352
- topic = Topic.new
353
- topic.title = "Stop changing the topic"
354
- def topic.read_attribute(attr_name)
355
- super(attr_name).upcase
356
- end
357
-
358
- assert_equal "STOP CHANGING THE TOPIC", topic.send(:read_attribute, "title")
359
- assert_equal "STOP CHANGING THE TOPIC", topic["title"]
360
-
361
- assert_equal "STOP CHANGING THE TOPIC", topic.send(:read_attribute, :title)
362
- assert_equal "STOP CHANGING THE TOPIC", topic[:title]
363
- end
364
-
365
- def test_read_overridden_attribute
366
- topic = Topic.new(:title => 'a')
367
- def topic.title() 'b' end
368
- assert_equal 'a', topic[:title]
369
- end
370
-
371
- def test_query_attribute_string
372
- [nil, "", " "].each do |value|
373
- assert_equal false, Topic.new(:author_name => value).author_name?
374
- end
375
-
376
- assert_equal true, Topic.new(:author_name => "Name").author_name?
377
- end
378
-
379
- def test_query_attribute_number
380
- [nil, 0, "0"].each do |value|
381
- assert_equal false, Developer.new(:salary => value).salary?
382
- end
383
-
384
- assert_equal true, Developer.new(:salary => 1).salary?
385
- assert_equal true, Developer.new(:salary => "1").salary?
386
- end
387
-
388
- def test_query_attribute_boolean
389
- [nil, "", false, "false", "f", 0].each do |value|
390
- assert_equal false, Topic.new(:approved => value).approved?
391
- end
392
-
393
- [true, "true", "1", 1].each do |value|
394
- assert_equal true, Topic.new(:approved => value).approved?
395
- end
396
- end
397
-
398
- def test_query_attribute_with_custom_fields
399
- object = Company.find_by_sql(<<-SQL).first
400
- SELECT c1.*, c2.ruby_type as string_value, c2.rating as int_value
401
- FROM companies c1, companies c2
402
- WHERE c1.firm_id = c2.id
403
- AND c1.id = 2
404
- SQL
405
-
406
- assert_equal "Firm", object.string_value
407
- assert object.string_value?
408
-
409
- object.string_value = " "
410
- assert !object.string_value?
411
-
412
- assert_equal 1, object.int_value.to_i
413
- assert object.int_value?
414
-
415
- object.int_value = "0"
416
- assert !object.int_value?
417
- end
418
-
419
- def test_non_attribute_access_and_assignment
420
- topic = Topic.new
421
- assert !topic.respond_to?("mumbo")
422
- assert_raise(NoMethodError) { topic.mumbo }
423
- assert_raise(NoMethodError) { topic.mumbo = 5 }
424
- end
425
-
426
- def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing
427
- topic = @target.new(:title => 'Budget')
428
- assert topic.respond_to?('title')
429
- assert_equal 'Budget', topic.title
430
- assert !topic.respond_to?('title_hello_world')
431
- assert_raise(NoMethodError) { topic.title_hello_world }
432
- end
433
-
434
- def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing
435
- topic = @target.new(:title => 'Budget')
436
- %w(default_ title_).each do |prefix|
437
- @target.class_eval "def #{prefix}attribute(*args) args end"
438
- @target.attribute_method_prefix prefix
439
-
440
- meth = "#{prefix}title"
441
- assert topic.respond_to?(meth)
442
- assert_equal ['title'], topic.send(meth)
443
- assert_equal ['title', 'a'], topic.send(meth, 'a')
444
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
445
- end
446
- end
447
-
448
- def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing
449
- topic = @target.new(:title => 'Budget')
450
- %w(_default _title_default _it! _candidate= able?).each do |suffix|
451
- @target.class_eval "def attribute#{suffix}(*args) args end"
452
- @target.attribute_method_suffix suffix
453
-
454
- meth = "title#{suffix}"
455
- assert topic.respond_to?(meth)
456
- assert_equal ['title'], topic.send(meth)
457
- assert_equal ['title', 'a'], topic.send(meth, 'a')
458
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
459
- end
460
- end
461
-
462
- def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing
463
- topic = @target.new(:title => 'Budget')
464
- [['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix|
465
- @target.class_eval "def #{prefix}attribute#{suffix}(*args) args end"
466
- @target.attribute_method_affix({ :prefix => prefix, :suffix => suffix })
467
-
468
- meth = "#{prefix}title#{suffix}"
469
- assert topic.respond_to?(meth)
470
- assert_equal ['title'], topic.send(meth)
471
- assert_equal ['title', 'a'], topic.send(meth, 'a')
472
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
473
- end
474
- end
475
-
476
- def test_should_unserialize_attributes_for_frozen_records
477
- myobj = {:value1 => :value2}
478
- topic = Topic.create("content" => myobj)
479
- topic.freeze
480
- assert_equal myobj, topic.content
481
- end
482
-
483
- def test_typecast_attribute_from_select_to_false
484
- topic = Topic.create(:title => 'Budget')
485
- # Oracle and DB2 does not support boolean expressions in SELECT
486
- if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
487
- topic = Topic.find(:first, :select => "topics.*, 0 as is_test")
488
- else
489
- topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
490
- end
491
- assert !topic.is_test?
492
- end
493
-
494
- def test_typecast_attribute_from_select_to_true
495
- topic = Topic.create(:title => 'Budget')
496
- # Oracle and DB2 does not support boolean expressions in SELECT
497
- if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
498
- topic = Topic.find(:first, :select => "topics.*, 1 as is_test")
499
- else
500
- topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
501
- end
502
- assert topic.is_test?
503
- end
504
-
505
- def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
506
- %w(save create_or_update).each do |method|
507
- klass = Class.new ActiveRecord::Base
508
- klass.class_eval "def #{method}() 'defined #{method}' end"
509
- assert_raise ActiveRecord::DangerousAttributeError do
510
- klass.instance_method_already_implemented?(method)
511
- end
512
- end
513
- end
514
-
515
- def test_only_time_related_columns_are_meant_to_be_cached_by_default
516
- expected = %w(datetime timestamp time date).sort
517
- assert_equal expected, ActiveRecord::Base.attribute_types_cached_by_default.map(&:to_s).sort
518
- end
519
-
520
- def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
521
- default_attributes = Topic.cached_attributes
522
- Topic.cache_attributes :replies_count
523
- expected = default_attributes + ["replies_count"]
524
- assert_equal expected.sort, Topic.cached_attributes.sort
525
- Topic.instance_variable_set "@cached_attributes", nil
526
- end
527
-
528
- def test_cacheable_columns_are_actually_cached
529
- assert_equal cached_columns.sort, Topic.cached_attributes.sort
530
- end
531
-
532
- def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
533
- t = topics(:first)
534
- cache = t.instance_variable_get "@attributes_cache"
535
-
536
- assert_not_nil cache
537
- assert cache.empty?
538
-
539
- all_columns = Topic.columns.map(&:name)
540
- uncached_columns = all_columns - cached_columns
541
-
542
- all_columns.each do |attr_name|
543
- attribute_gets_cached = Topic.cache_attribute?(attr_name)
544
- val = t.send attr_name unless attr_name == "type"
545
- if attribute_gets_cached
546
- assert cached_columns.include?(attr_name)
547
- assert_equal val, cache[attr_name]
548
- else
549
- assert uncached_columns.include?(attr_name)
550
- assert !cache.include?(attr_name)
551
- end
552
- end
553
- end
554
-
555
- def test_write_nil_to_time_attributes
556
- in_time_zone "Pacific Time (US & Canada)" do
557
- record = @target.new
558
- record.written_on = nil
559
- assert_nil record.written_on
560
- end
561
- end
562
-
563
- def test_time_attributes_are_retrieved_in_current_time_zone
564
- in_time_zone "Pacific Time (US & Canada)" do
565
- utc_time = Time.utc(2008, 1, 1)
566
- record = @target.new
567
- record[:written_on] = utc_time
568
- assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
569
- assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
570
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
571
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
572
- end
573
- end
574
-
575
- def test_setting_time_zone_aware_attribute_to_utc
576
- in_time_zone "Pacific Time (US & Canada)" do
577
- utc_time = Time.utc(2008, 1, 1)
578
- record = @target.new
579
- record.written_on = utc_time
580
- assert_equal utc_time, record.written_on
581
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
582
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
583
- end
584
- end
585
-
586
- def test_setting_time_zone_aware_attribute_in_other_time_zone
587
- utc_time = Time.utc(2008, 1, 1)
588
- cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
589
- in_time_zone "Pacific Time (US & Canada)" do
590
- record = @target.new
591
- record.written_on = cst_time
592
- assert_equal utc_time, record.written_on
593
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
594
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
595
- end
596
- end
597
-
598
- def test_setting_time_zone_aware_read_attribute
599
- utc_time = Time.utc(2008, 1, 1)
600
- cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
601
- in_time_zone "Pacific Time (US & Canada)" do
602
- record = @target.create(:written_on => cst_time).reload
603
- assert_equal utc_time, record[:written_on]
604
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record[:written_on].time_zone
605
- assert_equal Time.utc(2007, 12, 31, 16), record[:written_on].time
606
- end
607
- end
608
-
609
- def test_setting_time_zone_aware_attribute_with_string
610
- utc_time = Time.utc(2008, 1, 1)
611
- (-11..13).each do |timezone_offset|
612
- time_string = utc_time.in_time_zone(timezone_offset).to_s
613
- in_time_zone "Pacific Time (US & Canada)" do
614
- record = @target.new
615
- record.written_on = time_string
616
- assert_equal Time.zone.parse(time_string), record.written_on
617
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
618
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
619
- end
620
- end
621
- end
622
-
623
- def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
624
- in_time_zone "Pacific Time (US & Canada)" do
625
- record = @target.new
626
- record.written_on = ' '
627
- assert_nil record.written_on
628
- assert_nil record[:written_on]
629
- end
630
- end
631
-
632
- def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
633
- time_string = 'Tue Jan 01 00:00:00 2008'
634
- (-11..13).each do |timezone_offset|
635
- in_time_zone timezone_offset do
636
- record = @target.new
637
- record.written_on = time_string
638
- assert_equal Time.zone.parse(time_string), record.written_on
639
- assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
640
- assert_equal Time.utc(2008, 1, 1), record.written_on.time
641
- end
642
- end
643
- end
644
-
645
- def test_setting_time_zone_aware_attribute_in_current_time_zone
646
- utc_time = Time.utc(2008, 1, 1)
647
- in_time_zone "Pacific Time (US & Canada)" do
648
- record = @target.new
649
- record.written_on = utc_time.in_time_zone
650
- assert_equal utc_time, record.written_on
651
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
652
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
653
- end
654
- end
655
-
656
- def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
657
- Topic.skip_time_zone_conversion_for_attributes = [:field_a]
658
- Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
659
-
660
- assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
661
- assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
662
- end
663
-
664
- def test_read_attributes_respect_access_control
665
- privatize("title")
666
-
667
- topic = @target.new(:title => "The pros and cons of programming naked.")
668
- assert !topic.respond_to?(:title)
669
- exception = assert_raise(NoMethodError) { topic.title }
670
- assert exception.message.include?("private method")
671
- assert_equal "I'm private", topic.send(:title)
672
- end
673
-
674
- def test_write_attributes_respect_access_control
675
- privatize("title=(value)")
676
-
677
- topic = @target.new
678
- assert !topic.respond_to?(:title=)
679
- exception = assert_raise(NoMethodError) { topic.title = "Pants"}
680
- assert exception.message.include?("private method")
681
- topic.send(:title=, "Very large pants")
682
- end
683
-
684
- def test_question_attributes_respect_access_control
685
- privatize("title?")
686
-
687
- topic = @target.new(:title => "Isaac Newton's pants")
688
- assert !topic.respond_to?(:title?)
689
- exception = assert_raise(NoMethodError) { topic.title? }
690
- assert exception.message.include?("private method")
691
- assert topic.send(:title?)
692
- end
693
-
694
- def test_bulk_update_respects_access_control
695
- privatize("title=(value)")
696
-
697
- assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(:title => "Rants about pants") }
698
- assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
699
- end
700
-
701
- def test_read_attribute_overwrites_private_method_not_considered_implemented
702
- # simulate a model with a db column that shares its name an inherited
703
- # private method (e.g. Object#system)
704
- #
705
- Object.class_eval do
706
- private
707
- def title; "private!"; end
708
- end
709
- assert !@target.instance_method_already_implemented?(:title)
710
- topic = @target.new
711
- assert_nil topic.title
712
-
713
- Object.send(:undef_method, :title) # remove test method from object
714
- end
715
-
716
- def test_list_of_serialized_attributes
717
- assert_equal %w(content), Topic.serialized_attributes.keys
718
- assert_equal %w(preferences), Contact.serialized_attributes.keys
719
- end
720
-
721
- def test_instance_method_should_be_defined_on_the_base_class
722
- subklass = Class.new(Topic)
723
-
724
- Topic.define_attribute_methods
725
-
726
- instance = subklass.new
727
- instance.id = 5
728
- assert_equal 5, instance.id
729
- assert subklass.method_defined?(:id), "subklass is missing id method"
730
-
731
- Topic.undefine_attribute_methods
732
-
733
- assert_equal 5, instance.id
734
- assert subklass.method_defined?(:id), "subklass is missing id method"
735
- end
736
-
737
- def test_dispatching_column_attributes_through_method_missing_deprecated
738
- Topic.define_attribute_methods
739
-
740
- topic = Topic.new(:id => 5)
741
- topic.id = 5
742
-
743
- topic.method(:id).owner.send(:undef_method, :id)
744
-
745
- assert_deprecated do
746
- assert_equal 5, topic.id
747
- end
748
- ensure
749
- Topic.undefine_attribute_methods
750
- end
751
-
752
- def test_read_attribute_with_nil_should_not_asplode
753
- assert_equal nil, Topic.new.read_attribute(nil)
754
- end
755
-
756
- # If B < A, and A defines an accessor for 'foo', we don't want to override
757
- # that by defining a 'foo' method in the generated methods module for B.
758
- # (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].)
759
- def test_inherited_custom_accessors
760
- klass = Class.new(ActiveRecord::Base) do
761
- self.table_name = "topics"
762
- self.abstract_class = true
763
- def title; "omg"; end
764
- def title=(val); self.author_name = val; end
765
- end
766
- subklass = Class.new(klass)
767
- [klass, subklass].each(&:define_attribute_methods)
768
-
769
- topic = subklass.find(1)
770
- assert_equal "omg", topic.title
771
-
772
- topic.title = "lol"
773
- assert_equal "lol", topic.author_name
774
- end
775
-
776
- def test_inherited_hook_removed
777
- parent = Class.new(ActiveRecord::Base)
778
- parent.table_name = "posts"
779
- def parent.inherited(k)
780
- end
781
-
782
- klass = Class.new(parent)
783
- assert_deprecated { klass.define_attribute_methods }
784
- end
785
-
786
- def test_setting_new_attributes_deprecated
787
- t = Topic.new
788
- assert_deprecated { t[:foo] = "bar" }
789
- assert_equal "bar", t.foo
790
- assert_equal "bar", t[:foo]
791
- end
792
-
793
- private
794
- def cached_columns
795
- @cached_columns ||= time_related_columns_on_topic.map(&:name)
796
- end
797
-
798
- def time_related_columns_on_topic
799
- Topic.columns.select { |c| c.type.in?([:time, :date, :datetime, :timestamp]) }
800
- end
801
-
802
- def in_time_zone(zone)
803
- old_zone = Time.zone
804
- old_tz = ActiveRecord::Base.time_zone_aware_attributes
805
-
806
- Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
807
- ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
808
- yield
809
- ensure
810
- Time.zone = old_zone
811
- ActiveRecord::Base.time_zone_aware_attributes = old_tz
812
- end
813
-
814
- def privatize(method_signature)
815
- @target.class_eval <<-private_method
816
- private
817
- def #{method_signature}
818
- "I'm private"
819
- end
820
- private_method
821
- end
822
- end
1
+ require "cases/helper"
2
+ require 'active_support/core_ext/object/inclusion'
3
+ require 'models/minimalistic'
4
+ require 'models/developer'
5
+ require 'models/auto_id'
6
+ require 'models/boolean'
7
+ require 'models/computer'
8
+ require 'models/topic'
9
+ require 'models/company'
10
+ require 'models/category'
11
+ require 'models/reply'
12
+ require 'models/contact'
13
+ require 'models/keyboard'
14
+
15
+ class AttributeMethodsTest < ActiveRecord::TestCase
16
+ fixtures :topics, :developers, :companies, :computers
17
+
18
+ def setup
19
+ @old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
20
+ @target = Class.new(ActiveRecord::Base)
21
+ @target.table_name = 'topics'
22
+ end
23
+
24
+ def teardown
25
+ ActiveRecord::Base.send(:attribute_method_matchers).clear
26
+ ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
27
+ end
28
+
29
+ def test_attribute_present
30
+ t = Topic.new
31
+ t.title = "hello there!"
32
+ t.written_on = Time.now
33
+ t.author_name = ""
34
+ assert t.attribute_present?("title")
35
+ assert t.attribute_present?("written_on")
36
+ assert !t.attribute_present?("content")
37
+ assert !t.attribute_present?("author_name")
38
+
39
+ end
40
+
41
+ def test_attribute_present_with_booleans
42
+ b1 = Boolean.new
43
+ b1.value = false
44
+ assert b1.attribute_present?(:value)
45
+
46
+ b2 = Boolean.new
47
+ b2.value = true
48
+ assert b2.attribute_present?(:value)
49
+
50
+ b3 = Boolean.new
51
+ assert !b3.attribute_present?(:value)
52
+
53
+ b4 = Boolean.new
54
+ b4.value = false
55
+ b4.save!
56
+ assert Boolean.find(b4.id).attribute_present?(:value)
57
+ end
58
+
59
+ def test_caching_nil_primary_key
60
+ klass = Class.new(Minimalistic)
61
+ klass.expects(:reset_primary_key).returns(nil).once
62
+ 2.times { klass.primary_key }
63
+ end
64
+
65
+ def test_attribute_keys_on_new_instance
66
+ t = Topic.new
67
+ assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
68
+ assert_raise(NoMethodError) { t.title2 }
69
+ end
70
+
71
+ def test_boolean_attributes
72
+ assert ! Topic.find(1).approved?
73
+ assert Topic.find(2).approved?
74
+ end
75
+
76
+ def test_set_attributes
77
+ topic = Topic.find(1)
78
+ topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
79
+ topic.save
80
+ assert_equal("Budget", topic.title)
81
+ assert_equal("Jason", topic.author_name)
82
+ assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
83
+ end
84
+
85
+ def test_set_attributes_without_hash
86
+ topic = Topic.new
87
+ assert_nothing_raised { topic.attributes = '' }
88
+ end
89
+
90
+ def test_integers_as_nil
91
+ test = AutoId.create('value' => '')
92
+ assert_nil AutoId.find(test.id).value
93
+ end
94
+
95
+ def test_set_attributes_with_block
96
+ topic = Topic.new do |t|
97
+ t.title = "Budget"
98
+ t.author_name = "Jason"
99
+ end
100
+
101
+ assert_equal("Budget", topic.title)
102
+ assert_equal("Jason", topic.author_name)
103
+ end
104
+
105
+ def test_respond_to?
106
+ topic = Topic.find(1)
107
+ assert_respond_to topic, "title"
108
+ assert_respond_to topic, "_title"
109
+ assert_respond_to topic, "title?"
110
+ assert_respond_to topic, "title="
111
+ assert_respond_to topic, :title
112
+ assert_respond_to topic, :title?
113
+ assert_respond_to topic, :title=
114
+ assert_respond_to topic, "author_name"
115
+ assert_respond_to topic, "attribute_names"
116
+ assert !topic.respond_to?("nothingness")
117
+ assert !topic.respond_to?(:nothingness)
118
+ end
119
+
120
+ def test_deprecated_underscore_method
121
+ topic = Topic.find(1)
122
+ assert_equal topic.title, assert_deprecated { topic._title }
123
+ end
124
+
125
+ def test_respond_to_with_custom_primary_key
126
+ keyboard = Keyboard.create
127
+ assert_not_nil keyboard.key_number
128
+ assert_equal keyboard.key_number, keyboard.id
129
+ assert keyboard.respond_to?('key_number')
130
+ assert keyboard.respond_to?('_key_number')
131
+ assert keyboard.respond_to?('id')
132
+ assert keyboard.respond_to?('_id')
133
+ end
134
+
135
+ # Syck calls respond_to? before actually calling initialize
136
+ def test_respond_to_with_allocated_object
137
+ topic = Topic.allocate
138
+ assert !topic.respond_to?("nothingness")
139
+ assert !topic.respond_to?(:nothingness)
140
+ assert_respond_to topic, "title"
141
+ assert_respond_to topic, :title
142
+ end
143
+
144
+ # IRB inspects the return value of "MyModel.allocate"
145
+ # by inspecting it.
146
+ def test_allocated_object_can_be_inspected
147
+ topic = Topic.allocate
148
+ topic.instance_eval { @attributes = nil }
149
+ assert_nothing_raised { topic.inspect }
150
+ assert topic.inspect, "#<Topic not initialized>"
151
+ end
152
+
153
+ def test_array_content
154
+ topic = Topic.new
155
+ topic.content = %w( one two three )
156
+ topic.save
157
+
158
+ assert_equal(%w( one two three ), Topic.find(topic.id).content)
159
+ end
160
+
161
+ def test_read_attributes_before_type_cast
162
+ category = Category.new({:name=>"Test categoty", :type => nil})
163
+ category_attrs = {"name"=>"Test categoty", "id" => nil, "type" => nil, "categorizations_count" => nil}
164
+ assert_equal category_attrs , category.attributes_before_type_cast
165
+ end
166
+
167
+ if current_adapter?(:MysqlAdapter)
168
+ def test_read_attributes_before_type_cast_on_boolean
169
+ bool = Boolean.create({ "value" => false })
170
+ if RUBY_PLATFORM =~ /java/
171
+ # JRuby will return the value before typecast as string
172
+ assert_equal "0", bool.reload.attributes_before_type_cast["value"]
173
+ else
174
+ assert_equal 0, bool.reload.attributes_before_type_cast["value"]
175
+ end
176
+ end
177
+ end
178
+
179
+ def test_read_attributes_before_type_cast_on_datetime
180
+ in_time_zone "Pacific Time (US & Canada)" do
181
+ record = @target.new
182
+
183
+ record.written_on = "345643456"
184
+ assert_equal "345643456", record.written_on_before_type_cast
185
+ assert_equal nil, record.written_on
186
+
187
+ record.written_on = "2009-10-11 12:13:14"
188
+ assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast
189
+ assert_equal Time.zone.parse("2009-10-11 12:13:14"), record.written_on
190
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
191
+ end
192
+ end
193
+
194
+ def test_read_attributes_after_type_cast_on_datetime
195
+ tz = "Pacific Time (US & Canada)"
196
+
197
+ in_time_zone tz do
198
+ record = @target.new
199
+
200
+ date_string = "2011-03-24"
201
+ time = Time.zone.parse date_string
202
+
203
+ record.written_on = date_string
204
+ assert_equal date_string, record.written_on_before_type_cast
205
+ assert_equal time, record.written_on
206
+ assert_equal ActiveSupport::TimeZone[tz], record.written_on.time_zone
207
+
208
+ record.save
209
+ record.reload
210
+
211
+ assert_equal time, record.written_on
212
+ end
213
+ end
214
+
215
+ def test_hash_content
216
+ topic = Topic.new
217
+ topic.content = { "one" => 1, "two" => 2 }
218
+ topic.save
219
+
220
+ assert_equal 2, Topic.find(topic.id).content["two"]
221
+
222
+ topic.content_will_change!
223
+ topic.content["three"] = 3
224
+ topic.save
225
+
226
+ assert_equal 3, Topic.find(topic.id).content["three"]
227
+ end
228
+
229
+ def test_update_array_content
230
+ topic = Topic.new
231
+ topic.content = %w( one two three )
232
+
233
+ topic.content.push "four"
234
+ assert_equal(%w( one two three four ), topic.content)
235
+
236
+ topic.save
237
+
238
+ topic = Topic.find(topic.id)
239
+ topic.content << "five"
240
+ assert_equal(%w( one two three four five ), topic.content)
241
+ end
242
+
243
+ def test_case_sensitive_attributes_hash
244
+ # DB2 is not case-sensitive
245
+ return true if current_adapter?(:DB2Adapter,:IBM_DBAdapter)
246
+
247
+ assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
248
+ end
249
+
250
+ def test_hashes_not_mangled
251
+ new_topic = { :title => "New Topic" }
252
+ new_topic_values = { :title => "AnotherTopic" }
253
+
254
+ topic = Topic.new(new_topic)
255
+ assert_equal new_topic[:title], topic.title
256
+
257
+ topic.attributes= new_topic_values
258
+ assert_equal new_topic_values[:title], topic.title
259
+ end
260
+
261
+ def test_create_through_factory
262
+ topic = Topic.create("title" => "New Topic")
263
+ topicReloaded = Topic.find(topic.id)
264
+ assert_equal(topic, topicReloaded)
265
+ end
266
+
267
+ def test_write_attribute
268
+ topic = Topic.new
269
+ topic.send(:write_attribute, :title, "Still another topic")
270
+ assert_equal "Still another topic", topic.title
271
+
272
+ topic[:title] = "Still another topic: part 2"
273
+ assert_equal "Still another topic: part 2", topic.title
274
+
275
+ topic.send(:write_attribute, "title", "Still another topic: part 3")
276
+ assert_equal "Still another topic: part 3", topic.title
277
+
278
+ topic["title"] = "Still another topic: part 4"
279
+ assert_equal "Still another topic: part 4", topic.title
280
+ end
281
+
282
+ def test_read_attribute
283
+ topic = Topic.new
284
+ topic.title = "Don't change the topic"
285
+ assert_equal "Don't change the topic", topic.send(:read_attribute, "title")
286
+ assert_equal "Don't change the topic", topic["title"]
287
+
288
+ assert_equal "Don't change the topic", topic.send(:read_attribute, :title)
289
+ assert_equal "Don't change the topic", topic[:title]
290
+ end
291
+
292
+ def test_read_attribute_when_false
293
+ topic = topics(:first)
294
+ topic.approved = false
295
+ assert !topic.approved?, "approved should be false"
296
+ topic.approved = "false"
297
+ assert !topic.approved?, "approved should be false"
298
+ end
299
+
300
+ def test_read_attribute_when_true
301
+ topic = topics(:first)
302
+ topic.approved = true
303
+ assert topic.approved?, "approved should be true"
304
+ topic.approved = "true"
305
+ assert topic.approved?, "approved should be true"
306
+ end
307
+
308
+ def test_read_write_boolean_attribute
309
+ topic = Topic.new
310
+ # puts ""
311
+ # puts "New Topic"
312
+ # puts topic.inspect
313
+ topic.approved = "false"
314
+ # puts "Expecting false"
315
+ # puts topic.inspect
316
+ assert !topic.approved?, "approved should be false"
317
+ topic.approved = "false"
318
+ # puts "Expecting false"
319
+ # puts topic.inspect
320
+ assert !topic.approved?, "approved should be false"
321
+ topic.approved = "true"
322
+ # puts "Expecting true"
323
+ # puts topic.inspect
324
+ assert topic.approved?, "approved should be true"
325
+ topic.approved = "true"
326
+ # puts "Expecting true"
327
+ # puts topic.inspect
328
+ assert topic.approved?, "approved should be true"
329
+ # puts ""
330
+ end
331
+
332
+ def test_overridden_write_attribute
333
+ topic = Topic.new
334
+ def topic.write_attribute(attr_name, value)
335
+ super(attr_name, value.downcase)
336
+ end
337
+
338
+ topic.send(:write_attribute, :title, "Yet another topic")
339
+ assert_equal "yet another topic", topic.title
340
+
341
+ topic[:title] = "Yet another topic: part 2"
342
+ assert_equal "yet another topic: part 2", topic.title
343
+
344
+ topic.send(:write_attribute, "title", "Yet another topic: part 3")
345
+ assert_equal "yet another topic: part 3", topic.title
346
+
347
+ topic["title"] = "Yet another topic: part 4"
348
+ assert_equal "yet another topic: part 4", topic.title
349
+ end
350
+
351
+ def test_overridden_read_attribute
352
+ topic = Topic.new
353
+ topic.title = "Stop changing the topic"
354
+ def topic.read_attribute(attr_name)
355
+ super(attr_name).upcase
356
+ end
357
+
358
+ assert_equal "STOP CHANGING THE TOPIC", topic.send(:read_attribute, "title")
359
+ assert_equal "STOP CHANGING THE TOPIC", topic["title"]
360
+
361
+ assert_equal "STOP CHANGING THE TOPIC", topic.send(:read_attribute, :title)
362
+ assert_equal "STOP CHANGING THE TOPIC", topic[:title]
363
+ end
364
+
365
+ def test_read_overridden_attribute
366
+ topic = Topic.new(:title => 'a')
367
+ def topic.title() 'b' end
368
+ assert_equal 'a', topic[:title]
369
+ end
370
+
371
+ def test_query_attribute_string
372
+ [nil, "", " "].each do |value|
373
+ assert_equal false, Topic.new(:author_name => value).author_name?
374
+ end
375
+
376
+ assert_equal true, Topic.new(:author_name => "Name").author_name?
377
+ end
378
+
379
+ def test_query_attribute_number
380
+ [nil, 0, "0"].each do |value|
381
+ assert_equal false, Developer.new(:salary => value).salary?
382
+ end
383
+
384
+ assert_equal true, Developer.new(:salary => 1).salary?
385
+ assert_equal true, Developer.new(:salary => "1").salary?
386
+ end
387
+
388
+ def test_query_attribute_boolean
389
+ [nil, "", false, "false", "f", 0].each do |value|
390
+ assert_equal false, Topic.new(:approved => value).approved?
391
+ end
392
+
393
+ [true, "true", "1", 1].each do |value|
394
+ assert_equal true, Topic.new(:approved => value).approved?
395
+ end
396
+ end
397
+
398
+ def test_query_attribute_with_custom_fields
399
+ object = Company.find_by_sql(<<-SQL).first
400
+ SELECT c1.*, c2.ruby_type as string_value, c2.rating as int_value
401
+ FROM companies c1, companies c2
402
+ WHERE c1.firm_id = c2.id
403
+ AND c1.id = 2
404
+ SQL
405
+
406
+ assert_equal "Firm", object.string_value
407
+ assert object.string_value?
408
+
409
+ object.string_value = " "
410
+ assert !object.string_value?
411
+
412
+ assert_equal 1, object.int_value.to_i
413
+ assert object.int_value?
414
+
415
+ object.int_value = "0"
416
+ assert !object.int_value?
417
+ end
418
+
419
+ def test_non_attribute_access_and_assignment
420
+ topic = Topic.new
421
+ assert !topic.respond_to?("mumbo")
422
+ assert_raise(NoMethodError) { topic.mumbo }
423
+ assert_raise(NoMethodError) { topic.mumbo = 5 }
424
+ end
425
+
426
+ def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing
427
+ topic = @target.new(:title => 'Budget')
428
+ assert topic.respond_to?('title')
429
+ assert_equal 'Budget', topic.title
430
+ assert !topic.respond_to?('title_hello_world')
431
+ assert_raise(NoMethodError) { topic.title_hello_world }
432
+ end
433
+
434
+ def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing
435
+ topic = @target.new(:title => 'Budget')
436
+ %w(default_ title_).each do |prefix|
437
+ @target.class_eval "def #{prefix}attribute(*args) args end"
438
+ @target.attribute_method_prefix prefix
439
+
440
+ meth = "#{prefix}title"
441
+ assert topic.respond_to?(meth)
442
+ assert_equal ['title'], topic.send(meth)
443
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
444
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
445
+ end
446
+ end
447
+
448
+ def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing
449
+ topic = @target.new(:title => 'Budget')
450
+ %w(_default _title_default _it! _candidate= able?).each do |suffix|
451
+ @target.class_eval "def attribute#{suffix}(*args) args end"
452
+ @target.attribute_method_suffix suffix
453
+
454
+ meth = "title#{suffix}"
455
+ assert topic.respond_to?(meth)
456
+ assert_equal ['title'], topic.send(meth)
457
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
458
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
459
+ end
460
+ end
461
+
462
+ def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing
463
+ topic = @target.new(:title => 'Budget')
464
+ [['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix|
465
+ @target.class_eval "def #{prefix}attribute#{suffix}(*args) args end"
466
+ @target.attribute_method_affix({ :prefix => prefix, :suffix => suffix })
467
+
468
+ meth = "#{prefix}title#{suffix}"
469
+ assert topic.respond_to?(meth)
470
+ assert_equal ['title'], topic.send(meth)
471
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
472
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
473
+ end
474
+ end
475
+
476
+ def test_should_unserialize_attributes_for_frozen_records
477
+ myobj = {:value1 => :value2}
478
+ topic = Topic.create("content" => myobj)
479
+ topic.freeze
480
+ assert_equal myobj, topic.content
481
+ end
482
+
483
+ def test_typecast_attribute_from_select_to_false
484
+ topic = Topic.create(:title => 'Budget')
485
+ # Oracle and DB2 does not support boolean expressions in SELECT
486
+ if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
487
+ topic = Topic.find(:first, :select => "topics.*, 0 as is_test")
488
+ else
489
+ topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
490
+ end
491
+ assert !topic.is_test?
492
+ end
493
+
494
+ def test_typecast_attribute_from_select_to_true
495
+ topic = Topic.create(:title => 'Budget')
496
+ # Oracle and DB2 does not support boolean expressions in SELECT
497
+ if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
498
+ topic = Topic.find(:first, :select => "topics.*, 1 as is_test")
499
+ else
500
+ topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
501
+ end
502
+ assert topic.is_test?
503
+ end
504
+
505
+ def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
506
+ %w(save create_or_update).each do |method|
507
+ klass = Class.new ActiveRecord::Base
508
+ klass.class_eval "def #{method}() 'defined #{method}' end"
509
+ assert_raise ActiveRecord::DangerousAttributeError do
510
+ klass.instance_method_already_implemented?(method)
511
+ end
512
+ end
513
+ end
514
+
515
+ def test_only_time_related_columns_are_meant_to_be_cached_by_default
516
+ expected = %w(datetime timestamp time date).sort
517
+ assert_equal expected, ActiveRecord::Base.attribute_types_cached_by_default.map(&:to_s).sort
518
+ end
519
+
520
+ def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
521
+ default_attributes = Topic.cached_attributes
522
+ Topic.cache_attributes :replies_count
523
+ expected = default_attributes + ["replies_count"]
524
+ assert_equal expected.sort, Topic.cached_attributes.sort
525
+ Topic.instance_variable_set "@cached_attributes", nil
526
+ end
527
+
528
+ def test_cacheable_columns_are_actually_cached
529
+ assert_equal cached_columns.sort, Topic.cached_attributes.sort
530
+ end
531
+
532
+ def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
533
+ t = topics(:first)
534
+ cache = t.instance_variable_get "@attributes_cache"
535
+
536
+ assert_not_nil cache
537
+ assert cache.empty?
538
+
539
+ all_columns = Topic.columns.map(&:name)
540
+ uncached_columns = all_columns - cached_columns
541
+
542
+ all_columns.each do |attr_name|
543
+ attribute_gets_cached = Topic.cache_attribute?(attr_name)
544
+ val = t.send attr_name unless attr_name == "type"
545
+ if attribute_gets_cached
546
+ assert cached_columns.include?(attr_name)
547
+ assert_equal val, cache[attr_name]
548
+ else
549
+ assert uncached_columns.include?(attr_name)
550
+ assert !cache.include?(attr_name)
551
+ end
552
+ end
553
+ end
554
+
555
+ def test_write_nil_to_time_attributes
556
+ in_time_zone "Pacific Time (US & Canada)" do
557
+ record = @target.new
558
+ record.written_on = nil
559
+ assert_nil record.written_on
560
+ end
561
+ end
562
+
563
+ def test_time_attributes_are_retrieved_in_current_time_zone
564
+ in_time_zone "Pacific Time (US & Canada)" do
565
+ utc_time = Time.utc(2008, 1, 1)
566
+ record = @target.new
567
+ record[:written_on] = utc_time
568
+ assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
569
+ assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
570
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
571
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
572
+ end
573
+ end
574
+
575
+ def test_setting_time_zone_aware_attribute_to_utc
576
+ in_time_zone "Pacific Time (US & Canada)" do
577
+ utc_time = Time.utc(2008, 1, 1)
578
+ record = @target.new
579
+ record.written_on = utc_time
580
+ assert_equal utc_time, record.written_on
581
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
582
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
583
+ end
584
+ end
585
+
586
+ def test_setting_time_zone_aware_attribute_in_other_time_zone
587
+ utc_time = Time.utc(2008, 1, 1)
588
+ cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
589
+ in_time_zone "Pacific Time (US & Canada)" do
590
+ record = @target.new
591
+ record.written_on = cst_time
592
+ assert_equal utc_time, record.written_on
593
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
594
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
595
+ end
596
+ end
597
+
598
+ def test_setting_time_zone_aware_read_attribute
599
+ utc_time = Time.utc(2008, 1, 1)
600
+ cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
601
+ in_time_zone "Pacific Time (US & Canada)" do
602
+ record = @target.create(:written_on => cst_time).reload
603
+ assert_equal utc_time, record[:written_on]
604
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record[:written_on].time_zone
605
+ assert_equal Time.utc(2007, 12, 31, 16), record[:written_on].time
606
+ end
607
+ end
608
+
609
+ def test_setting_time_zone_aware_attribute_with_string
610
+ utc_time = Time.utc(2008, 1, 1)
611
+ (-11..13).each do |timezone_offset|
612
+ time_string = utc_time.in_time_zone(timezone_offset).to_s
613
+ in_time_zone "Pacific Time (US & Canada)" do
614
+ record = @target.new
615
+ record.written_on = time_string
616
+ assert_equal Time.zone.parse(time_string), record.written_on
617
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
618
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
619
+ end
620
+ end
621
+ end
622
+
623
+ def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
624
+ in_time_zone "Pacific Time (US & Canada)" do
625
+ record = @target.new
626
+ record.written_on = ' '
627
+ assert_nil record.written_on
628
+ assert_nil record[:written_on]
629
+ end
630
+ end
631
+
632
+ def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
633
+ time_string = 'Tue Jan 01 00:00:00 2008'
634
+ (-11..13).each do |timezone_offset|
635
+ in_time_zone timezone_offset do
636
+ record = @target.new
637
+ record.written_on = time_string
638
+ assert_equal Time.zone.parse(time_string), record.written_on
639
+ assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
640
+ assert_equal Time.utc(2008, 1, 1), record.written_on.time
641
+ end
642
+ end
643
+ end
644
+
645
+ def test_setting_time_zone_aware_attribute_in_current_time_zone
646
+ utc_time = Time.utc(2008, 1, 1)
647
+ in_time_zone "Pacific Time (US & Canada)" do
648
+ record = @target.new
649
+ record.written_on = utc_time.in_time_zone
650
+ assert_equal utc_time, record.written_on
651
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
652
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
653
+ end
654
+ end
655
+
656
+ def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
657
+ Topic.skip_time_zone_conversion_for_attributes = [:field_a]
658
+ Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
659
+
660
+ assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
661
+ assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
662
+ end
663
+
664
+ def test_read_attributes_respect_access_control
665
+ privatize("title")
666
+
667
+ topic = @target.new(:title => "The pros and cons of programming naked.")
668
+ assert !topic.respond_to?(:title)
669
+ exception = assert_raise(NoMethodError) { topic.title }
670
+ assert exception.message.include?("private method")
671
+ assert_equal "I'm private", topic.send(:title)
672
+ end
673
+
674
+ def test_write_attributes_respect_access_control
675
+ privatize("title=(value)")
676
+
677
+ topic = @target.new
678
+ assert !topic.respond_to?(:title=)
679
+ exception = assert_raise(NoMethodError) { topic.title = "Pants"}
680
+ assert exception.message.include?("private method")
681
+ topic.send(:title=, "Very large pants")
682
+ end
683
+
684
+ def test_question_attributes_respect_access_control
685
+ privatize("title?")
686
+
687
+ topic = @target.new(:title => "Isaac Newton's pants")
688
+ assert !topic.respond_to?(:title?)
689
+ exception = assert_raise(NoMethodError) { topic.title? }
690
+ assert exception.message.include?("private method")
691
+ assert topic.send(:title?)
692
+ end
693
+
694
+ def test_bulk_update_respects_access_control
695
+ privatize("title=(value)")
696
+
697
+ assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(:title => "Rants about pants") }
698
+ assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
699
+ end
700
+
701
+ def test_read_attribute_overwrites_private_method_not_considered_implemented
702
+ # simulate a model with a db column that shares its name an inherited
703
+ # private method (e.g. Object#system)
704
+ #
705
+ Object.class_eval do
706
+ private
707
+ def title; "private!"; end
708
+ end
709
+ assert !@target.instance_method_already_implemented?(:title)
710
+ topic = @target.new
711
+ assert_nil topic.title
712
+
713
+ Object.send(:undef_method, :title) # remove test method from object
714
+ end
715
+
716
+ def test_list_of_serialized_attributes
717
+ assert_equal %w(content), Topic.serialized_attributes.keys
718
+ assert_equal %w(preferences), Contact.serialized_attributes.keys
719
+ end
720
+
721
+ def test_instance_method_should_be_defined_on_the_base_class
722
+ subklass = Class.new(Topic)
723
+
724
+ Topic.define_attribute_methods
725
+
726
+ instance = subklass.new
727
+ instance.id = 5
728
+ assert_equal 5, instance.id
729
+ assert subklass.method_defined?(:id), "subklass is missing id method"
730
+
731
+ Topic.undefine_attribute_methods
732
+
733
+ assert_equal 5, instance.id
734
+ assert subklass.method_defined?(:id), "subklass is missing id method"
735
+ end
736
+
737
+ def test_dispatching_column_attributes_through_method_missing_deprecated
738
+ Topic.define_attribute_methods
739
+
740
+ topic = Topic.new(:id => 5)
741
+ topic.id = 5
742
+
743
+ topic.method(:id).owner.send(:undef_method, :id)
744
+
745
+ assert_deprecated do
746
+ assert_equal 5, topic.id
747
+ end
748
+ ensure
749
+ Topic.undefine_attribute_methods
750
+ end
751
+
752
+ def test_read_attribute_with_nil_should_not_asplode
753
+ assert_equal nil, Topic.new.read_attribute(nil)
754
+ end
755
+
756
+ # If B < A, and A defines an accessor for 'foo', we don't want to override
757
+ # that by defining a 'foo' method in the generated methods module for B.
758
+ # (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].)
759
+ def test_inherited_custom_accessors
760
+ klass = Class.new(ActiveRecord::Base) do
761
+ self.table_name = "topics"
762
+ self.abstract_class = true
763
+ def title; "omg"; end
764
+ def title=(val); self.author_name = val; end
765
+ end
766
+ subklass = Class.new(klass)
767
+ [klass, subklass].each(&:define_attribute_methods)
768
+
769
+ topic = subklass.find(1)
770
+ assert_equal "omg", topic.title
771
+
772
+ topic.title = "lol"
773
+ assert_equal "lol", topic.author_name
774
+ end
775
+
776
+ def test_inherited_hook_removed
777
+ parent = Class.new(ActiveRecord::Base)
778
+ parent.table_name = "posts"
779
+ def parent.inherited(k)
780
+ end
781
+
782
+ klass = Class.new(parent)
783
+ assert_deprecated { klass.define_attribute_methods }
784
+ end
785
+
786
+ def test_setting_new_attributes_deprecated
787
+ t = Topic.new
788
+ assert_deprecated { t[:foo] = "bar" }
789
+ assert_equal "bar", t.foo
790
+ assert_equal "bar", t[:foo]
791
+ end
792
+
793
+ private
794
+ def cached_columns
795
+ @cached_columns ||= time_related_columns_on_topic.map(&:name)
796
+ end
797
+
798
+ def time_related_columns_on_topic
799
+ Topic.columns.select { |c| c.type.in?([:time, :date, :datetime, :timestamp]) }
800
+ end
801
+
802
+ def in_time_zone(zone)
803
+ old_zone = Time.zone
804
+ old_tz = ActiveRecord::Base.time_zone_aware_attributes
805
+
806
+ Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
807
+ ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
808
+ yield
809
+ ensure
810
+ Time.zone = old_zone
811
+ ActiveRecord::Base.time_zone_aware_attributes = old_tz
812
+ end
813
+
814
+ def privatize(method_signature)
815
+ @target.class_eval <<-private_method
816
+ private
817
+ def #{method_signature}
818
+ "I'm private"
819
+ end
820
+ private_method
821
+ end
822
+ end