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.
- checksums.yaml +4 -4
- data/CHANGES +11 -0
- data/MANIFEST +14 -14
- data/README +225 -225
- data/ext/Makefile.nt32 +181 -181
- data/ext/Makefile.nt32.191 +212 -212
- data/ext/extconf.rb +264 -261
- data/ext/extconf_MacOS.rb +269 -0
- data/ext/ibm_db.c +11879 -11793
- data/ext/ruby_ibm_db.h +241 -240
- data/ext/ruby_ibm_db_cli.c +851 -845
- data/ext/ruby_ibm_db_cli.h +500 -489
- data/init.rb +41 -41
- data/lib/IBM_DB.rb +27 -19
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3339 -3289
- data/lib/active_record/connection_adapters/ibmdb_adapter.rb +1 -1
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
- data/test/cases/adapter_test.rb +207 -207
- data/test/cases/associations/belongs_to_associations_test.rb +711 -711
- data/test/cases/associations/cascaded_eager_loading_test.rb +181 -181
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +851 -851
- data/test/cases/associations/join_model_test.rb +743 -743
- data/test/cases/attribute_methods_test.rb +822 -822
- data/test/cases/base_test.rb +2133 -2133
- data/test/cases/calculations_test.rb +482 -482
- data/test/cases/migration_test.rb +2408 -2408
- data/test/cases/persistence_test.rb +642 -642
- data/test/cases/query_cache_test.rb +257 -257
- data/test/cases/relations_test.rb +1182 -1182
- data/test/cases/schema_dumper_test.rb +256 -256
- data/test/cases/transaction_callbacks_test.rb +300 -300
- data/test/cases/validations/uniqueness_validation_test.rb +299 -299
- data/test/cases/xml_serialization_test.rb +408 -408
- data/test/config.yml +154 -154
- data/test/connections/native_ibm_db/connection.rb +43 -43
- data/test/ibm_db_test.rb +24 -24
- data/test/models/warehouse_thing.rb +4 -4
- data/test/schema/schema.rb +751 -751
- metadata +6 -8
- data/lib/linux/rb18x/ibm_db.bundle +0 -0
- data/lib/linux/rb19x/ibm_db.bundle +0 -0
- data/lib/linux/rb20x/ibm_db.bundle +0 -0
- 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
|