ibm_db 1.1.1-mswin32
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 +155 -0
- data/LICENSE +18 -0
- data/MANIFEST +14 -0
- data/README +274 -0
- data/ext/Makefile.nt32 +181 -0
- data/ext/extconf.rb +58 -0
- data/ext/ibm_db.c +6553 -0
- data/ext/ruby_ibm_db.h +214 -0
- data/init.rb +42 -0
- data/lib/IBM_DB.rb +2 -0
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2218 -0
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
- data/lib/mswin32/ibm_db.so +0 -0
- data/test/cases/adapter_test.rb +180 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +133 -0
- data/test/cases/associations/eager_test.rb +842 -0
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +874 -0
- data/test/cases/associations/has_many_through_associations_test.rb +281 -0
- data/test/cases/associations/join_model_test.rb +801 -0
- data/test/cases/attribute_methods_test.rb +312 -0
- data/test/cases/base_test.rb +2114 -0
- data/test/cases/calculations_test.rb +346 -0
- data/test/cases/finder_test.rb +1092 -0
- data/test/cases/fixtures_test.rb +660 -0
- data/test/cases/migration_test.rb +1618 -0
- data/test/cases/schema_dumper_test.rb +197 -0
- data/test/cases/validations_test.rb +1604 -0
- data/test/connections/native_ibm_db/connection.rb +40 -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 +134 -0
- data/test/schema/ids/ibm_db_specific_schema.rb +137 -0
- data/test/schema/luw/ibm_db_specific_schema.rb +134 -0
- data/test/schema/schema.rb +499 -0
- data/test/schema/zOS/ibm_db_specific_schema.rb +205 -0
- metadata +115 -0
@@ -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
|
@@ -0,0 +1,2114 @@
|
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/author'
|
3
|
+
require 'models/topic'
|
4
|
+
require 'models/reply'
|
5
|
+
require 'models/category'
|
6
|
+
require 'models/company'
|
7
|
+
require 'models/customer'
|
8
|
+
require 'models/developer'
|
9
|
+
require 'models/project'
|
10
|
+
require 'models/default'
|
11
|
+
require 'models/auto_id'
|
12
|
+
require 'models/column_name'
|
13
|
+
require 'models/subscriber'
|
14
|
+
require 'models/keyboard'
|
15
|
+
require 'models/post'
|
16
|
+
require 'models/comment'
|
17
|
+
require 'models/minimalistic'
|
18
|
+
require 'models/warehouse_thing'
|
19
|
+
require 'models/parrot'
|
20
|
+
require 'rexml/document'
|
21
|
+
|
22
|
+
class Category < ActiveRecord::Base; end
|
23
|
+
class Categorization < ActiveRecord::Base; end
|
24
|
+
class Smarts < ActiveRecord::Base; end
|
25
|
+
class CreditCard < ActiveRecord::Base
|
26
|
+
class PinNumber < ActiveRecord::Base
|
27
|
+
class CvvCode < ActiveRecord::Base; end
|
28
|
+
class SubCvvCode < CvvCode; end
|
29
|
+
end
|
30
|
+
class SubPinNumber < PinNumber; end
|
31
|
+
class Brand < Category; end
|
32
|
+
end
|
33
|
+
class MasterCreditCard < ActiveRecord::Base; end
|
34
|
+
class Post < ActiveRecord::Base; end
|
35
|
+
class Computer < ActiveRecord::Base; end
|
36
|
+
class NonExistentTable < ActiveRecord::Base; end
|
37
|
+
class TestOracleDefault < ActiveRecord::Base; end
|
38
|
+
|
39
|
+
class LoosePerson < ActiveRecord::Base
|
40
|
+
self.table_name = 'people'
|
41
|
+
self.abstract_class = true
|
42
|
+
attr_protected :credit_rating, :administrator
|
43
|
+
end
|
44
|
+
|
45
|
+
class LooseDescendant < LoosePerson
|
46
|
+
attr_protected :phone_number
|
47
|
+
end
|
48
|
+
|
49
|
+
class LooseDescendantSecond< LoosePerson
|
50
|
+
attr_protected :phone_number
|
51
|
+
attr_protected :name
|
52
|
+
end
|
53
|
+
|
54
|
+
class TightPerson < ActiveRecord::Base
|
55
|
+
self.table_name = 'people'
|
56
|
+
attr_accessible :name, :address
|
57
|
+
end
|
58
|
+
|
59
|
+
class TightDescendant < TightPerson
|
60
|
+
attr_accessible :phone_number
|
61
|
+
end
|
62
|
+
|
63
|
+
class ReadonlyTitlePost < Post
|
64
|
+
attr_readonly :title
|
65
|
+
end
|
66
|
+
|
67
|
+
class Booleantest < ActiveRecord::Base; end
|
68
|
+
|
69
|
+
class Task < ActiveRecord::Base
|
70
|
+
attr_protected :starting
|
71
|
+
end
|
72
|
+
|
73
|
+
class TopicWithProtectedContentAndAccessibleAuthorName < ActiveRecord::Base
|
74
|
+
self.table_name = 'topics'
|
75
|
+
attr_accessible :author_name
|
76
|
+
attr_protected :content
|
77
|
+
end
|
78
|
+
|
79
|
+
class BasicsTest < ActiveRecord::TestCase
|
80
|
+
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, :warehouse_things, :authors, :categorizations, :categories, :posts
|
81
|
+
|
82
|
+
def test_table_exists
|
83
|
+
assert !NonExistentTable.table_exists?
|
84
|
+
assert Topic.table_exists?
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_set_attributes
|
88
|
+
topic = Topic.find(1)
|
89
|
+
topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
|
90
|
+
topic.save
|
91
|
+
assert_equal("Budget", topic.title)
|
92
|
+
assert_equal("Jason", topic.author_name)
|
93
|
+
assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_integers_as_nil
|
97
|
+
test = AutoId.create('value' => '')
|
98
|
+
assert_nil AutoId.find(test.id).value
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_set_attributes_with_block
|
102
|
+
topic = Topic.new do |t|
|
103
|
+
t.title = "Budget"
|
104
|
+
t.author_name = "Jason"
|
105
|
+
end
|
106
|
+
|
107
|
+
assert_equal("Budget", topic.title)
|
108
|
+
assert_equal("Jason", topic.author_name)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_respond_to?
|
112
|
+
topic = Topic.find(1)
|
113
|
+
assert topic.respond_to?("title")
|
114
|
+
assert topic.respond_to?("title?")
|
115
|
+
assert topic.respond_to?("title=")
|
116
|
+
assert topic.respond_to?(:title)
|
117
|
+
assert topic.respond_to?(:title?)
|
118
|
+
assert topic.respond_to?(:title=)
|
119
|
+
assert topic.respond_to?("author_name")
|
120
|
+
assert topic.respond_to?("attribute_names")
|
121
|
+
assert !topic.respond_to?("nothingness")
|
122
|
+
assert !topic.respond_to?(:nothingness)
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_array_content
|
126
|
+
topic = Topic.new
|
127
|
+
topic.content = %w( one two three )
|
128
|
+
topic.save
|
129
|
+
|
130
|
+
assert_equal(%w( one two three ), Topic.find(topic.id).content)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_read_attributes_before_type_cast
|
134
|
+
category = Category.new({:name=>"Test categoty", :type => nil})
|
135
|
+
category_attrs = {"name"=>"Test categoty", "type" => nil, "categorizations_count" => nil}
|
136
|
+
assert_equal category_attrs , category.attributes_before_type_cast
|
137
|
+
end
|
138
|
+
|
139
|
+
if current_adapter?(:MysqlAdapter)
|
140
|
+
def test_read_attributes_before_type_cast_on_boolean
|
141
|
+
bool = Booleantest.create({ "value" => false })
|
142
|
+
assert_equal "0", bool.reload.attributes_before_type_cast["value"]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_read_attributes_before_type_cast_on_datetime
|
147
|
+
developer = Developer.find(:first)
|
148
|
+
assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"]
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_hash_content
|
152
|
+
topic = Topic.new
|
153
|
+
topic.content = { "one" => 1, "two" => 2 }
|
154
|
+
topic.save
|
155
|
+
|
156
|
+
assert_equal 2, Topic.find(topic.id).content["two"]
|
157
|
+
|
158
|
+
topic.content_will_change!
|
159
|
+
topic.content["three"] = 3
|
160
|
+
topic.save
|
161
|
+
|
162
|
+
assert_equal 3, Topic.find(topic.id).content["three"]
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_update_array_content
|
166
|
+
topic = Topic.new
|
167
|
+
topic.content = %w( one two three )
|
168
|
+
|
169
|
+
topic.content.push "four"
|
170
|
+
assert_equal(%w( one two three four ), topic.content)
|
171
|
+
|
172
|
+
topic.save
|
173
|
+
|
174
|
+
topic = Topic.find(topic.id)
|
175
|
+
topic.content << "five"
|
176
|
+
assert_equal(%w( one two three four five ), topic.content)
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_case_sensitive_attributes_hash
|
180
|
+
# DB2 is not case-sensitive
|
181
|
+
return true if current_adapter?(:DB2Adapter, :IBM_DBAdapter)
|
182
|
+
|
183
|
+
assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_create
|
187
|
+
topic = Topic.new
|
188
|
+
topic.title = "New Topic"
|
189
|
+
topic.save
|
190
|
+
topic_reloaded = Topic.find(topic.id)
|
191
|
+
assert_equal("New Topic", topic_reloaded.title)
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_save!
|
195
|
+
topic = Topic.new(:title => "New Topic")
|
196
|
+
assert topic.save!
|
197
|
+
|
198
|
+
reply = Reply.new
|
199
|
+
assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_save_null_string_attributes
|
203
|
+
topic = Topic.find(1)
|
204
|
+
topic.attributes = { "title" => "null", "author_name" => "null" }
|
205
|
+
topic.save!
|
206
|
+
topic.reload
|
207
|
+
assert_equal("null", topic.title)
|
208
|
+
assert_equal("null", topic.author_name)
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_save_nil_string_attributes
|
212
|
+
topic = Topic.find(1)
|
213
|
+
topic.title = nil
|
214
|
+
topic.save!
|
215
|
+
topic.reload
|
216
|
+
assert_nil topic.title
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_save_for_record_with_only_primary_key
|
220
|
+
minimalistic = Minimalistic.new
|
221
|
+
assert_nothing_raised { minimalistic.save }
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_save_for_record_with_only_primary_key_that_is_provided
|
225
|
+
assert_nothing_raised { Minimalistic.create!(:id => 2) }
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_hashes_not_mangled
|
229
|
+
new_topic = { :title => "New Topic" }
|
230
|
+
new_topic_values = { :title => "AnotherTopic" }
|
231
|
+
|
232
|
+
topic = Topic.new(new_topic)
|
233
|
+
assert_equal new_topic[:title], topic.title
|
234
|
+
|
235
|
+
topic.attributes= new_topic_values
|
236
|
+
assert_equal new_topic_values[:title], topic.title
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_create_many
|
240
|
+
topics = Topic.create([ { "title" => "first" }, { "title" => "second" }])
|
241
|
+
assert_equal 2, topics.size
|
242
|
+
assert_equal "first", topics.first.title
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_create_columns_not_equal_attributes
|
246
|
+
topic = Topic.new
|
247
|
+
topic.title = 'Another New Topic'
|
248
|
+
topic.send :write_attribute, 'does_not_exist', 'test'
|
249
|
+
assert_nothing_raised { topic.save }
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_create_through_factory
|
253
|
+
topic = Topic.create("title" => "New Topic")
|
254
|
+
topicReloaded = Topic.find(topic.id)
|
255
|
+
assert_equal(topic, topicReloaded)
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_create_through_factory_with_block
|
259
|
+
topic = Topic.create("title" => "New Topic") do |t|
|
260
|
+
t.author_name = "David"
|
261
|
+
end
|
262
|
+
topicReloaded = Topic.find(topic.id)
|
263
|
+
assert_equal("New Topic", topic.title)
|
264
|
+
assert_equal("David", topic.author_name)
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_create_many_through_factory_with_block
|
268
|
+
topics = Topic.create([ { "title" => "first" }, { "title" => "second" }]) do |t|
|
269
|
+
t.author_name = "David"
|
270
|
+
end
|
271
|
+
assert_equal 2, topics.size
|
272
|
+
topic1, topic2 = Topic.find(topics[0].id), Topic.find(topics[1].id)
|
273
|
+
assert_equal "first", topic1.title
|
274
|
+
assert_equal "David", topic1.author_name
|
275
|
+
assert_equal "second", topic2.title
|
276
|
+
assert_equal "David", topic2.author_name
|
277
|
+
end
|
278
|
+
|
279
|
+
def test_update
|
280
|
+
topic = Topic.new
|
281
|
+
topic.title = "Another New Topic"
|
282
|
+
topic.written_on = "2003-12-12 23:23:00"
|
283
|
+
topic.save
|
284
|
+
topicReloaded = Topic.find(topic.id)
|
285
|
+
assert_equal("Another New Topic", topicReloaded.title)
|
286
|
+
|
287
|
+
topicReloaded.title = "Updated topic"
|
288
|
+
topicReloaded.save
|
289
|
+
|
290
|
+
topicReloadedAgain = Topic.find(topic.id)
|
291
|
+
|
292
|
+
assert_equal("Updated topic", topicReloadedAgain.title)
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_update_columns_not_equal_attributes
|
296
|
+
topic = Topic.new
|
297
|
+
topic.title = "Still another topic"
|
298
|
+
topic.save
|
299
|
+
|
300
|
+
topicReloaded = Topic.find(topic.id)
|
301
|
+
topicReloaded.title = "A New Topic"
|
302
|
+
topicReloaded.send :write_attribute, 'does_not_exist', 'test'
|
303
|
+
assert_nothing_raised { topicReloaded.save }
|
304
|
+
end
|
305
|
+
|
306
|
+
def test_update_for_record_with_only_primary_key
|
307
|
+
minimalistic = minimalistics(:first)
|
308
|
+
assert_nothing_raised { minimalistic.save }
|
309
|
+
end
|
310
|
+
|
311
|
+
def test_write_attribute
|
312
|
+
topic = Topic.new
|
313
|
+
topic.send(:write_attribute, :title, "Still another topic")
|
314
|
+
assert_equal "Still another topic", topic.title
|
315
|
+
|
316
|
+
topic.send(:write_attribute, "title", "Still another topic: part 2")
|
317
|
+
assert_equal "Still another topic: part 2", topic.title
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_read_attribute
|
321
|
+
topic = Topic.new
|
322
|
+
topic.title = "Don't change the topic"
|
323
|
+
assert_equal "Don't change the topic", topic.send(:read_attribute, "title")
|
324
|
+
assert_equal "Don't change the topic", topic["title"]
|
325
|
+
|
326
|
+
assert_equal "Don't change the topic", topic.send(:read_attribute, :title)
|
327
|
+
assert_equal "Don't change the topic", topic[:title]
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_read_attribute_when_false
|
331
|
+
topic = topics(:first)
|
332
|
+
topic.approved = false
|
333
|
+
assert !topic.approved?, "approved should be false"
|
334
|
+
topic.approved = "false"
|
335
|
+
assert !topic.approved?, "approved should be false"
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_read_attribute_when_true
|
339
|
+
topic = topics(:first)
|
340
|
+
topic.approved = true
|
341
|
+
assert topic.approved?, "approved should be true"
|
342
|
+
topic.approved = "true"
|
343
|
+
assert topic.approved?, "approved should be true"
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_read_write_boolean_attribute
|
347
|
+
topic = Topic.new
|
348
|
+
# puts ""
|
349
|
+
# puts "New Topic"
|
350
|
+
# puts topic.inspect
|
351
|
+
topic.approved = "false"
|
352
|
+
# puts "Expecting false"
|
353
|
+
# puts topic.inspect
|
354
|
+
assert !topic.approved?, "approved should be false"
|
355
|
+
topic.approved = "false"
|
356
|
+
# puts "Expecting false"
|
357
|
+
# puts topic.inspect
|
358
|
+
assert !topic.approved?, "approved should be false"
|
359
|
+
topic.approved = "true"
|
360
|
+
# puts "Expecting true"
|
361
|
+
# puts topic.inspect
|
362
|
+
assert topic.approved?, "approved should be true"
|
363
|
+
topic.approved = "true"
|
364
|
+
# puts "Expecting true"
|
365
|
+
# puts topic.inspect
|
366
|
+
assert topic.approved?, "approved should be true"
|
367
|
+
# puts ""
|
368
|
+
end
|
369
|
+
|
370
|
+
def test_query_attribute_string
|
371
|
+
[nil, "", " "].each do |value|
|
372
|
+
assert_equal false, Topic.new(:author_name => value).author_name?
|
373
|
+
end
|
374
|
+
|
375
|
+
assert_equal true, Topic.new(:author_name => "Name").author_name?
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_query_attribute_number
|
379
|
+
[nil, 0, "0"].each do |value|
|
380
|
+
assert_equal false, Developer.new(:salary => value).salary?
|
381
|
+
end
|
382
|
+
|
383
|
+
assert_equal true, Developer.new(:salary => 1).salary?
|
384
|
+
assert_equal true, Developer.new(:salary => "1").salary?
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_query_attribute_boolean
|
388
|
+
[nil, "", false, "false", "f", 0].each do |value|
|
389
|
+
assert_equal false, Topic.new(:approved => value).approved?
|
390
|
+
end
|
391
|
+
|
392
|
+
[true, "true", "1", 1].each do |value|
|
393
|
+
assert_equal true, Topic.new(:approved => value).approved?
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
def test_query_attribute_with_custom_fields
|
398
|
+
object = Company.find_by_sql(<<-SQL).first
|
399
|
+
SELECT c1.*, c2.ruby_type as string_value, c2.rating as int_value
|
400
|
+
FROM companies c1, companies c2
|
401
|
+
WHERE c1.firm_id = c2.id
|
402
|
+
AND c1.id = 2
|
403
|
+
SQL
|
404
|
+
|
405
|
+
assert_equal "Firm", object.string_value
|
406
|
+
assert object.string_value?
|
407
|
+
|
408
|
+
object.string_value = " "
|
409
|
+
assert !object.string_value?
|
410
|
+
|
411
|
+
assert_equal 1, object.int_value.to_i
|
412
|
+
assert object.int_value?
|
413
|
+
|
414
|
+
object.int_value = "0"
|
415
|
+
assert !object.int_value?
|
416
|
+
end
|
417
|
+
|
418
|
+
|
419
|
+
def test_reader_for_invalid_column_names
|
420
|
+
Topic.send(:define_read_method, "mumub-jumbo".to_sym, "mumub-jumbo", nil)
|
421
|
+
assert !Topic.generated_methods.include?("mumub-jumbo")
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_non_attribute_access_and_assignment
|
425
|
+
topic = Topic.new
|
426
|
+
assert !topic.respond_to?("mumbo")
|
427
|
+
assert_raise(NoMethodError) { topic.mumbo }
|
428
|
+
assert_raise(NoMethodError) { topic.mumbo = 5 }
|
429
|
+
end
|
430
|
+
|
431
|
+
def test_preserving_date_objects
|
432
|
+
if current_adapter?(:SybaseAdapter, :OracleAdapter)
|
433
|
+
# Sybase ctlib does not (yet?) support the date type; use datetime instead.
|
434
|
+
# Oracle treats all dates/times as Time.
|
435
|
+
assert_kind_of(
|
436
|
+
Time, Topic.find(1).last_read,
|
437
|
+
"The last_read attribute should be of the Time class"
|
438
|
+
)
|
439
|
+
else
|
440
|
+
assert_kind_of(
|
441
|
+
Date, Topic.find(1).last_read,
|
442
|
+
"The last_read attribute should be of the Date class"
|
443
|
+
)
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def test_preserving_time_objects
|
448
|
+
assert_kind_of(
|
449
|
+
Time, Topic.find(1).bonus_time,
|
450
|
+
"The bonus_time attribute should be of the Time class"
|
451
|
+
)
|
452
|
+
|
453
|
+
assert_kind_of(
|
454
|
+
Time, Topic.find(1).written_on,
|
455
|
+
"The written_on attribute should be of the Time class"
|
456
|
+
)
|
457
|
+
|
458
|
+
# For adapters which support microsecond resolution.
|
459
|
+
if current_adapter?(:PostgreSQLAdapter)
|
460
|
+
assert_equal 11, Topic.find(1).written_on.sec
|
461
|
+
assert_equal 223300, Topic.find(1).written_on.usec
|
462
|
+
assert_equal 9900, Topic.find(2).written_on.usec
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def test_custom_mutator
|
467
|
+
topic = Topic.find(1)
|
468
|
+
# This mutator is protected in the class definition
|
469
|
+
topic.send(:approved=, true)
|
470
|
+
assert topic.instance_variable_get("@custom_approved")
|
471
|
+
end
|
472
|
+
|
473
|
+
def test_delete
|
474
|
+
topic = Topic.find(1)
|
475
|
+
assert_equal topic, topic.delete, 'topic.delete did not return self'
|
476
|
+
assert topic.frozen?, 'topic not frozen after delete'
|
477
|
+
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
|
478
|
+
end
|
479
|
+
|
480
|
+
def test_delete_doesnt_run_callbacks
|
481
|
+
Topic.find(1).delete
|
482
|
+
assert_not_nil Topic.find(2)
|
483
|
+
end
|
484
|
+
|
485
|
+
def test_destroy
|
486
|
+
topic = Topic.find(1)
|
487
|
+
assert_equal topic, topic.destroy, 'topic.destroy did not return self'
|
488
|
+
assert topic.frozen?, 'topic not frozen after destroy'
|
489
|
+
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
|
490
|
+
end
|
491
|
+
|
492
|
+
def test_record_not_found_exception
|
493
|
+
assert_raise(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(99999) }
|
494
|
+
end
|
495
|
+
|
496
|
+
def test_initialize_with_attributes
|
497
|
+
topic = Topic.new({
|
498
|
+
"title" => "initialized from attributes", "written_on" => "2003-12-12 23:23"
|
499
|
+
})
|
500
|
+
|
501
|
+
assert_equal("initialized from attributes", topic.title)
|
502
|
+
end
|
503
|
+
|
504
|
+
def test_initialize_with_invalid_attribute
|
505
|
+
begin
|
506
|
+
topic = Topic.new({ "title" => "test",
|
507
|
+
"last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
|
508
|
+
rescue ActiveRecord::MultiparameterAssignmentErrors => ex
|
509
|
+
assert_equal(1, ex.errors.size)
|
510
|
+
assert_equal("last_read", ex.errors[0].attribute)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
def test_load
|
515
|
+
topics = Topic.find(:all, :order => 'id')
|
516
|
+
assert_equal(4, topics.size)
|
517
|
+
assert_equal(topics(:first).title, topics.first.title)
|
518
|
+
end
|
519
|
+
|
520
|
+
def test_load_with_condition
|
521
|
+
topics = Topic.find(:all, :conditions => "author_name = 'Mary'")
|
522
|
+
|
523
|
+
assert_equal(1, topics.size)
|
524
|
+
assert_equal(topics(:second).title, topics.first.title)
|
525
|
+
end
|
526
|
+
|
527
|
+
def test_table_name_guesses
|
528
|
+
classes = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]
|
529
|
+
|
530
|
+
assert_equal "topics", Topic.table_name
|
531
|
+
|
532
|
+
assert_equal "categories", Category.table_name
|
533
|
+
assert_equal "smarts", Smarts.table_name
|
534
|
+
assert_equal "credit_cards", CreditCard.table_name
|
535
|
+
assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
|
536
|
+
assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
|
537
|
+
assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
|
538
|
+
assert_equal "categories", CreditCard::Brand.table_name
|
539
|
+
assert_equal "master_credit_cards", MasterCreditCard.table_name
|
540
|
+
|
541
|
+
ActiveRecord::Base.pluralize_table_names = false
|
542
|
+
classes.each(&:reset_table_name)
|
543
|
+
|
544
|
+
assert_equal "category", Category.table_name
|
545
|
+
assert_equal "smarts", Smarts.table_name
|
546
|
+
assert_equal "credit_card", CreditCard.table_name
|
547
|
+
assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
|
548
|
+
assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
|
549
|
+
assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
|
550
|
+
assert_equal "category", CreditCard::Brand.table_name
|
551
|
+
assert_equal "master_credit_card", MasterCreditCard.table_name
|
552
|
+
|
553
|
+
ActiveRecord::Base.pluralize_table_names = true
|
554
|
+
classes.each(&:reset_table_name)
|
555
|
+
|
556
|
+
ActiveRecord::Base.table_name_prefix = "test_"
|
557
|
+
Category.reset_table_name
|
558
|
+
assert_equal "test_categories", Category.table_name
|
559
|
+
ActiveRecord::Base.table_name_suffix = "_test"
|
560
|
+
Category.reset_table_name
|
561
|
+
assert_equal "test_categories_test", Category.table_name
|
562
|
+
ActiveRecord::Base.table_name_prefix = ""
|
563
|
+
Category.reset_table_name
|
564
|
+
assert_equal "categories_test", Category.table_name
|
565
|
+
ActiveRecord::Base.table_name_suffix = ""
|
566
|
+
Category.reset_table_name
|
567
|
+
assert_equal "categories", Category.table_name
|
568
|
+
|
569
|
+
ActiveRecord::Base.pluralize_table_names = false
|
570
|
+
ActiveRecord::Base.table_name_prefix = "test_"
|
571
|
+
Category.reset_table_name
|
572
|
+
assert_equal "test_category", Category.table_name
|
573
|
+
ActiveRecord::Base.table_name_suffix = "_test"
|
574
|
+
Category.reset_table_name
|
575
|
+
assert_equal "test_category_test", Category.table_name
|
576
|
+
ActiveRecord::Base.table_name_prefix = ""
|
577
|
+
Category.reset_table_name
|
578
|
+
assert_equal "category_test", Category.table_name
|
579
|
+
ActiveRecord::Base.table_name_suffix = ""
|
580
|
+
Category.reset_table_name
|
581
|
+
assert_equal "category", Category.table_name
|
582
|
+
|
583
|
+
ActiveRecord::Base.pluralize_table_names = true
|
584
|
+
classes.each(&:reset_table_name)
|
585
|
+
end
|
586
|
+
|
587
|
+
def test_destroy_all
|
588
|
+
original_count = Topic.count
|
589
|
+
topics_by_mary = Topic.count(:conditions => mary = "author_name = 'Mary'")
|
590
|
+
|
591
|
+
Topic.destroy_all mary
|
592
|
+
assert_equal original_count - topics_by_mary, Topic.count
|
593
|
+
end
|
594
|
+
|
595
|
+
def test_destroy_many
|
596
|
+
assert_equal 3, Client.count
|
597
|
+
Client.destroy([2, 3])
|
598
|
+
assert_equal 1, Client.count
|
599
|
+
end
|
600
|
+
|
601
|
+
def test_delete_many
|
602
|
+
original_count = Topic.count
|
603
|
+
Topic.delete(deleting = [1, 2])
|
604
|
+
assert_equal original_count - deleting.size, Topic.count
|
605
|
+
end
|
606
|
+
|
607
|
+
def test_boolean_attributes
|
608
|
+
assert ! Topic.find(1).approved?
|
609
|
+
assert Topic.find(2).approved?
|
610
|
+
end
|
611
|
+
|
612
|
+
def test_increment_counter
|
613
|
+
Topic.increment_counter("replies_count", 1)
|
614
|
+
assert_equal 2, Topic.find(1).replies_count
|
615
|
+
|
616
|
+
Topic.increment_counter("replies_count", 1)
|
617
|
+
assert_equal 3, Topic.find(1).replies_count
|
618
|
+
end
|
619
|
+
|
620
|
+
def test_decrement_counter
|
621
|
+
Topic.decrement_counter("replies_count", 2)
|
622
|
+
assert_equal -1, Topic.find(2).replies_count
|
623
|
+
|
624
|
+
Topic.decrement_counter("replies_count", 2)
|
625
|
+
assert_equal -2, Topic.find(2).replies_count
|
626
|
+
end
|
627
|
+
|
628
|
+
def test_update_counter
|
629
|
+
category = categories(:general)
|
630
|
+
assert_nil category.categorizations_count
|
631
|
+
assert_equal 2, category.categorizations.count
|
632
|
+
|
633
|
+
Category.update_counters(category.id, "categorizations_count" => category.categorizations.count)
|
634
|
+
category.reload
|
635
|
+
assert_not_nil category.categorizations_count
|
636
|
+
assert_equal 2, category.categorizations_count
|
637
|
+
|
638
|
+
Category.update_counters(category.id, "categorizations_count" => category.categorizations.count)
|
639
|
+
category.reload
|
640
|
+
assert_not_nil category.categorizations_count
|
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
|
649
|
+
end
|
650
|
+
|
651
|
+
def test_update_all
|
652
|
+
assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
|
653
|
+
assert_equal "bulk updated!", Topic.find(1).content
|
654
|
+
assert_equal "bulk updated!", Topic.find(2).content
|
655
|
+
|
656
|
+
assert_equal Topic.count, Topic.update_all(['content = ?', 'bulk updated again!'])
|
657
|
+
assert_equal "bulk updated again!", Topic.find(1).content
|
658
|
+
assert_equal "bulk updated again!", Topic.find(2).content
|
659
|
+
|
660
|
+
assert_equal Topic.count, Topic.update_all(['content = ?', nil])
|
661
|
+
assert_nil Topic.find(1).content
|
662
|
+
end
|
663
|
+
|
664
|
+
def test_update_all_with_hash
|
665
|
+
assert_not_nil Topic.find(1).last_read
|
666
|
+
assert_equal Topic.count, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil)
|
667
|
+
assert_equal "bulk updated with hash!", Topic.find(1).content
|
668
|
+
assert_equal "bulk updated with hash!", Topic.find(2).content
|
669
|
+
assert_nil Topic.find(1).last_read
|
670
|
+
assert_nil Topic.find(2).last_read
|
671
|
+
end
|
672
|
+
|
673
|
+
def test_update_all_with_non_standard_table_name
|
674
|
+
assert_equal 1, WarehouseThing.update_all(['value = ?', 0], ['id = ?', 1])
|
675
|
+
assert_equal 0, WarehouseThing.find(1).value
|
676
|
+
end
|
677
|
+
|
678
|
+
if current_adapter?(:MysqlAdapter)
|
679
|
+
def test_update_all_with_order_and_limit
|
680
|
+
assert_equal 1, Topic.update_all("content = 'bulk updated!'", nil, :limit => 1, :order => 'id DESC')
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
def test_update_all_ignores_order_without_limit_from_association
|
685
|
+
author = authors(:david)
|
686
|
+
assert_nothing_raised do
|
687
|
+
assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all([ "body = ?", "bulk update!" ])
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
def test_update_all_with_order_and_limit_updates_subset_only
|
692
|
+
author = authors(:david)
|
693
|
+
assert_nothing_raised do
|
694
|
+
assert_equal 1, author.posts_sorted_by_id_limited.size
|
695
|
+
assert_equal 2, author.posts_sorted_by_id_limited.find(:all, :limit => 2).size
|
696
|
+
assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ])
|
697
|
+
assert_equal "bulk update!", posts(:welcome).body
|
698
|
+
assert_not_equal "bulk update!", posts(:thinking).body
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
def test_update_many
|
703
|
+
topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
|
704
|
+
updated = Topic.update(topic_data.keys, topic_data.values)
|
705
|
+
|
706
|
+
assert_equal 2, updated.size
|
707
|
+
assert_equal "1 updated", Topic.find(1).content
|
708
|
+
assert_equal "2 updated", Topic.find(2).content
|
709
|
+
end
|
710
|
+
|
711
|
+
def test_delete_all
|
712
|
+
assert Topic.count > 0
|
713
|
+
|
714
|
+
assert_equal Topic.count, Topic.delete_all
|
715
|
+
end
|
716
|
+
|
717
|
+
def test_update_by_condition
|
718
|
+
Topic.update_all "content = 'bulk updated!'", ["approved = ?", true]
|
719
|
+
assert_equal "Have a nice day", Topic.find(1).content
|
720
|
+
assert_equal "bulk updated!", Topic.find(2).content
|
721
|
+
end
|
722
|
+
|
723
|
+
def test_attribute_present
|
724
|
+
t = Topic.new
|
725
|
+
t.title = "hello there!"
|
726
|
+
t.written_on = Time.now
|
727
|
+
assert t.attribute_present?("title")
|
728
|
+
assert t.attribute_present?("written_on")
|
729
|
+
assert !t.attribute_present?("content")
|
730
|
+
end
|
731
|
+
|
732
|
+
def test_attribute_keys_on_new_instance
|
733
|
+
t = Topic.new
|
734
|
+
assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
|
735
|
+
assert_raise(NoMethodError) { t.title2 }
|
736
|
+
end
|
737
|
+
|
738
|
+
def test_class_name
|
739
|
+
assert_equal "Firm", ActiveRecord::Base.class_name("firms")
|
740
|
+
assert_equal "Category", ActiveRecord::Base.class_name("categories")
|
741
|
+
assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder")
|
742
|
+
|
743
|
+
ActiveRecord::Base.pluralize_table_names = false
|
744
|
+
assert_equal "Firms", ActiveRecord::Base.class_name( "firms" )
|
745
|
+
ActiveRecord::Base.pluralize_table_names = true
|
746
|
+
|
747
|
+
ActiveRecord::Base.table_name_prefix = "test_"
|
748
|
+
assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms" )
|
749
|
+
ActiveRecord::Base.table_name_suffix = "_tests"
|
750
|
+
assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms_tests" )
|
751
|
+
ActiveRecord::Base.table_name_prefix = ""
|
752
|
+
assert_equal "Firm", ActiveRecord::Base.class_name( "firms_tests" )
|
753
|
+
ActiveRecord::Base.table_name_suffix = ""
|
754
|
+
assert_equal "Firm", ActiveRecord::Base.class_name( "firms" )
|
755
|
+
end
|
756
|
+
|
757
|
+
def test_null_fields
|
758
|
+
assert_nil Topic.find(1).parent_id
|
759
|
+
assert_nil Topic.create("title" => "Hey you").parent_id
|
760
|
+
end
|
761
|
+
|
762
|
+
def test_default_values
|
763
|
+
topic = Topic.new
|
764
|
+
assert topic.approved?
|
765
|
+
assert_nil topic.written_on
|
766
|
+
assert_nil topic.bonus_time
|
767
|
+
assert_nil topic.last_read
|
768
|
+
|
769
|
+
topic.save
|
770
|
+
|
771
|
+
topic = Topic.find(topic.id)
|
772
|
+
assert topic.approved?
|
773
|
+
assert_nil topic.last_read
|
774
|
+
|
775
|
+
# Oracle has some funky default handling, so it requires a bit of
|
776
|
+
# extra testing. See ticket #2788.
|
777
|
+
if current_adapter?(:OracleAdapter)
|
778
|
+
test = TestOracleDefault.new
|
779
|
+
assert_equal "X", test.test_char
|
780
|
+
assert_equal "hello", test.test_string
|
781
|
+
assert_equal 3, test.test_int
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
# Oracle, and Sybase do not have a TIME datatype.
|
786
|
+
unless current_adapter?(:OracleAdapter, :SybaseAdapter)
|
787
|
+
def test_utc_as_time_zone
|
788
|
+
Topic.default_timezone = :utc
|
789
|
+
attributes = { "bonus_time" => "5:42:00AM" }
|
790
|
+
topic = Topic.find(1)
|
791
|
+
topic.attributes = attributes
|
792
|
+
assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
|
793
|
+
Topic.default_timezone = :local
|
794
|
+
end
|
795
|
+
|
796
|
+
def test_utc_as_time_zone_and_new
|
797
|
+
Topic.default_timezone = :utc
|
798
|
+
attributes = { "bonus_time(1i)"=>"2000",
|
799
|
+
"bonus_time(2i)"=>"1",
|
800
|
+
"bonus_time(3i)"=>"1",
|
801
|
+
"bonus_time(4i)"=>"10",
|
802
|
+
"bonus_time(5i)"=>"35",
|
803
|
+
"bonus_time(6i)"=>"50" }
|
804
|
+
topic = Topic.new(attributes)
|
805
|
+
assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
|
806
|
+
Topic.default_timezone = :local
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
def test_default_values_on_empty_strings
|
811
|
+
topic = Topic.new
|
812
|
+
topic.approved = nil
|
813
|
+
topic.last_read = nil
|
814
|
+
|
815
|
+
topic.save
|
816
|
+
|
817
|
+
topic = Topic.find(topic.id)
|
818
|
+
assert_nil topic.last_read
|
819
|
+
|
820
|
+
# Sybase adapter does not allow nulls in boolean columns
|
821
|
+
if current_adapter?(:SybaseAdapter)
|
822
|
+
assert topic.approved == false
|
823
|
+
else
|
824
|
+
assert_nil topic.approved
|
825
|
+
end
|
826
|
+
end
|
827
|
+
|
828
|
+
def test_equality
|
829
|
+
assert_equal Topic.find(1), Topic.find(2).topic
|
830
|
+
end
|
831
|
+
|
832
|
+
def test_equality_of_new_records
|
833
|
+
assert_not_equal Topic.new, Topic.new
|
834
|
+
end
|
835
|
+
|
836
|
+
def test_hashing
|
837
|
+
assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
|
838
|
+
end
|
839
|
+
|
840
|
+
def test_delete_new_record
|
841
|
+
client = Client.new
|
842
|
+
client.delete
|
843
|
+
assert client.frozen?
|
844
|
+
end
|
845
|
+
|
846
|
+
def test_delete_record_with_associations
|
847
|
+
client = Client.find(3)
|
848
|
+
client.delete
|
849
|
+
assert client.frozen?
|
850
|
+
assert_kind_of Firm, client.firm
|
851
|
+
assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
|
852
|
+
end
|
853
|
+
|
854
|
+
def test_destroy_new_record
|
855
|
+
client = Client.new
|
856
|
+
client.destroy
|
857
|
+
assert client.frozen?
|
858
|
+
end
|
859
|
+
|
860
|
+
def test_destroy_record_with_associations
|
861
|
+
client = Client.find(3)
|
862
|
+
client.destroy
|
863
|
+
assert client.frozen?
|
864
|
+
assert_kind_of Firm, client.firm
|
865
|
+
assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
|
866
|
+
end
|
867
|
+
|
868
|
+
def test_update_attribute
|
869
|
+
assert !Topic.find(1).approved?
|
870
|
+
Topic.find(1).update_attribute("approved", true)
|
871
|
+
assert Topic.find(1).approved?
|
872
|
+
|
873
|
+
Topic.find(1).update_attribute(:approved, false)
|
874
|
+
assert !Topic.find(1).approved?
|
875
|
+
end
|
876
|
+
|
877
|
+
def test_update_attributes
|
878
|
+
topic = Topic.find(1)
|
879
|
+
assert !topic.approved?
|
880
|
+
assert_equal "The First Topic", topic.title
|
881
|
+
|
882
|
+
topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
|
883
|
+
topic.reload
|
884
|
+
assert topic.approved?
|
885
|
+
assert_equal "The First Topic Updated", topic.title
|
886
|
+
|
887
|
+
topic.update_attributes(:approved => false, :title => "The First Topic")
|
888
|
+
topic.reload
|
889
|
+
assert !topic.approved?
|
890
|
+
assert_equal "The First Topic", topic.title
|
891
|
+
end
|
892
|
+
|
893
|
+
def test_update_attributes!
|
894
|
+
reply = Reply.find(2)
|
895
|
+
assert_equal "The Second Topic of the day", reply.title
|
896
|
+
assert_equal "Have a nice day", reply.content
|
897
|
+
|
898
|
+
reply.update_attributes!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
|
899
|
+
reply.reload
|
900
|
+
assert_equal "The Second Topic of the day updated", reply.title
|
901
|
+
assert_equal "Have a nice evening", reply.content
|
902
|
+
|
903
|
+
reply.update_attributes!(:title => "The Second Topic of the day", :content => "Have a nice day")
|
904
|
+
reply.reload
|
905
|
+
assert_equal "The Second Topic of the day", reply.title
|
906
|
+
assert_equal "Have a nice day", reply.content
|
907
|
+
|
908
|
+
assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(:title => nil, :content => "Have a nice evening") }
|
909
|
+
end
|
910
|
+
|
911
|
+
def test_mass_assignment_should_raise_exception_if_accessible_and_protected_attribute_writers_are_both_used
|
912
|
+
topic = TopicWithProtectedContentAndAccessibleAuthorName.new
|
913
|
+
assert_raise(RuntimeError) { topic.attributes = { "author_name" => "me" } }
|
914
|
+
assert_raise(RuntimeError) { topic.attributes = { "content" => "stuff" } }
|
915
|
+
end
|
916
|
+
|
917
|
+
def test_mass_assignment_protection
|
918
|
+
firm = Firm.new
|
919
|
+
firm.attributes = { "name" => "Next Angle", "rating" => 5 }
|
920
|
+
assert_equal 1, firm.rating
|
921
|
+
end
|
922
|
+
|
923
|
+
def test_mass_assignment_protection_against_class_attribute_writers
|
924
|
+
[:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names, :colorize_logging,
|
925
|
+
:default_timezone, :schema_format, :lock_optimistically, :record_timestamps].each do |method|
|
926
|
+
assert Task.respond_to?(method)
|
927
|
+
assert Task.respond_to?("#{method}=")
|
928
|
+
assert Task.new.respond_to?(method)
|
929
|
+
assert !Task.new.respond_to?("#{method}=")
|
930
|
+
end
|
931
|
+
end
|
932
|
+
|
933
|
+
def test_customized_primary_key_remains_protected
|
934
|
+
subscriber = Subscriber.new(:nick => 'webster123', :name => 'nice try')
|
935
|
+
assert_nil subscriber.id
|
936
|
+
|
937
|
+
keyboard = Keyboard.new(:key_number => 9, :name => 'nice try')
|
938
|
+
assert_nil keyboard.id
|
939
|
+
end
|
940
|
+
|
941
|
+
def test_customized_primary_key_remains_protected_when_referred_to_as_id
|
942
|
+
subscriber = Subscriber.new(:id => 'webster123', :name => 'nice try')
|
943
|
+
assert_nil subscriber.id
|
944
|
+
|
945
|
+
keyboard = Keyboard.new(:id => 9, :name => 'nice try')
|
946
|
+
assert_nil keyboard.id
|
947
|
+
end
|
948
|
+
|
949
|
+
def test_mass_assigning_invalid_attribute
|
950
|
+
firm = Firm.new
|
951
|
+
|
952
|
+
assert_raise(ActiveRecord::UnknownAttributeError) do
|
953
|
+
firm.attributes = { "id" => 5, "type" => "Client", "i_dont_even_exist" => 20 }
|
954
|
+
end
|
955
|
+
end
|
956
|
+
|
957
|
+
def test_mass_assignment_protection_on_defaults
|
958
|
+
firm = Firm.new
|
959
|
+
firm.attributes = { "id" => 5, "type" => "Client" }
|
960
|
+
assert_nil firm.id
|
961
|
+
assert_equal "Firm", firm[:type]
|
962
|
+
end
|
963
|
+
|
964
|
+
def test_mass_assignment_accessible
|
965
|
+
reply = Reply.new("title" => "hello", "content" => "world", "approved" => true)
|
966
|
+
reply.save
|
967
|
+
|
968
|
+
assert reply.approved?
|
969
|
+
|
970
|
+
reply.approved = false
|
971
|
+
reply.save
|
972
|
+
|
973
|
+
assert !reply.approved?
|
974
|
+
end
|
975
|
+
|
976
|
+
def test_mass_assignment_protection_inheritance
|
977
|
+
assert_nil LoosePerson.accessible_attributes
|
978
|
+
assert_equal Set.new([ 'credit_rating', 'administrator' ]), LoosePerson.protected_attributes
|
979
|
+
|
980
|
+
assert_nil LooseDescendant.accessible_attributes
|
981
|
+
assert_equal Set.new([ 'credit_rating', 'administrator', 'phone_number' ]), LooseDescendant.protected_attributes
|
982
|
+
|
983
|
+
assert_nil LooseDescendantSecond.accessible_attributes
|
984
|
+
assert_equal Set.new([ 'credit_rating', 'administrator', 'phone_number', 'name' ]), LooseDescendantSecond.protected_attributes, 'Running attr_protected twice in one class should merge the protections'
|
985
|
+
|
986
|
+
assert_nil TightPerson.protected_attributes
|
987
|
+
assert_equal Set.new([ 'name', 'address' ]), TightPerson.accessible_attributes
|
988
|
+
|
989
|
+
assert_nil TightDescendant.protected_attributes
|
990
|
+
assert_equal Set.new([ 'name', 'address', 'phone_number' ]), TightDescendant.accessible_attributes
|
991
|
+
end
|
992
|
+
|
993
|
+
def test_readonly_attributes
|
994
|
+
assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes
|
995
|
+
|
996
|
+
post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable")
|
997
|
+
post.reload
|
998
|
+
assert_equal "cannot change this", post.title
|
999
|
+
|
1000
|
+
post.update_attributes(:title => "try to change", :body => "changed")
|
1001
|
+
post.reload
|
1002
|
+
assert_equal "cannot change this", post.title
|
1003
|
+
assert_equal "changed", post.body
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
def test_multiparameter_attributes_on_date
|
1007
|
+
attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" }
|
1008
|
+
topic = Topic.find(1)
|
1009
|
+
topic.attributes = attributes
|
1010
|
+
# note that extra #to_date call allows test to pass for Oracle, which
|
1011
|
+
# treats dates/times the same
|
1012
|
+
assert_date_from_db Date.new(2004, 6, 24), topic.last_read.to_date
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
def test_multiparameter_attributes_on_date_with_empty_date
|
1016
|
+
attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "" }
|
1017
|
+
topic = Topic.find(1)
|
1018
|
+
topic.attributes = attributes
|
1019
|
+
# note that extra #to_date call allows test to pass for Oracle, which
|
1020
|
+
# treats dates/times the same
|
1021
|
+
assert_date_from_db Date.new(2004, 6, 1), topic.last_read.to_date
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
def test_multiparameter_attributes_on_date_with_all_empty
|
1025
|
+
attributes = { "last_read(1i)" => "", "last_read(2i)" => "", "last_read(3i)" => "" }
|
1026
|
+
topic = Topic.find(1)
|
1027
|
+
topic.attributes = attributes
|
1028
|
+
assert_nil topic.last_read
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
def test_multiparameter_attributes_on_time
|
1032
|
+
attributes = {
|
1033
|
+
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
1034
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
|
1035
|
+
}
|
1036
|
+
topic = Topic.find(1)
|
1037
|
+
topic.attributes = attributes
|
1038
|
+
assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def test_multiparameter_attributes_on_time_with_old_date
|
1042
|
+
attributes = {
|
1043
|
+
"written_on(1i)" => "1850", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
1044
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
|
1045
|
+
}
|
1046
|
+
topic = Topic.find(1)
|
1047
|
+
topic.attributes = attributes
|
1048
|
+
# testing against to_s(:db) representation because either a Time or a DateTime might be returned, depending on platform
|
1049
|
+
assert_equal "1850-06-24 16:24:00", topic.written_on.to_s(:db)
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
def test_multiparameter_attributes_on_time_with_utc
|
1053
|
+
ActiveRecord::Base.default_timezone = :utc
|
1054
|
+
attributes = {
|
1055
|
+
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
1056
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
|
1057
|
+
}
|
1058
|
+
topic = Topic.find(1)
|
1059
|
+
topic.attributes = attributes
|
1060
|
+
assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
|
1061
|
+
ensure
|
1062
|
+
ActiveRecord::Base.default_timezone = :local
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes
|
1066
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
1067
|
+
ActiveRecord::Base.default_timezone = :utc
|
1068
|
+
Time.zone = ActiveSupport::TimeZone[-28800]
|
1069
|
+
attributes = {
|
1070
|
+
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
1071
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
|
1072
|
+
}
|
1073
|
+
topic = Topic.find(1)
|
1074
|
+
topic.attributes = attributes
|
1075
|
+
assert_equal Time.utc(2004, 6, 24, 23, 24, 0), topic.written_on
|
1076
|
+
assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on.time
|
1077
|
+
assert_equal Time.zone, topic.written_on.time_zone
|
1078
|
+
ensure
|
1079
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
1080
|
+
ActiveRecord::Base.default_timezone = :local
|
1081
|
+
Time.zone = nil
|
1082
|
+
end
|
1083
|
+
|
1084
|
+
def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes_false
|
1085
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
1086
|
+
Time.zone = ActiveSupport::TimeZone[-28800]
|
1087
|
+
attributes = {
|
1088
|
+
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
1089
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
|
1090
|
+
}
|
1091
|
+
topic = Topic.find(1)
|
1092
|
+
topic.attributes = attributes
|
1093
|
+
assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
|
1094
|
+
assert_equal false, topic.written_on.respond_to?(:time_zone)
|
1095
|
+
ensure
|
1096
|
+
Time.zone = nil
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
def test_multiparameter_attributes_on_time_with_skip_time_zone_conversion_for_attributes
|
1100
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
1101
|
+
ActiveRecord::Base.default_timezone = :utc
|
1102
|
+
Time.zone = ActiveSupport::TimeZone[-28800]
|
1103
|
+
Topic.skip_time_zone_conversion_for_attributes = [:written_on]
|
1104
|
+
attributes = {
|
1105
|
+
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
1106
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
|
1107
|
+
}
|
1108
|
+
topic = Topic.find(1)
|
1109
|
+
topic.attributes = attributes
|
1110
|
+
assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
|
1111
|
+
assert_equal false, topic.written_on.respond_to?(:time_zone)
|
1112
|
+
ensure
|
1113
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
1114
|
+
ActiveRecord::Base.default_timezone = :local
|
1115
|
+
Time.zone = nil
|
1116
|
+
Topic.skip_time_zone_conversion_for_attributes = []
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion
|
1120
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
1121
|
+
ActiveRecord::Base.default_timezone = :utc
|
1122
|
+
Time.zone = ActiveSupport::TimeZone[-28800]
|
1123
|
+
attributes = {
|
1124
|
+
"bonus_time(1i)" => "2000", "bonus_time(2i)" => "1", "bonus_time(3i)" => "1",
|
1125
|
+
"bonus_time(4i)" => "16", "bonus_time(5i)" => "24"
|
1126
|
+
}
|
1127
|
+
topic = Topic.find(1)
|
1128
|
+
topic.attributes = attributes
|
1129
|
+
assert_equal Time.utc(2000, 1, 1, 16, 24, 0), topic.bonus_time
|
1130
|
+
assert topic.bonus_time.utc?
|
1131
|
+
ensure
|
1132
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
1133
|
+
ActiveRecord::Base.default_timezone = :local
|
1134
|
+
Time.zone = nil
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
def test_multiparameter_attributes_on_time_with_empty_seconds
|
1138
|
+
attributes = {
|
1139
|
+
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
|
1140
|
+
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => ""
|
1141
|
+
}
|
1142
|
+
topic = Topic.find(1)
|
1143
|
+
topic.attributes = attributes
|
1144
|
+
assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def test_multiparameter_mass_assignment_protector
|
1148
|
+
task = Task.new
|
1149
|
+
time = Time.mktime(2000, 1, 1, 1)
|
1150
|
+
task.starting = time
|
1151
|
+
attributes = { "starting(1i)" => "2004", "starting(2i)" => "6", "starting(3i)" => "24" }
|
1152
|
+
task.attributes = attributes
|
1153
|
+
assert_equal time, task.starting
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
def test_multiparameter_assignment_of_aggregation
|
1157
|
+
customer = Customer.new
|
1158
|
+
address = Address.new("The Street", "The City", "The Country")
|
1159
|
+
attributes = { "address(1)" => address.street, "address(2)" => address.city, "address(3)" => address.country }
|
1160
|
+
customer.attributes = attributes
|
1161
|
+
assert_equal address, customer.address
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
def test_attributes_on_dummy_time
|
1165
|
+
# Oracle, and Sybase do not have a TIME datatype.
|
1166
|
+
return true if current_adapter?(:OracleAdapter, :SybaseAdapter)
|
1167
|
+
|
1168
|
+
attributes = {
|
1169
|
+
"bonus_time" => "5:42:00AM"
|
1170
|
+
}
|
1171
|
+
topic = Topic.find(1)
|
1172
|
+
topic.attributes = attributes
|
1173
|
+
assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
def test_boolean
|
1177
|
+
b_nil = Booleantest.create({ "value" => nil })
|
1178
|
+
nil_id = b_nil.id
|
1179
|
+
b_false = Booleantest.create({ "value" => false })
|
1180
|
+
false_id = b_false.id
|
1181
|
+
b_true = Booleantest.create({ "value" => true })
|
1182
|
+
true_id = b_true.id
|
1183
|
+
|
1184
|
+
b_nil = Booleantest.find(nil_id)
|
1185
|
+
assert_nil b_nil.value
|
1186
|
+
b_false = Booleantest.find(false_id)
|
1187
|
+
assert !b_false.value?
|
1188
|
+
b_true = Booleantest.find(true_id)
|
1189
|
+
assert b_true.value?
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
def test_boolean_cast_from_string
|
1193
|
+
b_blank = Booleantest.create({ "value" => "" })
|
1194
|
+
blank_id = b_blank.id
|
1195
|
+
b_false = Booleantest.create({ "value" => "0" })
|
1196
|
+
false_id = b_false.id
|
1197
|
+
b_true = Booleantest.create({ "value" => "1" })
|
1198
|
+
true_id = b_true.id
|
1199
|
+
|
1200
|
+
b_blank = Booleantest.find(blank_id)
|
1201
|
+
assert_nil b_blank.value
|
1202
|
+
b_false = Booleantest.find(false_id)
|
1203
|
+
assert !b_false.value?
|
1204
|
+
b_true = Booleantest.find(true_id)
|
1205
|
+
assert b_true.value?
|
1206
|
+
end
|
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
|
+
|
1213
|
+
def test_clone
|
1214
|
+
topic = Topic.find(1)
|
1215
|
+
cloned_topic = nil
|
1216
|
+
assert_nothing_raised { cloned_topic = topic.clone }
|
1217
|
+
assert_equal topic.title, cloned_topic.title
|
1218
|
+
assert cloned_topic.new_record?
|
1219
|
+
|
1220
|
+
# test if the attributes have been cloned
|
1221
|
+
topic.title = "a"
|
1222
|
+
cloned_topic.title = "b"
|
1223
|
+
assert_equal "a", topic.title
|
1224
|
+
assert_equal "b", cloned_topic.title
|
1225
|
+
|
1226
|
+
# test if the attribute values have been cloned
|
1227
|
+
topic.title = {"a" => "b"}
|
1228
|
+
cloned_topic = topic.clone
|
1229
|
+
cloned_topic.title["a"] = "c"
|
1230
|
+
assert_equal "b", topic.title["a"]
|
1231
|
+
|
1232
|
+
#test if attributes set as part of after_initialize are cloned correctly
|
1233
|
+
assert_equal topic.author_email_address, cloned_topic.author_email_address
|
1234
|
+
|
1235
|
+
# test if saved clone object differs from original
|
1236
|
+
cloned_topic.save
|
1237
|
+
assert !cloned_topic.new_record?
|
1238
|
+
assert cloned_topic.id != topic.id
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
def test_clone_with_aggregate_of_same_name_as_attribute
|
1242
|
+
dev = DeveloperWithAggregate.find(1)
|
1243
|
+
assert_kind_of DeveloperSalary, dev.salary
|
1244
|
+
|
1245
|
+
clone = nil
|
1246
|
+
assert_nothing_raised { clone = dev.clone }
|
1247
|
+
assert_kind_of DeveloperSalary, clone.salary
|
1248
|
+
assert_equal dev.salary.amount, clone.salary.amount
|
1249
|
+
assert clone.new_record?
|
1250
|
+
|
1251
|
+
# test if the attributes have been cloned
|
1252
|
+
original_amount = clone.salary.amount
|
1253
|
+
dev.salary.amount = 1
|
1254
|
+
assert_equal original_amount, clone.salary.amount
|
1255
|
+
|
1256
|
+
assert clone.save
|
1257
|
+
assert !clone.new_record?
|
1258
|
+
assert clone.id != dev.id
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
def test_clone_preserves_subtype
|
1262
|
+
clone = nil
|
1263
|
+
assert_nothing_raised { clone = Company.find(3).clone }
|
1264
|
+
assert_kind_of Client, clone
|
1265
|
+
end
|
1266
|
+
|
1267
|
+
def test_bignum
|
1268
|
+
company = Company.find(1)
|
1269
|
+
company.rating = 2147483647
|
1270
|
+
company.save
|
1271
|
+
company = Company.find(1)
|
1272
|
+
assert_equal 2147483647, company.rating
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
# TODO: extend defaults tests to other databases!
|
1276
|
+
if current_adapter?(:PostgreSQLAdapter)
|
1277
|
+
def test_default
|
1278
|
+
default = Default.new
|
1279
|
+
|
1280
|
+
# fixed dates / times
|
1281
|
+
assert_equal Date.new(2004, 1, 1), default.fixed_date
|
1282
|
+
assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
|
1283
|
+
|
1284
|
+
# char types
|
1285
|
+
assert_equal 'Y', default.char1
|
1286
|
+
assert_equal 'a varchar field', default.char2
|
1287
|
+
assert_equal 'a text field', default.char3
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
class Geometric < ActiveRecord::Base; end
|
1291
|
+
def test_geometric_content
|
1292
|
+
|
1293
|
+
# accepted format notes:
|
1294
|
+
# ()'s aren't required
|
1295
|
+
# values can be a mix of float or integer
|
1296
|
+
|
1297
|
+
g = Geometric.new(
|
1298
|
+
:a_point => '(5.0, 6.1)',
|
1299
|
+
#:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
|
1300
|
+
:a_line_segment => '(2.0, 3), (5.5, 7.0)',
|
1301
|
+
:a_box => '2.0, 3, 5.5, 7.0',
|
1302
|
+
:a_path => '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]', # [ ] is an open path
|
1303
|
+
:a_polygon => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))',
|
1304
|
+
:a_circle => '<(5.3, 10.4), 2>'
|
1305
|
+
)
|
1306
|
+
|
1307
|
+
assert g.save
|
1308
|
+
|
1309
|
+
# Reload and check that we have all the geometric attributes.
|
1310
|
+
h = Geometric.find(g.id)
|
1311
|
+
|
1312
|
+
assert_equal '(5,6.1)', h.a_point
|
1313
|
+
assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
|
1314
|
+
assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
|
1315
|
+
assert_equal '[(2,3),(5.5,7),(8.5,11)]', h.a_path
|
1316
|
+
assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
|
1317
|
+
assert_equal '<(5.3,10.4),2>', h.a_circle
|
1318
|
+
|
1319
|
+
# use a geometric function to test for an open path
|
1320
|
+
objs = Geometric.find_by_sql ["select isopen(a_path) from geometrics where id = ?", g.id]
|
1321
|
+
assert_equal objs[0].isopen, 't'
|
1322
|
+
|
1323
|
+
# test alternate formats when defining the geometric types
|
1324
|
+
|
1325
|
+
g = Geometric.new(
|
1326
|
+
:a_point => '5.0, 6.1',
|
1327
|
+
#:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
|
1328
|
+
:a_line_segment => '((2.0, 3), (5.5, 7.0))',
|
1329
|
+
:a_box => '(2.0, 3), (5.5, 7.0)',
|
1330
|
+
:a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', # ( ) is a closed path
|
1331
|
+
:a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
|
1332
|
+
:a_circle => '((5.3, 10.4), 2)'
|
1333
|
+
)
|
1334
|
+
|
1335
|
+
assert g.save
|
1336
|
+
|
1337
|
+
# Reload and check that we have all the geometric attributes.
|
1338
|
+
h = Geometric.find(g.id)
|
1339
|
+
|
1340
|
+
assert_equal '(5,6.1)', h.a_point
|
1341
|
+
assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
|
1342
|
+
assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
|
1343
|
+
assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
|
1344
|
+
assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
|
1345
|
+
assert_equal '<(5.3,10.4),2>', h.a_circle
|
1346
|
+
|
1347
|
+
# use a geometric function to test for an closed path
|
1348
|
+
objs = Geometric.find_by_sql ["select isclosed(a_path) from geometrics where id = ?", g.id]
|
1349
|
+
assert_equal objs[0].isclosed, 't'
|
1350
|
+
end
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
class NumericData < ActiveRecord::Base
|
1354
|
+
self.table_name = 'numeric_data'
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
def test_numeric_fields
|
1358
|
+
m = NumericData.new(
|
1359
|
+
:bank_balance => 1586.43,
|
1360
|
+
:big_bank_balance => BigDecimal("1000234000567.95"),
|
1361
|
+
:world_population => 6000000000,
|
1362
|
+
:my_house_population => 3
|
1363
|
+
)
|
1364
|
+
assert m.save
|
1365
|
+
|
1366
|
+
m1 = NumericData.find(m.id)
|
1367
|
+
assert_not_nil m1
|
1368
|
+
|
1369
|
+
# As with migration_test.rb, we should make world_population >= 2**62
|
1370
|
+
# to cover 64-bit platforms and test it is a Bignum, but the main thing
|
1371
|
+
# is that it's an Integer.
|
1372
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1373
|
+
assert_kind_of Integer, m1.world_population
|
1374
|
+
else
|
1375
|
+
assert_kind_of BigDecimal, m1.world_population
|
1376
|
+
end
|
1377
|
+
assert_equal 6000000000, m1.world_population
|
1378
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1379
|
+
assert_kind_of Fixnum, m1.my_house_population
|
1380
|
+
else
|
1381
|
+
assert_kind_of BigDecimal, m1.my_house_population
|
1382
|
+
end
|
1383
|
+
assert_equal 3, m1.my_house_population
|
1384
|
+
|
1385
|
+
assert_kind_of BigDecimal, m1.bank_balance
|
1386
|
+
assert_equal BigDecimal("1586.43"), m1.bank_balance
|
1387
|
+
|
1388
|
+
assert_kind_of BigDecimal, m1.big_bank_balance
|
1389
|
+
assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
|
1390
|
+
end
|
1391
|
+
|
1392
|
+
def test_auto_id
|
1393
|
+
auto = AutoId.new
|
1394
|
+
auto.save
|
1395
|
+
assert (auto.id > 0)
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
def quote_column_name(name)
|
1399
|
+
"<#{name}>"
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
def test_quote_keys
|
1403
|
+
ar = AutoId.new
|
1404
|
+
source = {"foo" => "bar", "baz" => "quux"}
|
1405
|
+
actual = ar.send(:quote_columns, self, source)
|
1406
|
+
inverted = actual.invert
|
1407
|
+
assert_equal("<foo>", inverted["bar"])
|
1408
|
+
assert_equal("<baz>", inverted["quux"])
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
def test_sql_injection_via_find
|
1412
|
+
assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
|
1413
|
+
Topic.find("123456 OR id > 0")
|
1414
|
+
end
|
1415
|
+
end
|
1416
|
+
|
1417
|
+
def test_column_name_properly_quoted
|
1418
|
+
col_record = ColumnName.new
|
1419
|
+
col_record.references = 40
|
1420
|
+
assert col_record.save
|
1421
|
+
col_record.references = 41
|
1422
|
+
assert col_record.save
|
1423
|
+
assert_not_nil c2 = ColumnName.find(col_record.id)
|
1424
|
+
assert_equal(41, c2.references)
|
1425
|
+
end
|
1426
|
+
|
1427
|
+
def test_quoting_arrays
|
1428
|
+
replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
|
1429
|
+
assert_equal topics(:first).replies.size, replies.size
|
1430
|
+
|
1431
|
+
replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
|
1432
|
+
assert_equal 0, replies.size
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
MyObject = Struct.new :attribute1, :attribute2
|
1436
|
+
|
1437
|
+
def test_serialized_attribute
|
1438
|
+
myobj = MyObject.new('value1', 'value2')
|
1439
|
+
topic = Topic.create("content" => myobj)
|
1440
|
+
Topic.serialize("content", MyObject)
|
1441
|
+
assert_equal(myobj, topic.content)
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
def test_serialized_time_attribute
|
1445
|
+
myobj = Time.local(2008,1,1,1,0)
|
1446
|
+
topic = Topic.create("content" => myobj).reload
|
1447
|
+
assert_equal(myobj, topic.content)
|
1448
|
+
end
|
1449
|
+
|
1450
|
+
def test_serialized_string_attribute
|
1451
|
+
myobj = "Yes"
|
1452
|
+
topic = Topic.create("content" => myobj).reload
|
1453
|
+
assert_equal(myobj, topic.content)
|
1454
|
+
end
|
1455
|
+
|
1456
|
+
def test_nil_serialized_attribute_with_class_constraint
|
1457
|
+
myobj = MyObject.new('value1', 'value2')
|
1458
|
+
topic = Topic.new
|
1459
|
+
assert_nil topic.content
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
|
1463
|
+
myobj = MyObject.new('value1', 'value2')
|
1464
|
+
topic = Topic.new(:content => myobj)
|
1465
|
+
assert topic.save
|
1466
|
+
Topic.serialize(:content, Hash)
|
1467
|
+
assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content }
|
1468
|
+
ensure
|
1469
|
+
Topic.serialize(:content)
|
1470
|
+
end
|
1471
|
+
|
1472
|
+
def test_serialized_attribute_with_class_constraint
|
1473
|
+
settings = { "color" => "blue" }
|
1474
|
+
Topic.serialize(:content, Hash)
|
1475
|
+
topic = Topic.new(:content => settings)
|
1476
|
+
assert topic.save
|
1477
|
+
assert_equal(settings, Topic.find(topic.id).content)
|
1478
|
+
ensure
|
1479
|
+
Topic.serialize(:content)
|
1480
|
+
end
|
1481
|
+
|
1482
|
+
def test_quote
|
1483
|
+
author_name = "\\ \001 ' \n \\n \""
|
1484
|
+
topic = Topic.create('author_name' => author_name)
|
1485
|
+
assert_equal author_name, Topic.find(topic.id).author_name
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
if RUBY_VERSION < '1.9'
|
1489
|
+
def test_quote_chars
|
1490
|
+
with_kcode('UTF8') do
|
1491
|
+
str = 'The Narrator'
|
1492
|
+
topic = Topic.create(:author_name => str)
|
1493
|
+
assert_equal str, topic.author_name
|
1494
|
+
|
1495
|
+
assert_kind_of ActiveSupport::Multibyte.proxy_class, str.mb_chars
|
1496
|
+
topic = Topic.find_by_author_name(str.mb_chars)
|
1497
|
+
|
1498
|
+
assert_kind_of Topic, topic
|
1499
|
+
assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
|
1500
|
+
end
|
1501
|
+
end
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
def test_class_level_destroy
|
1505
|
+
should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
|
1506
|
+
Topic.find(1).replies << should_be_destroyed_reply
|
1507
|
+
|
1508
|
+
Topic.destroy(1)
|
1509
|
+
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
|
1510
|
+
assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
def test_class_level_delete
|
1514
|
+
should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
|
1515
|
+
Topic.find(1).replies << should_be_destroyed_reply
|
1516
|
+
|
1517
|
+
Topic.delete(1)
|
1518
|
+
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
|
1519
|
+
assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
|
1520
|
+
end
|
1521
|
+
|
1522
|
+
def test_increment_attribute
|
1523
|
+
assert_equal 50, accounts(:signals37).credit_limit
|
1524
|
+
accounts(:signals37).increment! :credit_limit
|
1525
|
+
assert_equal 51, accounts(:signals37, :reload).credit_limit
|
1526
|
+
|
1527
|
+
accounts(:signals37).increment(:credit_limit).increment!(:credit_limit)
|
1528
|
+
assert_equal 53, accounts(:signals37, :reload).credit_limit
|
1529
|
+
end
|
1530
|
+
|
1531
|
+
def test_increment_nil_attribute
|
1532
|
+
assert_nil topics(:first).parent_id
|
1533
|
+
topics(:first).increment! :parent_id
|
1534
|
+
assert_equal 1, topics(:first).parent_id
|
1535
|
+
end
|
1536
|
+
|
1537
|
+
def test_increment_attribute_by
|
1538
|
+
assert_equal 50, accounts(:signals37).credit_limit
|
1539
|
+
accounts(:signals37).increment! :credit_limit, 5
|
1540
|
+
assert_equal 55, accounts(:signals37, :reload).credit_limit
|
1541
|
+
|
1542
|
+
accounts(:signals37).increment(:credit_limit, 1).increment!(:credit_limit, 3)
|
1543
|
+
assert_equal 59, accounts(:signals37, :reload).credit_limit
|
1544
|
+
end
|
1545
|
+
|
1546
|
+
def test_decrement_attribute
|
1547
|
+
assert_equal 50, accounts(:signals37).credit_limit
|
1548
|
+
|
1549
|
+
accounts(:signals37).decrement!(:credit_limit)
|
1550
|
+
assert_equal 49, accounts(:signals37, :reload).credit_limit
|
1551
|
+
|
1552
|
+
accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit)
|
1553
|
+
assert_equal 47, accounts(:signals37, :reload).credit_limit
|
1554
|
+
end
|
1555
|
+
|
1556
|
+
def test_decrement_attribute_by
|
1557
|
+
assert_equal 50, accounts(:signals37).credit_limit
|
1558
|
+
accounts(:signals37).decrement! :credit_limit, 5
|
1559
|
+
assert_equal 45, accounts(:signals37, :reload).credit_limit
|
1560
|
+
|
1561
|
+
accounts(:signals37).decrement(:credit_limit, 1).decrement!(:credit_limit, 3)
|
1562
|
+
assert_equal 41, accounts(:signals37, :reload).credit_limit
|
1563
|
+
end
|
1564
|
+
|
1565
|
+
def test_toggle_attribute
|
1566
|
+
assert !topics(:first).approved?
|
1567
|
+
topics(:first).toggle!(:approved)
|
1568
|
+
assert topics(:first).approved?
|
1569
|
+
topic = topics(:first)
|
1570
|
+
topic.toggle(:approved)
|
1571
|
+
assert !topic.approved?
|
1572
|
+
topic.reload
|
1573
|
+
assert topic.approved?
|
1574
|
+
end
|
1575
|
+
|
1576
|
+
def test_reload
|
1577
|
+
t1 = Topic.find(1)
|
1578
|
+
t2 = Topic.find(1)
|
1579
|
+
t1.title = "something else"
|
1580
|
+
t1.save
|
1581
|
+
t2.reload
|
1582
|
+
assert_equal t1.title, t2.title
|
1583
|
+
end
|
1584
|
+
|
1585
|
+
def test_define_attr_method_with_value
|
1586
|
+
k = Class.new( ActiveRecord::Base )
|
1587
|
+
k.send(:define_attr_method, :table_name, "foo")
|
1588
|
+
assert_equal "foo", k.table_name
|
1589
|
+
end
|
1590
|
+
|
1591
|
+
def test_define_attr_method_with_block
|
1592
|
+
k = Class.new( ActiveRecord::Base )
|
1593
|
+
k.send(:define_attr_method, :primary_key) { "sys_" + original_primary_key }
|
1594
|
+
assert_equal "sys_id", k.primary_key
|
1595
|
+
end
|
1596
|
+
|
1597
|
+
def test_set_table_name_with_value
|
1598
|
+
k = Class.new( ActiveRecord::Base )
|
1599
|
+
k.table_name = "foo"
|
1600
|
+
assert_equal "foo", k.table_name
|
1601
|
+
k.set_table_name "bar"
|
1602
|
+
assert_equal "bar", k.table_name
|
1603
|
+
end
|
1604
|
+
|
1605
|
+
def test_set_table_name_with_block
|
1606
|
+
k = Class.new( ActiveRecord::Base )
|
1607
|
+
k.set_table_name { "ks" }
|
1608
|
+
assert_equal "ks", k.table_name
|
1609
|
+
end
|
1610
|
+
|
1611
|
+
def test_set_primary_key_with_value
|
1612
|
+
k = Class.new( ActiveRecord::Base )
|
1613
|
+
k.primary_key = "foo"
|
1614
|
+
assert_equal "foo", k.primary_key
|
1615
|
+
k.set_primary_key "bar"
|
1616
|
+
assert_equal "bar", k.primary_key
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
def test_set_primary_key_with_block
|
1620
|
+
k = Class.new( ActiveRecord::Base )
|
1621
|
+
k.set_primary_key { "sys_" + original_primary_key }
|
1622
|
+
assert_equal "sys_id", k.primary_key
|
1623
|
+
end
|
1624
|
+
|
1625
|
+
def test_set_inheritance_column_with_value
|
1626
|
+
k = Class.new( ActiveRecord::Base )
|
1627
|
+
k.inheritance_column = "foo"
|
1628
|
+
assert_equal "foo", k.inheritance_column
|
1629
|
+
k.set_inheritance_column "bar"
|
1630
|
+
assert_equal "bar", k.inheritance_column
|
1631
|
+
end
|
1632
|
+
|
1633
|
+
def test_set_inheritance_column_with_block
|
1634
|
+
k = Class.new( ActiveRecord::Base )
|
1635
|
+
k.set_inheritance_column { original_inheritance_column + "_id" }
|
1636
|
+
assert_equal "type_id", k.inheritance_column
|
1637
|
+
end
|
1638
|
+
|
1639
|
+
def test_count_with_join
|
1640
|
+
res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
|
1641
|
+
|
1642
|
+
res2 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'", :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
|
1643
|
+
assert_equal res, res2
|
1644
|
+
|
1645
|
+
res3 = nil
|
1646
|
+
assert_nothing_raised do
|
1647
|
+
res3 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'",
|
1648
|
+
:joins => "LEFT JOIN comments ON posts.id=comments.post_id")
|
1649
|
+
end
|
1650
|
+
assert_equal res, res3
|
1651
|
+
|
1652
|
+
res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
|
1653
|
+
res5 = nil
|
1654
|
+
assert_nothing_raised do
|
1655
|
+
res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
|
1656
|
+
:joins => "p, comments co",
|
1657
|
+
:select => "p.id")
|
1658
|
+
end
|
1659
|
+
|
1660
|
+
assert_equal res4, res5
|
1661
|
+
|
1662
|
+
unless current_adapter?(:SQLite2Adapter, :DeprecatedSQLiteAdapter)
|
1663
|
+
res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
|
1664
|
+
res7 = nil
|
1665
|
+
assert_nothing_raised do
|
1666
|
+
res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
|
1667
|
+
:joins => "p, comments co",
|
1668
|
+
:select => "p.id",
|
1669
|
+
:distinct => true)
|
1670
|
+
end
|
1671
|
+
assert_equal res6, res7
|
1672
|
+
end
|
1673
|
+
end
|
1674
|
+
|
1675
|
+
def test_clear_association_cache_stored
|
1676
|
+
firm = Firm.find(1)
|
1677
|
+
assert_kind_of Firm, firm
|
1678
|
+
|
1679
|
+
firm.clear_association_cache
|
1680
|
+
assert_equal Firm.find(1).clients.collect{ |x| x.name }.sort, firm.clients.collect{ |x| x.name }.sort
|
1681
|
+
end
|
1682
|
+
|
1683
|
+
def test_clear_association_cache_new_record
|
1684
|
+
firm = Firm.new
|
1685
|
+
client_stored = Client.find(3)
|
1686
|
+
client_new = Client.new
|
1687
|
+
client_new.name = "The Joneses"
|
1688
|
+
clients = [ client_stored, client_new ]
|
1689
|
+
|
1690
|
+
firm.clients << clients
|
1691
|
+
assert_equal clients.map(&:name).to_set, firm.clients.map(&:name).to_set
|
1692
|
+
|
1693
|
+
firm.clear_association_cache
|
1694
|
+
assert_equal clients.map(&:name).to_set, firm.clients.map(&:name).to_set
|
1695
|
+
end
|
1696
|
+
|
1697
|
+
def test_interpolate_sql
|
1698
|
+
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo@bar') }
|
1699
|
+
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar) baz') }
|
1700
|
+
assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar} baz') }
|
1701
|
+
end
|
1702
|
+
|
1703
|
+
def test_scoped_find_conditions
|
1704
|
+
scoped_developers = Developer.with_scope(:find => { :conditions => 'salary > 90000' }) do
|
1705
|
+
Developer.find(:all, :conditions => 'id < 5')
|
1706
|
+
end
|
1707
|
+
assert !scoped_developers.include?(developers(:david)) # David's salary is less than 90,000
|
1708
|
+
assert_equal 3, scoped_developers.size
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
def test_scoped_find_limit_offset
|
1712
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 3, :offset => 2 }) do
|
1713
|
+
Developer.find(:all, :order => 'id')
|
1714
|
+
end
|
1715
|
+
assert !scoped_developers.include?(developers(:david))
|
1716
|
+
assert !scoped_developers.include?(developers(:jamis))
|
1717
|
+
assert_equal 3, scoped_developers.size
|
1718
|
+
|
1719
|
+
# Test without scoped find conditions to ensure we get the whole thing
|
1720
|
+
developers = Developer.find(:all, :order => 'id')
|
1721
|
+
assert_equal Developer.count, developers.size
|
1722
|
+
end
|
1723
|
+
|
1724
|
+
def test_scoped_find_order
|
1725
|
+
# Test order in scope
|
1726
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 1, :order => 'salary DESC' }) do
|
1727
|
+
Developer.find(:all)
|
1728
|
+
end
|
1729
|
+
assert_equal 'Jamis', scoped_developers.first.name
|
1730
|
+
assert scoped_developers.include?(developers(:jamis))
|
1731
|
+
# Test scope without order and order in find
|
1732
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 1 }) do
|
1733
|
+
Developer.find(:all, :order => 'salary DESC')
|
1734
|
+
end
|
1735
|
+
# Test scope order + find order, find has priority
|
1736
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 3, :order => 'id DESC' }) do
|
1737
|
+
Developer.find(:all, :order => 'salary ASC')
|
1738
|
+
end
|
1739
|
+
assert scoped_developers.include?(developers(:poor_jamis))
|
1740
|
+
assert scoped_developers.include?(developers(:david))
|
1741
|
+
assert scoped_developers.include?(developers(:dev_10))
|
1742
|
+
# Test without scoped find conditions to ensure we get the right thing
|
1743
|
+
developers = Developer.find(:all, :order => 'id', :limit => 1)
|
1744
|
+
assert scoped_developers.include?(developers(:david))
|
1745
|
+
end
|
1746
|
+
|
1747
|
+
def test_scoped_find_limit_offset_including_has_many_association
|
1748
|
+
topics = Topic.with_scope(:find => {:limit => 1, :offset => 1, :include => :replies}) do
|
1749
|
+
Topic.find(:all, :order => "topics.id")
|
1750
|
+
end
|
1751
|
+
assert_equal 1, topics.size
|
1752
|
+
assert_equal 2, topics.first.id
|
1753
|
+
end
|
1754
|
+
|
1755
|
+
def test_scoped_find_order_including_has_many_association
|
1756
|
+
developers = Developer.with_scope(:find => { :order => 'developers.salary DESC', :include => :projects }) do
|
1757
|
+
Developer.find(:all)
|
1758
|
+
end
|
1759
|
+
assert developers.size >= 2
|
1760
|
+
for i in 1...developers.size
|
1761
|
+
assert developers[i-1].salary >= developers[i].salary
|
1762
|
+
end
|
1763
|
+
end
|
1764
|
+
|
1765
|
+
def test_scoped_find_with_group_and_having
|
1766
|
+
developers = Developer.with_scope(:find => { :group => 'developers.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
|
+
|
1772
|
+
def test_find_last
|
1773
|
+
last = Developer.find :last
|
1774
|
+
assert_equal last, Developer.find(:first, :order => 'id desc')
|
1775
|
+
end
|
1776
|
+
|
1777
|
+
def test_last
|
1778
|
+
assert_equal Developer.find(:first, :order => 'id desc'), Developer.last
|
1779
|
+
end
|
1780
|
+
|
1781
|
+
def test_all_with_conditions
|
1782
|
+
assert_equal Developer.find(:all, :order => 'id desc'), Developer.all(:order => 'id desc')
|
1783
|
+
end
|
1784
|
+
|
1785
|
+
def test_find_ordered_last
|
1786
|
+
last = Developer.find :last, :order => 'developers.salary ASC'
|
1787
|
+
assert_equal last, Developer.find(:all, :order => 'developers.salary ASC').last
|
1788
|
+
end
|
1789
|
+
|
1790
|
+
def test_find_reverse_ordered_last
|
1791
|
+
last = Developer.find :last, :order => 'developers.salary DESC'
|
1792
|
+
assert_equal last, Developer.find(:all, :order => 'developers.salary DESC').last
|
1793
|
+
end
|
1794
|
+
|
1795
|
+
def test_find_multiple_ordered_last
|
1796
|
+
last = Developer.find :last, :order => 'developers.name, developers.salary DESC'
|
1797
|
+
assert_equal last, Developer.find(:all, :order => 'developers.name, developers.salary DESC').last
|
1798
|
+
end
|
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
|
+
|
1805
|
+
def test_find_scoped_ordered_last
|
1806
|
+
last_developer = Developer.with_scope(:find => { :order => 'developers.salary ASC' }) do
|
1807
|
+
Developer.find(:last)
|
1808
|
+
end
|
1809
|
+
assert_equal last_developer, Developer.find(:all, :order => 'developers.salary ASC').last
|
1810
|
+
end
|
1811
|
+
|
1812
|
+
def test_abstract_class
|
1813
|
+
assert !ActiveRecord::Base.abstract_class?
|
1814
|
+
assert LoosePerson.abstract_class?
|
1815
|
+
assert !LooseDescendant.abstract_class?
|
1816
|
+
end
|
1817
|
+
|
1818
|
+
def test_base_class
|
1819
|
+
assert_equal LoosePerson, LoosePerson.base_class
|
1820
|
+
assert_equal LooseDescendant, LooseDescendant.base_class
|
1821
|
+
assert_equal TightPerson, TightPerson.base_class
|
1822
|
+
assert_equal TightPerson, TightDescendant.base_class
|
1823
|
+
|
1824
|
+
assert_equal Post, Post.base_class
|
1825
|
+
assert_equal Post, SpecialPost.base_class
|
1826
|
+
assert_equal Post, StiPost.base_class
|
1827
|
+
assert_equal SubStiPost, SubStiPost.base_class
|
1828
|
+
end
|
1829
|
+
|
1830
|
+
def test_descends_from_active_record
|
1831
|
+
# Tries to call Object.abstract_class?
|
1832
|
+
assert_raise(NoMethodError) do
|
1833
|
+
ActiveRecord::Base.descends_from_active_record?
|
1834
|
+
end
|
1835
|
+
|
1836
|
+
# Abstract subclass of AR::Base.
|
1837
|
+
assert LoosePerson.descends_from_active_record?
|
1838
|
+
|
1839
|
+
# Concrete subclass of an abstract class.
|
1840
|
+
assert LooseDescendant.descends_from_active_record?
|
1841
|
+
|
1842
|
+
# Concrete subclass of AR::Base.
|
1843
|
+
assert TightPerson.descends_from_active_record?
|
1844
|
+
|
1845
|
+
# Concrete subclass of a concrete class but has no type column.
|
1846
|
+
assert TightDescendant.descends_from_active_record?
|
1847
|
+
|
1848
|
+
# Concrete subclass of AR::Base.
|
1849
|
+
assert Post.descends_from_active_record?
|
1850
|
+
|
1851
|
+
# Abstract subclass of a concrete class which has a type column.
|
1852
|
+
# This is pathological, as you'll never have Sub < Abstract < Concrete.
|
1853
|
+
assert !StiPost.descends_from_active_record?
|
1854
|
+
|
1855
|
+
# Concrete subclasses an abstract class which has a type column.
|
1856
|
+
assert !SubStiPost.descends_from_active_record?
|
1857
|
+
end
|
1858
|
+
|
1859
|
+
def test_find_on_abstract_base_class_doesnt_use_type_condition
|
1860
|
+
old_class = LooseDescendant
|
1861
|
+
Object.send :remove_const, :LooseDescendant
|
1862
|
+
|
1863
|
+
descendant = old_class.create! :first_name => 'bob'
|
1864
|
+
assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
|
1865
|
+
ensure
|
1866
|
+
unless Object.const_defined?(:LooseDescendant)
|
1867
|
+
Object.const_set :LooseDescendant, old_class
|
1868
|
+
end
|
1869
|
+
end
|
1870
|
+
|
1871
|
+
def test_assert_queries
|
1872
|
+
query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
|
1873
|
+
assert_queries(2) { 2.times { query.call } }
|
1874
|
+
assert_queries 1, &query
|
1875
|
+
assert_no_queries { assert true }
|
1876
|
+
end
|
1877
|
+
|
1878
|
+
def test_to_xml
|
1879
|
+
xml = REXML::Document.new(topics(:first).to_xml(:indent => 0))
|
1880
|
+
bonus_time_in_current_timezone = topics(:first).bonus_time.xmlschema
|
1881
|
+
written_on_in_current_timezone = topics(:first).written_on.xmlschema
|
1882
|
+
last_read_in_current_timezone = topics(:first).last_read.xmlschema
|
1883
|
+
|
1884
|
+
assert_equal "topic", xml.root.name
|
1885
|
+
assert_equal "The First Topic" , xml.elements["//title"].text
|
1886
|
+
assert_equal "David" , xml.elements["//author-name"].text
|
1887
|
+
|
1888
|
+
assert_equal "1", xml.elements["//id"].text
|
1889
|
+
assert_equal "integer" , xml.elements["//id"].attributes['type']
|
1890
|
+
|
1891
|
+
assert_equal "1", xml.elements["//replies-count"].text
|
1892
|
+
assert_equal "integer" , xml.elements["//replies-count"].attributes['type']
|
1893
|
+
|
1894
|
+
assert_equal written_on_in_current_timezone, xml.elements["//written-on"].text
|
1895
|
+
assert_equal "datetime" , xml.elements["//written-on"].attributes['type']
|
1896
|
+
|
1897
|
+
assert_equal "--- Have a nice day\n" , xml.elements["//content"].text
|
1898
|
+
assert_equal "yaml" , xml.elements["//content"].attributes['type']
|
1899
|
+
|
1900
|
+
assert_equal "david@loudthinking.com", xml.elements["//author-email-address"].text
|
1901
|
+
|
1902
|
+
assert_equal nil, xml.elements["//parent-id"].text
|
1903
|
+
assert_equal "integer", xml.elements["//parent-id"].attributes['type']
|
1904
|
+
assert_equal "true", xml.elements["//parent-id"].attributes['nil']
|
1905
|
+
|
1906
|
+
if current_adapter?(:SybaseAdapter, :OracleAdapter)
|
1907
|
+
assert_equal last_read_in_current_timezone, xml.elements["//last-read"].text
|
1908
|
+
assert_equal "datetime" , xml.elements["//last-read"].attributes['type']
|
1909
|
+
else
|
1910
|
+
assert_equal "2004-04-15", xml.elements["//last-read"].text
|
1911
|
+
assert_equal "date" , xml.elements["//last-read"].attributes['type']
|
1912
|
+
end
|
1913
|
+
|
1914
|
+
# Oracle and DB2 don't have true boolean or time-only fields
|
1915
|
+
unless current_adapter?(:OracleAdapter, :DB2Adapter)
|
1916
|
+
assert_equal "false", xml.elements["//approved"].text
|
1917
|
+
assert_equal "boolean" , xml.elements["//approved"].attributes['type']
|
1918
|
+
|
1919
|
+
assert_equal bonus_time_in_current_timezone, xml.elements["//bonus-time"].text
|
1920
|
+
assert_equal "datetime" , xml.elements["//bonus-time"].attributes['type']
|
1921
|
+
end
|
1922
|
+
end
|
1923
|
+
|
1924
|
+
def test_to_xml_skipping_attributes
|
1925
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :replies_count])
|
1926
|
+
assert_equal "<topic>", xml.first(7)
|
1927
|
+
assert !xml.include?(%(<title>The First Topic</title>))
|
1928
|
+
assert xml.include?(%(<author-name>David</author-name>))
|
1929
|
+
|
1930
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :author_name, :replies_count])
|
1931
|
+
assert !xml.include?(%(<title>The First Topic</title>))
|
1932
|
+
assert !xml.include?(%(<author-name>David</author-name>))
|
1933
|
+
end
|
1934
|
+
|
1935
|
+
def test_to_xml_including_has_many_association
|
1936
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies, :except => :replies_count)
|
1937
|
+
assert_equal "<topic>", xml.first(7)
|
1938
|
+
assert xml.include?(%(<replies type="array"><reply>))
|
1939
|
+
assert xml.include?(%(<title>The Second Topic of the day</title>))
|
1940
|
+
end
|
1941
|
+
|
1942
|
+
def test_array_to_xml_including_has_many_association
|
1943
|
+
xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :include => :replies)
|
1944
|
+
assert xml.include?(%(<replies type="array"><reply>))
|
1945
|
+
end
|
1946
|
+
|
1947
|
+
def test_array_to_xml_including_methods
|
1948
|
+
xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :methods => [ :topic_id ])
|
1949
|
+
assert xml.include?(%(<topic-id type="integer">#{topics(:first).topic_id}</topic-id>)), xml
|
1950
|
+
assert xml.include?(%(<topic-id type="integer">#{topics(:second).topic_id}</topic-id>)), xml
|
1951
|
+
end
|
1952
|
+
|
1953
|
+
def test_array_to_xml_including_has_one_association
|
1954
|
+
xml = [ companies(:first_firm), companies(:rails_core) ].to_xml(:indent => 0, :skip_instruct => true, :include => :account)
|
1955
|
+
assert xml.include?(companies(:first_firm).account.to_xml(:indent => 0, :skip_instruct => true))
|
1956
|
+
assert xml.include?(companies(:rails_core).account.to_xml(:indent => 0, :skip_instruct => true))
|
1957
|
+
end
|
1958
|
+
|
1959
|
+
def test_array_to_xml_including_belongs_to_association
|
1960
|
+
xml = [ companies(:first_client), companies(:second_client), companies(:another_client) ].to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1961
|
+
assert xml.include?(companies(:first_client).to_xml(:indent => 0, :skip_instruct => true))
|
1962
|
+
assert xml.include?(companies(:second_client).firm.to_xml(:indent => 0, :skip_instruct => true))
|
1963
|
+
assert xml.include?(companies(:another_client).firm.to_xml(:indent => 0, :skip_instruct => true))
|
1964
|
+
end
|
1965
|
+
|
1966
|
+
def test_to_xml_including_belongs_to_association
|
1967
|
+
xml = companies(:first_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1968
|
+
assert !xml.include?("<firm>")
|
1969
|
+
|
1970
|
+
xml = companies(:second_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1971
|
+
assert xml.include?("<firm>")
|
1972
|
+
end
|
1973
|
+
|
1974
|
+
def test_to_xml_including_multiple_associations
|
1975
|
+
xml = companies(:first_firm).to_xml(:indent => 0, :skip_instruct => true, :include => [ :clients, :account ])
|
1976
|
+
assert_equal "<firm>", xml.first(6)
|
1977
|
+
assert xml.include?(%(<account>))
|
1978
|
+
assert xml.include?(%(<clients type="array"><client>))
|
1979
|
+
end
|
1980
|
+
|
1981
|
+
def test_to_xml_including_multiple_associations_with_options
|
1982
|
+
xml = companies(:first_firm).to_xml(
|
1983
|
+
:indent => 0, :skip_instruct => true,
|
1984
|
+
:include => { :clients => { :only => :name } }
|
1985
|
+
)
|
1986
|
+
|
1987
|
+
assert_equal "<firm>", xml.first(6)
|
1988
|
+
assert xml.include?(%(<client><name>Summit</name></client>))
|
1989
|
+
assert xml.include?(%(<clients type="array"><client>))
|
1990
|
+
end
|
1991
|
+
|
1992
|
+
def test_to_xml_including_methods
|
1993
|
+
xml = Company.new.to_xml(:methods => :arbitrary_method, :skip_instruct => true)
|
1994
|
+
assert_equal "<company>", xml.first(9)
|
1995
|
+
assert xml.include?(%(<arbitrary-method>I am Jack's profound disappointment</arbitrary-method>))
|
1996
|
+
end
|
1997
|
+
|
1998
|
+
def test_to_xml_with_block
|
1999
|
+
value = "Rockin' the block"
|
2000
|
+
xml = Company.new.to_xml(:skip_instruct => true) do |xml|
|
2001
|
+
xml.tag! "arbitrary-element", value
|
2002
|
+
end
|
2003
|
+
assert_equal "<company>", xml.first(9)
|
2004
|
+
assert xml.include?(%(<arbitrary-element>#{value}</arbitrary-element>))
|
2005
|
+
end
|
2006
|
+
|
2007
|
+
def test_type_name_with_module_should_handle_beginning
|
2008
|
+
assert_equal 'ActiveRecord::Person', ActiveRecord::Base.send(:type_name_with_module, 'Person')
|
2009
|
+
assert_equal '::Person', ActiveRecord::Base.send(:type_name_with_module, '::Person')
|
2010
|
+
end
|
2011
|
+
|
2012
|
+
def test_to_param_should_return_string
|
2013
|
+
assert_kind_of String, Client.find(:first).to_param
|
2014
|
+
end
|
2015
|
+
|
2016
|
+
def test_inspect_class
|
2017
|
+
assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect
|
2018
|
+
assert_equal 'LoosePerson(abstract)', LoosePerson.inspect
|
2019
|
+
assert_match(/^Topic\(id: integer, title: string/, Topic.inspect)
|
2020
|
+
end
|
2021
|
+
|
2022
|
+
def test_inspect_instance
|
2023
|
+
topic = topics(:first)
|
2024
|
+
assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil>), topic.inspect
|
2025
|
+
end
|
2026
|
+
|
2027
|
+
def test_inspect_new_instance
|
2028
|
+
assert_match /Topic id: nil/, Topic.new.inspect
|
2029
|
+
end
|
2030
|
+
|
2031
|
+
def test_inspect_limited_select_instance
|
2032
|
+
assert_equal %(#<Topic id: 1>), Topic.find(:first, :select => 'id', :conditions => 'id = 1').inspect
|
2033
|
+
assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.find(:first, :select => 'id, title', :conditions => 'id = 1').inspect
|
2034
|
+
end
|
2035
|
+
|
2036
|
+
def test_inspect_class_without_table
|
2037
|
+
assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect
|
2038
|
+
end
|
2039
|
+
|
2040
|
+
def test_attribute_for_inspect
|
2041
|
+
t = topics(:first)
|
2042
|
+
t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
|
2043
|
+
|
2044
|
+
assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
|
2045
|
+
assert_equal '"The First Topic Now Has A Title With\nNewlines And M..."', t.attribute_for_inspect(:title)
|
2046
|
+
end
|
2047
|
+
|
2048
|
+
def test_becomes
|
2049
|
+
assert_kind_of Reply, topics(:first).becomes(Reply)
|
2050
|
+
assert_equal "The First Topic", topics(:first).becomes(Reply).title
|
2051
|
+
end
|
2052
|
+
|
2053
|
+
def test_silence_sets_log_level_to_error_in_block
|
2054
|
+
original_logger = ActiveRecord::Base.logger
|
2055
|
+
log = StringIO.new
|
2056
|
+
ActiveRecord::Base.logger = Logger.new(log)
|
2057
|
+
ActiveRecord::Base.logger.level = Logger::DEBUG
|
2058
|
+
ActiveRecord::Base.silence do
|
2059
|
+
ActiveRecord::Base.logger.warn "warn"
|
2060
|
+
ActiveRecord::Base.logger.error "error"
|
2061
|
+
end
|
2062
|
+
assert_equal "error\n", log.string
|
2063
|
+
ensure
|
2064
|
+
ActiveRecord::Base.logger = original_logger
|
2065
|
+
end
|
2066
|
+
|
2067
|
+
def test_silence_sets_log_level_back_to_level_before_yield
|
2068
|
+
original_logger = ActiveRecord::Base.logger
|
2069
|
+
log = StringIO.new
|
2070
|
+
ActiveRecord::Base.logger = Logger.new(log)
|
2071
|
+
ActiveRecord::Base.logger.level = Logger::WARN
|
2072
|
+
ActiveRecord::Base.silence do
|
2073
|
+
end
|
2074
|
+
assert_equal Logger::WARN, ActiveRecord::Base.logger.level
|
2075
|
+
ensure
|
2076
|
+
ActiveRecord::Base.logger = original_logger
|
2077
|
+
end
|
2078
|
+
|
2079
|
+
def test_benchmark_with_log_level
|
2080
|
+
original_logger = ActiveRecord::Base.logger
|
2081
|
+
log = StringIO.new
|
2082
|
+
ActiveRecord::Base.logger = Logger.new(log)
|
2083
|
+
ActiveRecord::Base.logger.level = Logger::WARN
|
2084
|
+
ActiveRecord::Base.benchmark("Debug Topic Count", Logger::DEBUG) { Topic.count }
|
2085
|
+
ActiveRecord::Base.benchmark("Warn Topic Count", Logger::WARN) { Topic.count }
|
2086
|
+
ActiveRecord::Base.benchmark("Error Topic Count", Logger::ERROR) { Topic.count }
|
2087
|
+
assert_no_match /Debug Topic Count/, log.string
|
2088
|
+
assert_match /Warn Topic Count/, log.string
|
2089
|
+
assert_match /Error Topic Count/, log.string
|
2090
|
+
ensure
|
2091
|
+
ActiveRecord::Base.logger = original_logger
|
2092
|
+
end
|
2093
|
+
|
2094
|
+
def test_benchmark_with_use_silence
|
2095
|
+
original_logger = ActiveRecord::Base.logger
|
2096
|
+
log = StringIO.new
|
2097
|
+
ActiveRecord::Base.logger = Logger.new(log)
|
2098
|
+
ActiveRecord::Base.benchmark("Logging", Logger::DEBUG, true) { ActiveRecord::Base.logger.debug "Loud" }
|
2099
|
+
ActiveRecord::Base.benchmark("Logging", Logger::DEBUG, false) { ActiveRecord::Base.logger.debug "Quiet" }
|
2100
|
+
assert_no_match /Loud/, log.string
|
2101
|
+
assert_match /Quiet/, log.string
|
2102
|
+
ensure
|
2103
|
+
ActiveRecord::Base.logger = original_logger
|
2104
|
+
end
|
2105
|
+
|
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]
|
2112
|
+
end
|
2113
|
+
end
|
2114
|
+
end
|