ibm_db 1.0.2 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +8 -0
- data/README +1 -1
- data/ext/ibm_db.c +9 -6
- data/ext/ruby_ibm_db.h +9 -1
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +33 -16
- data/test/cases/associations/cascaded_eager_loading_test.rb +8 -0
- data/test/cases/associations/eager_test.rb +140 -8
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +77 -28
- data/test/cases/associations/has_many_through_associations_test.rb +39 -7
- data/test/cases/associations/join_model_test.rb +5 -7
- data/test/cases/attribute_methods_test.rb +312 -0
- data/test/cases/base_test.rb +44 -24
- data/test/cases/calculations_test.rb +37 -17
- data/test/cases/finder_test.rb +79 -44
- data/test/cases/fixtures_test.rb +15 -19
- data/test/cases/migration_test.rb +91 -67
- data/test/cases/query_cache_test.rb +20 -24
- data/test/cases/schema_dumper_test.rb +0 -1
- data/test/cases/validations_test.rb +228 -178
- data/test/schema/schema.rb +484 -451
- metadata +4 -3
@@ -1,11 +1,19 @@
|
|
1
1
|
require "cases/helper"
|
2
2
|
require 'models/post'
|
3
3
|
require 'models/person'
|
4
|
+
require 'models/reference'
|
5
|
+
require 'models/job'
|
4
6
|
require 'models/reader'
|
5
7
|
require 'models/comment'
|
8
|
+
require 'models/tag'
|
9
|
+
require 'models/tagging'
|
10
|
+
require 'models/author'
|
11
|
+
require 'models/owner'
|
12
|
+
require 'models/pet'
|
13
|
+
require 'models/toy'
|
6
14
|
|
7
15
|
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
8
|
-
fixtures :posts, :readers, :people, :comments, :authors
|
16
|
+
fixtures :posts, :readers, :people, :comments, :authors, :owners, :pets, :toys
|
9
17
|
|
10
18
|
def test_associate_existing
|
11
19
|
assert_queries(2) { posts(:thinking);people(:david) }
|
@@ -84,6 +92,24 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
|
84
92
|
assert posts(:welcome).reload.people(true).empty?
|
85
93
|
end
|
86
94
|
|
95
|
+
def test_destroy_association
|
96
|
+
assert_difference "Person.count", -1 do
|
97
|
+
posts(:welcome).people.destroy(people(:michael))
|
98
|
+
end
|
99
|
+
|
100
|
+
assert posts(:welcome).reload.people.empty?
|
101
|
+
assert posts(:welcome).people(true).empty?
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_destroy_all
|
105
|
+
assert_difference "Person.count", -1 do
|
106
|
+
posts(:welcome).people.destroy_all
|
107
|
+
end
|
108
|
+
|
109
|
+
assert posts(:welcome).reload.people.empty?
|
110
|
+
assert posts(:welcome).people(true).empty?
|
111
|
+
end
|
112
|
+
|
87
113
|
def test_replace_association
|
88
114
|
assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
|
89
115
|
|
@@ -203,6 +229,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
|
203
229
|
assert_equal 2, people(:michael).posts.count(:include => :readers)
|
204
230
|
end
|
205
231
|
|
232
|
+
def test_inner_join_with_quoted_table_name
|
233
|
+
assert_equal 2, people(:michael).jobs.size
|
234
|
+
end
|
235
|
+
|
206
236
|
def test_get_ids
|
207
237
|
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
|
208
238
|
end
|
@@ -223,12 +253,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
|
223
253
|
assert !person.posts.loaded?
|
224
254
|
end
|
225
255
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
# nothing
|
231
|
-
end
|
256
|
+
def test_association_proxy_transaction_method_starts_transaction_in_association_class
|
257
|
+
Tag.expects(:transaction)
|
258
|
+
Post.find(:first).tags.transaction do
|
259
|
+
# nothing
|
232
260
|
end
|
233
261
|
end
|
234
262
|
|
@@ -246,4 +274,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
|
|
246
274
|
author.author_favorites.create(:favorite_author_id => 3)
|
247
275
|
assert_equal post.author.author_favorites, post.author_favorites
|
248
276
|
end
|
277
|
+
|
278
|
+
def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
|
279
|
+
assert_equal 1, owners(:blackbeard).toys.count
|
280
|
+
end
|
249
281
|
end
|
@@ -568,13 +568,11 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
|
|
568
568
|
assert !author.comments.loaded?
|
569
569
|
end
|
570
570
|
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
assert !author.comments.loaded?
|
577
|
-
end
|
571
|
+
def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
|
572
|
+
author = authors(:david)
|
573
|
+
author.stubs(:read_attribute).with('comments_count').returns(100)
|
574
|
+
assert_equal 100, author.comments.size
|
575
|
+
assert !author.comments.loaded?
|
578
576
|
end
|
579
577
|
|
580
578
|
def test_adding_junk_to_has_many_through_should_raise_type_mismatch
|
@@ -0,0 +1,312 @@
|
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/topic'
|
3
|
+
require 'models/minimalistic'
|
4
|
+
|
5
|
+
class AttributeMethodsTest < ActiveRecord::TestCase
|
6
|
+
fixtures :topics
|
7
|
+
def setup
|
8
|
+
@old_suffixes = ActiveRecord::Base.send(:attribute_method_suffixes).dup
|
9
|
+
@target = Class.new(ActiveRecord::Base)
|
10
|
+
@target.table_name = 'topics'
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
ActiveRecord::Base.send(:attribute_method_suffixes).clear
|
15
|
+
ActiveRecord::Base.attribute_method_suffix *@old_suffixes
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_match_attribute_method_query_returns_match_data
|
19
|
+
assert_not_nil md = @target.match_attribute_method?('title=')
|
20
|
+
assert_equal 'title', md.pre_match
|
21
|
+
assert_equal ['='], md.captures
|
22
|
+
|
23
|
+
%w(_hello_world ist! _maybe?).each do |suffix|
|
24
|
+
@target.class_eval "def attribute#{suffix}(*args) args end"
|
25
|
+
@target.attribute_method_suffix suffix
|
26
|
+
|
27
|
+
assert_not_nil md = @target.match_attribute_method?("title#{suffix}")
|
28
|
+
assert_equal 'title', md.pre_match
|
29
|
+
assert_equal [suffix], md.captures
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_declared_attribute_method_affects_respond_to_and_method_missing
|
34
|
+
topic = @target.new(:title => 'Budget')
|
35
|
+
assert topic.respond_to?('title')
|
36
|
+
assert_equal 'Budget', topic.title
|
37
|
+
assert !topic.respond_to?('title_hello_world')
|
38
|
+
assert_raise(NoMethodError) { topic.title_hello_world }
|
39
|
+
|
40
|
+
%w(_hello_world _it! _candidate= able?).each do |suffix|
|
41
|
+
@target.class_eval "def attribute#{suffix}(*args) args end"
|
42
|
+
@target.attribute_method_suffix suffix
|
43
|
+
|
44
|
+
meth = "title#{suffix}"
|
45
|
+
assert topic.respond_to?(meth)
|
46
|
+
assert_equal ['title'], topic.send(meth)
|
47
|
+
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
48
|
+
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_should_unserialize_attributes_for_frozen_records
|
53
|
+
myobj = {:value1 => :value2}
|
54
|
+
topic = Topic.create("content" => myobj)
|
55
|
+
topic.freeze
|
56
|
+
assert_equal myobj, topic.content
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_typecast_attribute_from_select_to_false
|
60
|
+
topic = Topic.create(:title => 'Budget')
|
61
|
+
unless current_adapter?(:IBM_DBAdapter)
|
62
|
+
topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
|
63
|
+
assert !topic.is_test?
|
64
|
+
else
|
65
|
+
topic = Topic.find(:first, :select => "topics.approved as is_test")
|
66
|
+
assert topic.is_test?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
unless current_adapter?(:IBM_DBAdapter)
|
71
|
+
def test_typecast_attribute_from_select_to_true
|
72
|
+
topic = Topic.create(:title => 'Budget')
|
73
|
+
topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
|
74
|
+
assert topic.is_test?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_kernel_methods_not_implemented_in_activerecord
|
79
|
+
%w(test name display y).each do |method|
|
80
|
+
assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_primary_key_implemented
|
85
|
+
assert Class.new(ActiveRecord::Base).instance_method_already_implemented?('id')
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_defined_kernel_methods_implemented_in_model
|
89
|
+
%w(test name display y).each do |method|
|
90
|
+
klass = Class.new ActiveRecord::Base
|
91
|
+
klass.class_eval "def #{method}() 'defined #{method}' end"
|
92
|
+
assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_defined_kernel_methods_implemented_in_model_abstract_subclass
|
97
|
+
%w(test name display y).each do |method|
|
98
|
+
abstract = Class.new ActiveRecord::Base
|
99
|
+
abstract.class_eval "def #{method}() 'defined #{method}' end"
|
100
|
+
abstract.abstract_class = true
|
101
|
+
klass = Class.new abstract
|
102
|
+
assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
|
107
|
+
%w(save create_or_update).each do |method|
|
108
|
+
klass = Class.new ActiveRecord::Base
|
109
|
+
klass.class_eval "def #{method}() 'defined #{method}' end"
|
110
|
+
assert_raise ActiveRecord::DangerousAttributeError do
|
111
|
+
klass.instance_method_already_implemented?(method)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_only_time_related_columns_are_meant_to_be_cached_by_default
|
117
|
+
expected = %w(datetime timestamp time date).sort
|
118
|
+
assert_equal expected, ActiveRecord::Base.attribute_types_cached_by_default.map(&:to_s).sort
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
|
122
|
+
default_attributes = Topic.cached_attributes
|
123
|
+
Topic.cache_attributes :replies_count
|
124
|
+
expected = default_attributes + ["replies_count"]
|
125
|
+
assert_equal expected.sort, Topic.cached_attributes.sort
|
126
|
+
Topic.instance_variable_set "@cached_attributes", nil
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_time_related_columns_are_actually_cached
|
130
|
+
column_types = %w(datetime timestamp time date).map(&:to_sym)
|
131
|
+
column_names = Topic.columns.select{|c| column_types.include?(c.type) }.map(&:name)
|
132
|
+
|
133
|
+
assert_equal column_names.sort, Topic.cached_attributes.sort
|
134
|
+
assert_equal time_related_columns_on_topic.sort, Topic.cached_attributes.sort
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
|
138
|
+
t = topics(:first)
|
139
|
+
cache = t.instance_variable_get "@attributes_cache"
|
140
|
+
|
141
|
+
assert_not_nil cache
|
142
|
+
assert cache.empty?
|
143
|
+
|
144
|
+
all_columns = Topic.columns.map(&:name)
|
145
|
+
cached_columns = time_related_columns_on_topic
|
146
|
+
uncached_columns = all_columns - cached_columns
|
147
|
+
|
148
|
+
all_columns.each do |attr_name|
|
149
|
+
attribute_gets_cached = Topic.cache_attribute?(attr_name)
|
150
|
+
val = t.send attr_name unless attr_name == "type"
|
151
|
+
if attribute_gets_cached
|
152
|
+
assert cached_columns.include?(attr_name)
|
153
|
+
assert_equal val, cache[attr_name]
|
154
|
+
else
|
155
|
+
assert uncached_columns.include?(attr_name)
|
156
|
+
assert !cache.include?(attr_name)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_time_attributes_are_retrieved_in_current_time_zone
|
162
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
163
|
+
utc_time = Time.utc(2008, 1, 1)
|
164
|
+
record = @target.new
|
165
|
+
record[:written_on] = utc_time
|
166
|
+
assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
|
167
|
+
assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
|
168
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
|
169
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_setting_time_zone_aware_attribute_to_utc
|
174
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
175
|
+
utc_time = Time.utc(2008, 1, 1)
|
176
|
+
record = @target.new
|
177
|
+
record.written_on = utc_time
|
178
|
+
assert_equal utc_time, record.written_on
|
179
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
180
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_setting_time_zone_aware_attribute_in_other_time_zone
|
185
|
+
utc_time = Time.utc(2008, 1, 1)
|
186
|
+
cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
|
187
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
188
|
+
record = @target.new
|
189
|
+
record.written_on = cst_time
|
190
|
+
assert_equal utc_time, record.written_on
|
191
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
192
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_setting_time_zone_aware_attribute_with_string
|
197
|
+
utc_time = Time.utc(2008, 1, 1)
|
198
|
+
(-11..13).each do |timezone_offset|
|
199
|
+
time_string = utc_time.in_time_zone(timezone_offset).to_s
|
200
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
201
|
+
record = @target.new
|
202
|
+
record.written_on = time_string
|
203
|
+
assert_equal Time.zone.parse(time_string), record.written_on
|
204
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
205
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
|
211
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
212
|
+
record = @target.new
|
213
|
+
record.written_on = ' '
|
214
|
+
assert_nil record.written_on
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
|
219
|
+
time_string = 'Tue Jan 01 00:00:00 2008'
|
220
|
+
(-11..13).each do |timezone_offset|
|
221
|
+
in_time_zone timezone_offset do
|
222
|
+
record = @target.new
|
223
|
+
record.written_on = time_string
|
224
|
+
assert_equal Time.zone.parse(time_string), record.written_on
|
225
|
+
assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
|
226
|
+
assert_equal Time.utc(2008, 1, 1), record.written_on.time
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_setting_time_zone_aware_attribute_in_current_time_zone
|
232
|
+
utc_time = Time.utc(2008, 1, 1)
|
233
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
234
|
+
record = @target.new
|
235
|
+
record.written_on = utc_time.in_time_zone
|
236
|
+
assert_equal utc_time, record.written_on
|
237
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
238
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
|
243
|
+
Topic.skip_time_zone_conversion_for_attributes = [:field_a]
|
244
|
+
Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
|
245
|
+
|
246
|
+
assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
|
247
|
+
assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_read_attributes_respect_access_control
|
251
|
+
privatize("title")
|
252
|
+
|
253
|
+
topic = @target.new(:title => "The pros and cons of programming naked.")
|
254
|
+
assert !topic.respond_to?(:title)
|
255
|
+
exception = assert_raise(NoMethodError) { topic.title }
|
256
|
+
assert_equal "Attempt to call private method", exception.message
|
257
|
+
assert_equal "I'm private", topic.send(:title)
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_write_attributes_respect_access_control
|
261
|
+
privatize("title=(value)")
|
262
|
+
|
263
|
+
topic = @target.new
|
264
|
+
assert !topic.respond_to?(:title=)
|
265
|
+
exception = assert_raise(NoMethodError) { topic.title = "Pants"}
|
266
|
+
assert_equal "Attempt to call private method", exception.message
|
267
|
+
topic.send(:title=, "Very large pants")
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_question_attributes_respect_access_control
|
271
|
+
privatize("title?")
|
272
|
+
|
273
|
+
topic = @target.new(:title => "Isaac Newton's pants")
|
274
|
+
assert !topic.respond_to?(:title?)
|
275
|
+
exception = assert_raise(NoMethodError) { topic.title? }
|
276
|
+
assert_equal "Attempt to call private method", exception.message
|
277
|
+
assert topic.send(:title?)
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_bulk_update_respects_access_control
|
281
|
+
privatize("title=(value)")
|
282
|
+
|
283
|
+
assert_raise(ActiveRecord::UnknownAttributeError) { topic = @target.new(:title => "Rants about pants") }
|
284
|
+
assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
|
285
|
+
end
|
286
|
+
|
287
|
+
private
|
288
|
+
def time_related_columns_on_topic
|
289
|
+
Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
|
290
|
+
end
|
291
|
+
|
292
|
+
def in_time_zone(zone)
|
293
|
+
old_zone = Time.zone
|
294
|
+
old_tz = ActiveRecord::Base.time_zone_aware_attributes
|
295
|
+
|
296
|
+
Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
|
297
|
+
ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
|
298
|
+
yield
|
299
|
+
ensure
|
300
|
+
Time.zone = old_zone
|
301
|
+
ActiveRecord::Base.time_zone_aware_attributes = old_tz
|
302
|
+
end
|
303
|
+
|
304
|
+
def privatize(method_signature)
|
305
|
+
@target.class_eval <<-private_method
|
306
|
+
private
|
307
|
+
def #{method_signature}
|
308
|
+
"I'm private"
|
309
|
+
end
|
310
|
+
private_method
|
311
|
+
end
|
312
|
+
end
|
data/test/cases/base_test.rb
CHANGED
@@ -16,6 +16,7 @@ require 'models/post'
|
|
16
16
|
require 'models/comment'
|
17
17
|
require 'models/minimalistic'
|
18
18
|
require 'models/warehouse_thing'
|
19
|
+
require 'models/parrot'
|
19
20
|
require 'rexml/document'
|
20
21
|
|
21
22
|
class Category < ActiveRecord::Base; end
|
@@ -423,8 +424,8 @@ class BasicsTest < ActiveRecord::TestCase
|
|
423
424
|
def test_non_attribute_access_and_assignment
|
424
425
|
topic = Topic.new
|
425
426
|
assert !topic.respond_to?("mumbo")
|
426
|
-
|
427
|
-
|
427
|
+
assert_raise(NoMethodError) { topic.mumbo }
|
428
|
+
assert_raise(NoMethodError) { topic.mumbo = 5 }
|
428
429
|
end
|
429
430
|
|
430
431
|
def test_preserving_date_objects
|
@@ -489,7 +490,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
489
490
|
end
|
490
491
|
|
491
492
|
def test_record_not_found_exception
|
492
|
-
|
493
|
+
assert_raise(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(99999) }
|
493
494
|
end
|
494
495
|
|
495
496
|
def test_initialize_with_attributes
|
@@ -638,6 +639,13 @@ class BasicsTest < ActiveRecord::TestCase
|
|
638
639
|
category.reload
|
639
640
|
assert_not_nil category.categorizations_count
|
640
641
|
assert_equal 4, category.categorizations_count
|
642
|
+
|
643
|
+
category_2 = categories(:technology)
|
644
|
+
count_1, count_2 = (category.categorizations_count || 0), (category_2.categorizations_count || 0)
|
645
|
+
Category.update_counters([category.id, category_2.id], "categorizations_count" => 2)
|
646
|
+
category.reload; category_2.reload
|
647
|
+
assert_equal count_1 + 2, category.categorizations_count
|
648
|
+
assert_equal count_2 + 2, category_2.categorizations_count
|
641
649
|
end
|
642
650
|
|
643
651
|
def test_update_all
|
@@ -840,7 +848,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
840
848
|
client.delete
|
841
849
|
assert client.frozen?
|
842
850
|
assert_kind_of Firm, client.firm
|
843
|
-
|
851
|
+
assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
|
844
852
|
end
|
845
853
|
|
846
854
|
def test_destroy_new_record
|
@@ -854,7 +862,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
854
862
|
client.destroy
|
855
863
|
assert client.frozen?
|
856
864
|
assert_kind_of Firm, client.firm
|
857
|
-
|
865
|
+
assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
|
858
866
|
end
|
859
867
|
|
860
868
|
def test_update_attribute
|
@@ -902,8 +910,8 @@ class BasicsTest < ActiveRecord::TestCase
|
|
902
910
|
|
903
911
|
def test_mass_assignment_should_raise_exception_if_accessible_and_protected_attribute_writers_are_both_used
|
904
912
|
topic = TopicWithProtectedContentAndAccessibleAuthorName.new
|
905
|
-
|
906
|
-
|
913
|
+
assert_raise(RuntimeError) { topic.attributes = { "author_name" => "me" } }
|
914
|
+
assert_raise(RuntimeError) { topic.attributes = { "content" => "stuff" } }
|
907
915
|
end
|
908
916
|
|
909
917
|
def test_mass_assignment_protection
|
@@ -941,7 +949,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
941
949
|
def test_mass_assigning_invalid_attribute
|
942
950
|
firm = Firm.new
|
943
951
|
|
944
|
-
|
952
|
+
assert_raise(ActiveRecord::UnknownAttributeError) do
|
945
953
|
firm.attributes = { "id" => 5, "type" => "Client", "i_dont_even_exist" => 20 }
|
946
954
|
end
|
947
955
|
end
|
@@ -1196,7 +1204,12 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1196
1204
|
b_true = Booleantest.find(true_id)
|
1197
1205
|
assert b_true.value?
|
1198
1206
|
end
|
1199
|
-
|
1207
|
+
|
1208
|
+
def test_new_record_returns_boolean
|
1209
|
+
assert_equal Topic.new.new_record?, true
|
1210
|
+
assert_equal Topic.find(1).new_record?, false
|
1211
|
+
end
|
1212
|
+
|
1200
1213
|
def test_clone
|
1201
1214
|
topic = Topic.find(1)
|
1202
1215
|
cloned_topic = nil
|
@@ -1396,7 +1409,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1396
1409
|
end
|
1397
1410
|
|
1398
1411
|
def test_sql_injection_via_find
|
1399
|
-
|
1412
|
+
assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
|
1400
1413
|
Topic.find("123456 OR id > 0")
|
1401
1414
|
end
|
1402
1415
|
end
|
@@ -1748,7 +1761,14 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1748
1761
|
assert developers[i-1].salary >= developers[i].salary
|
1749
1762
|
end
|
1750
1763
|
end
|
1751
|
-
|
1764
|
+
|
1765
|
+
def test_scoped_find_with_group_and_having
|
1766
|
+
developers = Developer.with_scope(:find => { :group => 'salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do
|
1767
|
+
Developer.find(:all)
|
1768
|
+
end
|
1769
|
+
assert_equal 3, developers.size
|
1770
|
+
end
|
1771
|
+
|
1752
1772
|
def test_find_last
|
1753
1773
|
last = Developer.find :last
|
1754
1774
|
assert_equal last, Developer.find(:first, :order => 'id desc')
|
@@ -1776,7 +1796,12 @@ class BasicsTest < ActiveRecord::TestCase
|
|
1776
1796
|
last = Developer.find :last, :order => 'developers.name, developers.salary DESC'
|
1777
1797
|
assert_equal last, Developer.find(:all, :order => 'developers.name, developers.salary DESC').last
|
1778
1798
|
end
|
1779
|
-
|
1799
|
+
|
1800
|
+
def test_find_symbol_ordered_last
|
1801
|
+
last = Developer.find :last, :order => :salary
|
1802
|
+
assert_equal last, Developer.find(:all, :order => :salary).last
|
1803
|
+
end
|
1804
|
+
|
1780
1805
|
def test_find_scoped_ordered_last
|
1781
1806
|
last_developer = Developer.with_scope(:find => { :order => 'developers.salary ASC' }) do
|
1782
1807
|
Developer.find(:last)
|
@@ -2078,17 +2103,12 @@ class BasicsTest < ActiveRecord::TestCase
|
|
2078
2103
|
ActiveRecord::Base.logger = original_logger
|
2079
2104
|
end
|
2080
2105
|
|
2081
|
-
|
2082
|
-
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
|
2087
|
-
ensure
|
2088
|
-
$KCODE = orig_kcode
|
2089
|
-
end
|
2090
|
-
else
|
2091
|
-
yield
|
2092
|
-
end
|
2106
|
+
def test_create_with_custom_timestamps
|
2107
|
+
custom_datetime = 1.hour.ago.beginning_of_day
|
2108
|
+
|
2109
|
+
%w(created_at created_on updated_at updated_on).each do |attribute|
|
2110
|
+
parrot = LiveParrot.create(:name => "colombian", attribute => custom_datetime)
|
2111
|
+
assert_equal custom_datetime, parrot[attribute]
|
2093
2112
|
end
|
2113
|
+
end
|
2094
2114
|
end
|