persistence_test.rb 19.5 KB
Newer Older
1 2
require "cases/helper"
require 'models/post'
3
require 'models/comment'
4 5 6 7 8 9 10 11 12 13
require 'models/author'
require 'models/topic'
require 'models/reply'
require 'models/category'
require 'models/company'
require 'models/developer'
require 'models/project'
require 'models/minimalistic'
require 'models/warehouse_thing'
require 'models/parrot'
14
require 'models/minivan'
15
require 'models/person'
16 17 18 19 20
require 'rexml/document'
require 'active_support/core_ext/exception'

class PersistencesTest < ActiveRecord::TestCase

21
  fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts, :minivans
22

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
  # Oracle UPDATE does not support ORDER BY
  unless current_adapter?(:OracleAdapter)
    def test_update_all_ignores_order_without_limit_from_association
      author = authors(:david)
      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

    def test_update_all_with_order_and_limit_updates_subset_only
      author = authors(:david)
      assert_nothing_raised do
        assert_equal 1, author.posts_sorted_by_id_limited.size
        assert_equal 2, author.posts_sorted_by_id_limited.find(:all, :limit => 2).size
        assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ])
        assert_equal "bulk update!", posts(:welcome).body
        assert_not_equal "bulk update!", posts(:thinking).body
      end
    end
  end

  def test_update_many
    topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
    updated = Topic.update(topic_data.keys, topic_data.values)

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

  def test_delete_all
    assert Topic.count > 0

    assert_equal Topic.count, Topic.delete_all
  end

  def test_update_by_condition
    Topic.update_all "content = 'bulk updated!'", ["approved = ?", true]
    assert_equal "Have a nice day", Topic.find(1).content
    assert_equal "bulk updated!", Topic.find(2).content
  end

  def test_increment_attribute
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).increment! :credit_limit
    assert_equal 51, accounts(:signals37, :reload).credit_limit

    accounts(:signals37).increment(:credit_limit).increment!(:credit_limit)
    assert_equal 53, accounts(:signals37, :reload).credit_limit
  end

  def test_increment_nil_attribute
    assert_nil topics(:first).parent_id
    topics(:first).increment! :parent_id
    assert_equal 1, topics(:first).parent_id
  end

  def test_increment_attribute_by
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).increment! :credit_limit, 5
    assert_equal 55, accounts(:signals37, :reload).credit_limit

    accounts(:signals37).increment(:credit_limit, 1).increment!(:credit_limit, 3)
    assert_equal 59, accounts(:signals37, :reload).credit_limit
  end

  def test_destroy_all
    conditions = "author_name = 'Mary'"
    topics_by_mary = Topic.all(:conditions => conditions, :order => 'id')
    assert ! topics_by_mary.empty?

    assert_difference('Topic.count', -topics_by_mary.size) do
      destroyed = Topic.destroy_all(conditions).sort_by(&:id)
      assert_equal topics_by_mary, destroyed
      assert destroyed.all? { |topic| topic.frozen? }, "destroyed topics should be frozen"
    end
  end

  def test_destroy_many
    clients = Client.find([2, 3], :order => 'id')

    assert_difference('Client.count', -2) do
      destroyed = Client.destroy([2, 3]).sort_by(&:id)
      assert_equal clients, destroyed
      assert destroyed.all? { |client| client.frozen? }, "destroyed clients should be frozen"
    end
  end

  def test_delete_many
    original_count = Topic.count
    Topic.delete(deleting = [1, 2])
    assert_equal original_count - deleting.size, Topic.count
  end

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

    accounts(:signals37).decrement!(:credit_limit)
    assert_equal 49, accounts(:signals37, :reload).credit_limit

    accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit)
    assert_equal 47, accounts(:signals37, :reload).credit_limit
  end

  def test_decrement_attribute_by
    assert_equal 50, accounts(:signals37).credit_limit
    accounts(:signals37).decrement! :credit_limit, 5
    assert_equal 45, accounts(:signals37, :reload).credit_limit

    accounts(:signals37).decrement(:credit_limit, 1).decrement!(:credit_limit, 3)
    assert_equal 41, accounts(:signals37, :reload).credit_limit
  end

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
  def test_create
    topic = Topic.new
    topic.title = "New Topic"
    topic.save
    topic_reloaded = Topic.find(topic.id)
    assert_equal("New Topic", topic_reloaded.title)
  end

  def test_save!
    topic = Topic.new(:title => "New Topic")
    assert topic.save!

    reply = WrongReply.new
    assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
  end

  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)
  end

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

  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

  def test_create_many
    topics = Topic.create([ { "title" => "first" }, { "title" => "second" }])
    assert_equal 2, topics.size
    assert_equal "first", topics.first.title
  end

  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

  def test_create_through_factory_with_block
    topic = Topic.create("title" => "New Topic") do |t|
      t.author_name = "David"
    end
    assert_equal("New Topic", topic.title)
    assert_equal("David", topic.author_name)
  end

  def test_create_many_through_factory_with_block
    topics = Topic.create([ { "title" => "first" }, { "title" => "second" }]) do |t|
      t.author_name = "David"
    end
    assert_equal 2, topics.size
    topic1, topic2 = Topic.find(topics[0].id), Topic.find(topics[1].id)
    assert_equal "first", topic1.title
    assert_equal "David", topic1.author_name
    assert_equal "second", topic2.title
    assert_equal "David", topic2.author_name
  end

  def test_update
    topic = Topic.new
    topic.title = "Another New Topic"
    topic.written_on = "2003-12-12 23:23:00"
    topic.save
    topicReloaded = Topic.find(topic.id)
    assert_equal("Another New Topic", topicReloaded.title)

    topicReloaded.title = "Updated topic"
    topicReloaded.save

    topicReloadedAgain = Topic.find(topic.id)

    assert_equal("Updated topic", topicReloadedAgain.title)
  end

  def test_update_columns_not_equal_attributes
    topic = Topic.new
    topic.title = "Still another topic"
    topic.save

    topicReloaded = Topic.find(topic.id)
    topicReloaded.title = "A New Topic"
    topicReloaded.send :write_attribute, 'does_not_exist', 'test'
    assert_nothing_raised { topicReloaded.save }
  end

  def test_update_for_record_with_only_primary_key
    minimalistic = minimalistics(:first)
    assert_nothing_raised { minimalistic.save }
  end

243 244 245 246 247 248 249 250 251
  def test_update_sti_type
    assert_instance_of Reply, topics(:second)

    topic = topics(:second).becomes(Topic)
    assert_instance_of Topic, topic
    topic.save!
    assert_instance_of Topic, Topic.find(topic.id)
  end

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
  def test_delete
    topic = Topic.find(1)
    assert_equal topic, topic.delete, 'topic.delete did not return self'
    assert topic.frozen?, 'topic not frozen after delete'
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
  end

  def test_delete_doesnt_run_callbacks
    Topic.find(1).delete
    assert_not_nil Topic.find(2)
  end

  def test_destroy
    topic = Topic.find(1)
    assert_equal topic, topic.destroy, 'topic.destroy did not return self'
    assert topic.frozen?, 'topic not frozen after destroy'
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
  end

  def test_record_not_found_exception
A
Aaron Patterson 已提交
272
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(99999) }
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
  end

  def test_update_all
    assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
    assert_equal "bulk updated!", Topic.find(1).content
    assert_equal "bulk updated!", Topic.find(2).content

    assert_equal Topic.count, 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 Topic.count, 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 Topic.count, 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
  end

  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

  def test_delete_new_record
    client = Client.new
    client.delete
    assert client.frozen?
  end

  def test_delete_record_with_associations
    client = Client.find(3)
    client.delete
    assert client.frozen?
    assert_kind_of Firm, client.firm
    assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
  end

  def test_destroy_new_record
    client = Client.new
    client.destroy
    assert client.frozen?
  end

  def test_destroy_record_with_associations
    client = Client.find(3)
    client.destroy
    assert client.frozen?
    assert_kind_of Firm, client.firm
    assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
  end

330 331 332 333
  def test_update_attribute
    assert !Topic.find(1).approved?
    Topic.find(1).update_attribute("approved", true)
    assert Topic.find(1).approved?
334

335 336
    Topic.find(1).update_attribute(:approved, false)
    assert !Topic.find(1).approved?
337 338
  end

339
  def test_update_attribute_for_readonly_attribute
340
    minivan = Minivan.find('m1')
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
    assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
  end

  # This test is correct, but it is hard to fix it since
  # update_attribute trigger simply call save! that triggers
  # all callbacks.
  # def test_update_attribute_with_one_changed_and_one_updated
  #   t = Topic.order('id').limit(1).first
  #   title, author_name = t.title, t.author_name
  #   t.author_name = 'John'
  #   t.update_attribute(:title, 'super_title')
  #   assert_equal 'John', t.author_name
  #   assert_equal 'super_title', t.title
  #   assert t.changed?, "topic should have changed"
  #   assert t.author_name_changed?, "author_name should have changed"
  #   assert !t.title_changed?, "title should not have changed"
  #   assert_nil t.title_change, 'title change should be nil'
  #   assert_equal ['author_name'], t.changed
  #
  #   t.reload
  #   assert_equal 'David', t.author_name
  #   assert_equal 'super_title', t.title
  # end

  def test_update_attribute_with_one_updated
    t = Topic.first
    title = t.title
    t.update_attribute(:title, 'super_title')
    assert_equal 'super_title', t.title
    assert !t.changed?, "topic should not have changed"
    assert !t.title_changed?, "title should not have changed"
    assert_nil t.title_change, 'title change should be nil'
373

374 375
    t.reload
    assert_equal 'super_title', t.title
376 377
  end

378
  def test_update_attribute_for_updated_at_on
379
    developer = Developer.find(1)
380
    prev_month = Time.now.prev_month
381

382
    developer.update_attribute(:updated_at, prev_month)
383
    assert_equal prev_month, developer.updated_at
384

385 386
    developer.update_attribute(:salary, 80001)
    assert_not_equal prev_month, developer.updated_at
387

388
    developer.reload
389
    assert_not_equal prev_month, developer.updated_at
390 391
  end

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
  def test_update_column
    topic = Topic.find(1)
    topic.update_column("approved", true)
    assert topic.approved?
    topic.reload
    assert topic.approved?

    topic.update_column(:approved, false)
    assert !topic.approved?
    topic.reload
    assert !topic.approved?
  end

  def test_update_column_should_not_use_setter_method
    dev = Developer.find(1)
    dev.instance_eval { def salary=(value); write_attribute(:salary, value * 2); end }

    dev.update_column(:salary, 80000)
    assert_equal 80000, dev.salary

    dev.reload
    assert_equal 80000, dev.salary
  end

  def test_update_column_should_raise_exception_if_new_record
    topic = Topic.new
    assert_raises(ActiveRecord::ActiveRecordError) { topic.update_column("approved", false) }
  end

  def test_update_column_should_not_leave_the_object_dirty
    topic = Topic.find(1)
    topic.update_attribute("content", "Have a nice day")

    topic.reload
    topic.update_column(:content, "You too")
    assert_equal [], topic.changed

    topic.reload
    topic.update_column("content", "Have a nice day")
    assert_equal [], topic.changed
  end

  def test_update_column_with_model_having_primary_key_other_than_id
    minivan = Minivan.find('m1')
    new_name = 'sebavan'

    minivan.update_column(:name, new_name)
    assert_equal new_name, minivan.name
  end

  def test_update_column_for_readonly_attribute
    minivan = Minivan.find('m1')
    prev_color = minivan.color
    assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_column(:color, 'black') }
    assert_equal prev_color, minivan.color
  end

  def test_update_column_should_not_modify_updated_at
    developer = Developer.find(1)
    prev_month = Time.now.prev_month

    developer.update_column(:updated_at, prev_month)
    assert_equal prev_month, developer.updated_at

    developer.update_column(:salary, 80001)
    assert_equal prev_month, developer.updated_at

    developer.reload
460
    assert_equal prev_month.to_i, developer.updated_at.to_i
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
  end

  def test_update_column_with_one_changed_and_one_updated
    t = Topic.order('id').limit(1).first
    title, author_name = t.title, t.author_name
    t.author_name = 'John'
    t.update_column(:title, 'super_title')
    assert_equal 'John', t.author_name
    assert_equal 'super_title', t.title
    assert t.changed?, "topic should have changed"
    assert t.author_name_changed?, "author_name should have changed"

    t.reload
    assert_equal author_name, t.author_name
    assert_equal 'super_title', t.title
  end

478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
  def test_update_attributes
    topic = Topic.find(1)
    assert !topic.approved?
    assert_equal "The First Topic", topic.title

    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

494
  def test_update_attributes_as_admin
495
    person = TightPerson.create({ "first_name" => 'Joshua' })
496
    person.update_attributes({ "first_name" => 'Josh', "gender" => 'm', "comments" => 'from NZ' }, :as => :admin)
497 498
    person.reload

499 500
    assert_equal 'Josh',    person.first_name
    assert_equal 'm',       person.gender
501 502 503
    assert_equal 'from NZ', person.comments
  end

504 505
  def test_update_attributes_without_protection
    person = TightPerson.create({ "first_name" => 'Joshua' })
506
    person.update_attributes({ "first_name" => 'Josh', "gender" => 'm', "comments" => 'from NZ' }, :without_protection => true)
507 508
    person.reload

509 510
    assert_equal 'Josh',    person.first_name
    assert_equal 'm',       person.gender
511 512 513
    assert_equal 'from NZ', person.comments
  end

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
  def test_update_attributes!
    Reply.validates_presence_of(:title)
    reply = Reply.find(2)
    assert_equal "The Second Topic of the day", reply.title
    assert_equal "Have a nice day", reply.content

    reply.update_attributes!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
    reply.reload
    assert_equal "The Second Topic of the day updated", reply.title
    assert_equal "Have a nice evening", reply.content

    reply.update_attributes!(:title => "The Second Topic of the day", :content => "Have a nice day")
    reply.reload
    assert_equal "The Second Topic of the day", reply.title
    assert_equal "Have a nice day", reply.content

    assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(:title => nil, :content => "Have a nice evening") }
  ensure
    Reply.reset_callbacks(:validate)
  end

535 536
  def test_update_attributes_with_bang_as_admin
    person = TightPerson.create({ "first_name" => 'Joshua' })
537
    person.update_attributes!({ "first_name" => 'Josh', "gender" => 'm', "comments" => 'from NZ' }, :as => :admin)
538 539 540
    person.reload

    assert_equal 'Josh', person.first_name
541
    assert_equal 'm',    person.gender
542 543 544
    assert_equal 'from NZ', person.comments
  end

545 546
  def test_update_attributestes_with_bang_without_protection
    person = TightPerson.create({ "first_name" => 'Joshua' })
547
    person.update_attributes!({ "first_name" => 'Josh', "gender" => 'm', "comments" => 'from NZ' }, :without_protection => true)
548 549 550
    person.reload

    assert_equal 'Josh', person.first_name
551
    assert_equal 'm',    person.gender
552 553 554
    assert_equal 'from NZ', person.comments
  end

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
  def test_destroyed_returns_boolean
    developer = Developer.first
    assert_equal false, developer.destroyed?
    developer.destroy
    assert_equal true, developer.destroyed?

    developer = Developer.last
    assert_equal false, developer.destroyed?
    developer.delete
    assert_equal true, developer.destroyed?
  end

  def test_persisted_returns_boolean
    developer = Developer.new(:name => "Jose")
    assert_equal false, developer.persisted?
    developer.save!
    assert_equal true, developer.persisted?

    developer = Developer.first
    assert_equal true, developer.persisted?
    developer.destroy
    assert_equal false, developer.persisted?

    developer = Developer.last
    assert_equal true, developer.persisted?
    developer.delete
    assert_equal false, developer.persisted?
  end

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

    Topic.destroy(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
  end

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

    Topic.delete(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
    assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
  end

  def test_create_with_custom_timestamps
    custom_datetime = 1.hour.ago.beginning_of_day

    %w(created_at created_on updated_at updated_on).each do |attribute|
      parrot = LiveParrot.create(:name => "colombian", attribute => custom_datetime)
      assert_equal custom_datetime, parrot[attribute]
    end
  end

end