ibm_db 2.5.6-x86-mingw32

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. data/CHANGES +181 -0
  2. data/LICENSE +18 -0
  3. data/MANIFEST +14 -0
  4. data/ParameterizedQueries README +39 -0
  5. data/README +282 -0
  6. data/ext/Makefile.nt32 +181 -0
  7. data/ext/extconf.rb +66 -0
  8. data/ext/ibm_db.c +11166 -0
  9. data/ext/ruby_ibm_db.h +236 -0
  10. data/ext/ruby_ibm_db_cli.c +738 -0
  11. data/ext/ruby_ibm_db_cli.h +431 -0
  12. data/init.rb +42 -0
  13. data/lib/IBM_DB.rb +2 -0
  14. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2598 -0
  15. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
  16. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
  17. data/lib/mswin32/ibm_db.rb +1 -0
  18. data/lib/mswin32/rb18x/ibm_db.so +0 -0
  19. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  20. data/test/cases/adapter_test.rb +202 -0
  21. data/test/cases/associations/belongs_to_associations_test.rb +486 -0
  22. data/test/cases/associations/cascaded_eager_loading_test.rb +183 -0
  23. data/test/cases/associations/eager_test.rb +862 -0
  24. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +917 -0
  25. data/test/cases/associations/has_many_through_associations_test.rb +461 -0
  26. data/test/cases/associations/join_model_test.rb +793 -0
  27. data/test/cases/attribute_methods_test.rb +621 -0
  28. data/test/cases/base_test.rb +1486 -0
  29. data/test/cases/calculations_test.rb +362 -0
  30. data/test/cases/finder_test.rb +1088 -0
  31. data/test/cases/fixtures_test.rb +684 -0
  32. data/test/cases/migration_test.rb +2014 -0
  33. data/test/cases/schema_dumper_test.rb +232 -0
  34. data/test/cases/validations/uniqueness_validation_test.rb +283 -0
  35. data/test/connections/native_ibm_db/connection.rb +42 -0
  36. data/test/ibm_db_test.rb +25 -0
  37. data/test/models/warehouse_thing.rb +5 -0
  38. data/test/schema/i5/ibm_db_specific_schema.rb +135 -0
  39. data/test/schema/ids/ibm_db_specific_schema.rb +138 -0
  40. data/test/schema/luw/ibm_db_specific_schema.rb +135 -0
  41. data/test/schema/schema.rb +647 -0
  42. data/test/schema/zOS/ibm_db_specific_schema.rb +206 -0
  43. metadata +123 -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