base_test.rb 61.6 KB
Newer Older
1
require 'abstract_unit'
J
Jeremy Kemper 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15
require 'models/topic'
require 'models/reply'
require 'models/company'
require 'models/customer'
require 'models/developer'
require 'models/project'
require 'models/default'
require 'models/auto_id'
require 'models/column_name'
require 'models/subscriber'
require 'models/keyboard'
require 'models/post'
require 'models/minimalistic'
require 'models/warehouse_thing'
16
require 'rexml/document'
D
Initial  
David Heinemeier Hansson 已提交
17 18 19

class Category < ActiveRecord::Base; end
class Smarts < ActiveRecord::Base; end
20
class CreditCard < ActiveRecord::Base
21 22 23 24 25 26
  class PinNumber < ActiveRecord::Base
    class CvvCode < ActiveRecord::Base; end
    class SubCvvCode < CvvCode; end
  end
  class SubPinNumber < PinNumber; end
  class Brand < Category; end
27
end
D
Initial  
David Heinemeier Hansson 已提交
28
class MasterCreditCard < ActiveRecord::Base; end
29
class Post < ActiveRecord::Base; end
30
class Computer < ActiveRecord::Base; end
31
class NonExistentTable < ActiveRecord::Base; end
32
class TestOracleDefault < ActiveRecord::Base; end
D
Initial  
David Heinemeier Hansson 已提交
33 34

class LoosePerson < ActiveRecord::Base
35
  self.table_name = 'people'
36
  self.abstract_class = true
37
  attr_protected :credit_rating, :administrator
D
Initial  
David Heinemeier Hansson 已提交
38 39
end

40 41 42 43
class LooseDescendant < LoosePerson
  attr_protected :phone_number
end

44 45 46 47 48
class LooseDescendantSecond< LoosePerson
  attr_protected :phone_number
  attr_protected :name
end

D
Initial  
David Heinemeier Hansson 已提交
49
class TightPerson < ActiveRecord::Base
50
  self.table_name = 'people'
D
Initial  
David Heinemeier Hansson 已提交
51 52 53
  attr_accessible :name, :address
end

54
class TightDescendant < TightPerson
D
Initial  
David Heinemeier Hansson 已提交
55 56 57
  attr_accessible :phone_number
end

58 59 60 61
class ReadonlyTitlePost < Post
  attr_readonly :title
end

D
Initial  
David Heinemeier Hansson 已提交
62 63
class Booleantest < ActiveRecord::Base; end

64 65 66 67
class Task < ActiveRecord::Base
  attr_protected :starting
end

J
Jeremy Kemper 已提交
68 69
class TopicWithProtectedContentAndAccessibleAuthorName < ActiveRecord::Base
  self.table_name = 'topics'
70 71 72 73
  attr_accessible :author_name
  attr_protected  :content
end

74
class BasicsTest < ActiveSupport::TestCase
75
  fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things'
D
Initial  
David Heinemeier Hansson 已提交
76

77 78 79 80
  def test_table_exists
    assert !NonExistentTable.table_exists?
    assert Topic.table_exists?
  end
J
Jeremy Kemper 已提交
81

D
Initial  
David Heinemeier Hansson 已提交
82 83 84 85 86 87
  def test_set_attributes
    topic = Topic.find(1)
    topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
    topic.save
    assert_equal("Budget", topic.title)
    assert_equal("Jason", topic.author_name)
88
    assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
D
Initial  
David Heinemeier Hansson 已提交
89
  end
90

D
Initial  
David Heinemeier Hansson 已提交
91
  def test_integers_as_nil
J
Jeremy Kemper 已提交
92 93
    test = AutoId.create('value' => '')
    assert_nil AutoId.find(test.id).value
D
Initial  
David Heinemeier Hansson 已提交
94
  end
J
Jeremy Kemper 已提交
95

D
Initial  
David Heinemeier Hansson 已提交
96 97 98 99 100 101 102 103 104
  def test_set_attributes_with_block
    topic = Topic.new do |t|
      t.title       = "Budget"
      t.author_name = "Jason"
    end

    assert_equal("Budget", topic.title)
    assert_equal("Jason", topic.author_name)
  end
J
Jeremy Kemper 已提交
105

D
Initial  
David Heinemeier Hansson 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118
  def test_respond_to?
    topic = Topic.find(1)
    assert topic.respond_to?("title")
    assert topic.respond_to?("title?")
    assert topic.respond_to?("title=")
    assert topic.respond_to?(:title)
    assert topic.respond_to?(:title?)
    assert topic.respond_to?(:title=)
    assert topic.respond_to?("author_name")
    assert topic.respond_to?("attribute_names")
    assert !topic.respond_to?("nothingness")
    assert !topic.respond_to?(:nothingness)
  end
J
Jeremy Kemper 已提交
119

D
Initial  
David Heinemeier Hansson 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133
  def test_array_content
    topic = Topic.new
    topic.content = %w( one two three )
    topic.save

    assert_equal(%w( one two three ), Topic.find(topic.id).content)
  end

  def test_hash_content
    topic = Topic.new
    topic.content = { "one" => 1, "two" => 2 }
    topic.save

    assert_equal 2, Topic.find(topic.id).content["two"]
J
Jeremy Kemper 已提交
134

D
Initial  
David Heinemeier Hansson 已提交
135 136 137 138 139
    topic.content["three"] = 3
    topic.save

    assert_equal 3, Topic.find(topic.id).content["three"]
  end
J
Jeremy Kemper 已提交
140

D
Initial  
David Heinemeier Hansson 已提交
141 142 143 144 145 146 147 148
  def test_update_array_content
    topic = Topic.new
    topic.content = %w( one two three )

    topic.content.push "four"
    assert_equal(%w( one two three four ), topic.content)

    topic.save
J
Jeremy Kemper 已提交
149

D
Initial  
David Heinemeier Hansson 已提交
150 151 152 153
    topic = Topic.find(topic.id)
    topic.content << "five"
    assert_equal(%w( one two three four five ), topic.content)
  end
J
Jeremy Kemper 已提交
154

155 156 157 158
  def test_case_sensitive_attributes_hash
    # DB2 is not case-sensitive
    return true if current_adapter?(:DB2Adapter)

159
    assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
160
  end
161

D
Initial  
David Heinemeier Hansson 已提交
162 163 164 165
  def test_create
    topic = Topic.new
    topic.title = "New Topic"
    topic.save
166 167 168
    topic_reloaded = Topic.find(topic.id)
    assert_equal("New Topic", topic_reloaded.title)
  end
J
Jeremy Kemper 已提交
169

170 171 172
  def test_save!
    topic = Topic.new(:title => "New Topic")
    assert topic.save!
J
Jeremy Kemper 已提交
173

174 175 176
    reply = Reply.new
    assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
  end
177 178 179 180 181 182 183 184

  def test_save_null_string_attributes
    topic = Topic.find(1)
    topic.attributes = { "title" => "null", "author_name" => "null" }
    topic.save!
    topic.reload
    assert_equal("null", topic.title)
    assert_equal("null", topic.author_name)
185 186 187 188 189 190 191 192 193 194
  end

  def test_save_nil_string_attributes
    topic = Topic.find(1)
    topic.title = nil
    topic.save!
    topic.reload
    assert_nil topic.title
  end

195 196 197 198 199 200 201 202 203
  def test_save_for_record_with_only_primary_key
    minimalistic = Minimalistic.new
    assert_nothing_raised { minimalistic.save }
  end

  def test_save_for_record_with_only_primary_key_that_is_provided
    assert_nothing_raised { Minimalistic.create!(:id => 2) }
  end

204 205 206 207 208 209 210 211
  def test_hashes_not_mangled
    new_topic = { :title => "New Topic" }
    new_topic_values = { :title => "AnotherTopic" }

    topic = Topic.new(new_topic)
    assert_equal new_topic[:title], topic.title

    topic.attributes= new_topic_values
212
    assert_equal new_topic_values[:title], topic.title
D
Initial  
David Heinemeier Hansson 已提交
213
  end
J
Jeremy Kemper 已提交
214

215 216 217 218 219
  def test_create_many
    topics = Topic.create([ { "title" => "first" }, { "title" => "second" }])
    assert_equal 2, topics.size
    assert_equal "first", topics.first.title
  end
220 221 222 223 224 225 226 227

  def test_create_columns_not_equal_attributes
    topic = Topic.new
    topic.title = 'Another New Topic'
    topic.send :write_attribute, 'does_not_exist', 'test'
    assert_nothing_raised { topic.save }
  end

D
Initial  
David Heinemeier Hansson 已提交
228 229 230 231 232 233 234 235 236
  def test_create_through_factory
    topic = Topic.create("title" => "New Topic")
    topicReloaded = Topic.find(topic.id)
    assert_equal(topic, topicReloaded)
  end

  def test_update
    topic = Topic.new
    topic.title = "Another New Topic"
237
    topic.written_on = "2003-12-12 23:23:00"
D
Initial  
David Heinemeier Hansson 已提交
238
    topic.save
239
    topicReloaded = Topic.find(topic.id)
D
Initial  
David Heinemeier Hansson 已提交
240 241 242 243
    assert_equal("Another New Topic", topicReloaded.title)

    topicReloaded.title = "Updated topic"
    topicReloaded.save
J
Jeremy Kemper 已提交
244

245
    topicReloadedAgain = Topic.find(topic.id)
J
Jeremy Kemper 已提交
246

D
Initial  
David Heinemeier Hansson 已提交
247 248 249
    assert_equal("Updated topic", topicReloadedAgain.title)
  end

250 251 252 253
  def test_update_columns_not_equal_attributes
    topic = Topic.new
    topic.title = "Still another topic"
    topic.save
J
Jeremy Kemper 已提交
254

255
    topicReloaded = Topic.find(topic.id)
256 257 258 259
    topicReloaded.title = "A New Topic"
    topicReloaded.send :write_attribute, 'does_not_exist', 'test'
    assert_nothing_raised { topicReloaded.save }
  end
260 261 262 263 264

  def test_update_for_record_with_only_primary_key
    minimalistic = minimalistics(:first)
    assert_nothing_raised { minimalistic.save }
  end
J
Jeremy Kemper 已提交
265

266 267 268 269 270 271 272 273
  def test_write_attribute
    topic = Topic.new
    topic.send(:write_attribute, :title, "Still another topic")
    assert_equal "Still another topic", topic.title

    topic.send(:write_attribute, "title", "Still another topic: part 2")
    assert_equal "Still another topic: part 2", topic.title
  end
274

275 276 277 278 279 280 281 282 283 284
  def test_read_attribute
    topic = Topic.new
    topic.title = "Don't change the topic"
    assert_equal "Don't change the topic", topic.send(:read_attribute, "title")
    assert_equal "Don't change the topic", topic["title"]

    assert_equal "Don't change the topic", topic.send(:read_attribute, :title)
    assert_equal "Don't change the topic", topic[:title]
  end

285 286 287
  def test_read_attribute_when_false
    topic = topics(:first)
    topic.approved = false
J
Jeremy Kemper 已提交
288
    assert !topic.approved?, "approved should be false"
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
    topic.approved = "false"
    assert !topic.approved?, "approved should be false"
  end

  def test_read_attribute_when_true
    topic = topics(:first)
    topic.approved = true
    assert topic.approved?, "approved should be true"
    topic.approved = "true"
    assert topic.approved?, "approved should be true"
  end

  def test_read_write_boolean_attribute
    topic = Topic.new
    # puts ""
    # puts "New Topic"
    # puts topic.inspect
    topic.approved = "false"
    # puts "Expecting false"
    # puts topic.inspect
309
    assert !topic.approved?, "approved should be false"
310 311 312
    topic.approved = "false"
    # puts "Expecting false"
    # puts topic.inspect
313
    assert !topic.approved?, "approved should be false"
314 315 316
    topic.approved = "true"
    # puts "Expecting true"
    # puts topic.inspect
317
    assert topic.approved?, "approved should be true"
318 319 320
    topic.approved = "true"
    # puts "Expecting true"
    # puts topic.inspect
321
    assert topic.approved?, "approved should be true"
322
    # puts ""
323
  end
J
Jeremy Kemper 已提交
324

325 326 327 328
  def test_query_attribute_string
    [nil, "", " "].each do |value|
      assert_equal false, Topic.new(:author_name => value).author_name?
    end
J
Jeremy Kemper 已提交
329

330 331
    assert_equal true, Topic.new(:author_name => "Name").author_name?
  end
J
Jeremy Kemper 已提交
332

333 334 335 336
  def test_query_attribute_number
    [nil, 0, "0"].each do |value|
      assert_equal false, Developer.new(:salary => value).salary?
    end
J
Jeremy Kemper 已提交
337

338 339 340
    assert_equal true, Developer.new(:salary => 1).salary?
    assert_equal true, Developer.new(:salary => "1").salary?
  end
J
Jeremy Kemper 已提交
341

342 343 344 345
  def test_query_attribute_boolean
    [nil, "", false, "false", "f", 0].each do |value|
      assert_equal false, Topic.new(:approved => value).approved?
    end
J
Jeremy Kemper 已提交
346

347 348 349 350
    [true, "true", "1", 1].each do |value|
      assert_equal true, Topic.new(:approved => value).approved?
    end
  end
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365

  def test_query_attribute_with_custom_fields
    object = Company.find_by_sql(<<-SQL).first
      SELECT c1.*, c2.ruby_type as string_value, c2.rating as int_value
        FROM companies c1, companies c2
       WHERE c1.firm_id = c2.id
         AND c1.id = 2
    SQL

    assert_equal "Firm", object.string_value
    assert object.string_value?

    object.string_value = "  "
    assert !object.string_value?

J
Jamis Buck 已提交
366
    assert_equal 1, object.int_value.to_i
367 368 369 370 371 372
    assert object.int_value?

    object.int_value = "0"
    assert !object.int_value?
  end

373

374
  def test_reader_for_invalid_column_names
375 376
    Topic.send(:define_read_method, "mumub-jumbo".to_sym, "mumub-jumbo", nil)
    assert !Topic.generated_methods.include?("mumub-jumbo")
377 378
  end

379 380 381 382 383 384 385
  def test_non_attribute_access_and_assignment
    topic = Topic.new
    assert !topic.respond_to?("mumbo")
    assert_raises(NoMethodError) { topic.mumbo }
    assert_raises(NoMethodError) { topic.mumbo = 5 }
  end

D
Initial  
David Heinemeier Hansson 已提交
386 387
  def test_preserving_date_objects
    # SQL Server doesn't have a separate column type just for dates, so all are returned as time
388
    return true if current_adapter?(:SQLServerAdapter)
D
Initial  
David Heinemeier Hansson 已提交
389

390
    if current_adapter?(:SybaseAdapter, :OracleAdapter)
391
      # Sybase ctlib does not (yet?) support the date type; use datetime instead.
392
      # Oracle treats all dates/times as Time.
393
      assert_kind_of(
J
Jeremy Kemper 已提交
394
        Time, Topic.find(1).last_read,
395 396 397 398
        "The last_read attribute should be of the Time class"
      )
    else
      assert_kind_of(
J
Jeremy Kemper 已提交
399
        Date, Topic.find(1).last_read,
400 401 402
        "The last_read attribute should be of the Date class"
      )
    end
403
  end
404

405
  def test_preserving_time_objects
406 407 408 409
    assert_kind_of(
      Time, Topic.find(1).bonus_time,
      "The bonus_time attribute should be of the Time class"
    )
D
Initial  
David Heinemeier Hansson 已提交
410 411 412 413 414

    assert_kind_of(
      Time, Topic.find(1).written_on,
      "The written_on attribute should be of the Time class"
    )
415 416 417 418 419

    # For adapters which support microsecond resolution.
    if current_adapter?(:PostgreSQLAdapter)
      assert_equal 11, Topic.find(1).written_on.sec
      assert_equal 223300, Topic.find(1).written_on.usec
420
      assert_equal 9900, Topic.find(2).written_on.usec
421
    end
D
Initial  
David Heinemeier Hansson 已提交
422
  end
J
Jeremy Kemper 已提交
423

424 425 426 427 428 429
  def test_custom_mutator
    topic = Topic.find(1)
    # This mutator is protected in the class definition
    topic.send(:approved=, true)
    assert topic.instance_variable_get("@custom_approved")
  end
J
Jeremy Kemper 已提交
430

D
Initial  
David Heinemeier Hansson 已提交
431
  def test_destroy
J
Jeremy Kemper 已提交
432 433 434
    topic = Topic.find(1)
    assert_equal topic, topic.destroy, 'topic.destroy did not return self'
    assert topic.frozen?, 'topic not frozen after destroy'
435
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
D
Initial  
David Heinemeier Hansson 已提交
436
  end
J
Jeremy Kemper 已提交
437

D
Initial  
David Heinemeier Hansson 已提交
438
  def test_record_not_found_exception
439
    assert_raises(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(99999) }
D
Initial  
David Heinemeier Hansson 已提交
440
  end
J
Jeremy Kemper 已提交
441

D
Initial  
David Heinemeier Hansson 已提交
442
  def test_initialize_with_attributes
J
Jeremy Kemper 已提交
443
    topic = Topic.new({
D
Initial  
David Heinemeier Hansson 已提交
444 445
      "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23"
    })
J
Jeremy Kemper 已提交
446

D
Initial  
David Heinemeier Hansson 已提交
447 448
    assert_equal("initialized from attributes", topic.title)
  end
J
Jeremy Kemper 已提交
449

450 451
  def test_initialize_with_invalid_attribute
    begin
J
Jeremy Kemper 已提交
452
      topic = Topic.new({ "title" => "test",
453 454 455 456 457 458
        "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
    rescue ActiveRecord::MultiparameterAssignmentErrors => ex
      assert_equal(1, ex.errors.size)
      assert_equal("last_read", ex.errors[0].attribute)
    end
  end
J
Jeremy Kemper 已提交
459

D
Initial  
David Heinemeier Hansson 已提交
460
  def test_load
J
Jeremy Kemper 已提交
461
    topics = Topic.find(:all, :order => 'id')
D
Initial  
David Heinemeier Hansson 已提交
462
    assert_equal(2, topics.size)
463
    assert_equal(topics(:first).title, topics.first.title)
D
Initial  
David Heinemeier Hansson 已提交
464
  end
J
Jeremy Kemper 已提交
465

D
Initial  
David Heinemeier Hansson 已提交
466
  def test_load_with_condition
467
    topics = Topic.find(:all, :conditions => "author_name = 'Mary'")
J
Jeremy Kemper 已提交
468

D
Initial  
David Heinemeier Hansson 已提交
469
    assert_equal(1, topics.size)
470
    assert_equal(topics(:second).title, topics.first.title)
D
Initial  
David Heinemeier Hansson 已提交
471 472 473
  end

  def test_table_name_guesses
474 475
    classes = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]

D
Initial  
David Heinemeier Hansson 已提交
476
    assert_equal "topics", Topic.table_name
477

D
Initial  
David Heinemeier Hansson 已提交
478 479 480
    assert_equal "categories", Category.table_name
    assert_equal "smarts", Smarts.table_name
    assert_equal "credit_cards", CreditCard.table_name
481
    assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
482 483 484
    assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
    assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
    assert_equal "categories", CreditCard::Brand.table_name
D
Initial  
David Heinemeier Hansson 已提交
485 486 487
    assert_equal "master_credit_cards", MasterCreditCard.table_name

    ActiveRecord::Base.pluralize_table_names = false
488 489
    classes.each(&:reset_table_name)

D
Initial  
David Heinemeier Hansson 已提交
490 491 492
    assert_equal "category", Category.table_name
    assert_equal "smarts", Smarts.table_name
    assert_equal "credit_card", CreditCard.table_name
493
    assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
494 495 496
    assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
    assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
    assert_equal "category", CreditCard::Brand.table_name
D
Initial  
David Heinemeier Hansson 已提交
497
    assert_equal "master_credit_card", MasterCreditCard.table_name
498

D
Initial  
David Heinemeier Hansson 已提交
499
    ActiveRecord::Base.pluralize_table_names = true
500
    classes.each(&:reset_table_name)
D
Initial  
David Heinemeier Hansson 已提交
501 502

    ActiveRecord::Base.table_name_prefix = "test_"
503
    Category.reset_table_name
D
Initial  
David Heinemeier Hansson 已提交
504 505
    assert_equal "test_categories", Category.table_name
    ActiveRecord::Base.table_name_suffix = "_test"
506
    Category.reset_table_name
D
Initial  
David Heinemeier Hansson 已提交
507 508
    assert_equal "test_categories_test", Category.table_name
    ActiveRecord::Base.table_name_prefix = ""
509
    Category.reset_table_name
D
Initial  
David Heinemeier Hansson 已提交
510 511
    assert_equal "categories_test", Category.table_name
    ActiveRecord::Base.table_name_suffix = ""
512
    Category.reset_table_name
D
Initial  
David Heinemeier Hansson 已提交
513 514 515 516
    assert_equal "categories", Category.table_name

    ActiveRecord::Base.pluralize_table_names = false
    ActiveRecord::Base.table_name_prefix = "test_"
517
    Category.reset_table_name
D
Initial  
David Heinemeier Hansson 已提交
518 519
    assert_equal "test_category", Category.table_name
    ActiveRecord::Base.table_name_suffix = "_test"
520
    Category.reset_table_name
D
Initial  
David Heinemeier Hansson 已提交
521 522
    assert_equal "test_category_test", Category.table_name
    ActiveRecord::Base.table_name_prefix = ""
523
    Category.reset_table_name
D
Initial  
David Heinemeier Hansson 已提交
524 525
    assert_equal "category_test", Category.table_name
    ActiveRecord::Base.table_name_suffix = ""
526
    Category.reset_table_name
D
Initial  
David Heinemeier Hansson 已提交
527
    assert_equal "category", Category.table_name
528

D
Initial  
David Heinemeier Hansson 已提交
529
    ActiveRecord::Base.pluralize_table_names = true
530
    classes.each(&:reset_table_name)
D
Initial  
David Heinemeier Hansson 已提交
531
  end
J
Jeremy Kemper 已提交
532

D
Initial  
David Heinemeier Hansson 已提交
533
  def test_destroy_all
534
    assert_equal 2, Topic.count
D
Initial  
David Heinemeier Hansson 已提交
535 536

    Topic.destroy_all "author_name = 'Mary'"
537
    assert_equal 1, Topic.count
D
Initial  
David Heinemeier Hansson 已提交
538
  end
539 540

  def test_destroy_many
541
    assert_equal 3, Client.count
542
    Client.destroy([2, 3])
543
    assert_equal 1, Client.count
544 545 546 547 548 549 550
  end

  def test_delete_many
    Topic.delete([1, 2])
    assert_equal 0, Topic.count
  end

D
Initial  
David Heinemeier Hansson 已提交
551 552 553 554
  def test_boolean_attributes
    assert ! Topic.find(1).approved?
    assert Topic.find(2).approved?
  end
J
Jeremy Kemper 已提交
555

D
Initial  
David Heinemeier Hansson 已提交
556 557
  def test_increment_counter
    Topic.increment_counter("replies_count", 1)
558
    assert_equal 2, Topic.find(1).replies_count
D
Initial  
David Heinemeier Hansson 已提交
559 560

    Topic.increment_counter("replies_count", 1)
561
    assert_equal 3, Topic.find(1).replies_count
D
Initial  
David Heinemeier Hansson 已提交
562
  end
J
Jeremy Kemper 已提交
563

D
Initial  
David Heinemeier Hansson 已提交
564 565
  def test_decrement_counter
    Topic.decrement_counter("replies_count", 2)
566
    assert_equal -1, Topic.find(2).replies_count
D
Initial  
David Heinemeier Hansson 已提交
567 568

    Topic.decrement_counter("replies_count", 2)
569
    assert_equal -2, Topic.find(2).replies_count
D
Initial  
David Heinemeier Hansson 已提交
570
  end
571

572 573 574 575
  def test_update_all
    assert_equal 2, Topic.update_all("content = 'bulk updated!'")
    assert_equal "bulk updated!", Topic.find(1).content
    assert_equal "bulk updated!", Topic.find(2).content
576

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
    assert_equal 2, Topic.update_all(['content = ?', 'bulk updated again!'])
    assert_equal "bulk updated again!", Topic.find(1).content
    assert_equal "bulk updated again!", Topic.find(2).content

    assert_equal 2, Topic.update_all(['content = ?', nil])
    assert_nil Topic.find(1).content
  end

  def test_update_all_with_hash
    assert_not_nil Topic.find(1).last_read
    assert_equal 2, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil)
    assert_equal "bulk updated with hash!", Topic.find(1).content
    assert_equal "bulk updated with hash!", Topic.find(2).content
    assert_nil Topic.find(1).last_read
    assert_nil Topic.find(2).last_read
D
Initial  
David Heinemeier Hansson 已提交
592
  end
593

594 595 596 597 598
  def test_update_all_with_non_standard_table_name
    assert_equal 1, WarehouseThing.update_all(['value = ?', 0], ['id = ?', 1])
    assert_equal 0, WarehouseThing.find(1).value
  end

599 600 601 602 603 604
  if current_adapter?(:MysqlAdapter)
    def test_update_all_with_order_and_limit
      assert_equal 1, Topic.update_all("content = 'bulk updated!'", nil, :limit => 1, :order => 'id DESC')
    end
  end

605 606 607 608 609 610 611
  def test_update_all_ignores_order_limit_from_association
    author = Author.find(1)
    assert_nothing_raised do
      assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all("body = 'bulk update!'")
    end
  end

612
  def test_update_many
613
    topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
614
    updated = Topic.update(topic_data.keys, topic_data.values)
615 616 617 618 619 620

    assert_equal 2, updated.size
    assert_equal "1 updated", Topic.find(1).content
    assert_equal "2 updated", Topic.find(2).content
  end

621 622 623 624
  def test_delete_all
    assert_equal 2, Topic.delete_all
  end

D
Initial  
David Heinemeier Hansson 已提交
625
  def test_update_by_condition
626
    Topic.update_all "content = 'bulk updated!'", ["approved = ?", true]
D
Initial  
David Heinemeier Hansson 已提交
627 628 629
    assert_equal "Have a nice day", Topic.find(1).content
    assert_equal "bulk updated!", Topic.find(2).content
  end
J
Jeremy Kemper 已提交
630

D
Initial  
David Heinemeier Hansson 已提交
631 632 633 634 635 636 637 638
  def test_attribute_present
    t = Topic.new
    t.title = "hello there!"
    t.written_on = Time.now
    assert t.attribute_present?("title")
    assert t.attribute_present?("written_on")
    assert !t.attribute_present?("content")
  end
J
Jeremy Kemper 已提交
639

D
Initial  
David Heinemeier Hansson 已提交
640 641 642
  def test_attribute_keys_on_new_instance
    t = Topic.new
    assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
643
    assert_raise(NoMethodError) { t.title2 }
D
Initial  
David Heinemeier Hansson 已提交
644
  end
J
Jeremy Kemper 已提交
645

D
Initial  
David Heinemeier Hansson 已提交
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
  def test_class_name
    assert_equal "Firm", ActiveRecord::Base.class_name("firms")
    assert_equal "Category", ActiveRecord::Base.class_name("categories")
    assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder")

    ActiveRecord::Base.pluralize_table_names = false
    assert_equal "Firms", ActiveRecord::Base.class_name( "firms" )
    ActiveRecord::Base.pluralize_table_names = true

    ActiveRecord::Base.table_name_prefix = "test_"
    assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms" )
    ActiveRecord::Base.table_name_suffix = "_tests"
    assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms_tests" )
    ActiveRecord::Base.table_name_prefix = ""
    assert_equal "Firm", ActiveRecord::Base.class_name( "firms_tests" )
    ActiveRecord::Base.table_name_suffix = ""
    assert_equal "Firm", ActiveRecord::Base.class_name( "firms" )
  end
J
Jeremy Kemper 已提交
664

D
Initial  
David Heinemeier Hansson 已提交
665 666 667 668
  def test_null_fields
    assert_nil Topic.find(1).parent_id
    assert_nil Topic.create("title" => "Hey you").parent_id
  end
J
Jeremy Kemper 已提交
669

D
Initial  
David Heinemeier Hansson 已提交
670 671
  def test_default_values
    topic = Topic.new
J
Jeremy Kemper 已提交
672
    assert topic.approved?
D
Initial  
David Heinemeier Hansson 已提交
673
    assert_nil topic.written_on
674
    assert_nil topic.bonus_time
D
Initial  
David Heinemeier Hansson 已提交
675
    assert_nil topic.last_read
J
Jeremy Kemper 已提交
676

D
Initial  
David Heinemeier Hansson 已提交
677 678 679
    topic.save

    topic = Topic.find(topic.id)
J
Jeremy Kemper 已提交
680
    assert topic.approved?
D
Initial  
David Heinemeier Hansson 已提交
681
    assert_nil topic.last_read
682

J
Jeremy Kemper 已提交
683
    # Oracle has some funky default handling, so it requires a bit of
684
    # extra testing. See ticket #2788.
685 686
    if current_adapter?(:OracleAdapter)
      test = TestOracleDefault.new
687 688 689 690
      assert_equal "X", test.test_char
      assert_equal "hello", test.test_string
      assert_equal 3, test.test_int
    end
D
Initial  
David Heinemeier Hansson 已提交
691
  end
692

693 694
  # Oracle, SQLServer, and Sybase do not have a TIME datatype.
  unless current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
695 696 697 698 699 700 701 702
    def test_utc_as_time_zone
      Topic.default_timezone = :utc
      attributes = { "bonus_time" => "5:42:00AM" }
      topic = Topic.find(1)
      topic.attributes = attributes
      assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
      Topic.default_timezone = :local
    end
703

704 705 706 707 708 709 710 711 712 713 714 715
    def test_utc_as_time_zone_and_new
      Topic.default_timezone = :utc
      attributes = { "bonus_time(1i)"=>"2000",
                     "bonus_time(2i)"=>"1",
                     "bonus_time(3i)"=>"1",
                     "bonus_time(4i)"=>"10",
                     "bonus_time(5i)"=>"35",
                     "bonus_time(6i)"=>"50" }
      topic = Topic.new(attributes)
      assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
      Topic.default_timezone = :local
    end
716 717
  end

D
Initial  
David Heinemeier Hansson 已提交
718 719 720 721 722 723 724 725 726
  def test_default_values_on_empty_strings
    topic = Topic.new
    topic.approved  = nil
    topic.last_read = nil

    topic.save

    topic = Topic.find(topic.id)
    assert_nil topic.last_read
727 728 729 730 731 732 733

    # Sybase adapter does not allow nulls in boolean columns
    if current_adapter?(:SybaseAdapter)
      assert topic.approved == false
    else
      assert_nil topic.approved
    end
D
Initial  
David Heinemeier Hansson 已提交
734
  end
735

D
Initial  
David Heinemeier Hansson 已提交
736
  def test_equality
737
    assert_equal Topic.find(1), Topic.find(2).topic
D
Initial  
David Heinemeier Hansson 已提交
738
  end
J
Jeremy Kemper 已提交
739

740 741 742
  def test_equality_of_new_records
    assert_not_equal Topic.new, Topic.new
  end
J
Jeremy Kemper 已提交
743

D
Initial  
David Heinemeier Hansson 已提交
744
  def test_hashing
745
    assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
D
Initial  
David Heinemeier Hansson 已提交
746
  end
J
Jeremy Kemper 已提交
747

D
Initial  
David Heinemeier Hansson 已提交
748 749 750 751 752
  def test_destroy_new_record
    client = Client.new
    client.destroy
    assert client.frozen?
  end
J
Jeremy Kemper 已提交
753

754 755 756 757 758
  def test_destroy_record_with_associations
    client = Client.find(3)
    client.destroy
    assert client.frozen?
    assert_kind_of Firm, client.firm
759
    assert_raises(ActiveSupport::FrozenObjectError) { client.name = "something else" }
760
  end
J
Jeremy Kemper 已提交
761

D
Initial  
David Heinemeier Hansson 已提交
762 763 764 765
  def test_update_attribute
    assert !Topic.find(1).approved?
    Topic.find(1).update_attribute("approved", true)
    assert Topic.find(1).approved?
766 767 768

    Topic.find(1).update_attribute(:approved, false)
    assert !Topic.find(1).approved?
D
Initial  
David Heinemeier Hansson 已提交
769
  end
J
Jeremy Kemper 已提交
770

771 772 773 774
  def test_update_attributes
    topic = Topic.find(1)
    assert !topic.approved?
    assert_equal "The First Topic", topic.title
J
Jeremy Kemper 已提交
775

776 777 778 779 780 781 782 783 784 785
    topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
    topic.reload
    assert topic.approved?
    assert_equal "The First Topic Updated", topic.title

    topic.update_attributes(:approved => false, :title => "The First Topic")
    topic.reload
    assert !topic.approved?
    assert_equal "The First Topic", topic.title
  end
J
Jeremy Kemper 已提交
786

787 788 789 790
  def test_update_attributes!
    reply = Reply.find(2)
    assert_equal "The Second Topic's of the day", reply.title
    assert_equal "Have a nice day", reply.content
J
Jeremy Kemper 已提交
791

792 793 794 795
    reply.update_attributes!("title" => "The Second Topic's of the day updated", "content" => "Have a nice evening")
    reply.reload
    assert_equal "The Second Topic's of the day updated", reply.title
    assert_equal "Have a nice evening", reply.content
J
Jeremy Kemper 已提交
796

797 798 799 800
    reply.update_attributes!(:title => "The Second Topic's of the day", :content => "Have a nice day")
    reply.reload
    assert_equal "The Second Topic's of the day", reply.title
    assert_equal "Have a nice day", reply.content
J
Jeremy Kemper 已提交
801

802 803
    assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(:title => nil, :content => "Have a nice evening") }
  end
J
Jeremy Kemper 已提交
804

805 806 807 808 809
  def test_mass_assignment_should_raise_exception_if_accessible_and_protected_attribute_writers_are_both_used
    topic = TopicWithProtectedContentAndAccessibleAuthorName.new
    assert_raises(RuntimeError) { topic.attributes = { "author_name" => "me" } }
    assert_raises(RuntimeError) { topic.attributes = { "content" => "stuff" } }
  end
J
Jeremy Kemper 已提交
810

D
Initial  
David Heinemeier Hansson 已提交
811 812 813 814 815
  def test_mass_assignment_protection
    firm = Firm.new
    firm.attributes = { "name" => "Next Angle", "rating" => 5 }
    assert_equal 1, firm.rating
  end
J
Jeremy Kemper 已提交
816

817 818
  def test_mass_assignment_protection_against_class_attribute_writers
    [:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names, :colorize_logging,
819
      :default_timezone, :allow_concurrency, :schema_format, :verification_timeout, :lock_optimistically, :record_timestamps].each do |method|
820 821 822 823 824 825
      assert  Task.respond_to?(method)
      assert  Task.respond_to?("#{method}=")
      assert  Task.new.respond_to?(method)
      assert !Task.new.respond_to?("#{method}=")
    end
  end
826 827 828 829 830 831 832 833 834

  def test_customized_primary_key_remains_protected
    subscriber = Subscriber.new(:nick => 'webster123', :name => 'nice try')
    assert_nil subscriber.id

    keyboard = Keyboard.new(:key_number => 9, :name => 'nice try')
    assert_nil keyboard.id
  end

835
  def test_customized_primary_key_remains_protected_when_referred_to_as_id
836 837 838 839 840 841
    subscriber = Subscriber.new(:id => 'webster123', :name => 'nice try')
    assert_nil subscriber.id

    keyboard = Keyboard.new(:id => 9, :name => 'nice try')
    assert_nil keyboard.id
  end
J
Jeremy Kemper 已提交
842

843 844 845 846 847 848
  def test_mass_assignment_protection_on_defaults
    firm = Firm.new
    firm.attributes = { "id" => 5, "type" => "Client" }
    assert_nil firm.id
    assert_equal "Firm", firm[:type]
  end
J
Jeremy Kemper 已提交
849

D
Initial  
David Heinemeier Hansson 已提交
850
  def test_mass_assignment_accessible
851
    reply = Reply.new("title" => "hello", "content" => "world", "approved" => true)
D
Initial  
David Heinemeier Hansson 已提交
852
    reply.save
J
Jeremy Kemper 已提交
853 854

    assert reply.approved?
J
Jeremy Kemper 已提交
855

J
Jeremy Kemper 已提交
856
    reply.approved = false
D
Initial  
David Heinemeier Hansson 已提交
857 858
    reply.save

J
Jeremy Kemper 已提交
859
    assert !reply.approved?
D
Initial  
David Heinemeier Hansson 已提交
860
  end
J
Jeremy Kemper 已提交
861

D
Initial  
David Heinemeier Hansson 已提交
862
  def test_mass_assignment_protection_inheritance
863
    assert_nil LoosePerson.accessible_attributes
864
    assert_equal Set.new([ 'credit_rating', 'administrator' ]), LoosePerson.protected_attributes
865 866

    assert_nil LooseDescendant.accessible_attributes
867 868 869 870
    assert_equal Set.new([ 'credit_rating', 'administrator', 'phone_number' ]), LooseDescendant.protected_attributes

    assert_nil LooseDescendantSecond.accessible_attributes
    assert_equal Set.new([ 'credit_rating', 'administrator', 'phone_number', 'name' ]), LooseDescendantSecond.protected_attributes, 'Running attr_protected twice in one class should merge the protections'
871

D
Initial  
David Heinemeier Hansson 已提交
872
    assert_nil TightPerson.protected_attributes
873
    assert_equal Set.new([ 'name', 'address' ]), TightPerson.accessible_attributes
874 875

    assert_nil TightDescendant.protected_attributes
876
    assert_equal Set.new([ 'name', 'address', 'phone_number' ]), TightDescendant.accessible_attributes
D
Initial  
David Heinemeier Hansson 已提交
877
  end
J
Jeremy Kemper 已提交
878

879
  def test_readonly_attributes
880
    assert_equal Set.new([ 'title' ]), ReadonlyTitlePost.readonly_attributes
J
Jeremy Kemper 已提交
881

882 883 884
    post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable")
    post.reload
    assert_equal "cannot change this", post.title
J
Jeremy Kemper 已提交
885

886 887 888 889 890
    post.update_attributes(:title => "try to change", :body => "changed")
    post.reload
    assert_equal "cannot change this", post.title
    assert_equal "changed", post.body
  end
D
Initial  
David Heinemeier Hansson 已提交
891 892 893 894 895

  def test_multiparameter_attributes_on_date
    attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" }
    topic = Topic.find(1)
    topic.attributes = attributes
J
Jeremy Kemper 已提交
896
    # note that extra #to_date call allows test to pass for Oracle, which
897
    # treats dates/times the same
898
    assert_date_from_db Date.new(2004, 6, 24), topic.last_read.to_date
D
Initial  
David Heinemeier Hansson 已提交
899 900 901 902 903 904
  end

  def test_multiparameter_attributes_on_date_with_empty_date
    attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "" }
    topic = Topic.find(1)
    topic.attributes = attributes
J
Jeremy Kemper 已提交
905
    # note that extra #to_date call allows test to pass for Oracle, which
906
    # treats dates/times the same
907
    assert_date_from_db Date.new(2004, 6, 1), topic.last_read.to_date
D
Initial  
David Heinemeier Hansson 已提交
908 909 910 911 912 913 914 915 916 917
  end

  def test_multiparameter_attributes_on_date_with_all_empty
    attributes = { "last_read(1i)" => "", "last_read(2i)" => "", "last_read(3i)" => "" }
    topic = Topic.find(1)
    topic.attributes = attributes
    assert_nil topic.last_read
  end

  def test_multiparameter_attributes_on_time
J
Jeremy Kemper 已提交
918 919
    attributes = {
      "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
D
Initial  
David Heinemeier Hansson 已提交
920 921 922 923 924 925 926 927
      "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
    }
    topic = Topic.find(1)
    topic.attributes = attributes
    assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
  end

  def test_multiparameter_attributes_on_time_with_empty_seconds
J
Jeremy Kemper 已提交
928 929
    attributes = {
      "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
D
Initial  
David Heinemeier Hansson 已提交
930 931 932 933 934 935 936
      "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => ""
    }
    topic = Topic.find(1)
    topic.attributes = attributes
    assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
  end

937 938
  def test_multiparameter_mass_assignment_protector
    task = Task.new
939
    time = Time.mktime(2000, 1, 1, 1)
J
Jeremy Kemper 已提交
940
    task.starting = time
941 942 943 944
    attributes = { "starting(1i)" => "2004", "starting(2i)" => "6", "starting(3i)" => "24" }
    task.attributes = attributes
    assert_equal time, task.starting
  end
J
Jeremy Kemper 已提交
945

946 947 948 949 950 951 952
  def test_multiparameter_assignment_of_aggregation
    customer = Customer.new
    address = Address.new("The Street", "The City", "The Country")
    attributes = { "address(1)" => address.street, "address(2)" => address.city, "address(3)" => address.country }
    customer.attributes = attributes
    assert_equal address, customer.address
  end
953

954
  def test_attributes_on_dummy_time
955 956
    # Oracle, SQL Server, and Sybase do not have a TIME datatype.
    return true if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
957

958 959 960 961 962 963 964 965
    attributes = {
      "bonus_time" => "5:42:00AM"
    }
    topic = Topic.find(1)
    topic.attributes = attributes
    assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
  end

D
Initial  
David Heinemeier Hansson 已提交
966 967 968 969 970 971 972 973 974 975 976
  def test_boolean
    b_false = Booleantest.create({ "value" => false })
    false_id = b_false.id
    b_true = Booleantest.create({ "value" => true })
    true_id = b_true.id

    b_false = Booleantest.find(false_id)
    assert !b_false.value?
    b_true = Booleantest.find(true_id)
    assert b_true.value?
  end
977 978

  def test_boolean_cast_from_string
D
David Heinemeier Hansson 已提交
979
    b_false = Booleantest.create({ "value" => "0" })
980
    false_id = b_false.id
D
David Heinemeier Hansson 已提交
981
    b_true = Booleantest.create({ "value" => "1" })
982 983 984 985 986
    true_id = b_true.id

    b_false = Booleantest.find(false_id)
    assert !b_false.value?
    b_true = Booleantest.find(true_id)
J
Jeremy Kemper 已提交
987
    assert b_true.value?
988
  end
J
Jeremy Kemper 已提交
989

D
Initial  
David Heinemeier Hansson 已提交
990 991
  def test_clone
    topic = Topic.find(1)
992 993
    cloned_topic = nil
    assert_nothing_raised { cloned_topic = topic.clone }
D
Initial  
David Heinemeier Hansson 已提交
994
    assert_equal topic.title, cloned_topic.title
995
    assert cloned_topic.new_record?
D
Initial  
David Heinemeier Hansson 已提交
996 997

    # test if the attributes have been cloned
J
Jeremy Kemper 已提交
998 999
    topic.title = "a"
    cloned_topic.title = "b"
D
Initial  
David Heinemeier Hansson 已提交
1000 1001 1002 1003 1004 1005
    assert_equal "a", topic.title
    assert_equal "b", cloned_topic.title

    # test if the attribute values have been cloned
    topic.title = {"a" => "b"}
    cloned_topic = topic.clone
J
Jeremy Kemper 已提交
1006
    cloned_topic.title["a"] = "c"
D
Initial  
David Heinemeier Hansson 已提交
1007
    assert_equal "b", topic.title["a"]
1008

1009 1010 1011 1012
    #test if attributes set as part of after_initialize are cloned correctly
    assert_equal topic.author_email_address, cloned_topic.author_email_address

    # test if saved clone object differs from original
1013
    cloned_topic.save
1014
    assert !cloned_topic.new_record?
1015
    assert cloned_topic.id != topic.id
D
Initial  
David Heinemeier Hansson 已提交
1016
  end
1017 1018 1019 1020 1021 1022 1023 1024 1025

  def test_clone_with_aggregate_of_same_name_as_attribute
    dev = DeveloperWithAggregate.find(1)
    assert_kind_of DeveloperSalary, dev.salary

    clone = nil
    assert_nothing_raised { clone = dev.clone }
    assert_kind_of DeveloperSalary, clone.salary
    assert_equal dev.salary.amount, clone.salary.amount
1026
    assert clone.new_record?
1027 1028 1029 1030 1031 1032 1033

    # test if the attributes have been cloned
    original_amount = clone.salary.amount
    dev.salary.amount = 1
    assert_equal original_amount, clone.salary.amount

    assert clone.save
1034
    assert !clone.new_record?
1035 1036 1037 1038 1039 1040 1041 1042 1043
    assert clone.id != dev.id
  end

  def test_clone_preserves_subtype
    clone = nil
    assert_nothing_raised { clone = Company.find(3).clone }
    assert_kind_of Client, clone
  end

D
Initial  
David Heinemeier Hansson 已提交
1044 1045 1046 1047 1048 1049 1050 1051
  def test_bignum
    company = Company.find(1)
    company.rating = 2147483647
    company.save
    company = Company.find(1)
    assert_equal 2147483647, company.rating
  end

1052
  # TODO: extend defaults tests to other databases!
1053
  if current_adapter?(:PostgreSQLAdapter)
1054
    def test_default
D
Initial  
David Heinemeier Hansson 已提交
1055
      default = Default.new
J
Jeremy Kemper 已提交
1056

D
Initial  
David Heinemeier Hansson 已提交
1057 1058 1059
      # fixed dates / times
      assert_equal Date.new(2004, 1, 1), default.fixed_date
      assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
J
Jeremy Kemper 已提交
1060

D
Initial  
David Heinemeier Hansson 已提交
1061 1062 1063 1064 1065
      # char types
      assert_equal 'Y', default.char1
      assert_equal 'a varchar field', default.char2
      assert_equal 'a text field', default.char3
    end
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082

    class Geometric < ActiveRecord::Base; end
    def test_geometric_content

      # accepted format notes:
      # ()'s aren't required
      # values can be a mix of float or integer

      g = Geometric.new(
        :a_point        => '(5.0, 6.1)',
        #:a_line         => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
        :a_line_segment => '(2.0, 3), (5.5, 7.0)',
        :a_box          => '2.0, 3, 5.5, 7.0',
        :a_path         => '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]',  # [ ] is an open path
        :a_polygon      => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))',
        :a_circle       => '<(5.3, 10.4), 2>'
      )
J
Jeremy Kemper 已提交
1083

1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
      assert g.save

      # Reload and check that we have all the geometric attributes.
      h = Geometric.find(g.id)

      assert_equal '(5,6.1)', h.a_point
      assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
      assert_equal '(5.5,7),(2,3)', h.a_box   # reordered to store upper right corner then bottom left corner
      assert_equal '[(2,3),(5.5,7),(8.5,11)]', h.a_path
      assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
      assert_equal '<(5.3,10.4),2>', h.a_circle

      # use a geometric function to test for an open path
      objs = Geometric.find_by_sql ["select isopen(a_path) from geometrics where id = ?", g.id]
      assert_equal objs[0].isopen, 't'

      # test alternate formats when defining the geometric types
J
Jeremy Kemper 已提交
1101

1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
      g = Geometric.new(
        :a_point        => '5.0, 6.1',
        #:a_line         => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
        :a_line_segment => '((2.0, 3), (5.5, 7.0))',
        :a_box          => '(2.0, 3), (5.5, 7.0)',
        :a_path         => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))',  # ( ) is a closed path
        :a_polygon      => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
        :a_circle       => '((5.3, 10.4), 2)'
      )

      assert g.save

      # Reload and check that we have all the geometric attributes.
      h = Geometric.find(g.id)
J
Jeremy Kemper 已提交
1116

1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
      assert_equal '(5,6.1)', h.a_point
      assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
      assert_equal '(5.5,7),(2,3)', h.a_box   # reordered to store upper right corner then bottom left corner
      assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
      assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
      assert_equal '<(5.3,10.4),2>', h.a_circle

      # use a geometric function to test for an closed path
      objs = Geometric.find_by_sql ["select isclosed(a_path) from geometrics where id = ?", g.id]
      assert_equal objs[0].isclosed, 't'
    end
D
Initial  
David Heinemeier Hansson 已提交
1128 1129
  end

1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
  class NumericData < ActiveRecord::Base
    self.table_name = 'numeric_data'
  end

  def test_numeric_fields
    m = NumericData.new(
      :bank_balance => 1586.43,
      :big_bank_balance => BigDecimal("1000234000567.95"),
      :world_population => 6000000000,
      :my_house_population => 3
    )
    assert m.save

    m1 = NumericData.find(m.id)
    assert_not_nil m1

    # As with migration_test.rb, we should make world_population >= 2**62
    # to cover 64-bit platforms and test it is a Bignum, but the main thing
    # is that it's an Integer.
    assert_kind_of Integer, m1.world_population
    assert_equal 6000000000, m1.world_population

    assert_kind_of Fixnum, m1.my_house_population
    assert_equal 3, m1.my_house_population

    assert_kind_of BigDecimal, m1.bank_balance
    assert_equal BigDecimal("1586.43"), m1.bank_balance

    assert_kind_of BigDecimal, m1.big_bank_balance
    assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
  end

D
Initial  
David Heinemeier Hansson 已提交
1162 1163 1164 1165 1166
  def test_auto_id
    auto = AutoId.new
    auto.save
    assert (auto.id > 0)
  end
1167

D
Initial  
David Heinemeier Hansson 已提交
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
  def quote_column_name(name)
    "<#{name}>"
  end

  def test_quote_keys
    ar = AutoId.new
    source = {"foo" => "bar", "baz" => "quux"}
    actual = ar.send(:quote_columns, self, source)
    inverted = actual.invert
    assert_equal("<foo>", inverted["bar"])
    assert_equal("<baz>", inverted["quux"])
  end

1181
  def test_sql_injection_via_find
1182
    assert_raises(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
1183 1184 1185 1186
      Topic.find("123456 OR id > 0")
    end
  end

D
Initial  
David Heinemeier Hansson 已提交
1187 1188 1189
  def test_column_name_properly_quoted
    col_record = ColumnName.new
    col_record.references = 40
1190
    assert col_record.save
D
Initial  
David Heinemeier Hansson 已提交
1191
    col_record.references = 41
1192 1193
    assert col_record.save
    assert_not_nil c2 = ColumnName.find(col_record.id)
D
Initial  
David Heinemeier Hansson 已提交
1194 1195 1196
    assert_equal(41, c2.references)
  end

1197
  def test_quoting_arrays
1198
    replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
1199 1200
    assert_equal topics(:first).replies.size, replies.size

1201
    replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
1202 1203 1204
    assert_equal 0, replies.size
  end

D
Initial  
David Heinemeier Hansson 已提交
1205
  MyObject = Struct.new :attribute1, :attribute2
J
Jeremy Kemper 已提交
1206

D
Initial  
David Heinemeier Hansson 已提交
1207 1208
  def test_serialized_attribute
    myobj = MyObject.new('value1', 'value2')
J
Jeremy Kemper 已提交
1209
    topic = Topic.create("content" => myobj)
D
Initial  
David Heinemeier Hansson 已提交
1210 1211 1212 1213
    Topic.serialize("content", MyObject)
    assert_equal(myobj, topic.content)
  end

1214
  def test_nil_serialized_attribute_with_class_constraint
D
Initial  
David Heinemeier Hansson 已提交
1215
    myobj = MyObject.new('value1', 'value2')
1216 1217 1218
    topic = Topic.new
    assert_nil topic.content
  end
D
Initial  
David Heinemeier Hansson 已提交
1219

1220 1221 1222 1223 1224
  def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
    myobj = MyObject.new('value1', 'value2')
    topic = Topic.new(:content => myobj)
    assert topic.save
    Topic.serialize(:content, Hash)
1225
    assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content }
1226 1227 1228
  ensure
    Topic.serialize(:content)
  end
D
Initial  
David Heinemeier Hansson 已提交
1229

1230
  def test_serialized_attribute_with_class_constraint
D
Initial  
David Heinemeier Hansson 已提交
1231
    settings = { "color" => "blue" }
1232 1233 1234
    Topic.serialize(:content, Hash)
    topic = Topic.new(:content => settings)
    assert topic.save
D
Initial  
David Heinemeier Hansson 已提交
1235
    assert_equal(settings, Topic.find(topic.id).content)
1236
  ensure
D
Initial  
David Heinemeier Hansson 已提交
1237 1238 1239 1240
    Topic.serialize(:content)
  end

  def test_quote
1241 1242 1243
    author_name = "\\ \001 ' \n \\n \""
    topic = Topic.create('author_name' => author_name)
    assert_equal author_name, Topic.find(topic.id).author_name
D
Initial  
David Heinemeier Hansson 已提交
1244
  end
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257

  if RUBY_VERSION < '1.9'
    def test_quote_chars
      str = 'The Narrator'
      topic = Topic.create(:author_name => str)
      assert_equal str, topic.author_name

      assert_kind_of ActiveSupport::Multibyte::Chars, str.chars
      topic = Topic.find_by_author_name(str.chars)

      assert_kind_of Topic, topic
      assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
    end
1258
  end
1259

1260 1261
  def test_class_level_destroy
    should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
1262
    Topic.find(1).replies << should_be_destroyed_reply
1263 1264

    Topic.destroy(1)
1265 1266
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
1267 1268 1269 1270
  end

  def test_class_level_delete
    should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
1271
    Topic.find(1).replies << should_be_destroyed_reply
1272 1273

    Topic.delete(1)
1274
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
1275 1276
    assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
  end
1277 1278

  def test_increment_attribute
1279 1280
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).increment! :credit_limit
J
Jeremy Kemper 已提交
1281
    assert_equal 51, accounts(:signals37, :reload).credit_limit
1282 1283 1284

    accounts(:signals37).increment(:credit_limit).increment!(:credit_limit)
    assert_equal 53, accounts(:signals37, :reload).credit_limit
1285
  end
J
Jeremy Kemper 已提交
1286

1287
  def test_increment_nil_attribute
1288 1289 1290
    assert_nil topics(:first).parent_id
    topics(:first).increment! :parent_id
    assert_equal 1, topics(:first).parent_id
1291
  end
J
Jeremy Kemper 已提交
1292

1293 1294 1295
  def test_increment_attribute_by
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).increment! :credit_limit, 5
J
Jeremy Kemper 已提交
1296
    assert_equal 55, accounts(:signals37, :reload).credit_limit
1297 1298 1299 1300

    accounts(:signals37).increment(:credit_limit, 1).increment!(:credit_limit, 3)
    assert_equal 59, accounts(:signals37, :reload).credit_limit
  end
J
Jeremy Kemper 已提交
1301

1302
  def test_decrement_attribute
1303
    assert_equal 50, accounts(:signals37).credit_limit
1304

1305 1306
    accounts(:signals37).decrement!(:credit_limit)
    assert_equal 49, accounts(:signals37, :reload).credit_limit
J
Jeremy Kemper 已提交
1307

1308 1309
    accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit)
    assert_equal 47, accounts(:signals37, :reload).credit_limit
1310
  end
J
Jeremy Kemper 已提交
1311

1312 1313 1314
  def test_decrement_attribute_by
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).decrement! :credit_limit, 5
J
Jeremy Kemper 已提交
1315
    assert_equal 45, accounts(:signals37, :reload).credit_limit
1316 1317 1318 1319

    accounts(:signals37).decrement(:credit_limit, 1).decrement!(:credit_limit, 3)
    assert_equal 41, accounts(:signals37, :reload).credit_limit
  end
J
Jeremy Kemper 已提交
1320

1321
  def test_toggle_attribute
1322 1323 1324
    assert !topics(:first).approved?
    topics(:first).toggle!(:approved)
    assert topics(:first).approved?
1325 1326 1327 1328 1329
    topic = topics(:first)
    topic.toggle(:approved)
    assert !topic.approved?
    topic.reload
    assert topic.approved?
1330
  end
1331 1332 1333 1334 1335 1336 1337 1338 1339

  def test_reload
    t1 = Topic.find(1)
    t2 = Topic.find(1)
    t1.title = "something else"
    t1.save
    t2.reload
    assert_equal t1.title, t2.title
  end
1340 1341 1342

  def test_define_attr_method_with_value
    k = Class.new( ActiveRecord::Base )
1343
    k.send(:define_attr_method, :table_name, "foo")
1344 1345 1346 1347 1348
    assert_equal "foo", k.table_name
  end

  def test_define_attr_method_with_block
    k = Class.new( ActiveRecord::Base )
1349
    k.send(:define_attr_method, :primary_key) { "sys_" + original_primary_key }
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
    assert_equal "sys_id", k.primary_key
  end

  def test_set_table_name_with_value
    k = Class.new( ActiveRecord::Base )
    k.table_name = "foo"
    assert_equal "foo", k.table_name
    k.set_table_name "bar"
    assert_equal "bar", k.table_name
  end

  def test_set_table_name_with_block
    k = Class.new( ActiveRecord::Base )
    k.set_table_name { "ks" }
    assert_equal "ks", k.table_name
  end

  def test_set_primary_key_with_value
    k = Class.new( ActiveRecord::Base )
    k.primary_key = "foo"
    assert_equal "foo", k.primary_key
    k.set_primary_key "bar"
    assert_equal "bar", k.primary_key
  end

  def test_set_primary_key_with_block
    k = Class.new( ActiveRecord::Base )
    k.set_primary_key { "sys_" + original_primary_key }
    assert_equal "sys_id", k.primary_key
  end

  def test_set_inheritance_column_with_value
    k = Class.new( ActiveRecord::Base )
    k.inheritance_column = "foo"
    assert_equal "foo", k.inheritance_column
    k.set_inheritance_column "bar"
    assert_equal "bar", k.inheritance_column
  end

  def test_set_inheritance_column_with_block
    k = Class.new( ActiveRecord::Base )
    k.set_inheritance_column { original_inheritance_column + "_id" }
    assert_equal "type_id", k.inheritance_column
  end
1394 1395

  def test_count_with_join
1396
    res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
J
Jeremy Kemper 已提交
1397

1398
    res2 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'", :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
1399
    assert_equal res, res2
J
Jeremy Kemper 已提交
1400

1401
    res3 = nil
1402 1403 1404 1405 1406
    assert_nothing_raised do
      res3 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'",
                        :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
    end
    assert_equal res, res3
J
Jeremy Kemper 已提交
1407

1408
    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"
1409 1410
    res5 = nil
    assert_nothing_raised do
1411 1412
      res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
                        :joins => "p, comments co",
1413 1414 1415
                        :select => "p.id")
    end

J
Jeremy Kemper 已提交
1416
    assert_equal res4, res5
1417

1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
    unless current_adapter?(:SQLite2Adapter, :DeprecatedSQLiteAdapter)
      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"
      res7 = nil
      assert_nothing_raised do
        res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
                          :joins => "p, comments co",
                          :select => "p.id",
                          :distinct => true)
      end
      assert_equal res6, res7
1428
    end
1429
  end
J
Jeremy Kemper 已提交
1430 1431

  def test_clear_association_cache_stored
1432 1433 1434 1435 1436 1437
    firm = Firm.find(1)
    assert_kind_of Firm, firm

    firm.clear_association_cache
    assert_equal Firm.find(1).clients.collect{ |x| x.name }.sort, firm.clients.collect{ |x| x.name }.sort
  end
J
Jeremy Kemper 已提交
1438

1439 1440 1441 1442 1443 1444
  def test_clear_association_cache_new_record
     firm            = Firm.new
     client_stored   = Client.find(3)
     client_new      = Client.new
     client_new.name = "The Joneses"
     clients         = [ client_stored, client_new ]
1445

1446
     firm.clients    << clients
1447
     assert_equal clients.map(&:name).to_set, firm.clients.map(&:name).to_set
1448 1449

     firm.clear_association_cache
1450
     assert_equal clients.map(&:name).to_set, firm.clients.map(&:name).to_set
1451
  end
1452

1453 1454 1455 1456 1457 1458
  def test_interpolate_sql
    assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo@bar') }
    assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar) baz') }
    assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar} baz') }
  end

1459
  def test_scoped_find_conditions
M
Marcel Molina 已提交
1460
    scoped_developers = Developer.with_scope(:find => { :conditions => 'salary > 90000' }) do
1461 1462
      Developer.find(:all, :conditions => 'id < 5')
    end
M
Marcel Molina 已提交
1463 1464
    assert !scoped_developers.include?(developers(:david)) # David's salary is less than 90,000
    assert_equal 3, scoped_developers.size
1465
  end
J
Jeremy Kemper 已提交
1466

1467
  def test_scoped_find_limit_offset
M
Marcel Molina 已提交
1468
    scoped_developers = Developer.with_scope(:find => { :limit => 3, :offset => 2 }) do
1469
      Developer.find(:all, :order => 'id')
J
Jeremy Kemper 已提交
1470
    end
M
Marcel Molina 已提交
1471 1472 1473
    assert !scoped_developers.include?(developers(:david))
    assert !scoped_developers.include?(developers(:jamis))
    assert_equal 3, scoped_developers.size
J
Jeremy Kemper 已提交
1474

1475
    # Test without scoped find conditions to ensure we get the whole thing
1476
    developers = Developer.find(:all, :order => 'id')
M
Marcel Molina 已提交
1477
    assert_equal Developer.count, developers.size
1478
  end
1479

J
Jeremy Kemper 已提交
1480 1481
  def test_scoped_find_order
    # Test order in scope
1482 1483
    scoped_developers = Developer.with_scope(:find => { :limit => 1, :order => 'salary DESC' }) do
      Developer.find(:all)
J
Jeremy Kemper 已提交
1484
    end
1485 1486 1487 1488 1489
    assert_equal 'Jamis', scoped_developers.first.name
    assert scoped_developers.include?(developers(:jamis))
    # Test scope without order and order in find
    scoped_developers = Developer.with_scope(:find => { :limit => 1 }) do
      Developer.find(:all, :order => 'salary DESC')
J
Jeremy Kemper 已提交
1490
    end
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502
    # Test scope order + find order, find has priority
    scoped_developers = Developer.with_scope(:find => { :limit => 3, :order => 'id DESC' }) do
      Developer.find(:all, :order => 'salary ASC')
    end
    assert scoped_developers.include?(developers(:poor_jamis))
    assert scoped_developers.include?(developers(:david))
    assert scoped_developers.include?(developers(:dev_10))
    # Test without scoped find conditions to ensure we get the right thing
    developers = Developer.find(:all, :order => 'id', :limit => 1)
    assert scoped_developers.include?(developers(:david))
  end

1503 1504 1505 1506 1507 1508 1509 1510
  def test_scoped_find_limit_offset_including_has_many_association
    topics = Topic.with_scope(:find => {:limit => 1, :offset => 1, :include => :replies}) do
      Topic.find(:all, :order => "topics.id")
    end
    assert_equal 1, topics.size
    assert_equal 2, topics.first.id
  end

1511 1512 1513 1514 1515 1516 1517 1518 1519 1520
  def test_scoped_find_order_including_has_many_association
    developers = Developer.with_scope(:find => { :order => 'developers.salary DESC', :include => :projects }) do
      Developer.find(:all)
    end
    assert developers.size >= 2
    for i in 1...developers.size
      assert developers[i-1].salary >= developers[i].salary
    end
  end

1521
  def test_abstract_class
1522
    assert !ActiveRecord::Base.abstract_class?
1523 1524
    assert LoosePerson.abstract_class?
    assert !LooseDescendant.abstract_class?
1525 1526 1527
  end

  def test_base_class
1528 1529 1530 1531
    assert_equal LoosePerson,     LoosePerson.base_class
    assert_equal LooseDescendant, LooseDescendant.base_class
    assert_equal TightPerson,     TightPerson.base_class
    assert_equal TightPerson,     TightDescendant.base_class
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564

    assert_equal Post, Post.base_class
    assert_equal Post, SpecialPost.base_class
    assert_equal Post, StiPost.base_class
    assert_equal SubStiPost, SubStiPost.base_class
  end

  def test_descends_from_active_record
    # Tries to call Object.abstract_class?
    assert_raise(NoMethodError) do
      ActiveRecord::Base.descends_from_active_record?
    end

    # Abstract subclass of AR::Base.
    assert LoosePerson.descends_from_active_record?

    # Concrete subclass of an abstract class.
    assert LooseDescendant.descends_from_active_record?

    # Concrete subclass of AR::Base.
    assert TightPerson.descends_from_active_record?

    # Concrete subclass of a concrete class but has no type column.
    assert TightDescendant.descends_from_active_record?

    # Concrete subclass of AR::Base.
    assert Post.descends_from_active_record?

    # Abstract subclass of a concrete class which has a type column.
    # This is pathological, as you'll never have Sub < Abstract < Concrete.
    assert !StiPost.descends_from_active_record?

    # Concrete subclasses an abstract class which has a type column.
1565
    assert !SubStiPost.descends_from_active_record?
1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
  end

  def test_find_on_abstract_base_class_doesnt_use_type_condition
    old_class = LooseDescendant
    Object.send :remove_const, :LooseDescendant

    descendant = old_class.create!
    assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
  ensure
    unless Object.const_defined?(:LooseDescendant)
      Object.const_set :LooseDescendant, old_class
    end
1578 1579
  end

1580 1581 1582 1583 1584 1585 1586
  def test_assert_queries
    query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
    assert_queries(2) { 2.times { query.call } }
    assert_queries 1, &query
    assert_no_queries { assert true }
  end

1587
  def test_to_xml
1588
    xml = REXML::Document.new(topics(:first).to_xml(:indent => 0))
1589 1590
    bonus_time_in_current_timezone = topics(:first).bonus_time.xmlschema
    written_on_in_current_timezone = topics(:first).written_on.xmlschema
1591
    last_read_in_current_timezone = topics(:first).last_read.xmlschema
1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614

    assert_equal "topic", xml.root.name
    assert_equal "The First Topic" , xml.elements["//title"].text
    assert_equal "David" , xml.elements["//author-name"].text

    assert_equal "1", xml.elements["//id"].text
    assert_equal "integer" , xml.elements["//id"].attributes['type']

    assert_equal "1", xml.elements["//replies-count"].text
    assert_equal "integer" , xml.elements["//replies-count"].attributes['type']

    assert_equal written_on_in_current_timezone, xml.elements["//written-on"].text
    assert_equal "datetime" , xml.elements["//written-on"].attributes['type']

    assert_equal "--- Have a nice day\n" , xml.elements["//content"].text
    assert_equal "yaml" , xml.elements["//content"].attributes['type']

    assert_equal "david@loudthinking.com", xml.elements["//author-email-address"].text

    assert_equal nil, xml.elements["//parent-id"].text
    assert_equal "integer", xml.elements["//parent-id"].attributes['type']
    assert_equal "true", xml.elements["//parent-id"].attributes['nil']

1615
    if current_adapter?(:SybaseAdapter, :SQLServerAdapter, :OracleAdapter)
1616 1617
      assert_equal last_read_in_current_timezone, xml.elements["//last-read"].text
      assert_equal "datetime" , xml.elements["//last-read"].attributes['type']
1618
    else
1619 1620
      assert_equal "2004-04-15", xml.elements["//last-read"].text
      assert_equal "date" , xml.elements["//last-read"].attributes['type']
1621
    end
1622

1623
    # Oracle and DB2 don't have true boolean or time-only fields
1624
    unless current_adapter?(:OracleAdapter, :DB2Adapter)
1625 1626 1627 1628 1629
      assert_equal "false", xml.elements["//approved"].text
      assert_equal "boolean" , xml.elements["//approved"].attributes['type']

      assert_equal bonus_time_in_current_timezone, xml.elements["//bonus-time"].text
      assert_equal "datetime" , xml.elements["//bonus-time"].attributes['type']
1630
    end
1631
  end
1632

1633
  def test_to_xml_skipping_attributes
1634
    xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :replies_count])
1635
    assert_equal "<topic>", xml.first(7)
1636
    assert !xml.include?(%(<title>The First Topic</title>))
J
Jeremy Kemper 已提交
1637
    assert xml.include?(%(<author-name>David</author-name>))
1638

1639
    xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :author_name, :replies_count])
1640
    assert !xml.include?(%(<title>The First Topic</title>))
J
Jeremy Kemper 已提交
1641
    assert !xml.include?(%(<author-name>David</author-name>))
1642
  end
1643

1644
  def test_to_xml_including_has_many_association
1645
    xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies, :except => :replies_count)
1646
    assert_equal "<topic>", xml.first(7)
1647
    assert xml.include?(%(<replies type="array"><reply>))
1648
    assert xml.include?(%(<title>The Second Topic's of the day</title>))
1649
  end
1650 1651 1652

  def test_array_to_xml_including_has_many_association
    xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :include => :replies)
1653
    assert xml.include?(%(<replies type="array"><reply>))
1654
  end
1655 1656 1657

  def test_array_to_xml_including_methods
    xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :methods => [ :topic_id ])
1658 1659
    assert xml.include?(%(<topic-id type="integer">#{topics(:first).topic_id}</topic-id>)), xml
    assert xml.include?(%(<topic-id type="integer">#{topics(:second).topic_id}</topic-id>)), xml
1660
  end
J
Jeremy Kemper 已提交
1661

1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673
  def test_array_to_xml_including_has_one_association
    xml = [ companies(:first_firm), companies(:rails_core) ].to_xml(:indent => 0, :skip_instruct => true, :include => :account)
    assert xml.include?(companies(:first_firm).account.to_xml(:indent => 0, :skip_instruct => true))
    assert xml.include?(companies(:rails_core).account.to_xml(:indent => 0, :skip_instruct => true))
  end

  def test_array_to_xml_including_belongs_to_association
    xml = [ companies(:first_client), companies(:second_client), companies(:another_client) ].to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
    assert xml.include?(companies(:first_client).to_xml(:indent => 0, :skip_instruct => true))
    assert xml.include?(companies(:second_client).firm.to_xml(:indent => 0, :skip_instruct => true))
    assert xml.include?(companies(:another_client).firm.to_xml(:indent => 0, :skip_instruct => true))
  end
1674 1675 1676 1677 1678 1679 1680 1681

  def test_to_xml_including_belongs_to_association
    xml = companies(:first_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
    assert !xml.include?("<firm>")

    xml = companies(:second_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
    assert xml.include?("<firm>")
  end
J
Jeremy Kemper 已提交
1682

1683 1684 1685 1686
  def test_to_xml_including_multiple_associations
    xml = companies(:first_firm).to_xml(:indent => 0, :skip_instruct => true, :include => [ :clients, :account ])
    assert_equal "<firm>", xml.first(6)
    assert xml.include?(%(<account>))
1687
    assert xml.include?(%(<clients type="array"><client>))
1688
  end
1689 1690 1691

  def test_to_xml_including_multiple_associations_with_options
    xml = companies(:first_firm).to_xml(
J
Jeremy Kemper 已提交
1692
      :indent  => 0, :skip_instruct => true,
1693 1694
      :include => { :clients => { :only => :name } }
    )
J
Jeremy Kemper 已提交
1695

1696
    assert_equal "<firm>", xml.first(6)
1697
    assert xml.include?(%(<client><name>Summit</name></client>))
1698
    assert xml.include?(%(<clients type="array"><client>))
1699
  end
J
Jeremy Kemper 已提交
1700

1701 1702 1703 1704 1705
  def test_to_xml_including_methods
    xml = Company.new.to_xml(:methods => :arbitrary_method, :skip_instruct => true)
    assert_equal "<company>", xml.first(9)
    assert xml.include?(%(<arbitrary-method>I am Jack's profound disappointment</arbitrary-method>))
  end
J
Jeremy Kemper 已提交
1706

1707 1708 1709 1710 1711 1712 1713 1714
  def test_to_xml_with_block
    value = "Rockin' the block"
    xml = Company.new.to_xml(:skip_instruct => true) do |xml|
      xml.tag! "arbitrary-element", value
    end
    assert_equal "<company>", xml.first(9)
    assert xml.include?(%(<arbitrary-element>#{value}</arbitrary-element>))
  end
J
Jeremy Kemper 已提交
1715

1716 1717
  def test_except_attributes
    assert_equal(
1718 1719
      %w( author_name type id approved replies_count bonus_time written_on content author_email_address parent_id last_read).sort,
      topics(:first).attributes(:except => :title).keys.sort
1720 1721 1722
    )

    assert_equal(
1723 1724
      %w( replies_count bonus_time written_on content author_email_address parent_id last_read).sort,
      topics(:first).attributes(:except => [ :title, :id, :type, :approved, :author_name ]).keys.sort
1725 1726
    )
  end
J
Jeremy Kemper 已提交
1727

1728 1729
  def test_include_attributes
    assert_equal(%w( title ), topics(:first).attributes(:only => :title).keys)
1730
    assert_equal(%w( title author_name type id approved ).sort, topics(:first).attributes(:only => [ :title, :id, :type, :approved, :author_name ]).keys.sort)
1731
  end
J
Jeremy Kemper 已提交
1732

1733 1734 1735 1736
  def test_type_name_with_module_should_handle_beginning
    assert_equal 'ActiveRecord::Person', ActiveRecord::Base.send(:type_name_with_module, 'Person')
    assert_equal '::Person', ActiveRecord::Base.send(:type_name_with_module, '::Person')
  end
J
Jeremy Kemper 已提交
1737

1738 1739 1740
  def test_to_param_should_return_string
    assert_kind_of String, Client.find(:first).to_param
  end
J
Jeremy Kemper 已提交
1741

1742 1743 1744 1745 1746 1747 1748
  def test_inspect_class
    assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect
    assert_equal 'LoosePerson(abstract)', LoosePerson.inspect
    assert_match(/^Topic\(id: integer, title: string/, Topic.inspect)
  end

  def test_inspect_instance
1749
    topic = topics(:first)
1750
    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
1751
  end
1752

1753
  def test_inspect_new_instance
1754 1755 1756
    assert_match /Topic id: nil/, Topic.new.inspect
  end

1757 1758 1759 1760
  def test_inspect_limited_select_instance
    assert_equal %(#<Topic id: 1>), Topic.find(:first, :select => 'id', :conditions => 'id = 1').inspect
    assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.find(:first, :select => 'id, title', :conditions => 'id = 1').inspect
  end
J
Jeremy Kemper 已提交
1761

1762 1763 1764
  def test_inspect_class_without_table
    assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect
  end
1765

1766 1767
  def test_attribute_for_inspect
    t = topics(:first)
1768
    t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
1769 1770

    assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
1771
    assert_equal '"The First Topic Now Has A Title With\nNewlines And M..."', t.attribute_for_inspect(:title)
1772
  end
J
Jeremy Kemper 已提交
1773

1774 1775 1776 1777
  def test_becomes
    assert_kind_of Reply, topics(:first).becomes(Reply)
    assert_equal "The First Topic", topics(:first).becomes(Reply).title
  end
1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830

  def test_silence_sets_log_level_to_error_in_block
    original_logger = ActiveRecord::Base.logger
    log = StringIO.new
    ActiveRecord::Base.logger = Logger.new(log)
    ActiveRecord::Base.logger.level = Logger::DEBUG
    ActiveRecord::Base.silence do
      ActiveRecord::Base.logger.warn "warn"
      ActiveRecord::Base.logger.error "error"
    end
    assert_equal "error\n", log.string
  ensure
    ActiveRecord::Base.logger = original_logger
  end

  def test_silence_sets_log_level_back_to_level_before_yield
    original_logger = ActiveRecord::Base.logger
    log = StringIO.new
    ActiveRecord::Base.logger = Logger.new(log)
    ActiveRecord::Base.logger.level = Logger::WARN
    ActiveRecord::Base.silence do
    end
    assert_equal Logger::WARN, ActiveRecord::Base.logger.level
  ensure
    ActiveRecord::Base.logger = original_logger
  end

  def test_benchmark_with_log_level
    original_logger = ActiveRecord::Base.logger
    log = StringIO.new
    ActiveRecord::Base.logger = Logger.new(log)
    ActiveRecord::Base.logger.level = Logger::WARN
    ActiveRecord::Base.benchmark("Debug Topic Count", Logger::DEBUG) { Topic.count }
    ActiveRecord::Base.benchmark("Warn Topic Count",  Logger::WARN)  { Topic.count }
    ActiveRecord::Base.benchmark("Error Topic Count", Logger::ERROR) { Topic.count }
    assert_no_match /Debug Topic Count/, log.string
    assert_match /Warn Topic Count/, log.string
    assert_match /Error Topic Count/, log.string
  ensure
    ActiveRecord::Base.logger = original_logger
  end

  def test_benchmark_with_use_silence
    original_logger = ActiveRecord::Base.logger
    log = StringIO.new
    ActiveRecord::Base.logger = Logger.new(log)
    ActiveRecord::Base.benchmark("Logging", Logger::DEBUG, true) { ActiveRecord::Base.logger.debug "Loud" }
    ActiveRecord::Base.benchmark("Logging", Logger::DEBUG, false)  { ActiveRecord::Base.logger.debug "Quiet" }
    assert_no_match /Loud/, log.string
    assert_match /Quiet/, log.string
  ensure
    ActiveRecord::Base.logger = original_logger
  end
1831
end