db2 2.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGES +181 -0
  3. data/LICENSE +18 -0
  4. data/MANIFEST +14 -0
  5. data/ParameterizedQueries README +39 -0
  6. data/README +282 -0
  7. data/ext/Makefile.nt32 +181 -0
  8. data/ext/extconf.rb +66 -0
  9. data/ext/ibm_db.c +11166 -0
  10. data/ext/ruby_ibm_db.h +236 -0
  11. data/ext/ruby_ibm_db_cli.c +738 -0
  12. data/ext/ruby_ibm_db_cli.h +431 -0
  13. data/init.rb +42 -0
  14. data/lib/IBM_DB.rb +2 -0
  15. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2558 -0
  16. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
  17. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
  18. data/test/cases/adapter_test.rb +202 -0
  19. data/test/cases/associations/belongs_to_associations_test.rb +486 -0
  20. data/test/cases/associations/cascaded_eager_loading_test.rb +183 -0
  21. data/test/cases/associations/eager_test.rb +862 -0
  22. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +917 -0
  23. data/test/cases/associations/has_many_through_associations_test.rb +461 -0
  24. data/test/cases/associations/join_model_test.rb +793 -0
  25. data/test/cases/attribute_methods_test.rb +621 -0
  26. data/test/cases/base_test.rb +1486 -0
  27. data/test/cases/calculations_test.rb +362 -0
  28. data/test/cases/finder_test.rb +1088 -0
  29. data/test/cases/fixtures_test.rb +684 -0
  30. data/test/cases/migration_test.rb +2014 -0
  31. data/test/cases/schema_dumper_test.rb +232 -0
  32. data/test/cases/validations/uniqueness_validation_test.rb +283 -0
  33. data/test/connections/native_ibm_db/connection.rb +42 -0
  34. data/test/ibm_db_test.rb +25 -0
  35. data/test/models/warehouse_thing.rb +5 -0
  36. data/test/schema/i5/ibm_db_specific_schema.rb +135 -0
  37. data/test/schema/ids/ibm_db_specific_schema.rb +138 -0
  38. data/test/schema/luw/ibm_db_specific_schema.rb +135 -0
  39. data/test/schema/schema.rb +647 -0
  40. data/test/schema/zOS/ibm_db_specific_schema.rb +206 -0
  41. metadata +105 -0
@@ -0,0 +1,621 @@
1
+ require "cases/helper"
2
+ require 'models/minimalistic'
3
+ require 'models/developer'
4
+ require 'models/auto_id'
5
+ require 'models/boolean'
6
+ require 'models/computer'
7
+ require 'models/topic'
8
+ require 'models/company'
9
+ require 'models/category'
10
+ require 'models/reply'
11
+
12
+ class AttributeMethodsTest < ActiveRecord::TestCase
13
+ fixtures :topics, :developers, :companies, :computers
14
+
15
+ def setup
16
+ @old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
17
+ @target = Class.new(ActiveRecord::Base)
18
+ @target.table_name = 'topics'
19
+ end
20
+
21
+ def teardown
22
+ ActiveRecord::Base.send(:attribute_method_matchers).clear
23
+ ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
24
+ end
25
+
26
+ def test_attribute_present
27
+ t = Topic.new
28
+ t.title = "hello there!"
29
+ t.written_on = Time.now
30
+ assert t.attribute_present?("title")
31
+ assert t.attribute_present?("written_on")
32
+ assert !t.attribute_present?("content")
33
+ end
34
+
35
+ def test_attribute_keys_on_new_instance
36
+ t = Topic.new
37
+ assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
38
+ assert_raise(NoMethodError) { t.title2 }
39
+ end
40
+
41
+ def test_boolean_attributes
42
+ assert ! Topic.find(1).approved?
43
+ assert Topic.find(2).approved?
44
+ end
45
+
46
+ def test_set_attributes
47
+ topic = Topic.find(1)
48
+ topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
49
+ topic.save
50
+ assert_equal("Budget", topic.title)
51
+ assert_equal("Jason", topic.author_name)
52
+ assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
53
+ end
54
+
55
+ def test_set_attributes_without_hash
56
+ topic = Topic.new
57
+ assert_nothing_raised { topic.attributes = '' }
58
+ end
59
+
60
+ def test_integers_as_nil
61
+ test = AutoId.create('value' => '')
62
+ assert_nil AutoId.find(test.id).value
63
+ end
64
+
65
+ def test_set_attributes_with_block
66
+ topic = Topic.new do |t|
67
+ t.title = "Budget"
68
+ t.author_name = "Jason"
69
+ end
70
+
71
+ assert_equal("Budget", topic.title)
72
+ assert_equal("Jason", topic.author_name)
73
+ end
74
+
75
+ def test_respond_to?
76
+ topic = Topic.find(1)
77
+ assert_respond_to topic, "title"
78
+ assert_respond_to topic, "title?"
79
+ assert_respond_to topic, "title="
80
+ assert_respond_to topic, :title
81
+ assert_respond_to topic, :title?
82
+ assert_respond_to topic, :title=
83
+ assert_respond_to topic, "author_name"
84
+ assert_respond_to topic, "attribute_names"
85
+ assert !topic.respond_to?("nothingness")
86
+ assert !topic.respond_to?(:nothingness)
87
+ end
88
+
89
+ def test_array_content
90
+ topic = Topic.new
91
+ topic.content = %w( one two three )
92
+ topic.save
93
+
94
+ assert_equal(%w( one two three ), Topic.find(topic.id).content)
95
+ end
96
+
97
+ def test_read_attributes_before_type_cast
98
+ category = Category.new({:name=>"Test categoty", :type => nil})
99
+ category_attrs = {"name"=>"Test categoty", "type" => nil, "categorizations_count" => nil}
100
+ assert_equal category_attrs , category.attributes_before_type_cast
101
+ end
102
+
103
+ if current_adapter?(:MysqlAdapter)
104
+ def test_read_attributes_before_type_cast_on_boolean
105
+ bool = Boolean.create({ "value" => false })
106
+ assert_equal "0", bool.reload.attributes_before_type_cast["value"]
107
+ end
108
+ end
109
+
110
+ unless current_adapter?(:Mysql2Adapter)
111
+ def test_read_attributes_before_type_cast_on_datetime
112
+ developer = Developer.find(:first)
113
+ # Oracle adapter returns Time before type cast
114
+ unless current_adapter?(:OracleAdapter)
115
+ assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"]
116
+ else
117
+ assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"].to_s(:db)
118
+
119
+ developer.created_at = "345643456"
120
+ assert_equal developer.created_at_before_type_cast, "345643456"
121
+ assert_equal developer.created_at, nil
122
+
123
+ developer.created_at = "2010-03-21 21:23:32"
124
+ assert_equal developer.created_at_before_type_cast, "2010-03-21 21:23:32"
125
+ assert_equal developer.created_at, Time.parse("2010-03-21 21:23:32")
126
+ end
127
+ end
128
+ end
129
+
130
+ def test_hash_content
131
+ topic = Topic.new
132
+ topic.content = { "one" => 1, "two" => 2 }
133
+ topic.save
134
+
135
+ assert_equal 2, Topic.find(topic.id).content["two"]
136
+
137
+ topic.content_will_change!
138
+ topic.content["three"] = 3
139
+ topic.save
140
+
141
+ assert_equal 3, Topic.find(topic.id).content["three"]
142
+ end
143
+
144
+ def test_update_array_content
145
+ topic = Topic.new
146
+ topic.content = %w( one two three )
147
+
148
+ topic.content.push "four"
149
+ assert_equal(%w( one two three four ), topic.content)
150
+
151
+ topic.save
152
+
153
+ topic = Topic.find(topic.id)
154
+ topic.content << "five"
155
+ assert_equal(%w( one two three four five ), topic.content)
156
+ end
157
+
158
+ def test_case_sensitive_attributes_hash
159
+ # DB2 is not case-sensitive
160
+ return true if current_adapter?(:DB2Adapter)
161
+
162
+ assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
163
+ end
164
+
165
+ def test_hashes_not_mangled
166
+ new_topic = { :title => "New Topic" }
167
+ new_topic_values = { :title => "AnotherTopic" }
168
+
169
+ topic = Topic.new(new_topic)
170
+ assert_equal new_topic[:title], topic.title
171
+
172
+ topic.attributes= new_topic_values
173
+ assert_equal new_topic_values[:title], topic.title
174
+ end
175
+
176
+ def test_create_through_factory
177
+ topic = Topic.create("title" => "New Topic")
178
+ topicReloaded = Topic.find(topic.id)
179
+ assert_equal(topic, topicReloaded)
180
+ end
181
+
182
+ def test_write_attribute
183
+ topic = Topic.new
184
+ topic.send(:write_attribute, :title, "Still another topic")
185
+ assert_equal "Still another topic", topic.title
186
+
187
+ topic.send(:write_attribute, "title", "Still another topic: part 2")
188
+ assert_equal "Still another topic: part 2", topic.title
189
+ end
190
+
191
+ def test_read_attribute
192
+ topic = Topic.new
193
+ topic.title = "Don't change the topic"
194
+ assert_equal "Don't change the topic", topic.send(:read_attribute, "title")
195
+ assert_equal "Don't change the topic", topic["title"]
196
+
197
+ assert_equal "Don't change the topic", topic.send(:read_attribute, :title)
198
+ assert_equal "Don't change the topic", topic[:title]
199
+ end
200
+
201
+ def test_read_attribute_when_false
202
+ topic = topics(:first)
203
+ topic.approved = false
204
+ assert !topic.approved?, "approved should be false"
205
+ topic.approved = "false"
206
+ assert !topic.approved?, "approved should be false"
207
+ end
208
+
209
+ def test_read_attribute_when_true
210
+ topic = topics(:first)
211
+ topic.approved = true
212
+ assert topic.approved?, "approved should be true"
213
+ topic.approved = "true"
214
+ assert topic.approved?, "approved should be true"
215
+ end
216
+
217
+ def test_read_write_boolean_attribute
218
+ topic = Topic.new
219
+ # puts ""
220
+ # puts "New Topic"
221
+ # puts topic.inspect
222
+ topic.approved = "false"
223
+ # puts "Expecting false"
224
+ # puts topic.inspect
225
+ assert !topic.approved?, "approved should be false"
226
+ topic.approved = "false"
227
+ # puts "Expecting false"
228
+ # puts topic.inspect
229
+ assert !topic.approved?, "approved should be false"
230
+ topic.approved = "true"
231
+ # puts "Expecting true"
232
+ # puts topic.inspect
233
+ assert topic.approved?, "approved should be true"
234
+ topic.approved = "true"
235
+ # puts "Expecting true"
236
+ # puts topic.inspect
237
+ assert topic.approved?, "approved should be true"
238
+ # puts ""
239
+ end
240
+
241
+ def test_query_attribute_string
242
+ [nil, "", " "].each do |value|
243
+ assert_equal false, Topic.new(:author_name => value).author_name?
244
+ end
245
+
246
+ assert_equal true, Topic.new(:author_name => "Name").author_name?
247
+ end
248
+
249
+ def test_query_attribute_number
250
+ [nil, 0, "0"].each do |value|
251
+ assert_equal false, Developer.new(:salary => value).salary?
252
+ end
253
+
254
+ assert_equal true, Developer.new(:salary => 1).salary?
255
+ assert_equal true, Developer.new(:salary => "1").salary?
256
+ end
257
+
258
+ def test_query_attribute_boolean
259
+ [nil, "", false, "false", "f", 0].each do |value|
260
+ assert_equal false, Topic.new(:approved => value).approved?
261
+ end
262
+
263
+ [true, "true", "1", 1].each do |value|
264
+ assert_equal true, Topic.new(:approved => value).approved?
265
+ end
266
+ end
267
+
268
+ def test_query_attribute_with_custom_fields
269
+ object = Company.find_by_sql(<<-SQL).first
270
+ SELECT c1.*, c2.ruby_type as string_value, c2.rating as int_value
271
+ FROM companies c1, companies c2
272
+ WHERE c1.firm_id = c2.id
273
+ AND c1.id = 2
274
+ SQL
275
+
276
+ assert_equal "Firm", object.string_value
277
+ assert object.string_value?
278
+
279
+ object.string_value = " "
280
+ assert !object.string_value?
281
+
282
+ assert_equal 1, object.int_value.to_i
283
+ assert object.int_value?
284
+
285
+ object.int_value = "0"
286
+ assert !object.int_value?
287
+ end
288
+
289
+ def test_non_attribute_access_and_assignment
290
+ topic = Topic.new
291
+ assert !topic.respond_to?("mumbo")
292
+ assert_raise(NoMethodError) { topic.mumbo }
293
+ assert_raise(NoMethodError) { topic.mumbo = 5 }
294
+ end
295
+
296
+ def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing
297
+ topic = @target.new(:title => 'Budget')
298
+ assert topic.respond_to?('title')
299
+ assert_equal 'Budget', topic.title
300
+ assert !topic.respond_to?('title_hello_world')
301
+ assert_raise(NoMethodError) { topic.title_hello_world }
302
+ end
303
+
304
+ def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing
305
+ topic = @target.new(:title => 'Budget')
306
+ %w(default_ title_).each do |prefix|
307
+ @target.class_eval "def #{prefix}attribute(*args) args end"
308
+ @target.attribute_method_prefix prefix
309
+
310
+ meth = "#{prefix}title"
311
+ assert topic.respond_to?(meth)
312
+ assert_equal ['title'], topic.send(meth)
313
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
314
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
315
+ end
316
+ end
317
+
318
+ def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing
319
+ topic = @target.new(:title => 'Budget')
320
+ %w(_default _title_default _it! _candidate= able?).each do |suffix|
321
+ @target.class_eval "def attribute#{suffix}(*args) args end"
322
+ @target.attribute_method_suffix suffix
323
+
324
+ meth = "title#{suffix}"
325
+ assert topic.respond_to?(meth)
326
+ assert_equal ['title'], topic.send(meth)
327
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
328
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
329
+ end
330
+ end
331
+
332
+ def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing
333
+ topic = @target.new(:title => 'Budget')
334
+ [['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix|
335
+ @target.class_eval "def #{prefix}attribute#{suffix}(*args) args end"
336
+ @target.attribute_method_affix({ :prefix => prefix, :suffix => suffix })
337
+
338
+ meth = "#{prefix}title#{suffix}"
339
+ assert topic.respond_to?(meth)
340
+ assert_equal ['title'], topic.send(meth)
341
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
342
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
343
+ end
344
+ end
345
+
346
+ def test_should_unserialize_attributes_for_frozen_records
347
+ myobj = {:value1 => :value2}
348
+ topic = Topic.create("content" => myobj)
349
+ topic.freeze
350
+ assert_equal myobj, topic.content
351
+ end
352
+
353
+ def test_typecast_attribute_from_select_to_false
354
+ topic = Topic.create(:title => 'Budget')
355
+ # Oracle does not support boolean expressions in SELECT
356
+ if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
357
+ topic = Topic.find(:first, :select => "topics.*, 0 as is_test")
358
+ else
359
+ topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
360
+ end
361
+ assert !topic.is_test?
362
+ end
363
+
364
+ def test_typecast_attribute_from_select_to_true
365
+ topic = Topic.create(:title => 'Budget')
366
+ # Oracle does not support boolean expressions in SELECT
367
+ if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
368
+ topic = Topic.find(:first, :select => "topics.*, 1 as is_test")
369
+ else
370
+ topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
371
+ end
372
+ assert topic.is_test?
373
+ end
374
+
375
+ def test_kernel_methods_not_implemented_in_activerecord
376
+ %w(test name display y).each do |method|
377
+ assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
378
+ end
379
+ end
380
+
381
+ def test_defined_kernel_methods_implemented_in_model
382
+ %w(test name display y).each do |method|
383
+ klass = Class.new ActiveRecord::Base
384
+ klass.class_eval "def #{method}() 'defined #{method}' end"
385
+ assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
386
+ end
387
+ end
388
+
389
+ def test_defined_kernel_methods_implemented_in_model_abstract_subclass
390
+ %w(test name display y).each do |method|
391
+ abstract = Class.new ActiveRecord::Base
392
+ abstract.class_eval "def #{method}() 'defined #{method}' end"
393
+ abstract.abstract_class = true
394
+ klass = Class.new abstract
395
+ assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
396
+ end
397
+ end
398
+
399
+ def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
400
+ %w(save create_or_update).each do |method|
401
+ klass = Class.new ActiveRecord::Base
402
+ klass.class_eval "def #{method}() 'defined #{method}' end"
403
+ assert_raise ActiveRecord::DangerousAttributeError do
404
+ klass.instance_method_already_implemented?(method)
405
+ end
406
+ end
407
+ end
408
+
409
+ def test_only_time_related_columns_are_meant_to_be_cached_by_default
410
+ expected = %w(datetime timestamp time date).sort
411
+ assert_equal expected, ActiveRecord::Base.attribute_types_cached_by_default.map(&:to_s).sort
412
+ end
413
+
414
+ def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
415
+ default_attributes = Topic.cached_attributes
416
+ Topic.cache_attributes :replies_count
417
+ expected = default_attributes + ["replies_count"]
418
+ assert_equal expected.sort, Topic.cached_attributes.sort
419
+ Topic.instance_variable_set "@cached_attributes", nil
420
+ end
421
+
422
+ def test_time_related_columns_are_actually_cached
423
+ column_types = %w(datetime timestamp time date).map(&:to_sym)
424
+ column_names = Topic.columns.select{|c| column_types.include?(c.type) }.map(&:name)
425
+
426
+ assert_equal column_names.sort, Topic.cached_attributes.sort
427
+ assert_equal time_related_columns_on_topic.sort, Topic.cached_attributes.sort
428
+ end
429
+
430
+ def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
431
+ t = topics(:first)
432
+ cache = t.instance_variable_get "@attributes_cache"
433
+
434
+ assert_not_nil cache
435
+ assert cache.empty?
436
+
437
+ all_columns = Topic.columns.map(&:name)
438
+ cached_columns = time_related_columns_on_topic
439
+ uncached_columns = all_columns - cached_columns
440
+
441
+ all_columns.each do |attr_name|
442
+ attribute_gets_cached = Topic.cache_attribute?(attr_name)
443
+ val = t.send attr_name unless attr_name == "type"
444
+ if attribute_gets_cached
445
+ assert cached_columns.include?(attr_name)
446
+ assert_equal val, cache[attr_name]
447
+ else
448
+ assert uncached_columns.include?(attr_name)
449
+ assert !cache.include?(attr_name)
450
+ end
451
+ end
452
+ end
453
+
454
+ def test_time_attributes_are_retrieved_in_current_time_zone
455
+ in_time_zone "Pacific Time (US & Canada)" do
456
+ utc_time = Time.utc(2008, 1, 1)
457
+ record = @target.new
458
+ record[:written_on] = utc_time
459
+ assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
460
+ assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
461
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
462
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
463
+ end
464
+ end
465
+
466
+ def test_setting_time_zone_aware_attribute_to_utc
467
+ in_time_zone "Pacific Time (US & Canada)" do
468
+ utc_time = Time.utc(2008, 1, 1)
469
+ record = @target.new
470
+ record.written_on = utc_time
471
+ assert_equal utc_time, record.written_on
472
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
473
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
474
+ end
475
+ end
476
+
477
+ def test_setting_time_zone_aware_attribute_in_other_time_zone
478
+ utc_time = Time.utc(2008, 1, 1)
479
+ cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
480
+ in_time_zone "Pacific Time (US & Canada)" do
481
+ record = @target.new
482
+ record.written_on = cst_time
483
+ assert_equal utc_time, record.written_on
484
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
485
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
486
+ end
487
+ end
488
+
489
+ def test_setting_time_zone_aware_attribute_with_string
490
+ utc_time = Time.utc(2008, 1, 1)
491
+ (-11..13).each do |timezone_offset|
492
+ time_string = utc_time.in_time_zone(timezone_offset).to_s
493
+ in_time_zone "Pacific Time (US & Canada)" do
494
+ record = @target.new
495
+ record.written_on = time_string
496
+ assert_equal Time.zone.parse(time_string), record.written_on
497
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
498
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
499
+ end
500
+ end
501
+ end
502
+
503
+ def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
504
+ in_time_zone "Pacific Time (US & Canada)" do
505
+ record = @target.new
506
+ record.written_on = ' '
507
+ assert_nil record.written_on
508
+ end
509
+ end
510
+
511
+ def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
512
+ time_string = 'Tue Jan 01 00:00:00 2008'
513
+ (-11..13).each do |timezone_offset|
514
+ in_time_zone timezone_offset do
515
+ record = @target.new
516
+ record.written_on = time_string
517
+ assert_equal Time.zone.parse(time_string), record.written_on
518
+ assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
519
+ assert_equal Time.utc(2008, 1, 1), record.written_on.time
520
+ end
521
+ end
522
+ end
523
+
524
+ def test_setting_time_zone_aware_attribute_in_current_time_zone
525
+ utc_time = Time.utc(2008, 1, 1)
526
+ in_time_zone "Pacific Time (US & Canada)" do
527
+ record = @target.new
528
+ record.written_on = utc_time.in_time_zone
529
+ assert_equal utc_time, record.written_on
530
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
531
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
532
+ end
533
+ end
534
+
535
+ def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
536
+ Topic.skip_time_zone_conversion_for_attributes = [:field_a]
537
+ Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
538
+
539
+ assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
540
+ assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
541
+ end
542
+
543
+ def test_read_attributes_respect_access_control
544
+ privatize("title")
545
+
546
+ topic = @target.new(:title => "The pros and cons of programming naked.")
547
+ assert !topic.respond_to?(:title)
548
+ exception = assert_raise(NoMethodError) { topic.title }
549
+ assert_equal "Attempt to call private method", exception.message
550
+ assert_equal "I'm private", topic.send(:title)
551
+ end
552
+
553
+ def test_write_attributes_respect_access_control
554
+ privatize("title=(value)")
555
+
556
+ topic = @target.new
557
+ assert !topic.respond_to?(:title=)
558
+ exception = assert_raise(NoMethodError) { topic.title = "Pants"}
559
+ assert_equal "Attempt to call private method", exception.message
560
+ topic.send(:title=, "Very large pants")
561
+ end
562
+
563
+ def test_question_attributes_respect_access_control
564
+ privatize("title?")
565
+
566
+ topic = @target.new(:title => "Isaac Newton's pants")
567
+ assert !topic.respond_to?(:title?)
568
+ exception = assert_raise(NoMethodError) { topic.title? }
569
+ assert_equal "Attempt to call private method", exception.message
570
+ assert topic.send(:title?)
571
+ end
572
+
573
+ def test_bulk_update_respects_access_control
574
+ privatize("title=(value)")
575
+
576
+ assert_raise(ActiveRecord::UnknownAttributeError) { topic = @target.new(:title => "Rants about pants") }
577
+ assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
578
+ end
579
+
580
+ def test_read_attribute_overwrites_private_method_not_considered_implemented
581
+ # simulate a model with a db column that shares its name an inherited
582
+ # private method (e.g. Object#system)
583
+ #
584
+ Object.class_eval do
585
+ private
586
+ def title; "private!"; end
587
+ end
588
+ assert !@target.instance_method_already_implemented?(:title)
589
+ topic = @target.new
590
+ assert_nil topic.title
591
+
592
+ Object.send(:undef_method, :title) # remove test method from object
593
+ end
594
+
595
+
596
+ private
597
+ def time_related_columns_on_topic
598
+ Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
599
+ end
600
+
601
+ def in_time_zone(zone)
602
+ old_zone = Time.zone
603
+ old_tz = ActiveRecord::Base.time_zone_aware_attributes
604
+
605
+ Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
606
+ ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
607
+ yield
608
+ ensure
609
+ Time.zone = old_zone
610
+ ActiveRecord::Base.time_zone_aware_attributes = old_tz
611
+ end
612
+
613
+ def privatize(method_signature)
614
+ @target.class_eval <<-private_method
615
+ private
616
+ def #{method_signature}
617
+ "I'm private"
618
+ end
619
+ private_method
620
+ end
621
+ end