ibm_db 2.5.6-x86-mswin32-60
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.
- data/CHANGES +181 -0
- data/LICENSE +18 -0
- data/MANIFEST +14 -0
- data/ParameterizedQueries README +39 -0
- data/README +282 -0
- data/ext/Makefile.nt32 +181 -0
- data/ext/extconf.rb +66 -0
- data/ext/ibm_db.c +11166 -0
- data/ext/ruby_ibm_db.h +236 -0
- data/ext/ruby_ibm_db_cli.c +738 -0
- data/ext/ruby_ibm_db_cli.h +431 -0
- data/init.rb +42 -0
- data/lib/IBM_DB.rb +2 -0
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2598 -0
- data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
- data/lib/mswin32/ibm_db.rb +1 -0
- data/lib/mswin32/rb18x/ibm_db.so +0 -0
- data/lib/mswin32/rb19x/ibm_db.so +0 -0
- data/test/cases/adapter_test.rb +202 -0
- data/test/cases/associations/belongs_to_associations_test.rb +486 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +183 -0
- data/test/cases/associations/eager_test.rb +862 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +917 -0
- data/test/cases/associations/has_many_through_associations_test.rb +461 -0
- data/test/cases/associations/join_model_test.rb +793 -0
- data/test/cases/attribute_methods_test.rb +621 -0
- data/test/cases/base_test.rb +1486 -0
- data/test/cases/calculations_test.rb +362 -0
- data/test/cases/finder_test.rb +1088 -0
- data/test/cases/fixtures_test.rb +684 -0
- data/test/cases/migration_test.rb +2014 -0
- data/test/cases/schema_dumper_test.rb +232 -0
- data/test/cases/validations/uniqueness_validation_test.rb +283 -0
- data/test/connections/native_ibm_db/connection.rb +42 -0
- data/test/ibm_db_test.rb +25 -0
- data/test/models/warehouse_thing.rb +5 -0
- data/test/schema/i5/ibm_db_specific_schema.rb +135 -0
- data/test/schema/ids/ibm_db_specific_schema.rb +138 -0
- data/test/schema/luw/ibm_db_specific_schema.rb +135 -0
- data/test/schema/schema.rb +647 -0
- data/test/schema/zOS/ibm_db_specific_schema.rb +206 -0
- metadata +107 -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
|