base_test.rb 38.1 KB
Newer Older
1
require 'abstract_unit'
2
require "fixtures/person"
3
require "fixtures/customer"
4
require "fixtures/street_address"
5
require "fixtures/sound"
6
require "fixtures/beast"
M
Marshall Huss 已提交
7
require "fixtures/proxy"
8 9
require "fixtures/address"
require "fixtures/subscription_plan"
10
require 'active_support/json'
J
Jeremy Kemper 已提交
11
require 'active_support/core_ext/hash/conversions'
12
require 'mocha'
13

14
class BaseTest < ActiveSupport::TestCase
15
  def setup
16
    setup_response # find me in abstract_unit
Y
Yehuda Katz 已提交
17
    @original_person_site = Person.site
18 19
  end

Y
Yehuda Katz 已提交
20 21 22 23
  def teardown
    Person.site = @original_person_site
  end

24 25 26
  ########################################################################
  # Tests relating to setting up the API-connection configuration
  ########################################################################
J
Jeremy Kemper 已提交
27 28 29 30 31 32 33 34 35 36 37

  def test_site_accessor_accepts_uri_or_string_argument
    site = URI.parse('http://localhost')

    assert_nothing_raised { Person.site = 'http://localhost' }
    assert_equal site, Person.site

    assert_nothing_raised { Person.site = site }
    assert_equal site, Person.site
  end

38 39 40 41
  def test_should_use_site_prefix_and_credentials
    assert_equal 'http://foo:bar@beast.caboo.se', Forum.site.to_s
    assert_equal 'http://foo:bar@beast.caboo.se/forums/:forum_id', Topic.site.to_s
  end
42

43
  def test_site_variable_can_be_reset
44
    actor = Class.new(ActiveResource::Base)
45 46 47
    assert_nil actor.site
    actor.site = 'http://localhost:31337'
    actor.site = nil
48
    assert_nil actor.site
49
  end
50

M
Marshall Huss 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
  def test_proxy_accessor_accepts_uri_or_string_argument
    proxy = URI.parse('http://localhost')

    assert_nothing_raised { Person.proxy = 'http://localhost' }
    assert_equal proxy, Person.proxy

    assert_nothing_raised { Person.proxy = proxy }
    assert_equal proxy, Person.proxy
  end

  def test_should_use_proxy_prefix_and_credentials
    assert_equal 'http://user:password@proxy.local:3000', ProxyResource.proxy.to_s
  end

  def test_proxy_variable_can_be_reset
    actor = Class.new(ActiveResource::Base)
    assert_nil actor.site
    actor.proxy = 'http://localhost:31337'
    actor.proxy = nil
    assert_nil actor.site
  end

73 74 75 76 77 78 79 80 81 82 83 84
  def test_should_accept_setting_user
    Forum.user = 'david'
    assert_equal('david', Forum.user)
    assert_equal('david', Forum.connection.user)
  end

  def test_should_accept_setting_password
    Forum.password = 'test123'
    assert_equal('test123', Forum.password)
    assert_equal('test123', Forum.connection.password)
  end

P
pivotal 已提交
85 86 87 88 89 90
  def test_should_accept_setting_auth_type
    Forum.auth_type = :digest
    assert_equal(:digest, Forum.auth_type)
    assert_equal(:digest, Forum.connection.auth_type)
  end

91 92 93 94 95 96
  def test_should_accept_setting_timeout
    Forum.timeout = 5
    assert_equal(5, Forum.timeout)
    assert_equal(5, Forum.connection.timeout)
  end

97 98 99 100 101 102 103
  def test_should_accept_setting_ssl_options
    expected = {:verify => 1}
    Forum.ssl_options= expected
    assert_equal(expected, Forum.ssl_options)
    assert_equal(expected, Forum.connection.ssl_options)
  end

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
  def test_user_variable_can_be_reset
    actor = Class.new(ActiveResource::Base)
    actor.site = 'http://cinema'
    assert_nil actor.user
    actor.user = 'username'
    actor.user = nil
    assert_nil actor.user
    assert_nil actor.connection.user
  end

  def test_password_variable_can_be_reset
    actor = Class.new(ActiveResource::Base)
    actor.site = 'http://cinema'
    assert_nil actor.password
    actor.password = 'username'
    actor.password = nil
    assert_nil actor.password
    assert_nil actor.connection.password
  end

124 125 126 127 128 129 130 131 132 133
  def test_timeout_variable_can_be_reset
    actor = Class.new(ActiveResource::Base)
    actor.site = 'http://cinema'
    assert_nil actor.timeout
    actor.timeout = 5
    actor.timeout = nil
    assert_nil actor.timeout
    assert_nil actor.connection.timeout
  end

134 135 136 137 138 139 140 141 142 143
  def test_ssl_options_hash_can_be_reset
    actor = Class.new(ActiveResource::Base)
    actor.site = 'https://cinema'
    assert_nil actor.ssl_options
    actor.ssl_options = {:foo => 5}
    actor.ssl_options = nil
    assert_nil actor.ssl_options
    assert_nil actor.connection.ssl_options
  end

144 145 146 147 148 149 150
  def test_credentials_from_site_are_decoded
    actor = Class.new(ActiveResource::Base)
    actor.site = 'http://my%40email.com:%31%32%33@cinema'
    assert_equal("my@email.com", actor.user)
    assert_equal("123", actor.password)
  end

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
  def test_site_reader_uses_superclass_site_until_written
    # Superclass is Object so returns nil.
    assert_nil ActiveResource::Base.site
    assert_nil Class.new(ActiveResource::Base).site

    # Subclass uses superclass site.
    actor = Class.new(Person)
    assert_equal Person.site, actor.site

    # Subclass returns frozen superclass copy.
    assert !Person.site.frozen?
    assert actor.site.frozen?

    # Changing subclass site doesn't change superclass site.
    actor.site = 'http://localhost:31337'
    assert_not_equal Person.site, actor.site

    # Changed subclass site is not frozen.
    assert !actor.site.frozen?

    # Changing superclass site doesn't overwrite subclass site.
    Person.site = 'http://somewhere.else'
    assert_not_equal Person.site, actor.site

    # Changing superclass site after subclassing changes subclass site.
    jester = Class.new(actor)
    actor.site = 'http://nomad'
    assert_equal actor.site, jester.site
    assert jester.site.frozen?
180 181

    # Subclasses are always equal to superclass site when not overridden
182 183
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
184

185
    fruit.site = 'http://market'
186
    assert_equal fruit.site, apple.site, 'subclass did not adopt changes from parent class'
187

188
    fruit.site = 'http://supermarket'
189
    assert_equal fruit.site, apple.site, 'subclass did not adopt changes from parent class'
190
  end
191

M
Marshall Huss 已提交
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
  def test_proxy_reader_uses_superclass_site_until_written
    # Superclass is Object so returns nil.
    assert_nil ActiveResource::Base.proxy
    assert_nil Class.new(ActiveResource::Base).proxy

    # Subclass uses superclass proxy.
    actor = Class.new(Person)
    assert_equal Person.proxy, actor.proxy

    # Subclass returns frozen superclass copy.
    assert !Person.proxy.frozen?
    assert actor.proxy.frozen?

    # Changing subclass proxy doesn't change superclass site.
    actor.proxy = 'http://localhost:31337'
    assert_not_equal Person.proxy, actor.proxy

    # Changed subclass proxy is not frozen.
    assert !actor.proxy.frozen?

    # Changing superclass proxy doesn't overwrite subclass site.
    Person.proxy = 'http://somewhere.else'
    assert_not_equal Person.proxy, actor.proxy

    # Changing superclass proxy after subclassing changes subclass site.
    jester = Class.new(actor)
    actor.proxy = 'http://nomad'
    assert_equal actor.proxy, jester.proxy
    assert jester.proxy.frozen?

    # Subclasses are always equal to superclass proxy when not overridden
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)

    fruit.proxy = 'http://market'
    assert_equal fruit.proxy, apple.proxy, 'subclass did not adopt changes from parent class'

    fruit.proxy = 'http://supermarket'
    assert_equal fruit.proxy, apple.proxy, 'subclass did not adopt changes from parent class'
  end

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 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
  def test_user_reader_uses_superclass_user_until_written
    # Superclass is Object so returns nil.
    assert_nil ActiveResource::Base.user
    assert_nil Class.new(ActiveResource::Base).user
    Person.user = 'anonymous'

    # Subclass uses superclass user.
    actor = Class.new(Person)
    assert_equal Person.user, actor.user

    # Subclass returns frozen superclass copy.
    assert !Person.user.frozen?
    assert actor.user.frozen?

    # Changing subclass user doesn't change superclass user.
    actor.user = 'david'
    assert_not_equal Person.user, actor.user

    # Changing superclass user doesn't overwrite subclass user.
    Person.user = 'john'
    assert_not_equal Person.user, actor.user

    # Changing superclass user after subclassing changes subclass user.
    jester = Class.new(actor)
    actor.user = 'john.doe'
    assert_equal actor.user, jester.user

    # Subclasses are always equal to superclass user when not overridden
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)

    fruit.user = 'manager'
    assert_equal fruit.user, apple.user, 'subclass did not adopt changes from parent class'

    fruit.user = 'client'
    assert_equal fruit.user, apple.user, 'subclass did not adopt changes from parent class'
  end

  def test_password_reader_uses_superclass_password_until_written
    # Superclass is Object so returns nil.
    assert_nil ActiveResource::Base.password
    assert_nil Class.new(ActiveResource::Base).password
    Person.password = 'my-password'

    # Subclass uses superclass password.
    actor = Class.new(Person)
    assert_equal Person.password, actor.password

    # Subclass returns frozen superclass copy.
    assert !Person.password.frozen?
    assert actor.password.frozen?

    # Changing subclass password doesn't change superclass password.
    actor.password = 'secret'
    assert_not_equal Person.password, actor.password

    # Changing superclass password doesn't overwrite subclass password.
    Person.password = 'super-secret'
    assert_not_equal Person.password, actor.password

    # Changing superclass password after subclassing changes subclass password.
    jester = Class.new(actor)
    actor.password = 'even-more-secret'
    assert_equal actor.password, jester.password

    # Subclasses are always equal to superclass password when not overridden
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)

    fruit.password = 'mega-secret'
    assert_equal fruit.password, apple.password, 'subclass did not adopt changes from parent class'

    fruit.password = 'ok-password'
    assert_equal fruit.password, apple.password, 'subclass did not adopt changes from parent class'
  end

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
  def test_timeout_reader_uses_superclass_timeout_until_written
    # Superclass is Object so returns nil.
    assert_nil ActiveResource::Base.timeout
    assert_nil Class.new(ActiveResource::Base).timeout
    Person.timeout = 5

    # Subclass uses superclass timeout.
    actor = Class.new(Person)
    assert_equal Person.timeout, actor.timeout

    # Changing subclass timeout doesn't change superclass timeout.
    actor.timeout = 10
    assert_not_equal Person.timeout, actor.timeout

    # Changing superclass timeout doesn't overwrite subclass timeout.
    Person.timeout = 15
    assert_not_equal Person.timeout, actor.timeout

    # Changing superclass timeout after subclassing changes subclass timeout.
    jester = Class.new(actor)
    actor.timeout = 20
    assert_equal actor.timeout, jester.timeout

    # Subclasses are always equal to superclass timeout when not overridden.
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)

    fruit.timeout = 25
    assert_equal fruit.timeout, apple.timeout, 'subclass did not adopt changes from parent class'

    fruit.timeout = 30
    assert_equal fruit.timeout, apple.timeout, 'subclass did not adopt changes from parent class'
  end

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 373 374 375 376
  def test_ssl_options_reader_uses_superclass_ssl_options_until_written
    # Superclass is Object so returns nil.
    assert_nil ActiveResource::Base.ssl_options
    assert_nil Class.new(ActiveResource::Base).ssl_options
    Person.ssl_options = {:foo => 'bar'}

    # Subclass uses superclass ssl_options.
    actor = Class.new(Person)
    assert_equal Person.ssl_options, actor.ssl_options

    # Changing subclass ssl_options doesn't change superclass ssl_options.
    actor.ssl_options = {:baz => ''}
    assert_not_equal Person.ssl_options, actor.ssl_options

    # Changing superclass ssl_options doesn't overwrite subclass ssl_options.
    Person.ssl_options = {:color => 'blue'}
    assert_not_equal Person.ssl_options, actor.ssl_options

    # Changing superclass ssl_options after subclassing changes subclass ssl_options.
    jester = Class.new(actor)
    actor.ssl_options = {:color => 'red'}
    assert_equal actor.ssl_options, jester.ssl_options

    # Subclasses are always equal to superclass ssl_options when not overridden.
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)

    fruit.ssl_options = {:alpha => 'betas'}
    assert_equal fruit.ssl_options, apple.ssl_options, 'subclass did not adopt changes from parent class'

    fruit.ssl_options = {:omega => 'moos'}
    assert_equal fruit.ssl_options, apple.ssl_options, 'subclass did not adopt changes from parent class'
  end

377
  def test_updating_baseclass_site_object_wipes_descendent_cached_connection_objects
378
    # Subclasses are always equal to superclass site when not overridden
379 380
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
381

382 383
    fruit.site = 'http://market'
    assert_equal fruit.connection.site, apple.connection.site
384
    first_connection = apple.connection.object_id
385

386
    fruit.site = 'http://supermarket'
387 388 389 390 391 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
    assert_equal fruit.connection.site, apple.connection.site
    second_connection = apple.connection.object_id
    assert_not_equal(first_connection, second_connection, 'Connection should be re-created')
  end

  def test_updating_baseclass_user_wipes_descendent_cached_connection_objects
    # Subclasses are always equal to superclass user when not overridden
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
    fruit.site = 'http://market'

    fruit.user = 'david'
    assert_equal fruit.connection.user, apple.connection.user
    first_connection = apple.connection.object_id

    fruit.user = 'john'
    assert_equal fruit.connection.user, apple.connection.user
    second_connection = apple.connection.object_id
    assert_not_equal(first_connection, second_connection, 'Connection should be re-created')
  end

  def test_updating_baseclass_password_wipes_descendent_cached_connection_objects
    # Subclasses are always equal to superclass password when not overridden
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
    fruit.site = 'http://market'

    fruit.password = 'secret'
    assert_equal fruit.connection.password, apple.connection.password
    first_connection = apple.connection.object_id

    fruit.password = 'supersecret'
    assert_equal fruit.connection.password, apple.connection.password
    second_connection = apple.connection.object_id
    assert_not_equal(first_connection, second_connection, 'Connection should be re-created')
422
  end
J
Jeremy Kemper 已提交
423

424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
  def test_updating_baseclass_timeout_wipes_descendent_cached_connection_objects
    # Subclasses are always equal to superclass timeout when not overridden
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
    fruit.site = 'http://market'

    fruit.timeout = 5
    assert_equal fruit.connection.timeout, apple.connection.timeout
    first_connection = apple.connection.object_id

    fruit.timeout = 10
    assert_equal fruit.connection.timeout, apple.connection.timeout
    second_connection = apple.connection.object_id
    assert_not_equal(first_connection, second_connection, 'Connection should be re-created')
  end

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
  def test_header_inheritance
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
    fruit.site = 'http://market'

    fruit.headers['key'] = 'value'
    assert_equal 'value', apple.headers['key']
  end

  def test_header_inheritance_set_at_multiple_points
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
    fruit.site = 'http://market'

    fruit.headers['key'] = 'value'
    assert_equal 'value', apple.headers['key']

    apple.headers['key2'] = 'value2'
    fruit.headers['key3'] = 'value3'

    assert_equal 'value', apple.headers['key']
    assert_equal 'value2', apple.headers['key2']
    assert_equal 'value3', apple.headers['key3']
  end

  def test_header_inheritance_should_not_leak_upstream
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
    fruit.site = 'http://market'

    fruit.headers['key'] = 'value'

    apple.headers['key2'] = 'value2'
    assert_equal nil, fruit.headers['key2']
  end

  def test_header_inheritance_should_not_leak_upstream
    fruit = Class.new(ActiveResource::Base)
    apple = Class.new(fruit)
    fruit.site = 'http://market'

    fruit.headers['key'] = 'value'

    apple.headers['key2'] = 'value2'
    assert_equal nil, fruit.headers['key2']
  end
486 487 488 489 490

  ########################################################################
  # Tests for setting up remote URLs for a given model (including adding
  # parameters appropriately)
  ########################################################################
491 492 493 494
  def test_collection_name
    assert_equal "people", Person.collection_name
  end

495
  def test_collection_path
496
    assert_equal '/people.json', Person.collection_path
497 498
  end

499
  def test_collection_path_with_parameters
500 501 502
    assert_equal '/people.json?gender=male', Person.collection_path(:gender => 'male')
    assert_equal '/people.json?gender=false', Person.collection_path(:gender => false)
    assert_equal '/people.json?gender=', Person.collection_path(:gender => nil)
503

504
    assert_equal '/people.json?gender=male', Person.collection_path('gender' => 'male')
505

506
    # Use includes? because ordering of param hash is not guaranteed
507
    assert Person.collection_path(:gender => 'male', :student => true).include?('/people.json?')
508 509
    assert Person.collection_path(:gender => 'male', :student => true).include?('gender=male')
    assert Person.collection_path(:gender => 'male', :student => true).include?('student=true')
510

511
    assert_equal '/people.json?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D=&name%5B%5D=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false])
512
    assert_equal '/people.json?struct%5Ba%5D%5B%5D=2&struct%5Ba%5D%5B%5D=1&struct%5Bb%5D=fred', Person.collection_path(:struct => {:a => [2,1], 'b' => 'fred'})
513 514
  end

515
  def test_custom_element_path
516 517 518 519
    assert_equal '/people/1/addresses/1.json', StreetAddress.element_path(1, :person_id => 1)
    assert_equal '/people/1/addresses/1.json', StreetAddress.element_path(1, 'person_id' => 1)
    assert_equal '/people/Greg/addresses/1.json', StreetAddress.element_path(1, 'person_id' => 'Greg')
    assert_equal '/people/ann%20mary/addresses/ann%20mary.json', StreetAddress.element_path(:'ann mary', 'person_id' => 'ann mary')
520
  end
521

522
  def test_custom_element_path_without_required_prefix_param
523
    assert_raise ActiveResource::MissingPrefixParam do
524
      StreetAddress.element_path(1)
525 526 527
    end
  end

528
  def test_module_element_path
529
    assert_equal '/sounds/1.json', Asset::Sound.element_path(1)
530 531
  end

532 533 534
  def test_custom_element_path_with_redefined_to_param
    Person.module_eval do
      alias_method :original_to_param_element_path, :to_param
535
       def to_param
536 537 538 539 540
         name
       end
    end

    # Class method.
541
    assert_equal '/people/Greg.json', Person.element_path('Greg')
542

543
    # Protected Instance method.
544
    assert_equal '/people/Greg.json', Person.find('Greg').send(:element_path)
545 546 547 548 549 550 551 552

    ensure
      # revert back to original
      Person.module_eval do
        # save the 'new' to_param so we don't get a warning about discarding the method
        alias_method :element_path_to_param, :to_param
        alias_method :to_param, :original_to_param_element_path
      end
553 554
  end

555
  def test_custom_element_path_with_parameters
556 557 558 559
    assert_equal '/people/1/addresses/1.json?type=work', StreetAddress.element_path(1, :person_id => 1, :type => 'work')
    assert_equal '/people/1/addresses/1.json?type=work', StreetAddress.element_path(1, 'person_id' => 1, :type => 'work')
    assert_equal '/people/1/addresses/1.json?type=work', StreetAddress.element_path(1, :type => 'work', :person_id => 1)
    assert_equal '/people/1/addresses/1.json?type%5B%5D=work&type%5B%5D=play+time', StreetAddress.element_path(1, :person_id => 1, :type => ['work', 'play time'])
560 561
  end

562
  def test_custom_element_path_with_prefix_and_parameters
563
    assert_equal '/people/1/addresses/1.json?type=work', StreetAddress.element_path(1, {:person_id => 1}, {:type => 'work'})
564 565
  end

566 567 568 569 570 571
  def test_custom_collection_path_without_required_prefix_param
    assert_raise ActiveResource::MissingPrefixParam do
      StreetAddress.collection_path
    end
  end

572
  def test_custom_collection_path
573 574
    assert_equal '/people/1/addresses.json', StreetAddress.collection_path(:person_id => 1)
    assert_equal '/people/1/addresses.json', StreetAddress.collection_path('person_id' => 1)
575 576
  end

577
  def test_custom_collection_path_with_parameters
578 579
    assert_equal '/people/1/addresses.json?type=work', StreetAddress.collection_path(:person_id => 1, :type => 'work')
    assert_equal '/people/1/addresses.json?type=work', StreetAddress.collection_path('person_id' => 1, :type => 'work')
580 581
  end

582
  def test_custom_collection_path_with_prefix_and_parameters
583
    assert_equal '/people/1/addresses.json?type=work', StreetAddress.collection_path({:person_id => 1}, {:type => 'work'})
584 585
  end

586 587 588 589 590 591 592 593 594 595
  def test_custom_element_name
    assert_equal 'address', StreetAddress.element_name
  end

  def test_custom_collection_name
    assert_equal 'addresses', StreetAddress.collection_name
  end

  def test_prefix
    assert_equal "/", Person.prefix
596
    assert_equal Set.new, Person.__send__(:prefix_parameters)
597
  end
598

599 600 601 602 603 604
  def test_set_prefix
    SetterTrap.rollback_sets(Person) do |person_class|
      person_class.prefix = "the_prefix"
      assert_equal "the_prefix", person_class.prefix
    end
  end
605

606 607 608 609 610 611
  def test_set_prefix_with_inline_keys
    SetterTrap.rollback_sets(Person) do |person_class|
      person_class.prefix = "the_prefix:the_param"
      assert_equal "the_prefixthe_param_value", person_class.prefix(:the_param => "the_param_value")
    end
  end
612

613 614 615 616 617 618
  def test_set_prefix_twice_should_clear_params
    SetterTrap.rollback_sets(Person) do |person_class|
      person_class.prefix = "the_prefix/:the_param1"
      assert_equal Set.new([:the_param1]), person_class.prefix_parameters
      person_class.prefix = "the_prefix/:the_param2"
      assert_equal Set.new([:the_param2]), person_class.prefix_parameters
619 620
      person_class.prefix = "the_prefix/:the_param1/other_prefix/:the_param2"
      assert_equal Set.new([:the_param2, :the_param1]), person_class.prefix_parameters
621 622 623
    end
  end

624 625 626 627 628 629
  def test_set_prefix_with_default_value
    SetterTrap.rollback_sets(Person) do |person_class|
      person_class.set_prefix
      assert_equal "/", person_class.prefix
    end
  end
630 631 632 633

  def test_custom_prefix
    assert_equal '/people//', StreetAddress.prefix
    assert_equal '/people/1/', StreetAddress.prefix(:person_id => 1)
634
    assert_equal [:person_id].to_set, StreetAddress.__send__(:prefix_parameters)
635 636
  end

637 638 639 640

  ########################################################################
  # Tests basic CRUD functions (find/save/create etc)
  ########################################################################
641 642
  def test_respond_to
    matz = Person.find(1)
643 644 645
    assert_respond_to matz, :name
    assert_respond_to matz, :name=
    assert_respond_to matz, :name?
646
    assert !matz.respond_to?(:super_scalable_stuff)
647
  end
648

649
  def test_custom_header
650
    Person.headers['key'] = 'value'
651
    assert_raise(ActiveResource::ResourceNotFound) { Person.find(4) }
652
  ensure
653
    Person.headers.delete('key')
654 655
  end

656
  def test_save
657
    rick = Person.new
658 659 660 661 662 663 664
    assert rick.save
    assert_equal '5', rick.id
  end

  def test_save!
    rick = Person.new
    assert rick.save!
665 666 667
    assert_equal '5', rick.id
  end

668 669 670
  def test_id_from_response
    p = Person.new
    resp = {'Location' => '/foo/bar/1'}
671
    assert_equal '1', p.__send__(:id_from_response, resp)
672

673
    resp['Location'] << '.json'
674
    assert_equal '1', p.__send__(:id_from_response, resp)
675 676
  end

677 678 679
  def test_id_from_response_without_location
    p = Person.new
    resp = {}
680
    assert_nil p.__send__(:id_from_response, resp)
681 682
  end

683
  def test_not_persisted_with_no_body_and_positive_content_length
N
Neeraj Singh 已提交
684 685
    resp = ActiveResource::Response.new(nil)
    resp['Content-Length'] = "100"
686 687 688 689 690 691 692 693 694
    Person.connection.expects(:post).returns(resp)
    assert !Person.create.persisted?
  end

  def test_not_persisted_with_body_and_zero_content_length
    resp = ActiveResource::Response.new(@rick)
    resp['Content-Length'] = "0"
    Person.connection.expects(:post).returns(resp)
    assert !Person.create.persisted?
N
Neeraj Singh 已提交
695 696
  end

697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
  # These response codes aren't allowed to have bodies per HTTP spec
  def test_not_persisted_with_empty_response_codes
    [100,101,204,304].each do |status_code|
      resp = ActiveResource::Response.new(@rick, status_code)
      Person.connection.expects(:post).returns(resp)
      assert !Person.create.persisted?
    end
  end

  # Content-Length is not required by HTTP 1.1, so we should read
  # the body anyway in its absence.
  def test_persisted_with_no_content_length
    resp = ActiveResource::Response.new(@rick)
    resp['Content-Length'] = nil
    Person.connection.expects(:post).returns(resp)
    assert Person.create.persisted?
  end
N
Neeraj Singh 已提交
714

715
  def test_create_with_custom_prefix
716
    matzs_house = StreetAddress.new(:person_id => 1)
717 718
    matzs_house.save
    assert_equal '5', matzs_house.id
719
  end
720

721 722
  # Test that loading a resource preserves its prefix_options.
  def test_load_preserves_prefix_options
723
    address = StreetAddress.find(1, :params => { :person_id => 1 })
724 725 726
    ryan = Person.new(:id => 1, :name => 'Ryan', :address => address)
    assert_equal address.prefix_options, ryan.address.prefix_options
  end
727

728 729 730 731
  def test_reload_works_with_prefix_options
    address = StreetAddress.find(1, :params => { :person_id => 1 })
    assert_equal address, address.reload
  end
732

733 734 735
  def test_reload_with_redefined_to_param
    Person.module_eval do
      alias_method :original_to_param_reload, :to_param
736
       def to_param
737 738 739 740 741 742 743 744 745 746 747 748 749 750
         name
       end
    end

    person = Person.find('Greg')
    assert_equal person, person.reload

    ensure
      # revert back to original
      Person.module_eval do
        # save the 'new' to_param so we don't get a warning about discarding the method
        alias_method :reload_to_param, :to_param
        alias_method :to_param, :original_to_param_reload
      end
751 752 753
  end

  def test_reload_works_without_prefix_options
754 755 756
    person = Person.find(:first)
    assert_equal person, person.reload
  end
757

758 759 760 761 762
  def test_create
    rick = Person.create(:name => 'Rick')
    assert rick.valid?
    assert !rick.new?
    assert_equal '5', rick.id
763 764 765

    # test additional attribute returned on create
    assert_equal 25, rick.age
766

767 768
    # Test that save exceptions get bubbled up too
    ActiveResource::HttpMock.respond_to do |mock|
769
      mock.post   "/people.json", {}, nil, 409
770
    end
771
    assert_raise(ActiveResource::ResourceConflict) { Person.create(:name => 'Rick') }
772 773
  end

774 775
  def test_create_without_location
    ActiveResource::HttpMock.respond_to do |mock|
776
      mock.post   "/people.json", {}, nil, 201
777 778
    end
    person = Person.create(:name => 'Rick')
779
    assert_nil person.id
780 781
  end

782
  def test_clone
J
Jeremy Kemper 已提交
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
    matz = Person.find(1)
    matz_c = matz.clone
    assert matz_c.new?
    matz.attributes.each do |k, v|
      assert_equal v, matz_c.send(k) if k != Person.primary_key
    end
  end

  def test_nested_clone
    addy = StreetAddress.find(1, :params => {:person_id => 1})
    addy_c = addy.clone
    assert addy_c.new?
    addy.attributes.each do |k, v|
      assert_equal v, addy_c.send(k) if k != StreetAddress.primary_key
    end
    assert_equal addy.prefix_options, addy_c.prefix_options
  end

  def test_complex_clone
    matz = Person.find(1)
    matz.address = StreetAddress.find(1, :params => {:person_id => matz.id})
    matz.non_ar_hash = {:not => "an ARes instance"}
    matz.non_ar_arr = ["not", "ARes"]
    matz_c = matz.clone
    assert matz_c.new?
808
    assert_raise(NoMethodError) {matz_c.address}
J
Jeremy Kemper 已提交
809 810 811 812 813 814 815
    assert_equal matz.non_ar_hash, matz_c.non_ar_hash
    assert_equal matz.non_ar_arr, matz_c.non_ar_arr

    # Test that actual copy, not just reference copy
    matz.non_ar_hash[:not] = "changed"
    assert_not_equal matz.non_ar_hash, matz_c.non_ar_hash
  end
816

817 818 819 820 821
  def test_update
    matz = Person.find(:first)
    matz.name = "David"
    assert_kind_of Person, matz
    assert_equal "David", matz.name
822
    assert_equal true, matz.save
823
  end
824

825
  def test_update_with_custom_prefix_with_specific_id
826
    addy = StreetAddress.find(1, :params => { :person_id => 1 })
827 828 829 830 831 832
    addy.street = "54321 Street"
    assert_kind_of StreetAddress, addy
    assert_equal "54321 Street", addy.street
    addy.save
  end

833 834 835 836 837 838 839
  def test_update_with_custom_prefix_without_specific_id
    addy = StreetAddress.find(:first, :params => { :person_id => 1 })
    addy.street = "54321 Lane"
    assert_kind_of StreetAddress, addy
    assert_equal "54321 Lane", addy.street
    addy.save
  end
840

841 842
  def test_update_conflict
    ActiveResource::HttpMock.respond_to do |mock|
843 844
      mock.get "/people/2.json", {}, @david
      mock.put "/people/2.json", @default_request_headers, nil, 409
845
    end
846
    assert_raise(ActiveResource::ResourceConflict) { Person.find(2).save }
847 848
  end

849 850 851

  ######
  # update_attribute(s)(!)
852

853 854 855 856 857 858 859 860
  def test_update_attribute_as_symbol
    matz = Person.first
    matz.expects(:save).returns(true)

    assert_equal "Matz", matz.name
    assert matz.update_attribute(:name, "David")
    assert_equal "David", matz.name
  end
861

862 863 864 865 866 867 868 869 870
  def test_update_attribute_as_string
    matz = Person.first
    matz.expects(:save).returns(true)

    assert_equal "Matz", matz.name
    assert matz.update_attribute('name', "David")
    assert_equal "David", matz.name
  end

871

872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
  def test_update_attributes_as_symbols
    addy = StreetAddress.first(:params => {:person_id => 1})
    addy.expects(:save).returns(true)

    assert_equal "12345 Street", addy.street
    assert_equal "Australia", addy.country
    assert addy.update_attributes(:street => '54321 Street', :country => 'USA')
    assert_equal "54321 Street", addy.street
    assert_equal "USA", addy.country
  end

  def test_update_attributes_as_strings
    addy = StreetAddress.first(:params => {:person_id => 1})
    addy.expects(:save).returns(true)

    assert_equal "12345 Street", addy.street
    assert_equal "Australia", addy.country
    assert addy.update_attributes('street' => '54321 Street', 'country' => 'USA')
    assert_equal "54321 Street", addy.street
    assert_equal "USA", addy.country
  end


  #####
  # Mayhem and destruction

898 899
  def test_destroy
    assert Person.find(1).destroy
900
    ActiveResource::HttpMock.respond_to do |mock|
901
      mock.get "/people/1.json", {}, nil, 404
902
    end
903
    assert_raise(ActiveResource::ResourceNotFound) { Person.find(1).destroy }
904 905 906
  end

  def test_destroy_with_custom_prefix
907
    assert StreetAddress.find(1, :params => { :person_id => 1 }).destroy
908
    ActiveResource::HttpMock.respond_to do |mock|
909
      mock.get "/people/1/addresses/1.json", {}, nil, 404
910
    end
911
    assert_raise(ActiveResource::ResourceNotFound) { StreetAddress.find(1, :params => { :person_id => 1 }) }
912
  end
913

914 915 916
  def test_destroy_with_410_gone
    assert Person.find(1).destroy
    ActiveResource::HttpMock.respond_to do |mock|
917
      mock.get "/people/1.json", {}, nil, 410
918 919 920 921
    end
    assert_raise(ActiveResource::ResourceGone) { Person.find(1).destroy }
  end

922 923
  def test_delete
    assert Person.delete(1)
924
    ActiveResource::HttpMock.respond_to do |mock|
925
      mock.get "/people/1.json", {}, nil, 404
926
    end
927
    assert_raise(ActiveResource::ResourceNotFound) { Person.find(1) }
928
  end
929

930 931 932
  def test_delete_with_custom_prefix
    assert StreetAddress.delete(1, :person_id => 1)
    ActiveResource::HttpMock.respond_to do |mock|
933
      mock.get "/people/1/addresses/1.json", {}, nil, 404
934
    end
935
    assert_raise(ActiveResource::ResourceNotFound) { StreetAddress.find(1, :params => { :person_id => 1 }) }
936
  end
937

938 939 940
  def test_delete_with_410_gone
    assert Person.delete(1)
    ActiveResource::HttpMock.respond_to do |mock|
941
      mock.get "/people/1.json", {}, nil, 410
942 943 944
    end
    assert_raise(ActiveResource::ResourceGone) { Person.find(1) }
  end
945

946
  ########################################################################
R
R.T. Lechow 已提交
947
  # Tests the more miscellaneous helper methods
948
  ########################################################################
949 950 951 952 953 954 955 956 957 958 959 960
  def test_exists
    # Class method.
    assert !Person.exists?(nil)
    assert Person.exists?(1)
    assert !Person.exists?(99)

    # Instance method.
    assert !Person.new.exists?
    assert Person.find(1).exists?
    assert !Person.new(:id => 99).exists?

    # Nested class method.
961 962 963
    assert StreetAddress.exists?(1,  :params => { :person_id => 1 })
    assert !StreetAddress.exists?(1, :params => { :person_id => 2 })
    assert !StreetAddress.exists?(2, :params => { :person_id => 1 })
964 965

    # Nested instance method.
966
    assert StreetAddress.find(1, :params => { :person_id => 1 }).exists?
967 968
    assert !StreetAddress.new({:id => 1, :person_id => 2}).exists?
    assert !StreetAddress.new({:id => 2, :person_id => 1}).exists?
969
  end
970

971 972 973
  def test_exists_with_redefined_to_param
    Person.module_eval do
      alias_method :original_to_param_exists, :to_param
J
Jeremy Kemper 已提交
974 975 976
      def to_param
        name
      end
977 978 979
    end

    # Class method.
980
    assert Person.exists?('Greg')
981 982

    # Instance method.
983
    assert Person.find('Greg').exists?
984 985

    # Nested class method.
986
    assert StreetAddress.exists?(1,  :params => { :person_id => Person.find('Greg').to_param })
987 988 989 990

    # Nested instance method.
    assert StreetAddress.find(1, :params => { :person_id => Person.find('Greg').to_param }).exists?

J
Jeremy Kemper 已提交
991 992 993 994 995 996 997
  ensure
    # revert back to original
    Person.module_eval do
      # save the 'new' to_param so we don't get a warning about discarding the method
      alias_method :exists_to_param, :to_param
      alias_method :to_param, :original_to_param_exists
    end
998 999
  end

1000 1001 1002 1003 1004 1005 1006 1007
  def test_exists_without_http_mock
    http = Net::HTTP.new(Person.site.host, Person.site.port)
    ActiveResource::Connection.any_instance.expects(:http).returns(http)
    http.expects(:request).returns(ActiveResource::Response.new(""))

    assert Person.exists?('not-mocked')
  end

1008 1009
  def test_exists_with_410_gone
    ActiveResource::HttpMock.respond_to do |mock|
1010
      mock.head "/people/1.json", {}, nil, 410
1011 1012 1013 1014 1015
    end

    assert !Person.exists?(1)
  end

1016
  def test_to_xml
1017
    Person.format = :xml
1018
    matz = Person.find(1)
1019 1020 1021
    encode = matz.encode
    xml = matz.to_xml

1022
    assert_equal encode, xml
1023
    assert xml.include?('<?xml version="1.0" encoding="UTF-8"?>')
1024 1025
    assert xml.include?('<name>Matz</name>')
    assert xml.include?('<id type="integer">1</id>')
1026 1027
  ensure
    Person.format = :json
1028
  end
1029

1030
  def test_to_xml_with_element_name
1031
    Person.format = :xml
1032 1033 1034 1035 1036 1037
    old_elem_name = Person.element_name
    matz = Person.find(1)
    Person.element_name = 'ruby_creator'
    encode = matz.encode
    xml = matz.to_xml

1038
    assert_equal encode, xml
1039 1040 1041 1042 1043 1044
    assert xml.include?('<?xml version="1.0" encoding="UTF-8"?>')
    assert xml.include?('<ruby-creator>')
    assert xml.include?('<name>Matz</name>')
    assert xml.include?('<id type="integer">1</id>')
    assert xml.include?('</ruby-creator>')
  ensure
1045
    Person.format = :json
1046 1047
    Person.element_name = old_elem_name
  end
1048

1049
  def test_to_xml_with_private_method_name_as_attribute
1050
    Person.format = :xml
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061

    customer = Customer.new(:foo => "foo")
    customer.singleton_class.class_eval do
      def foo
        "bar"
      end
      private :foo
    end

    assert !customer.to_xml.include?("<foo>bar</foo>")
    assert customer.to_xml.include?("<foo>foo</foo>")
1062 1063
  ensure
    Person.format = :json
1064
  end
1065

1066 1067 1068
  def test_to_json
    Person.include_root_in_json = true
    joe = Person.find(6)
1069 1070
    encode = joe.encode
    json = joe.to_json
1071

1072
    assert_equal encode, json
1073
    assert_match %r{^\{"person":\{}, json
1074 1075
    assert_match %r{"id":6}, json
    assert_match %r{"name":"Joe"}, json
1076
    assert_match %r{\}\}$}, json
1077 1078
  end

1079 1080 1081 1082 1083 1084 1085 1086
  def test_to_json_with_element_name
    old_elem_name = Person.element_name
    Person.include_root_in_json = true
    joe = Person.find(6)
    Person.element_name = 'ruby_creator'
    encode = joe.encode
    json = joe.to_json

1087
    assert_equal encode, json
1088
    assert_match %r{^\{"ruby_creator":\{}, json
1089 1090
    assert_match %r{"id":6}, json
    assert_match %r{"name":"Joe"}, json
1091
    assert_match %r{\}\}$}, json
1092 1093 1094 1095
  ensure
    Person.element_name = old_elem_name
  end

1096 1097 1098 1099 1100 1101
  def test_to_param_quacks_like_active_record
    new_person = Person.new
    assert_nil new_person.to_param
    matz = Person.find(1)
    assert_equal '1', matz.to_param
  end
1102

1103 1104 1105 1106 1107 1108 1109
  def test_to_key_quacks_like_active_record
    new_person = Person.new
    assert_nil new_person.to_key
    matz = Person.find(1)
    assert_equal [1], matz.to_key
  end

1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
  def test_parse_deep_nested_resources
    luis = Customer.find(1)
    assert_kind_of Customer, luis
    luis.friends.each do |friend|
      assert_kind_of Customer::Friend, friend
      friend.brothers.each do |brother|
        assert_kind_of Customer::Friend::Brother, brother
        brother.children.each do |child|
          assert_kind_of Customer::Friend::Brother::Child, child
        end
      end
    end
  end
1123 1124 1125

  def test_load_yaml_array
    assert_nothing_raised do
1126
      Person.format = :xml
1127 1128 1129 1130 1131 1132
      marty = Person.find(5)
      assert_equal 3, marty.colors.size
      marty.colors.each do |color|
        assert_kind_of String, color
      end
    end
1133 1134
  ensure
    Person.format = :json
1135
  end
1136 1137

  def test_with_custom_formatter
1138
    addresses = [{ :id => "1", :street => "1 Infinite Loop", :city => "Cupertino", :state => "CA" }].to_xml(:root => :addresses)
1139 1140

    ActiveResource::HttpMock.respond_to do |mock|
1141
      mock.get "/addresses.xml", {}, addresses, 200
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
    end

    # late bind the site
    AddressResource.site = "http://localhost"
    addresses = AddressResource.find(:all)

    assert_equal "Cupertino, CA", addresses.first.city_state
  end

  def test_create_with_custom_primary_key
1152
    silver_plan = { :plan => { :code => "silver", :price => 5.00 } }.to_json
1153 1154

    ActiveResource::HttpMock.respond_to do |mock|
1155
      mock.post "/plans.json", {}, silver_plan, 201, 'Location' => '/plans/silver.json'
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
    end

    plan = SubscriptionPlan.new(:code => "silver", :price => 5.00)
    assert plan.new?

    plan.save!
    assert !plan.new?
  end

  def test_update_with_custom_primary_key
1166 1167
    silver_plan = { :plan => { :code => "silver", :price => 5.00 } }.to_json
    silver_plan_updated = { :plan => { :code => "silver", :price => 10.00 } }.to_json
1168 1169

    ActiveResource::HttpMock.respond_to do |mock|
1170 1171
      mock.get "/plans/silver.json", {}, silver_plan
      mock.put "/plans/silver.json", {}, silver_plan_updated, 201, 'Location' => '/plans/silver.json'
1172 1173 1174 1175
    end

    plan = SubscriptionPlan.find("silver")
    assert !plan.new?
J
José Valim 已提交
1176
    assert_equal 5.00, plan.price
1177 1178 1179 1180

    # update price
    plan.price = 10.00
    plan.save!
J
José Valim 已提交
1181
    assert_equal 10.00, plan.price
1182
  end
1183

1184 1185 1186 1187
  def test_namespacing
    sound = Asset::Sound.find(1)
    assert_equal "Asset::Sound::Author", sound.author.class.to_s
  end
J
Jeremy Kemper 已提交
1188
end