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